1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2011 The Android Open Source Project
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci * 2021.9.9 SkFontMgr_config_parser on previewer of ohos.
7cb93a386Sopenharmony_ci *           Copyright (c) 2021 Huawei Device Co., Ltd. All rights reserved.
8cb93a386Sopenharmony_ci */
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci// Despite the name and location, this is portable code.
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_ci#include "src/ports/SkFontMgr_config_parser.h"
13cb93a386Sopenharmony_ci#include "src/ports/skia_ohos/HmSymbolConfig_ohos.h"
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci#include <expat.h>
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ci#include "include/core/SkStream.h"
18cb93a386Sopenharmony_ci#include "include/private/SkFixed.h"
19cb93a386Sopenharmony_ci#include "src/core/SkTSearch.h"
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ci#define SK_FONT_CONFIG_FILE_NAME "fonts.xml"
22cb93a386Sopenharmony_cistd::string SkFontMgr::containerFontPath = "";
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_cinamespace {
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_cistd::string g_lmpSystemFontsFile = "INVALID_FILE_PATH";
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_ci}
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ci/**
31cb93a386Sopenharmony_ci * This parser file for android contains TWO 'familyset' handlers:
32cb93a386Sopenharmony_ci * One for JB and earlier and the other for LMP and later.
33cb93a386Sopenharmony_ci * For previewer, we only use the fonts.xml in LMP, so the LMP 'familyset' handler is only needed.
34cb93a386Sopenharmony_ci */
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_cistruct FamilyData;
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_cistruct TagHandler {
39cb93a386Sopenharmony_ci    /** Called at the start tag.
40cb93a386Sopenharmony_ci     *  Called immediately after the parent tag retuns this handler from a call to 'tag'.
41cb93a386Sopenharmony_ci     *  Allows setting up for handling the tag content and processing attributes.
42cb93a386Sopenharmony_ci     *  If nullptr, will not be called.
43cb93a386Sopenharmony_ci     */
44cb93a386Sopenharmony_ci    void (*start)(FamilyData* data, const char* tag, const char** attributes);
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_ci    /** Called at the end tag.
47cb93a386Sopenharmony_ci     *  Allows post-processing of any accumulated information.
48cb93a386Sopenharmony_ci     *  This will be the last call made in relation to the current tag.
49cb93a386Sopenharmony_ci     *  If nullptr, will not be called.
50cb93a386Sopenharmony_ci     */
51cb93a386Sopenharmony_ci    void (*end)(FamilyData* data, const char* tag);
52cb93a386Sopenharmony_ci
53cb93a386Sopenharmony_ci    /** Called when a nested tag is encountered.
54cb93a386Sopenharmony_ci     *  This is responsible for determining how to handle the tag.
55cb93a386Sopenharmony_ci     *  If the tag is not recognized, return nullptr to skip the tag.
56cb93a386Sopenharmony_ci     *  If nullptr, all nested tags will be skipped.
57cb93a386Sopenharmony_ci     */
58cb93a386Sopenharmony_ci    const TagHandler* (*tag)(FamilyData* data, const char* tag, const char** attributes);
59cb93a386Sopenharmony_ci
60cb93a386Sopenharmony_ci    /** The character handler for this tag.
61cb93a386Sopenharmony_ci     *  This is only active for character data contained directly in this tag (not sub-tags).
62cb93a386Sopenharmony_ci     *  The first parameter will be castable to a FamilyData*.
63cb93a386Sopenharmony_ci     *  If nullptr, any character data in this tag will be ignored.
64cb93a386Sopenharmony_ci     */
65cb93a386Sopenharmony_ci    XML_CharacterDataHandler chars;
66cb93a386Sopenharmony_ci};
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ci/** Represents the current parsing state. */
69cb93a386Sopenharmony_cistruct FamilyData {
70cb93a386Sopenharmony_ci    FamilyData(XML_Parser parser, SkTDArray<FontFamily*>& families,
71cb93a386Sopenharmony_ci               const SkString& basePath, bool isFallback, const char* filename,
72cb93a386Sopenharmony_ci               const TagHandler* topLevelHandler)
73cb93a386Sopenharmony_ci        : fParser(parser)
74cb93a386Sopenharmony_ci        , fFamilies(families)
75cb93a386Sopenharmony_ci        , fCurrentFamily(nullptr)
76cb93a386Sopenharmony_ci        , fCurrentFontInfo(nullptr)
77cb93a386Sopenharmony_ci        , fVersion(0)
78cb93a386Sopenharmony_ci        , fBasePath(basePath)
79cb93a386Sopenharmony_ci        , fIsFallback(isFallback)
80cb93a386Sopenharmony_ci        , fFilename(filename)
81cb93a386Sopenharmony_ci        , fDepth(1)
82cb93a386Sopenharmony_ci        , fSkip(0)
83cb93a386Sopenharmony_ci        , fHandler(&topLevelHandler, 1)
84cb93a386Sopenharmony_ci    { }
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci    XML_Parser fParser;                         // The expat parser doing the work, owned by caller
87cb93a386Sopenharmony_ci    SkTDArray<FontFamily*>& fFamilies;          // The array to append families, owned by caller
88cb93a386Sopenharmony_ci    std::unique_ptr<FontFamily> fCurrentFamily; // The family being created, owned by this
89cb93a386Sopenharmony_ci    FontFileInfo* fCurrentFontInfo;             // The info being created, owned by fCurrentFamily
90cb93a386Sopenharmony_ci    int fVersion;                               // The version of the file parsed.
91cb93a386Sopenharmony_ci    const SkString& fBasePath;                  // The current base path.
92cb93a386Sopenharmony_ci    const bool fIsFallback;                     // The file being parsed is a fallback file
93cb93a386Sopenharmony_ci    const char* fFilename;                      // The name of the file currently being parsed.
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci    int fDepth;                                 // The current element depth of the parse.
96cb93a386Sopenharmony_ci    int fSkip;                                  // The depth to stop skipping, 0 if not skipping.
97cb93a386Sopenharmony_ci    SkTDArray<const TagHandler*> fHandler;      // The stack of current tag handlers.
98cb93a386Sopenharmony_ci};
99cb93a386Sopenharmony_ci
100cb93a386Sopenharmony_cistatic bool memeq(const char *s1, const char *s2, size_t n1, size_t n2)
101cb93a386Sopenharmony_ci{
102cb93a386Sopenharmony_ci    return n1 == n2 && 0 == memcmp(s1, s2, n1);
103cb93a386Sopenharmony_ci}
104cb93a386Sopenharmony_ci#define MEMEQ(c, s, n) memeq(c, s, sizeof(c) - 1, n)
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci#define ATTS_NON_NULL(a, i) (a[i] != nullptr && a[i + 1] != nullptr)
107cb93a386Sopenharmony_ci
108cb93a386Sopenharmony_ci#define SK_FONTMGR_CONFIG_PARSER_PREFIX "[SkFontMgr Config Parser] "
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ci#define SK_FONTCONFIGPARSER_WARNING(message, ...)                                                 \
111cb93a386Sopenharmony_ci    SkDebugf(SK_FONTMGR_CONFIG_PARSER_PREFIX "%s:%d:%d: warning: " message "\n", self->fFilename, \
112cb93a386Sopenharmony_ci             XML_GetCurrentLineNumber(self->fParser), XML_GetCurrentColumnNumber(self->fParser), ##__VA_ARGS__)
113cb93a386Sopenharmony_ci
114cb93a386Sopenharmony_cistatic bool is_whitespace(char c)
115cb93a386Sopenharmony_ci{
116cb93a386Sopenharmony_ci    return c == ' ' || c == '\n' || c == '\r' || c == '\t';
117cb93a386Sopenharmony_ci}
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_cistatic void trim_string(SkString* s)
120cb93a386Sopenharmony_ci{
121cb93a386Sopenharmony_ci    char* str = s->writable_str();
122cb93a386Sopenharmony_ci    const char* start = str;  // start is inclusive
123cb93a386Sopenharmony_ci    const char* end = start + s->size();  // end is exclusive
124cb93a386Sopenharmony_ci    while (is_whitespace(*start)) { ++start; }
125cb93a386Sopenharmony_ci    if (start != end) {
126cb93a386Sopenharmony_ci        --end;  // make end inclusive
127cb93a386Sopenharmony_ci        while (is_whitespace(*end)) {
128cb93a386Sopenharmony_ci            --end;
129cb93a386Sopenharmony_ci        }
130cb93a386Sopenharmony_ci        ++end;  // make end exclusive
131cb93a386Sopenharmony_ci    }
132cb93a386Sopenharmony_ci    size_t len = end - start;
133cb93a386Sopenharmony_ci    memmove(str, start, len);
134cb93a386Sopenharmony_ci    s->resize(len);
135cb93a386Sopenharmony_ci}
136cb93a386Sopenharmony_ci
137cb93a386Sopenharmony_cinamespace lmpParser {
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_cistatic const TagHandler axisHandler = {
140cb93a386Sopenharmony_ci    /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
141cb93a386Sopenharmony_ci        FontFileInfo& file = *self->fCurrentFontInfo;
142cb93a386Sopenharmony_ci        SkFourByteTag axisTag = SkSetFourByteTag('\0', '\0', '\0', '\0');
143cb93a386Sopenharmony_ci        SkFixed axisStyleValue = 0;
144cb93a386Sopenharmony_ci        bool axisTagIsValid = false;
145cb93a386Sopenharmony_ci        bool axisStyleValueIsValid = false;
146cb93a386Sopenharmony_ci        for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
147cb93a386Sopenharmony_ci            const char* name = attributes[i];
148cb93a386Sopenharmony_ci            const char* value = attributes[i + 1];
149cb93a386Sopenharmony_ci            size_t nameLen = strlen(name);
150cb93a386Sopenharmony_ci            if (MEMEQ("tag", name, nameLen)) {
151cb93a386Sopenharmony_ci                size_t valueLen = strlen(value);
152cb93a386Sopenharmony_ci                if (valueLen == 4) {
153cb93a386Sopenharmony_ci                    axisTag = SkSetFourByteTag(value[0], value[1], value[2], value[3]);
154cb93a386Sopenharmony_ci                    axisTagIsValid = true;
155cb93a386Sopenharmony_ci                    for (int j = 0; j < file.fVariationDesignPosition.count() - 1; ++j) {
156cb93a386Sopenharmony_ci                        if (file.fVariationDesignPosition[j].axis == axisTag) {
157cb93a386Sopenharmony_ci                            axisTagIsValid = false;
158cb93a386Sopenharmony_ci                            SK_FONTCONFIGPARSER_WARNING("'%c%c%c%c' axis specified more than once",
159cb93a386Sopenharmony_ci                                                        (axisTag >> 24) & 0xFF,
160cb93a386Sopenharmony_ci                                                        (axisTag >> 16) & 0xFF,
161cb93a386Sopenharmony_ci                                                        (axisTag >>  8) & 0xFF,
162cb93a386Sopenharmony_ci                                                        (axisTag      ) & 0xFF);
163cb93a386Sopenharmony_ci                        }
164cb93a386Sopenharmony_ci                    }
165cb93a386Sopenharmony_ci                } else {
166cb93a386Sopenharmony_ci                    SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid axis tag", value);
167cb93a386Sopenharmony_ci                }
168cb93a386Sopenharmony_ci            } else if (MEMEQ("stylevalue", name, nameLen)) {
169cb93a386Sopenharmony_ci                if (parse_fixed<16>(value, &axisStyleValue)) {
170cb93a386Sopenharmony_ci                    axisStyleValueIsValid = true;
171cb93a386Sopenharmony_ci                } else {
172cb93a386Sopenharmony_ci                    SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid axis stylevalue", value);
173cb93a386Sopenharmony_ci                }
174cb93a386Sopenharmony_ci            }
175cb93a386Sopenharmony_ci        }
176cb93a386Sopenharmony_ci        if (axisTagIsValid && axisStyleValueIsValid) {
177cb93a386Sopenharmony_ci            auto& coordinate = file.fVariationDesignPosition.push_back();
178cb93a386Sopenharmony_ci            coordinate.axis = axisTag;
179cb93a386Sopenharmony_ci            coordinate.value = SkFixedToScalar(axisStyleValue);
180cb93a386Sopenharmony_ci        }
181cb93a386Sopenharmony_ci    },
182cb93a386Sopenharmony_ci    /*end*/nullptr,
183cb93a386Sopenharmony_ci    /*tag*/nullptr,
184cb93a386Sopenharmony_ci    /*chars*/nullptr,
185cb93a386Sopenharmony_ci};
186cb93a386Sopenharmony_ci
187cb93a386Sopenharmony_cistatic const TagHandler fontHandler = {
188cb93a386Sopenharmony_ci    /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
189cb93a386Sopenharmony_ci        // 'weight' (non-negative integer) [default 0]
190cb93a386Sopenharmony_ci        // 'style' ("normal", "italic") [default "auto"]
191cb93a386Sopenharmony_ci        // 'index' (non-negative integer) [default 0]
192cb93a386Sopenharmony_ci        // The character data should be a filename.
193cb93a386Sopenharmony_ci        FontFileInfo& file = self->fCurrentFamily->fFonts.push_back();
194cb93a386Sopenharmony_ci        self->fCurrentFontInfo = &file;
195cb93a386Sopenharmony_ci        SkString fallbackFor;
196cb93a386Sopenharmony_ci        for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
197cb93a386Sopenharmony_ci            const char* name = attributes[i];
198cb93a386Sopenharmony_ci            const char* value = attributes[i + 1];
199cb93a386Sopenharmony_ci            size_t nameLen = strlen(name);
200cb93a386Sopenharmony_ci            if (MEMEQ("weight", name, nameLen)) {
201cb93a386Sopenharmony_ci                if (!parse_non_negative_integer(value, &file.fWeight)) {
202cb93a386Sopenharmony_ci                    SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value);
203cb93a386Sopenharmony_ci                }
204cb93a386Sopenharmony_ci            } else if (MEMEQ("style", name, nameLen)) {
205cb93a386Sopenharmony_ci                size_t valueLen = strlen(value);
206cb93a386Sopenharmony_ci                if (MEMEQ("normal", value, valueLen)) {
207cb93a386Sopenharmony_ci                    file.fStyle = FontFileInfo::Style::kNormal;
208cb93a386Sopenharmony_ci                } else if (MEMEQ("italic", value, valueLen)) {
209cb93a386Sopenharmony_ci                    file.fStyle = FontFileInfo::Style::kItalic;
210cb93a386Sopenharmony_ci                }
211cb93a386Sopenharmony_ci            } else if (MEMEQ("index", name, nameLen)) {
212cb93a386Sopenharmony_ci                if (!parse_non_negative_integer(value, &file.fIndex)) {
213cb93a386Sopenharmony_ci                    SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value);
214cb93a386Sopenharmony_ci                }
215cb93a386Sopenharmony_ci            } else if (MEMEQ("fallbackFor", name, nameLen)) {
216cb93a386Sopenharmony_ci                /** fallbackFor specifies a family fallback and should have been on family. */
217cb93a386Sopenharmony_ci                fallbackFor = value;
218cb93a386Sopenharmony_ci            }
219cb93a386Sopenharmony_ci        }
220cb93a386Sopenharmony_ci        if (!fallbackFor.isEmpty()) {
221cb93a386Sopenharmony_ci            std::unique_ptr<FontFamily>* fallbackFamily =
222cb93a386Sopenharmony_ci                self->fCurrentFamily->fallbackFamilies.find(fallbackFor);
223cb93a386Sopenharmony_ci            if (!fallbackFamily) {
224cb93a386Sopenharmony_ci                std::unique_ptr<FontFamily> newFallbackFamily(
225cb93a386Sopenharmony_ci                    new FontFamily(self->fCurrentFamily->fBasePath, true));
226cb93a386Sopenharmony_ci                fallbackFamily = self->fCurrentFamily->fallbackFamilies.set(
227cb93a386Sopenharmony_ci                    fallbackFor, std::move(newFallbackFamily));
228cb93a386Sopenharmony_ci                (*fallbackFamily)->fLanguages = self->fCurrentFamily->fLanguages;
229cb93a386Sopenharmony_ci                (*fallbackFamily)->fVariant = self->fCurrentFamily->fVariant;
230cb93a386Sopenharmony_ci                (*fallbackFamily)->fOrder = self->fCurrentFamily->fOrder;
231cb93a386Sopenharmony_ci                (*fallbackFamily)->fFallbackFor = fallbackFor;
232cb93a386Sopenharmony_ci            }
233cb93a386Sopenharmony_ci            self->fCurrentFontInfo = &(*fallbackFamily)->fFonts.emplace_back(file);
234cb93a386Sopenharmony_ci            self->fCurrentFamily->fFonts.pop_back();
235cb93a386Sopenharmony_ci        }
236cb93a386Sopenharmony_ci    },
237cb93a386Sopenharmony_ci    /*end*/[](FamilyData* self, const char* tag) {
238cb93a386Sopenharmony_ci        trim_string(&self->fCurrentFontInfo->fFileName);
239cb93a386Sopenharmony_ci    },
240cb93a386Sopenharmony_ci    /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
241cb93a386Sopenharmony_ci        size_t len = strlen(tag);
242cb93a386Sopenharmony_ci        if (MEMEQ("axis", tag, len)) {
243cb93a386Sopenharmony_ci            return &axisHandler;
244cb93a386Sopenharmony_ci        }
245cb93a386Sopenharmony_ci        return nullptr;
246cb93a386Sopenharmony_ci    },
247cb93a386Sopenharmony_ci    /*chars*/[](void* data, const char* s, int len) {
248cb93a386Sopenharmony_ci        FamilyData* self = static_cast<FamilyData*>(data);
249cb93a386Sopenharmony_ci        self->fCurrentFontInfo->fFileName.append(s, len);
250cb93a386Sopenharmony_ci    }
251cb93a386Sopenharmony_ci};
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_cistatic const TagHandler familyHandler = {
254cb93a386Sopenharmony_ci    /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
255cb93a386Sopenharmony_ci        // 'name' (string) [optional]
256cb93a386Sopenharmony_ci        // 'lang' (space separated string) [default ""]
257cb93a386Sopenharmony_ci        // 'variant' ("elegant", "compact") [default "default"]
258cb93a386Sopenharmony_ci        // If there is no name, this is a fallback only font.
259cb93a386Sopenharmony_ci        FontFamily* family = new FontFamily(self->fBasePath, true);
260cb93a386Sopenharmony_ci        self->fCurrentFamily.reset(family);
261cb93a386Sopenharmony_ci        for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
262cb93a386Sopenharmony_ci            const char* name = attributes[i];
263cb93a386Sopenharmony_ci            const char* value = attributes[i + 1];
264cb93a386Sopenharmony_ci            size_t nameLen = strlen(name);
265cb93a386Sopenharmony_ci            size_t valueLen = strlen(value);
266cb93a386Sopenharmony_ci            if (MEMEQ("name", name, nameLen)) {
267cb93a386Sopenharmony_ci                SkAutoAsciiToLC tolc(value);
268cb93a386Sopenharmony_ci                family->fNames.push_back().set(tolc.lc());
269cb93a386Sopenharmony_ci                family->fIsFallbackFont = false;
270cb93a386Sopenharmony_ci            } else if (MEMEQ("lang", name, nameLen)) {
271cb93a386Sopenharmony_ci                size_t i = 0;
272cb93a386Sopenharmony_ci                while (true) {
273cb93a386Sopenharmony_ci                    for (; i < valueLen && is_whitespace(value[i]); ++i) { }
274cb93a386Sopenharmony_ci                    if (i == valueLen) {
275cb93a386Sopenharmony_ci                        break;
276cb93a386Sopenharmony_ci                    }
277cb93a386Sopenharmony_ci                    size_t j;
278cb93a386Sopenharmony_ci                    for (j = i + 1; j < valueLen && !is_whitespace(value[j]); ++j) { }
279cb93a386Sopenharmony_ci                    family->fLanguages.emplace_back(value + i, j - i);
280cb93a386Sopenharmony_ci                    i = j;
281cb93a386Sopenharmony_ci                    if (i == valueLen) {
282cb93a386Sopenharmony_ci                        break;
283cb93a386Sopenharmony_ci                    }
284cb93a386Sopenharmony_ci                }
285cb93a386Sopenharmony_ci            } else if (MEMEQ("variant", name, nameLen)) {
286cb93a386Sopenharmony_ci                if (MEMEQ("elegant", value, valueLen)) {
287cb93a386Sopenharmony_ci                    family->fVariant = kElegant_FontVariant;
288cb93a386Sopenharmony_ci                } else if (MEMEQ("compact", value, valueLen)) {
289cb93a386Sopenharmony_ci                    family->fVariant = kCompact_FontVariant;
290cb93a386Sopenharmony_ci                }
291cb93a386Sopenharmony_ci            }
292cb93a386Sopenharmony_ci        }
293cb93a386Sopenharmony_ci    },
294cb93a386Sopenharmony_ci    /*end*/[](FamilyData* self, const char* tag) {
295cb93a386Sopenharmony_ci        *self->fFamilies.append() = self->fCurrentFamily.release();
296cb93a386Sopenharmony_ci    },
297cb93a386Sopenharmony_ci    /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
298cb93a386Sopenharmony_ci        size_t len = strlen(tag);
299cb93a386Sopenharmony_ci        if (MEMEQ("font", tag, len)) {
300cb93a386Sopenharmony_ci            return &fontHandler;
301cb93a386Sopenharmony_ci        }
302cb93a386Sopenharmony_ci        return nullptr;
303cb93a386Sopenharmony_ci    },
304cb93a386Sopenharmony_ci    /*chars*/nullptr,
305cb93a386Sopenharmony_ci};
306cb93a386Sopenharmony_ci
307cb93a386Sopenharmony_cistatic FontFamily* find_family(FamilyData* self, const SkString& familyName)
308cb93a386Sopenharmony_ci{
309cb93a386Sopenharmony_ci    for (int i = 0; i < self->fFamilies.count(); i++) {
310cb93a386Sopenharmony_ci        FontFamily* candidate = self->fFamilies[i];
311cb93a386Sopenharmony_ci        for (int j = 0; j < candidate->fNames.count(); j++) {
312cb93a386Sopenharmony_ci            if (candidate->fNames[j] == familyName) {
313cb93a386Sopenharmony_ci                return candidate;
314cb93a386Sopenharmony_ci            }
315cb93a386Sopenharmony_ci        }
316cb93a386Sopenharmony_ci    }
317cb93a386Sopenharmony_ci    return nullptr;
318cb93a386Sopenharmony_ci}
319cb93a386Sopenharmony_ci
320cb93a386Sopenharmony_cistatic const TagHandler aliasHandler = {
321cb93a386Sopenharmony_ci    /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
322cb93a386Sopenharmony_ci        // 'name' (string) introduces a new family name.
323cb93a386Sopenharmony_ci        // 'to' (string) specifies which (previous) family to alias
324cb93a386Sopenharmony_ci        // 'weight' (non-negative integer) [optional]
325cb93a386Sopenharmony_ci        // If it *does not* have a weight, 'name' is an alias for the entire 'to' family.
326cb93a386Sopenharmony_ci        // If it *does* have a weight, 'name' is a new family consisting of
327cb93a386Sopenharmony_ci        // the font(s) with 'weight' from the 'to' family.
328cb93a386Sopenharmony_ci
329cb93a386Sopenharmony_ci        SkString aliasName;
330cb93a386Sopenharmony_ci        SkString to;
331cb93a386Sopenharmony_ci        int weight = 0;
332cb93a386Sopenharmony_ci        for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
333cb93a386Sopenharmony_ci            const char* name = attributes[i];
334cb93a386Sopenharmony_ci            const char* value = attributes[i + 1];
335cb93a386Sopenharmony_ci            size_t nameLen = strlen(name);
336cb93a386Sopenharmony_ci            if (MEMEQ("name", name, nameLen)) {
337cb93a386Sopenharmony_ci                SkAutoAsciiToLC tolc(value);
338cb93a386Sopenharmony_ci                aliasName.set(tolc.lc());
339cb93a386Sopenharmony_ci            } else if (MEMEQ("to", name, nameLen)) {
340cb93a386Sopenharmony_ci                to.set(value);
341cb93a386Sopenharmony_ci            } else if (MEMEQ("weight", name, nameLen)) {
342cb93a386Sopenharmony_ci                if (!parse_non_negative_integer(value, &weight)) {
343cb93a386Sopenharmony_ci                    SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value);
344cb93a386Sopenharmony_ci                }
345cb93a386Sopenharmony_ci            }
346cb93a386Sopenharmony_ci        }
347cb93a386Sopenharmony_ci
348cb93a386Sopenharmony_ci        // Assumes that the named family is already declared
349cb93a386Sopenharmony_ci        FontFamily* targetFamily = find_family(self, to);
350cb93a386Sopenharmony_ci        if (!targetFamily) {
351cb93a386Sopenharmony_ci            SK_FONTCONFIGPARSER_WARNING("'%s' alias target not found", to.c_str());
352cb93a386Sopenharmony_ci            return;
353cb93a386Sopenharmony_ci        }
354cb93a386Sopenharmony_ci
355cb93a386Sopenharmony_ci        if (weight) {
356cb93a386Sopenharmony_ci            FontFamily* family = new FontFamily(targetFamily->fBasePath, self->fIsFallback);
357cb93a386Sopenharmony_ci            family->fNames.push_back().set(aliasName);
358cb93a386Sopenharmony_ci
359cb93a386Sopenharmony_ci            for (int i = 0; i < targetFamily->fFonts.count(); i++) {
360cb93a386Sopenharmony_ci                if (targetFamily->fFonts[i].fWeight == weight) {
361cb93a386Sopenharmony_ci                    family->fFonts.push_back(targetFamily->fFonts[i]);
362cb93a386Sopenharmony_ci                }
363cb93a386Sopenharmony_ci            }
364cb93a386Sopenharmony_ci            *self->fFamilies.append() = family;
365cb93a386Sopenharmony_ci        } else {
366cb93a386Sopenharmony_ci            targetFamily->fNames.push_back().set(aliasName);
367cb93a386Sopenharmony_ci        }
368cb93a386Sopenharmony_ci    },
369cb93a386Sopenharmony_ci    /*end*/nullptr,
370cb93a386Sopenharmony_ci    /*tag*/nullptr,
371cb93a386Sopenharmony_ci    /*chars*/nullptr,
372cb93a386Sopenharmony_ci};
373cb93a386Sopenharmony_ci
374cb93a386Sopenharmony_cistatic const TagHandler familySetHandler = {
375cb93a386Sopenharmony_ci    /*start*/[](FamilyData* self, const char* tag, const char** attributes) { },
376cb93a386Sopenharmony_ci    /*end*/nullptr,
377cb93a386Sopenharmony_ci    /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
378cb93a386Sopenharmony_ci        size_t len = strlen(tag);
379cb93a386Sopenharmony_ci        if (MEMEQ("family", tag, len)) {
380cb93a386Sopenharmony_ci            return &familyHandler;
381cb93a386Sopenharmony_ci        } else if (MEMEQ("alias", tag, len)) {
382cb93a386Sopenharmony_ci            return &aliasHandler;
383cb93a386Sopenharmony_ci        }
384cb93a386Sopenharmony_ci        return nullptr;
385cb93a386Sopenharmony_ci    },
386cb93a386Sopenharmony_ci    /*chars*/nullptr,
387cb93a386Sopenharmony_ci};
388cb93a386Sopenharmony_ci
389cb93a386Sopenharmony_ci} // namespace lmpParser
390cb93a386Sopenharmony_ci
391cb93a386Sopenharmony_cistatic const TagHandler topLevelHandler = {
392cb93a386Sopenharmony_ci    /*start*/nullptr,
393cb93a386Sopenharmony_ci    /*end*/nullptr,
394cb93a386Sopenharmony_ci    /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
395cb93a386Sopenharmony_ci        size_t len = strlen(tag);
396cb93a386Sopenharmony_ci        if (MEMEQ("familyset", tag, len)) {
397cb93a386Sopenharmony_ci            // 'version' (non-negative integer) [default 0]
398cb93a386Sopenharmony_ci            for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
399cb93a386Sopenharmony_ci                const char* name = attributes[i];
400cb93a386Sopenharmony_ci                size_t nameLen = strlen(name);
401cb93a386Sopenharmony_ci                if (MEMEQ("version", name, nameLen)) {
402cb93a386Sopenharmony_ci                    const char* value = attributes[i + 1];
403cb93a386Sopenharmony_ci                    if (parse_non_negative_integer(value, &self->fVersion)) {
404cb93a386Sopenharmony_ci                        if (self->fVersion >= 21) {
405cb93a386Sopenharmony_ci                            return &lmpParser::familySetHandler;
406cb93a386Sopenharmony_ci                        }
407cb93a386Sopenharmony_ci                    }
408cb93a386Sopenharmony_ci                }
409cb93a386Sopenharmony_ci            }
410cb93a386Sopenharmony_ci        }
411cb93a386Sopenharmony_ci        return nullptr;
412cb93a386Sopenharmony_ci    },
413cb93a386Sopenharmony_ci    /*chars*/ nullptr,
414cb93a386Sopenharmony_ci};
415cb93a386Sopenharmony_ci
416cb93a386Sopenharmony_cistatic void XMLCALL start_element_handler(void *data, const char *tag, const char **attributes)
417cb93a386Sopenharmony_ci{
418cb93a386Sopenharmony_ci    FamilyData* self = static_cast<FamilyData*>(data);
419cb93a386Sopenharmony_ci
420cb93a386Sopenharmony_ci    if (!self->fSkip) {
421cb93a386Sopenharmony_ci        const TagHandler* parent = self->fHandler.top();
422cb93a386Sopenharmony_ci        const TagHandler* child = parent->tag ? parent->tag(self, tag, attributes) : nullptr;
423cb93a386Sopenharmony_ci        if (child) {
424cb93a386Sopenharmony_ci            if (child->start) {
425cb93a386Sopenharmony_ci                child->start(self, tag, attributes);
426cb93a386Sopenharmony_ci            }
427cb93a386Sopenharmony_ci            self->fHandler.push_back(child);
428cb93a386Sopenharmony_ci            XML_SetCharacterDataHandler(self->fParser, child->chars);
429cb93a386Sopenharmony_ci        } else {
430cb93a386Sopenharmony_ci            SK_FONTCONFIGPARSER_WARNING("'%s' tag not recognized, skipping", tag);
431cb93a386Sopenharmony_ci            XML_SetCharacterDataHandler(self->fParser, nullptr);
432cb93a386Sopenharmony_ci            self->fSkip = self->fDepth;
433cb93a386Sopenharmony_ci        }
434cb93a386Sopenharmony_ci    }
435cb93a386Sopenharmony_ci
436cb93a386Sopenharmony_ci    ++self->fDepth;
437cb93a386Sopenharmony_ci}
438cb93a386Sopenharmony_ci
439cb93a386Sopenharmony_cistatic void XMLCALL end_element_handler(void* data, const char* tag)
440cb93a386Sopenharmony_ci{
441cb93a386Sopenharmony_ci    FamilyData* self = static_cast<FamilyData*>(data);
442cb93a386Sopenharmony_ci    --self->fDepth;
443cb93a386Sopenharmony_ci
444cb93a386Sopenharmony_ci    if (!self->fSkip) {
445cb93a386Sopenharmony_ci        const TagHandler* child = self->fHandler.top();
446cb93a386Sopenharmony_ci        if (child->end) {
447cb93a386Sopenharmony_ci            child->end(self, tag);
448cb93a386Sopenharmony_ci        }
449cb93a386Sopenharmony_ci        self->fHandler.pop();
450cb93a386Sopenharmony_ci        const TagHandler* parent = self->fHandler.top();
451cb93a386Sopenharmony_ci        XML_SetCharacterDataHandler(self->fParser, parent->chars);
452cb93a386Sopenharmony_ci    }
453cb93a386Sopenharmony_ci
454cb93a386Sopenharmony_ci    if (self->fSkip == self->fDepth) {
455cb93a386Sopenharmony_ci        self->fSkip = 0;
456cb93a386Sopenharmony_ci        const TagHandler* parent = self->fHandler.top();
457cb93a386Sopenharmony_ci        XML_SetCharacterDataHandler(self->fParser, parent->chars);
458cb93a386Sopenharmony_ci    }
459cb93a386Sopenharmony_ci}
460cb93a386Sopenharmony_ci
461cb93a386Sopenharmony_cistatic void XMLCALL xml_entity_decl_handler(void *data,
462cb93a386Sopenharmony_ci                                            const XML_Char *entityName,
463cb93a386Sopenharmony_ci                                            int is_parameter_entity,
464cb93a386Sopenharmony_ci                                            const XML_Char *value,
465cb93a386Sopenharmony_ci                                            int value_length,
466cb93a386Sopenharmony_ci                                            const XML_Char *base,
467cb93a386Sopenharmony_ci                                            const XML_Char *systemId,
468cb93a386Sopenharmony_ci                                            const XML_Char *publicId,
469cb93a386Sopenharmony_ci                                            const XML_Char *notationName)
470cb93a386Sopenharmony_ci{
471cb93a386Sopenharmony_ci    FamilyData* self = static_cast<FamilyData*>(data);
472cb93a386Sopenharmony_ci    SK_FONTCONFIGPARSER_WARNING("'%s' entity declaration found, stopping processing", entityName);
473cb93a386Sopenharmony_ci    XML_StopParser(self->fParser, XML_FALSE);
474cb93a386Sopenharmony_ci}
475cb93a386Sopenharmony_ci
476cb93a386Sopenharmony_cistatic const XML_Memory_Handling_Suite sk_XML_alloc = {
477cb93a386Sopenharmony_ci    sk_malloc_throw,
478cb93a386Sopenharmony_ci    sk_realloc_throw,
479cb93a386Sopenharmony_ci    sk_free
480cb93a386Sopenharmony_ci};
481cb93a386Sopenharmony_ci
482cb93a386Sopenharmony_ci/**
483cb93a386Sopenharmony_ci * This function parses the given filename and stores the results in the given
484cb93a386Sopenharmony_ci * families array. Returns the version of the file, negative if the file does not exist.
485cb93a386Sopenharmony_ci */
486cb93a386Sopenharmony_cistatic int parse_config_file(const char* filename, SkTDArray<FontFamily*>& families,
487cb93a386Sopenharmony_ci                             const SkString& basePath, bool isFallback)
488cb93a386Sopenharmony_ci{
489cb93a386Sopenharmony_ci    SkFILEStream file(filename);
490cb93a386Sopenharmony_ci
491cb93a386Sopenharmony_ci    // Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml)
492cb93a386Sopenharmony_ci    // are optional - failure here is okay because one of these optional files may not exist.
493cb93a386Sopenharmony_ci    if (!file.isValid()) {
494cb93a386Sopenharmony_ci        SkDebugf(SK_FONTMGR_CONFIG_PARSER_PREFIX "'%s' could not be opened\n", filename);
495cb93a386Sopenharmony_ci        return -1;
496cb93a386Sopenharmony_ci    }
497cb93a386Sopenharmony_ci
498cb93a386Sopenharmony_ci    SkAutoTCallVProc<std::remove_pointer_t<XML_Parser>, XML_ParserFree> parser(
499cb93a386Sopenharmony_ci        XML_ParserCreate_MM(nullptr, &sk_XML_alloc, nullptr));
500cb93a386Sopenharmony_ci    if (!parser) {
501cb93a386Sopenharmony_ci        SkDebugf(SK_FONTMGR_CONFIG_PARSER_PREFIX "could not create XML parser\n");
502cb93a386Sopenharmony_ci        return -1;
503cb93a386Sopenharmony_ci    }
504cb93a386Sopenharmony_ci
505cb93a386Sopenharmony_ci    FamilyData self(parser, families, basePath, isFallback, filename, &topLevelHandler);
506cb93a386Sopenharmony_ci    XML_SetUserData(parser, &self);
507cb93a386Sopenharmony_ci
508cb93a386Sopenharmony_ci    // Disable entity processing, to inhibit internal entity expansion. See expat CVE-2013-0340
509cb93a386Sopenharmony_ci    XML_SetEntityDeclHandler(parser, xml_entity_decl_handler);
510cb93a386Sopenharmony_ci
511cb93a386Sopenharmony_ci    // Start parsing oldschool; switch these in flight if we detect a newer version of the file.
512cb93a386Sopenharmony_ci    XML_SetElementHandler(parser, start_element_handler, end_element_handler);
513cb93a386Sopenharmony_ci
514cb93a386Sopenharmony_ci    // One would assume it would be faster to have a buffer on the stack and call XML_Parse.
515cb93a386Sopenharmony_ci    // But XML_Parse will call XML_GetBuffer anyway and memmove the passed buffer into it.
516cb93a386Sopenharmony_ci    // (Unless XML_CONTEXT_BYTES is undefined, but all users define it.)
517cb93a386Sopenharmony_ci    // In debug, buffer a small odd number of bytes to detect slicing in XML_CharacterDataHandler.
518cb93a386Sopenharmony_ci    static const int bufferSize = 512 SkDEBUGCODE(-507);
519cb93a386Sopenharmony_ci    bool done = false;
520cb93a386Sopenharmony_ci    while (!done) {
521cb93a386Sopenharmony_ci        void* buffer = XML_GetBuffer(parser, bufferSize);
522cb93a386Sopenharmony_ci        if (!buffer) {
523cb93a386Sopenharmony_ci            SkDebugf(SK_FONTMGR_CONFIG_PARSER_PREFIX "could not buffer enough to continue\n");
524cb93a386Sopenharmony_ci            return -1;
525cb93a386Sopenharmony_ci        }
526cb93a386Sopenharmony_ci        size_t len = file.read(buffer, bufferSize);
527cb93a386Sopenharmony_ci        done = file.isAtEnd();
528cb93a386Sopenharmony_ci        XML_Status status = XML_ParseBuffer(parser, len, done);
529cb93a386Sopenharmony_ci        if (XML_STATUS_ERROR == status) {
530cb93a386Sopenharmony_ci            XML_Error error = XML_GetErrorCode(parser);
531cb93a386Sopenharmony_ci            int line = XML_GetCurrentLineNumber(parser);
532cb93a386Sopenharmony_ci            int column = XML_GetCurrentColumnNumber(parser);
533cb93a386Sopenharmony_ci            const XML_LChar* errorString = XML_ErrorString(error);
534cb93a386Sopenharmony_ci            SkDebugf(SK_FONTMGR_CONFIG_PARSER_PREFIX "%s:%d:%d error %d: %s.\n",
535cb93a386Sopenharmony_ci                     filename, line, column, error, errorString);
536cb93a386Sopenharmony_ci            return -1;
537cb93a386Sopenharmony_ci        }
538cb93a386Sopenharmony_ci    }
539cb93a386Sopenharmony_ci    return self.fVersion;
540cb93a386Sopenharmony_ci}
541cb93a386Sopenharmony_ci
542cb93a386Sopenharmony_ci/** Returns the version of the system font file actually found, negative if none. */
543cb93a386Sopenharmony_cistatic int append_system_font_families(SkTDArray<FontFamily*>& fontFamilies,
544cb93a386Sopenharmony_ci                                       const SkString& basePath)
545cb93a386Sopenharmony_ci{
546cb93a386Sopenharmony_ci    int version = parse_config_file(g_lmpSystemFontsFile.c_str(), fontFamilies, basePath, false);
547cb93a386Sopenharmony_ci    return version;
548cb93a386Sopenharmony_ci}
549cb93a386Sopenharmony_ci
550cb93a386Sopenharmony_civoid SkFontMgr_Config_Parser::GetSystemFontFamilies(SkTDArray<FontFamily*>& fontFamilies)
551cb93a386Sopenharmony_ci{
552cb93a386Sopenharmony_ci    std::string containerFontBasePath = SkFontMgr::containerFontPath;
553cb93a386Sopenharmony_ci    if (containerFontBasePath.empty()) {
554cb93a386Sopenharmony_ci        printf("error getting font base path '%s'\n", containerFontBasePath.c_str());
555cb93a386Sopenharmony_ci    }
556cb93a386Sopenharmony_ci    SkString basePath(containerFontBasePath.c_str());
557cb93a386Sopenharmony_ci    g_lmpSystemFontsFile = containerFontBasePath.append(SK_FONT_CONFIG_FILE_NAME);
558cb93a386Sopenharmony_ci    HmSymbolConfig_OHOS::GetInstance()->ParseConfigOfHmSymbol("hm_symbol_config_next.json", basePath);
559cb93a386Sopenharmony_ci    append_system_font_families(fontFamilies, basePath);
560cb93a386Sopenharmony_ci}
561cb93a386Sopenharmony_ci
562cb93a386Sopenharmony_ciSkLanguage SkLanguage::getParent() const
563cb93a386Sopenharmony_ci{
564cb93a386Sopenharmony_ci    SkASSERT(!fTag.isEmpty());
565cb93a386Sopenharmony_ci    const char* tag = fTag.c_str();
566cb93a386Sopenharmony_ci
567cb93a386Sopenharmony_ci    // strip off the rightmost "-.*"
568cb93a386Sopenharmony_ci    const char* parentTagEnd = strrchr(tag, '-');
569cb93a386Sopenharmony_ci    if (parentTagEnd == nullptr) {
570cb93a386Sopenharmony_ci        return SkLanguage();
571cb93a386Sopenharmony_ci    }
572cb93a386Sopenharmony_ci    size_t parentTagLen = parentTagEnd - tag;
573cb93a386Sopenharmony_ci    return SkLanguage(tag, parentTagLen);
574cb93a386Sopenharmony_ci}