diff options
author | tomhudson <tomhudson@chromium.org> | 2014-08-05 13:35:00 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-08-05 13:35:02 -0700 |
commit | 07544757c9fcf0f359f1686a3779eb2e75dd5b36 (patch) | |
tree | b1610aa02f5364a584ff53fef283ce10651d5c32 /src | |
parent | 43f9d3edf888419474e17ec7b40aee49363d3e9a (diff) |
Parses sample code provided by Android project. Attempts to keep FontFamily data structures produced consistent with expectations of previous versions of Skia.
R=bungeman@google.com, djsollen@google.com, tomhudson@google.com
Author: tomhudson@chromium.org
Review URL: https://codereview.chromium.org/446473003
Diffstat (limited to 'src')
-rw-r--r-- | src/ports/SkFontConfigParser_android.cpp | 185 | ||||
-rw-r--r-- | src/ports/SkFontConfigParser_android.h | 18 |
2 files changed, 192 insertions, 11 deletions
diff --git a/src/ports/SkFontConfigParser_android.cpp b/src/ports/SkFontConfigParser_android.cpp index fbbb6a627a..d1169b99fb 100644 --- a/src/ports/SkFontConfigParser_android.cpp +++ b/src/ports/SkFontConfigParser_android.cpp @@ -77,15 +77,190 @@ template <typename T> static bool parseNonNegativeInteger(const char* s, T* valu namespace lmpParser { -void startElementHandler(void* data, const char* tag, - const char** attributes) { - //SkDebugf("lmp started %s", tag); +void familyElementHandler(FontFamily* family, const char** attributes) { + // A non-fallback <family> tag must have a canonical name attribute. + // A (fallback) <family> tag may have lang and variant attributes. + for (int i = 0; attributes[i] != NULL; i += 2) { + const char* name = attributes[i]; + const char* value = attributes[i+1]; + int nameLen = strlen(name); + int valueLen = strlen(value); + if (nameLen == 4 && !strncmp("name", name, nameLen)) { + family->fNames.push_back().set(value); + } else if (nameLen == 4 && !strncmp("lang", name, nameLen)) { + family->fLanguage = SkLanguage (value); + } else if (nameLen == 7 && !strncmp("variant", name, nameLen)) { + // Value should be either elegant or compact. + if (valueLen == 7 && !strncmp("elegant", value, valueLen)) { + family->fVariant = SkPaintOptionsAndroid::kElegant_Variant; + } else if (valueLen == 7 && !strncmp("compact", value, valueLen)) { + family->fVariant = SkPaintOptionsAndroid::kCompact_Variant; + } + } + } } -void endElementHandler(void* data, const char* tag) { +void fontFileNameHandler(void *data, const char *s, int len) { + FamilyData *familyData = (FamilyData*) data; + familyData->currentFontInfo->fFileName.set(s, len); +} - //SkDebugf("lmp ended %s", tag); +void familyElementEndHandler(FontFamily* family) { + for (int i = 0; i < family->fFontFiles.count(); i++) { + family->fFontFiles[i].fPaintOptions.setLanguage(family->fLanguage); + family->fFontFiles[i].fPaintOptions.setFontVariant(family->fVariant); + } +} + +void fontElementHandler(XML_Parser* parser, FontFileInfo* file, const char** attributes) { + // A <font> should have weight (integer) and style (normal, italic) attributes. + // NOTE: we ignore the style. + // The element should contain a filename. + for (int i = 0; attributes[i] != NULL; i += 2) { + const char* name = attributes[i]; + const char* value = attributes[i+1]; + int nameLen = strlen(name); + if (nameLen == 6 && !strncmp("weight", name, nameLen)) { + parseNonNegativeInteger(value, &file->fWeight); + } + } + XML_SetCharacterDataHandler(*parser, fontFileNameHandler); +} + +FontFamily* findFamily(FamilyData* familyData, const char* familyName) { + unsigned int nameLen = strlen(familyName); + for (int i = 0; i < familyData->families.count(); i++) { + FontFamily* candidate = familyData->families[i]; + for (int j = 0; j < candidate->fNames.count(); j++) { + if (!strncmp(candidate->fNames[j].c_str(), familyName, nameLen) && + nameLen == strlen(candidate->fNames[j].c_str())) { + return candidate; + } + } + } + return NULL; +} + +void aliasElementHandler(FamilyData* familyData, const char** attributes) { + // An <alias> must have name and to attributes. + // It may have weight (integer). + // If it *does not* have a weight, it is a variant name for a <family>. + // If it *does* have a weight, it names the <font>(s) of a specific weight + // from a <family>. + + SkString aliasName; + SkString to; + int weight = 0; + for (int i = 0; attributes[i] != NULL; i += 2) { + const char* name = attributes[i]; + const char* value = attributes[i+1]; + int nameLen = strlen(name); + if (nameLen == 4 && !strncmp("name", name, nameLen)) { + aliasName.set(value); + } else if (nameLen == 2 && !strncmp("to", name, nameLen)) { + to.set(value); + } else if (nameLen == 6 && !strncmp("weight", name, nameLen)) { + parseNonNegativeInteger(value, &weight); + } + } + + // Assumes that the named family is already declared + FontFamily* targetFamily = findFamily(familyData, to.c_str()); + if (!targetFamily) { + SkDebugf("---- Font alias target %s (NOT FOUND)", to.c_str()); + return; + } + + if (weight) { + FontFamily* family = new FontFamily(); + family->fNames.push_back().set(aliasName); + + for (int i = 0; i < targetFamily->fFontFiles.count(); i++) { + if (targetFamily->fFontFiles[i].fWeight == weight) { + family->fFontFiles.push_back(targetFamily->fFontFiles[i]); + } + } + *familyData->families.append() = family; + } else { + targetFamily->fNames.push_back().set(aliasName); + } +} + +bool findWeight400(FontFamily* family) { + for (int i = 0; i < family->fFontFiles.count(); i++) { + if (family->fFontFiles[i].fWeight == 400) { + return true; + } + } + return false; +} + +bool desiredWeight(int weight) { + return (weight == 400 || weight == 700); +} + +int countDesiredWeight(FontFamily* family) { + int count = 0; + for (int i = 0; i < family->fFontFiles.count(); i++) { + if (desiredWeight(family->fFontFiles[i].fWeight)) { + count++; + } + } + return count; +} + +// To meet Skia's expectations, any family that contains weight=400 +// fonts should *only* contain {400,700} +void purgeUndesiredWeights(FontFamily* family) { + int count = countDesiredWeight(family); + for (int i = 1, j = 0; i < family->fFontFiles.count(); i++) { + if (desiredWeight(family->fFontFiles[j].fWeight)) { + j++; + } + if ((i != j) && desiredWeight(family->fFontFiles[i].fWeight)) { + family->fFontFiles[j] = family->fFontFiles[i]; + } + } + family->fFontFiles.resize_back(count); +} + +void familysetElementEndHandler(FamilyData* familyData) { + for (int i = 0; i < familyData->families.count(); i++) { + if (findWeight400(familyData->families[i])) { + purgeUndesiredWeights(familyData->families[i]); + } + } +} + +void startElementHandler(void* data, const char* tag, + const char** attributes) { + FamilyData* familyData = (FamilyData*) data; + int len = strlen(tag); + if (len == 6 && !strncmp(tag, "family", len)) { + familyData->currentFamily = new FontFamily(); + familyElementHandler(familyData->currentFamily, attributes); + } else if (len == 4 && !strncmp(tag, "font", len)) { + FontFileInfo* file = &familyData->currentFamily->fFontFiles.push_back(); + familyData->currentFontInfo = file; + fontElementHandler(familyData->parser, file, attributes); + } else if (len == 5 && !strncmp(tag, "alias", len)) { + aliasElementHandler(familyData, attributes); + } +} + +void endElementHandler(void* data, const char* tag) { + FamilyData *familyData = (FamilyData*) data; + int len = strlen(tag); + if (len == 9 && strncmp(tag, "familyset", len) == 0) { + familysetElementEndHandler(familyData); + } else if (len == 6 && strncmp(tag, "family", len) == 0) { + familyElementEndHandler(familyData->currentFamily); + *familyData->families.append() = familyData->currentFamily; + familyData->currentFamily = NULL; + } else if (len == 4 && !strncmp(tag, "font", len)) { + XML_SetCharacterDataHandler(*familyData->parser, NULL); + } } } // lmpParser diff --git a/src/ports/SkFontConfigParser_android.h b/src/ports/SkFontConfigParser_android.h index 8119fd7558..513422d29b 100644 --- a/src/ports/SkFontConfigParser_android.h +++ b/src/ports/SkFontConfigParser_android.h @@ -15,11 +15,12 @@ #include "SkTDArray.h" struct FontFileInfo { - FontFileInfo() : fIndex(0) { } + FontFileInfo() : fIndex(0), fWeight(0) { } SkString fFileName; int fIndex; SkPaintOptionsAndroid fPaintOptions; + int fWeight; }; /** @@ -31,12 +32,17 @@ struct FontFileInfo { * they are read from the configuration files. */ struct FontFamily { - FontFamily() : fIsFallbackFont(false), order(-1) {} + FontFamily() + : fVariant(SkPaintOptionsAndroid::kDefault_Variant) + , order(-1) + , fIsFallbackFont(false) { } - SkTArray<SkString> fNames; - SkTArray<FontFileInfo> fFontFiles; - bool fIsFallbackFont; - int order; // only used internally by SkFontConfigParser + SkTArray<SkString> fNames; + SkTArray<FontFileInfo> fFontFiles; + SkLanguage fLanguage; + SkPaintOptionsAndroid::FontVariant fVariant; + int order; // only used internally by SkFontConfigParser + bool fIsFallbackFont; }; namespace SkFontConfigParser { |