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 "SkTDArray.h" | 9 #include "SkTDArray.h" |
10 #include "SkTSearch.h" | 10 #include "SkTSearch.h" |
11 #include "SkTypeface.h" | 11 #include "SkTypeface.h" |
12 | 12 |
13 #include <expat.h> | 13 #include <expat.h> |
| 14 #include <dirent.h> |
14 #include <stdio.h> | 15 #include <stdio.h> |
15 #include <sys/system_properties.h> | |
16 | 16 |
17 #include <limits> | 17 #include <limits> |
18 | 18 |
19 #define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" | 19 #define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" |
20 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" | 20 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" |
21 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" | 21 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" |
22 | 22 |
| 23 #define LOCALE_FALLBACK_FONTS_DIR "/system/etc" |
| 24 #define LOCALE_FALLBACK_FONTS_PREFIX "fallback_fonts-" |
| 25 #define LOCALE_FALLBACK_FONTS_SUFFIX ".xml" |
| 26 |
23 // These defines are used to determine the kind of tag that we're currently | 27 // These defines are used to determine the kind of tag that we're currently |
24 // populating with data. We only care about the sibling tags nameset and fileset | 28 // populating with data. We only care about the sibling tags nameset and fileset |
25 // for now. | 29 // for now. |
26 #define NO_TAG 0 | 30 #define NO_TAG 0 |
27 #define NAMESET_TAG 1 | 31 #define NAMESET_TAG 1 |
28 #define FILESET_TAG 2 | 32 #define FILESET_TAG 2 |
29 | 33 |
30 /** | 34 /** |
31 * The FamilyData structure is passed around by the parser so that each handler | 35 * The FamilyData structure is passed around by the parser so that each handler |
32 * can read these variables that are relevant to the current parsing. | 36 * can read these variables that are relevant to the current parsing. |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 XML_SetCharacterDataHandler(*familyData->parser, NULL); | 191 XML_SetCharacterDataHandler(*familyData->parser, NULL); |
188 } | 192 } |
189 } | 193 } |
190 | 194 |
191 /** | 195 /** |
192 * This function parses the given filename and stores the results in the given | 196 * This function parses the given filename and stores the results in the given |
193 * families array. | 197 * families array. |
194 */ | 198 */ |
195 static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &famili
es) { | 199 static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &famili
es) { |
196 | 200 |
197 FILE* file = NULL; | 201 FILE* file = fopen(filename, "r"); |
198 | |
199 #if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) | |
200 // if we are using a version of Android prior to Android 4.2 (JellyBean MR1 | |
201 // at API Level 17) then we need to look for files with a different suffix. | |
202 char sdkVersion[PROP_VALUE_MAX]; | |
203 __system_property_get("ro.build.version.sdk", sdkVersion); | |
204 const int sdkVersionInt = atoi(sdkVersion); | |
205 | |
206 if (0 != *sdkVersion && sdkVersionInt < 17) { | |
207 SkString basename; | |
208 SkString updatedFilename; | |
209 SkString locale = SkFontConfigParser::GetLocale(); | |
210 | |
211 basename.set(filename); | |
212 // Remove the .xml suffix. We'll add it back in a moment. | |
213 if (basename.endsWith(".xml")) { | |
214 basename.resize(basename.size()-4); | |
215 } | |
216 // Try first with language and region | |
217 updatedFilename.printf("%s-%s.xml", basename.c_str(), locale.c_str()); | |
218 file = fopen(updatedFilename.c_str(), "r"); | |
219 if (!file) { | |
220 // If not found, try next with just language | |
221 updatedFilename.printf("%s-%.2s.xml", basename.c_str(), locale.c_str
()); | |
222 file = fopen(updatedFilename.c_str(), "r"); | |
223 } | |
224 } | |
225 #endif | |
226 | |
227 if (NULL == file) { | |
228 file = fopen(filename, "r"); | |
229 } | |
230 | 202 |
231 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac
k_fonts.xml) | 203 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac
k_fonts.xml) |
232 // are optional - failure here is okay because one of these optional files m
ay not exist. | 204 // are optional - failure here is okay because one of these optional files m
ay not exist. |
233 if (NULL == file) { | 205 if (NULL == file) { |
234 return; | 206 return; |
235 } | 207 } |
236 | 208 |
237 XML_Parser parser = XML_ParserCreate(NULL); | 209 XML_Parser parser = XML_ParserCreate(NULL); |
238 FamilyData *familyData = new FamilyData(&parser, families); | 210 FamilyData *familyData = new FamilyData(&parser, families); |
239 XML_SetUserData(parser, familyData); | 211 XML_SetUserData(parser, familyData); |
(...skipping 15 matching lines...) Expand all Loading... |
255 | 227 |
256 static void getSystemFontFamilies(SkTDArray<FontFamily*> &fontFamilies) { | 228 static void getSystemFontFamilies(SkTDArray<FontFamily*> &fontFamilies) { |
257 parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies); | 229 parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies); |
258 } | 230 } |
259 | 231 |
260 static void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts) { | 232 static void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts) { |
261 SkTDArray<FontFamily*> vendorFonts; | 233 SkTDArray<FontFamily*> vendorFonts; |
262 parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts); | 234 parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts); |
263 parseConfigFile(VENDOR_FONTS_FILE, vendorFonts); | 235 parseConfigFile(VENDOR_FONTS_FILE, vendorFonts); |
264 | 236 |
| 237 #if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) |
| 238 // In some versions of Android prior to Android 4.2 (JellyBean MR1 at API |
| 239 // Level 17) the fallback fonts for certain locales were encoded in their |
| 240 // own XML files with a suffix that identified the locale. We search the |
| 241 // system for those files and add all of their entries to the fallback chain |
| 242 // including the locale in the entry. |
| 243 |
| 244 DIR* fontDirectory = opendir(LOCALE_FALLBACK_FONTS_DIR); |
| 245 if (fontDirectory != NULL){ |
| 246 struct dirent* dirEntry = readdir(fontDirectory); |
| 247 while (dirEntry) { |
| 248 |
| 249 // The size of both the prefix, suffix, and a minimum valid language
code |
| 250 static const int minSize = strlen(LOCALE_FALLBACK_FONTS_PREFIX) + |
| 251 strlen(LOCALE_FALLBACK_FONTS_SUFFIX) + 2; |
| 252 |
| 253 SkString fileName(dirEntry->d_name); |
| 254 if (fileName.size() >= minSize && |
| 255 fileName.startsWith(LOCALE_FALLBACK_FONTS_PREFIX) && |
| 256 fileName.endsWith(LOCALE_FALLBACK_FONTS_SUFFIX)) { |
| 257 |
| 258 static const int fixedLen = strlen(LOCALE_FALLBACK_FONTS_PREFIX)
- |
| 259 strlen(LOCALE_FALLBACK_FONTS_SUFFIX)
; |
| 260 |
| 261 SkString locale(fileName.c_str() - strlen(LOCALE_FALLBACK_FONTS_
PREFIX), |
| 262 fileName.size() - fixedLen); |
| 263 |
| 264 SkString absoluteFilename; |
| 265 absoluteFilename.printf("%s/%s", LOCALE_FALLBACK_FONTS_DIR, file
Name.c_str()); |
| 266 |
| 267 SkTDArray<FontFamily*> langSpecificFonts; |
| 268 parseConfigFile(absoluteFilename.c_str(), langSpecificFonts); |
| 269 |
| 270 for (int i = 0; i < langSpecificFonts.count(); ++i) { |
| 271 FontFamily* family = langSpecificFonts[i]; |
| 272 for (int j = 0; j < family->fFontFiles.count(); ++j) { |
| 273 family->fFontFiles[j].fPaintOptions.setLanguage(locale); |
| 274 } |
| 275 *fallbackFonts.append() = family; |
| 276 } |
| 277 } |
| 278 |
| 279 // proceed to the next entry in the directory |
| 280 dirEntry = readdir(fontDirectory); |
| 281 } |
| 282 // cleanup the directory reference |
| 283 closedir(fontDirectory); |
| 284 } |
| 285 #endif |
| 286 |
265 // This loop inserts the vendor fallback fonts in the correct order in the | 287 // This loop inserts the vendor fallback fonts in the correct order in the |
266 // overall fallbacks list. | 288 // overall fallbacks list. |
267 int currentOrder = -1; | 289 int currentOrder = -1; |
268 for (int i = 0; i < vendorFonts.count(); ++i) { | 290 for (int i = 0; i < vendorFonts.count(); ++i) { |
269 FontFamily* family = vendorFonts[i]; | 291 FontFamily* family = vendorFonts[i]; |
270 int order = family->order; | 292 int order = family->order; |
271 if (order < 0) { | 293 if (order < 0) { |
272 if (currentOrder < 0) { | 294 if (currentOrder < 0) { |
273 // Default case - just add it to the end of the fallback list | 295 // Default case - just add it to the end of the fallback list |
274 *fallbackFonts.append() = family; | 296 *fallbackFonts.append() = family; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 | 332 |
311 SkTDArray<FontFamily*> fallbackFonts; | 333 SkTDArray<FontFamily*> fallbackFonts; |
312 parseConfigFile(testFallbackConfigFile, fallbackFonts); | 334 parseConfigFile(testFallbackConfigFile, fallbackFonts); |
313 | 335 |
314 // Append all fallback fonts to system fonts | 336 // Append all fallback fonts to system fonts |
315 for (int i = 0; i < fallbackFonts.count(); ++i) { | 337 for (int i = 0; i < fallbackFonts.count(); ++i) { |
316 fallbackFonts[i]->fIsFallbackFont = true; | 338 fallbackFonts[i]->fIsFallbackFont = true; |
317 *fontFamilies.append() = fallbackFonts[i]; | 339 *fontFamilies.append() = fallbackFonts[i]; |
318 } | 340 } |
319 } | 341 } |
320 | |
321 /** | |
322 * Read the persistent locale. | |
323 */ | |
324 SkString SkFontConfigParser::GetLocale() | |
325 { | |
326 char propLang[PROP_VALUE_MAX], propRegn[PROP_VALUE_MAX]; | |
327 __system_property_get("persist.sys.language", propLang); | |
328 __system_property_get("persist.sys.country", propRegn); | |
329 | |
330 if (*propLang == 0 && *propRegn == 0) { | |
331 /* Set to ro properties, default is en_US */ | |
332 __system_property_get("ro.product.locale.language", propLang); | |
333 __system_property_get("ro.product.locale.region", propRegn); | |
334 if (*propLang == 0 && *propRegn == 0) { | |
335 strcpy(propLang, "en"); | |
336 strcpy(propRegn, "US"); | |
337 } | |
338 } | |
339 | |
340 SkString locale(6); | |
341 char* localeCStr = locale.writable_str(); | |
342 | |
343 strncpy(localeCStr, propLang, 2); | |
344 localeCStr[2] = '-'; | |
345 strncpy(&localeCStr[3], propRegn, 2); | |
346 localeCStr[5] = '\0'; | |
347 | |
348 return locale; | |
349 } | |
OLD | NEW |