OLD | NEW |
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 Loading... |
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 } |
OLD | NEW |