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