Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(830)

Unified Diff: src/ports/SkFontConfigParser_android.cpp

Issue 1138073002: Extensible Android font configuration parsing. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Add comments, allow NULL. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/ports/SkFontConfigParser_android.cpp
diff --git a/src/ports/SkFontConfigParser_android.cpp b/src/ports/SkFontConfigParser_android.cpp
index 3f0ebbfc6b8f3f2e1547db559d26b778d15d4524..73e4c4773896afa4aaf2f7d59975da5e696557d5 100644
--- a/src/ports/SkFontConfigParser_android.cpp
+++ b/src/ports/SkFontConfigParser_android.cpp
@@ -19,10 +19,6 @@
#include <limits>
#include <stdlib.h>
-// From Android version LMP onwards, all font files collapse into
-// /system/etc/fonts.xml. Instead of trying to detect which version
-// we're on, try to open fonts.xml; if that fails, fall back to the
-// older filename.
#define LMP_SYSTEM_FONTS_FILE "/system/etc/fonts.xml"
#define OLD_SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml"
#define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml"
@@ -38,48 +34,81 @@
#endif
/**
- * 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.
+ * This file contains TWO 'familyset' handlers:
+ * One for JB and earlier which works with
+ * /system/etc/system_fonts.xml
+ * /system/etc/fallback_fonts.xml
+ * /vendor/etc/fallback_fonts.xml
+ * /system/etc/fallback_fonts-XX.xml
+ * /vendor/etc/fallback_fonts-XX.xml
+ * and the other for LMP and later which works with
+ * /system/etc/fonts.xml
+ *
+ * If the 'familyset' 'version' attribute is 21 or higher the LMP parser is used, otherwise the JB.
*/
-/** Used to track which tag is currently populating with data.
- * Only nameset and fileset are of interest for now.
- */
-enum CurrentTag {
- kNo_CurrentTag,
- kNameSet_CurrentTag,
- kFileSet_CurrentTag
+struct FamilyData;
+
+struct TagHandler {
+ /** Called at the start tag.
+ * Called immediately after the parent tag retuns this handler from a call to 'tag'.
+ * Allows setting up for handling the tag content and processing attributes.
+ * If NULL, will not be called.
+ */
+ void (*start)(FamilyData* data, const char* tag, const char** attributes);
+
+ /** Called at the end tag.
+ * Allows post-processing of any accumulated information.
+ * This will be the last call made in relation to the current tag.
+ * If NULL, will not be called.
+ */
+ void (*end)(FamilyData* data, const char* tag);
+
+ /** Called when a nested tag is encountered.
+ * This is responsible for determining how to handle the tag.
+ * If the tag is not recognized, return NULL to skip the tag.
+ * If NULL, all nested tags will be skipped.
+ */
+ const TagHandler* (*tag)(FamilyData* data, const char* tag, const char** attributes);
+
+ /** The character handler for this tag.
+ * This is only active for character data contained directly in this tag (not sub-tags).
+ * The first parameter will be castable to a FamilyData*.
+ * If NULL, any character data in this tag will be ignored.
+ */
+ XML_CharacterDataHandler chars;
};
-/**
- * The FamilyData structure is passed around by the parser so that each handler
- * can read these variables that are relevant to the current parsing.
- */
+/** Represents the current parsing state. */
struct FamilyData {
FamilyData(XML_Parser parser, SkTDArray<FontFamily*>& families,
- const SkString& basePath, bool isFallback, const char* filename)
+ const SkString& basePath, bool isFallback, const char* filename,
+ const TagHandler* topLevelHandler)
: fParser(parser)
, fFamilies(families)
, fCurrentFamily(NULL)
, fCurrentFontInfo(NULL)
- , fCurrentTag(kNo_CurrentTag)
, fVersion(0)
, fBasePath(basePath)
, fIsFallback(isFallback)
, fFilename(filename)
+ , fDepth(1)
+ , fSkip(0)
+ , fHandler(&topLevelHandler, 1)
{ };
XML_Parser fParser; // The expat parser doing the work, owned by caller
SkTDArray<FontFamily*>& fFamilies; // The array to append families, owned by caller
SkAutoTDelete<FontFamily> fCurrentFamily; // The family being created, owned by this
FontFileInfo* fCurrentFontInfo; // The fontInfo being created, owned by fCurrentFamily
- CurrentTag fCurrentTag; // The kind of tag currently being parsed.
int fVersion; // The version of the file parsed.
const SkString& fBasePath; // The current base path.
const bool fIsFallback; // Indicates the file being parsed is a fallback file
const char* fFilename; // The name of the file currently being parsed.
+
+ int fDepth; // The current element depth of the parse.
+ int fSkip; // The depth to stop skipping, 0 if not skipping.
+ SkTDArray<const TagHandler*> fHandler; // The stack of current tag handlers.
};
/** Parses a null terminated string into an integer type, checking for overflow.
@@ -124,70 +153,107 @@ static bool memeq(const char* s1, const char* s2, size_t n1, size_t n2) {
XML_GetCurrentColumnNumber(self->fParser), \
##__VA_ARGS__);
-namespace lmpParser {
+static bool is_whitespace(char c) {
+ return c == ' ' || c == '\n'|| c == '\r' || c == '\t';
+}
-static void family_element_handler(FamilyData* self, const char** attributes) {
- // A <family> element without a 'name' (string) attribute is a fallback font.
- // The element may have 'lang' (string) and 'variant' ("elegant", "compact") attributes.
- // The element should contain <font> elements.
- FontFamily* family = new FontFamily(self->fBasePath, true);
- self->fCurrentFamily.reset(family);
- for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
- const char* name = attributes[i];
- const char* value = attributes[i+1];
- size_t nameLen = strlen(name);
- size_t valueLen = strlen(value);
- if (MEMEQ("name", name, nameLen)) {
- SkAutoAsciiToLC tolc(value);
- family->fNames.push_back().set(tolc.lc());
- family->fIsFallbackFont = false;
- } else if (MEMEQ("lang", name, nameLen)) {
- family->fLanguage = SkLanguage(value, valueLen);
- } else if (MEMEQ("variant", name, nameLen)) {
- if (MEMEQ("elegant", value, valueLen)) {
- family->fVariant = kElegant_FontVariant;
- } else if (MEMEQ("compact", value, valueLen)) {
- family->fVariant = kCompact_FontVariant;
- }
- }
+static void trim_string(SkString* s) {
+ char* str = s->writable_str();
+ const char* start = str; // start is inclusive
+ const char* end = start + s->size(); // end is exclusive
+ while (is_whitespace(*start)) { ++start; }
+ if (start != end) {
+ --end; // make end inclusive
+ while (is_whitespace(*end)) { --end; }
+ ++end; // make end exclusive
}
+ size_t len = end - start;
+ memmove(str, start, len);
+ s->resize(len);
}
-static void XMLCALL font_file_name_handler(void* data, const char* s, int len) {
- FamilyData* self = static_cast<FamilyData*>(data);
- self->fCurrentFontInfo->fFileName.append(s, len);
-}
+namespace lmpParser {
-static void font_element_handler(FamilyData* self, const char** attributes) {
- // A <font> element should be contained in a <family> element.
- // The element may have 'weight' (non-negative integer), 'style' ("normal", "italic"),
- // and 'index' (non-negative integer) attributes.
- // The element should contain a filename.
- FontFileInfo& file = self->fCurrentFamily->fFonts.push_back();
- self->fCurrentFontInfo = &file;
- for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
- const char* name = attributes[i];
- const char* value = attributes[i+1];
- size_t nameLen = strlen(name);
- if (MEMEQ("weight", name, nameLen)) {
- if (!parse_non_negative_integer(value, &file.fWeight)) {
- SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value);
+static const TagHandler fontHandler = {
+ /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
+ // 'weight' (non-negative integer) [default 0]
+ // 'style' ("normal", "italic") [default "auto"]
+ // 'index' (non-negative integer) [default 0]
+ // The character data should be a filename.
+ FontFileInfo& file = self->fCurrentFamily->fFonts.push_back();
+ self->fCurrentFontInfo = &file;
+ for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
+ const char* name = attributes[i];
+ const char* value = attributes[i+1];
+ size_t nameLen = strlen(name);
+ if (MEMEQ("weight", name, nameLen)) {
+ if (!parse_non_negative_integer(value, &file.fWeight)) {
+ SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value);
+ }
+ } else if (MEMEQ("style", name, nameLen)) {
+ size_t valueLen = strlen(value);
+ if (MEMEQ("normal", value, valueLen)) {
+ file.fStyle = FontFileInfo::Style::kNormal;
+ } else if (MEMEQ("italic", value, valueLen)) {
+ file.fStyle = FontFileInfo::Style::kItalic;
+ }
+ } else if (MEMEQ("index", name, nameLen)) {
+ if (!parse_non_negative_integer(value, &file.fIndex)) {
+ SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value);
+ }
}
- } else if (MEMEQ("style", name, nameLen)) {
+ }
+ },
+ /*end*/[](FamilyData* self, const char* tag) {
+ trim_string(&self->fCurrentFontInfo->fFileName);
+ },
+ /*tag*/NULL,
+ /*chars*/[](void* data, const char* s, int len) {
+ FamilyData* self = static_cast<FamilyData*>(data);
+ self->fCurrentFontInfo->fFileName.append(s, len);
+ }
+};
+
+static const TagHandler familyHandler = {
+ /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
+ // 'name' (string) [optional]
+ // 'lang' (string) [default ""]
+ // 'variant' ("elegant", "compact") [default "default"]
+ // If there is no name, this is a fallback only font.
+ FontFamily* family = new FontFamily(self->fBasePath, true);
+ self->fCurrentFamily.reset(family);
+ for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
+ const char* name = attributes[i];
+ const char* value = attributes[i+1];
+ size_t nameLen = strlen(name);
size_t valueLen = strlen(value);
- if (MEMEQ("normal", value, valueLen)) {
- file.fStyle = FontFileInfo::Style::kNormal;
- } else if (MEMEQ("italic", value, valueLen)) {
- file.fStyle = FontFileInfo::Style::kItalic;
- }
- } else if (MEMEQ("index", name, nameLen)) {
- if (!parse_non_negative_integer(value, &file.fIndex)) {
- SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value);
+ if (MEMEQ("name", name, nameLen)) {
+ SkAutoAsciiToLC tolc(value);
+ family->fNames.push_back().set(tolc.lc());
+ family->fIsFallbackFont = false;
+ } else if (MEMEQ("lang", name, nameLen)) {
+ family->fLanguage = SkLanguage(value, valueLen);
+ } else if (MEMEQ("variant", name, nameLen)) {
+ if (MEMEQ("elegant", value, valueLen)) {
+ family->fVariant = kElegant_FontVariant;
+ } else if (MEMEQ("compact", value, valueLen)) {
+ family->fVariant = kCompact_FontVariant;
+ }
}
}
- }
- XML_SetCharacterDataHandler(self->fParser, font_file_name_handler);
-}
+ },
+ /*end*/[](FamilyData* self, const char* tag) {
+ *self->fFamilies.append() = self->fCurrentFamily.detach();
+ },
+ /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
+ size_t len = strlen(tag);
+ if (MEMEQ("font", tag, len)) {
+ return &fontHandler;
+ }
+ return NULL;
+ },
+ /*chars*/NULL,
+};
static FontFamily* find_family(FamilyData* self, const SkString& familyName) {
for (int i = 0; i < self->fFamilies.count(); i++) {
@@ -201,242 +267,279 @@ static FontFamily* find_family(FamilyData* self, const SkString& familyName) {
return NULL;
}
-static void alias_element_handler(FamilyData* self, const char** attributes) {
- // A <alias> element must have 'name' (string) and 'to' (string) attributes.
- // The element may also have a 'weight' (non-negative integer) attribute.
- // The 'name' introduces a new family name.
- // The 'to' specifies which (previous) <family> to alias.
- // If it *does not* have a weight, 'name' is an alias for the entire 'to' <family>.
- // If it *does* have a weight, 'name' is a new family consisting of the <font>(s) with 'weight'
- // from the 'to' <family>.
-
- SkString aliasName;
- SkString to;
- int weight = 0;
- for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
- const char* name = attributes[i];
- const char* value = attributes[i+1];
- size_t nameLen = strlen(name);
- if (MEMEQ("name", name, nameLen)) {
- SkAutoAsciiToLC tolc(value);
- aliasName.set(tolc.lc());
- } else if (MEMEQ("to", name, nameLen)) {
- to.set(value);
- } else if (MEMEQ("weight", name, nameLen)) {
- if (!parse_non_negative_integer(value, &weight)) {
- SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value);
+static const TagHandler aliasHandler = {
+ /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
+ // 'name' (string) introduces a new family name.
+ // 'to' (string) specifies which (previous) family to alias
+ // 'weight' (non-negative integer) [optional]
+ // If it *does not* have a weight, 'name' is an alias for the entire 'to' family.
+ // If it *does* have a weight, 'name' is a new family consisting of
+ // the font(s) with 'weight' from the 'to' family.
+
+ SkString aliasName;
+ SkString to;
+ int weight = 0;
+ for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
+ const char* name = attributes[i];
+ const char* value = attributes[i+1];
+ size_t nameLen = strlen(name);
+ if (MEMEQ("name", name, nameLen)) {
+ SkAutoAsciiToLC tolc(value);
+ aliasName.set(tolc.lc());
+ } else if (MEMEQ("to", name, nameLen)) {
+ to.set(value);
+ } else if (MEMEQ("weight", name, nameLen)) {
+ if (!parse_non_negative_integer(value, &weight)) {
+ SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value);
+ }
}
}
- }
- // Assumes that the named family is already declared
- FontFamily* targetFamily = find_family(self, to);
- if (!targetFamily) {
- SK_FONTCONFIGPARSER_WARNING("'%s' alias target not found", to.c_str());
- return;
- }
+ // Assumes that the named family is already declared
+ FontFamily* targetFamily = find_family(self, to);
+ if (!targetFamily) {
+ SK_FONTCONFIGPARSER_WARNING("'%s' alias target not found", to.c_str());
+ return;
+ }
- if (weight) {
- FontFamily* family = new FontFamily(targetFamily->fBasePath, self->fIsFallback);
- family->fNames.push_back().set(aliasName);
+ if (weight) {
+ FontFamily* family = new FontFamily(targetFamily->fBasePath, self->fIsFallback);
+ family->fNames.push_back().set(aliasName);
- for (int i = 0; i < targetFamily->fFonts.count(); i++) {
- if (targetFamily->fFonts[i].fWeight == weight) {
- family->fFonts.push_back(targetFamily->fFonts[i]);
+ for (int i = 0; i < targetFamily->fFonts.count(); i++) {
+ if (targetFamily->fFonts[i].fWeight == weight) {
+ family->fFonts.push_back(targetFamily->fFonts[i]);
+ }
}
+ *self->fFamilies.append() = family;
+ } else {
+ targetFamily->fNames.push_back().set(aliasName);
}
- *self->fFamilies.append() = family;
- } else {
- targetFamily->fNames.push_back().set(aliasName);
- }
-}
-
-static void XMLCALL start_element_handler(void* data, const char* tag, const char** attributes) {
- FamilyData* self = static_cast<FamilyData*>(data);
- size_t len = strlen(tag);
- if (MEMEQ("family", tag, len)) {
- family_element_handler(self, attributes);
- } else if (MEMEQ("font", tag, len)) {
- font_element_handler(self, attributes);
- } else if (MEMEQ("alias", tag, len)) {
- alias_element_handler(self, attributes);
- }
-}
-
-static bool is_whitespace(char c) {
- return c == ' ' || c == '\n'|| c == '\r' || c == '\t';
-}
-
-static void trim_string(SkString* s) {
- char* str = s->writable_str();
- const char* start = str; // start is inclusive
- const char* end = start + s->size(); // end is exclusive
- while (is_whitespace(*start)) { ++start; }
- if (start != end) {
- --end; // make end inclusive
- while (is_whitespace(*end)) { --end; }
- ++end; // make end exclusive
- }
- size_t len = end - start;
- memmove(str, start, len);
- s->resize(len);
-}
+ },
+ /*end*/NULL,
+ /*tag*/NULL,
+ /*chars*/NULL,
+};
-static void XMLCALL end_element_handler(void* data, const char* tag) {
- FamilyData* self = static_cast<FamilyData*>(data);
- size_t len = strlen(tag);
- if (MEMEQ("family", tag, len)) {
- *self->fFamilies.append() = self->fCurrentFamily.detach();
- } else if (MEMEQ("font", tag, len)) {
- XML_SetCharacterDataHandler(self->fParser, NULL);
- trim_string(&self->fCurrentFontInfo->fFileName);
- }
-}
+static const TagHandler familySetHandler = {
+ /*start*/[](FamilyData* self, const char* tag, const char** attributes) { },
+ /*end*/NULL,
+ /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
+ size_t len = strlen(tag);
+ if (MEMEQ("family", tag, len)) {
+ return &familyHandler;
+ } else if (MEMEQ("alias", tag, len)) {
+ return &aliasHandler;
+ }
+ return NULL;
+ },
+ /*chars*/NULL,
+};
} // 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.
- */
-static void XMLCALL text_handler(void* data, const char* s, int len) {
- FamilyData* self = static_cast<FamilyData*>(data);
- // Make sure we're in the right state to store this name information
- if (self->fCurrentFamily.get()) {
- switch (self->fCurrentTag) {
- case kNameSet_CurrentTag: {
- SkAutoAsciiToLC tolc(s, len);
- self->fCurrentFamily->fNames.back().append(tolc.lc(), len);
- break;
- }
- case kFileSet_CurrentTag:
- if (self->fCurrentFontInfo) {
- self->fCurrentFontInfo->fFileName.append(s, len);
+static const TagHandler fileHandler = {
+ /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
+ // 'variant' ("elegant", "compact") [default "default"]
+ // 'lang' (string) [default ""]
+ // 'index' (non-negative integer) [default 0]
+ // The character data should be a filename.
+ FontFamily& currentFamily = *self->fCurrentFamily.get();
+ FontFileInfo& newFileInfo = currentFamily.fFonts.push_back();
+ if (attributes) {
+ for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
+ const char* name = attributes[i];
+ const char* value = attributes[i+1];
+ size_t nameLen = strlen(name);
+ size_t valueLen = strlen(value);
+ if (MEMEQ("variant", name, nameLen)) {
+ const FontVariant prevVariant = currentFamily.fVariant;
+ if (MEMEQ("elegant", value, valueLen)) {
+ currentFamily.fVariant = kElegant_FontVariant;
+ } else if (MEMEQ("compact", value, valueLen)) {
+ currentFamily.fVariant = kCompact_FontVariant;
+ }
+ if (currentFamily.fFonts.count() > 1 && currentFamily.fVariant != prevVariant) {
+ SK_FONTCONFIGPARSER_WARNING("'%s' unexpected variant found\n"
+ "Note: Every font file within a family must have identical variants.",
+ value);
+ }
+
+ } else if (MEMEQ("lang", name, nameLen)) {
+ SkLanguage prevLang = currentFamily.fLanguage;
+ currentFamily.fLanguage = SkLanguage(value, valueLen);
+ if (currentFamily.fFonts.count() > 1 && currentFamily.fLanguage != prevLang) {
+ SK_FONTCONFIGPARSER_WARNING("'%s' unexpected language found\n"
+ "Note: Every font file within a family must have identical languages.",
+ value);
+ }
+
+ } else if (MEMEQ("index", name, nameLen)) {
+ if (!parse_non_negative_integer(value, &newFileInfo.fIndex)) {
+ SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value);
+ }
+ }
}
- break;
- default:
- // Noop - don't care about any text that's not in the Fonts or Names list
- break;
}
+ self->fCurrentFontInfo = &newFileInfo;
+ },
+ /*end*/NULL,
+ /*tag*/NULL,
+ /*chars*/[](void* data, const char* s, int len) {
+ FamilyData* self = static_cast<FamilyData*>(data);
+ self->fCurrentFontInfo->fFileName.append(s, len);
}
-}
+};
-/**
- * Handler for font files. This processes the attributes for language and
- * variants then lets textHandler handle the actual file name
- */
-static void font_file_element_handler(FamilyData* self, const char** attributes) {
- FontFamily& currentFamily = *self->fCurrentFamily.get();
- FontFileInfo& newFileInfo = currentFamily.fFonts.push_back();
- if (attributes) {
+static const TagHandler fileSetHandler = {
+ /*start*/NULL,
+ /*end*/NULL,
+ /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
+ size_t len = strlen(tag);
+ if (MEMEQ("file", tag, len)) {
+ return &fileHandler;
+ }
+ return NULL;
+ },
+ /*chars*/NULL,
+};
+
+static const TagHandler nameHandler = {
+ /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
+ // The character data should be a name for the font.
+ self->fCurrentFamily->fNames.push_back();
+ },
+ /*end*/NULL,
+ /*tag*/NULL,
+ /*chars*/[](void* data, const char* s, int len) {
+ FamilyData* self = static_cast<FamilyData*>(data);
+ SkAutoAsciiToLC tolc(s, len);
+ self->fCurrentFamily->fNames.back().append(tolc.lc(), len);
+ }
+};
+
+static const TagHandler nameSetHandler = {
+ /*start*/NULL,
+ /*end*/NULL,
+ /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
+ size_t len = strlen(tag);
+ if (MEMEQ("name", tag, len)) {
+ return &nameHandler;
+ }
+ return NULL;
+ },
+ /*chars*/NULL,
+};
+
+static const TagHandler familyHandler = {
+ /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
+ self->fCurrentFamily.reset(new FontFamily(self->fBasePath, self->fIsFallback));
+ // 'order' (non-negative integer) [default -1]
for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
- const char* name = attributes[i];
const char* value = attributes[i+1];
- size_t nameLen = strlen(name);
- size_t valueLen = strlen(value);
- if (MEMEQ("variant", name, nameLen)) {
- const FontVariant prevVariant = currentFamily.fVariant;
- if (MEMEQ("elegant", value, valueLen)) {
- currentFamily.fVariant = kElegant_FontVariant;
- } else if (MEMEQ("compact", value, valueLen)) {
- currentFamily.fVariant = kCompact_FontVariant;
- }
- if (currentFamily.fFonts.count() > 1 && currentFamily.fVariant != prevVariant) {
- SK_FONTCONFIGPARSER_WARNING("'%s' unexpected variant found\n"
- "Note: Every font file within a family must have identical variants.",
- value);
- }
+ parse_non_negative_integer(value, &self->fCurrentFamily->fOrder);
+ }
+ },
+ /*end*/[](FamilyData* self, const char* tag) {
+ *self->fFamilies.append() = self->fCurrentFamily.detach();
+ },
+ /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
+ size_t len = strlen(tag);
+ if (MEMEQ("nameset", tag, len)) {
+ return &nameSetHandler;
+ } else if (MEMEQ("fileset", tag, len)) {
+ return &fileSetHandler;
+ }
+ return NULL;
+ },
+ /*chars*/NULL,
+};
- } else if (MEMEQ("lang", name, nameLen)) {
- SkLanguage prevLang = currentFamily.fLanguage;
- currentFamily.fLanguage = SkLanguage(value, valueLen);
- if (currentFamily.fFonts.count() > 1 && currentFamily.fLanguage != prevLang) {
- SK_FONTCONFIGPARSER_WARNING("'%s' unexpected language found\n"
- "Note: Every font file within a family must have identical languages.",
- value);
- }
+static const TagHandler familySetHandler = {
+ /*start*/NULL,
+ /*end*/NULL,
+ /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
+ size_t len = strlen(tag);
+ if (MEMEQ("family", tag, len)) {
+ return &familyHandler;
+ }
+ return NULL;
+ },
+ /*chars*/NULL,
+};
- } else if (MEMEQ("index", name, nameLen)) {
- if (!parse_non_negative_integer(value, &newFileInfo.fIndex)) {
- SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value);
+} // namespace jbParser
+
+static const TagHandler topLevelHandler = {
+ /*start*/NULL,
+ /*end*/NULL,
+ /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
+ size_t len = strlen(tag);
+ if (MEMEQ("familyset", tag, len)) {
+ // 'version' (non-negative integer) [default 0]
+ for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
+ const char* name = attributes[i];
+ size_t nameLen = strlen(name);
+ if (MEMEQ("version", name, nameLen)) {
+ const char* value = attributes[i+1];
+ if (parse_non_negative_integer(value, &self->fVersion)) {
+ if (self->fVersion >= 21) {
+ return &lmpParser::familySetHandler;
+ }
+ }
}
}
+ return &jbParser::familySetHandler;
}
- }
- self->fCurrentFontInfo = &newFileInfo;
- XML_SetCharacterDataHandler(self->fParser, text_handler);
-}
+ return NULL;
+ },
+ /*chars*/NULL,
+};
-/**
- * Handler for the start of a tag. The only tags we expect are familyset, family,
- * nameset, fileset, name, and file.
- */
-static void XMLCALL start_element_handler(void* data, const char* tag, const char** attributes) {
+static void XMLCALL start_element_handler(void *data, const char *tag, const char **attributes) {
FamilyData* self = static_cast<FamilyData*>(data);
- size_t len = strlen(tag);
- if (MEMEQ("familyset", tag, len)) {
- // The <familyset> element has an optional 'version' (non-negative integer) attribute.
- for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
- size_t nameLen = strlen(attributes[i]);
- if (!MEMEQ("version", attributes[i], nameLen)) continue;
- const char* valueString = attributes[i+1];
- int version;
- if (parse_non_negative_integer(valueString, &version) && (version >= 21)) {
- XML_SetElementHandler(self->fParser,
- lmpParser::start_element_handler,
- lmpParser::end_element_handler);
- self->fVersion = version;
- }
- }
- } else if (MEMEQ("family", tag, len)) {
- self->fCurrentFamily.reset(new FontFamily(self->fBasePath, self->fIsFallback));
- // The <family> element has an optional 'order' (non-negative integer) attribute.
- // If this attribute does not exist, the default value is -1.
- for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
- const char* valueString = attributes[i+1];
- int value;
- if (parse_non_negative_integer(valueString, &value)) {
- self->fCurrentFamily->fOrder = value;
+
+ if (!self->fSkip) {
+ const TagHandler* parent = self->fHandler.top();
+ const TagHandler* child = parent->tag ? parent->tag(self, tag, attributes) : NULL;
+ if (child) {
+ if (child->start) {
+ child->start(self, tag, attributes);
}
+ self->fHandler.push(child);
+ XML_SetCharacterDataHandler(self->fParser, child->chars);
+ } else {
+ SK_FONTCONFIGPARSER_WARNING("'%s' tag not recognized, skipping", tag);
+ XML_SetCharacterDataHandler(self->fParser, NULL);
+ self->fSkip = self->fDepth;
}
- } else if (MEMEQ("nameset", tag, len)) {
- self->fCurrentTag = kNameSet_CurrentTag;
- } else if (MEMEQ("fileset", tag, len)) {
- self->fCurrentTag = kFileSet_CurrentTag;
- } else if (MEMEQ("name", tag, len) && self->fCurrentTag == kNameSet_CurrentTag) {
- // If it's a Name, parse the text inside
- self->fCurrentFamily->fNames.push_back();
- XML_SetCharacterDataHandler(self->fParser, text_handler);
- } else if (MEMEQ("file", tag, len) && self->fCurrentTag == kFileSet_CurrentTag) {
- // If it's a file, parse the attributes, then parse the text inside
- font_file_element_handler(self, attributes);
}
+
+ ++self->fDepth;
}
-/**
- * Handler for the end of tags. We only care about family, nameset, fileset,
- * name, and file.
- */
static void XMLCALL end_element_handler(void* data, const char* tag) {
FamilyData* self = static_cast<FamilyData*>(data);
- size_t len = strlen(tag);
- if (MEMEQ("family", tag, len)) {
- // Done parsing a Family - store the created currentFamily in the families array
- *self->fFamilies.append() = self->fCurrentFamily.detach();
- } else if (MEMEQ("nameset", tag, len)) {
- self->fCurrentTag = kNo_CurrentTag;
- } else if (MEMEQ("fileset", tag, len)) {
- self->fCurrentTag = kNo_CurrentTag;
- } else if ((MEMEQ("name", tag, len) && self->fCurrentTag == kNameSet_CurrentTag) ||
- (MEMEQ("file", tag, len) && self->fCurrentTag == kFileSet_CurrentTag)) {
- // Disable the arbitrary text handler installed to load Name data
- XML_SetCharacterDataHandler(self->fParser, NULL);
+ --self->fDepth;
+
+ if (!self->fSkip) {
+ const TagHandler* child = self->fHandler.top();
+ if (child->end) {
+ child->end(self, tag);
+ }
+ self->fHandler.pop();
+ const TagHandler* parent = self->fHandler.top();
+ XML_SetCharacterDataHandler(self->fParser, parent->chars);
}
-}
-} // namespace jbParser
+ if (self->fSkip == self->fDepth) {
+ self->fSkip = 0;
+ const TagHandler* parent = self->fHandler.top();
+ XML_SetCharacterDataHandler(self->fParser, parent->chars);
+ }
+}
static void XMLCALL xml_entity_decl_handler(void *data,
const XML_Char *entityName,
@@ -485,14 +588,14 @@ static int parse_config_file(const char* filename, SkTDArray<FontFamily*>& famil
return -1;
}
- FamilyData self(parser, families, basePath, isFallback, filename);
+ FamilyData self(parser, families, basePath, isFallback, filename, &topLevelHandler);
XML_SetUserData(parser, &self);
// Disable entity processing, to inhibit internal entity expansion. See expat CVE-2013-0340
XML_SetEntityDeclHandler(parser, xml_entity_decl_handler);
// Start parsing oldschool; switch these in flight if we detect a newer version of the file.
- XML_SetElementHandler(parser, jbParser::start_element_handler, jbParser::end_element_handler);
+ XML_SetElementHandler(parser, start_element_handler, end_element_handler);
// One would assume it would be faster to have a buffer on the stack and call XML_Parse.
// But XML_Parse will call XML_GetBuffer anyway and memmove the passed buffer into it.
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698