diff options
author | Russell Brenner <russellbrenner@google.com> | 2012-03-07 17:23:37 -0800 |
---|---|---|
committer | Russell Brenner <russellbrenner@google.com> | 2012-03-13 10:14:04 -0700 |
commit | d71541402192b57e2e03355594567afcd60c14b8 (patch) | |
tree | 89bdcb4d33949e82c850ee267fdf7053bf5719b9 /src/ports | |
parent | a8a1f8b5da30d0ce9091b8475d336c4ddb0f2b4e (diff) | |
download | external_skia-d71541402192b57e2e03355594567afcd60c14b8.zip external_skia-d71541402192b57e2e03355594567afcd60c14b8.tar.gz external_skia-d71541402192b57e2e03355594567afcd60c14b8.tar.bz2 |
Reload fallback fonts when system language changes
When the system locale is changed, skia reloads its fallback fonts
using the best-matching configuration files for both framework and
vendor.
Bug: 5873170
Change-Id: Ie1d13cb404905ae2af05d8f20fbd857c96f39e4b
Diffstat (limited to 'src/ports')
-rw-r--r-- | src/ports/FontHostConfiguration_android.cpp | 90 | ||||
-rw-r--r-- | src/ports/FontHostConfiguration_android.h | 17 | ||||
-rw-r--r-- | src/ports/SkFontHost_android.cpp | 132 |
3 files changed, 222 insertions, 17 deletions
diff --git a/src/ports/FontHostConfiguration_android.cpp b/src/ports/FontHostConfiguration_android.cpp index 475dc4a..d1164c8 100644 --- a/src/ports/FontHostConfiguration_android.cpp +++ b/src/ports/FontHostConfiguration_android.cpp @@ -16,8 +16,12 @@ */ #include "FontHostConfiguration_android.h" -#include <expat.h> +#include "SkString.h" #include "SkTDArray.h" +#include <expat.h> +#if !defined(SK_BUILD_FOR_ANDROID_NDK) + #include <cutils/properties.h> +#endif #define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" @@ -127,6 +131,65 @@ void endElementHandler(void *data, const char *tag) { } } +#if !defined(SK_BUILD_FOR_ANDROID_NDK) +/** + * Read the persistent locale. + */ +void getLocale(char* language, char* region) +{ + char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX]; + + property_get("persist.sys.language", propLang, ""); + property_get("persist.sys.country", propRegn, ""); + if (*propLang == 0 && *propRegn == 0) { + /* Set to ro properties, default is en_US */ + property_get("ro.product.locale.language", propLang, "en"); + property_get("ro.product.locale.region", propRegn, "US"); + } + strncat(language, propLang, 2); + strncat(region, propRegn, 2); +} +#endif + +/** + * Use the current system locale (language and region) to open the best matching + * customization. For example, when the language is Japanese, the sequence might be: + * /system/etc/fallback_fonts-ja-JP.xml + * /system/etc/fallback_fonts-ja.xml + * /system/etc/fallback_fonts.xml + */ +FILE* openLocalizedFile(const char* origname) { + FILE* file = 0; + +#if !defined(SK_BUILD_FOR_ANDROID_NDK) + SkString basename; + SkString filename; + char language[3] = ""; + char region[3] = ""; + + basename.set(origname); + // Remove the .xml suffix. We'll add it back in a moment. + if (basename.endsWith(".xml")) { + basename.resize(basename.size()-4); + } + getLocale(language, region); + // Try first with language and region + filename.printf("%s-%s-%s.xml", basename.c_str(), language, region); + file = fopen(filename.c_str(), "r"); + if (!file) { + // If not found, try next with just language + filename.printf("%s-%s.xml", basename.c_str(), language); + file = fopen(filename.c_str(), "r"); + } +#endif + + if (!file) { + // If still not found, try just the original name + file = fopen(origname, "r"); + } + return file; +} + /** * This function parses the given filename and stores the results in the given * families array. @@ -136,7 +199,7 @@ void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) { FamilyData *familyData = new FamilyData(&parser, families); XML_SetUserData(parser, familyData); XML_SetElementHandler(parser, startElementHandler, endElementHandler); - FILE *file = fopen(filename, "r"); + FILE *file = openLocalizedFile(filename); // Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml) // are optional - failure here is okay because one of these optional files may not exist. if (file == NULL) { @@ -154,15 +217,12 @@ void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) { } } -/** - * Loads data on font families from various expected configuration files. The - * resulting data is returned in the given fontFamilies array. - */ -void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies) { +void getSystemFontFamilies(SkTDArray<FontFamily*> &fontFamilies) { + parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies); +} - SkTDArray<FontFamily*> fallbackFonts; +void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts) { SkTDArray<FontFamily*> vendorFonts; - parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies); parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts); parseConfigFile(VENDOR_FONTS_FILE, vendorFonts); @@ -188,6 +248,18 @@ void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies) { currentOrder = order + 1; } } +} + +/** + * Loads data on font families from various expected configuration files. The + * resulting data is returned in the given fontFamilies array. + */ +void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies) { + SkTDArray<FontFamily*> fallbackFonts; + + getSystemFontFamilies(fontFamilies); + getFallbackFontFamilies(fallbackFonts); + // Append all fallback fonts to system fonts for (int i = 0; i < fallbackFonts.count(); ++i) { *fontFamilies.append() = fallbackFonts[i]; diff --git a/src/ports/FontHostConfiguration_android.h b/src/ports/FontHostConfiguration_android.h index 010f0ef..2441f0e 100644 --- a/src/ports/FontHostConfiguration_android.h +++ b/src/ports/FontHostConfiguration_android.h @@ -39,4 +39,21 @@ struct FontFamily { */ void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies); +/** + * Parse only the core system font configuration file and return the results in + * an array of FontFamily structures. + */ +void getSystemFontFamilies(SkTDArray<FontFamily*> &fontFamilies); + + +/** + * Parse the fallback and vendor system font configuration files and return the + * results in an array of FontFamily structures. + */ +void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts); + +#if !defined(SK_BUILD_FOR_ANDROID_NDK) + void getLocale(char* language, char* region); +#endif + #endif /* FONTHOSTCONFIGURATION_ANDROID_H_ */ diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp index 1856cff..f2893a8 100644 --- a/src/ports/SkFontHost_android.cpp +++ b/src/ports/SkFontHost_android.cpp @@ -16,6 +16,7 @@ */ #include "SkFontHost.h" +#include "SkGraphics.h" #include "SkDescriptor.h" #include "SkMMapStream.h" #include "SkPaint.h" @@ -25,6 +26,7 @@ #include "SkTSearch.h" #include "FontHostConfiguration_android.h" #include <stdio.h> +#include <string.h> #define FONT_CACHE_MEMORY_BUDGET (768 * 1024) @@ -72,6 +74,7 @@ static int32_t gUniqueFontID; // this is the mutex that protects gFamilyHead and GetNameList() SK_DECLARE_STATIC_MUTEX(gFamilyHeadAndNameListMutex); static FamilyRec* gFamilyHead; +static SkTDArray<NameFamilyPair> gFallbackFilenameList; static NameFamilyPairList& GetNameList() { /* @@ -264,7 +267,6 @@ public: : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) { fIsSysFont = sysFont; - // our caller has acquired the gFamilyHeadAndNameListMutex so this is safe FamilyRec* rec = NULL; if (familyMember) { @@ -423,18 +425,72 @@ static const char* gFBNames[] = { NULL }; static FontInitRec *gSystemFonts; static size_t gNumSystemFonts = 0; -#define SYSTEM_FONTS_FILE "/system/etc/system_fonts.cfg" - // these globals are assigned (once) by load_system_fonts() static FamilyRec* gDefaultFamily; static SkTypeface* gDefaultNormal; static char** gDefaultNames = NULL; static uint32_t *gFallbackFonts; +static void dump_globals() { + SkDebugf("gDefaultNormal=%p id=%u refCnt=%d", gDefaultNormal, + gDefaultNormal ? gDefaultNormal->uniqueID() : 0, + gDefaultNormal ? gDefaultNormal->getRefCnt() : 0); + + if (gDefaultFamily) { + SkDebugf("gDefaultFamily=%p fFaces={%u,%u,%u,%u} refCnt={%d,%d,%d,%d}", + gDefaultFamily, + gDefaultFamily->fFaces[0] ? gDefaultFamily->fFaces[0]->uniqueID() : 0, + gDefaultFamily->fFaces[1] ? gDefaultFamily->fFaces[1]->uniqueID() : 0, + gDefaultFamily->fFaces[2] ? gDefaultFamily->fFaces[2]->uniqueID() : 0, + gDefaultFamily->fFaces[3] ? gDefaultFamily->fFaces[3]->uniqueID() : 0, + gDefaultFamily->fFaces[0] ? gDefaultFamily->fFaces[0]->getRefCnt() : 0, + gDefaultFamily->fFaces[1] ? gDefaultFamily->fFaces[1]->getRefCnt() : 0, + gDefaultFamily->fFaces[2] ? gDefaultFamily->fFaces[2]->getRefCnt() : 0, + gDefaultFamily->fFaces[3] ? gDefaultFamily->fFaces[3]->getRefCnt() : 0); + } else { + SkDebugf("gDefaultFamily=%p", gDefaultFamily); + } + + SkDebugf("gNumSystemFonts=%d gSystemFonts=%p gFallbackFonts=%p", + gNumSystemFonts, gSystemFonts, gFallbackFonts); + + for (size_t i = 0; i < gNumSystemFonts; ++i) { + SkDebugf("gSystemFonts[%d] fileName=%s", i, gSystemFonts[i].fFileName); + size_t namesIndex = 0; + if (gSystemFonts[i].fNames) + for (const char* fontName = gSystemFonts[i].fNames[namesIndex]; + fontName != 0; + fontName = gSystemFonts[i].fNames[++namesIndex]) { + SkDebugf(" name[%u]=%s", namesIndex, fontName); + } + } + + if (gFamilyHead) { + FamilyRec* rec = gFamilyHead; + int i=0; + while (rec) { + SkDebugf("gFamilyHead[%d]=%p fFaces={%u,%u,%u,%u} refCnt={%d,%d,%d,%d}", + i++, rec, + rec->fFaces[0] ? rec->fFaces[0]->uniqueID() : 0, + rec->fFaces[1] ? rec->fFaces[1]->uniqueID() : 0, + rec->fFaces[2] ? rec->fFaces[2]->uniqueID() : 0, + rec->fFaces[3] ? rec->fFaces[3]->uniqueID() : 0, + rec->fFaces[0] ? rec->fFaces[0]->getRefCnt() : 0, + rec->fFaces[1] ? rec->fFaces[1]->getRefCnt() : 0, + rec->fFaces[2] ? rec->fFaces[2]->getRefCnt() : 0, + rec->fFaces[3] ? rec->fFaces[3]->getRefCnt() : 0); + rec = rec->fNext; + } + } else { + SkDebugf("gFamilyHead=%p", gFamilyHead); + } + +} + + /* Load info from a configuration file that populates the system/fallback font structures */ static void load_font_info() { -// load_font_info_xml("/system/etc/system_fonts.xml"); SkTDArray<FontFamily*> fontFamilies; getFontFamilies(fontFamilies); @@ -495,9 +551,9 @@ static void load_font_info() { * * gFamilyHeadAndNameListMutex must already be acquired. */ -static void load_system_fonts() { - // check if we've already be called - if (NULL != gDefaultNormal) { +static void init_system_fonts() { + // check if we've already been called + if (gDefaultNormal) { return; } @@ -565,6 +621,65 @@ static void load_system_fonts() { gFallbackFonts[fallbackCount] = 0; } +static size_t find_uniqueID(const char* filename) { + // uniqueID is the index, offset by one, of the associated element in gSystemFonts[] + // return 0 if not found + const FontInitRec* rec = gSystemFonts; + for (size_t i = 0; i < gNumSystemFonts; i++) { + if (strcmp(rec[i].fFileName, filename) == 0) { + return i+1; + } + } + return 0; +} + +static void reload_fallback_fonts() { + SkGraphics::PurgeFontCache(); + + SkTDArray<FontFamily*> fallbackFamilies; + getFallbackFontFamilies(fallbackFamilies); + + for (int i = 0; i < fallbackFamilies.count(); ++i) { + FontFamily *family = fallbackFamilies[i]; + + for (int j = 0; j < family->fFileNames.count(); ++j) { + if (family->fFileNames[j]) { + size_t uniqueID = find_uniqueID(family->fFileNames[j]); + if (uniqueID != gFallbackFonts[i]) + gFallbackFonts[i] = uniqueID; + break; // The fallback set contains only the first font of each family + } + } + } +} + +static void load_system_fonts() { +#if !defined(SK_BUILD_FOR_ANDROID_NDK) + static char prevLanguage[3]; + static char prevRegion[3]; + char language[3] = ""; + char region[3] = ""; + + getLocale(language, region); + + if (!gDefaultNormal) { + strncpy(prevLanguage, language, 2); + strncpy(prevRegion, region, 2); + init_system_fonts(); + } else if (strncmp(language, prevLanguage, 2) || strncmp(region, prevRegion, 2)) { + strncpy(prevLanguage, language, 2); + strncpy(prevRegion, region, 2); + reload_fallback_fonts(); + } +#else + if (!gDefaultNormal) { + init_system_fonts(); + reload_fallback_fonts(); + } +#endif +} + + /////////////////////////////////////////////////////////////////////////////// void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { @@ -683,7 +798,7 @@ SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, tf = find_best_face(gDefaultFamily, style); } - // we ref(), since the symantic is to return a new instance + // we ref(), since the semantic is to return a new instance tf->ref(); return tf; } @@ -732,6 +847,7 @@ SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { SkASSERT(origTypeface != 0); SkASSERT(currTypeface != 0); + SkASSERT(gFallbackFonts); // Our fallback list always stores the id of the plain in each fallback // family, so we transform currFontID to its plain equivalent. |