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