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 */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci// Despite the name and location, this is portable code. 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkFontMgr.h" 11cb93a386Sopenharmony_ci#include "include/core/SkStream.h" 12cb93a386Sopenharmony_ci#include "include/private/SkFixed.h" 13cb93a386Sopenharmony_ci#include "include/private/SkMalloc.h" 14cb93a386Sopenharmony_ci#include "include/private/SkTDArray.h" 15cb93a386Sopenharmony_ci#include "include/private/SkTLogic.h" 16cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 17cb93a386Sopenharmony_ci#include "src/core/SkOSFile.h" 18cb93a386Sopenharmony_ci#include "src/core/SkTSearch.h" 19cb93a386Sopenharmony_ci#include "src/ports/SkFontMgr_android_parser.h" 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci#include <expat.h> 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci#include <stdlib.h> 24cb93a386Sopenharmony_ci#include <string.h> 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci#include <memory> 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ci#define LMP_SYSTEM_FONTS_FILE "/system/etc/fonts.xml" 29cb93a386Sopenharmony_ci#define OLD_SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" 30cb93a386Sopenharmony_ci#define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" 31cb93a386Sopenharmony_ci#define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci#define LOCALE_FALLBACK_FONTS_SYSTEM_DIR "/system/etc" 34cb93a386Sopenharmony_ci#define LOCALE_FALLBACK_FONTS_VENDOR_DIR "/vendor/etc" 35cb93a386Sopenharmony_ci#define LOCALE_FALLBACK_FONTS_PREFIX "fallback_fonts-" 36cb93a386Sopenharmony_ci#define LOCALE_FALLBACK_FONTS_SUFFIX ".xml" 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci#ifndef SK_FONT_FILE_PREFIX 39cb93a386Sopenharmony_ci# define SK_FONT_FILE_PREFIX "/fonts/" 40cb93a386Sopenharmony_ci#endif 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci/** 43cb93a386Sopenharmony_ci * This file contains TWO 'familyset' handlers: 44cb93a386Sopenharmony_ci * One for JB and earlier which works with 45cb93a386Sopenharmony_ci * /system/etc/system_fonts.xml 46cb93a386Sopenharmony_ci * /system/etc/fallback_fonts.xml 47cb93a386Sopenharmony_ci * /vendor/etc/fallback_fonts.xml 48cb93a386Sopenharmony_ci * /system/etc/fallback_fonts-XX.xml 49cb93a386Sopenharmony_ci * /vendor/etc/fallback_fonts-XX.xml 50cb93a386Sopenharmony_ci * and the other for LMP and later which works with 51cb93a386Sopenharmony_ci * /system/etc/fonts.xml 52cb93a386Sopenharmony_ci * 53cb93a386Sopenharmony_ci * If the 'familyset' 'version' attribute is 21 or higher the LMP parser is used, otherwise the JB. 54cb93a386Sopenharmony_ci */ 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_cistruct FamilyData; 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_cistruct TagHandler { 59cb93a386Sopenharmony_ci /** Called at the start tag. 60cb93a386Sopenharmony_ci * Called immediately after the parent tag retuns this handler from a call to 'tag'. 61cb93a386Sopenharmony_ci * Allows setting up for handling the tag content and processing attributes. 62cb93a386Sopenharmony_ci * If nullptr, will not be called. 63cb93a386Sopenharmony_ci */ 64cb93a386Sopenharmony_ci void (*start)(FamilyData* data, const char* tag, const char** attributes); 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ci /** Called at the end tag. 67cb93a386Sopenharmony_ci * Allows post-processing of any accumulated information. 68cb93a386Sopenharmony_ci * This will be the last call made in relation to the current tag. 69cb93a386Sopenharmony_ci * If nullptr, will not be called. 70cb93a386Sopenharmony_ci */ 71cb93a386Sopenharmony_ci void (*end)(FamilyData* data, const char* tag); 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_ci /** Called when a nested tag is encountered. 74cb93a386Sopenharmony_ci * This is responsible for determining how to handle the tag. 75cb93a386Sopenharmony_ci * If the tag is not recognized, return nullptr to skip the tag. 76cb93a386Sopenharmony_ci * If nullptr, all nested tags will be skipped. 77cb93a386Sopenharmony_ci */ 78cb93a386Sopenharmony_ci const TagHandler* (*tag)(FamilyData* data, const char* tag, const char** attributes); 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci /** The character handler for this tag. 81cb93a386Sopenharmony_ci * This is only active for character data contained directly in this tag (not sub-tags). 82cb93a386Sopenharmony_ci * The first parameter will be castable to a FamilyData*. 83cb93a386Sopenharmony_ci * If nullptr, any character data in this tag will be ignored. 84cb93a386Sopenharmony_ci */ 85cb93a386Sopenharmony_ci XML_CharacterDataHandler chars; 86cb93a386Sopenharmony_ci}; 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ci/** Represents the current parsing state. */ 89cb93a386Sopenharmony_cistruct FamilyData { 90cb93a386Sopenharmony_ci FamilyData(XML_Parser parser, SkTDArray<FontFamily*>& families, 91cb93a386Sopenharmony_ci const SkString& basePath, bool isFallback, const char* filename, 92cb93a386Sopenharmony_ci const TagHandler* topLevelHandler) 93cb93a386Sopenharmony_ci : fParser(parser) 94cb93a386Sopenharmony_ci , fFamilies(families) 95cb93a386Sopenharmony_ci , fCurrentFamily(nullptr) 96cb93a386Sopenharmony_ci , fCurrentFontInfo(nullptr) 97cb93a386Sopenharmony_ci , fVersion(0) 98cb93a386Sopenharmony_ci , fBasePath(basePath) 99cb93a386Sopenharmony_ci , fIsFallback(isFallback) 100cb93a386Sopenharmony_ci , fFilename(filename) 101cb93a386Sopenharmony_ci , fDepth(1) 102cb93a386Sopenharmony_ci , fSkip(0) 103cb93a386Sopenharmony_ci , fHandler(&topLevelHandler, 1) 104cb93a386Sopenharmony_ci { } 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ci XML_Parser fParser; // The expat parser doing the work, owned by caller 107cb93a386Sopenharmony_ci SkTDArray<FontFamily*>& fFamilies; // The array to append families, owned by caller 108cb93a386Sopenharmony_ci std::unique_ptr<FontFamily> fCurrentFamily; // The family being created, owned by this 109cb93a386Sopenharmony_ci FontFileInfo* fCurrentFontInfo; // The info being created, owned by fCurrentFamily 110cb93a386Sopenharmony_ci int fVersion; // The version of the file parsed. 111cb93a386Sopenharmony_ci const SkString& fBasePath; // The current base path. 112cb93a386Sopenharmony_ci const bool fIsFallback; // The file being parsed is a fallback file 113cb93a386Sopenharmony_ci const char* fFilename; // The name of the file currently being parsed. 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_ci int fDepth; // The current element depth of the parse. 116cb93a386Sopenharmony_ci int fSkip; // The depth to stop skipping, 0 if not skipping. 117cb93a386Sopenharmony_ci SkTDArray<const TagHandler*> fHandler; // The stack of current tag handlers. 118cb93a386Sopenharmony_ci}; 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_cistatic bool memeq(const char* s1, const char* s2, size_t n1, size_t n2) { 121cb93a386Sopenharmony_ci return n1 == n2 && 0 == memcmp(s1, s2, n1); 122cb93a386Sopenharmony_ci} 123cb93a386Sopenharmony_ci#define MEMEQ(c, s, n) memeq(c, s, sizeof(c) - 1, n) 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ci#define ATTS_NON_NULL(a, i) (a[i] != nullptr && a[i+1] != nullptr) 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_ci#define SK_FONTMGR_ANDROID_PARSER_PREFIX "[SkFontMgr Android Parser] " 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci#define SK_FONTCONFIGPARSER_WARNING(message, ...) \ 130cb93a386Sopenharmony_ci SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "%s:%d:%d: warning: " message "\n", \ 131cb93a386Sopenharmony_ci self->fFilename, \ 132cb93a386Sopenharmony_ci (int)XML_GetCurrentLineNumber(self->fParser), \ 133cb93a386Sopenharmony_ci (int)XML_GetCurrentColumnNumber(self->fParser), \ 134cb93a386Sopenharmony_ci ##__VA_ARGS__) 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_cistatic bool is_whitespace(char c) { 137cb93a386Sopenharmony_ci return c == ' ' || c == '\n'|| c == '\r' || c == '\t'; 138cb93a386Sopenharmony_ci} 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_cistatic void trim_string(SkString* s) { 141cb93a386Sopenharmony_ci char* str = s->writable_str(); 142cb93a386Sopenharmony_ci const char* start = str; // start is inclusive 143cb93a386Sopenharmony_ci const char* end = start + s->size(); // end is exclusive 144cb93a386Sopenharmony_ci while (is_whitespace(*start)) { ++start; } 145cb93a386Sopenharmony_ci if (start != end) { 146cb93a386Sopenharmony_ci --end; // make end inclusive 147cb93a386Sopenharmony_ci while (is_whitespace(*end)) { --end; } 148cb93a386Sopenharmony_ci ++end; // make end exclusive 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci size_t len = end - start; 151cb93a386Sopenharmony_ci memmove(str, start, len); 152cb93a386Sopenharmony_ci s->resize(len); 153cb93a386Sopenharmony_ci} 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_cistatic void parse_space_separated_languages(const char* value, size_t valueLen, 156cb93a386Sopenharmony_ci SkTArray<SkLanguage, true>& languages) 157cb93a386Sopenharmony_ci{ 158cb93a386Sopenharmony_ci size_t i = 0; 159cb93a386Sopenharmony_ci while (true) { 160cb93a386Sopenharmony_ci for (; i < valueLen && is_whitespace(value[i]); ++i) { } 161cb93a386Sopenharmony_ci if (i == valueLen) { break; } 162cb93a386Sopenharmony_ci size_t j; 163cb93a386Sopenharmony_ci for (j = i + 1; j < valueLen && !is_whitespace(value[j]); ++j) { } 164cb93a386Sopenharmony_ci languages.emplace_back(value + i, j - i); 165cb93a386Sopenharmony_ci i = j; 166cb93a386Sopenharmony_ci if (i == valueLen) { break; } 167cb93a386Sopenharmony_ci } 168cb93a386Sopenharmony_ci} 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_cinamespace lmpParser { 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_cistatic const TagHandler axisHandler = { 173cb93a386Sopenharmony_ci /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 174cb93a386Sopenharmony_ci FontFileInfo& file = *self->fCurrentFontInfo; 175cb93a386Sopenharmony_ci SkFourByteTag axisTag = SkSetFourByteTag('\0','\0','\0','\0'); 176cb93a386Sopenharmony_ci SkFixed axisStyleValue = 0; 177cb93a386Sopenharmony_ci bool axisTagIsValid = false; 178cb93a386Sopenharmony_ci bool axisStyleValueIsValid = false; 179cb93a386Sopenharmony_ci for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 180cb93a386Sopenharmony_ci const char* name = attributes[i]; 181cb93a386Sopenharmony_ci const char* value = attributes[i+1]; 182cb93a386Sopenharmony_ci size_t nameLen = strlen(name); 183cb93a386Sopenharmony_ci if (MEMEQ("tag", name, nameLen)) { 184cb93a386Sopenharmony_ci size_t valueLen = strlen(value); 185cb93a386Sopenharmony_ci if (valueLen == 4) { 186cb93a386Sopenharmony_ci axisTag = SkSetFourByteTag(value[0], value[1], value[2], value[3]); 187cb93a386Sopenharmony_ci axisTagIsValid = true; 188cb93a386Sopenharmony_ci for (int j = 0; j < file.fVariationDesignPosition.count() - 1; ++j) { 189cb93a386Sopenharmony_ci if (file.fVariationDesignPosition[j].axis == axisTag) { 190cb93a386Sopenharmony_ci axisTagIsValid = false; 191cb93a386Sopenharmony_ci SK_FONTCONFIGPARSER_WARNING("'%c%c%c%c' axis specified more than once", 192cb93a386Sopenharmony_ci (axisTag >> 24) & 0xFF, 193cb93a386Sopenharmony_ci (axisTag >> 16) & 0xFF, 194cb93a386Sopenharmony_ci (axisTag >> 8) & 0xFF, 195cb93a386Sopenharmony_ci (axisTag ) & 0xFF); 196cb93a386Sopenharmony_ci } 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci } else { 199cb93a386Sopenharmony_ci SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid axis tag", value); 200cb93a386Sopenharmony_ci } 201cb93a386Sopenharmony_ci } else if (MEMEQ("stylevalue", name, nameLen)) { 202cb93a386Sopenharmony_ci if (parse_fixed<16>(value, &axisStyleValue)) { 203cb93a386Sopenharmony_ci axisStyleValueIsValid = true; 204cb93a386Sopenharmony_ci } else { 205cb93a386Sopenharmony_ci SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid axis stylevalue", value); 206cb93a386Sopenharmony_ci } 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci } 209cb93a386Sopenharmony_ci if (axisTagIsValid && axisStyleValueIsValid) { 210cb93a386Sopenharmony_ci auto& coordinate = file.fVariationDesignPosition.push_back(); 211cb93a386Sopenharmony_ci coordinate.axis = axisTag; 212cb93a386Sopenharmony_ci coordinate.value = SkFixedToScalar(axisStyleValue); 213cb93a386Sopenharmony_ci } 214cb93a386Sopenharmony_ci }, 215cb93a386Sopenharmony_ci /*end*/nullptr, 216cb93a386Sopenharmony_ci /*tag*/nullptr, 217cb93a386Sopenharmony_ci /*chars*/nullptr, 218cb93a386Sopenharmony_ci}; 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_cistatic const TagHandler fontHandler = { 221cb93a386Sopenharmony_ci /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 222cb93a386Sopenharmony_ci // 'weight' (non-negative integer) [default 0] 223cb93a386Sopenharmony_ci // 'style' ("normal", "italic") [default "auto"] 224cb93a386Sopenharmony_ci // 'index' (non-negative integer) [default 0] 225cb93a386Sopenharmony_ci // The character data should be a filename. 226cb93a386Sopenharmony_ci FontFileInfo& file = self->fCurrentFamily->fFonts.push_back(); 227cb93a386Sopenharmony_ci self->fCurrentFontInfo = &file; 228cb93a386Sopenharmony_ci SkString fallbackFor; 229cb93a386Sopenharmony_ci for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 230cb93a386Sopenharmony_ci const char* name = attributes[i]; 231cb93a386Sopenharmony_ci const char* value = attributes[i+1]; 232cb93a386Sopenharmony_ci size_t nameLen = strlen(name); 233cb93a386Sopenharmony_ci if (MEMEQ("weight", name, nameLen)) { 234cb93a386Sopenharmony_ci if (!parse_non_negative_integer(value, &file.fWeight)) { 235cb93a386Sopenharmony_ci SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value); 236cb93a386Sopenharmony_ci } 237cb93a386Sopenharmony_ci } else if (MEMEQ("style", name, nameLen)) { 238cb93a386Sopenharmony_ci size_t valueLen = strlen(value); 239cb93a386Sopenharmony_ci if (MEMEQ("normal", value, valueLen)) { 240cb93a386Sopenharmony_ci file.fStyle = FontFileInfo::Style::kNormal; 241cb93a386Sopenharmony_ci } else if (MEMEQ("italic", value, valueLen)) { 242cb93a386Sopenharmony_ci file.fStyle = FontFileInfo::Style::kItalic; 243cb93a386Sopenharmony_ci } 244cb93a386Sopenharmony_ci } else if (MEMEQ("index", name, nameLen)) { 245cb93a386Sopenharmony_ci if (!parse_non_negative_integer(value, &file.fIndex)) { 246cb93a386Sopenharmony_ci SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value); 247cb93a386Sopenharmony_ci } 248cb93a386Sopenharmony_ci } else if (MEMEQ("fallbackFor", name, nameLen)) { 249cb93a386Sopenharmony_ci /** fallbackFor specifies a family fallback and should have been on family. */ 250cb93a386Sopenharmony_ci fallbackFor = value; 251cb93a386Sopenharmony_ci } 252cb93a386Sopenharmony_ci } 253cb93a386Sopenharmony_ci if (!fallbackFor.isEmpty()) { 254cb93a386Sopenharmony_ci std::unique_ptr<FontFamily>* fallbackFamily = 255cb93a386Sopenharmony_ci self->fCurrentFamily->fallbackFamilies.find(fallbackFor); 256cb93a386Sopenharmony_ci if (!fallbackFamily) { 257cb93a386Sopenharmony_ci std::unique_ptr<FontFamily> newFallbackFamily( 258cb93a386Sopenharmony_ci new FontFamily(self->fCurrentFamily->fBasePath, true)); 259cb93a386Sopenharmony_ci fallbackFamily = self->fCurrentFamily->fallbackFamilies.set( 260cb93a386Sopenharmony_ci fallbackFor, std::move(newFallbackFamily)); 261cb93a386Sopenharmony_ci (*fallbackFamily)->fLanguages = self->fCurrentFamily->fLanguages; 262cb93a386Sopenharmony_ci (*fallbackFamily)->fVariant = self->fCurrentFamily->fVariant; 263cb93a386Sopenharmony_ci (*fallbackFamily)->fOrder = self->fCurrentFamily->fOrder; 264cb93a386Sopenharmony_ci (*fallbackFamily)->fFallbackFor = fallbackFor; 265cb93a386Sopenharmony_ci } 266cb93a386Sopenharmony_ci self->fCurrentFontInfo = &(*fallbackFamily)->fFonts.emplace_back(file); 267cb93a386Sopenharmony_ci self->fCurrentFamily->fFonts.pop_back(); 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci }, 270cb93a386Sopenharmony_ci /*end*/[](FamilyData* self, const char* tag) { 271cb93a386Sopenharmony_ci trim_string(&self->fCurrentFontInfo->fFileName); 272cb93a386Sopenharmony_ci }, 273cb93a386Sopenharmony_ci /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 274cb93a386Sopenharmony_ci size_t len = strlen(tag); 275cb93a386Sopenharmony_ci if (MEMEQ("axis", tag, len)) { 276cb93a386Sopenharmony_ci return &axisHandler; 277cb93a386Sopenharmony_ci } 278cb93a386Sopenharmony_ci return nullptr; 279cb93a386Sopenharmony_ci }, 280cb93a386Sopenharmony_ci /*chars*/[](void* data, const char* s, int len) { 281cb93a386Sopenharmony_ci FamilyData* self = static_cast<FamilyData*>(data); 282cb93a386Sopenharmony_ci self->fCurrentFontInfo->fFileName.append(s, len); 283cb93a386Sopenharmony_ci } 284cb93a386Sopenharmony_ci}; 285cb93a386Sopenharmony_ci 286cb93a386Sopenharmony_cistatic const TagHandler familyHandler = { 287cb93a386Sopenharmony_ci /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 288cb93a386Sopenharmony_ci // 'name' (string) [optional] 289cb93a386Sopenharmony_ci // 'lang' (space separated string) [default ""] 290cb93a386Sopenharmony_ci // 'variant' ("elegant", "compact") [default "default"] 291cb93a386Sopenharmony_ci // If there is no name, this is a fallback only font. 292cb93a386Sopenharmony_ci FontFamily* family = new FontFamily(self->fBasePath, true); 293cb93a386Sopenharmony_ci self->fCurrentFamily.reset(family); 294cb93a386Sopenharmony_ci for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 295cb93a386Sopenharmony_ci const char* name = attributes[i]; 296cb93a386Sopenharmony_ci const char* value = attributes[i+1]; 297cb93a386Sopenharmony_ci size_t nameLen = strlen(name); 298cb93a386Sopenharmony_ci size_t valueLen = strlen(value); 299cb93a386Sopenharmony_ci if (MEMEQ("name", name, nameLen)) { 300cb93a386Sopenharmony_ci SkAutoAsciiToLC tolc(value); 301cb93a386Sopenharmony_ci family->fNames.push_back().set(tolc.lc()); 302cb93a386Sopenharmony_ci family->fIsFallbackFont = false; 303cb93a386Sopenharmony_ci } else if (MEMEQ("lang", name, nameLen)) { 304cb93a386Sopenharmony_ci parse_space_separated_languages(value, valueLen, family->fLanguages); 305cb93a386Sopenharmony_ci } else if (MEMEQ("variant", name, nameLen)) { 306cb93a386Sopenharmony_ci if (MEMEQ("elegant", value, valueLen)) { 307cb93a386Sopenharmony_ci family->fVariant = kElegant_FontVariant; 308cb93a386Sopenharmony_ci } else if (MEMEQ("compact", value, valueLen)) { 309cb93a386Sopenharmony_ci family->fVariant = kCompact_FontVariant; 310cb93a386Sopenharmony_ci } 311cb93a386Sopenharmony_ci } 312cb93a386Sopenharmony_ci } 313cb93a386Sopenharmony_ci }, 314cb93a386Sopenharmony_ci /*end*/[](FamilyData* self, const char* tag) { 315cb93a386Sopenharmony_ci *self->fFamilies.append() = self->fCurrentFamily.release(); 316cb93a386Sopenharmony_ci }, 317cb93a386Sopenharmony_ci /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 318cb93a386Sopenharmony_ci size_t len = strlen(tag); 319cb93a386Sopenharmony_ci if (MEMEQ("font", tag, len)) { 320cb93a386Sopenharmony_ci return &fontHandler; 321cb93a386Sopenharmony_ci } 322cb93a386Sopenharmony_ci return nullptr; 323cb93a386Sopenharmony_ci }, 324cb93a386Sopenharmony_ci /*chars*/nullptr, 325cb93a386Sopenharmony_ci}; 326cb93a386Sopenharmony_ci 327cb93a386Sopenharmony_cistatic FontFamily* find_family(FamilyData* self, const SkString& familyName) { 328cb93a386Sopenharmony_ci for (int i = 0; i < self->fFamilies.count(); i++) { 329cb93a386Sopenharmony_ci FontFamily* candidate = self->fFamilies[i]; 330cb93a386Sopenharmony_ci for (int j = 0; j < candidate->fNames.count(); j++) { 331cb93a386Sopenharmony_ci if (candidate->fNames[j] == familyName) { 332cb93a386Sopenharmony_ci return candidate; 333cb93a386Sopenharmony_ci } 334cb93a386Sopenharmony_ci } 335cb93a386Sopenharmony_ci } 336cb93a386Sopenharmony_ci return nullptr; 337cb93a386Sopenharmony_ci} 338cb93a386Sopenharmony_ci 339cb93a386Sopenharmony_cistatic const TagHandler aliasHandler = { 340cb93a386Sopenharmony_ci /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 341cb93a386Sopenharmony_ci // 'name' (string) introduces a new family name. 342cb93a386Sopenharmony_ci // 'to' (string) specifies which (previous) family to alias 343cb93a386Sopenharmony_ci // 'weight' (non-negative integer) [optional] 344cb93a386Sopenharmony_ci // If it *does not* have a weight, 'name' is an alias for the entire 'to' family. 345cb93a386Sopenharmony_ci // If it *does* have a weight, 'name' is a new family consisting of 346cb93a386Sopenharmony_ci // the font(s) with 'weight' from the 'to' family. 347cb93a386Sopenharmony_ci 348cb93a386Sopenharmony_ci SkString aliasName; 349cb93a386Sopenharmony_ci SkString to; 350cb93a386Sopenharmony_ci int weight = 0; 351cb93a386Sopenharmony_ci for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 352cb93a386Sopenharmony_ci const char* name = attributes[i]; 353cb93a386Sopenharmony_ci const char* value = attributes[i+1]; 354cb93a386Sopenharmony_ci size_t nameLen = strlen(name); 355cb93a386Sopenharmony_ci if (MEMEQ("name", name, nameLen)) { 356cb93a386Sopenharmony_ci SkAutoAsciiToLC tolc(value); 357cb93a386Sopenharmony_ci aliasName.set(tolc.lc()); 358cb93a386Sopenharmony_ci } else if (MEMEQ("to", name, nameLen)) { 359cb93a386Sopenharmony_ci to.set(value); 360cb93a386Sopenharmony_ci } else if (MEMEQ("weight", name, nameLen)) { 361cb93a386Sopenharmony_ci if (!parse_non_negative_integer(value, &weight)) { 362cb93a386Sopenharmony_ci SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value); 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci } 365cb93a386Sopenharmony_ci } 366cb93a386Sopenharmony_ci 367cb93a386Sopenharmony_ci // Assumes that the named family is already declared 368cb93a386Sopenharmony_ci FontFamily* targetFamily = find_family(self, to); 369cb93a386Sopenharmony_ci if (!targetFamily) { 370cb93a386Sopenharmony_ci SK_FONTCONFIGPARSER_WARNING("'%s' alias target not found", to.c_str()); 371cb93a386Sopenharmony_ci return; 372cb93a386Sopenharmony_ci } 373cb93a386Sopenharmony_ci 374cb93a386Sopenharmony_ci if (weight) { 375cb93a386Sopenharmony_ci FontFamily* family = new FontFamily(targetFamily->fBasePath, self->fIsFallback); 376cb93a386Sopenharmony_ci family->fNames.push_back().set(aliasName); 377cb93a386Sopenharmony_ci 378cb93a386Sopenharmony_ci for (int i = 0; i < targetFamily->fFonts.count(); i++) { 379cb93a386Sopenharmony_ci if (targetFamily->fFonts[i].fWeight == weight) { 380cb93a386Sopenharmony_ci family->fFonts.push_back(targetFamily->fFonts[i]); 381cb93a386Sopenharmony_ci } 382cb93a386Sopenharmony_ci } 383cb93a386Sopenharmony_ci *self->fFamilies.append() = family; 384cb93a386Sopenharmony_ci } else { 385cb93a386Sopenharmony_ci targetFamily->fNames.push_back().set(aliasName); 386cb93a386Sopenharmony_ci } 387cb93a386Sopenharmony_ci }, 388cb93a386Sopenharmony_ci /*end*/nullptr, 389cb93a386Sopenharmony_ci /*tag*/nullptr, 390cb93a386Sopenharmony_ci /*chars*/nullptr, 391cb93a386Sopenharmony_ci}; 392cb93a386Sopenharmony_ci 393cb93a386Sopenharmony_cistatic const TagHandler familySetHandler = { 394cb93a386Sopenharmony_ci /*start*/[](FamilyData* self, const char* tag, const char** attributes) { }, 395cb93a386Sopenharmony_ci /*end*/nullptr, 396cb93a386Sopenharmony_ci /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 397cb93a386Sopenharmony_ci size_t len = strlen(tag); 398cb93a386Sopenharmony_ci if (MEMEQ("family", tag, len)) { 399cb93a386Sopenharmony_ci return &familyHandler; 400cb93a386Sopenharmony_ci } else if (MEMEQ("alias", tag, len)) { 401cb93a386Sopenharmony_ci return &aliasHandler; 402cb93a386Sopenharmony_ci } 403cb93a386Sopenharmony_ci return nullptr; 404cb93a386Sopenharmony_ci }, 405cb93a386Sopenharmony_ci /*chars*/nullptr, 406cb93a386Sopenharmony_ci}; 407cb93a386Sopenharmony_ci 408cb93a386Sopenharmony_ci} // namespace lmpParser 409cb93a386Sopenharmony_ci 410cb93a386Sopenharmony_cinamespace jbParser { 411cb93a386Sopenharmony_ci 412cb93a386Sopenharmony_cistatic const TagHandler fileHandler = { 413cb93a386Sopenharmony_ci /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 414cb93a386Sopenharmony_ci // 'variant' ("elegant", "compact") [default "default"] 415cb93a386Sopenharmony_ci // 'lang' (string) [default ""] 416cb93a386Sopenharmony_ci // 'index' (non-negative integer) [default 0] 417cb93a386Sopenharmony_ci // The character data should be a filename. 418cb93a386Sopenharmony_ci FontFamily& currentFamily = *self->fCurrentFamily; 419cb93a386Sopenharmony_ci FontFileInfo& newFileInfo = currentFamily.fFonts.push_back(); 420cb93a386Sopenharmony_ci if (attributes) { 421cb93a386Sopenharmony_ci for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 422cb93a386Sopenharmony_ci const char* name = attributes[i]; 423cb93a386Sopenharmony_ci const char* value = attributes[i+1]; 424cb93a386Sopenharmony_ci size_t nameLen = strlen(name); 425cb93a386Sopenharmony_ci size_t valueLen = strlen(value); 426cb93a386Sopenharmony_ci if (MEMEQ("variant", name, nameLen)) { 427cb93a386Sopenharmony_ci const FontVariant prevVariant = currentFamily.fVariant; 428cb93a386Sopenharmony_ci if (MEMEQ("elegant", value, valueLen)) { 429cb93a386Sopenharmony_ci currentFamily.fVariant = kElegant_FontVariant; 430cb93a386Sopenharmony_ci } else if (MEMEQ("compact", value, valueLen)) { 431cb93a386Sopenharmony_ci currentFamily.fVariant = kCompact_FontVariant; 432cb93a386Sopenharmony_ci } 433cb93a386Sopenharmony_ci if (currentFamily.fFonts.count() > 1 && currentFamily.fVariant != prevVariant) { 434cb93a386Sopenharmony_ci SK_FONTCONFIGPARSER_WARNING("'%s' unexpected variant found\n" 435cb93a386Sopenharmony_ci "Note: Every font file within a family must have identical variants.", 436cb93a386Sopenharmony_ci value); 437cb93a386Sopenharmony_ci } 438cb93a386Sopenharmony_ci 439cb93a386Sopenharmony_ci } else if (MEMEQ("lang", name, nameLen)) { 440cb93a386Sopenharmony_ci SkLanguage currentLanguage = SkLanguage(value, valueLen); 441cb93a386Sopenharmony_ci bool showWarning = false; 442cb93a386Sopenharmony_ci if (currentFamily.fLanguages.empty()) { 443cb93a386Sopenharmony_ci showWarning = (currentFamily.fFonts.count() > 1); 444cb93a386Sopenharmony_ci currentFamily.fLanguages.push_back(std::move(currentLanguage)); 445cb93a386Sopenharmony_ci } else if (currentFamily.fLanguages[0] != currentLanguage) { 446cb93a386Sopenharmony_ci showWarning = true; 447cb93a386Sopenharmony_ci currentFamily.fLanguages[0] = std::move(currentLanguage); 448cb93a386Sopenharmony_ci } 449cb93a386Sopenharmony_ci if (showWarning) { 450cb93a386Sopenharmony_ci SK_FONTCONFIGPARSER_WARNING("'%s' unexpected language found\n" 451cb93a386Sopenharmony_ci "Note: Every font file within a family must have identical languages.", 452cb93a386Sopenharmony_ci value); 453cb93a386Sopenharmony_ci } 454cb93a386Sopenharmony_ci 455cb93a386Sopenharmony_ci } else if (MEMEQ("index", name, nameLen)) { 456cb93a386Sopenharmony_ci if (!parse_non_negative_integer(value, &newFileInfo.fIndex)) { 457cb93a386Sopenharmony_ci SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value); 458cb93a386Sopenharmony_ci } 459cb93a386Sopenharmony_ci } 460cb93a386Sopenharmony_ci } 461cb93a386Sopenharmony_ci } 462cb93a386Sopenharmony_ci self->fCurrentFontInfo = &newFileInfo; 463cb93a386Sopenharmony_ci }, 464cb93a386Sopenharmony_ci /*end*/nullptr, 465cb93a386Sopenharmony_ci /*tag*/nullptr, 466cb93a386Sopenharmony_ci /*chars*/[](void* data, const char* s, int len) { 467cb93a386Sopenharmony_ci FamilyData* self = static_cast<FamilyData*>(data); 468cb93a386Sopenharmony_ci self->fCurrentFontInfo->fFileName.append(s, len); 469cb93a386Sopenharmony_ci } 470cb93a386Sopenharmony_ci}; 471cb93a386Sopenharmony_ci 472cb93a386Sopenharmony_cistatic const TagHandler fileSetHandler = { 473cb93a386Sopenharmony_ci /*start*/nullptr, 474cb93a386Sopenharmony_ci /*end*/nullptr, 475cb93a386Sopenharmony_ci /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 476cb93a386Sopenharmony_ci size_t len = strlen(tag); 477cb93a386Sopenharmony_ci if (MEMEQ("file", tag, len)) { 478cb93a386Sopenharmony_ci return &fileHandler; 479cb93a386Sopenharmony_ci } 480cb93a386Sopenharmony_ci return nullptr; 481cb93a386Sopenharmony_ci }, 482cb93a386Sopenharmony_ci /*chars*/nullptr, 483cb93a386Sopenharmony_ci}; 484cb93a386Sopenharmony_ci 485cb93a386Sopenharmony_cistatic const TagHandler nameHandler = { 486cb93a386Sopenharmony_ci /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 487cb93a386Sopenharmony_ci // The character data should be a name for the font. 488cb93a386Sopenharmony_ci self->fCurrentFamily->fNames.push_back(); 489cb93a386Sopenharmony_ci }, 490cb93a386Sopenharmony_ci /*end*/nullptr, 491cb93a386Sopenharmony_ci /*tag*/nullptr, 492cb93a386Sopenharmony_ci /*chars*/[](void* data, const char* s, int len) { 493cb93a386Sopenharmony_ci FamilyData* self = static_cast<FamilyData*>(data); 494cb93a386Sopenharmony_ci SkAutoAsciiToLC tolc(s, len); 495cb93a386Sopenharmony_ci self->fCurrentFamily->fNames.back().append(tolc.lc(), len); 496cb93a386Sopenharmony_ci } 497cb93a386Sopenharmony_ci}; 498cb93a386Sopenharmony_ci 499cb93a386Sopenharmony_cistatic const TagHandler nameSetHandler = { 500cb93a386Sopenharmony_ci /*start*/nullptr, 501cb93a386Sopenharmony_ci /*end*/nullptr, 502cb93a386Sopenharmony_ci /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 503cb93a386Sopenharmony_ci size_t len = strlen(tag); 504cb93a386Sopenharmony_ci if (MEMEQ("name", tag, len)) { 505cb93a386Sopenharmony_ci return &nameHandler; 506cb93a386Sopenharmony_ci } 507cb93a386Sopenharmony_ci return nullptr; 508cb93a386Sopenharmony_ci }, 509cb93a386Sopenharmony_ci /*chars*/nullptr, 510cb93a386Sopenharmony_ci}; 511cb93a386Sopenharmony_ci 512cb93a386Sopenharmony_cistatic const TagHandler familyHandler = { 513cb93a386Sopenharmony_ci /*start*/[](FamilyData* self, const char* tag, const char** attributes) { 514cb93a386Sopenharmony_ci self->fCurrentFamily = std::make_unique<FontFamily>(self->fBasePath, self->fIsFallback); 515cb93a386Sopenharmony_ci // 'order' (non-negative integer) [default -1] 516cb93a386Sopenharmony_ci for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 517cb93a386Sopenharmony_ci const char* value = attributes[i+1]; 518cb93a386Sopenharmony_ci parse_non_negative_integer(value, &self->fCurrentFamily->fOrder); 519cb93a386Sopenharmony_ci } 520cb93a386Sopenharmony_ci }, 521cb93a386Sopenharmony_ci /*end*/[](FamilyData* self, const char* tag) { 522cb93a386Sopenharmony_ci *self->fFamilies.append() = self->fCurrentFamily.release(); 523cb93a386Sopenharmony_ci }, 524cb93a386Sopenharmony_ci /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 525cb93a386Sopenharmony_ci size_t len = strlen(tag); 526cb93a386Sopenharmony_ci if (MEMEQ("nameset", tag, len)) { 527cb93a386Sopenharmony_ci return &nameSetHandler; 528cb93a386Sopenharmony_ci } else if (MEMEQ("fileset", tag, len)) { 529cb93a386Sopenharmony_ci return &fileSetHandler; 530cb93a386Sopenharmony_ci } 531cb93a386Sopenharmony_ci return nullptr; 532cb93a386Sopenharmony_ci }, 533cb93a386Sopenharmony_ci /*chars*/nullptr, 534cb93a386Sopenharmony_ci}; 535cb93a386Sopenharmony_ci 536cb93a386Sopenharmony_cistatic const TagHandler familySetHandler = { 537cb93a386Sopenharmony_ci /*start*/nullptr, 538cb93a386Sopenharmony_ci /*end*/nullptr, 539cb93a386Sopenharmony_ci /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 540cb93a386Sopenharmony_ci size_t len = strlen(tag); 541cb93a386Sopenharmony_ci if (MEMEQ("family", tag, len)) { 542cb93a386Sopenharmony_ci return &familyHandler; 543cb93a386Sopenharmony_ci } 544cb93a386Sopenharmony_ci return nullptr; 545cb93a386Sopenharmony_ci }, 546cb93a386Sopenharmony_ci /*chars*/nullptr, 547cb93a386Sopenharmony_ci}; 548cb93a386Sopenharmony_ci 549cb93a386Sopenharmony_ci} // namespace jbParser 550cb93a386Sopenharmony_ci 551cb93a386Sopenharmony_cistatic const TagHandler topLevelHandler = { 552cb93a386Sopenharmony_ci /*start*/nullptr, 553cb93a386Sopenharmony_ci /*end*/nullptr, 554cb93a386Sopenharmony_ci /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* { 555cb93a386Sopenharmony_ci size_t len = strlen(tag); 556cb93a386Sopenharmony_ci if (MEMEQ("familyset", tag, len)) { 557cb93a386Sopenharmony_ci // 'version' (non-negative integer) [default 0] 558cb93a386Sopenharmony_ci for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) { 559cb93a386Sopenharmony_ci const char* name = attributes[i]; 560cb93a386Sopenharmony_ci size_t nameLen = strlen(name); 561cb93a386Sopenharmony_ci if (MEMEQ("version", name, nameLen)) { 562cb93a386Sopenharmony_ci const char* value = attributes[i+1]; 563cb93a386Sopenharmony_ci if (parse_non_negative_integer(value, &self->fVersion)) { 564cb93a386Sopenharmony_ci if (self->fVersion >= 21) { 565cb93a386Sopenharmony_ci return &lmpParser::familySetHandler; 566cb93a386Sopenharmony_ci } 567cb93a386Sopenharmony_ci } 568cb93a386Sopenharmony_ci } 569cb93a386Sopenharmony_ci } 570cb93a386Sopenharmony_ci return &jbParser::familySetHandler; 571cb93a386Sopenharmony_ci } 572cb93a386Sopenharmony_ci return nullptr; 573cb93a386Sopenharmony_ci }, 574cb93a386Sopenharmony_ci /*chars*/nullptr, 575cb93a386Sopenharmony_ci}; 576cb93a386Sopenharmony_ci 577cb93a386Sopenharmony_cistatic void XMLCALL start_element_handler(void *data, const char *tag, const char **attributes) { 578cb93a386Sopenharmony_ci FamilyData* self = static_cast<FamilyData*>(data); 579cb93a386Sopenharmony_ci 580cb93a386Sopenharmony_ci if (!self->fSkip) { 581cb93a386Sopenharmony_ci const TagHandler* parent = self->fHandler.top(); 582cb93a386Sopenharmony_ci const TagHandler* child = parent->tag ? parent->tag(self, tag, attributes) : nullptr; 583cb93a386Sopenharmony_ci if (child) { 584cb93a386Sopenharmony_ci if (child->start) { 585cb93a386Sopenharmony_ci child->start(self, tag, attributes); 586cb93a386Sopenharmony_ci } 587cb93a386Sopenharmony_ci self->fHandler.push_back(child); 588cb93a386Sopenharmony_ci XML_SetCharacterDataHandler(self->fParser, child->chars); 589cb93a386Sopenharmony_ci } else { 590cb93a386Sopenharmony_ci SK_FONTCONFIGPARSER_WARNING("'%s' tag not recognized, skipping", tag); 591cb93a386Sopenharmony_ci XML_SetCharacterDataHandler(self->fParser, nullptr); 592cb93a386Sopenharmony_ci self->fSkip = self->fDepth; 593cb93a386Sopenharmony_ci } 594cb93a386Sopenharmony_ci } 595cb93a386Sopenharmony_ci 596cb93a386Sopenharmony_ci ++self->fDepth; 597cb93a386Sopenharmony_ci} 598cb93a386Sopenharmony_ci 599cb93a386Sopenharmony_cistatic void XMLCALL end_element_handler(void* data, const char* tag) { 600cb93a386Sopenharmony_ci FamilyData* self = static_cast<FamilyData*>(data); 601cb93a386Sopenharmony_ci --self->fDepth; 602cb93a386Sopenharmony_ci 603cb93a386Sopenharmony_ci if (!self->fSkip) { 604cb93a386Sopenharmony_ci const TagHandler* child = self->fHandler.top(); 605cb93a386Sopenharmony_ci if (child->end) { 606cb93a386Sopenharmony_ci child->end(self, tag); 607cb93a386Sopenharmony_ci } 608cb93a386Sopenharmony_ci self->fHandler.pop(); 609cb93a386Sopenharmony_ci const TagHandler* parent = self->fHandler.top(); 610cb93a386Sopenharmony_ci XML_SetCharacterDataHandler(self->fParser, parent->chars); 611cb93a386Sopenharmony_ci } 612cb93a386Sopenharmony_ci 613cb93a386Sopenharmony_ci if (self->fSkip == self->fDepth) { 614cb93a386Sopenharmony_ci self->fSkip = 0; 615cb93a386Sopenharmony_ci const TagHandler* parent = self->fHandler.top(); 616cb93a386Sopenharmony_ci XML_SetCharacterDataHandler(self->fParser, parent->chars); 617cb93a386Sopenharmony_ci } 618cb93a386Sopenharmony_ci} 619cb93a386Sopenharmony_ci 620cb93a386Sopenharmony_cistatic void XMLCALL xml_entity_decl_handler(void *data, 621cb93a386Sopenharmony_ci const XML_Char *entityName, 622cb93a386Sopenharmony_ci int is_parameter_entity, 623cb93a386Sopenharmony_ci const XML_Char *value, 624cb93a386Sopenharmony_ci int value_length, 625cb93a386Sopenharmony_ci const XML_Char *base, 626cb93a386Sopenharmony_ci const XML_Char *systemId, 627cb93a386Sopenharmony_ci const XML_Char *publicId, 628cb93a386Sopenharmony_ci const XML_Char *notationName) 629cb93a386Sopenharmony_ci{ 630cb93a386Sopenharmony_ci FamilyData* self = static_cast<FamilyData*>(data); 631cb93a386Sopenharmony_ci SK_FONTCONFIGPARSER_WARNING("'%s' entity declaration found, stopping processing", entityName); 632cb93a386Sopenharmony_ci XML_StopParser(self->fParser, XML_FALSE); 633cb93a386Sopenharmony_ci} 634cb93a386Sopenharmony_ci 635cb93a386Sopenharmony_cistatic const XML_Memory_Handling_Suite sk_XML_alloc = { 636cb93a386Sopenharmony_ci sk_malloc_throw, 637cb93a386Sopenharmony_ci sk_realloc_throw, 638cb93a386Sopenharmony_ci sk_free 639cb93a386Sopenharmony_ci}; 640cb93a386Sopenharmony_ci 641cb93a386Sopenharmony_ci/** 642cb93a386Sopenharmony_ci * This function parses the given filename and stores the results in the given 643cb93a386Sopenharmony_ci * families array. Returns the version of the file, negative if the file does not exist. 644cb93a386Sopenharmony_ci */ 645cb93a386Sopenharmony_cistatic int parse_config_file(const char* filename, SkTDArray<FontFamily*>& families, 646cb93a386Sopenharmony_ci const SkString& basePath, bool isFallback) 647cb93a386Sopenharmony_ci{ 648cb93a386Sopenharmony_ci SkFILEStream file(filename); 649cb93a386Sopenharmony_ci 650cb93a386Sopenharmony_ci // Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml) 651cb93a386Sopenharmony_ci // are optional - failure here is okay because one of these optional files may not exist. 652cb93a386Sopenharmony_ci if (!file.isValid()) { 653cb93a386Sopenharmony_ci SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "'%s' could not be opened\n", filename); 654cb93a386Sopenharmony_ci return -1; 655cb93a386Sopenharmony_ci } 656cb93a386Sopenharmony_ci 657cb93a386Sopenharmony_ci SkAutoTCallVProc<std::remove_pointer_t<XML_Parser>, XML_ParserFree> parser( 658cb93a386Sopenharmony_ci XML_ParserCreate_MM(nullptr, &sk_XML_alloc, nullptr)); 659cb93a386Sopenharmony_ci if (!parser) { 660cb93a386Sopenharmony_ci SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "could not create XML parser\n"); 661cb93a386Sopenharmony_ci return -1; 662cb93a386Sopenharmony_ci } 663cb93a386Sopenharmony_ci 664cb93a386Sopenharmony_ci FamilyData self(parser, families, basePath, isFallback, filename, &topLevelHandler); 665cb93a386Sopenharmony_ci XML_SetUserData(parser, &self); 666cb93a386Sopenharmony_ci 667cb93a386Sopenharmony_ci // Disable entity processing, to inhibit internal entity expansion. See expat CVE-2013-0340 668cb93a386Sopenharmony_ci XML_SetEntityDeclHandler(parser, xml_entity_decl_handler); 669cb93a386Sopenharmony_ci 670cb93a386Sopenharmony_ci // Start parsing oldschool; switch these in flight if we detect a newer version of the file. 671cb93a386Sopenharmony_ci XML_SetElementHandler(parser, start_element_handler, end_element_handler); 672cb93a386Sopenharmony_ci 673cb93a386Sopenharmony_ci // One would assume it would be faster to have a buffer on the stack and call XML_Parse. 674cb93a386Sopenharmony_ci // But XML_Parse will call XML_GetBuffer anyway and memmove the passed buffer into it. 675cb93a386Sopenharmony_ci // (Unless XML_CONTEXT_BYTES is undefined, but all users define it.) 676cb93a386Sopenharmony_ci // In debug, buffer a small odd number of bytes to detect slicing in XML_CharacterDataHandler. 677cb93a386Sopenharmony_ci static const int bufferSize = 512 SkDEBUGCODE( - 507); 678cb93a386Sopenharmony_ci bool done = false; 679cb93a386Sopenharmony_ci while (!done) { 680cb93a386Sopenharmony_ci void* buffer = XML_GetBuffer(parser, bufferSize); 681cb93a386Sopenharmony_ci if (!buffer) { 682cb93a386Sopenharmony_ci SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "could not buffer enough to continue\n"); 683cb93a386Sopenharmony_ci return -1; 684cb93a386Sopenharmony_ci } 685cb93a386Sopenharmony_ci size_t len = file.read(buffer, bufferSize); 686cb93a386Sopenharmony_ci done = file.isAtEnd(); 687cb93a386Sopenharmony_ci XML_Status status = XML_ParseBuffer(parser, len, done); 688cb93a386Sopenharmony_ci if (XML_STATUS_ERROR == status) { 689cb93a386Sopenharmony_ci XML_Error error = XML_GetErrorCode(parser); 690cb93a386Sopenharmony_ci int line = XML_GetCurrentLineNumber(parser); 691cb93a386Sopenharmony_ci int column = XML_GetCurrentColumnNumber(parser); 692cb93a386Sopenharmony_ci const XML_LChar* errorString = XML_ErrorString(error); 693cb93a386Sopenharmony_ci SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "%s:%d:%d error %d: %s.\n", 694cb93a386Sopenharmony_ci filename, line, column, error, errorString); 695cb93a386Sopenharmony_ci return -1; 696cb93a386Sopenharmony_ci } 697cb93a386Sopenharmony_ci } 698cb93a386Sopenharmony_ci return self.fVersion; 699cb93a386Sopenharmony_ci} 700cb93a386Sopenharmony_ci 701cb93a386Sopenharmony_ci/** Returns the version of the system font file actually found, negative if none. */ 702cb93a386Sopenharmony_cistatic int append_system_font_families(SkTDArray<FontFamily*>& fontFamilies, 703cb93a386Sopenharmony_ci const SkString& basePath) 704cb93a386Sopenharmony_ci{ 705cb93a386Sopenharmony_ci int initialCount = fontFamilies.count(); 706cb93a386Sopenharmony_ci int version = parse_config_file(LMP_SYSTEM_FONTS_FILE, fontFamilies, basePath, false); 707cb93a386Sopenharmony_ci if (version < 0 || fontFamilies.count() == initialCount) { 708cb93a386Sopenharmony_ci version = parse_config_file(OLD_SYSTEM_FONTS_FILE, fontFamilies, basePath, false); 709cb93a386Sopenharmony_ci } 710cb93a386Sopenharmony_ci return version; 711cb93a386Sopenharmony_ci} 712cb93a386Sopenharmony_ci 713cb93a386Sopenharmony_ci/** 714cb93a386Sopenharmony_ci * In some versions of Android prior to Android 4.2 (JellyBean MR1 at API 715cb93a386Sopenharmony_ci * Level 17) the fallback fonts for certain locales were encoded in their own 716cb93a386Sopenharmony_ci * XML files with a suffix that identified the locale. We search the provided 717cb93a386Sopenharmony_ci * directory for those files,add all of their entries to the fallback chain, and 718cb93a386Sopenharmony_ci * include the locale as part of each entry. 719cb93a386Sopenharmony_ci */ 720cb93a386Sopenharmony_cistatic void append_fallback_font_families_for_locale(SkTDArray<FontFamily*>& fallbackFonts, 721cb93a386Sopenharmony_ci const char* dir, 722cb93a386Sopenharmony_ci const SkString& basePath) 723cb93a386Sopenharmony_ci{ 724cb93a386Sopenharmony_ci SkOSFile::Iter iter(dir, nullptr); 725cb93a386Sopenharmony_ci SkString fileName; 726cb93a386Sopenharmony_ci while (iter.next(&fileName, false)) { 727cb93a386Sopenharmony_ci // The size of the prefix and suffix. 728cb93a386Sopenharmony_ci static const size_t fixedLen = sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1 729cb93a386Sopenharmony_ci + sizeof(LOCALE_FALLBACK_FONTS_SUFFIX) - 1; 730cb93a386Sopenharmony_ci 731cb93a386Sopenharmony_ci // The size of the prefix, suffix, and a minimum valid language code 732cb93a386Sopenharmony_ci static const size_t minSize = fixedLen + 2; 733cb93a386Sopenharmony_ci 734cb93a386Sopenharmony_ci if (fileName.size() < minSize || 735cb93a386Sopenharmony_ci !fileName.startsWith(LOCALE_FALLBACK_FONTS_PREFIX) || 736cb93a386Sopenharmony_ci !fileName.endsWith(LOCALE_FALLBACK_FONTS_SUFFIX)) 737cb93a386Sopenharmony_ci { 738cb93a386Sopenharmony_ci continue; 739cb93a386Sopenharmony_ci } 740cb93a386Sopenharmony_ci 741cb93a386Sopenharmony_ci SkString locale(fileName.c_str() + sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1, 742cb93a386Sopenharmony_ci fileName.size() - fixedLen); 743cb93a386Sopenharmony_ci 744cb93a386Sopenharmony_ci SkString absoluteFilename; 745cb93a386Sopenharmony_ci absoluteFilename.printf("%s/%s", dir, fileName.c_str()); 746cb93a386Sopenharmony_ci 747cb93a386Sopenharmony_ci SkTDArray<FontFamily*> langSpecificFonts; 748cb93a386Sopenharmony_ci parse_config_file(absoluteFilename.c_str(), langSpecificFonts, basePath, true); 749cb93a386Sopenharmony_ci 750cb93a386Sopenharmony_ci for (int i = 0; i < langSpecificFonts.count(); ++i) { 751cb93a386Sopenharmony_ci FontFamily* family = langSpecificFonts[i]; 752cb93a386Sopenharmony_ci family->fLanguages.emplace_back(locale); 753cb93a386Sopenharmony_ci *fallbackFonts.append() = family; 754cb93a386Sopenharmony_ci } 755cb93a386Sopenharmony_ci } 756cb93a386Sopenharmony_ci} 757cb93a386Sopenharmony_ci 758cb93a386Sopenharmony_cistatic void append_system_fallback_font_families(SkTDArray<FontFamily*>& fallbackFonts, 759cb93a386Sopenharmony_ci const SkString& basePath) 760cb93a386Sopenharmony_ci{ 761cb93a386Sopenharmony_ci parse_config_file(FALLBACK_FONTS_FILE, fallbackFonts, basePath, true); 762cb93a386Sopenharmony_ci append_fallback_font_families_for_locale(fallbackFonts, 763cb93a386Sopenharmony_ci LOCALE_FALLBACK_FONTS_SYSTEM_DIR, 764cb93a386Sopenharmony_ci basePath); 765cb93a386Sopenharmony_ci} 766cb93a386Sopenharmony_ci 767cb93a386Sopenharmony_cistatic void mixin_vendor_fallback_font_families(SkTDArray<FontFamily*>& fallbackFonts, 768cb93a386Sopenharmony_ci const SkString& basePath) 769cb93a386Sopenharmony_ci{ 770cb93a386Sopenharmony_ci SkTDArray<FontFamily*> vendorFonts; 771cb93a386Sopenharmony_ci parse_config_file(VENDOR_FONTS_FILE, vendorFonts, basePath, true); 772cb93a386Sopenharmony_ci append_fallback_font_families_for_locale(vendorFonts, 773cb93a386Sopenharmony_ci LOCALE_FALLBACK_FONTS_VENDOR_DIR, 774cb93a386Sopenharmony_ci basePath); 775cb93a386Sopenharmony_ci 776cb93a386Sopenharmony_ci // This loop inserts the vendor fallback fonts in the correct order in the 777cb93a386Sopenharmony_ci // overall fallbacks list. 778cb93a386Sopenharmony_ci int currentOrder = -1; 779cb93a386Sopenharmony_ci for (int i = 0; i < vendorFonts.count(); ++i) { 780cb93a386Sopenharmony_ci FontFamily* family = vendorFonts[i]; 781cb93a386Sopenharmony_ci int order = family->fOrder; 782cb93a386Sopenharmony_ci if (order < 0) { 783cb93a386Sopenharmony_ci if (currentOrder < 0) { 784cb93a386Sopenharmony_ci // Default case - just add it to the end of the fallback list 785cb93a386Sopenharmony_ci *fallbackFonts.append() = family; 786cb93a386Sopenharmony_ci } else { 787cb93a386Sopenharmony_ci // no order specified on this font, but we're incrementing the order 788cb93a386Sopenharmony_ci // based on an earlier order insertion request 789cb93a386Sopenharmony_ci *fallbackFonts.insert(currentOrder++) = family; 790cb93a386Sopenharmony_ci } 791cb93a386Sopenharmony_ci } else { 792cb93a386Sopenharmony_ci // Add the font into the fallback list in the specified order. Set 793cb93a386Sopenharmony_ci // currentOrder for correct placement of other fonts in the vendor list. 794cb93a386Sopenharmony_ci *fallbackFonts.insert(order) = family; 795cb93a386Sopenharmony_ci currentOrder = order + 1; 796cb93a386Sopenharmony_ci } 797cb93a386Sopenharmony_ci } 798cb93a386Sopenharmony_ci} 799cb93a386Sopenharmony_ci 800cb93a386Sopenharmony_civoid SkFontMgr_Android_Parser::GetSystemFontFamilies(SkTDArray<FontFamily*>& fontFamilies) { 801cb93a386Sopenharmony_ci // Version 21 of the system font configuration does not need any fallback configuration files. 802cb93a386Sopenharmony_ci SkString basePath(getenv("ANDROID_ROOT")); 803cb93a386Sopenharmony_ci basePath.append(SK_FONT_FILE_PREFIX, sizeof(SK_FONT_FILE_PREFIX) - 1); 804cb93a386Sopenharmony_ci 805cb93a386Sopenharmony_ci if (append_system_font_families(fontFamilies, basePath) >= 21) { 806cb93a386Sopenharmony_ci return; 807cb93a386Sopenharmony_ci } 808cb93a386Sopenharmony_ci 809cb93a386Sopenharmony_ci // Append all the fallback fonts to system fonts 810cb93a386Sopenharmony_ci SkTDArray<FontFamily*> fallbackFonts; 811cb93a386Sopenharmony_ci append_system_fallback_font_families(fallbackFonts, basePath); 812cb93a386Sopenharmony_ci mixin_vendor_fallback_font_families(fallbackFonts, basePath); 813cb93a386Sopenharmony_ci fontFamilies.append(fallbackFonts.count(), fallbackFonts.begin()); 814cb93a386Sopenharmony_ci} 815cb93a386Sopenharmony_ci 816cb93a386Sopenharmony_civoid SkFontMgr_Android_Parser::GetCustomFontFamilies(SkTDArray<FontFamily*>& fontFamilies, 817cb93a386Sopenharmony_ci const SkString& basePath, 818cb93a386Sopenharmony_ci const char* fontsXml, 819cb93a386Sopenharmony_ci const char* fallbackFontsXml, 820cb93a386Sopenharmony_ci const char* langFallbackFontsDir) 821cb93a386Sopenharmony_ci{ 822cb93a386Sopenharmony_ci if (fontsXml) { 823cb93a386Sopenharmony_ci parse_config_file(fontsXml, fontFamilies, basePath, false); 824cb93a386Sopenharmony_ci } 825cb93a386Sopenharmony_ci if (fallbackFontsXml) { 826cb93a386Sopenharmony_ci parse_config_file(fallbackFontsXml, fontFamilies, basePath, true); 827cb93a386Sopenharmony_ci } 828cb93a386Sopenharmony_ci if (langFallbackFontsDir) { 829cb93a386Sopenharmony_ci append_fallback_font_families_for_locale(fontFamilies, 830cb93a386Sopenharmony_ci langFallbackFontsDir, 831cb93a386Sopenharmony_ci basePath); 832cb93a386Sopenharmony_ci } 833cb93a386Sopenharmony_ci} 834cb93a386Sopenharmony_ci 835cb93a386Sopenharmony_ciSkLanguage SkLanguage::getParent() const { 836cb93a386Sopenharmony_ci SkASSERT(!fTag.isEmpty()); 837cb93a386Sopenharmony_ci const char* tag = fTag.c_str(); 838cb93a386Sopenharmony_ci 839cb93a386Sopenharmony_ci // strip off the rightmost "-.*" 840cb93a386Sopenharmony_ci const char* parentTagEnd = strrchr(tag, '-'); 841cb93a386Sopenharmony_ci if (parentTagEnd == nullptr) { 842cb93a386Sopenharmony_ci return SkLanguage(); 843cb93a386Sopenharmony_ci } 844cb93a386Sopenharmony_ci size_t parentTagLen = parentTagEnd - tag; 845cb93a386Sopenharmony_ci return SkLanguage(tag, parentTagLen); 846cb93a386Sopenharmony_ci} 847