Index: src/ports/SkFontConfigParser_android.cpp |
diff --git a/src/ports/SkFontConfigParser_android.cpp b/src/ports/SkFontConfigParser_android.cpp |
index cc2ca8cad92f7fe4fcc7e4e66a0c24833081635a..fbbb6a627a2b21f62d52abebaca152fd8fd7875d 100644 |
--- a/src/ports/SkFontConfigParser_android.cpp |
+++ b/src/ports/SkFontConfigParser_android.cpp |
@@ -20,6 +20,13 @@ |
#define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" |
#define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" |
+/** |
+ * This file contains TWO parsers: one for JB and earlier (system_fonts.xml / |
+ * fallback_fonts.xml), one for LMP and later (fonts.xml). |
+ * We start with the JB parser, and if we detect a <familyset> tag with |
+ * version 21 or higher we switch to the LMP parser. |
+ */ |
+ |
// 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. |
@@ -46,6 +53,45 @@ struct FamilyData { |
int currentTag; // A flag to indicate whether we're in nameset/fileset tags |
}; |
+/** http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-negative-def */ |
+template <typename T> static bool parseNonNegativeInteger(const char* s, T* value) { |
+ SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer); |
+ const T nMax = std::numeric_limits<T>::max() / 10; |
+ const T dMax = std::numeric_limits<T>::max() - (nMax * 10); |
+ T n = 0; |
+ for (; *s; ++s) { |
+ // Check if digit |
+ if (*s < '0' || '9' < *s) { |
+ return false; |
+ } |
+ int d = *s - '0'; |
+ // Check for overflow |
+ if (n > nMax || (n == nMax && d > dMax)) { |
+ return false; |
+ } |
+ n = (n * 10) + d; |
+ } |
+ *value = n; |
+ return true; |
+} |
+ |
+namespace lmpParser { |
+ |
+void startElementHandler(void* data, const char* tag, |
+ const char** attributes) { |
+ //SkDebugf("lmp started %s", tag); |
+} |
+ |
+void endElementHandler(void* data, const char* tag) { |
+ |
+ //SkDebugf("lmp ended %s", tag); |
+ |
+} |
+ |
+} // lmpParser |
+ |
+namespace jbParser { |
+ |
/** |
* 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 FontFileInfo arrays. |
@@ -73,34 +119,11 @@ static void textHandler(void *data, const char *s, int len) { |
} |
} |
-/** http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-negative-def */ |
-template <typename T> static bool parseNonNegativeInteger(const char* s, T* value) { |
- SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer); |
- const T nMax = std::numeric_limits<T>::max() / 10; |
- const T dMax = std::numeric_limits<T>::max() - (nMax * 10); |
- T n = 0; |
- for (; *s; ++s) { |
- // Check if digit |
- if (*s < '0' || '9' < *s) { |
- return false; |
- } |
- int d = *s - '0'; |
- // Check for overflow |
- if (n > nMax || (n == nMax && d > dMax)) { |
- return false; |
- } |
- n = (n * 10) + d; |
- } |
- *value = n; |
- return true; |
-} |
- |
/** |
* 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 = familyData->currentFamily->fFontFiles.push_back(); |
if (attributes) { |
int currentAttributeIndex = 0; |
@@ -109,15 +132,16 @@ static void fontFileElementHandler(FamilyData *familyData, const char **attribut |
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) { |
+ if (nameLength == 7 && strncmp(attributeName, "variant", nameLength) == 0) { |
+ if (valueLength == 7 && strncmp(attributeValue, "elegant", valueLength) == 0) { |
newFileInfo.fPaintOptions.setFontVariant(SkPaintOptionsAndroid::kElegant_Variant); |
- } else if (strncmp(attributeValue, "compact", valueLength) == 0) { |
+ } else if (valueLength == 7 && |
+ strncmp(attributeValue, "compact", valueLength) == 0) { |
newFileInfo.fPaintOptions.setFontVariant(SkPaintOptionsAndroid::kCompact_Variant); |
} |
- } else if (strncmp(attributeName, "lang", nameLength) == 0) { |
+ } else if (nameLength == 4 && strncmp(attributeName, "lang", nameLength) == 0) { |
newFileInfo.fPaintOptions.setLanguage(attributeValue); |
- } else if (strncmp(attributeName, "index", nameLength) == 0) { |
+ } else if (nameLength == 5 && strncmp(attributeName, "index", nameLength) == 0) { |
int value; |
if (parseNonNegativeInteger(attributeValue, &value)) { |
newFileInfo.fIndex = value; |
@@ -134,13 +158,26 @@ static void fontFileElementHandler(FamilyData *familyData, const char **attribut |
} |
/** |
- * Handler for the start of a tag. The only tags we expect are family, nameset, |
- * fileset, name, and file. |
+ * Handler for the start of a tag. The only tags we expect are familyset, family, |
+ * nameset, fileset, name, and file. |
*/ |
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) { |
+ if (len == 9 && strncmp(tag, "familyset", len) == 0) { |
+ // The familyset tag has an optional "version" attribute with an integer value >= 0 |
+ for (int i = 0; atts[i] != NULL; i += 2) { |
+ int nameLen = strlen(atts[i]); |
+ if (nameLen == 7 && strncmp(atts[i], "version", nameLen)) continue; |
+ const char* valueString = atts[i+1]; |
+ int version; |
+ if (parseNonNegativeInteger(valueString, &version) && (version >= 21)) { |
+ XML_SetElementHandler(*familyData->parser, |
+ lmpParser::startElementHandler, |
+ lmpParser::endElementHandler); |
+ } |
+ } |
+ } else if (len == 6 && strncmp(tag, "family", len) == 0) { |
familyData->currentFamily = new FontFamily(); |
familyData->currentFamily->order = -1; |
// The Family tag has an optional "order" attribute with an integer value >= 0 |
@@ -148,8 +185,7 @@ static void startElementHandler(void *data, const char *tag, const char **atts) |
for (int i = 0; atts[i] != NULL; i += 2) { |
const char* valueString = atts[i+1]; |
int value; |
- int len = sscanf(valueString, "%d", &value); |
- if (len > 0) { |
+ if (parseNonNegativeInteger(valueString, &value)) { |
familyData->currentFamily->order = value; |
} |
} |
@@ -157,10 +193,10 @@ static void startElementHandler(void *data, const char *tag, const char **atts) |
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) { |
+ } else if (len == 4 && 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) { |
+ } else if (len == 4 && strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG) { |
// If it's a file, parse the attributes, then parse the text inside |
fontFileElementHandler(familyData, atts); |
} |
@@ -173,7 +209,7 @@ static void startElementHandler(void *data, const char *tag, const char **atts) |
static void endElementHandler(void *data, const char *tag) { |
FamilyData *familyData = (FamilyData*) data; |
int len = strlen(tag); |
- if (strncmp(tag, "family", len)== 0) { |
+ if (len == 6 && strncmp(tag, "family", len)== 0) { |
// Done parsing a Family - store the created currentFamily in the families array |
*familyData->families.append() = familyData->currentFamily; |
familyData->currentFamily = NULL; |
@@ -181,13 +217,19 @@ static void endElementHandler(void *data, const char *tag) { |
familyData->currentTag = NO_TAG; |
} 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)) { |
+ } else if ((len == 4 && |
+ strncmp(tag, "name", len) == 0 && |
+ familyData->currentTag == NAMESET_TAG) || |
+ (len == 4 && |
+ strncmp(tag, "file", len) == 0 && |
+ familyData->currentTag == FILESET_TAG)) { |
// Disable the arbitrary text handler installed to load Name data |
XML_SetCharacterDataHandler(*familyData->parser, NULL); |
} |
} |
+} // namespace jbParser |
+ |
/** |
* This function parses the given filename and stores the results in the given |
* families array. |
@@ -237,7 +279,8 @@ static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &famili |
XML_Parser parser = XML_ParserCreate(NULL); |
FamilyData *familyData = new FamilyData(&parser, families); |
XML_SetUserData(parser, familyData); |
- XML_SetElementHandler(parser, startElementHandler, endElementHandler); |
+ // Start parsing oldschool; switch these in flight if we detect a newer version of the file. |
+ XML_SetElementHandler(parser, jbParser::startElementHandler, jbParser::endElementHandler); |
char buffer[512]; |
bool done = false; |
@@ -309,7 +352,9 @@ void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*> &fontFamilie |
parseConfigFile(testMainConfigFile, fontFamilies); |
SkTDArray<FontFamily*> fallbackFonts; |
- parseConfigFile(testFallbackConfigFile, fallbackFonts); |
+ if (NULL != testFallbackConfigFile) { |
+ parseConfigFile(testFallbackConfigFile, fallbackFonts); |
+ } |
// Append all fallback fonts to system fonts |
for (int i = 0; i < fallbackFonts.count(); ++i) { |