aboutsummaryrefslogtreecommitdiffstats
path: root/src/ports
diff options
context:
space:
mode:
authorChet Haase <chet@google.com>2011-07-06 11:23:25 -0700
committerChet Haase <chet@google.com>2011-07-15 11:01:16 -0700
commit9c0ebce1a8c21bbbe49d9f935685b82b5eb5047f (patch)
tree4a80b828af132e850061497275e06286b7380bca /src/ports
parent252e26654d93268285d642c1c99e22f578a41d11 (diff)
downloadexternal_skia-9c0ebce1a8c21bbbe49d9f935685b82b5eb5047f.zip
external_skia-9c0ebce1a8c21bbbe49d9f935685b82b5eb5047f.tar.gz
external_skia-9c0ebce1a8c21bbbe49d9f935685b82b5eb5047f.tar.bz2
Read font info from system config files
This change adds new files in /system/etc: system_fonts.xml and fallback_fonts.xml. The change also allows a third file to be added by vendors in /vendor/etc/fallback_fonts.xml. These files, loaded at boot time, mimic the logic that used to be in code, but which is now configurable through editing these files, making the system more flexible and easy to work with for us and vendors as future fonts are added to the system. Change-Id: Iac0af4924ca0454c6dde4d53058b1425200ed4b7
Diffstat (limited to 'src/ports')
-rw-r--r--src/ports/FontHostConfiguration_android.cpp192
-rw-r--r--src/ports/FontHostConfiguration_android.h41
-rw-r--r--src/ports/SkFontHost_android.cpp119
3 files changed, 302 insertions, 50 deletions
diff --git a/src/ports/FontHostConfiguration_android.cpp b/src/ports/FontHostConfiguration_android.cpp
new file mode 100644
index 0000000..78f1de4
--- /dev/null
+++ b/src/ports/FontHostConfiguration_android.cpp
@@ -0,0 +1,192 @@
+/* libs/graphics/ports/FontHostConfiguration_android.cpp
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "FontHostConfiguration_android.h"
+#include <expat.h>
+#include "SkTDArray.h"
+
+#define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml"
+#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.
+#define NO_TAG 0
+#define NAMESET_TAG 1
+#define FILESET_TAG 2
+
+/**
+ * The FamilyData structure is passed around by the parser so that each handler can read these
+ * variables that are relevant to the current parsing.
+ */
+struct FamilyData {
+ FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef) :
+ parser(parserRef), families(familiesRef), 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
+ int currentTag; // A flag to indicate whether we're in nameset/fileset tags
+};
+
+/**
+ * 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.
+ */
+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 &&
+ (familyData->currentTag == NAMESET_TAG || familyData->currentTag == FILESET_TAG)) {
+ // Malloc new buffer to store the string
+ char *buff;
+ buff = (char*) malloc((len + 1) * sizeof(char));
+ strncpy(buff, s, len);
+ buff[len] = '\0';
+ switch (familyData->currentTag) {
+ case NAMESET_TAG:
+ *(familyData->currentFamily->fNames.append()) = buff;
+ break;
+ case FILESET_TAG:
+ *(familyData->currentFamily->fFileNames.append()) = buff;
+ break;
+ default:
+ // Noop - don't care about any text that's not in the Fonts or Names list
+ break;
+ }
+ }
+}
+
+/**
+ * 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) {
+ FamilyData *familyData = (FamilyData*) data;
+ int len = strlen(tag);
+ if (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
+ // If this attribute does not exist, the default value is -1
+ for (int i = 0; atts[i] != NULL; i += 2) {
+ const char* attribute = atts[i];
+ const char* valueString = atts[i+1];
+ int value;
+ int len = sscanf(valueString, "%d", &value);
+ if (len > 0) {
+ familyData->currentFamily->order = value;
+ }
+ }
+ } 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) ||
+ (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG)) {
+ // If it's a Name, parse the text inside
+ XML_SetCharacterDataHandler(*familyData->parser, textHandler);
+ }
+}
+
+/**
+ * Handler for the end of tags. We only care about family, nameset, fileset, name, and file.
+ */
+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
+ *familyData->families.append() = familyData->currentFamily;
+ familyData->currentFamily = NULL;
+ } else if (len == 7 && strncmp(tag, "nameset", len)== 0) {
+ 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)) {
+ // Disable the arbitrary text handler installed to load Name data
+ XML_SetCharacterDataHandler(*familyData->parser, NULL);
+ }
+}
+
+/**
+ * This function parses the given filename and stores the results in the given families array.
+ */
+void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) {
+ XML_Parser parser = XML_ParserCreate(NULL);
+ FamilyData *familyData = new FamilyData(&parser, families);
+ XML_SetUserData(parser, familyData);
+ XML_SetElementHandler(parser, startElementHandler, endElementHandler);
+ FILE *file = fopen(filename, "r");
+ if (file == NULL) {
+ // 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.
+ return;
+ }
+ char buffer[512];
+ bool done = false;
+ while (!done) {
+ fgets(buffer, sizeof(buffer), file);
+ int len = strlen(buffer);
+ if (feof(file) != 0) {
+ done = true;
+ }
+ XML_Parse(parser, buffer, len, done);
+ }
+}
+
+/**
+ * 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;
+ SkTDArray<FontFamily*> vendorFonts;
+ parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies);
+ parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts);
+ parseConfigFile(VENDOR_FONTS_FILE, vendorFonts);
+
+ // This loop inserts the vendor fallback fonts in the correct order in the overall
+ // fallbacks list.
+ int currentOrder = -1;
+ for (int i = 0; i < vendorFonts.count(); ++i) {
+ FontFamily* family = vendorFonts[i];
+ int order = family->order;
+ if (order < 0) {
+ if (currentOrder < 0) {
+ // Default case - just add it to the end of the fallback list
+ *fallbackFonts.append() = family;
+ } else {
+ // no order specified on this font, but we're incrementing the order
+ // based on an earlier order insertion request
+ *fallbackFonts.insert(currentOrder++) = family;
+ }
+ } else {
+ // Add the font into the fallback list in the specified order. Set currentOrder
+ // for correct placement of other fonts in the vendor list.
+ *fallbackFonts.insert(order) = family;
+ currentOrder = order + 1;
+ }
+ }
+ // 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
new file mode 100644
index 0000000..57a0126
--- /dev/null
+++ b/src/ports/FontHostConfiguration_android.h
@@ -0,0 +1,41 @@
+/* libs/graphics/ports/FontHostConfiguration_android.h
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+#ifndef FONTHOSTCONFIGURATION_ANDROID_H_
+#define FONTHOSTCONFIGURATION_ANDROID_H_
+
+#include "SkTDArray.h"
+
+/**
+ * The FontFamily data structure is created during parsing and handed back to Skia to fold
+ * into its representation of font families. fNames is the list of font names that alias to a
+ * font family. fFileNames is the list of font filenames for the family. Order is the priority
+ * order for the font. This is used internally to determine the order in which to place fallback
+ * fonts as they are read from the configuration files.
+ */
+struct FontFamily {
+ SkTDArray<const char*> fNames;
+ SkTDArray<const char*> fFileNames;
+ int order;
+};
+
+/**
+ * Parses all system font configuration files and returns the results in an array of FontFamily
+ * structures.
+ */
+void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies);
+
+#endif /* FONTHOSTCONFIGURATION_ANDROID_H_ */
diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp
index 7d17544..76d9961 100644
--- a/src/ports/SkFontHost_android.cpp
+++ b/src/ports/SkFontHost_android.cpp
@@ -23,6 +23,7 @@
#include "SkStream.h"
#include "SkThread.h"
#include "SkTSearch.h"
+#include "FontHostConfiguration_android.h"
#include <stdio.h>
#define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
@@ -395,64 +396,80 @@ struct FontInitRec {
const char* const* fNames; // null-terminated list
};
-static const char* gSansNames[] = {
- "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
-};
-
-static const char* gSerifNames[] = {
- "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
- "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
-};
-
-static const char* gMonoNames[] = {
- "monospace", "courier", "courier new", "monaco", NULL
-};
-
// deliberately empty, but we use the address to identify fallback fonts
static const char* gFBNames[] = { NULL };
-/* Fonts must be grouped by family, with the first font in a family having the
+
+/* Fonts are grouped by family, with the first font in a family having the
list of names (even if that list is empty), and the following members having
- null for the list. The names list must be NULL-terminated
+ null for the list. The names list must be NULL-terminated.
*/
-static const FontInitRec gSystemFonts[] = {
- { "DroidSans.ttf", gSansNames },
- { "DroidSans-Bold.ttf", NULL },
- { "DroidSerif-Regular.ttf", gSerifNames },
- { "DroidSerif-Bold.ttf", NULL },
- { "DroidSerif-Italic.ttf", NULL },
- { "DroidSerif-BoldItalic.ttf", NULL },
- { "DroidSansMono.ttf", gMonoNames },
- /* These are optional, and can be ignored if not found in the file system.
- These are appended to gFallbackFonts[] as they are seen, so we list
- them in the order we want them to be accessed by NextLogicalFont().
- */
- { "DroidSansArabic.ttf", gFBNames },
- { "DroidSansHebrew-Regular.ttf",gFBNames },
- { "DroidSansHebrew-Bold.ttf", NULL },
- { "DroidSansThai.ttf", gFBNames },
- { "MTLmr3m.ttf", gFBNames }, // Motoya Japanese Font
- { "MTLc3m.ttf", gFBNames }, // Motoya Japanese Font
- { "DroidSansJapanese.ttf", gFBNames },
- { "DroidSansEthiopic-Regular.ttf",gFBNames },
- { "DroidSansEthiopic-Bold.ttf", NULL },
- { "DroidSansFallback.ttf", gFBNames }
-};
+static FontInitRec *gSystemFonts;
+static size_t gNumSystemFonts = 0;
-#define DEFAULT_NAMES gSansNames
+#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;
-/* This is sized conservatively, assuming that it will never be a size issue.
- It will be initialized in load_system_fonts(), and will be filled with the
- fontIDs that can be used for fallback consideration, in sorted order (sorted
- meaning element[0] should be used first, then element[1], etc. When we hit
- a fontID==0 in the array, the list is done, hence our allocation size is
- +1 the total number of possible system fonts. Also see NextLogicalFont().
- */
-static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
+/* 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);
+
+ SkTDArray<FontInitRec> fontInfo;
+ bool firstInFamily = false;
+ for (int i = 0; i < fontFamilies.count(); ++i) {
+ FontFamily *family = fontFamilies[i];
+ firstInFamily = true;
+ for (int j = 0; j < family->fFileNames.count(); ++j) {
+ FontInitRec fontInfoRecord;
+ fontInfoRecord.fFileName = family->fFileNames[j];
+ if (j == 0) {
+ if (family->fNames.count() == 0) {
+ // Fallback font
+ fontInfoRecord.fNames = (char **)gFBNames;
+ } else {
+ SkTDArray<const char*> names = family->fNames;
+ const char **nameList = (const char**)
+ malloc((names.count() + 1) * sizeof(char*));
+ if (nameList == NULL) {
+ // shouldn't get here
+ break;
+ }
+ if (gDefaultNames == NULL) {
+ gDefaultNames = (char**) nameList;
+ }
+ for (int i = 0; i < names.count(); ++i) {
+ nameList[i] = names[i];
+ }
+ nameList[names.count()] = NULL;
+ fontInfoRecord.fNames = nameList;
+ }
+ } else {
+ fontInfoRecord.fNames = NULL;
+ }
+ *fontInfo.append() = fontInfoRecord;
+ }
+ }
+ gNumSystemFonts = fontInfo.count();
+ gSystemFonts = (FontInitRec*) malloc(gNumSystemFonts * sizeof(FontInitRec));
+ gFallbackFonts = (uint32_t*) malloc((gNumSystemFonts + 1) * sizeof(uint32_t));
+ if (gSystemFonts == NULL) {
+ // shouldn't get here
+ gNumSystemFonts = 0;
+ }
+ for (size_t i = 0; i < gNumSystemFonts; ++i) {
+ gSystemFonts[i].fFileName = fontInfo[i].fFileName;
+ gSystemFonts[i].fNames = fontInfo[i].fNames;
+ }
+ fontFamilies.deleteAll();
+}
/* Called once (ensured by the sentinel check at the beginning of our body).
Initializes all the globals, and register the system fonts.
@@ -463,11 +480,13 @@ static void load_system_fonts() {
return;
}
+ load_font_info();
+
const FontInitRec* rec = gSystemFonts;
SkTypeface* firstInFamily = NULL;
int fallbackCount = 0;
- for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
+ for (size_t i = 0; i < gNumSystemFonts; i++) {
// if we're the first in a new family, clear firstInFamily
if (rec[i].fNames != NULL) {
firstInFamily = NULL;
@@ -505,7 +524,7 @@ static void load_system_fonts() {
const char* const* names = rec[i].fNames;
// record the default family if this is it
- if (names == DEFAULT_NAMES) {
+ if (names == gDefaultNames) {
gDefaultFamily = family;
}
// add the names to map to this family
@@ -553,7 +572,7 @@ SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
stream->read(str.writable_str(), len);
const FontInitRec* rec = gSystemFonts;
- for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
+ for (size_t i = 0; i < gNumSystemFonts; i++) {
if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
// backup until we hit the fNames
for (int j = i; j >= 0; --j) {