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

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

Issue 439813002: Test and generalize font configuration parser (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Fix nit and install Android fonts.xml update Created 6 years, 4 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
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 "SkFontConfigParser_android.h" 8 #include "SkFontConfigParser_android.h"
9 #include "SkTDArray.h" 9 #include "SkTDArray.h"
10 #include "SkTSearch.h" 10 #include "SkTSearch.h"
11 #include "SkTypeface.h" 11 #include "SkTypeface.h"
12 12
13 #include <expat.h> 13 #include <expat.h>
14 #include <stdio.h> 14 #include <stdio.h>
15 #include <sys/system_properties.h> 15 #include <sys/system_properties.h>
16 16
17 #include <limits> 17 #include <limits>
18 18
19 #define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" 19 #define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml"
20 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" 20 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml"
21 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" 21 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml"
22 22
23 /**
24 * This file contains TWO parsers: one for JB and earlier (system_fonts.xml /
25 * fallback_fonts.xml), one for LMP and later (fonts.xml).
26 * We start with the JB parser, and if we detect a <familyset> tag with
27 * version 21 or higher we switch to the LMP parser.
28 */
29
23 // These defines are used to determine the kind of tag that we're currently 30 // These defines are used to determine the kind of tag that we're currently
24 // populating with data. We only care about the sibling tags nameset and fileset 31 // populating with data. We only care about the sibling tags nameset and fileset
25 // for now. 32 // for now.
26 #define NO_TAG 0 33 #define NO_TAG 0
27 #define NAMESET_TAG 1 34 #define NAMESET_TAG 1
28 #define FILESET_TAG 2 35 #define FILESET_TAG 2
29 36
30 /** 37 /**
31 * The FamilyData structure is passed around by the parser so that each handler 38 * The FamilyData structure is passed around by the parser so that each handler
32 * can read these variables that are relevant to the current parsing. 39 * can read these variables that are relevant to the current parsing.
33 */ 40 */
34 struct FamilyData { 41 struct FamilyData {
35 FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef) : 42 FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef) :
36 parser(parserRef), 43 parser(parserRef),
37 families(familiesRef), 44 families(familiesRef),
38 currentFamily(NULL), 45 currentFamily(NULL),
39 currentFontInfo(NULL), 46 currentFontInfo(NULL),
40 currentTag(NO_TAG) {}; 47 currentTag(NO_TAG) {};
41 48
42 XML_Parser *parser; // The expat parser doing the work 49 XML_Parser *parser; // The expat parser doing the work
43 SkTDArray<FontFamily*> &families; // The array that each family is put into as it is parsed 50 SkTDArray<FontFamily*> &families; // The array that each family is put into as it is parsed
44 FontFamily *currentFamily; // The current family being created 51 FontFamily *currentFamily; // The current family being created
45 FontFileInfo *currentFontInfo; // The current fontInfo being created 52 FontFileInfo *currentFontInfo; // The current fontInfo being created
46 int currentTag; // A flag to indicate whether we're in na meset/fileset tags 53 int currentTag; // A flag to indicate whether we're in na meset/fileset tags
47 }; 54 };
48 55
56 /** http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-nega tive-def */
57 template <typename T> static bool parseNonNegativeInteger(const char* s, T* valu e) {
58 SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer);
59 const T nMax = std::numeric_limits<T>::max() / 10;
60 const T dMax = std::numeric_limits<T>::max() - (nMax * 10);
61 T n = 0;
62 for (; *s; ++s) {
63 // Check if digit
64 if (*s < '0' || '9' < *s) {
65 return false;
66 }
67 int d = *s - '0';
68 // Check for overflow
69 if (n > nMax || (n == nMax && d > dMax)) {
70 return false;
71 }
72 n = (n * 10) + d;
73 }
74 *value = n;
75 return true;
76 }
77
78 namespace lmpParser {
79
80 void startElementHandler(void* data, const char* tag,
81 const char** attributes) {
82 //SkDebugf("lmp started %s", tag);
83 }
84
85 void endElementHandler(void* data, const char* tag) {
86
87 //SkDebugf("lmp ended %s", tag);
88
89 }
90
91 } // lmpParser
92
93 namespace jbParser {
94
49 /** 95 /**
50 * Handler for arbitrary text. This is used to parse the text inside each name 96 * Handler for arbitrary text. This is used to parse the text inside each name
51 * or file tag. The resulting strings are put into the fNames or FontFileInfo ar rays. 97 * or file tag. The resulting strings are put into the fNames or FontFileInfo ar rays.
52 */ 98 */
53 static void textHandler(void *data, const char *s, int len) { 99 static void textHandler(void *data, const char *s, int len) {
54 FamilyData *familyData = (FamilyData*) data; 100 FamilyData *familyData = (FamilyData*) data;
55 // Make sure we're in the right state to store this name information 101 // Make sure we're in the right state to store this name information
56 if (familyData->currentFamily && 102 if (familyData->currentFamily &&
57 (familyData->currentTag == NAMESET_TAG || familyData->currentTag == FILESET_TAG)) { 103 (familyData->currentTag == NAMESET_TAG || familyData->currentTag == FILESET_TAG)) {
58 switch (familyData->currentTag) { 104 switch (familyData->currentTag) {
59 case NAMESET_TAG: { 105 case NAMESET_TAG: {
60 SkAutoAsciiToLC tolc(s, len); 106 SkAutoAsciiToLC tolc(s, len);
61 familyData->currentFamily->fNames.push_back().set(tolc.lc(), len); 107 familyData->currentFamily->fNames.push_back().set(tolc.lc(), len);
62 break; 108 break;
63 } 109 }
64 case FILESET_TAG: 110 case FILESET_TAG:
65 if (familyData->currentFontInfo) { 111 if (familyData->currentFontInfo) {
66 familyData->currentFontInfo->fFileName.set(s, len); 112 familyData->currentFontInfo->fFileName.set(s, len);
67 } 113 }
68 break; 114 break;
69 default: 115 default:
70 // Noop - don't care about any text that's not in the Fonts or Names list 116 // Noop - don't care about any text that's not in the Fonts or Names list
71 break; 117 break;
72 } 118 }
73 } 119 }
74 } 120 }
75 121
76 /** http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-nega tive-def */
77 template <typename T> static bool parseNonNegativeInteger(const char* s, T* valu e) {
78 SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer);
79 const T nMax = std::numeric_limits<T>::max() / 10;
80 const T dMax = std::numeric_limits<T>::max() - (nMax * 10);
81 T n = 0;
82 for (; *s; ++s) {
83 // Check if digit
84 if (*s < '0' || '9' < *s) {
85 return false;
86 }
87 int d = *s - '0';
88 // Check for overflow
89 if (n > nMax || (n == nMax && d > dMax)) {
90 return false;
91 }
92 n = (n * 10) + d;
93 }
94 *value = n;
95 return true;
96 }
97
98 /** 122 /**
99 * Handler for font files. This processes the attributes for language and 123 * Handler for font files. This processes the attributes for language and
100 * variants then lets textHandler handle the actual file name 124 * variants then lets textHandler handle the actual file name
101 */ 125 */
102 static void fontFileElementHandler(FamilyData *familyData, const char **attribut es) { 126 static void fontFileElementHandler(FamilyData *familyData, const char **attribut es) {
103
104 FontFileInfo& newFileInfo = familyData->currentFamily->fFontFiles.push_back( ); 127 FontFileInfo& newFileInfo = familyData->currentFamily->fFontFiles.push_back( );
105 if (attributes) { 128 if (attributes) {
106 int currentAttributeIndex = 0; 129 int currentAttributeIndex = 0;
107 while (attributes[currentAttributeIndex]) { 130 while (attributes[currentAttributeIndex]) {
108 const char* attributeName = attributes[currentAttributeIndex]; 131 const char* attributeName = attributes[currentAttributeIndex];
109 const char* attributeValue = attributes[currentAttributeIndex+1]; 132 const char* attributeValue = attributes[currentAttributeIndex+1];
110 int nameLength = strlen(attributeName); 133 int nameLength = strlen(attributeName);
111 int valueLength = strlen(attributeValue); 134 int valueLength = strlen(attributeValue);
112 if (strncmp(attributeName, "variant", nameLength) == 0) { 135 if (nameLength == 7 && strncmp(attributeName, "variant", nameLength) == 0) {
113 if (strncmp(attributeValue, "elegant", valueLength) == 0) { 136 if (valueLength == 7 && strncmp(attributeValue, "elegant", value Length) == 0) {
114 newFileInfo.fPaintOptions.setFontVariant(SkPaintOptionsAndro id::kElegant_Variant); 137 newFileInfo.fPaintOptions.setFontVariant(SkPaintOptionsAndro id::kElegant_Variant);
115 } else if (strncmp(attributeValue, "compact", valueLength) == 0) { 138 } else if (valueLength == 7 &&
139 strncmp(attributeValue, "compact", valueLength) == 0) {
116 newFileInfo.fPaintOptions.setFontVariant(SkPaintOptionsAndro id::kCompact_Variant); 140 newFileInfo.fPaintOptions.setFontVariant(SkPaintOptionsAndro id::kCompact_Variant);
117 } 141 }
118 } else if (strncmp(attributeName, "lang", nameLength) == 0) { 142 } else if (nameLength == 4 && strncmp(attributeName, "lang", nameLen gth) == 0) {
119 newFileInfo.fPaintOptions.setLanguage(attributeValue); 143 newFileInfo.fPaintOptions.setLanguage(attributeValue);
120 } else if (strncmp(attributeName, "index", nameLength) == 0) { 144 } else if (nameLength == 5 && strncmp(attributeName, "index", nameLe ngth) == 0) {
121 int value; 145 int value;
122 if (parseNonNegativeInteger(attributeValue, &value)) { 146 if (parseNonNegativeInteger(attributeValue, &value)) {
123 newFileInfo.fIndex = value; 147 newFileInfo.fIndex = value;
124 } else { 148 } else {
125 SkDebugf("---- SystemFonts index=%s (INVALID)", attributeVal ue); 149 SkDebugf("---- SystemFonts index=%s (INVALID)", attributeVal ue);
126 } 150 }
127 } 151 }
128 //each element is a pair of attributeName/attributeValue string pair s 152 //each element is a pair of attributeName/attributeValue string pair s
129 currentAttributeIndex += 2; 153 currentAttributeIndex += 2;
130 } 154 }
131 } 155 }
132 familyData->currentFontInfo = &newFileInfo; 156 familyData->currentFontInfo = &newFileInfo;
133 XML_SetCharacterDataHandler(*familyData->parser, textHandler); 157 XML_SetCharacterDataHandler(*familyData->parser, textHandler);
134 } 158 }
135 159
136 /** 160 /**
137 * Handler for the start of a tag. The only tags we expect are family, nameset, 161 * Handler for the start of a tag. The only tags we expect are familyset, family ,
138 * fileset, name, and file. 162 * nameset, fileset, name, and file.
139 */ 163 */
140 static void startElementHandler(void *data, const char *tag, const char **atts) { 164 static void startElementHandler(void *data, const char *tag, const char **atts) {
141 FamilyData *familyData = (FamilyData*) data; 165 FamilyData *familyData = (FamilyData*) data;
142 int len = strlen(tag); 166 int len = strlen(tag);
143 if (strncmp(tag, "family", len)== 0) { 167 if (len == 9 && strncmp(tag, "familyset", len) == 0) {
168 // The familyset tag has an optional "version" attribute with an integer value >= 0
169 for (int i = 0; atts[i] != NULL; i += 2) {
170 int nameLen = strlen(atts[i]);
171 if (nameLen == 7 && strncmp(atts[i], "version", nameLen)) continue;
172 const char* valueString = atts[i+1];
173 int version;
174 if (parseNonNegativeInteger(valueString, &version) && (version >= 21 )) {
175 XML_SetElementHandler(*familyData->parser,
176 lmpParser::startElementHandler,
177 lmpParser::endElementHandler);
178 }
179 }
180 } else if (len == 6 && strncmp(tag, "family", len) == 0) {
144 familyData->currentFamily = new FontFamily(); 181 familyData->currentFamily = new FontFamily();
145 familyData->currentFamily->order = -1; 182 familyData->currentFamily->order = -1;
146 // The Family tag has an optional "order" attribute with an integer valu e >= 0 183 // The Family tag has an optional "order" attribute with an integer valu e >= 0
147 // If this attribute does not exist, the default value is -1 184 // If this attribute does not exist, the default value is -1
148 for (int i = 0; atts[i] != NULL; i += 2) { 185 for (int i = 0; atts[i] != NULL; i += 2) {
149 const char* valueString = atts[i+1]; 186 const char* valueString = atts[i+1];
150 int value; 187 int value;
151 int len = sscanf(valueString, "%d", &value); 188 if (parseNonNegativeInteger(valueString, &value)) {
152 if (len > 0) {
153 familyData->currentFamily->order = value; 189 familyData->currentFamily->order = value;
154 } 190 }
155 } 191 }
156 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) { 192 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) {
157 familyData->currentTag = NAMESET_TAG; 193 familyData->currentTag = NAMESET_TAG;
158 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { 194 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
159 familyData->currentTag = FILESET_TAG; 195 familyData->currentTag = FILESET_TAG;
160 } else if (strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMES ET_TAG) { 196 } else if (len == 4 && strncmp(tag, "name", len) == 0 && familyData->current Tag == NAMESET_TAG) {
161 // If it's a Name, parse the text inside 197 // If it's a Name, parse the text inside
162 XML_SetCharacterDataHandler(*familyData->parser, textHandler); 198 XML_SetCharacterDataHandler(*familyData->parser, textHandler);
163 } else if (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILES ET_TAG) { 199 } else if (len == 4 && strncmp(tag, "file", len) == 0 && familyData->current Tag == FILESET_TAG) {
164 // If it's a file, parse the attributes, then parse the text inside 200 // If it's a file, parse the attributes, then parse the text inside
165 fontFileElementHandler(familyData, atts); 201 fontFileElementHandler(familyData, atts);
166 } 202 }
167 } 203 }
168 204
169 /** 205 /**
170 * Handler for the end of tags. We only care about family, nameset, fileset, 206 * Handler for the end of tags. We only care about family, nameset, fileset,
171 * name, and file. 207 * name, and file.
172 */ 208 */
173 static void endElementHandler(void *data, const char *tag) { 209 static void endElementHandler(void *data, const char *tag) {
174 FamilyData *familyData = (FamilyData*) data; 210 FamilyData *familyData = (FamilyData*) data;
175 int len = strlen(tag); 211 int len = strlen(tag);
176 if (strncmp(tag, "family", len)== 0) { 212 if (len == 6 && strncmp(tag, "family", len)== 0) {
177 // Done parsing a Family - store the created currentFamily in the famili es array 213 // Done parsing a Family - store the created currentFamily in the famili es array
178 *familyData->families.append() = familyData->currentFamily; 214 *familyData->families.append() = familyData->currentFamily;
179 familyData->currentFamily = NULL; 215 familyData->currentFamily = NULL;
180 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) { 216 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) {
181 familyData->currentTag = NO_TAG; 217 familyData->currentTag = NO_TAG;
182 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { 218 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
183 familyData->currentTag = NO_TAG; 219 familyData->currentTag = NO_TAG;
184 } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAME SET_TAG) || 220 } else if ((len == 4 &&
185 (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET _TAG)) { 221 strncmp(tag, "name", len) == 0 &&
222 familyData->currentTag == NAMESET_TAG) ||
223 (len == 4 &&
224 strncmp(tag, "file", len) == 0 &&
225 familyData->currentTag == FILESET_TAG)) {
186 // Disable the arbitrary text handler installed to load Name data 226 // Disable the arbitrary text handler installed to load Name data
187 XML_SetCharacterDataHandler(*familyData->parser, NULL); 227 XML_SetCharacterDataHandler(*familyData->parser, NULL);
188 } 228 }
189 } 229 }
190 230
231 } // namespace jbParser
232
191 /** 233 /**
192 * This function parses the given filename and stores the results in the given 234 * This function parses the given filename and stores the results in the given
193 * families array. 235 * families array.
194 */ 236 */
195 static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &famili es) { 237 static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &famili es) {
196 238
197 FILE* file = NULL; 239 FILE* file = NULL;
198 240
199 #if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) 241 #if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
200 // if we are using a version of Android prior to Android 4.2 (JellyBean MR1 242 // if we are using a version of Android prior to Android 4.2 (JellyBean MR1
(...skipping 29 matching lines...) Expand all
230 272
231 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac k_fonts.xml) 273 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac k_fonts.xml)
232 // are optional - failure here is okay because one of these optional files m ay not exist. 274 // are optional - failure here is okay because one of these optional files m ay not exist.
233 if (NULL == file) { 275 if (NULL == file) {
234 return; 276 return;
235 } 277 }
236 278
237 XML_Parser parser = XML_ParserCreate(NULL); 279 XML_Parser parser = XML_ParserCreate(NULL);
238 FamilyData *familyData = new FamilyData(&parser, families); 280 FamilyData *familyData = new FamilyData(&parser, families);
239 XML_SetUserData(parser, familyData); 281 XML_SetUserData(parser, familyData);
240 XML_SetElementHandler(parser, startElementHandler, endElementHandler); 282 // Start parsing oldschool; switch these in flight if we detect a newer vers ion of the file.
283 XML_SetElementHandler(parser, jbParser::startElementHandler, jbParser::endEl ementHandler);
241 284
242 char buffer[512]; 285 char buffer[512];
243 bool done = false; 286 bool done = false;
244 while (!done) { 287 while (!done) {
245 fgets(buffer, sizeof(buffer), file); 288 fgets(buffer, sizeof(buffer), file);
246 int len = strlen(buffer); 289 int len = strlen(buffer);
247 if (feof(file) != 0) { 290 if (feof(file) != 0) {
248 done = true; 291 done = true;
249 } 292 }
250 XML_Parse(parser, buffer, len, done); 293 XML_Parse(parser, buffer, len, done);
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 *fontFamilies.append() = fallbackFonts[i]; 345 *fontFamilies.append() = fallbackFonts[i];
303 } 346 }
304 } 347 }
305 348
306 void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*> &fontFamilie s, 349 void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*> &fontFamilie s,
307 const char* testMainConfigFile, 350 const char* testMainConfigFile,
308 const char* testFallbackConfigFile) { 351 const char* testFallbackConfigFile) {
309 parseConfigFile(testMainConfigFile, fontFamilies); 352 parseConfigFile(testMainConfigFile, fontFamilies);
310 353
311 SkTDArray<FontFamily*> fallbackFonts; 354 SkTDArray<FontFamily*> fallbackFonts;
312 parseConfigFile(testFallbackConfigFile, fallbackFonts); 355 if (NULL != testFallbackConfigFile) {
356 parseConfigFile(testFallbackConfigFile, fallbackFonts);
357 }
313 358
314 // Append all fallback fonts to system fonts 359 // Append all fallback fonts to system fonts
315 for (int i = 0; i < fallbackFonts.count(); ++i) { 360 for (int i = 0; i < fallbackFonts.count(); ++i) {
316 fallbackFonts[i]->fIsFallbackFont = true; 361 fallbackFonts[i]->fIsFallbackFont = true;
317 *fontFamilies.append() = fallbackFonts[i]; 362 *fontFamilies.append() = fallbackFonts[i];
318 } 363 }
319 } 364 }
320 365
321 /** 366 /**
322 * Read the persistent locale. 367 * Read the persistent locale.
(...skipping 17 matching lines...) Expand all
340 SkString locale(6); 385 SkString locale(6);
341 char* localeCStr = locale.writable_str(); 386 char* localeCStr = locale.writable_str();
342 387
343 strncpy(localeCStr, propLang, 2); 388 strncpy(localeCStr, propLang, 2);
344 localeCStr[2] = '-'; 389 localeCStr[2] = '-';
345 strncpy(&localeCStr[3], propRegn, 2); 390 strncpy(&localeCStr[3], propRegn, 2);
346 localeCStr[5] = '\0'; 391 localeCStr[5] = '\0';
347 392
348 return locale; 393 return locale;
349 } 394 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698