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