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