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' (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                 family->fLanguage = SkLanguage(value, valueLen);
    268             } else if (MEMEQ("variant", name, nameLen)) {
    269                 if (MEMEQ("elegant", value, valueLen)) {
    270                     family->fVariant = kElegant_FontVariant;
    271                 } else if (MEMEQ("compact", value, valueLen)) {
    272                     family->fVariant = kCompact_FontVariant;
    273                 }
    274             }
    275         }
    276     },
    277     /*end*/[](FamilyData* self, const char* tag) {
    278         *self->fFamilies.append() = self->fCurrentFamily.release();
    279     },
    280     /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
    281         size_t len = strlen(tag);
    282         if (MEMEQ("font", tag, len)) {
    283             return &fontHandler;
    284         }
    285         return nullptr;
    286     },
    287     /*chars*/nullptr,
    288 };
    289 
    290 static FontFamily* find_family(FamilyData* self, const SkString& familyName) {
    291     for (int i = 0; i < self->fFamilies.count(); i++) {
    292         FontFamily* candidate = self->fFamilies[i];
    293         for (int j = 0; j < candidate->fNames.count(); j++) {
    294             if (candidate->fNames[j] == familyName) {
    295                 return candidate;
    296             }
    297         }
    298     }
    299     return nullptr;
    300 }
    301 
    302 static const TagHandler aliasHandler = {
    303     /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
    304         // 'name' (string) introduces a new family name.
    305         // 'to' (string) specifies which (previous) family to alias
    306         // 'weight' (non-negative integer) [optional]
    307         // If it *does not* have a weight, 'name' is an alias for the entire 'to' family.
    308         // If it *does* have a weight, 'name' is a new family consisting of
    309         // the font(s) with 'weight' from the 'to' family.
    310 
    311         SkString aliasName;
    312         SkString to;
    313         int weight = 0;
    314         for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
    315             const char* name = attributes[i];
    316             const char* value = attributes[i+1];
    317             size_t nameLen = strlen(name);
    318             if (MEMEQ("name", name, nameLen)) {
    319                 SkAutoAsciiToLC tolc(value);
    320                 aliasName.set(tolc.lc());
    321             } else if (MEMEQ("to", name, nameLen)) {
    322                 to.set(value);
    323             } else if (MEMEQ("weight", name, nameLen)) {
    324                 if (!parse_non_negative_integer(value, &weight)) {
    325                     SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value);
    326                 }
    327             }
    328         }
    329 
    330         // Assumes that the named family is already declared
    331         FontFamily* targetFamily = find_family(self, to);
    332         if (!targetFamily) {
    333             SK_FONTCONFIGPARSER_WARNING("'%s' alias target not found", to.c_str());
    334             return;
    335         }
    336 
    337         if (weight) {
    338             FontFamily* family = new FontFamily(targetFamily->fBasePath, self->fIsFallback);
    339             family->fNames.push_back().set(aliasName);
    340 
    341             for (int i = 0; i < targetFamily->fFonts.count(); i++) {
    342                 if (targetFamily->fFonts[i].fWeight == weight) {
    343                     family->fFonts.push_back(targetFamily->fFonts[i]);
    344                 }
    345             }
    346             *self->fFamilies.append() = family;
    347         } else {
    348             targetFamily->fNames.push_back().set(aliasName);
    349         }
    350     },
    351     /*end*/nullptr,
    352     /*tag*/nullptr,
    353     /*chars*/nullptr,
    354 };
    355 
    356 static const TagHandler familySetHandler = {
    357     /*start*/[](FamilyData* self, const char* tag, const char** attributes) { },
    358     /*end*/nullptr,
    359     /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
    360         size_t len = strlen(tag);
    361         if (MEMEQ("family", tag, len)) {
    362             return &familyHandler;
    363         } else if (MEMEQ("alias", tag, len)) {
    364             return &aliasHandler;
    365         }
    366         return nullptr;
    367     },
    368     /*chars*/nullptr,
    369 };
    370 
    371 } // lmpParser
    372 
    373 namespace jbParser {
    374 
    375 static const TagHandler fileHandler = {
    376     /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
    377         // 'variant' ("elegant", "compact") [default "default"]
    378         // 'lang' (string) [default ""]
    379         // 'index' (non-negative integer) [default 0]
    380         // The character data should be a filename.
    381         FontFamily& currentFamily = *self->fCurrentFamily.get();
    382         FontFileInfo& newFileInfo = currentFamily.fFonts.push_back();
    383         if (attributes) {
    384             for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
    385                 const char* name = attributes[i];
    386                 const char* value = attributes[i+1];
    387                 size_t nameLen = strlen(name);
    388                 size_t valueLen = strlen(value);
    389                 if (MEMEQ("variant", name, nameLen)) {
    390                     const FontVariant prevVariant = currentFamily.fVariant;
    391                     if (MEMEQ("elegant", value, valueLen)) {
    392                         currentFamily.fVariant = kElegant_FontVariant;
    393                     } else if (MEMEQ("compact", value, valueLen)) {
    394                         currentFamily.fVariant = kCompact_FontVariant;
    395                     }
    396                     if (currentFamily.fFonts.count() > 1 && currentFamily.fVariant != prevVariant) {
    397                         SK_FONTCONFIGPARSER_WARNING("'%s' unexpected variant found\n"
    398                             "Note: Every font file within a family must have identical variants.",
    399                             value);
    400                     }
    401 
    402                 } else if (MEMEQ("lang", name, nameLen)) {
    403                     SkLanguage prevLang = currentFamily.fLanguage;
    404                     currentFamily.fLanguage = SkLanguage(value, valueLen);
    405                     if (currentFamily.fFonts.count() > 1 && currentFamily.fLanguage != prevLang) {
    406                         SK_FONTCONFIGPARSER_WARNING("'%s' unexpected language found\n"
    407                             "Note: Every font file within a family must have identical languages.",
    408                             value);
    409                     }
    410 
    411                 } else if (MEMEQ("index", name, nameLen)) {
    412                     if (!parse_non_negative_integer(value, &newFileInfo.fIndex)) {
    413                         SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value);
    414                     }
    415                 }
    416             }
    417         }
    418         self->fCurrentFontInfo = &newFileInfo;
    419     },
    420     /*end*/nullptr,
    421     /*tag*/nullptr,
    422     /*chars*/[](void* data, const char* s, int len) {
    423         FamilyData* self = static_cast<FamilyData*>(data);
    424         self->fCurrentFontInfo->fFileName.append(s, len);
    425     }
    426 };
    427 
    428 static const TagHandler fileSetHandler = {
    429     /*start*/nullptr,
    430     /*end*/nullptr,
    431     /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
    432         size_t len = strlen(tag);
    433         if (MEMEQ("file", tag, len)) {
    434             return &fileHandler;
    435         }
    436         return nullptr;
    437     },
    438     /*chars*/nullptr,
    439 };
    440 
    441 static const TagHandler nameHandler = {
    442     /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
    443         // The character data should be a name for the font.
    444         self->fCurrentFamily->fNames.push_back();
    445     },
    446     /*end*/nullptr,
    447     /*tag*/nullptr,
    448     /*chars*/[](void* data, const char* s, int len) {
    449         FamilyData* self = static_cast<FamilyData*>(data);
    450         SkAutoAsciiToLC tolc(s, len);
    451         self->fCurrentFamily->fNames.back().append(tolc.lc(), len);
    452     }
    453 };
    454 
    455 static const TagHandler nameSetHandler = {
    456     /*start*/nullptr,
    457     /*end*/nullptr,
    458     /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
    459         size_t len = strlen(tag);
    460         if (MEMEQ("name", tag, len)) {
    461             return &nameHandler;
    462         }
    463         return nullptr;
    464     },
    465     /*chars*/nullptr,
    466 };
    467 
    468 static const TagHandler familyHandler = {
    469     /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
    470         self->fCurrentFamily.reset(new FontFamily(self->fBasePath, self->fIsFallback));
    471         // 'order' (non-negative integer) [default -1]
    472         for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
    473             const char* value = attributes[i+1];
    474             parse_non_negative_integer(value, &self->fCurrentFamily->fOrder);
    475         }
    476     },
    477     /*end*/[](FamilyData* self, const char* tag) {
    478         *self->fFamilies.append() = self->fCurrentFamily.release();
    479     },
    480     /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
    481         size_t len = strlen(tag);
    482         if (MEMEQ("nameset", tag, len)) {
    483             return &nameSetHandler;
    484         } else if (MEMEQ("fileset", tag, len)) {
    485             return &fileSetHandler;
    486         }
    487         return nullptr;
    488     },
    489     /*chars*/nullptr,
    490 };
    491 
    492 static const TagHandler familySetHandler = {
    493     /*start*/nullptr,
    494     /*end*/nullptr,
    495     /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
    496         size_t len = strlen(tag);
    497         if (MEMEQ("family", tag, len)) {
    498             return &familyHandler;
    499         }
    500         return nullptr;
    501     },
    502     /*chars*/nullptr,
    503 };
    504 
    505 } // namespace jbParser
    506 
    507 static const TagHandler topLevelHandler = {
    508     /*start*/nullptr,
    509     /*end*/nullptr,
    510     /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
    511         size_t len = strlen(tag);
    512         if (MEMEQ("familyset", tag, len)) {
    513             // 'version' (non-negative integer) [default 0]
    514             for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
    515                 const char* name = attributes[i];
    516                 size_t nameLen = strlen(name);
    517                 if (MEMEQ("version", name, nameLen)) {
    518                     const char* value = attributes[i+1];
    519                     if (parse_non_negative_integer(value, &self->fVersion)) {
    520                         if (self->fVersion >= 21) {
    521                             return &lmpParser::familySetHandler;
    522                         }
    523                     }
    524                 }
    525             }
    526             return &jbParser::familySetHandler;
    527         }
    528         return nullptr;
    529     },
    530     /*chars*/nullptr,
    531 };
    532 
    533 static void XMLCALL start_element_handler(void *data, const char *tag, const char **attributes) {
    534     FamilyData* self = static_cast<FamilyData*>(data);
    535 
    536     if (!self->fSkip) {
    537         const TagHandler* parent = self->fHandler.top();
    538         const TagHandler* child = parent->tag ? parent->tag(self, tag, attributes) : nullptr;
    539         if (child) {
    540             if (child->start) {
    541                 child->start(self, tag, attributes);
    542             }
    543             self->fHandler.push(child);
    544             XML_SetCharacterDataHandler(self->fParser, child->chars);
    545         } else {
    546             SK_FONTCONFIGPARSER_WARNING("'%s' tag not recognized, skipping", tag);
    547             XML_SetCharacterDataHandler(self->fParser, nullptr);
    548             self->fSkip = self->fDepth;
    549         }
    550     }
    551 
    552     ++self->fDepth;
    553 }
    554 
    555 static void XMLCALL end_element_handler(void* data, const char* tag) {
    556     FamilyData* self = static_cast<FamilyData*>(data);
    557     --self->fDepth;
    558 
    559     if (!self->fSkip) {
    560         const TagHandler* child = self->fHandler.top();
    561         if (child->end) {
    562             child->end(self, tag);
    563         }
    564         self->fHandler.pop();
    565         const TagHandler* parent = self->fHandler.top();
    566         XML_SetCharacterDataHandler(self->fParser, parent->chars);
    567     }
    568 
    569     if (self->fSkip == self->fDepth) {
    570         self->fSkip = 0;
    571         const TagHandler* parent = self->fHandler.top();
    572         XML_SetCharacterDataHandler(self->fParser, parent->chars);
    573     }
    574 }
    575 
    576 static void XMLCALL xml_entity_decl_handler(void *data,
    577                                             const XML_Char *entityName,
    578                                             int is_parameter_entity,
    579                                             const XML_Char *value,
    580                                             int value_length,
    581                                             const XML_Char *base,
    582                                             const XML_Char *systemId,
    583                                             const XML_Char *publicId,
    584                                             const XML_Char *notationName)
    585 {
    586     FamilyData* self = static_cast<FamilyData*>(data);
    587     SK_FONTCONFIGPARSER_WARNING("'%s' entity declaration found, stopping processing", entityName);
    588     XML_StopParser(self->fParser, XML_FALSE);
    589 }
    590 
    591 static const XML_Memory_Handling_Suite sk_XML_alloc = {
    592     sk_malloc_throw,
    593     sk_realloc_throw,
    594     sk_free
    595 };
    596 
    597 /**
    598  * This function parses the given filename and stores the results in the given
    599  * families array. Returns the version of the file, negative if the file does not exist.
    600  */
    601 static int parse_config_file(const char* filename, SkTDArray<FontFamily*>& families,
    602                              const SkString& basePath, bool isFallback)
    603 {
    604     SkFILEStream file(filename);
    605 
    606     // Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml)
    607     // are optional - failure here is okay because one of these optional files may not exist.
    608     if (!file.isValid()) {
    609         SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "'%s' could not be opened\n", filename);
    610         return -1;
    611     }
    612 
    613     SkAutoTCallVProc<skstd::remove_pointer_t<XML_Parser>, XML_ParserFree> parser(
    614         XML_ParserCreate_MM(nullptr, &sk_XML_alloc, nullptr));
    615     if (!parser) {
    616         SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "could not create XML parser\n");
    617         return -1;
    618     }
    619 
    620     FamilyData self(parser, families, basePath, isFallback, filename, &topLevelHandler);
    621     XML_SetUserData(parser, &self);
    622 
    623     // Disable entity processing, to inhibit internal entity expansion. See expat CVE-2013-0340
    624     XML_SetEntityDeclHandler(parser, xml_entity_decl_handler);
    625 
    626     // Start parsing oldschool; switch these in flight if we detect a newer version of the file.
    627     XML_SetElementHandler(parser, start_element_handler, end_element_handler);
    628 
    629     // One would assume it would be faster to have a buffer on the stack and call XML_Parse.
    630     // But XML_Parse will call XML_GetBuffer anyway and memmove the passed buffer into it.
    631     // (Unless XML_CONTEXT_BYTES is undefined, but all users define it.)
    632     // In debug, buffer a small odd number of bytes to detect slicing in XML_CharacterDataHandler.
    633     static const int bufferSize = 512 SkDEBUGCODE( - 507);
    634     bool done = false;
    635     while (!done) {
    636         void* buffer = XML_GetBuffer(parser, bufferSize);
    637         if (!buffer) {
    638             SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "could not buffer enough to continue\n");
    639             return -1;
    640         }
    641         size_t len = file.read(buffer, bufferSize);
    642         done = file.isAtEnd();
    643         XML_Status status = XML_ParseBuffer(parser, len, done);
    644         if (XML_STATUS_ERROR == status) {
    645             XML_Error error = XML_GetErrorCode(parser);
    646             int line = XML_GetCurrentLineNumber(parser);
    647             int column = XML_GetCurrentColumnNumber(parser);
    648             const XML_LChar* errorString = XML_ErrorString(error);
    649             SkDebugf(SK_FONTMGR_ANDROID_PARSER_PREFIX "%s:%d:%d error %d: %s.\n",
    650                      filename, line, column, error, errorString);
    651             return -1;
    652         }
    653     }
    654     return self.fVersion;
    655 }
    656 
    657 /** Returns the version of the system font file actually found, negative if none. */
    658 static int append_system_font_families(SkTDArray<FontFamily*>& fontFamilies,
    659                                        const SkString& basePath)
    660 {
    661     int initialCount = fontFamilies.count();
    662     int version = parse_config_file(LMP_SYSTEM_FONTS_FILE, fontFamilies, basePath, false);
    663     if (version < 0 || fontFamilies.count() == initialCount) {
    664         version = parse_config_file(OLD_SYSTEM_FONTS_FILE, fontFamilies, basePath, false);
    665     }
    666     return version;
    667 }
    668 
    669 /**
    670  * In some versions of Android prior to Android 4.2 (JellyBean MR1 at API
    671  * Level 17) the fallback fonts for certain locales were encoded in their own
    672  * XML files with a suffix that identified the locale.  We search the provided
    673  * directory for those files,add all of their entries to the fallback chain, and
    674  * include the locale as part of each entry.
    675  */
    676 static void append_fallback_font_families_for_locale(SkTDArray<FontFamily*>& fallbackFonts,
    677                                                      const char* dir,
    678                                                      const SkString& basePath)
    679 {
    680     SkOSFile::Iter iter(dir, nullptr);
    681     SkString fileName;
    682     while (iter.next(&fileName, false)) {
    683         // The size of the prefix and suffix.
    684         static const size_t fixedLen = sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1
    685                                      + sizeof(LOCALE_FALLBACK_FONTS_SUFFIX) - 1;
    686 
    687         // The size of the prefix, suffix, and a minimum valid language code
    688         static const size_t minSize = fixedLen + 2;
    689 
    690         if (fileName.size() < minSize ||
    691             !fileName.startsWith(LOCALE_FALLBACK_FONTS_PREFIX) ||
    692             !fileName.endsWith(LOCALE_FALLBACK_FONTS_SUFFIX))
    693         {
    694             continue;
    695         }
    696 
    697         SkString locale(fileName.c_str() + sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1,
    698                         fileName.size() - fixedLen);
    699 
    700         SkString absoluteFilename;
    701         absoluteFilename.printf("%s/%s", dir, fileName.c_str());
    702 
    703         SkTDArray<FontFamily*> langSpecificFonts;
    704         parse_config_file(absoluteFilename.c_str(), langSpecificFonts, basePath, true);
    705 
    706         for (int i = 0; i < langSpecificFonts.count(); ++i) {
    707             FontFamily* family = langSpecificFonts[i];
    708             family->fLanguage = SkLanguage(locale);
    709             *fallbackFonts.append() = family;
    710         }
    711     }
    712 }
    713 
    714 static void append_system_fallback_font_families(SkTDArray<FontFamily*>& fallbackFonts,
    715                                                  const SkString& basePath)
    716 {
    717     parse_config_file(FALLBACK_FONTS_FILE, fallbackFonts, basePath, true);
    718     append_fallback_font_families_for_locale(fallbackFonts,
    719                                              LOCALE_FALLBACK_FONTS_SYSTEM_DIR,
    720                                              basePath);
    721 }
    722 
    723 static void mixin_vendor_fallback_font_families(SkTDArray<FontFamily*>& fallbackFonts,
    724                                                 const SkString& basePath)
    725 {
    726     SkTDArray<FontFamily*> vendorFonts;
    727     parse_config_file(VENDOR_FONTS_FILE, vendorFonts, basePath, true);
    728     append_fallback_font_families_for_locale(vendorFonts,
    729                                              LOCALE_FALLBACK_FONTS_VENDOR_DIR,
    730                                              basePath);
    731 
    732     // This loop inserts the vendor fallback fonts in the correct order in the
    733     // overall fallbacks list.
    734     int currentOrder = -1;
    735     for (int i = 0; i < vendorFonts.count(); ++i) {
    736         FontFamily* family = vendorFonts[i];
    737         int order = family->fOrder;
    738         if (order < 0) {
    739             if (currentOrder < 0) {
    740                 // Default case - just add it to the end of the fallback list
    741                 *fallbackFonts.append() = family;
    742             } else {
    743                 // no order specified on this font, but we're incrementing the order
    744                 // based on an earlier order insertion request
    745                 *fallbackFonts.insert(currentOrder++) = family;
    746             }
    747         } else {
    748             // Add the font into the fallback list in the specified order. Set
    749             // currentOrder for correct placement of other fonts in the vendor list.
    750             *fallbackFonts.insert(order) = family;
    751             currentOrder = order + 1;
    752         }
    753     }
    754 }
    755 
    756 void SkFontMgr_Android_Parser::GetSystemFontFamilies(SkTDArray<FontFamily*>& fontFamilies) {
    757     // Version 21 of the system font configuration does not need any fallback configuration files.
    758     SkString basePath(getenv("ANDROID_ROOT"));
    759     basePath.append(SK_FONT_FILE_PREFIX, sizeof(SK_FONT_FILE_PREFIX) - 1);
    760 
    761     if (append_system_font_families(fontFamilies, basePath) >= 21) {
    762         return;
    763     }
    764 
    765     // Append all the fallback fonts to system fonts
    766     SkTDArray<FontFamily*> fallbackFonts;
    767     append_system_fallback_font_families(fallbackFonts, basePath);
    768     mixin_vendor_fallback_font_families(fallbackFonts, basePath);
    769     fontFamilies.append(fallbackFonts.count(), fallbackFonts.begin());
    770 }
    771 
    772 void SkFontMgr_Android_Parser::GetCustomFontFamilies(SkTDArray<FontFamily*>& fontFamilies,
    773                                                      const SkString& basePath,
    774                                                      const char* fontsXml,
    775                                                      const char* fallbackFontsXml,
    776                                                      const char* langFallbackFontsDir)
    777 {
    778     if (fontsXml) {
    779         parse_config_file(fontsXml, fontFamilies, basePath, false);
    780     }
    781     if (fallbackFontsXml) {
    782         parse_config_file(fallbackFontsXml, fontFamilies, basePath, true);
    783     }
    784     if (langFallbackFontsDir) {
    785         append_fallback_font_families_for_locale(fontFamilies,
    786                                                  langFallbackFontsDir,
    787                                                  basePath);
    788     }
    789 }
    790 
    791 SkLanguage SkLanguage::getParent() const {
    792     SkASSERT(!fTag.isEmpty());
    793     const char* tag = fTag.c_str();
    794 
    795     // strip off the rightmost "-.*"
    796     const char* parentTagEnd = strrchr(tag, '-');
    797     if (parentTagEnd == nullptr) {
    798         return SkLanguage();
    799     }
    800     size_t parentTagLen = parentTagEnd - tag;
    801     return SkLanguage(tag, parentTagLen);
    802 }
    803