| 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 |