| 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 |