OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2011 The Android Open Source Project | 2 * Copyright 2011 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkFontConfigParser_android.h" | 8 #include "SkFontConfigParser_android.h" |
9 #include "SkTDArray.h" | 9 #include "SkTDArray.h" |
10 #include "SkTSearch.h" | 10 #include "SkTSearch.h" |
11 #include "SkTypeface.h" | 11 #include "SkTypeface.h" |
12 | 12 |
13 #include <expat.h> | 13 #include <expat.h> |
14 #include <stdio.h> | 14 #include <stdio.h> |
15 #include <sys/system_properties.h> | 15 #include <sys/system_properties.h> |
16 | 16 |
17 #include <limits> | 17 #include <limits> |
18 | 18 |
19 #define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" | 19 #define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" |
20 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" | 20 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" |
21 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" | 21 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" |
22 | 22 |
23 /** | |
24 * This file contains TWO parsers: one for JB and earlier (system_fonts.xml / | |
25 * fallback_fonts.xml), one for LMP and later (fonts.xml). | |
26 * We start with the JB parser, and if we detect a <familyset> tag with | |
27 * version 21 or higher we switch to the LMP parser. | |
28 */ | |
29 | |
23 // These defines are used to determine the kind of tag that we're currently | 30 // These defines are used to determine the kind of tag that we're currently |
24 // populating with data. We only care about the sibling tags nameset and fileset | 31 // populating with data. We only care about the sibling tags nameset and fileset |
25 // for now. | 32 // for now. |
26 #define NO_TAG 0 | 33 #define NO_TAG 0 |
27 #define NAMESET_TAG 1 | 34 #define NAMESET_TAG 1 |
28 #define FILESET_TAG 2 | 35 #define FILESET_TAG 2 |
29 | 36 |
30 /** | 37 /** |
31 * The FamilyData structure is passed around by the parser so that each handler | 38 * The FamilyData structure is passed around by the parser so that each handler |
32 * can read these variables that are relevant to the current parsing. | 39 * can read these variables that are relevant to the current parsing. |
33 */ | 40 */ |
34 struct FamilyData { | 41 struct FamilyData { |
35 FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef) : | 42 FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef) : |
36 parser(parserRef), | 43 parser(parserRef), |
37 families(familiesRef), | 44 families(familiesRef), |
38 currentFamily(NULL), | 45 currentFamily(NULL), |
39 currentFontInfo(NULL), | 46 currentFontInfo(NULL), |
40 currentTag(NO_TAG) {}; | 47 currentTag(NO_TAG) {}; |
41 | 48 |
42 XML_Parser *parser; // The expat parser doing the work | 49 XML_Parser *parser; // The expat parser doing the work |
43 SkTDArray<FontFamily*> &families; // The array that each family is put into as it is parsed | 50 SkTDArray<FontFamily*> &families; // The array that each family is put into as it is parsed |
44 FontFamily *currentFamily; // The current family being created | 51 FontFamily *currentFamily; // The current family being created |
45 FontFileInfo *currentFontInfo; // The current fontInfo being created | 52 FontFileInfo *currentFontInfo; // The current fontInfo being created |
46 int currentTag; // A flag to indicate whether we're in na meset/fileset tags | 53 int currentTag; // A flag to indicate whether we're in na meset/fileset tags |
47 }; | 54 }; |
48 | 55 |
56 /** http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-nega tive-def */ | |
57 template <typename T> static bool parseNonNegativeInteger(const char* s, T* valu e) { | |
tomhudson
2014/08/04 17:33:48
Moved to start of file so everybody can see it.
| |
58 SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer); | |
59 const T nMax = std::numeric_limits<T>::max() / 10; | |
60 const T dMax = std::numeric_limits<T>::max() - (nMax * 10); | |
61 T n = 0; | |
62 for (; *s; ++s) { | |
63 // Check if digit | |
64 if (*s < '0' || '9' < *s) { | |
65 return false; | |
66 } | |
67 int d = *s - '0'; | |
68 // Check for overflow | |
69 if (n > nMax || (n == nMax && d > dMax)) { | |
70 return false; | |
71 } | |
72 n = (n * 10) + d; | |
73 } | |
74 *value = n; | |
75 return true; | |
76 } | |
77 | |
78 namespace lmpParser { | |
tomhudson
2014/08/04 17:33:48
Will fill in with cleaned-up version of prototype
djsollen
2014/08/04 18:13:35
I'm ok with putting both of them in this file for
tomhudson
2014/08/04 21:03:56
Acknowledged.
| |
79 | |
80 void startElementHandler(void* data, const char* tag, | |
81 const char** attributes) { | |
82 //SkDebugf("lmp started %s", tag); | |
83 } | |
84 | |
85 void endElementHandler(void* data, const char* tag) { | |
86 | |
87 //SkDebugf("lmp ended %s", tag); | |
88 | |
89 } | |
90 | |
91 } // lmpParser | |
92 | |
93 namespace jbParser { | |
94 | |
49 /** | 95 /** |
50 * Handler for arbitrary text. This is used to parse the text inside each name | 96 * Handler for arbitrary text. This is used to parse the text inside each name |
51 * or file tag. The resulting strings are put into the fNames or FontFileInfo ar rays. | 97 * or file tag. The resulting strings are put into the fNames or FontFileInfo ar rays. |
52 */ | 98 */ |
53 static void textHandler(void *data, const char *s, int len) { | 99 static void textHandler(void *data, const char *s, int len) { |
54 FamilyData *familyData = (FamilyData*) data; | 100 FamilyData *familyData = (FamilyData*) data; |
55 // Make sure we're in the right state to store this name information | 101 // Make sure we're in the right state to store this name information |
56 if (familyData->currentFamily && | 102 if (familyData->currentFamily && |
57 (familyData->currentTag == NAMESET_TAG || familyData->currentTag == FILESET_TAG)) { | 103 (familyData->currentTag == NAMESET_TAG || familyData->currentTag == FILESET_TAG)) { |
58 switch (familyData->currentTag) { | 104 switch (familyData->currentTag) { |
59 case NAMESET_TAG: { | 105 case NAMESET_TAG: { |
60 SkAutoAsciiToLC tolc(s, len); | 106 SkAutoAsciiToLC tolc(s, len); |
61 familyData->currentFamily->fNames.push_back().set(tolc.lc(), len); | 107 familyData->currentFamily->fNames.push_back().set(tolc.lc(), len); |
62 break; | 108 break; |
63 } | 109 } |
64 case FILESET_TAG: | 110 case FILESET_TAG: { |
bungeman-skia
2014/08/04 18:02:12
nit: The extra braces seem extraneous, normally th
tomhudson
2014/08/04 21:03:56
Done.
| |
65 if (familyData->currentFontInfo) { | 111 if (familyData->currentFontInfo) { |
66 familyData->currentFontInfo->fFileName.set(s, len); | 112 familyData->currentFontInfo->fFileName.set(s, len); |
67 } | 113 } |
68 break; | 114 } break; |
69 default: | 115 default: |
70 // Noop - don't care about any text that's not in the Fonts or Names list | 116 // Noop - don't care about any text that's not in the Fonts or Names list |
71 break; | 117 break; |
72 } | 118 } |
73 } | 119 } |
74 } | 120 } |
75 | 121 |
76 /** http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-nega tive-def */ | |
77 template <typename T> static bool parseNonNegativeInteger(const char* s, T* valu e) { | |
78 SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer); | |
79 const T nMax = std::numeric_limits<T>::max() / 10; | |
80 const T dMax = std::numeric_limits<T>::max() - (nMax * 10); | |
81 T n = 0; | |
82 for (; *s; ++s) { | |
83 // Check if digit | |
84 if (*s < '0' || '9' < *s) { | |
85 return false; | |
86 } | |
87 int d = *s - '0'; | |
88 // Check for overflow | |
89 if (n > nMax || (n == nMax && d > dMax)) { | |
90 return false; | |
91 } | |
92 n = (n * 10) + d; | |
93 } | |
94 *value = n; | |
95 return true; | |
96 } | |
97 | |
98 /** | 122 /** |
99 * Handler for font files. This processes the attributes for language and | 123 * Handler for font files. This processes the attributes for language and |
100 * variants then lets textHandler handle the actual file name | 124 * variants then lets textHandler handle the actual file name |
101 */ | 125 */ |
102 static void fontFileElementHandler(FamilyData *familyData, const char **attribut es) { | 126 static void fontFileElementHandler(FamilyData *familyData, const char **attribut es) { |
103 | |
104 FontFileInfo& newFileInfo = familyData->currentFamily->fFontFiles.push_back( ); | 127 FontFileInfo& newFileInfo = familyData->currentFamily->fFontFiles.push_back( ); |
105 if (attributes) { | 128 if (attributes) { |
106 int currentAttributeIndex = 0; | 129 int currentAttributeIndex = 0; |
107 while (attributes[currentAttributeIndex]) { | 130 while (attributes[currentAttributeIndex]) { |
108 const char* attributeName = attributes[currentAttributeIndex]; | 131 const char* attributeName = attributes[currentAttributeIndex]; |
109 const char* attributeValue = attributes[currentAttributeIndex+1]; | 132 const char* attributeValue = attributes[currentAttributeIndex+1]; |
110 int nameLength = strlen(attributeName); | 133 int nameLength = strlen(attributeName); |
111 int valueLength = strlen(attributeValue); | 134 int valueLength = strlen(attributeValue); |
112 if (strncmp(attributeName, "variant", nameLength) == 0) { | 135 if (strncmp(attributeName, "variant", nameLength) == 0) { |
113 if (strncmp(attributeValue, "elegant", valueLength) == 0) { | 136 if (strncmp(attributeValue, "elegant", valueLength) == 0) { |
(...skipping 13 matching lines...) Expand all Loading... | |
127 } | 150 } |
128 //each element is a pair of attributeName/attributeValue string pair s | 151 //each element is a pair of attributeName/attributeValue string pair s |
129 currentAttributeIndex += 2; | 152 currentAttributeIndex += 2; |
130 } | 153 } |
131 } | 154 } |
132 familyData->currentFontInfo = &newFileInfo; | 155 familyData->currentFontInfo = &newFileInfo; |
133 XML_SetCharacterDataHandler(*familyData->parser, textHandler); | 156 XML_SetCharacterDataHandler(*familyData->parser, textHandler); |
134 } | 157 } |
135 | 158 |
136 /** | 159 /** |
137 * Handler for the start of a tag. The only tags we expect are family, nameset, | 160 * Handler for the start of a tag. The only tags we expect are familyset, family , |
138 * fileset, name, and file. | 161 * nameset, fileset, name, and file. |
139 */ | 162 */ |
140 static void startElementHandler(void *data, const char *tag, const char **atts) { | 163 static void startElementHandler(void *data, const char *tag, const char **atts) { |
141 FamilyData *familyData = (FamilyData*) data; | 164 FamilyData *familyData = (FamilyData*) data; |
142 int len = strlen(tag); | 165 int len = strlen(tag); |
143 if (strncmp(tag, "family", len)== 0) { | 166 if (len == 9 && strncmp(tag, "familyset", len) == 0) { |
tomhudson
2014/08/04 17:33:48
Note to self: remember to check len explicitly, ot
bungeman-skia
2014/08/04 18:02:12
This is an interesting quirk, in that with strncmp
tomhudson
2014/08/04 18:14:49
The len == MAGIC && !strncmp() pattern was present
| |
167 // The familyset tag has an optional "version" attribute with an integer value >= 0 | |
168 for (int i = 0; atts[i] != NULL; i += 2) { | |
169 int nameLen = strlen(atts[i]); | |
170 if (strncmp(atts[i], "version", nameLen)) continue; | |
bungeman-skia
2014/08/04 18:02:12
Add the 'nameLen = strlen("version")' thing here t
tomhudson
2014/08/04 21:03:56
Done.
Added it to every strlen() in the file, inc
| |
171 const char* valueString = atts[i+1]; | |
172 int version; | |
173 int len = sscanf(valueString, "%d", &version); | |
bungeman-skia
2014/08/04 18:02:12
It seems you put parseNonNegativeInteger up top in
tomhudson
2014/08/04 18:14:49
qv <family> order=; for some reason the previous v
tomhudson
2014/08/04 21:03:56
Done.
| |
174 if (len > 0 && version >= 21) { | |
175 XML_SetElementHandler(*familyData->parser, | |
176 lmpParser::startElementHandler, | |
177 lmpParser::endElementHandler); | |
178 } | |
179 } | |
180 } else if (len == 6 && strncmp(tag, "family", len) == 0) { | |
144 familyData->currentFamily = new FontFamily(); | 181 familyData->currentFamily = new FontFamily(); |
145 familyData->currentFamily->order = -1; | 182 familyData->currentFamily->order = -1; |
146 // The Family tag has an optional "order" attribute with an integer valu e >= 0 | 183 // The Family tag has an optional "order" attribute with an integer valu e >= 0 |
147 // If this attribute does not exist, the default value is -1 | 184 // If this attribute does not exist, the default value is -1 |
148 for (int i = 0; atts[i] != NULL; i += 2) { | 185 for (int i = 0; atts[i] != NULL; i += 2) { |
149 const char* valueString = atts[i+1]; | 186 const char* valueString = atts[i+1]; |
150 int value; | 187 int value; |
151 int len = sscanf(valueString, "%d", &value); | 188 int len = sscanf(valueString, "%d", &value); |
152 if (len > 0) { | 189 if (len > 0) { |
153 familyData->currentFamily->order = value; | 190 familyData->currentFamily->order = value; |
(...skipping 27 matching lines...) Expand all Loading... | |
181 familyData->currentTag = NO_TAG; | 218 familyData->currentTag = NO_TAG; |
182 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { | 219 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { |
183 familyData->currentTag = NO_TAG; | 220 familyData->currentTag = NO_TAG; |
184 } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAME SET_TAG) || | 221 } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAME SET_TAG) || |
185 (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET _TAG)) { | 222 (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET _TAG)) { |
186 // Disable the arbitrary text handler installed to load Name data | 223 // Disable the arbitrary text handler installed to load Name data |
187 XML_SetCharacterDataHandler(*familyData->parser, NULL); | 224 XML_SetCharacterDataHandler(*familyData->parser, NULL); |
188 } | 225 } |
189 } | 226 } |
190 | 227 |
228 } // namespace jbParser | |
229 | |
191 /** | 230 /** |
192 * This function parses the given filename and stores the results in the given | 231 * This function parses the given filename and stores the results in the given |
193 * families array. | 232 * families array. |
194 */ | 233 */ |
195 static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &famili es) { | 234 static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &famili es) { |
196 | 235 |
197 FILE* file = NULL; | 236 FILE* file = NULL; |
198 | 237 |
199 #if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) | 238 #if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) |
200 // if we are using a version of Android prior to Android 4.2 (JellyBean MR1 | 239 // if we are using a version of Android prior to Android 4.2 (JellyBean MR1 |
(...skipping 29 matching lines...) Expand all Loading... | |
230 | 269 |
231 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac k_fonts.xml) | 270 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac k_fonts.xml) |
232 // are optional - failure here is okay because one of these optional files m ay not exist. | 271 // are optional - failure here is okay because one of these optional files m ay not exist. |
233 if (NULL == file) { | 272 if (NULL == file) { |
234 return; | 273 return; |
235 } | 274 } |
236 | 275 |
237 XML_Parser parser = XML_ParserCreate(NULL); | 276 XML_Parser parser = XML_ParserCreate(NULL); |
238 FamilyData *familyData = new FamilyData(&parser, families); | 277 FamilyData *familyData = new FamilyData(&parser, families); |
239 XML_SetUserData(parser, familyData); | 278 XML_SetUserData(parser, familyData); |
240 XML_SetElementHandler(parser, startElementHandler, endElementHandler); | 279 // Start parsing oldschool; switch these in flight if we detect a newer vers ion of the file. |
280 XML_SetElementHandler(parser, jbParser::startElementHandler, jbParser::endEl ementHandler); | |
241 | 281 |
242 char buffer[512]; | 282 char buffer[512]; |
243 bool done = false; | 283 bool done = false; |
244 while (!done) { | 284 while (!done) { |
245 fgets(buffer, sizeof(buffer), file); | 285 fgets(buffer, sizeof(buffer), file); |
246 int len = strlen(buffer); | 286 int len = strlen(buffer); |
247 if (feof(file) != 0) { | 287 if (feof(file) != 0) { |
248 done = true; | 288 done = true; |
249 } | 289 } |
250 XML_Parse(parser, buffer, len, done); | 290 XML_Parse(parser, buffer, len, done); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
302 *fontFamilies.append() = fallbackFonts[i]; | 342 *fontFamilies.append() = fallbackFonts[i]; |
303 } | 343 } |
304 } | 344 } |
305 | 345 |
306 void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*> &fontFamilie s, | 346 void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*> &fontFamilie s, |
307 const char* testMainConfigFile, | 347 const char* testMainConfigFile, |
308 const char* testFallbackConfigFile) { | 348 const char* testFallbackConfigFile) { |
309 parseConfigFile(testMainConfigFile, fontFamilies); | 349 parseConfigFile(testMainConfigFile, fontFamilies); |
310 | 350 |
311 SkTDArray<FontFamily*> fallbackFonts; | 351 SkTDArray<FontFamily*> fallbackFonts; |
312 parseConfigFile(testFallbackConfigFile, fallbackFonts); | 352 if (NULL != testFallbackConfigFile) { |
tomhudson
2014/08/04 17:33:48
For v22, we only have one file; instead of adding
djsollen
2014/08/04 18:13:35
Acknowledged.
| |
353 parseConfigFile(testFallbackConfigFile, fallbackFonts); | |
354 } | |
313 | 355 |
314 // Append all fallback fonts to system fonts | 356 // Append all fallback fonts to system fonts |
315 for (int i = 0; i < fallbackFonts.count(); ++i) { | 357 for (int i = 0; i < fallbackFonts.count(); ++i) { |
316 fallbackFonts[i]->fIsFallbackFont = true; | 358 fallbackFonts[i]->fIsFallbackFont = true; |
317 *fontFamilies.append() = fallbackFonts[i]; | 359 *fontFamilies.append() = fallbackFonts[i]; |
318 } | 360 } |
319 } | 361 } |
320 | 362 |
321 /** | 363 /** |
322 * Read the persistent locale. | 364 * Read the persistent locale. |
(...skipping 17 matching lines...) Expand all Loading... | |
340 SkString locale(6); | 382 SkString locale(6); |
341 char* localeCStr = locale.writable_str(); | 383 char* localeCStr = locale.writable_str(); |
342 | 384 |
343 strncpy(localeCStr, propLang, 2); | 385 strncpy(localeCStr, propLang, 2); |
344 localeCStr[2] = '-'; | 386 localeCStr[2] = '-'; |
345 strncpy(&localeCStr[3], propRegn, 2); | 387 strncpy(&localeCStr[3], propRegn, 2); |
346 localeCStr[5] = '\0'; | 388 localeCStr[5] = '\0'; |
347 | 389 |
348 return locale; | 390 return locale; |
349 } | 391 } |
OLD | NEW |