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