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

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: Safety tweak to attribute comparisons 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) {
tomhudson 2014/08/04 17:33:48 Moved to start of file so everybody can see it.
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 {
tomhudson 2014/08/04 17:33:48 Will fill in with cleaned-up version of prototype
djsollen 2014/08/04 18:13:35 I'm ok with putting both of them in this file for
tomhudson 2014/08/04 21:03:56 Acknowledged.
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: {
bungeman-skia 2014/08/04 18:02:12 nit: The extra braces seem extraneous, normally th
tomhudson 2014/08/04 21:03:56 Done.
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 (strncmp(attributeName, "variant", nameLength) == 0) {
113 if (strncmp(attributeValue, "elegant", valueLength) == 0) { 136 if (strncmp(attributeValue, "elegant", valueLength) == 0) {
(...skipping 13 matching lines...) Expand all
127 } 150 }
128 //each element is a pair of attributeName/attributeValue string pair s 151 //each element is a pair of attributeName/attributeValue string pair s
129 currentAttributeIndex += 2; 152 currentAttributeIndex += 2;
130 } 153 }
131 } 154 }
132 familyData->currentFontInfo = &newFileInfo; 155 familyData->currentFontInfo = &newFileInfo;
133 XML_SetCharacterDataHandler(*familyData->parser, textHandler); 156 XML_SetCharacterDataHandler(*familyData->parser, textHandler);
134 } 157 }
135 158
136 /** 159 /**
137 * Handler for the start of a tag. The only tags we expect are family, nameset, 160 * Handler for the start of a tag. The only tags we expect are familyset, family ,
138 * fileset, name, and file. 161 * nameset, fileset, name, and file.
139 */ 162 */
140 static void startElementHandler(void *data, const char *tag, const char **atts) { 163 static void startElementHandler(void *data, const char *tag, const char **atts) {
141 FamilyData *familyData = (FamilyData*) data; 164 FamilyData *familyData = (FamilyData*) data;
142 int len = strlen(tag); 165 int len = strlen(tag);
143 if (strncmp(tag, "family", len)== 0) { 166 if (len == 9 && strncmp(tag, "familyset", len) == 0) {
tomhudson 2014/08/04 17:33:48 Note to self: remember to check len explicitly, ot
bungeman-skia 2014/08/04 18:02:12 This is an interesting quirk, in that with strncmp
tomhudson 2014/08/04 18:14:49 The len == MAGIC && !strncmp() pattern was present
167 // The familyset tag has an optional "version" attribute with an integer value >= 0
168 for (int i = 0; atts[i] != NULL; i += 2) {
169 int nameLen = strlen(atts[i]);
170 if (strncmp(atts[i], "version", nameLen)) continue;
bungeman-skia 2014/08/04 18:02:12 Add the 'nameLen = strlen("version")' thing here t
tomhudson 2014/08/04 21:03:56 Done. Added it to every strlen() in the file, inc
171 const char* valueString = atts[i+1];
172 int version;
173 int len = sscanf(valueString, "%d", &version);
bungeman-skia 2014/08/04 18:02:12 It seems you put parseNonNegativeInteger up top in
tomhudson 2014/08/04 18:14:49 qv <family> order=; for some reason the previous v
tomhudson 2014/08/04 21:03:56 Done.
174 if (len > 0 && 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 int len = sscanf(valueString, "%d", &value);
152 if (len > 0) { 189 if (len > 0) {
153 familyData->currentFamily->order = value; 190 familyData->currentFamily->order = value;
(...skipping 27 matching lines...) Expand all
181 familyData->currentTag = NO_TAG; 218 familyData->currentTag = NO_TAG;
182 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { 219 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
183 familyData->currentTag = NO_TAG; 220 familyData->currentTag = NO_TAG;
184 } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAME SET_TAG) || 221 } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAME SET_TAG) ||
185 (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET _TAG)) { 222 (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET _TAG)) {
186 // Disable the arbitrary text handler installed to load Name data 223 // Disable the arbitrary text handler installed to load Name data
187 XML_SetCharacterDataHandler(*familyData->parser, NULL); 224 XML_SetCharacterDataHandler(*familyData->parser, NULL);
188 } 225 }
189 } 226 }
190 227
228 } // namespace jbParser
229
191 /** 230 /**
192 * This function parses the given filename and stores the results in the given 231 * This function parses the given filename and stores the results in the given
193 * families array. 232 * families array.
194 */ 233 */
195 static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &famili es) { 234 static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &famili es) {
196 235
197 FILE* file = NULL; 236 FILE* file = NULL;
198 237
199 #if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) 238 #if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
200 // if we are using a version of Android prior to Android 4.2 (JellyBean MR1 239 // if we are using a version of Android prior to Android 4.2 (JellyBean MR1
(...skipping 29 matching lines...) Expand all
230 269
231 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac k_fonts.xml) 270 // 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. 271 // are optional - failure here is okay because one of these optional files m ay not exist.
233 if (NULL == file) { 272 if (NULL == file) {
234 return; 273 return;
235 } 274 }
236 275
237 XML_Parser parser = XML_ParserCreate(NULL); 276 XML_Parser parser = XML_ParserCreate(NULL);
238 FamilyData *familyData = new FamilyData(&parser, families); 277 FamilyData *familyData = new FamilyData(&parser, families);
239 XML_SetUserData(parser, familyData); 278 XML_SetUserData(parser, familyData);
240 XML_SetElementHandler(parser, startElementHandler, endElementHandler); 279 // Start parsing oldschool; switch these in flight if we detect a newer vers ion of the file.
280 XML_SetElementHandler(parser, jbParser::startElementHandler, jbParser::endEl ementHandler);
241 281
242 char buffer[512]; 282 char buffer[512];
243 bool done = false; 283 bool done = false;
244 while (!done) { 284 while (!done) {
245 fgets(buffer, sizeof(buffer), file); 285 fgets(buffer, sizeof(buffer), file);
246 int len = strlen(buffer); 286 int len = strlen(buffer);
247 if (feof(file) != 0) { 287 if (feof(file) != 0) {
248 done = true; 288 done = true;
249 } 289 }
250 XML_Parse(parser, buffer, len, done); 290 XML_Parse(parser, buffer, len, done);
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 *fontFamilies.append() = fallbackFonts[i]; 342 *fontFamilies.append() = fallbackFonts[i];
303 } 343 }
304 } 344 }
305 345
306 void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*> &fontFamilie s, 346 void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*> &fontFamilie s,
307 const char* testMainConfigFile, 347 const char* testMainConfigFile,
308 const char* testFallbackConfigFile) { 348 const char* testFallbackConfigFile) {
309 parseConfigFile(testMainConfigFile, fontFamilies); 349 parseConfigFile(testMainConfigFile, fontFamilies);
310 350
311 SkTDArray<FontFamily*> fallbackFonts; 351 SkTDArray<FontFamily*> fallbackFonts;
312 parseConfigFile(testFallbackConfigFile, fallbackFonts); 352 if (NULL != testFallbackConfigFile) {
tomhudson 2014/08/04 17:33:48 For v22, we only have one file; instead of adding
djsollen 2014/08/04 18:13:35 Acknowledged.
353 parseConfigFile(testFallbackConfigFile, fallbackFonts);
354 }
313 355
314 // Append all fallback fonts to system fonts 356 // Append all fallback fonts to system fonts
315 for (int i = 0; i < fallbackFonts.count(); ++i) { 357 for (int i = 0; i < fallbackFonts.count(); ++i) {
316 fallbackFonts[i]->fIsFallbackFont = true; 358 fallbackFonts[i]->fIsFallbackFont = true;
317 *fontFamilies.append() = fallbackFonts[i]; 359 *fontFamilies.append() = fallbackFonts[i];
318 } 360 }
319 } 361 }
320 362
321 /** 363 /**
322 * Read the persistent locale. 364 * Read the persistent locale.
(...skipping 17 matching lines...) Expand all
340 SkString locale(6); 382 SkString locale(6);
341 char* localeCStr = locale.writable_str(); 383 char* localeCStr = locale.writable_str();
342 384
343 strncpy(localeCStr, propLang, 2); 385 strncpy(localeCStr, propLang, 2);
344 localeCStr[2] = '-'; 386 localeCStr[2] = '-';
345 strncpy(&localeCStr[3], propRegn, 2); 387 strncpy(&localeCStr[3], propRegn, 2);
346 localeCStr[5] = '\0'; 388 localeCStr[5] = '\0';
347 389
348 return locale; 390 return locale;
349 } 391 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698