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