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 <stdio.h> | 15 #include <stdio.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 #define LOCALE_FALLBACK_FONTS_SYSTEM_DIR "/system/etc" |
| 24 #define LOCALE_FALLBACK_FONTS_VENDOR_DIR "/vendor/etc" |
| 25 #define LOCALE_FALLBACK_FONTS_PREFIX "fallback_fonts-" |
| 26 #define LOCALE_FALLBACK_FONTS_SUFFIX ".xml" |
| 27 |
23 /** | 28 /** |
24 * This file contains TWO parsers: one for JB and earlier (system_fonts.xml / | 29 * This file contains TWO parsers: one for JB and earlier (system_fonts.xml / |
25 * fallback_fonts.xml), one for LMP and later (fonts.xml). | 30 * 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 | 31 * 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. | 32 * version 21 or higher we switch to the LMP parser. |
28 */ | 33 */ |
29 | 34 |
30 // These defines are used to determine the kind of tag that we're currently | 35 // These defines are used to determine the kind of tag that we're currently |
31 // populating with data. We only care about the sibling tags nameset and fileset | 36 // populating with data. We only care about the sibling tags nameset and fileset |
32 // for now. | 37 // for now. |
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
404 } | 409 } |
405 | 410 |
406 } // namespace jbParser | 411 } // namespace jbParser |
407 | 412 |
408 /** | 413 /** |
409 * This function parses the given filename and stores the results in the given | 414 * This function parses the given filename and stores the results in the given |
410 * families array. | 415 * families array. |
411 */ | 416 */ |
412 static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &famili
es) { | 417 static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &famili
es) { |
413 | 418 |
414 FILE* file = NULL; | 419 FILE* file = fopen(filename, "r"); |
415 | |
416 #if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) | |
417 // if we are using a version of Android prior to Android 4.2 (JellyBean MR1 | |
418 // at API Level 17) then we need to look for files with a different suffix. | |
419 char sdkVersion[PROP_VALUE_MAX]; | |
420 __system_property_get("ro.build.version.sdk", sdkVersion); | |
421 const int sdkVersionInt = atoi(sdkVersion); | |
422 | |
423 if (0 != *sdkVersion && sdkVersionInt < 17) { | |
424 SkString basename; | |
425 SkString updatedFilename; | |
426 SkString locale = SkFontConfigParser::GetLocale(); | |
427 | |
428 basename.set(filename); | |
429 // Remove the .xml suffix. We'll add it back in a moment. | |
430 if (basename.endsWith(".xml")) { | |
431 basename.resize(basename.size()-4); | |
432 } | |
433 // Try first with language and region | |
434 updatedFilename.printf("%s-%s.xml", basename.c_str(), locale.c_str()); | |
435 file = fopen(updatedFilename.c_str(), "r"); | |
436 if (!file) { | |
437 // If not found, try next with just language | |
438 updatedFilename.printf("%s-%.2s.xml", basename.c_str(), locale.c_str
()); | |
439 file = fopen(updatedFilename.c_str(), "r"); | |
440 } | |
441 } | |
442 #endif | |
443 | |
444 if (NULL == file) { | |
445 file = fopen(filename, "r"); | |
446 } | |
447 | 420 |
448 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac
k_fonts.xml) | 421 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac
k_fonts.xml) |
449 // are optional - failure here is okay because one of these optional files m
ay not exist. | 422 // are optional - failure here is okay because one of these optional files m
ay not exist. |
450 if (NULL == file) { | 423 if (NULL == file) { |
451 return; | 424 return; |
452 } | 425 } |
453 | 426 |
454 XML_Parser parser = XML_ParserCreate(NULL); | 427 XML_Parser parser = XML_ParserCreate(NULL); |
455 FamilyData *familyData = new FamilyData(&parser, families); | 428 FamilyData *familyData = new FamilyData(&parser, families); |
456 XML_SetUserData(parser, familyData); | 429 XML_SetUserData(parser, familyData); |
(...skipping 11 matching lines...) Expand all Loading... |
468 XML_Parse(parser, buffer, len, done); | 441 XML_Parse(parser, buffer, len, done); |
469 } | 442 } |
470 XML_ParserFree(parser); | 443 XML_ParserFree(parser); |
471 fclose(file); | 444 fclose(file); |
472 } | 445 } |
473 | 446 |
474 static void getSystemFontFamilies(SkTDArray<FontFamily*> &fontFamilies) { | 447 static void getSystemFontFamilies(SkTDArray<FontFamily*> &fontFamilies) { |
475 parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies); | 448 parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies); |
476 } | 449 } |
477 | 450 |
| 451 /** |
| 452 * In some versions of Android prior to Android 4.2 (JellyBean MR1 at API |
| 453 * Level 17) the fallback fonts for certain locales were encoded in their own |
| 454 * XML files with a suffix that identified the locale. We search the provided |
| 455 * directory for those files,add all of their entries to the fallback chain, and |
| 456 * include the locale as part of each entry. |
| 457 */ |
| 458 static void getFallbackFontFamiliesForLocale(SkTDArray<FontFamily*> &fallbackFon
ts, const char* dir) { |
| 459 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) |
| 460 // The framework is beyond Android 4.2 and can therefore skip this function |
| 461 return; |
| 462 #endif |
| 463 |
| 464 DIR* fontDirectory = opendir(dir); |
| 465 if (fontDirectory != NULL){ |
| 466 struct dirent* dirEntry = readdir(fontDirectory); |
| 467 while (dirEntry) { |
| 468 |
| 469 // The size of both the prefix, suffix, and a minimum valid language
code |
| 470 static const int minSize = strlen(LOCALE_FALLBACK_FONTS_PREFIX) + |
| 471 strlen(LOCALE_FALLBACK_FONTS_SUFFIX) + 2; |
| 472 |
| 473 SkString fileName(dirEntry->d_name); |
| 474 if (fileName.size() >= minSize && |
| 475 fileName.startsWith(LOCALE_FALLBACK_FONTS_PREFIX) && |
| 476 fileName.endsWith(LOCALE_FALLBACK_FONTS_SUFFIX)) { |
| 477 |
| 478 static const int fixedLen = strlen(LOCALE_FALLBACK_FONTS_PREFIX)
- |
| 479 strlen(LOCALE_FALLBACK_FONTS_SUFFIX)
; |
| 480 |
| 481 SkString locale(fileName.c_str() - strlen(LOCALE_FALLBACK_FONTS_
PREFIX), |
| 482 fileName.size() - fixedLen); |
| 483 |
| 484 SkString absoluteFilename; |
| 485 absoluteFilename.printf("%s/%s", dir, fileName.c_str()); |
| 486 |
| 487 SkTDArray<FontFamily*> langSpecificFonts; |
| 488 parseConfigFile(absoluteFilename.c_str(), langSpecificFonts); |
| 489 |
| 490 for (int i = 0; i < langSpecificFonts.count(); ++i) { |
| 491 FontFamily* family = langSpecificFonts[i]; |
| 492 for (int j = 0; j < family->fFontFiles.count(); ++j) { |
| 493 family->fFontFiles[j].fPaintOptions.setLanguage(locale); |
| 494 } |
| 495 *fallbackFonts.append() = family; |
| 496 } |
| 497 } |
| 498 |
| 499 // proceed to the next entry in the directory |
| 500 dirEntry = readdir(fontDirectory); |
| 501 } |
| 502 // cleanup the directory reference |
| 503 closedir(fontDirectory); |
| 504 } |
| 505 } |
| 506 |
478 static void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts) { | 507 static void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts) { |
479 SkTDArray<FontFamily*> vendorFonts; | 508 SkTDArray<FontFamily*> vendorFonts; |
480 parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts); | 509 parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts); |
481 parseConfigFile(VENDOR_FONTS_FILE, vendorFonts); | 510 parseConfigFile(VENDOR_FONTS_FILE, vendorFonts); |
482 | 511 |
| 512 getFallbackFontFamiliesForLocale(fallbackFonts, LOCALE_FALLBACK_FONTS_SYSTEM
_DIR); |
| 513 getFallbackFontFamiliesForLocale(vendorFonts, LOCALE_FALLBACK_FONTS_VENDOR_D
IR); |
| 514 |
483 // This loop inserts the vendor fallback fonts in the correct order in the | 515 // This loop inserts the vendor fallback fonts in the correct order in the |
484 // overall fallbacks list. | 516 // overall fallbacks list. |
485 int currentOrder = -1; | 517 int currentOrder = -1; |
486 for (int i = 0; i < vendorFonts.count(); ++i) { | 518 for (int i = 0; i < vendorFonts.count(); ++i) { |
487 FontFamily* family = vendorFonts[i]; | 519 FontFamily* family = vendorFonts[i]; |
488 int order = family->order; | 520 int order = family->order; |
489 if (order < 0) { | 521 if (order < 0) { |
490 if (currentOrder < 0) { | 522 if (currentOrder < 0) { |
491 // Default case - just add it to the end of the fallback list | 523 // Default case - just add it to the end of the fallback list |
492 *fallbackFonts.append() = family; | 524 *fallbackFonts.append() = family; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 if (NULL != testFallbackConfigFile) { | 562 if (NULL != testFallbackConfigFile) { |
531 parseConfigFile(testFallbackConfigFile, fallbackFonts); | 563 parseConfigFile(testFallbackConfigFile, fallbackFonts); |
532 } | 564 } |
533 | 565 |
534 // Append all fallback fonts to system fonts | 566 // Append all fallback fonts to system fonts |
535 for (int i = 0; i < fallbackFonts.count(); ++i) { | 567 for (int i = 0; i < fallbackFonts.count(); ++i) { |
536 fallbackFonts[i]->fIsFallbackFont = true; | 568 fallbackFonts[i]->fIsFallbackFont = true; |
537 *fontFamilies.append() = fallbackFonts[i]; | 569 *fontFamilies.append() = fallbackFonts[i]; |
538 } | 570 } |
539 } | 571 } |
540 | |
541 /** | |
542 * Read the persistent locale. | |
543 */ | |
544 SkString SkFontConfigParser::GetLocale() | |
545 { | |
546 char propLang[PROP_VALUE_MAX], propRegn[PROP_VALUE_MAX]; | |
547 __system_property_get("persist.sys.language", propLang); | |
548 __system_property_get("persist.sys.country", propRegn); | |
549 | |
550 if (*propLang == 0 && *propRegn == 0) { | |
551 /* Set to ro properties, default is en_US */ | |
552 __system_property_get("ro.product.locale.language", propLang); | |
553 __system_property_get("ro.product.locale.region", propRegn); | |
554 if (*propLang == 0 && *propRegn == 0) { | |
555 strcpy(propLang, "en"); | |
556 strcpy(propRegn, "US"); | |
557 } | |
558 } | |
559 | |
560 SkString locale(6); | |
561 char* localeCStr = locale.writable_str(); | |
562 | |
563 strncpy(localeCStr, propLang, 2); | |
564 localeCStr[2] = '-'; | |
565 strncpy(&localeCStr[3], propRegn, 2); | |
566 localeCStr[5] = '\0'; | |
567 | |
568 return locale; | |
569 } | |
OLD | NEW |