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}