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

Side by Side Diff: src/ports/SkFontConfigParser_android.cpp

Issue 14731025: Add a fontConfig interface for android. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: rebasing Created 7 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ports/SkFontConfigParser_android.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2011 The Android Open Source Project 2 * Copyright 2011 The Android Open Source Project
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "FontHostConfiguration_android.h" 8 #include "SkFontConfigParser_android.h"
9 #include "SkString.h"
10 #include "SkTDArray.h" 9 #include "SkTDArray.h"
10 #include "SkTypeface.h"
11
11 #include <expat.h> 12 #include <expat.h>
12 #include <sys/system_properties.h> 13 #include <sys/system_properties.h>
13 14
14 #define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" 15 #define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml"
15 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" 16 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml"
16 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" 17 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml"
17 18
18
19 // These defines are used to determine the kind of tag that we're currently 19 // These defines are used to determine the kind of tag that we're currently
20 // populating with data. We only care about the sibling tags nameset and fileset 20 // populating with data. We only care about the sibling tags nameset and fileset
21 // for now. 21 // for now.
22 #define NO_TAG 0 22 #define NO_TAG 0
23 #define NAMESET_TAG 1 23 #define NAMESET_TAG 1
24 #define FILESET_TAG 2 24 #define FILESET_TAG 2
25 25
26 /** 26 /**
27 * The FamilyData structure is passed around by the parser so that each handler 27 * The FamilyData structure is passed around by the parser so that each handler
28 * can read these variables that are relevant to the current parsing. 28 * can read these variables that are relevant to the current parsing.
29 */ 29 */
30 struct FamilyData { 30 struct FamilyData {
31 FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef, const AndroidLocale &localeRef) : 31 FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef) :
32 parser(parserRef), families(familiesRef), currentTag(NO_TAG), 32 parser(parserRef),
33 locale(localeRef), currentFamilyLangMatch(false), familyLangMatchCou nt(0) {} 33 families(familiesRef),
34 currentFamily(NULL),
35 currentFontInfo(NULL),
36 currentTag(NO_TAG) {};
34 37
35 XML_Parser *parser; // The expat parser doing the work 38 XML_Parser *parser; // The expat parser doing the work
36 SkTDArray<FontFamily*> &families; // The array that each family is put into as it is parsed 39 SkTDArray<FontFamily*> &families; // The array that each family is put into as it is parsed
37 FontFamily *currentFamily; // The current family being created 40 FontFamily *currentFamily; // The current family being created
41 FontFileInfo *currentFontInfo; // The current fontInfo being created
38 int currentTag; // A flag to indicate whether we're in na meset/fileset tags 42 int currentTag; // A flag to indicate whether we're in na meset/fileset tags
39 const AndroidLocale &locale; // The locale to which we compare the "la ng" attribute of File.
40 bool currentFamilyLangMatch; // If currentFamily's File has a "lang" a ttribute and matches locale.
41 int familyLangMatchCount; // Number of families containing File whi ch has a "lang" attribute and matches locale.
42 }; 43 };
43 44
44 /** 45 /**
45 * Handler for arbitrary text. This is used to parse the text inside each name 46 * Handler for arbitrary text. This is used to parse the text inside each name
46 * or file tag. The resulting strings are put into the fNames or fFileNames arra ys. 47 * or file tag. The resulting strings are put into the fNames or FontFileInfo ar rays.
47 */ 48 */
48 void textHandler(void *data, const char *s, int len) { 49 static void textHandler(void *data, const char *s, int len) {
49 FamilyData *familyData = (FamilyData*) data; 50 FamilyData *familyData = (FamilyData*) data;
50 // Make sure we're in the right state to store this name information 51 // Make sure we're in the right state to store this name information
51 if (familyData->currentFamily && 52 if (familyData->currentFamily &&
52 (familyData->currentTag == NAMESET_TAG || familyData->currentTag == FILESET_TAG)) { 53 (familyData->currentTag == NAMESET_TAG || familyData->currentTag == FILESET_TAG)) {
53 // Malloc new buffer to store the string 54 // Malloc new buffer to store the string
54 char *buff; 55 char *buff;
55 buff = (char*) malloc((len + 1) * sizeof(char)); 56 buff = (char*) malloc((len + 1) * sizeof(char));
56 strncpy(buff, s, len); 57 strncpy(buff, s, len);
57 buff[len] = '\0'; 58 buff[len] = '\0';
58 switch (familyData->currentTag) { 59 switch (familyData->currentTag) {
59 case NAMESET_TAG: 60 case NAMESET_TAG:
60 *(familyData->currentFamily->fNames.append()) = buff; 61 *(familyData->currentFamily->fNames.append()) = buff;
61 break; 62 break;
62 case FILESET_TAG: 63 case FILESET_TAG:
63 *(familyData->currentFamily->fFileNames.append()) = buff; 64 if (familyData->currentFontInfo) {
65 familyData->currentFontInfo->fFileName = buff;
66 }
64 break; 67 break;
65 default: 68 default:
66 // Noop - don't care about any text that's not in the Fonts or Names list 69 // Noop - don't care about any text that's not in the Fonts or Names list
67 break; 70 break;
68 } 71 }
69 } 72 }
70 } 73 }
71 74
72 /** 75 /**
76 * Handler for font files. This processes the attributes for language and
77 * variants then lets textHandler handle the actual file name
78 */
79 static void fontFileElementHandler(FamilyData *familyData, const char **attribut es) {
80 FontFileInfo* newFileInfo = new FontFileInfo();
81 if (attributes) {
82 int currentAttributeIndex = 0;
83 while (attributes[currentAttributeIndex]) {
84 const char* attributeName = attributes[currentAttributeIndex];
85 const char* attributeValue = attributes[currentAttributeIndex+1];
86 int nameLength = strlen(attributeName);
87 int valueLength = strlen(attributeValue);
88 if (strncmp(attributeName, "variant", nameLength) == 0) {
89 if (strncmp(attributeValue, "elegant", valueLength) == 0) {
90 newFileInfo->fPaintOptions.setFontVariant(SkPaintOptionsAndr oid::kElegant_Variant);
91 } else if (strncmp(attributeValue, "compact", valueLength) == 0) {
92 newFileInfo->fPaintOptions.setFontVariant(SkPaintOptionsAndr oid::kCompact_Variant);
93 }
94 } else if (strncmp(attributeName, "lang", nameLength) == 0) {
95 newFileInfo->fPaintOptions.setLanguage(attributeValue);
96 }
97 //each element is a pair of attributeName/attributeValue string pair s
98 currentAttributeIndex += 2;
99 }
100 }
101 *(familyData->currentFamily->fFontFiles.append()) = newFileInfo;
102 familyData->currentFontInfo = newFileInfo;
103 XML_SetCharacterDataHandler(*familyData->parser, textHandler);
104 }
105
106 /**
73 * Handler for the start of a tag. The only tags we expect are family, nameset, 107 * Handler for the start of a tag. The only tags we expect are family, nameset,
74 * fileset, name, and file. 108 * fileset, name, and file.
75 */ 109 */
76 void startElementHandler(void *data, const char *tag, const char **atts) { 110 static void startElementHandler(void *data, const char *tag, const char **atts) {
77 FamilyData *familyData = (FamilyData*) data; 111 FamilyData *familyData = (FamilyData*) data;
78 int len = strlen(tag); 112 int len = strlen(tag);
79 if (strncmp(tag, "family", len)== 0) { 113 if (strncmp(tag, "family", len)== 0) {
80 familyData->currentFamily = new FontFamily(); 114 familyData->currentFamily = new FontFamily();
81 familyData->currentFamily->order = -1; 115 familyData->currentFamily->order = -1;
82 // The Family tag has an optional "order" attribute with an integer valu e >= 0 116 // The Family tag has an optional "order" attribute with an integer valu e >= 0
83 // If this attribute does not exist, the default value is -1 117 // If this attribute does not exist, the default value is -1
84 for (int i = 0; atts[i] != NULL; i += 2) { 118 for (int i = 0; atts[i] != NULL; i += 2) {
85 const char* valueString = atts[i+1]; 119 const char* valueString = atts[i+1];
86 int value; 120 int value;
87 int len = sscanf(valueString, "%d", &value); 121 int len = sscanf(valueString, "%d", &value);
88 if (len > 0) { 122 if (len > 0) {
89 familyData->currentFamily->order = value; 123 familyData->currentFamily->order = value;
90 } 124 }
91 } 125 }
92 } else if (len == 7 && strncmp(tag, "nameset", len)== 0) { 126 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) {
93 familyData->currentTag = NAMESET_TAG; 127 familyData->currentTag = NAMESET_TAG;
94 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { 128 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
95 familyData->currentTag = FILESET_TAG; 129 familyData->currentTag = FILESET_TAG;
96 } else if (strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMES ET_TAG) { 130 } else if (strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMES ET_TAG) {
131 // If it's a Name, parse the text inside
97 XML_SetCharacterDataHandler(*familyData->parser, textHandler); 132 XML_SetCharacterDataHandler(*familyData->parser, textHandler);
98 } else if (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILES ET_TAG) { 133 } else if (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILES ET_TAG) {
99 // From JB MR1, the File tag has a "lang" attribute to specify a languag e specific font file 134 // If it's a file, parse the attributes, then parse the text inside
100 // and the family entry has higher priority than the others without "lan g" attribute. 135 fontFileElementHandler(familyData, atts);
101 bool includeTheEntry = true;
102 for (int i = 0; atts[i] != NULL; i += 2) {
103 const char* attribute = atts[i];
104 const char* value = atts[i+1];
105 if (strncmp(attribute, "lang", 4) == 0) {
106 if (strcmp(value, familyData->locale.language) == 0) {
107 // Found matching "lang" attribute. The current Family will have higher priority in the family list.
108 familyData->currentFamilyLangMatch = true;
109 } else {
110 // Don't include the entry if "lang" is specified but not ma tching.
111 includeTheEntry = false;
112 }
113 }
114 }
115 if (includeTheEntry) {
116 XML_SetCharacterDataHandler(*familyData->parser, textHandler);
117 }
118 } 136 }
119 } 137 }
120 138
121 /** 139 /**
122 * Handler for the end of tags. We only care about family, nameset, fileset, 140 * Handler for the end of tags. We only care about family, nameset, fileset,
123 * name, and file. 141 * name, and file.
124 */ 142 */
125 void endElementHandler(void *data, const char *tag) { 143 static void endElementHandler(void *data, const char *tag) {
126 FamilyData *familyData = (FamilyData*) data; 144 FamilyData *familyData = (FamilyData*) data;
127 int len = strlen(tag); 145 int len = strlen(tag);
128 if (strncmp(tag, "family", len)== 0) { 146 if (strncmp(tag, "family", len)== 0) {
129 // Done parsing a Family - store the created currentFamily in the famili es array 147 // Done parsing a Family - store the created currentFamily in the famili es array
130 if (familyData->currentFamilyLangMatch) { 148 *familyData->families.append() = familyData->currentFamily;
131 *familyData->families.insert(familyData->familyLangMatchCount++) = f amilyData->currentFamily;
132 familyData->currentFamilyLangMatch = false;
133 } else {
134 *familyData->families.append() = familyData->currentFamily;
135 }
136 familyData->currentFamily = NULL; 149 familyData->currentFamily = NULL;
137 } else if (len == 7 && strncmp(tag, "nameset", len)== 0) { 150 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) {
138 familyData->currentTag = NO_TAG; 151 familyData->currentTag = NO_TAG;
139 } else if (len == 7 && strncmp(tag, "fileset", len)== 0) { 152 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
140 familyData->currentTag = NO_TAG; 153 familyData->currentTag = NO_TAG;
141 } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAME SET_TAG) || 154 } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAME SET_TAG) ||
142 (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET _TAG)) { 155 (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET _TAG)) {
143 // Disable the arbitrary text handler installed to load Name data 156 // Disable the arbitrary text handler installed to load Name data
144 XML_SetCharacterDataHandler(*familyData->parser, NULL); 157 XML_SetCharacterDataHandler(*familyData->parser, NULL);
145 } 158 }
146 } 159 }
147 160
148 /** 161 /**
149 * Read the persistent locale.
150 */
151 void getLocale(AndroidLocale &locale)
152 {
153 char propLang[PROP_VALUE_MAX], propRegn[PROP_VALUE_MAX];
154 __system_property_get("persist.sys.language", propLang);
155 __system_property_get("persist.sys.country", propRegn);
156
157 if (*propLang == 0 && *propRegn == 0) {
158 /* Set to ro properties, default is en_US */
159 __system_property_get("ro.product.locale.language", propLang);
160 __system_property_get("ro.product.locale.region", propRegn);
161 if (*propLang == 0 && *propRegn == 0) {
162 strcpy(propLang, "en");
163 strcpy(propRegn, "US");
164 }
165 }
166 strncpy(locale.language, propLang, 2);
167 locale.language[2] = '\0';
168 strncpy(locale.region, propRegn, 2);
169 locale.region[2] = '\0';
170 }
171
172 /**
173 * Use the current system locale (language and region) to open the best matching
174 * customization. For example, when the language is Japanese, the sequence might be:
175 * /system/etc/fallback_fonts-ja-JP.xml
176 * /system/etc/fallback_fonts-ja.xml
177 * /system/etc/fallback_fonts.xml
178 */
179 FILE* openLocalizedFile(const char* origname, const AndroidLocale& locale) {
180 FILE* file = 0;
181 SkString basename;
182 SkString filename;
183
184 basename.set(origname);
185 // Remove the .xml suffix. We'll add it back in a moment.
186 if (basename.endsWith(".xml")) {
187 basename.resize(basename.size()-4);
188 }
189 // Try first with language and region
190 filename.printf("%s-%s-%s.xml", basename.c_str(), locale.language, locale.re gion);
191 file = fopen(filename.c_str(), "r");
192 if (!file) {
193 // If not found, try next with just language
194 filename.printf("%s-%s.xml", basename.c_str(), locale.language);
195 file = fopen(filename.c_str(), "r");
196
197 if (!file) {
198 // If still not found, try just the original name
199 file = fopen(origname, "r");
200 }
201 }
202 return file;
203 }
204
205 /**
206 * This function parses the given filename and stores the results in the given 162 * This function parses the given filename and stores the results in the given
207 * families array. 163 * families array.
208 */ 164 */
209 void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) { 165 static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &famili es) {
210 AndroidLocale locale;
211 getLocale(locale);
212 XML_Parser parser = XML_ParserCreate(NULL); 166 XML_Parser parser = XML_ParserCreate(NULL);
213 FamilyData familyData(&parser, families, locale); 167 FamilyData *familyData = new FamilyData(&parser, families);
214 XML_SetUserData(parser, &familyData); 168 XML_SetUserData(parser, familyData);
215 XML_SetElementHandler(parser, startElementHandler, endElementHandler); 169 XML_SetElementHandler(parser, startElementHandler, endElementHandler);
216 FILE *file = openLocalizedFile(filename, locale); 170 FILE *file = fopen(filename, "r");
217 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac k_fonts.xml) 171 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac k_fonts.xml)
218 // are optional - failure here is okay because one of these optional files m ay not exist. 172 // are optional - failure here is okay because one of these optional files m ay not exist.
219 if (file == NULL) { 173 if (file == NULL) {
220 return; 174 return;
221 } 175 }
222 char buffer[512]; 176 char buffer[512];
223 bool done = false; 177 bool done = false;
224 while (!done) { 178 while (!done) {
225 fgets(buffer, sizeof(buffer), file); 179 fgets(buffer, sizeof(buffer), file);
226 int len = strlen(buffer); 180 int len = strlen(buffer);
227 if (feof(file) != 0) { 181 if (feof(file) != 0) {
228 done = true; 182 done = true;
229 } 183 }
230 XML_Parse(parser, buffer, len, done); 184 XML_Parse(parser, buffer, len, done);
231 } 185 }
232 fclose(file); 186 fclose(file);
233 XML_ParserFree(parser);
234 } 187 }
235 188
236 void getSystemFontFamilies(SkTDArray<FontFamily*> &fontFamilies) { 189 static void getSystemFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
237 parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies); 190 parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies);
238 } 191 }
239 192
240 void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts) { 193 static void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts) {
241 SkTDArray<FontFamily*> vendorFonts; 194 SkTDArray<FontFamily*> vendorFonts;
242 parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts); 195 parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts);
243 parseConfigFile(VENDOR_FONTS_FILE, vendorFonts); 196 parseConfigFile(VENDOR_FONTS_FILE, vendorFonts);
244 197
245 // This loop inserts the vendor fallback fonts in the correct order in the 198 // This loop inserts the vendor fallback fonts in the correct order in the
246 // overall fallbacks list. 199 // overall fallbacks list.
247 int currentOrder = -1; 200 int currentOrder = -1;
248 for (int i = 0; i < vendorFonts.count(); ++i) { 201 for (int i = 0; i < vendorFonts.count(); ++i) {
249 FontFamily* family = vendorFonts[i]; 202 FontFamily* family = vendorFonts[i];
250 int order = family->order; 203 int order = family->order;
(...skipping 12 matching lines...) Expand all
263 *fallbackFonts.insert(order) = family; 216 *fallbackFonts.insert(order) = family;
264 currentOrder = order + 1; 217 currentOrder = order + 1;
265 } 218 }
266 } 219 }
267 } 220 }
268 221
269 /** 222 /**
270 * Loads data on font families from various expected configuration files. The 223 * Loads data on font families from various expected configuration files. The
271 * resulting data is returned in the given fontFamilies array. 224 * resulting data is returned in the given fontFamilies array.
272 */ 225 */
273 void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies) { 226 void SkFontConfigParser::GetFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
274 SkTDArray<FontFamily*> fallbackFonts;
275 227
276 getSystemFontFamilies(fontFamilies); 228 getSystemFontFamilies(fontFamilies);
229
230 // Append all the fallback fonts to system fonts
231 SkTDArray<FontFamily*> fallbackFonts;
277 getFallbackFontFamilies(fallbackFonts); 232 getFallbackFontFamilies(fallbackFonts);
278
279 // Append all fallback fonts to system fonts
280 for (int i = 0; i < fallbackFonts.count(); ++i) { 233 for (int i = 0; i < fallbackFonts.count(); ++i) {
234 fallbackFonts[i]->fIsFallbackFont = true;
281 *fontFamilies.append() = fallbackFonts[i]; 235 *fontFamilies.append() = fallbackFonts[i];
282 } 236 }
283 } 237 }
284 238
285 void getTestFontFamilies(SkTDArray<FontFamily*> &fontFamilies, 239 void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*> &fontFamilie s,
286 const char* testMainConfigFile, 240 const char* testMainConfigFile,
287 const char* testFallbackConfigFile) { 241 const char* testFallbackConfigFile) {
288 parseConfigFile(testMainConfigFile, fontFamilies); 242 parseConfigFile(testMainConfigFile, fontFamilies);
289 243
290 SkTDArray<FontFamily*> fallbackFonts; 244 SkTDArray<FontFamily*> fallbackFonts;
291 parseConfigFile(testFallbackConfigFile, fallbackFonts); 245 parseConfigFile(testFallbackConfigFile, fallbackFonts);
292 246
293 // Append all fallback fonts to system fonts 247 // Append all fallback fonts to system fonts
294 for (int i = 0; i < fallbackFonts.count(); ++i) { 248 for (int i = 0; i < fallbackFonts.count(); ++i) {
249 fallbackFonts[i]->fIsFallbackFont = true;
295 *fontFamilies.append() = fallbackFonts[i]; 250 *fontFamilies.append() = fallbackFonts[i];
296 } 251 }
297 } 252 }
253
254 /**
255 * Read the persistent locale.
256 */
257 void SkFontConfigParser::GetLocale(AndroidLocale &locale)
258 {
259 char propLang[PROP_VALUE_MAX], propRegn[PROP_VALUE_MAX];
260 __system_property_get("persist.sys.language", propLang);
261 __system_property_get("persist.sys.country", propRegn);
262
263 if (*propLang == 0 && *propRegn == 0) {
264 /* Set to ro properties, default is en_US */
265 __system_property_get("ro.product.locale.language", propLang);
266 __system_property_get("ro.product.locale.region", propRegn);
267 if (*propLang == 0 && *propRegn == 0) {
268 strcpy(propLang, "en");
269 strcpy(propRegn, "US");
270 }
271 }
272 strncpy(locale.language, propLang, 2);
273 locale.language[2] = '\0';
274 strncpy(locale.region, propRegn, 2);
275 locale.region[2] = '\0';
276 }
OLDNEW
« no previous file with comments | « src/ports/SkFontConfigParser_android.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698