| Index: src/ports/SkFontConfigParser_android.cpp
|
| diff --git a/src/ports/FontHostConfiguration_android.cpp b/src/ports/SkFontConfigParser_android.cpp
|
| similarity index 64%
|
| copy from src/ports/FontHostConfiguration_android.cpp
|
| copy to src/ports/SkFontConfigParser_android.cpp
|
| index ef5a742a18ab90eb22108be000d3d2641f1fef36..9214d1bf61484e8addc8198ca4753d840c61c234 100644
|
| --- a/src/ports/FontHostConfiguration_android.cpp
|
| +++ b/src/ports/SkFontConfigParser_android.cpp
|
| @@ -5,9 +5,10 @@
|
| * found in the LICENSE file.
|
| */
|
|
|
| -#include "FontHostConfiguration_android.h"
|
| -#include "SkString.h"
|
| +#include "SkFontConfigParser_android.h"
|
| #include "SkTDArray.h"
|
| +#include "SkTypeface.h"
|
| +
|
| #include <expat.h>
|
| #include <sys/system_properties.h>
|
|
|
| @@ -15,7 +16,6 @@
|
| #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml"
|
| #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml"
|
|
|
| -
|
| // These defines are used to determine the kind of tag that we're currently
|
| // populating with data. We only care about the sibling tags nameset and fileset
|
| // for now.
|
| @@ -28,24 +28,25 @@
|
| * can read these variables that are relevant to the current parsing.
|
| */
|
| struct FamilyData {
|
| - FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef, const AndroidLocale &localeRef) :
|
| - parser(parserRef), families(familiesRef), currentTag(NO_TAG),
|
| - locale(localeRef), currentFamilyLangMatch(false), familyLangMatchCount(0) {}
|
| + FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef) :
|
| + parser(parserRef),
|
| + families(familiesRef),
|
| + currentFamily(NULL),
|
| + currentFontInfo(NULL),
|
| + currentTag(NO_TAG) {};
|
|
|
| XML_Parser *parser; // The expat parser doing the work
|
| SkTDArray<FontFamily*> &families; // The array that each family is put into as it is parsed
|
| FontFamily *currentFamily; // The current family being created
|
| + FontFileInfo *currentFontInfo; // The current fontInfo being created
|
| int currentTag; // A flag to indicate whether we're in nameset/fileset tags
|
| - const AndroidLocale &locale; // The locale to which we compare the "lang" attribute of File.
|
| - bool currentFamilyLangMatch; // If currentFamily's File has a "lang" attribute and matches locale.
|
| - int familyLangMatchCount; // Number of families containing File which has a "lang" attribute and matches locale.
|
| };
|
|
|
| /**
|
| * Handler for arbitrary text. This is used to parse the text inside each name
|
| - * or file tag. The resulting strings are put into the fNames or fFileNames arrays.
|
| + * or file tag. The resulting strings are put into the fNames or FontFileInfo arrays.
|
| */
|
| -void textHandler(void *data, const char *s, int len) {
|
| +static void textHandler(void *data, const char *s, int len) {
|
| FamilyData *familyData = (FamilyData*) data;
|
| // Make sure we're in the right state to store this name information
|
| if (familyData->currentFamily &&
|
| @@ -60,7 +61,9 @@ void textHandler(void *data, const char *s, int len) {
|
| *(familyData->currentFamily->fNames.append()) = buff;
|
| break;
|
| case FILESET_TAG:
|
| - *(familyData->currentFamily->fFileNames.append()) = buff;
|
| + if (familyData->currentFontInfo) {
|
| + familyData->currentFontInfo->fFileName = buff;
|
| + }
|
| break;
|
| default:
|
| // Noop - don't care about any text that's not in the Fonts or Names list
|
| @@ -70,10 +73,41 @@ void textHandler(void *data, const char *s, int len) {
|
| }
|
|
|
| /**
|
| + * Handler for font files. This processes the attributes for language and
|
| + * variants then lets textHandler handle the actual file name
|
| + */
|
| +static void fontFileElementHandler(FamilyData *familyData, const char **attributes) {
|
| + FontFileInfo* newFileInfo = new FontFileInfo();
|
| + if (attributes) {
|
| + int currentAttributeIndex = 0;
|
| + while (attributes[currentAttributeIndex]) {
|
| + const char* attributeName = attributes[currentAttributeIndex];
|
| + const char* attributeValue = attributes[currentAttributeIndex+1];
|
| + int nameLength = strlen(attributeName);
|
| + int valueLength = strlen(attributeValue);
|
| + if (strncmp(attributeName, "variant", nameLength) == 0) {
|
| + if (strncmp(attributeValue, "elegant", valueLength) == 0) {
|
| + newFileInfo->fPaintOptions.setFontVariant(SkPaintOptionsAndroid::kElegant_Variant);
|
| + } else if (strncmp(attributeValue, "compact", valueLength) == 0) {
|
| + newFileInfo->fPaintOptions.setFontVariant(SkPaintOptionsAndroid::kCompact_Variant);
|
| + }
|
| + } else if (strncmp(attributeName, "lang", nameLength) == 0) {
|
| + newFileInfo->fPaintOptions.setLanguage(attributeValue);
|
| + }
|
| + //each element is a pair of attributeName/attributeValue string pairs
|
| + currentAttributeIndex += 2;
|
| + }
|
| + }
|
| + *(familyData->currentFamily->fFontFiles.append()) = newFileInfo;
|
| + familyData->currentFontInfo = newFileInfo;
|
| + XML_SetCharacterDataHandler(*familyData->parser, textHandler);
|
| +}
|
| +
|
| +/**
|
| * Handler for the start of a tag. The only tags we expect are family, nameset,
|
| * fileset, name, and file.
|
| */
|
| -void startElementHandler(void *data, const char *tag, const char **atts) {
|
| +static void startElementHandler(void *data, const char *tag, const char **atts) {
|
| FamilyData *familyData = (FamilyData*) data;
|
| int len = strlen(tag);
|
| if (strncmp(tag, "family", len)== 0) {
|
| @@ -89,32 +123,16 @@ void startElementHandler(void *data, const char *tag, const char **atts) {
|
| familyData->currentFamily->order = value;
|
| }
|
| }
|
| - } else if (len == 7 && strncmp(tag, "nameset", len)== 0) {
|
| + } else if (len == 7 && strncmp(tag, "nameset", len) == 0) {
|
| familyData->currentTag = NAMESET_TAG;
|
| } else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
|
| familyData->currentTag = FILESET_TAG;
|
| } else if (strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) {
|
| + // If it's a Name, parse the text inside
|
| XML_SetCharacterDataHandler(*familyData->parser, textHandler);
|
| } else if (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG) {
|
| - // From JB MR1, the File tag has a "lang" attribute to specify a language specific font file
|
| - // and the family entry has higher priority than the others without "lang" attribute.
|
| - bool includeTheEntry = true;
|
| - for (int i = 0; atts[i] != NULL; i += 2) {
|
| - const char* attribute = atts[i];
|
| - const char* value = atts[i+1];
|
| - if (strncmp(attribute, "lang", 4) == 0) {
|
| - if (strcmp(value, familyData->locale.language) == 0) {
|
| - // Found matching "lang" attribute. The current Family will have higher priority in the family list.
|
| - familyData->currentFamilyLangMatch = true;
|
| - } else {
|
| - // Don't include the entry if "lang" is specified but not matching.
|
| - includeTheEntry = false;
|
| - }
|
| - }
|
| - }
|
| - if (includeTheEntry) {
|
| - XML_SetCharacterDataHandler(*familyData->parser, textHandler);
|
| - }
|
| + // If it's a file, parse the attributes, then parse the text inside
|
| + fontFileElementHandler(familyData, atts);
|
| }
|
| }
|
|
|
| @@ -122,21 +140,16 @@ void startElementHandler(void *data, const char *tag, const char **atts) {
|
| * Handler for the end of tags. We only care about family, nameset, fileset,
|
| * name, and file.
|
| */
|
| -void endElementHandler(void *data, const char *tag) {
|
| +static void endElementHandler(void *data, const char *tag) {
|
| FamilyData *familyData = (FamilyData*) data;
|
| int len = strlen(tag);
|
| if (strncmp(tag, "family", len)== 0) {
|
| // Done parsing a Family - store the created currentFamily in the families array
|
| - if (familyData->currentFamilyLangMatch) {
|
| - *familyData->families.insert(familyData->familyLangMatchCount++) = familyData->currentFamily;
|
| - familyData->currentFamilyLangMatch = false;
|
| - } else {
|
| - *familyData->families.append() = familyData->currentFamily;
|
| - }
|
| + *familyData->families.append() = familyData->currentFamily;
|
| familyData->currentFamily = NULL;
|
| - } else if (len == 7 && strncmp(tag, "nameset", len)== 0) {
|
| + } else if (len == 7 && strncmp(tag, "nameset", len) == 0) {
|
| familyData->currentTag = NO_TAG;
|
| - } else if (len == 7 && strncmp(tag, "fileset", len)== 0) {
|
| + } else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
|
| familyData->currentTag = NO_TAG;
|
| } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) ||
|
| (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG)) {
|
| @@ -146,74 +159,15 @@ void endElementHandler(void *data, const char *tag) {
|
| }
|
|
|
| /**
|
| - * Read the persistent locale.
|
| - */
|
| -void getLocale(AndroidLocale &locale)
|
| -{
|
| - char propLang[PROP_VALUE_MAX], propRegn[PROP_VALUE_MAX];
|
| - __system_property_get("persist.sys.language", propLang);
|
| - __system_property_get("persist.sys.country", propRegn);
|
| -
|
| - if (*propLang == 0 && *propRegn == 0) {
|
| - /* Set to ro properties, default is en_US */
|
| - __system_property_get("ro.product.locale.language", propLang);
|
| - __system_property_get("ro.product.locale.region", propRegn);
|
| - if (*propLang == 0 && *propRegn == 0) {
|
| - strcpy(propLang, "en");
|
| - strcpy(propRegn, "US");
|
| - }
|
| - }
|
| - strncpy(locale.language, propLang, 2);
|
| - locale.language[2] = '\0';
|
| - strncpy(locale.region, propRegn, 2);
|
| - locale.region[2] = '\0';
|
| -}
|
| -
|
| -/**
|
| - * 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, const AndroidLocale& locale) {
|
| - FILE* file = 0;
|
| - SkString basename;
|
| - SkString filename;
|
| -
|
| - basename.set(origname);
|
| - // Remove the .xml suffix. We'll add it back in a moment.
|
| - if (basename.endsWith(".xml")) {
|
| - basename.resize(basename.size()-4);
|
| - }
|
| - // Try first with language and region
|
| - filename.printf("%s-%s-%s.xml", basename.c_str(), locale.language, locale.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(), locale.language);
|
| - file = fopen(filename.c_str(), "r");
|
| -
|
| - 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.
|
| */
|
| -void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) {
|
| - AndroidLocale locale;
|
| - getLocale(locale);
|
| +static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) {
|
| XML_Parser parser = XML_ParserCreate(NULL);
|
| - FamilyData familyData(&parser, families, locale);
|
| - XML_SetUserData(parser, &familyData);
|
| + FamilyData *familyData = new FamilyData(&parser, families);
|
| + XML_SetUserData(parser, familyData);
|
| XML_SetElementHandler(parser, startElementHandler, endElementHandler);
|
| - FILE *file = openLocalizedFile(filename, locale);
|
| + FILE *file = fopen(filename, "r");
|
| // 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) {
|
| @@ -230,14 +184,13 @@ void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) {
|
| XML_Parse(parser, buffer, len, done);
|
| }
|
| fclose(file);
|
| - XML_ParserFree(parser);
|
| }
|
|
|
| -void getSystemFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
|
| +static void getSystemFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
|
| parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies);
|
| }
|
|
|
| -void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts) {
|
| +static void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts) {
|
| SkTDArray<FontFamily*> vendorFonts;
|
| parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts);
|
| parseConfigFile(VENDOR_FONTS_FILE, vendorFonts);
|
| @@ -270,21 +223,22 @@ void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts) {
|
| * 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;
|
| +void SkFontConfigParser::GetFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
|
|
|
| getSystemFontFamilies(fontFamilies);
|
| - getFallbackFontFamilies(fallbackFonts);
|
|
|
| - // Append all fallback fonts to system fonts
|
| + // Append all the fallback fonts to system fonts
|
| + SkTDArray<FontFamily*> fallbackFonts;
|
| + getFallbackFontFamilies(fallbackFonts);
|
| for (int i = 0; i < fallbackFonts.count(); ++i) {
|
| + fallbackFonts[i]->fIsFallbackFont = true;
|
| *fontFamilies.append() = fallbackFonts[i];
|
| }
|
| }
|
|
|
| -void getTestFontFamilies(SkTDArray<FontFamily*> &fontFamilies,
|
| - const char* testMainConfigFile,
|
| - const char* testFallbackConfigFile) {
|
| +void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*> &fontFamilies,
|
| + const char* testMainConfigFile,
|
| + const char* testFallbackConfigFile) {
|
| parseConfigFile(testMainConfigFile, fontFamilies);
|
|
|
| SkTDArray<FontFamily*> fallbackFonts;
|
| @@ -292,6 +246,31 @@ void getTestFontFamilies(SkTDArray<FontFamily*> &fontFamilies,
|
|
|
| // Append all fallback fonts to system fonts
|
| for (int i = 0; i < fallbackFonts.count(); ++i) {
|
| + fallbackFonts[i]->fIsFallbackFont = true;
|
| *fontFamilies.append() = fallbackFonts[i];
|
| }
|
| }
|
| +
|
| +/**
|
| + * Read the persistent locale.
|
| + */
|
| +void SkFontConfigParser::GetLocale(AndroidLocale &locale)
|
| +{
|
| + char propLang[PROP_VALUE_MAX], propRegn[PROP_VALUE_MAX];
|
| + __system_property_get("persist.sys.language", propLang);
|
| + __system_property_get("persist.sys.country", propRegn);
|
| +
|
| + if (*propLang == 0 && *propRegn == 0) {
|
| + /* Set to ro properties, default is en_US */
|
| + __system_property_get("ro.product.locale.language", propLang);
|
| + __system_property_get("ro.product.locale.region", propRegn);
|
| + if (*propLang == 0 && *propRegn == 0) {
|
| + strcpy(propLang, "en");
|
| + strcpy(propRegn, "US");
|
| + }
|
| + }
|
| + strncpy(locale.language, propLang, 2);
|
| + locale.language[2] = '\0';
|
| + strncpy(locale.region, propRegn, 2);
|
| + locale.region[2] = '\0';
|
| +}
|
|
|