aboutsummaryrefslogtreecommitdiffstats
path: root/src/ports
diff options
context:
space:
mode:
authorRussell Brenner <russellbrenner@google.com>2012-03-07 17:23:37 -0800
committerRussell Brenner <russellbrenner@google.com>2012-03-13 10:14:04 -0700
commitd71541402192b57e2e03355594567afcd60c14b8 (patch)
tree89bdcb4d33949e82c850ee267fdf7053bf5719b9 /src/ports
parenta8a1f8b5da30d0ce9091b8475d336c4ddb0f2b4e (diff)
downloadexternal_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.cpp90
-rw-r--r--src/ports/FontHostConfiguration_android.h17
-rw-r--r--src/ports/SkFontHost_android.cpp132
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.