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

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

Issue 887113002: Add factory for Android font manager. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Remove no longer wanted function. Created 5 years, 10 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
« no previous file with comments | « src/ports/SkFontConfigParser_android.h ('k') | src/ports/SkFontMgr_android.cpp » ('j') | 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 "SkFontConfigParser_android.h" 8 #include "SkFontConfigParser_android.h"
9 #include "SkFontMgr_android.h"
10 #include "SkStream.h"
9 #include "SkTDArray.h" 11 #include "SkTDArray.h"
10 #include "SkTSearch.h" 12 #include "SkTSearch.h"
11 #include "SkTypeface.h" 13 #include "SkTypeface.h"
12 14
13 #include <expat.h> 15 #include <expat.h>
14 #include <dirent.h> 16 #include <dirent.h>
15 #include <stdio.h> 17 #include <stdio.h>
16 18
17 #include <limits> 19 #include <limits>
20 #include <stdlib.h>
18 21
19 // From Android version LMP onwards, all font files collapse into 22 // From Android version LMP onwards, all font files collapse into
20 // /system/etc/fonts.xml. Instead of trying to detect which version 23 // /system/etc/fonts.xml. Instead of trying to detect which version
21 // we're on, try to open fonts.xml; if that fails, fall back to the 24 // we're on, try to open fonts.xml; if that fails, fall back to the
22 // older filename. 25 // older filename.
23 #define LMP_SYSTEM_FONTS_FILE "/system/etc/fonts.xml" 26 #define LMP_SYSTEM_FONTS_FILE "/system/etc/fonts.xml"
24 #define OLD_SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" 27 #define OLD_SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml"
25 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" 28 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml"
26 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" 29 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml"
27 30
28 #define LOCALE_FALLBACK_FONTS_SYSTEM_DIR "/system/etc" 31 #define LOCALE_FALLBACK_FONTS_SYSTEM_DIR "/system/etc"
29 #define LOCALE_FALLBACK_FONTS_VENDOR_DIR "/vendor/etc" 32 #define LOCALE_FALLBACK_FONTS_VENDOR_DIR "/vendor/etc"
30 #define LOCALE_FALLBACK_FONTS_PREFIX "fallback_fonts-" 33 #define LOCALE_FALLBACK_FONTS_PREFIX "fallback_fonts-"
31 #define LOCALE_FALLBACK_FONTS_SUFFIX ".xml" 34 #define LOCALE_FALLBACK_FONTS_SUFFIX ".xml"
32 35
36 #ifndef SK_FONT_FILE_PREFIX
37 # define SK_FONT_FILE_PREFIX "/fonts/"
38 #endif
39
33 /** 40 /**
34 * This file contains TWO parsers: one for JB and earlier (system_fonts.xml / 41 * This file contains TWO parsers: one for JB and earlier (system_fonts.xml /
35 * fallback_fonts.xml), one for LMP and later (fonts.xml). 42 * fallback_fonts.xml), one for LMP and later (fonts.xml).
36 * We start with the JB parser, and if we detect a <familyset> tag with 43 * We start with the JB parser, and if we detect a <familyset> tag with
37 * version 21 or higher we switch to the LMP parser. 44 * version 21 or higher we switch to the LMP parser.
38 */ 45 */
39 46
40 // These defines are used to determine the kind of tag that we're currently 47 /** Used to track which tag is currently populating with data.
41 // populating with data. We only care about the sibling tags nameset and fileset 48 * Only nameset and fileset are of interest for now.
42 // for now. 49 */
43 #define NO_TAG 0 50 enum CurrentTag {
44 #define NAMESET_TAG 1 51 kNo_CurrentTag,
45 #define FILESET_TAG 2 52 kNameSet_CurrentTag,
53 kFileSet_CurrentTag
54 };
46 55
47 /** 56 /**
48 * The FamilyData structure is passed around by the parser so that each handler 57 * The FamilyData structure is passed around by the parser so that each handler
49 * can read these variables that are relevant to the current parsing. 58 * can read these variables that are relevant to the current parsing.
50 */ 59 */
51 struct FamilyData { 60 struct FamilyData {
52 FamilyData(XML_Parser parser, SkTDArray<FontFamily*>& families) 61 FamilyData(XML_Parser parser, SkTDArray<FontFamily*>& families,
62 const SkString& basePath, bool isFallback)
53 : fParser(parser) 63 : fParser(parser)
54 , fFamilies(families) 64 , fFamilies(families)
55 , fCurrentFamily(NULL) 65 , fCurrentFamily(NULL)
56 , fCurrentFontInfo(NULL) 66 , fCurrentFontInfo(NULL)
57 , fCurrentTag(NO_TAG) 67 , fCurrentTag(kNo_CurrentTag)
58 , fVersion(0) 68 , fVersion(0)
59 { } 69 , fBasePath(basePath)
70 , fIsFallback(isFallback)
71 { };
60 72
61 XML_Parser fParser; // The expat parser doing the work , owned by caller 73 XML_Parser fParser; // The expat parser doing the work , owned by caller
62 SkTDArray<FontFamily*>& fFamilies; // The array to append families, o wned by caller 74 SkTDArray<FontFamily*>& fFamilies; // The array to append families, o wned by caller
63 SkAutoTDelete<FontFamily> fCurrentFamily; // The family being created, owned by this 75 SkAutoTDelete<FontFamily> fCurrentFamily; // The family being created, owned by this
64 FontFileInfo* fCurrentFontInfo; // The fontInfo being created, own ed by currentFamily 76 FontFileInfo* fCurrentFontInfo; // The fontInfo being created, own ed by fCurrentFamily
65 int fCurrentTag; // Flag to indicate when we're in nameset/fileset tags 77 CurrentTag fCurrentTag; // The kind of tag currently being parsed.
66 int fVersion; // The version of the file parsed. 78 int fVersion; // The version of the file parsed.
79 const SkString& fBasePath; // The current base path.
80 const bool fIsFallback; // Indicates the file being parsed is a fallback file
67 }; 81 };
68 82
69 /** http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-nega tive-def */ 83 /** Parses a null terminated string into an integer type, checking for overflow.
84 * http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-nega tive-def
85 *
86 * If the string cannot be parsed into 'value', returns false and does not chan ge 'value'.
87 */
70 template <typename T> static bool parse_non_negative_integer(const char* s, T* v alue) { 88 template <typename T> static bool parse_non_negative_integer(const char* s, T* v alue) {
71 SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer); 89 SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer);
72 const T nMax = std::numeric_limits<T>::max() / 10; 90 const T nMax = std::numeric_limits<T>::max() / 10;
73 const T dMax = std::numeric_limits<T>::max() - (nMax * 10); 91 const T dMax = std::numeric_limits<T>::max() - (nMax * 10);
74 T n = 0; 92 T n = 0;
75 for (; *s; ++s) { 93 for (; *s; ++s) {
76 // Check if digit 94 // Check if digit
77 if (*s < '0' || '9' < *s) { 95 if (*s < '0' || '9' < *s) {
78 return false; 96 return false;
79 } 97 }
80 int d = *s - '0'; 98 int d = *s - '0';
81 // Check for overflow 99 // Check for overflow
82 if (n > nMax || (n == nMax && d > dMax)) { 100 if (n > nMax || (n == nMax && d > dMax)) {
83 return false; 101 return false;
84 } 102 }
85 n = (n * 10) + d; 103 n = (n * 10) + d;
86 } 104 }
87 *value = n; 105 *value = n;
88 return true; 106 return true;
89 } 107 }
90 108
109 static bool memeq(const char* s1, const char* s2, size_t n1, size_t n2) {
110 return n1 == n2 && 0 == memcmp(s1, s2, n1);
111 }
112 #define MEMEQ(c, s, n) memeq(c, s, sizeof(c) - 1, n)
113
114 #define ATTS_NON_NULL(a, i) (a[i] != NULL && a[i+1] != NULL)
115
91 namespace lmpParser { 116 namespace lmpParser {
92 117
93 void familyElementHandler(FontFamily* family, const char** attributes) { 118 void familyElementHandler(FontFamily* family, const char** attributes) {
94 // A non-fallback <family> tag must have a canonical name attribute. 119 // A non-fallback <family> tag must have a canonical name attribute.
95 // A fallback <family> tag has no name, and may have lang and variant 120 // A fallback <family> tag has no name, and may have lang and variant
96 // attributes. 121 // attributes.
97 family->fIsFallbackFont = true; 122 family->fIsFallbackFont = true;
98 for (size_t i = 0; attributes[i] != NULL && 123 for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
99 attributes[i+1] != NULL; i += 2) {
100 const char* name = attributes[i]; 124 const char* name = attributes[i];
101 const char* value = attributes[i+1]; 125 const char* value = attributes[i+1];
102 size_t nameLen = strlen(name); 126 size_t nameLen = strlen(name);
103 size_t valueLen = strlen(value); 127 size_t valueLen = strlen(value);
104 if (nameLen == 4 && !strncmp("name", name, nameLen)) { 128 if (MEMEQ("name", name, nameLen)) {
105 SkAutoAsciiToLC tolc(value); 129 SkAutoAsciiToLC tolc(value);
106 family->fNames.push_back().set(tolc.lc()); 130 family->fNames.push_back().set(tolc.lc());
107 family->fIsFallbackFont = false; 131 family->fIsFallbackFont = false;
108 } else if (nameLen == 4 && !strncmp("lang", name, nameLen)) { 132 } else if (MEMEQ("lang", name, nameLen)) {
109 family->fLanguage = SkLanguage (value); 133 family->fLanguage = SkLanguage(value, valueLen);
110 } else if (nameLen == 7 && !strncmp("variant", name, nameLen)) { 134 } else if (MEMEQ("variant", name, nameLen)) {
111 // Value should be either elegant or compact. 135 // Value should be either elegant or compact.
112 if (valueLen == 7 && !strncmp("elegant", value, valueLen)) { 136 if (MEMEQ("elegant", value, valueLen)) {
113 family->fVariant = kElegant_FontVariant; 137 family->fVariant = kElegant_FontVariant;
114 } else if (valueLen == 7 && !strncmp("compact", value, valueLen)) { 138 } else if (MEMEQ("compact", value, valueLen)) {
115 family->fVariant = kCompact_FontVariant; 139 family->fVariant = kCompact_FontVariant;
116 } 140 }
117 } 141 }
118 } 142 }
119 } 143 }
120 144
121 void fontFileNameHandler(void* data, const char* s, int len) { 145 void XMLCALL fontFileNameHandler(void* data, const char* s, int len) {
122 FamilyData* familyData = (FamilyData*) data; 146 FamilyData* self = static_cast<FamilyData*>(data);
123 familyData->fCurrentFontInfo->fFileName.set(s, len); 147 self->fCurrentFontInfo->fFileName.append(s, len);
124 } 148 }
125 149
126 void fontElementHandler(XML_Parser parser, FontFileInfo* file, const char** attr ibutes) { 150 void fontElementHandler(FamilyData* self, FontFileInfo* file, const char** attri butes) {
127 // A <font> should have weight (integer) and style (normal, italic) attribut es. 151 // A <font> should have weight (integer) and style (normal, italic) attribut es.
128 // NOTE: we ignore the style. 152 // NOTE: we ignore the style.
129 // The element should contain a filename. 153 // The element should contain a filename.
130 for (size_t i = 0; attributes[i] != NULL && 154 for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
131 attributes[i+1] != NULL; i += 2) {
132 const char* name = attributes[i]; 155 const char* name = attributes[i];
133 const char* value = attributes[i+1]; 156 const char* value = attributes[i+1];
134 size_t nameLen = strlen(name); 157 size_t nameLen = strlen(name);
135 if (nameLen == 6 && !strncmp("weight", name, nameLen)) { 158 if (MEMEQ("weight", name, nameLen)) {
136 if (!parse_non_negative_integer(value, &file->fWeight)) { 159 if (!parse_non_negative_integer(value, &file->fWeight)) {
137 SkDebugf("---- Font weight %s (INVALID)", value); 160 SkDebugf("---- Font weight %s (INVALID)", value);
138 file->fWeight = 0;
139 } 161 }
140 } 162 }
141 } 163 }
142 XML_SetCharacterDataHandler(parser, fontFileNameHandler); 164 XML_SetCharacterDataHandler(self->fParser, fontFileNameHandler);
143 } 165 }
144 166
145 FontFamily* findFamily(FamilyData* familyData, const char* familyName) { 167 FontFamily* findFamily(FamilyData* self, const SkString& familyName) {
146 size_t nameLen = strlen(familyName); 168 for (int i = 0; i < self->fFamilies.count(); i++) {
147 for (int i = 0; i < familyData->fFamilies.count(); i++) { 169 FontFamily* candidate = self->fFamilies[i];
148 FontFamily* candidate = familyData->fFamilies[i];
149 for (int j = 0; j < candidate->fNames.count(); j++) { 170 for (int j = 0; j < candidate->fNames.count(); j++) {
150 if (!strncmp(candidate->fNames[j].c_str(), familyName, nameLen) && 171 if (candidate->fNames[j] == familyName) {
151 nameLen == strlen(candidate->fNames[j].c_str())) {
152 return candidate; 172 return candidate;
153 } 173 }
154 } 174 }
155 } 175 }
156
157 return NULL; 176 return NULL;
158 } 177 }
159 178
160 void aliasElementHandler(FamilyData* familyData, const char** attributes) { 179 void aliasElementHandler(FamilyData* self, const char** attributes) {
161 // An <alias> must have name and to attributes. 180 // An <alias> must have name and to attributes.
162 // It may have weight (integer). 181 // It may have weight (integer).
163 // If it *does not* have a weight, it is a variant name for a <family>. 182 // If it *does not* have a weight, it is a variant name for a <family>.
164 // If it *does* have a weight, it names the <font>(s) of a specific weight 183 // If it *does* have a weight, it names the <font>(s) of a specific weight
165 // from a <family>. 184 // from a <family>.
166 185
167 SkString aliasName; 186 SkString aliasName;
168 SkString to; 187 SkString to;
169 int weight = 0; 188 int weight = 0;
170 for (size_t i = 0; attributes[i] != NULL && 189 for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
171 attributes[i+1] != NULL; i += 2) {
172 const char* name = attributes[i]; 190 const char* name = attributes[i];
173 const char* value = attributes[i+1]; 191 const char* value = attributes[i+1];
174 size_t nameLen = strlen(name); 192 size_t nameLen = strlen(name);
175 if (nameLen == 4 && !strncmp("name", name, nameLen)) { 193 if (MEMEQ("name", name, nameLen)) {
176 SkAutoAsciiToLC tolc(value); 194 SkAutoAsciiToLC tolc(value);
177 aliasName.set(tolc.lc()); 195 aliasName.set(tolc.lc());
178 } else if (nameLen == 2 && !strncmp("to", name, nameLen)) { 196 } else if (MEMEQ("to", name, nameLen)) {
179 to.set(value); 197 to.set(value);
180 } else if (nameLen == 6 && !strncmp("weight", name, nameLen)) { 198 } else if (MEMEQ("weight", name, nameLen)) {
181 parse_non_negative_integer(value, &weight); 199 if (!parse_non_negative_integer(value, &weight)) {
200 SkDebugf("---- Font weight %s (INVALID)", value);
201 }
182 } 202 }
183 } 203 }
184 204
185 // Assumes that the named family is already declared 205 // Assumes that the named family is already declared
186 FontFamily* targetFamily = findFamily(familyData, to.c_str()); 206 FontFamily* targetFamily = findFamily(self, to);
187 if (!targetFamily) { 207 if (!targetFamily) {
188 SkDebugf("---- Font alias target %s (NOT FOUND)", to.c_str()); 208 SkDebugf("---- Font alias target %s (NOT FOUND)", to.c_str());
189 return; 209 return;
190 } 210 }
191 211
192 if (weight) { 212 if (weight) {
193 FontFamily* family = new FontFamily(); 213 FontFamily* family = new FontFamily(targetFamily->fBasePath, self->fIsFa llback);
194 family->fNames.push_back().set(aliasName); 214 family->fNames.push_back().set(aliasName);
195 215
196 for (int i = 0; i < targetFamily->fFonts.count(); i++) { 216 for (int i = 0; i < targetFamily->fFonts.count(); i++) {
197 if (targetFamily->fFonts[i].fWeight == weight) { 217 if (targetFamily->fFonts[i].fWeight == weight) {
198 family->fFonts.push_back(targetFamily->fFonts[i]); 218 family->fFonts.push_back(targetFamily->fFonts[i]);
199 } 219 }
200 } 220 }
201 *familyData->fFamilies.append() = family; 221 *self->fFamilies.append() = family;
202 } else { 222 } else {
203 targetFamily->fNames.push_back().set(aliasName); 223 targetFamily->fNames.push_back().set(aliasName);
204 } 224 }
205 } 225 }
206 226
207 void startElementHandler(void* data, const char* tag, const char** attributes) { 227 void XMLCALL startElementHandler(void* data, const char* tag, const char** attri butes) {
208 FamilyData* familyData = (FamilyData*) data; 228 FamilyData* self = static_cast<FamilyData*>(data);
209 size_t len = strlen(tag); 229 size_t len = strlen(tag);
210 if (len == 6 && !strncmp(tag, "family", len)) { 230 if (MEMEQ("family", tag, len)) {
211 familyData->fCurrentFamily.reset(new FontFamily()); 231 self->fCurrentFamily.reset(new FontFamily(self->fBasePath, self->fIsFall back));
212 familyElementHandler(familyData->fCurrentFamily, attributes); 232 familyElementHandler(self->fCurrentFamily, attributes);
213 } else if (len == 4 && !strncmp(tag, "font", len)) { 233 } else if (MEMEQ("font", tag, len)) {
214 FontFileInfo* file = &familyData->fCurrentFamily->fFonts.push_back(); 234 FontFileInfo* file = &self->fCurrentFamily->fFonts.push_back();
215 familyData->fCurrentFontInfo = file; 235 self->fCurrentFontInfo = file;
216 fontElementHandler(familyData->fParser, file, attributes); 236 fontElementHandler(self, file, attributes);
217 } else if (len == 5 && !strncmp(tag, "alias", len)) { 237 } else if (MEMEQ("alias", tag, len)) {
218 aliasElementHandler(familyData, attributes); 238 aliasElementHandler(self, attributes);
219 } 239 }
220 } 240 }
221 241
222 void endElementHandler(void* data, const char* tag) { 242 void XMLCALL endElementHandler(void* data, const char* tag) {
223 FamilyData* familyData = (FamilyData*) data; 243 FamilyData* self = static_cast<FamilyData*>(data);
224 size_t len = strlen(tag); 244 size_t len = strlen(tag);
225 if (len == 6 && strncmp(tag, "family", len) == 0) { 245 if (MEMEQ("family", tag, len)) {
226 *familyData->fFamilies.append() = familyData->fCurrentFamily.detach(); 246 *self->fFamilies.append() = self->fCurrentFamily.detach();
227 } else if (len == 4 && !strncmp(tag, "font", len)) { 247 } else if (MEMEQ("font", tag, len)) {
228 XML_SetCharacterDataHandler(familyData->fParser, NULL); 248 XML_SetCharacterDataHandler(self->fParser, NULL);
229 } 249 }
230 } 250 }
231 251
232 } // lmpParser 252 } // lmpParser
233 253
234 namespace jbParser { 254 namespace jbParser {
235 255
236 /** 256 /**
237 * Handler for arbitrary text. This is used to parse the text inside each name 257 * Handler for arbitrary text. This is used to parse the text inside each name
238 * or file tag. The resulting strings are put into the fNames or FontFileInfo ar rays. 258 * or file tag. The resulting strings are put into the fNames or FontFileInfo ar rays.
239 */ 259 */
240 static void text_handler(void* data, const char* s, int len) { 260 static void XMLCALL text_handler(void* data, const char* s, int len) {
241 FamilyData* familyData = (FamilyData*) data; 261 FamilyData* self = static_cast<FamilyData*>(data);
242 // Make sure we're in the right state to store this name information 262 // Make sure we're in the right state to store this name information
243 if (familyData->fCurrentFamily.get() && 263 if (self->fCurrentFamily.get()) {
244 (familyData->fCurrentTag == NAMESET_TAG || familyData->fCurrentTag = = FILESET_TAG)) { 264 switch (self->fCurrentTag) {
245 switch (familyData->fCurrentTag) { 265 case kNameSet_CurrentTag: {
246 case NAMESET_TAG: {
247 SkAutoAsciiToLC tolc(s, len); 266 SkAutoAsciiToLC tolc(s, len);
248 familyData->fCurrentFamily->fNames.push_back().set(tolc.lc(), len); 267 self->fCurrentFamily->fNames.back().append(tolc.lc(), len);
249 break; 268 break;
250 } 269 }
251 case FILESET_TAG: 270 case kFileSet_CurrentTag:
252 if (familyData->fCurrentFontInfo) { 271 if (self->fCurrentFontInfo) {
253 familyData->fCurrentFontInfo->fFileName.set(s, len); 272 self->fCurrentFontInfo->fFileName.append(s, len);
254 } 273 }
255 break; 274 break;
256 default: 275 default:
257 // Noop - don't care about any text that's not in the Fonts or Names list 276 // Noop - don't care about any text that's not in the Fonts or Names list
258 break; 277 break;
259 } 278 }
260 } 279 }
261 } 280 }
262 281
263 /** 282 /**
264 * Handler for font files. This processes the attributes for language and 283 * Handler for font files. This processes the attributes for language and
265 * variants then lets textHandler handle the actual file name 284 * variants then lets textHandler handle the actual file name
266 */ 285 */
267 static void font_file_element_handler(FamilyData* familyData, const char** attri butes) { 286 static void font_file_element_handler(FamilyData* self, const char** attributes) {
268 FontFileInfo& newFileInfo = familyData->fCurrentFamily->fFonts.push_back(); 287 FontFamily& currentFamily = *self->fCurrentFamily.get();
288 FontFileInfo& newFileInfo = currentFamily.fFonts.push_back();
269 if (attributes) { 289 if (attributes) {
270 size_t currentAttributeIndex = 0; 290 for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
271 while (attributes[currentAttributeIndex] && 291 const char* attributeName = attributes[i];
272 attributes[currentAttributeIndex + 1]) { 292 const char* attributeValue = attributes[i+1];
273 const char* attributeName = attributes[currentAttributeIndex];
274 const char* attributeValue = attributes[currentAttributeIndex+1];
275 size_t nameLength = strlen(attributeName); 293 size_t nameLength = strlen(attributeName);
276 size_t valueLength = strlen(attributeValue); 294 size_t valueLength = strlen(attributeValue);
277 if (nameLength == 7 && strncmp(attributeName, "variant", nameLength) == 0) { 295 if (MEMEQ("variant", attributeName, nameLength)) {
278 const FontVariant prevVariant = familyData->fCurrentFamily->fVar iant; 296 const FontVariant prevVariant = currentFamily.fVariant;
279 if (valueLength == 7 && strncmp(attributeValue, "elegant", value Length) == 0) { 297 if (MEMEQ("elegant", attributeValue, valueLength)) {
280 familyData->fCurrentFamily->fVariant = kElegant_FontVariant; 298 currentFamily.fVariant = kElegant_FontVariant;
281 } else if (valueLength == 7 && 299 } else if (MEMEQ("compact", attributeValue, valueLength)) {
282 strncmp(attributeValue, "compact", valueLength) == 0) { 300 currentFamily.fVariant = kCompact_FontVariant;
283 familyData->fCurrentFamily->fVariant = kCompact_FontVariant;
284 } 301 }
285 if (familyData->fCurrentFamily->fFonts.count() > 1 && 302 if (currentFamily.fFonts.count() > 1 && currentFamily.fVariant ! = prevVariant) {
286 familyData->fCurrentFamily->fVariant != prevVariant) {
287 SkDebugf("Every font file within a family must have identica l variants"); 303 SkDebugf("Every font file within a family must have identica l variants");
288 sk_throw();
289 } 304 }
290 305
291 } else if (nameLength == 4 && strncmp(attributeName, "lang", nameLen gth) == 0) { 306 } else if (MEMEQ("lang", attributeName, nameLength)) {
292 SkLanguage prevLang = familyData->fCurrentFamily->fLanguage; 307 SkLanguage prevLang = currentFamily.fLanguage;
293 familyData->fCurrentFamily->fLanguage = SkLanguage(attributeValu e); 308 currentFamily.fLanguage = SkLanguage(attributeValue, valueLength );
294 if (familyData->fCurrentFamily->fFonts.count() > 1 && 309 if (currentFamily.fFonts.count() > 1 && currentFamily.fLanguage != prevLang) {
295 familyData->fCurrentFamily->fLanguage != prevLang) {
296 SkDebugf("Every font file within a family must have identica l languages"); 310 SkDebugf("Every font file within a family must have identica l languages");
297 sk_throw();
298 } 311 }
299 } else if (nameLength == 5 && strncmp(attributeName, "index", nameLe ngth) == 0) { 312
300 int value; 313 } else if (MEMEQ("index", attributeName, nameLength)) {
301 if (parse_non_negative_integer(attributeValue, &value)) { 314 if (!parse_non_negative_integer(attributeValue, &newFileInfo.fIn dex)) {
302 newFileInfo.fIndex = value;
303 } else {
304 SkDebugf("---- SystemFonts index=%s (INVALID)", attributeVal ue); 315 SkDebugf("---- SystemFonts index=%s (INVALID)", attributeVal ue);
305 } 316 }
306 } 317 }
307 //each element is a pair of attributeName/attributeValue string pair s
308 currentAttributeIndex += 2;
309 } 318 }
310 } 319 }
311 familyData->fCurrentFontInfo = &newFileInfo; 320 self->fCurrentFontInfo = &newFileInfo;
312 XML_SetCharacterDataHandler(familyData->fParser, text_handler); 321 XML_SetCharacterDataHandler(self->fParser, text_handler);
313 } 322 }
314 323
315 /** 324 /**
316 * Handler for the start of a tag. The only tags we expect are familyset, family , 325 * Handler for the start of a tag. The only tags we expect are familyset, family ,
317 * nameset, fileset, name, and file. 326 * nameset, fileset, name, and file.
318 */ 327 */
319 static void start_element_handler(void* data, const char* tag, const char** atts ) { 328 static void XMLCALL start_element_handler(void* data, const char* tag, const cha r** attributes) {
320 FamilyData* familyData = (FamilyData*) data; 329 FamilyData* self = static_cast<FamilyData*>(data);
321 size_t len = strlen(tag); 330 size_t len = strlen(tag);
322 if (len == 9 && strncmp(tag, "familyset", len) == 0) { 331 if (MEMEQ("familyset", tag, len)) {
323 // The familyset tag has an optional "version" attribute with an integer value >= 0 332 // The familyset tag has an optional "version" attribute with an integer value >= 0
324 for (size_t i = 0; atts[i] != NULL && 333 for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
325 atts[i+1] != NULL; i += 2) { 334 size_t nameLen = strlen(attributes[i]);
326 size_t nameLen = strlen(atts[i]); 335 if (!MEMEQ("version", attributes[i], nameLen)) continue;
327 if (nameLen == 7 && strncmp(atts[i], "version", nameLen)) continue; 336 const char* valueString = attributes[i+1];
328 const char* valueString = atts[i+1];
329 int version; 337 int version;
330 if (parse_non_negative_integer(valueString, &version) && (version >= 21)) { 338 if (parse_non_negative_integer(valueString, &version) && (version >= 21)) {
331 XML_SetElementHandler(familyData->fParser, 339 XML_SetElementHandler(self->fParser,
332 lmpParser::startElementHandler, 340 lmpParser::startElementHandler,
333 lmpParser::endElementHandler); 341 lmpParser::endElementHandler);
334 familyData->fVersion = version; 342 self->fVersion = version;
335 } 343 }
336 } 344 }
337 } else if (len == 6 && strncmp(tag, "family", len) == 0) { 345 } else if (MEMEQ("family", tag, len)) {
338 familyData->fCurrentFamily.reset(new FontFamily()); 346 self->fCurrentFamily.reset(new FontFamily(self->fBasePath, self->fIsFall back));
339 // The Family tag has an optional "order" attribute with an integer valu e >= 0 347 // The Family tag has an optional "order" attribute with an integer valu e >= 0
340 // If this attribute does not exist, the default value is -1 348 // If this attribute does not exist, the default value is -1
341 for (size_t i = 0; atts[i] != NULL && 349 for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
342 atts[i+1] != NULL; i += 2) { 350 const char* valueString = attributes[i+1];
343 const char* valueString = atts[i+1];
344 int value; 351 int value;
345 if (parse_non_negative_integer(valueString, &value)) { 352 if (parse_non_negative_integer(valueString, &value)) {
346 familyData->fCurrentFamily->fOrder = value; 353 self->fCurrentFamily->fOrder = value;
347 } 354 }
348 } 355 }
349 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) { 356 } else if (MEMEQ("nameset", tag, len)) {
350 familyData->fCurrentTag = NAMESET_TAG; 357 self->fCurrentTag = kNameSet_CurrentTag;
351 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { 358 } else if (MEMEQ("fileset", tag, len)) {
352 familyData->fCurrentTag = FILESET_TAG; 359 self->fCurrentTag = kFileSet_CurrentTag;
353 } else if (len == 4 && strncmp(tag, "name", len) == 0 && familyData->fCurren tTag == NAMESET_TAG) { 360 } else if (MEMEQ("name", tag, len) && self->fCurrentTag == kNameSet_CurrentT ag) {
354 // If it's a Name, parse the text inside 361 // If it's a Name, parse the text inside
355 XML_SetCharacterDataHandler(familyData->fParser, text_handler); 362 self->fCurrentFamily->fNames.push_back();
356 } else if (len == 4 && strncmp(tag, "file", len) == 0 && familyData->fCurren tTag == FILESET_TAG) { 363 XML_SetCharacterDataHandler(self->fParser, text_handler);
364 } else if (MEMEQ("file", tag, len) && self->fCurrentTag == kFileSet_CurrentT ag) {
357 // If it's a file, parse the attributes, then parse the text inside 365 // If it's a file, parse the attributes, then parse the text inside
358 font_file_element_handler(familyData, atts); 366 font_file_element_handler(self, attributes);
359 } 367 }
360 } 368 }
361 369
362 /** 370 /**
363 * Handler for the end of tags. We only care about family, nameset, fileset, 371 * Handler for the end of tags. We only care about family, nameset, fileset,
364 * name, and file. 372 * name, and file.
365 */ 373 */
366 static void end_element_handler(void* data, const char* tag) { 374 static void XMLCALL end_element_handler(void* data, const char* tag) {
367 FamilyData* familyData = (FamilyData*) data; 375 FamilyData* self = static_cast<FamilyData*>(data);
368 size_t len = strlen(tag); 376 size_t len = strlen(tag);
369 if (len == 6 && strncmp(tag, "family", len)== 0) { 377 if (MEMEQ("family", tag, len)) {
370 // Done parsing a Family - store the created currentFamily in the famili es array 378 // Done parsing a Family - store the created currentFamily in the famili es array
371 *familyData->fFamilies.append() = familyData->fCurrentFamily.detach(); 379 *self->fFamilies.append() = self->fCurrentFamily.detach();
372 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) { 380 } else if (MEMEQ("nameset", tag, len)) {
373 familyData->fCurrentTag = NO_TAG; 381 self->fCurrentTag = kNo_CurrentTag;
374 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { 382 } else if (MEMEQ("fileset", tag, len)) {
375 familyData->fCurrentTag = NO_TAG; 383 self->fCurrentTag = kNo_CurrentTag;
376 } else if ((len == 4 && 384 } else if ((MEMEQ("name", tag, len) && self->fCurrentTag == kNameSet_Current Tag) ||
377 strncmp(tag, "name", len) == 0 && 385 (MEMEQ("file", tag, len) && self->fCurrentTag == kFileSet_Current Tag)) {
378 familyData->fCurrentTag == NAMESET_TAG) ||
379 (len == 4 &&
380 strncmp(tag, "file", len) == 0 &&
381 familyData->fCurrentTag == FILESET_TAG)) {
382 // Disable the arbitrary text handler installed to load Name data 386 // Disable the arbitrary text handler installed to load Name data
383 XML_SetCharacterDataHandler(familyData->fParser, NULL); 387 XML_SetCharacterDataHandler(self->fParser, NULL);
384 } 388 }
385 } 389 }
386 390
387 } // namespace jbParser 391 } // namespace jbParser
388 392
393 static void XMLCALL xml_entity_decl_handler(void *data,
394 const XML_Char *entityName,
395 int is_parameter_entity,
396 const XML_Char *value,
397 int value_length,
398 const XML_Char *base,
399 const XML_Char *systemId,
400 const XML_Char *publicId,
401 const XML_Char *notationName)
402 {
403 FamilyData* self = static_cast<FamilyData*>(data);
404 SkDebugf("Entity declaration %s found, stopping processing.", entityName);
405 XML_StopParser(self->fParser, XML_FALSE);
406 }
407
408 template<typename T> struct remove_ptr {typedef T type;};
409 template<typename T> struct remove_ptr<T*> {typedef T type;};
410
389 /** 411 /**
390 * This function parses the given filename and stores the results in the given 412 * This function parses the given filename and stores the results in the given
391 * families array. Returns the version of the file, negative if the file does no t exist. 413 * families array. Returns the version of the file, negative if the file does no t exist.
392 */ 414 */
393 static int parse_config_file(const char* filename, SkTDArray<FontFamily*>& famil ies) { 415 static int parse_config_file(const char* filename, SkTDArray<FontFamily*>& famil ies,
394 416 const SkString& basePath, bool isFallback)
395 FILE* file = fopen(filename, "r"); 417 {
418 SkFILEStream file(filename);
396 419
397 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac k_fonts.xml) 420 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac k_fonts.xml)
398 // are optional - failure here is okay because one of these optional files m ay not exist. 421 // are optional - failure here is okay because one of these optional files m ay not exist.
399 if (NULL == file) { 422 if (!file.isValid()) {
423 SkDebugf("File %s could not be opened.\n", filename);
400 return -1; 424 return -1;
401 } 425 }
402 426
403 XML_Parser parser = XML_ParserCreate(NULL); 427 SkAutoTCallVProc<remove_ptr<XML_Parser>::type, XML_ParserFree> parser(XML_Pa rserCreate(NULL));
404 FamilyData familyData(parser, families); 428 if (!parser) {
405 XML_SetUserData(parser, &familyData); 429 SkDebugf("Could not create XML parser.\n");
430 return -1;
431 }
432
433 FamilyData self(parser, families, basePath, isFallback);
434 XML_SetUserData(parser, &self);
435
436 // Disable entity processing, to inhibit internal entity expansion. See expa t CVE-2013-0340
437 XML_SetEntityDeclHandler(parser, xml_entity_decl_handler);
438
406 // Start parsing oldschool; switch these in flight if we detect a newer vers ion of the file. 439 // Start parsing oldschool; switch these in flight if we detect a newer vers ion of the file.
407 XML_SetElementHandler(parser, jbParser::start_element_handler, jbParser::end _element_handler); 440 XML_SetElementHandler(parser, jbParser::start_element_handler, jbParser::end _element_handler);
408 441
409 char buffer[512]; 442 char buffer[512];
410 bool done = false; 443 bool done = false;
411 while (!done) { 444 while (!done) {
412 fgets(buffer, sizeof(buffer), file); 445 size_t len = file.read(buffer, SK_ARRAY_COUNT(buffer));
413 size_t len = strlen(buffer); 446 done = file.isAtEnd();
414 if (feof(file) != 0) { 447 XML_Status status = XML_Parse(parser, buffer, len, done);
415 done = true; 448 if (XML_STATUS_ERROR == status) {
449 XML_Error error = XML_GetErrorCode(parser);
450 int line = XML_GetCurrentLineNumber(parser);
451 int column = XML_GetCurrentColumnNumber(parser);
452 int index = XML_GetCurrentByteIndex(parser);
453 const XML_LChar* errorString = XML_ErrorString(error);
454 SkDebugf("Line: %d Column: %d (Offset: %d) Error %d: %s.\n",
455 line, column, index, error, errorString);
456 return -1;
416 } 457 }
417 XML_Parse(parser, buffer, len, done);
418 } 458 }
419 XML_ParserFree(parser); 459 return self.fVersion;
420 fclose(file);
421 return familyData.fVersion;
422 } 460 }
423 461
424 /** Returns the version of the system font file actually found, negative if none . */ 462 /** Returns the version of the system font file actually found, negative if none . */
425 static int append_system_font_families(SkTDArray<FontFamily*>& fontFamilies) { 463 static int append_system_font_families(SkTDArray<FontFamily*>& fontFamilies,
464 const SkString& basePath)
465 {
426 int initialCount = fontFamilies.count(); 466 int initialCount = fontFamilies.count();
427 int version = parse_config_file(LMP_SYSTEM_FONTS_FILE, fontFamilies); 467 int version = parse_config_file(LMP_SYSTEM_FONTS_FILE, fontFamilies, basePat h, false);
428 if (version < 0 || fontFamilies.count() == initialCount) { 468 if (version < 0 || fontFamilies.count() == initialCount) {
429 version = parse_config_file(OLD_SYSTEM_FONTS_FILE, fontFamilies); 469 version = parse_config_file(OLD_SYSTEM_FONTS_FILE, fontFamilies, basePat h, false);
430 } 470 }
431 return version; 471 return version;
432 } 472 }
433 473
434 /** 474 /**
435 * In some versions of Android prior to Android 4.2 (JellyBean MR1 at API 475 * In some versions of Android prior to Android 4.2 (JellyBean MR1 at API
436 * Level 17) the fallback fonts for certain locales were encoded in their own 476 * Level 17) the fallback fonts for certain locales were encoded in their own
437 * XML files with a suffix that identified the locale. We search the provided 477 * XML files with a suffix that identified the locale. We search the provided
438 * directory for those files,add all of their entries to the fallback chain, and 478 * directory for those files,add all of their entries to the fallback chain, and
439 * include the locale as part of each entry. 479 * include the locale as part of each entry.
440 */ 480 */
441 static void append_fallback_font_families_for_locale(SkTDArray<FontFamily*>& fal lbackFonts, 481 static void append_fallback_font_families_for_locale(SkTDArray<FontFamily*>& fal lbackFonts,
442 const char* dir) 482 const char* dir,
483 const SkString& basePath)
443 { 484 {
444 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) 485 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
445 // The framework is beyond Android 4.2 and can therefore skip this function 486 // The framework is beyond Android 4.2 and can therefore skip this function
446 return; 487 return;
447 #endif 488 #endif
448 489
449 DIR* fontDirectory = opendir(dir); 490 DIR* fontDirectory = opendir(dir);
450 if (fontDirectory != NULL){ 491 if (fontDirectory != NULL){
451 struct dirent* dirEntry = readdir(fontDirectory); 492 struct dirent* dirEntry = readdir(fontDirectory);
452 while (dirEntry) { 493 while (dirEntry) {
(...skipping 10 matching lines...) Expand all
463 static const size_t fixedLen = strlen(LOCALE_FALLBACK_FONTS_PREF IX) - 504 static const size_t fixedLen = strlen(LOCALE_FALLBACK_FONTS_PREF IX) -
464 strlen(LOCALE_FALLBACK_FONTS_SUFF IX); 505 strlen(LOCALE_FALLBACK_FONTS_SUFF IX);
465 506
466 SkString locale(fileName.c_str() - strlen(LOCALE_FALLBACK_FONTS_ PREFIX), 507 SkString locale(fileName.c_str() - strlen(LOCALE_FALLBACK_FONTS_ PREFIX),
467 fileName.size() - fixedLen); 508 fileName.size() - fixedLen);
468 509
469 SkString absoluteFilename; 510 SkString absoluteFilename;
470 absoluteFilename.printf("%s/%s", dir, fileName.c_str()); 511 absoluteFilename.printf("%s/%s", dir, fileName.c_str());
471 512
472 SkTDArray<FontFamily*> langSpecificFonts; 513 SkTDArray<FontFamily*> langSpecificFonts;
473 parse_config_file(absoluteFilename.c_str(), langSpecificFonts); 514 parse_config_file(absoluteFilename.c_str(), langSpecificFonts, b asePath, true);
474 515
475 for (int i = 0; i < langSpecificFonts.count(); ++i) { 516 for (int i = 0; i < langSpecificFonts.count(); ++i) {
476 FontFamily* family = langSpecificFonts[i]; 517 FontFamily* family = langSpecificFonts[i];
477 family->fLanguage = SkLanguage(locale); 518 family->fLanguage = SkLanguage(locale);
478 *fallbackFonts.append() = family; 519 *fallbackFonts.append() = family;
479 } 520 }
480 } 521 }
481 522
482 // proceed to the next entry in the directory 523 // proceed to the next entry in the directory
483 dirEntry = readdir(fontDirectory); 524 dirEntry = readdir(fontDirectory);
484 } 525 }
485 // cleanup the directory reference 526 // cleanup the directory reference
486 closedir(fontDirectory); 527 closedir(fontDirectory);
487 } 528 }
488 } 529 }
489 530
490 static void append_system_fallback_font_families(SkTDArray<FontFamily*>& fallbac kFonts) { 531 static void append_system_fallback_font_families(SkTDArray<FontFamily*>& fallbac kFonts,
491 parse_config_file(FALLBACK_FONTS_FILE, fallbackFonts); 532 const SkString& basePath)
492 append_fallback_font_families_for_locale(fallbackFonts, LOCALE_FALLBACK_FONT S_SYSTEM_DIR); 533 {
534 parse_config_file(FALLBACK_FONTS_FILE, fallbackFonts, basePath, true);
535 append_fallback_font_families_for_locale(fallbackFonts,
536 LOCALE_FALLBACK_FONTS_SYSTEM_DIR,
537 basePath);
493 } 538 }
494 539
495 static void mixin_vendor_fallback_font_families(SkTDArray<FontFamily*>& fallback Fonts) { 540 static void mixin_vendor_fallback_font_families(SkTDArray<FontFamily*>& fallback Fonts,
541 const SkString& basePath)
542 {
496 SkTDArray<FontFamily*> vendorFonts; 543 SkTDArray<FontFamily*> vendorFonts;
497 parse_config_file(VENDOR_FONTS_FILE, vendorFonts); 544 parse_config_file(VENDOR_FONTS_FILE, vendorFonts, basePath, true);
498 append_fallback_font_families_for_locale(vendorFonts, LOCALE_FALLBACK_FONTS_ VENDOR_DIR); 545 append_fallback_font_families_for_locale(vendorFonts,
546 LOCALE_FALLBACK_FONTS_VENDOR_DIR,
547 basePath);
499 548
500 // This loop inserts the vendor fallback fonts in the correct order in the 549 // This loop inserts the vendor fallback fonts in the correct order in the
501 // overall fallbacks list. 550 // overall fallbacks list.
502 int currentOrder = -1; 551 int currentOrder = -1;
503 for (int i = 0; i < vendorFonts.count(); ++i) { 552 for (int i = 0; i < vendorFonts.count(); ++i) {
504 FontFamily* family = vendorFonts[i]; 553 FontFamily* family = vendorFonts[i];
505 int order = family->fOrder; 554 int order = family->fOrder;
506 if (order < 0) { 555 if (order < 0) {
507 if (currentOrder < 0) { 556 if (currentOrder < 0) {
508 // Default case - just add it to the end of the fallback list 557 // Default case - just add it to the end of the fallback list
509 *fallbackFonts.append() = family; 558 *fallbackFonts.append() = family;
510 } else { 559 } else {
511 // no order specified on this font, but we're incrementing the o rder 560 // no order specified on this font, but we're incrementing the o rder
512 // based on an earlier order insertion request 561 // based on an earlier order insertion request
513 *fallbackFonts.insert(currentOrder++) = family; 562 *fallbackFonts.insert(currentOrder++) = family;
514 } 563 }
515 } else { 564 } else {
516 // Add the font into the fallback list in the specified order. Set 565 // Add the font into the fallback list in the specified order. Set
517 // currentOrder for correct placement of other fonts in the vendor l ist. 566 // currentOrder for correct placement of other fonts in the vendor l ist.
518 *fallbackFonts.insert(order) = family; 567 *fallbackFonts.insert(order) = family;
519 currentOrder = order + 1; 568 currentOrder = order + 1;
520 } 569 }
521 } 570 }
522 } 571 }
523 572
524 /** 573 void SkFontConfigParser::GetSystemFontFamilies(SkTDArray<FontFamily*>& fontFamil ies) {
525 * Loads data on font families from various expected configuration files. The
526 * resulting data is returned in the given fontFamilies array.
527 */
528 void SkFontConfigParser::GetFontFamilies(SkTDArray<FontFamily*>& fontFamilies) {
529 // Version 21 of the system font configuration does not need any fallback co nfiguration files. 574 // Version 21 of the system font configuration does not need any fallback co nfiguration files.
530 if (append_system_font_families(fontFamilies) >= 21) { 575 SkString basePath(getenv("ANDROID_ROOT"));
576 basePath.append(SK_FONT_FILE_PREFIX, sizeof(SK_FONT_FILE_PREFIX) - 1);
577
578 if (append_system_font_families(fontFamilies, basePath) >= 21) {
531 return; 579 return;
532 } 580 }
533 581
534 // Append all the fallback fonts to system fonts 582 // Append all the fallback fonts to system fonts
535 SkTDArray<FontFamily*> fallbackFonts; 583 SkTDArray<FontFamily*> fallbackFonts;
536 append_system_fallback_font_families(fallbackFonts); 584 append_system_fallback_font_families(fallbackFonts, basePath);
537 mixin_vendor_fallback_font_families(fallbackFonts); 585 mixin_vendor_fallback_font_families(fallbackFonts, basePath);
538 for (int i = 0; i < fallbackFonts.count(); ++i) { 586 fontFamilies.append(fallbackFonts.count(), fallbackFonts.begin());
539 fallbackFonts[i]->fIsFallbackFont = true; 587 }
540 *fontFamilies.append() = fallbackFonts[i]; 588
589 void SkFontConfigParser::GetCustomFontFamilies(SkTDArray<FontFamily*>& fontFamil ies,
590 const SkString& basePath,
591 const char* fontsXml,
592 const char* fallbackFontsXml)
593 {
594 if (fontsXml) {
595 parse_config_file(fontsXml, fontFamilies, basePath, false);
596 }
597 if (fallbackFontsXml) {
598 parse_config_file(fallbackFontsXml, fontFamilies, basePath, true);
541 } 599 }
542 } 600 }
543 601
544 void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*>& fontFamilie s,
545 const char* testMainConfigFile,
546 const char* testFallbackConfigFile) {
547 parse_config_file(testMainConfigFile, fontFamilies);
548
549 SkTDArray<FontFamily*> fallbackFonts;
550 if (testFallbackConfigFile) {
551 parse_config_file(testFallbackConfigFile, fallbackFonts);
552 }
553
554 // Append all fallback fonts to system fonts
555 for (int i = 0; i < fallbackFonts.count(); ++i) {
556 fallbackFonts[i]->fIsFallbackFont = true;
557 *fontFamilies.append() = fallbackFonts[i];
558 }
559 }
560
561 SkLanguage SkLanguage::getParent() const { 602 SkLanguage SkLanguage::getParent() const {
562 SkASSERT(!fTag.isEmpty()); 603 SkASSERT(!fTag.isEmpty());
563 const char* tag = fTag.c_str(); 604 const char* tag = fTag.c_str();
564 605
565 // strip off the rightmost "-.*" 606 // strip off the rightmost "-.*"
566 const char* parentTagEnd = strrchr(tag, '-'); 607 const char* parentTagEnd = strrchr(tag, '-');
567 if (parentTagEnd == NULL) { 608 if (parentTagEnd == NULL) {
568 return SkLanguage(); 609 return SkLanguage();
569 } 610 }
570 size_t parentTagLen = parentTagEnd - tag; 611 size_t parentTagLen = parentTagEnd - tag;
571 return SkLanguage(tag, parentTagLen); 612 return SkLanguage(tag, parentTagLen);
572 } 613 }
OLDNEW
« no previous file with comments | « src/ports/SkFontConfigParser_android.h ('k') | src/ports/SkFontMgr_android.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698