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 <dirent.h> | 14 #include <dirent.h> |
15 #include <stdio.h> | 15 #include <stdio.h> |
16 | 16 |
17 #include <limits> | 17 #include <limits> |
18 | 18 |
19 | |
20 | |
21 // From Android version LMP onwards, all font files collapse into | 19 // From Android version LMP onwards, all font files collapse into |
22 // /system/etc/fonts.xml. Instead of trying to detect which version | 20 // /system/etc/fonts.xml. Instead of trying to detect which version |
23 // we're on, try to open fonts.xml; if that fails, fall back to the | 21 // we're on, try to open fonts.xml; if that fails, fall back to the |
24 // older filename. | 22 // older filename. |
25 #define LMP_SYSTEM_FONTS_FILE "/system/etc/fonts.xml" | 23 #define LMP_SYSTEM_FONTS_FILE "/system/etc/fonts.xml" |
26 #define OLD_SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" | 24 #define OLD_SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" |
27 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" | 25 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" |
28 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" | 26 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" |
29 | 27 |
30 #define LOCALE_FALLBACK_FONTS_SYSTEM_DIR "/system/etc" | 28 #define LOCALE_FALLBACK_FONTS_SYSTEM_DIR "/system/etc" |
(...skipping 13 matching lines...) Expand all Loading... |
44 // for now. | 42 // for now. |
45 #define NO_TAG 0 | 43 #define NO_TAG 0 |
46 #define NAMESET_TAG 1 | 44 #define NAMESET_TAG 1 |
47 #define FILESET_TAG 2 | 45 #define FILESET_TAG 2 |
48 | 46 |
49 /** | 47 /** |
50 * The FamilyData structure is passed around by the parser so that each handler | 48 * The FamilyData structure is passed around by the parser so that each handler |
51 * can read these variables that are relevant to the current parsing. | 49 * can read these variables that are relevant to the current parsing. |
52 */ | 50 */ |
53 struct FamilyData { | 51 struct FamilyData { |
54 FamilyData(XML_Parser parser, SkTDArray<FontFamily*> &families) | 52 FamilyData(XML_Parser parser, SkTDArray<FontFamily*>& families) |
55 : fParser(parser) | 53 : fParser(parser) |
56 , fFamilies(families) | 54 , fFamilies(families) |
57 , fCurrentFamily(NULL) | 55 , fCurrentFamily(NULL) |
58 , fCurrentFontInfo(NULL) | 56 , fCurrentFontInfo(NULL) |
59 , fCurrentTag(NO_TAG) | 57 , fCurrentTag(NO_TAG) |
60 { }; | 58 , fVersion(0) |
| 59 { } |
61 | 60 |
62 XML_Parser fParser; // The expat parser doing the work
, owned by caller | 61 XML_Parser fParser; // The expat parser doing the work
, owned by caller |
63 SkTDArray<FontFamily*>& fFamilies; // The array to append families, o
wned by caller | 62 SkTDArray<FontFamily*>& fFamilies; // The array to append families, o
wned by caller |
64 SkAutoTDelete<FontFamily> fCurrentFamily; // The family being created, owned
by this | 63 SkAutoTDelete<FontFamily> fCurrentFamily; // The family being created, owned
by this |
65 FontFileInfo* fCurrentFontInfo; // The fontInfo being created, own
ed by currentFamily | 64 FontFileInfo* fCurrentFontInfo; // The fontInfo being created, own
ed by currentFamily |
66 int fCurrentTag; // Flag to indicate when we're in
nameset/fileset tags | 65 int fCurrentTag; // Flag to indicate when we're in
nameset/fileset tags |
| 66 int fVersion; // The version of the file parsed. |
67 }; | 67 }; |
68 | 68 |
69 /** http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-nega
tive-def */ | 69 /** http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-nega
tive-def */ |
70 template <typename T> static bool parseNonNegativeInteger(const char* s, T* valu
e) { | 70 template <typename T> static bool parse_non_negative_integer(const char* s, T* v
alue) { |
71 SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer); | 71 SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer); |
72 const T nMax = std::numeric_limits<T>::max() / 10; | 72 const T nMax = std::numeric_limits<T>::max() / 10; |
73 const T dMax = std::numeric_limits<T>::max() - (nMax * 10); | 73 const T dMax = std::numeric_limits<T>::max() - (nMax * 10); |
74 T n = 0; | 74 T n = 0; |
75 for (; *s; ++s) { | 75 for (; *s; ++s) { |
76 // Check if digit | 76 // Check if digit |
77 if (*s < '0' || '9' < *s) { | 77 if (*s < '0' || '9' < *s) { |
78 return false; | 78 return false; |
79 } | 79 } |
80 int d = *s - '0'; | 80 int d = *s - '0'; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 void fontElementHandler(XML_Parser parser, FontFileInfo* file, const char** attr
ibutes) { | 126 void fontElementHandler(XML_Parser parser, FontFileInfo* file, const char** attr
ibutes) { |
127 // A <font> should have weight (integer) and style (normal, italic) attribut
es. | 127 // A <font> should have weight (integer) and style (normal, italic) attribut
es. |
128 // NOTE: we ignore the style. | 128 // NOTE: we ignore the style. |
129 // The element should contain a filename. | 129 // The element should contain a filename. |
130 for (size_t i = 0; attributes[i] != NULL && | 130 for (size_t i = 0; attributes[i] != NULL && |
131 attributes[i+1] != NULL; i += 2) { | 131 attributes[i+1] != NULL; i += 2) { |
132 const char* name = attributes[i]; | 132 const char* name = attributes[i]; |
133 const char* value = attributes[i+1]; | 133 const char* value = attributes[i+1]; |
134 size_t nameLen = strlen(name); | 134 size_t nameLen = strlen(name); |
135 if (nameLen == 6 && !strncmp("weight", name, nameLen)) { | 135 if (nameLen == 6 && !strncmp("weight", name, nameLen)) { |
136 if (!parseNonNegativeInteger(value, &file->fWeight)) { | 136 if (!parse_non_negative_integer(value, &file->fWeight)) { |
137 SkDebugf("---- Font weight %s (INVALID)", value); | 137 SkDebugf("---- Font weight %s (INVALID)", value); |
138 file->fWeight = 0; | 138 file->fWeight = 0; |
139 } | 139 } |
140 } | 140 } |
141 } | 141 } |
142 XML_SetCharacterDataHandler(parser, fontFileNameHandler); | 142 XML_SetCharacterDataHandler(parser, fontFileNameHandler); |
143 } | 143 } |
144 | 144 |
145 FontFamily* findFamily(FamilyData* familyData, const char* familyName) { | 145 FontFamily* findFamily(FamilyData* familyData, const char* familyName) { |
146 size_t nameLen = strlen(familyName); | 146 size_t nameLen = strlen(familyName); |
(...skipping 24 matching lines...) Expand all Loading... |
171 attributes[i+1] != NULL; i += 2) { | 171 attributes[i+1] != NULL; i += 2) { |
172 const char* name = attributes[i]; | 172 const char* name = attributes[i]; |
173 const char* value = attributes[i+1]; | 173 const char* value = attributes[i+1]; |
174 size_t nameLen = strlen(name); | 174 size_t nameLen = strlen(name); |
175 if (nameLen == 4 && !strncmp("name", name, nameLen)) { | 175 if (nameLen == 4 && !strncmp("name", name, nameLen)) { |
176 SkAutoAsciiToLC tolc(value); | 176 SkAutoAsciiToLC tolc(value); |
177 aliasName.set(tolc.lc()); | 177 aliasName.set(tolc.lc()); |
178 } else if (nameLen == 2 && !strncmp("to", name, nameLen)) { | 178 } else if (nameLen == 2 && !strncmp("to", name, nameLen)) { |
179 to.set(value); | 179 to.set(value); |
180 } else if (nameLen == 6 && !strncmp("weight", name, nameLen)) { | 180 } else if (nameLen == 6 && !strncmp("weight", name, nameLen)) { |
181 parseNonNegativeInteger(value, &weight); | 181 parse_non_negative_integer(value, &weight); |
182 } | 182 } |
183 } | 183 } |
184 | 184 |
185 // Assumes that the named family is already declared | 185 // Assumes that the named family is already declared |
186 FontFamily* targetFamily = findFamily(familyData, to.c_str()); | 186 FontFamily* targetFamily = findFamily(familyData, to.c_str()); |
187 if (!targetFamily) { | 187 if (!targetFamily) { |
188 SkDebugf("---- Font alias target %s (NOT FOUND)", to.c_str()); | 188 SkDebugf("---- Font alias target %s (NOT FOUND)", to.c_str()); |
189 return; | 189 return; |
190 } | 190 } |
191 | 191 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 } | 230 } |
231 | 231 |
232 } // lmpParser | 232 } // lmpParser |
233 | 233 |
234 namespace jbParser { | 234 namespace jbParser { |
235 | 235 |
236 /** | 236 /** |
237 * Handler for arbitrary text. This is used to parse the text inside each name | 237 * Handler for arbitrary text. This is used to parse the text inside each name |
238 * or file tag. The resulting strings are put into the fNames or FontFileInfo ar
rays. | 238 * or file tag. The resulting strings are put into the fNames or FontFileInfo ar
rays. |
239 */ | 239 */ |
240 static void textHandler(void* data, const char* s, int len) { | 240 static void text_handler(void* data, const char* s, int len) { |
241 FamilyData* familyData = (FamilyData*) data; | 241 FamilyData* familyData = (FamilyData*) data; |
242 // Make sure we're in the right state to store this name information | 242 // Make sure we're in the right state to store this name information |
243 if (familyData->fCurrentFamily.get() && | 243 if (familyData->fCurrentFamily.get() && |
244 (familyData->fCurrentTag == NAMESET_TAG || familyData->fCurrentTag =
= FILESET_TAG)) { | 244 (familyData->fCurrentTag == NAMESET_TAG || familyData->fCurrentTag =
= FILESET_TAG)) { |
245 switch (familyData->fCurrentTag) { | 245 switch (familyData->fCurrentTag) { |
246 case NAMESET_TAG: { | 246 case NAMESET_TAG: { |
247 SkAutoAsciiToLC tolc(s, len); | 247 SkAutoAsciiToLC tolc(s, len); |
248 familyData->fCurrentFamily->fNames.push_back().set(tolc.lc(), len); | 248 familyData->fCurrentFamily->fNames.push_back().set(tolc.lc(), len); |
249 break; | 249 break; |
250 } | 250 } |
251 case FILESET_TAG: | 251 case FILESET_TAG: |
252 if (familyData->fCurrentFontInfo) { | 252 if (familyData->fCurrentFontInfo) { |
253 familyData->fCurrentFontInfo->fFileName.set(s, len); | 253 familyData->fCurrentFontInfo->fFileName.set(s, len); |
254 } | 254 } |
255 break; | 255 break; |
256 default: | 256 default: |
257 // Noop - don't care about any text that's not in the Fonts or Names
list | 257 // Noop - don't care about any text that's not in the Fonts or Names
list |
258 break; | 258 break; |
259 } | 259 } |
260 } | 260 } |
261 } | 261 } |
262 | 262 |
263 /** | 263 /** |
264 * Handler for font files. This processes the attributes for language and | 264 * Handler for font files. This processes the attributes for language and |
265 * variants then lets textHandler handle the actual file name | 265 * variants then lets textHandler handle the actual file name |
266 */ | 266 */ |
267 static void fontFileElementHandler(FamilyData* familyData, const char** attribut
es) { | 267 static void font_file_element_handler(FamilyData* familyData, const char** attri
butes) { |
268 FontFileInfo& newFileInfo = familyData->fCurrentFamily->fFonts.push_back(); | 268 FontFileInfo& newFileInfo = familyData->fCurrentFamily->fFonts.push_back(); |
269 if (attributes) { | 269 if (attributes) { |
270 size_t currentAttributeIndex = 0; | 270 size_t currentAttributeIndex = 0; |
271 while (attributes[currentAttributeIndex] && | 271 while (attributes[currentAttributeIndex] && |
272 attributes[currentAttributeIndex + 1]) { | 272 attributes[currentAttributeIndex + 1]) { |
273 const char* attributeName = attributes[currentAttributeIndex]; | 273 const char* attributeName = attributes[currentAttributeIndex]; |
274 const char* attributeValue = attributes[currentAttributeIndex+1]; | 274 const char* attributeValue = attributes[currentAttributeIndex+1]; |
275 size_t nameLength = strlen(attributeName); | 275 size_t nameLength = strlen(attributeName); |
276 size_t valueLength = strlen(attributeValue); | 276 size_t valueLength = strlen(attributeValue); |
277 if (nameLength == 7 && strncmp(attributeName, "variant", nameLength)
== 0) { | 277 if (nameLength == 7 && strncmp(attributeName, "variant", nameLength)
== 0) { |
(...skipping 13 matching lines...) Expand all Loading... |
291 } else if (nameLength == 4 && strncmp(attributeName, "lang", nameLen
gth) == 0) { | 291 } else if (nameLength == 4 && strncmp(attributeName, "lang", nameLen
gth) == 0) { |
292 SkLanguage prevLang = familyData->fCurrentFamily->fLanguage; | 292 SkLanguage prevLang = familyData->fCurrentFamily->fLanguage; |
293 familyData->fCurrentFamily->fLanguage = SkLanguage(attributeValu
e); | 293 familyData->fCurrentFamily->fLanguage = SkLanguage(attributeValu
e); |
294 if (familyData->fCurrentFamily->fFonts.count() > 1 && | 294 if (familyData->fCurrentFamily->fFonts.count() > 1 && |
295 familyData->fCurrentFamily->fLanguage != prevLang) { | 295 familyData->fCurrentFamily->fLanguage != prevLang) { |
296 SkDebugf("Every font file within a family must have identica
l languages"); | 296 SkDebugf("Every font file within a family must have identica
l languages"); |
297 sk_throw(); | 297 sk_throw(); |
298 } | 298 } |
299 } else if (nameLength == 5 && strncmp(attributeName, "index", nameLe
ngth) == 0) { | 299 } else if (nameLength == 5 && strncmp(attributeName, "index", nameLe
ngth) == 0) { |
300 int value; | 300 int value; |
301 if (parseNonNegativeInteger(attributeValue, &value)) { | 301 if (parse_non_negative_integer(attributeValue, &value)) { |
302 newFileInfo.fIndex = value; | 302 newFileInfo.fIndex = value; |
303 } else { | 303 } else { |
304 SkDebugf("---- SystemFonts index=%s (INVALID)", attributeVal
ue); | 304 SkDebugf("---- SystemFonts index=%s (INVALID)", attributeVal
ue); |
305 } | 305 } |
306 } | 306 } |
307 //each element is a pair of attributeName/attributeValue string pair
s | 307 //each element is a pair of attributeName/attributeValue string pair
s |
308 currentAttributeIndex += 2; | 308 currentAttributeIndex += 2; |
309 } | 309 } |
310 } | 310 } |
311 familyData->fCurrentFontInfo = &newFileInfo; | 311 familyData->fCurrentFontInfo = &newFileInfo; |
312 XML_SetCharacterDataHandler(familyData->fParser, textHandler); | 312 XML_SetCharacterDataHandler(familyData->fParser, text_handler); |
313 } | 313 } |
314 | 314 |
315 /** | 315 /** |
316 * Handler for the start of a tag. The only tags we expect are familyset, family
, | 316 * Handler for the start of a tag. The only tags we expect are familyset, family
, |
317 * nameset, fileset, name, and file. | 317 * nameset, fileset, name, and file. |
318 */ | 318 */ |
319 static void startElementHandler(void* data, const char* tag, const char** atts)
{ | 319 static void start_element_handler(void* data, const char* tag, const char** atts
) { |
320 FamilyData* familyData = (FamilyData*) data; | 320 FamilyData* familyData = (FamilyData*) data; |
321 size_t len = strlen(tag); | 321 size_t len = strlen(tag); |
322 if (len == 9 && strncmp(tag, "familyset", len) == 0) { | 322 if (len == 9 && strncmp(tag, "familyset", len) == 0) { |
323 // The familyset tag has an optional "version" attribute with an integer
value >= 0 | 323 // The familyset tag has an optional "version" attribute with an integer
value >= 0 |
324 for (size_t i = 0; atts[i] != NULL && | 324 for (size_t i = 0; atts[i] != NULL && |
325 atts[i+1] != NULL; i += 2) { | 325 atts[i+1] != NULL; i += 2) { |
326 size_t nameLen = strlen(atts[i]); | 326 size_t nameLen = strlen(atts[i]); |
327 if (nameLen == 7 && strncmp(atts[i], "version", nameLen)) continue; | 327 if (nameLen == 7 && strncmp(atts[i], "version", nameLen)) continue; |
328 const char* valueString = atts[i+1]; | 328 const char* valueString = atts[i+1]; |
329 int version; | 329 int version; |
330 if (parseNonNegativeInteger(valueString, &version) && (version >= 21
)) { | 330 if (parse_non_negative_integer(valueString, &version) && (version >=
21)) { |
331 XML_SetElementHandler(familyData->fParser, | 331 XML_SetElementHandler(familyData->fParser, |
332 lmpParser::startElementHandler, | 332 lmpParser::startElementHandler, |
333 lmpParser::endElementHandler); | 333 lmpParser::endElementHandler); |
| 334 familyData->fVersion = version; |
334 } | 335 } |
335 } | 336 } |
336 } else if (len == 6 && strncmp(tag, "family", len) == 0) { | 337 } else if (len == 6 && strncmp(tag, "family", len) == 0) { |
337 familyData->fCurrentFamily.reset(new FontFamily()); | 338 familyData->fCurrentFamily.reset(new FontFamily()); |
338 // The Family tag has an optional "order" attribute with an integer valu
e >= 0 | 339 // The Family tag has an optional "order" attribute with an integer valu
e >= 0 |
339 // If this attribute does not exist, the default value is -1 | 340 // If this attribute does not exist, the default value is -1 |
340 for (size_t i = 0; atts[i] != NULL && | 341 for (size_t i = 0; atts[i] != NULL && |
341 atts[i+1] != NULL; i += 2) { | 342 atts[i+1] != NULL; i += 2) { |
342 const char* valueString = atts[i+1]; | 343 const char* valueString = atts[i+1]; |
343 int value; | 344 int value; |
344 if (parseNonNegativeInteger(valueString, &value)) { | 345 if (parse_non_negative_integer(valueString, &value)) { |
345 familyData->fCurrentFamily->fOrder = value; | 346 familyData->fCurrentFamily->fOrder = value; |
346 } | 347 } |
347 } | 348 } |
348 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) { | 349 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) { |
349 familyData->fCurrentTag = NAMESET_TAG; | 350 familyData->fCurrentTag = NAMESET_TAG; |
350 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { | 351 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { |
351 familyData->fCurrentTag = FILESET_TAG; | 352 familyData->fCurrentTag = FILESET_TAG; |
352 } else if (len == 4 && strncmp(tag, "name", len) == 0 && familyData->fCurren
tTag == NAMESET_TAG) { | 353 } else if (len == 4 && strncmp(tag, "name", len) == 0 && familyData->fCurren
tTag == NAMESET_TAG) { |
353 // If it's a Name, parse the text inside | 354 // If it's a Name, parse the text inside |
354 XML_SetCharacterDataHandler(familyData->fParser, textHandler); | 355 XML_SetCharacterDataHandler(familyData->fParser, text_handler); |
355 } else if (len == 4 && strncmp(tag, "file", len) == 0 && familyData->fCurren
tTag == FILESET_TAG) { | 356 } else if (len == 4 && strncmp(tag, "file", len) == 0 && familyData->fCurren
tTag == FILESET_TAG) { |
356 // If it's a file, parse the attributes, then parse the text inside | 357 // If it's a file, parse the attributes, then parse the text inside |
357 fontFileElementHandler(familyData, atts); | 358 font_file_element_handler(familyData, atts); |
358 } | 359 } |
359 } | 360 } |
360 | 361 |
361 /** | 362 /** |
362 * Handler for the end of tags. We only care about family, nameset, fileset, | 363 * Handler for the end of tags. We only care about family, nameset, fileset, |
363 * name, and file. | 364 * name, and file. |
364 */ | 365 */ |
365 static void endElementHandler(void* data, const char* tag) { | 366 static void end_element_handler(void* data, const char* tag) { |
366 FamilyData* familyData = (FamilyData*) data; | 367 FamilyData* familyData = (FamilyData*) data; |
367 size_t len = strlen(tag); | 368 size_t len = strlen(tag); |
368 if (len == 6 && strncmp(tag, "family", len)== 0) { | 369 if (len == 6 && strncmp(tag, "family", len)== 0) { |
369 // Done parsing a Family - store the created currentFamily in the famili
es array | 370 // Done parsing a Family - store the created currentFamily in the famili
es array |
370 *familyData->fFamilies.append() = familyData->fCurrentFamily.detach(); | 371 *familyData->fFamilies.append() = familyData->fCurrentFamily.detach(); |
371 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) { | 372 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) { |
372 familyData->fCurrentTag = NO_TAG; | 373 familyData->fCurrentTag = NO_TAG; |
373 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { | 374 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { |
374 familyData->fCurrentTag = NO_TAG; | 375 familyData->fCurrentTag = NO_TAG; |
375 } else if ((len == 4 && | 376 } else if ((len == 4 && |
376 strncmp(tag, "name", len) == 0 && | 377 strncmp(tag, "name", len) == 0 && |
377 familyData->fCurrentTag == NAMESET_TAG) || | 378 familyData->fCurrentTag == NAMESET_TAG) || |
378 (len == 4 && | 379 (len == 4 && |
379 strncmp(tag, "file", len) == 0 && | 380 strncmp(tag, "file", len) == 0 && |
380 familyData->fCurrentTag == FILESET_TAG)) { | 381 familyData->fCurrentTag == FILESET_TAG)) { |
381 // Disable the arbitrary text handler installed to load Name data | 382 // Disable the arbitrary text handler installed to load Name data |
382 XML_SetCharacterDataHandler(familyData->fParser, NULL); | 383 XML_SetCharacterDataHandler(familyData->fParser, NULL); |
383 } | 384 } |
384 } | 385 } |
385 | 386 |
386 } // namespace jbParser | 387 } // namespace jbParser |
387 | 388 |
388 /** | 389 /** |
389 * This function parses the given filename and stores the results in the given | 390 * This function parses the given filename and stores the results in the given |
390 * families array. | 391 * families array. Returns the version of the file, negative if the file does no
t exist. |
391 */ | 392 */ |
392 static void parseConfigFile(const char* filename, SkTDArray<FontFamily*> &famili
es) { | 393 static int parse_config_file(const char* filename, SkTDArray<FontFamily*>& famil
ies) { |
393 | 394 |
394 FILE* file = fopen(filename, "r"); | 395 FILE* file = fopen(filename, "r"); |
395 | 396 |
396 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac
k_fonts.xml) | 397 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac
k_fonts.xml) |
397 // are optional - failure here is okay because one of these optional files m
ay not exist. | 398 // are optional - failure here is okay because one of these optional files m
ay not exist. |
398 if (NULL == file) { | 399 if (NULL == file) { |
399 return; | 400 return -1; |
400 } | 401 } |
401 | 402 |
402 XML_Parser parser = XML_ParserCreate(NULL); | 403 XML_Parser parser = XML_ParserCreate(NULL); |
403 FamilyData familyData(parser, families); | 404 FamilyData familyData(parser, families); |
404 XML_SetUserData(parser, &familyData); | 405 XML_SetUserData(parser, &familyData); |
405 // Start parsing oldschool; switch these in flight if we detect a newer vers
ion of the file. | 406 // Start parsing oldschool; switch these in flight if we detect a newer vers
ion of the file. |
406 XML_SetElementHandler(parser, jbParser::startElementHandler, jbParser::endEl
ementHandler); | 407 XML_SetElementHandler(parser, jbParser::start_element_handler, jbParser::end
_element_handler); |
407 | 408 |
408 char buffer[512]; | 409 char buffer[512]; |
409 bool done = false; | 410 bool done = false; |
410 while (!done) { | 411 while (!done) { |
411 fgets(buffer, sizeof(buffer), file); | 412 fgets(buffer, sizeof(buffer), file); |
412 size_t len = strlen(buffer); | 413 size_t len = strlen(buffer); |
413 if (feof(file) != 0) { | 414 if (feof(file) != 0) { |
414 done = true; | 415 done = true; |
415 } | 416 } |
416 XML_Parse(parser, buffer, len, done); | 417 XML_Parse(parser, buffer, len, done); |
417 } | 418 } |
418 XML_ParserFree(parser); | 419 XML_ParserFree(parser); |
419 fclose(file); | 420 fclose(file); |
| 421 return familyData.fVersion; |
420 } | 422 } |
421 | 423 |
422 static void getSystemFontFamilies(SkTDArray<FontFamily*> &fontFamilies) { | 424 /** Returns the version of the system font file actually found, negative if none
. */ |
| 425 static int append_system_font_families(SkTDArray<FontFamily*>& fontFamilies) { |
423 int initialCount = fontFamilies.count(); | 426 int initialCount = fontFamilies.count(); |
424 parseConfigFile(LMP_SYSTEM_FONTS_FILE, fontFamilies); | 427 int version = parse_config_file(LMP_SYSTEM_FONTS_FILE, fontFamilies); |
425 | 428 if (version < 0 || fontFamilies.count() == initialCount) { |
426 if (initialCount == fontFamilies.count()) { | 429 version = parse_config_file(OLD_SYSTEM_FONTS_FILE, fontFamilies); |
427 parseConfigFile(OLD_SYSTEM_FONTS_FILE, fontFamilies); | |
428 } | 430 } |
| 431 return version; |
429 } | 432 } |
430 | 433 |
431 /** | 434 /** |
432 * In some versions of Android prior to Android 4.2 (JellyBean MR1 at API | 435 * In some versions of Android prior to Android 4.2 (JellyBean MR1 at API |
433 * Level 17) the fallback fonts for certain locales were encoded in their own | 436 * Level 17) the fallback fonts for certain locales were encoded in their own |
434 * XML files with a suffix that identified the locale. We search the provided | 437 * XML files with a suffix that identified the locale. We search the provided |
435 * directory for those files,add all of their entries to the fallback chain, and | 438 * directory for those files,add all of their entries to the fallback chain, and |
436 * include the locale as part of each entry. | 439 * include the locale as part of each entry. |
437 */ | 440 */ |
438 static void getFallbackFontFamiliesForLocale(SkTDArray<FontFamily*> &fallbackFon
ts, const char* dir) { | 441 static void append_fallback_font_families_for_locale(SkTDArray<FontFamily*>& fal
lbackFonts, |
| 442 const char* dir) |
| 443 { |
439 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) | 444 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) |
440 // The framework is beyond Android 4.2 and can therefore skip this function | 445 // The framework is beyond Android 4.2 and can therefore skip this function |
441 return; | 446 return; |
442 #endif | 447 #endif |
443 | 448 |
444 DIR* fontDirectory = opendir(dir); | 449 DIR* fontDirectory = opendir(dir); |
445 if (fontDirectory != NULL){ | 450 if (fontDirectory != NULL){ |
446 struct dirent* dirEntry = readdir(fontDirectory); | 451 struct dirent* dirEntry = readdir(fontDirectory); |
447 while (dirEntry) { | 452 while (dirEntry) { |
448 | 453 |
449 // The size of both the prefix, suffix, and a minimum valid language
code | 454 // The size of both the prefix, suffix, and a minimum valid language
code |
450 static const size_t minSize = strlen(LOCALE_FALLBACK_FONTS_PREFIX) + | 455 static const size_t minSize = strlen(LOCALE_FALLBACK_FONTS_PREFIX) + |
451 strlen(LOCALE_FALLBACK_FONTS_SUFFIX) +
2; | 456 strlen(LOCALE_FALLBACK_FONTS_SUFFIX) +
2; |
452 | 457 |
453 SkString fileName(dirEntry->d_name); | 458 SkString fileName(dirEntry->d_name); |
454 if (fileName.size() >= minSize && | 459 if (fileName.size() >= minSize && |
455 fileName.startsWith(LOCALE_FALLBACK_FONTS_PREFIX) && | 460 fileName.startsWith(LOCALE_FALLBACK_FONTS_PREFIX) && |
456 fileName.endsWith(LOCALE_FALLBACK_FONTS_SUFFIX)) { | 461 fileName.endsWith(LOCALE_FALLBACK_FONTS_SUFFIX)) { |
457 | 462 |
458 static const size_t fixedLen = strlen(LOCALE_FALLBACK_FONTS_PREF
IX) - | 463 static const size_t fixedLen = strlen(LOCALE_FALLBACK_FONTS_PREF
IX) - |
459 strlen(LOCALE_FALLBACK_FONTS_SUFF
IX); | 464 strlen(LOCALE_FALLBACK_FONTS_SUFF
IX); |
460 | 465 |
461 SkString locale(fileName.c_str() - strlen(LOCALE_FALLBACK_FONTS_
PREFIX), | 466 SkString locale(fileName.c_str() - strlen(LOCALE_FALLBACK_FONTS_
PREFIX), |
462 fileName.size() - fixedLen); | 467 fileName.size() - fixedLen); |
463 | 468 |
464 SkString absoluteFilename; | 469 SkString absoluteFilename; |
465 absoluteFilename.printf("%s/%s", dir, fileName.c_str()); | 470 absoluteFilename.printf("%s/%s", dir, fileName.c_str()); |
466 | 471 |
467 SkTDArray<FontFamily*> langSpecificFonts; | 472 SkTDArray<FontFamily*> langSpecificFonts; |
468 parseConfigFile(absoluteFilename.c_str(), langSpecificFonts); | 473 parse_config_file(absoluteFilename.c_str(), langSpecificFonts); |
469 | 474 |
470 for (int i = 0; i < langSpecificFonts.count(); ++i) { | 475 for (int i = 0; i < langSpecificFonts.count(); ++i) { |
471 FontFamily* family = langSpecificFonts[i]; | 476 FontFamily* family = langSpecificFonts[i]; |
472 family->fLanguage = SkLanguage(locale); | 477 family->fLanguage = SkLanguage(locale); |
473 *fallbackFonts.append() = family; | 478 *fallbackFonts.append() = family; |
474 } | 479 } |
475 } | 480 } |
476 | 481 |
477 // proceed to the next entry in the directory | 482 // proceed to the next entry in the directory |
478 dirEntry = readdir(fontDirectory); | 483 dirEntry = readdir(fontDirectory); |
479 } | 484 } |
480 // cleanup the directory reference | 485 // cleanup the directory reference |
481 closedir(fontDirectory); | 486 closedir(fontDirectory); |
482 } | 487 } |
483 } | 488 } |
484 | 489 |
485 static void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts) { | 490 static void append_system_fallback_font_families(SkTDArray<FontFamily*>& fallbac
kFonts) { |
| 491 parse_config_file(FALLBACK_FONTS_FILE, fallbackFonts); |
| 492 append_fallback_font_families_for_locale(fallbackFonts, LOCALE_FALLBACK_FONT
S_SYSTEM_DIR); |
| 493 } |
| 494 |
| 495 static void mixin_vendor_fallback_font_families(SkTDArray<FontFamily*>& fallback
Fonts) { |
486 SkTDArray<FontFamily*> vendorFonts; | 496 SkTDArray<FontFamily*> vendorFonts; |
487 parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts); | 497 parse_config_file(VENDOR_FONTS_FILE, vendorFonts); |
488 parseConfigFile(VENDOR_FONTS_FILE, vendorFonts); | 498 append_fallback_font_families_for_locale(vendorFonts, LOCALE_FALLBACK_FONTS_
VENDOR_DIR); |
489 | |
490 getFallbackFontFamiliesForLocale(fallbackFonts, LOCALE_FALLBACK_FONTS_SYSTEM
_DIR); | |
491 getFallbackFontFamiliesForLocale(vendorFonts, LOCALE_FALLBACK_FONTS_VENDOR_D
IR); | |
492 | 499 |
493 // This loop inserts the vendor fallback fonts in the correct order in the | 500 // This loop inserts the vendor fallback fonts in the correct order in the |
494 // overall fallbacks list. | 501 // overall fallbacks list. |
495 int currentOrder = -1; | 502 int currentOrder = -1; |
496 for (int i = 0; i < vendorFonts.count(); ++i) { | 503 for (int i = 0; i < vendorFonts.count(); ++i) { |
497 FontFamily* family = vendorFonts[i]; | 504 FontFamily* family = vendorFonts[i]; |
498 int order = family->fOrder; | 505 int order = family->fOrder; |
499 if (order < 0) { | 506 if (order < 0) { |
500 if (currentOrder < 0) { | 507 if (currentOrder < 0) { |
501 // Default case - just add it to the end of the fallback list | 508 // Default case - just add it to the end of the fallback list |
502 *fallbackFonts.append() = family; | 509 *fallbackFonts.append() = family; |
503 } else { | 510 } else { |
504 // no order specified on this font, but we're incrementing the o
rder | 511 // no order specified on this font, but we're incrementing the o
rder |
505 // based on an earlier order insertion request | 512 // based on an earlier order insertion request |
506 *fallbackFonts.insert(currentOrder++) = family; | 513 *fallbackFonts.insert(currentOrder++) = family; |
507 } | 514 } |
508 } else { | 515 } else { |
509 // Add the font into the fallback list in the specified order. Set | 516 // Add the font into the fallback list in the specified order. Set |
510 // currentOrder for correct placement of other fonts in the vendor l
ist. | 517 // currentOrder for correct placement of other fonts in the vendor l
ist. |
511 *fallbackFonts.insert(order) = family; | 518 *fallbackFonts.insert(order) = family; |
512 currentOrder = order + 1; | 519 currentOrder = order + 1; |
513 } | 520 } |
514 } | 521 } |
515 } | 522 } |
516 | 523 |
517 /** | 524 /** |
518 * Loads data on font families from various expected configuration files. The | 525 * Loads data on font families from various expected configuration files. The |
519 * resulting data is returned in the given fontFamilies array. | 526 * resulting data is returned in the given fontFamilies array. |
520 */ | 527 */ |
521 void SkFontConfigParser::GetFontFamilies(SkTDArray<FontFamily*> &fontFamilies) { | 528 void SkFontConfigParser::GetFontFamilies(SkTDArray<FontFamily*>& fontFamilies) { |
522 | 529 // Version 21 of the system font configuration does not need any fallback co
nfiguration files. |
523 getSystemFontFamilies(fontFamilies); | 530 if (append_system_font_families(fontFamilies) >= 21) { |
| 531 return; |
| 532 } |
524 | 533 |
525 // Append all the fallback fonts to system fonts | 534 // Append all the fallback fonts to system fonts |
526 SkTDArray<FontFamily*> fallbackFonts; | 535 SkTDArray<FontFamily*> fallbackFonts; |
527 getFallbackFontFamilies(fallbackFonts); | 536 append_system_fallback_font_families(fallbackFonts); |
| 537 mixin_vendor_fallback_font_families(fallbackFonts); |
528 for (int i = 0; i < fallbackFonts.count(); ++i) { | 538 for (int i = 0; i < fallbackFonts.count(); ++i) { |
529 fallbackFonts[i]->fIsFallbackFont = true; | 539 fallbackFonts[i]->fIsFallbackFont = true; |
530 *fontFamilies.append() = fallbackFonts[i]; | 540 *fontFamilies.append() = fallbackFonts[i]; |
531 } | 541 } |
532 } | 542 } |
533 | 543 |
534 void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*> &fontFamilie
s, | 544 void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*>& fontFamilie
s, |
535 const char* testMainConfigFile, | 545 const char* testMainConfigFile, |
536 const char* testFallbackConfigFile)
{ | 546 const char* testFallbackConfigFile)
{ |
537 parseConfigFile(testMainConfigFile, fontFamilies); | 547 parse_config_file(testMainConfigFile, fontFamilies); |
538 | 548 |
539 SkTDArray<FontFamily*> fallbackFonts; | 549 SkTDArray<FontFamily*> fallbackFonts; |
540 if (testFallbackConfigFile) { | 550 if (testFallbackConfigFile) { |
541 parseConfigFile(testFallbackConfigFile, fallbackFonts); | 551 parse_config_file(testFallbackConfigFile, fallbackFonts); |
542 } | 552 } |
543 | 553 |
544 // Append all fallback fonts to system fonts | 554 // Append all fallback fonts to system fonts |
545 for (int i = 0; i < fallbackFonts.count(); ++i) { | 555 for (int i = 0; i < fallbackFonts.count(); ++i) { |
546 fallbackFonts[i]->fIsFallbackFont = true; | 556 fallbackFonts[i]->fIsFallbackFont = true; |
547 *fontFamilies.append() = fallbackFonts[i]; | 557 *fontFamilies.append() = fallbackFonts[i]; |
548 } | 558 } |
549 } | 559 } |
550 | 560 |
551 SkLanguage SkLanguage::getParent() const { | 561 SkLanguage SkLanguage::getParent() const { |
552 SkASSERT(!fTag.isEmpty()); | 562 SkASSERT(!fTag.isEmpty()); |
553 const char* tag = fTag.c_str(); | 563 const char* tag = fTag.c_str(); |
554 | 564 |
555 // strip off the rightmost "-.*" | 565 // strip off the rightmost "-.*" |
556 const char* parentTagEnd = strrchr(tag, '-'); | 566 const char* parentTagEnd = strrchr(tag, '-'); |
557 if (parentTagEnd == NULL) { | 567 if (parentTagEnd == NULL) { |
558 return SkLanguage(); | 568 return SkLanguage(); |
559 } | 569 } |
560 size_t parentTagLen = parentTagEnd - tag; | 570 size_t parentTagLen = parentTagEnd - tag; |
561 return SkLanguage(tag, parentTagLen); | 571 return SkLanguage(tag, parentTagLen); |
562 } | 572 } |
OLD | NEW |