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