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