Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkFontMgr_android_parser.cpp
Go to the documentation of this file.
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
17#include "src/base/SkTSearch.h"
18#include "src/core/SkOSFile.h"
20
21#include <expat.h>
22
23#include <stdlib.h>
24#include <string.h>
25
26#include <memory>
27
28using 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
58struct FamilyData;
59
60struct 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. */
91struct FamilyData {
92 FamilyData(XML_Parser parser, SkTDArray<FontFamily*>& families,
93 const SkString& basePath, bool isFallback, const char* filename,
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)
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
122static 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
138static bool is_whitespace(char c) {
139 return c == ' ' || c == '\n'|| c == '\r' || c == '\t';
140}
141
142static 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
157static 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
172namespace lmpParser {
173
174static const TagHandler axisHandler = {
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
222static const TagHandler fontHandler = {
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 },
272 /*end*/[](FamilyData* self, const char* tag) {
273 trim_string(&self->fCurrentFontInfo->fFileName);
274 },
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 },
282 /*chars*/[](void* data, const char* s, int len) {
283 FamilyData* self = static_cast<FamilyData*>(data);
285 }
286};
287
288static const TagHandler familyHandler = {
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)) {
303 family->fNames.push_back().set(tolc.lc());
304 family->fIsFallbackFont = false;
305 } else if (MEMEQ("lang", name, nameLen)) {
307 } else if (MEMEQ("variant", name, nameLen)) {
308 if (MEMEQ("elegant", value, valueLen)) {
310 } else if (MEMEQ("compact", value, valueLen)) {
312 }
313 }
314 }
315 },
316 /*end*/[](FamilyData* self, const char* tag) {
317 *self->fFamilies.append() = self->fCurrentFamily.release();
318 },
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
329static 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
341static const TagHandler aliasHandler = {
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)) {
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
396 /*start*/[](FamilyData* self, const char* tag, const char** attributes) { },
397 /*end*/nullptr,
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
412namespace jbParser {
413
414static const TagHandler fileHandler = {
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,
468 /*chars*/[](void* data, const char* s, int len) {
469 FamilyData* self = static_cast<FamilyData*>(data);
471 }
472};
473
475 /*start*/nullptr,
476 /*end*/nullptr,
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
487static const TagHandler nameHandler = {
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,
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
502 /*start*/nullptr,
503 /*end*/nullptr,
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
514static const TagHandler familyHandler = {
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 },
523 /*end*/[](FamilyData* self, const char* tag) {
524 *self->fFamilies.append() = self->fCurrentFamily.release();
525 },
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
539 /*start*/nullptr,
540 /*end*/nullptr,
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
554 /*start*/nullptr,
555 /*end*/nullptr,
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) {
568 }
569 }
570 }
571 }
573 }
574 return nullptr;
575 },
576 /*chars*/nullptr,
577};
578
579static 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
601static 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
622static 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
637static const XML_Memory_Handling_Suite sk_XML_alloc = {
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 */
647static 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
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. */
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 */
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 ||
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
761 const SkString& basePath)
762{
763 parse_config_file(FALLBACK_FONTS_FILE, fallbackFonts, basePath, true);
766 basePath);
767}
768
770 const SkString& basePath)
771{
772 SkTDArray<FontFamily*> vendorFonts;
773 parse_config_file(VENDOR_FONTS_FILE, vendorFonts, basePath, true);
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
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
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) {
832 langFallbackFontsDir,
833 basePath);
834 }
835}
836
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}
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
Definition DM.cpp:263
#define SkASSERT(cond)
Definition SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
int32_t SkFixed
Definition SkFixed.h:25
#define SkFixedToScalar(x)
Definition SkFixed.h:124
#define LOCALE_FALLBACK_FONTS_VENDOR_DIR
static void append_fallback_font_families_for_locale(SkTDArray< FontFamily * > &fallbackFonts, const char *dir, const SkString &basePath)
#define ATTS_NON_NULL(a, i)
static void XMLCALL start_element_handler(void *data, const char *tag, const char **attributes)
static void XMLCALL end_element_handler(void *data, const char *tag)
static void XMLCALL 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)
#define VENDOR_FONTS_FILE
static bool memeq(const char *s1, const char *s2, size_t n1, size_t n2)
static const TagHandler topLevelHandler
#define FALLBACK_FONTS_FILE
#define OLD_SYSTEM_FONTS_FILE
static int parse_config_file(const char *filename, SkTDArray< FontFamily * > &families, const SkString &basePath, bool isFallback)
static void mixin_vendor_fallback_font_families(SkTDArray< FontFamily * > &fallbackFonts, const SkString &basePath)
static void append_system_fallback_font_families(SkTDArray< FontFamily * > &fallbackFonts, const SkString &basePath)
#define MEMEQ(c, s, n)
static void trim_string(SkString *s)
static bool is_whitespace(char c)
static const XML_Memory_Handling_Suite sk_XML_alloc
static void parse_space_separated_languages(const char *value, size_t valueLen, TArray< SkLanguage, true > &languages)
#define SK_FONTCONFIGPARSER_WARNING(message,...)
#define SK_FONT_FILE_PREFIX
#define LOCALE_FALLBACK_FONTS_SUFFIX
#define SK_FONTMGR_ANDROID_PARSER_PREFIX
#define LOCALE_FALLBACK_FONTS_PREFIX
#define LMP_SYSTEM_FONTS_FILE
#define LOCALE_FALLBACK_FONTS_SYSTEM_DIR
static int append_system_font_families(SkTDArray< FontFamily * > &fontFamilies, const SkString &basePath)
bool parse_non_negative_integer(const char *s, T *value)
uint32_t FontVariant
@ kCompact_FontVariant
@ kElegant_FontVariant
SK_API void sk_free(void *)
static void * sk_malloc_throw(size_t size)
Definition SkMalloc.h:67
SK_API void * sk_realloc_throw(void *buffer, size_t size)
uint32_t SkFourByteTag
Definition SkTypes.h:166
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Definition SkTypes.h:167
const char * lc() const
Definition SkTSearch.h:117
SkLanguage getParent() const
SK_SPI bool next(SkString *name, bool getDir=false)
bool startsWith(const char prefixStr[]) const
Definition SkString.h:140
void printf(const char format[],...) SK_PRINTF_LIKE(2
Definition SkString.cpp:534
size_t size() const
Definition SkString.h:131
void set(const SkString &src)
Definition SkString.h:186
bool isEmpty() const
Definition SkString.h:130
void append(const char text[])
Definition SkString.h:203
bool endsWith(const char suffixStr[]) const
Definition SkString.h:146
const char * c_str() const
Definition SkString.h:133
int size() const
Definition SkTDArray.h:138
T * begin()
Definition SkTDArray.h:150
T * append()
Definition SkTDArray.h:191
T * insert(int index)
Definition SkTDArray.h:203
bool empty() const
Definition SkTArray.h:194
int size() const
Definition SkTArray.h:416
T & emplace_back(Args &&... args)
Definition SkTArray.h:243
struct MyStruct s
glong glong end
static const uint8_t buffer[]
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
const char * name
Definition fuchsia.cc:50
void GetCustomFontFamilies(SkTDArray< FontFamily * > &fontFamilies, const SkString &basePath, const char *fontsXml, const char *fallbackFontsXml, const char *langFallbackFontsDir=nullptr)
void GetSystemFontFamilies(SkTDArray< FontFamily * > &fontFamilies)
static const TagHandler nameSetHandler
static const TagHandler fileSetHandler
static const TagHandler fileHandler
static const TagHandler nameHandler
static const TagHandler familyHandler
static const TagHandler familySetHandler
static FontFamily * find_family(FamilyData *self, const SkString &familyName)
static const TagHandler aliasHandler
static const TagHandler axisHandler
static const TagHandler fontHandler
static const TagHandler familySetHandler
static const TagHandler familyHandler
std::unique_ptr< FontFamily > fCurrentFamily
SkTDArray< const TagHandler * > fHandler
SkTDArray< FontFamily * > & fFamilies
const SkString & fBasePath
FontFileInfo * fCurrentFontInfo
FamilyData(XML_Parser parser, SkTDArray< FontFamily * > &families, const SkString &basePath, bool isFallback, const char *filename, const TagHandler *topLevelHandler)
skia_private::TArray< SkString, true > fNames
const SkString fBasePath
skia_private::TArray< SkLanguage, true > fLanguages
skia_private::TArray< FontFileInfo, true > fFonts
const TagHandler *(* tag)(FamilyData *data, const char *tag, const char **attributes)
void(* start)(FamilyData *data, const char *tag, const char **attributes)
XML_CharacterDataHandler chars
void(* end)(FamilyData *data, const char *tag)