Chromium Code Reviews| 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 <stdio.h> | 14 #include <stdio.h> |
| 15 #include <sys/system_properties.h> | 15 #include <sys/system_properties.h> |
| 16 | 16 |
| 17 #include <limits> | 17 #include <limits> |
| 18 | 18 |
| 19 #define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" | 19 #define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml" |
| 20 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" | 20 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml" |
| 21 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" | 21 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml" |
| 22 | 22 |
| 23 /** | |
| 24 * This file contains TWO parsers: one for JB and earlier (system_fonts.xml / | |
| 25 * fallback_fonts.xml), one for LMP and later (fonts.xml). | |
| 26 * We start with the JB parser, and if we detect a <familyset> tag with | |
| 27 * version 21 or higher we switch to the LMP parser. | |
| 28 */ | |
| 29 | |
| 23 // These defines are used to determine the kind of tag that we're currently | 30 // These defines are used to determine the kind of tag that we're currently |
| 24 // populating with data. We only care about the sibling tags nameset and fileset | 31 // populating with data. We only care about the sibling tags nameset and fileset |
| 25 // for now. | 32 // for now. |
| 26 #define NO_TAG 0 | 33 #define NO_TAG 0 |
| 27 #define NAMESET_TAG 1 | 34 #define NAMESET_TAG 1 |
| 28 #define FILESET_TAG 2 | 35 #define FILESET_TAG 2 |
| 29 | 36 |
| 30 /** | 37 /** |
| 31 * The FamilyData structure is passed around by the parser so that each handler | 38 * The FamilyData structure is passed around by the parser so that each handler |
| 32 * can read these variables that are relevant to the current parsing. | 39 * can read these variables that are relevant to the current parsing. |
| 33 */ | 40 */ |
| 34 struct FamilyData { | 41 struct FamilyData { |
| 35 FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef) : | 42 FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef) : |
| 36 parser(parserRef), | 43 parser(parserRef), |
| 37 families(familiesRef), | 44 families(familiesRef), |
| 38 currentFamily(NULL), | 45 currentFamily(NULL), |
| 39 currentFontInfo(NULL), | 46 currentFontInfo(NULL), |
| 40 currentTag(NO_TAG) {}; | 47 currentTag(NO_TAG) {}; |
| 41 | 48 |
| 42 XML_Parser *parser; // The expat parser doing the work | 49 XML_Parser *parser; // The expat parser doing the work |
| 43 SkTDArray<FontFamily*> &families; // The array that each family is put into as it is parsed | 50 SkTDArray<FontFamily*> &families; // The array that each family is put into as it is parsed |
| 44 FontFamily *currentFamily; // The current family being created | 51 FontFamily *currentFamily; // The current family being created |
| 45 FontFileInfo *currentFontInfo; // The current fontInfo being created | 52 FontFileInfo *currentFontInfo; // The current fontInfo being created |
| 46 int currentTag; // A flag to indicate whether we're in na meset/fileset tags | 53 int currentTag; // A flag to indicate whether we're in na meset/fileset tags |
| 47 }; | 54 }; |
| 48 | 55 |
| 56 /** http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-nega tive-def */ | |
| 57 template <typename T> static bool parseNonNegativeInteger(const char* s, T* valu e) { | |
| 58 SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer); | |
| 59 const T nMax = std::numeric_limits<T>::max() / 10; | |
| 60 const T dMax = std::numeric_limits<T>::max() - (nMax * 10); | |
| 61 T n = 0; | |
| 62 for (; *s; ++s) { | |
| 63 // Check if digit | |
| 64 if (*s < '0' || '9' < *s) { | |
| 65 return false; | |
| 66 } | |
| 67 int d = *s - '0'; | |
| 68 // Check for overflow | |
| 69 if (n > nMax || (n == nMax && d > dMax)) { | |
| 70 return false; | |
| 71 } | |
| 72 n = (n * 10) + d; | |
| 73 } | |
| 74 *value = n; | |
| 75 return true; | |
| 76 } | |
| 77 | |
| 78 namespace lmpParser { | |
| 79 | |
| 80 void startElementHandler(void* data, const char* tag, | |
| 81 const char** attributes) { | |
| 82 //SkDebugf("lmp started %s", tag); | |
| 83 } | |
| 84 | |
| 85 void endElementHandler(void* data, const char* tag) { | |
| 86 | |
| 87 //SkDebugf("lmp ended %s", tag); | |
| 88 | |
| 89 } | |
| 90 | |
| 91 } // lmpParser | |
| 92 | |
| 93 namespace jbParser { | |
| 94 | |
| 49 /** | 95 /** |
| 50 * Handler for arbitrary text. This is used to parse the text inside each name | 96 * Handler for arbitrary text. This is used to parse the text inside each name |
| 51 * or file tag. The resulting strings are put into the fNames or FontFileInfo ar rays. | 97 * or file tag. The resulting strings are put into the fNames or FontFileInfo ar rays. |
| 52 */ | 98 */ |
| 53 static void textHandler(void *data, const char *s, int len) { | 99 static void textHandler(void *data, const char *s, int len) { |
| 54 FamilyData *familyData = (FamilyData*) data; | 100 FamilyData *familyData = (FamilyData*) data; |
| 55 // Make sure we're in the right state to store this name information | 101 // Make sure we're in the right state to store this name information |
| 56 if (familyData->currentFamily && | 102 if (familyData->currentFamily && |
| 57 (familyData->currentTag == NAMESET_TAG || familyData->currentTag == FILESET_TAG)) { | 103 (familyData->currentTag == NAMESET_TAG || familyData->currentTag == FILESET_TAG)) { |
| 58 switch (familyData->currentTag) { | 104 switch (familyData->currentTag) { |
| 59 case NAMESET_TAG: { | 105 case NAMESET_TAG: { |
| 60 SkAutoAsciiToLC tolc(s, len); | 106 SkAutoAsciiToLC tolc(s, len); |
| 61 familyData->currentFamily->fNames.push_back().set(tolc.lc(), len); | 107 familyData->currentFamily->fNames.push_back().set(tolc.lc(), len); |
| 62 break; | 108 break; |
| 63 } | 109 } |
| 64 case FILESET_TAG: | 110 case FILESET_TAG: |
| 65 if (familyData->currentFontInfo) { | 111 if (familyData->currentFontInfo) { |
| 66 familyData->currentFontInfo->fFileName.set(s, len); | 112 familyData->currentFontInfo->fFileName.set(s, len); |
| 67 } | 113 } |
| 68 break; | 114 break; |
| 69 default: | 115 default: |
| 70 // Noop - don't care about any text that's not in the Fonts or Names list | 116 // Noop - don't care about any text that's not in the Fonts or Names list |
| 71 break; | 117 break; |
| 72 } | 118 } |
| 73 } | 119 } |
| 74 } | 120 } |
| 75 | 121 |
| 76 /** http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-nega tive-def */ | |
| 77 template <typename T> static bool parseNonNegativeInteger(const char* s, T* valu e) { | |
| 78 SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer); | |
| 79 const T nMax = std::numeric_limits<T>::max() / 10; | |
| 80 const T dMax = std::numeric_limits<T>::max() - (nMax * 10); | |
| 81 T n = 0; | |
| 82 for (; *s; ++s) { | |
| 83 // Check if digit | |
| 84 if (*s < '0' || '9' < *s) { | |
| 85 return false; | |
| 86 } | |
| 87 int d = *s - '0'; | |
| 88 // Check for overflow | |
| 89 if (n > nMax || (n == nMax && d > dMax)) { | |
| 90 return false; | |
| 91 } | |
| 92 n = (n * 10) + d; | |
| 93 } | |
| 94 *value = n; | |
| 95 return true; | |
| 96 } | |
| 97 | |
| 98 /** | 122 /** |
| 99 * Handler for font files. This processes the attributes for language and | 123 * Handler for font files. This processes the attributes for language and |
| 100 * variants then lets textHandler handle the actual file name | 124 * variants then lets textHandler handle the actual file name |
| 101 */ | 125 */ |
| 102 static void fontFileElementHandler(FamilyData *familyData, const char **attribut es) { | 126 static void fontFileElementHandler(FamilyData *familyData, const char **attribut es) { |
| 103 | |
| 104 FontFileInfo& newFileInfo = familyData->currentFamily->fFontFiles.push_back( ); | 127 FontFileInfo& newFileInfo = familyData->currentFamily->fFontFiles.push_back( ); |
| 105 if (attributes) { | 128 if (attributes) { |
| 106 int currentAttributeIndex = 0; | 129 int currentAttributeIndex = 0; |
| 107 while (attributes[currentAttributeIndex]) { | 130 while (attributes[currentAttributeIndex]) { |
| 108 const char* attributeName = attributes[currentAttributeIndex]; | 131 const char* attributeName = attributes[currentAttributeIndex]; |
| 109 const char* attributeValue = attributes[currentAttributeIndex+1]; | 132 const char* attributeValue = attributes[currentAttributeIndex+1]; |
| 110 int nameLength = strlen(attributeName); | 133 int nameLength = strlen(attributeName); |
| 111 int valueLength = strlen(attributeValue); | 134 int valueLength = strlen(attributeValue); |
| 112 if (strncmp(attributeName, "variant", nameLength) == 0) { | 135 if (nameLength == 7 && strncmp(attributeName, "variant", nameLength) == 0) { |
| 113 if (strncmp(attributeValue, "elegant", valueLength) == 0) { | 136 if (valueLength == 7 && strncmp(attributeValue, "elegant", value Length) == 0) { |
| 114 newFileInfo.fPaintOptions.setFontVariant(SkPaintOptionsAndro id::kElegant_Variant); | 137 newFileInfo.fPaintOptions.setFontVariant(SkPaintOptionsAndro id::kElegant_Variant); |
| 115 } else if (strncmp(attributeValue, "compact", valueLength) == 0) { | 138 } else if (valueLength == 7 && |
| 139 strncmp(attributeValue, "compact", valueLength) == 0) { | |
| 116 newFileInfo.fPaintOptions.setFontVariant(SkPaintOptionsAndro id::kCompact_Variant); | 140 newFileInfo.fPaintOptions.setFontVariant(SkPaintOptionsAndro id::kCompact_Variant); |
| 117 } | 141 } |
| 118 } else if (strncmp(attributeName, "lang", nameLength) == 0) { | 142 } else if (nameLength == 4 && strncmp(attributeName, "lang", nameLen gth) == 0) { |
| 119 newFileInfo.fPaintOptions.setLanguage(attributeValue); | 143 newFileInfo.fPaintOptions.setLanguage(attributeValue); |
| 120 } else if (strncmp(attributeName, "index", nameLength) == 0) { | 144 } else if (nameLength == 5 && strncmp(attributeName, "index", nameLe ngth) == 0) { |
| 121 int value; | 145 int value; |
| 122 if (parseNonNegativeInteger(attributeValue, &value)) { | 146 if (parseNonNegativeInteger(attributeValue, &value)) { |
| 123 newFileInfo.fIndex = value; | 147 newFileInfo.fIndex = value; |
| 124 } else { | 148 } else { |
| 125 SkDebugf("---- SystemFonts index=%s (INVALID)", attributeVal ue); | 149 SkDebugf("---- SystemFonts index=%s (INVALID)", attributeVal ue); |
| 126 } | 150 } |
| 127 } | 151 } |
| 128 //each element is a pair of attributeName/attributeValue string pair s | 152 //each element is a pair of attributeName/attributeValue string pair s |
| 129 currentAttributeIndex += 2; | 153 currentAttributeIndex += 2; |
| 130 } | 154 } |
| 131 } | 155 } |
| 132 familyData->currentFontInfo = &newFileInfo; | 156 familyData->currentFontInfo = &newFileInfo; |
| 133 XML_SetCharacterDataHandler(*familyData->parser, textHandler); | 157 XML_SetCharacterDataHandler(*familyData->parser, textHandler); |
| 134 } | 158 } |
| 135 | 159 |
| 136 /** | 160 /** |
| 137 * Handler for the start of a tag. The only tags we expect are family, nameset, | 161 * Handler for the start of a tag. The only tags we expect are familyset, family , |
| 138 * fileset, name, and file. | 162 * nameset, fileset, name, and file. |
| 139 */ | 163 */ |
| 140 static void startElementHandler(void *data, const char *tag, const char **atts) { | 164 static void startElementHandler(void *data, const char *tag, const char **atts) { |
| 141 FamilyData *familyData = (FamilyData*) data; | 165 FamilyData *familyData = (FamilyData*) data; |
| 142 int len = strlen(tag); | 166 int len = strlen(tag); |
| 143 if (strncmp(tag, "family", len)== 0) { | 167 if (len == 9 && strncmp(tag, "familyset", len) == 0) { |
| 168 // The familyset tag has an optional "version" attribute with an integer value >= 0 | |
| 169 for (int i = 0; atts[i] != NULL; i += 2) { | |
| 170 int nameLen = strlen(atts[i]); | |
| 171 if (nameLen == 7 && strncmp(atts[i], "version", nameLen)) continue; | |
| 172 const char* valueString = atts[i+1]; | |
| 173 int version; | |
| 174 bool success = parseNonNegativeInteger(valueString, &version); | |
| 175 if (success && version >= 21) { | |
|
bungeman-skia
2014/08/04 21:27:55
nit: I think there's enough room here for
if (par
| |
| 176 XML_SetElementHandler(*familyData->parser, | |
| 177 lmpParser::startElementHandler, | |
| 178 lmpParser::endElementHandler); | |
| 179 } | |
| 180 } | |
| 181 } else if (len == 6 && strncmp(tag, "family", len) == 0) { | |
| 144 familyData->currentFamily = new FontFamily(); | 182 familyData->currentFamily = new FontFamily(); |
| 145 familyData->currentFamily->order = -1; | 183 familyData->currentFamily->order = -1; |
| 146 // The Family tag has an optional "order" attribute with an integer valu e >= 0 | 184 // The Family tag has an optional "order" attribute with an integer valu e >= 0 |
| 147 // If this attribute does not exist, the default value is -1 | 185 // If this attribute does not exist, the default value is -1 |
| 148 for (int i = 0; atts[i] != NULL; i += 2) { | 186 for (int i = 0; atts[i] != NULL; i += 2) { |
| 149 const char* valueString = atts[i+1]; | 187 const char* valueString = atts[i+1]; |
| 150 int value; | 188 int value; |
| 151 int len = sscanf(valueString, "%d", &value); | 189 if (parseNonNegativeInteger(valueString, &value)) { |
| 152 if (len > 0) { | |
| 153 familyData->currentFamily->order = value; | 190 familyData->currentFamily->order = value; |
| 154 } | 191 } |
| 155 } | 192 } |
| 156 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) { | 193 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) { |
| 157 familyData->currentTag = NAMESET_TAG; | 194 familyData->currentTag = NAMESET_TAG; |
| 158 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { | 195 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { |
| 159 familyData->currentTag = FILESET_TAG; | 196 familyData->currentTag = FILESET_TAG; |
| 160 } else if (strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMES ET_TAG) { | 197 } else if (len == 4 && strncmp(tag, "name", len) == 0 && familyData->current Tag == NAMESET_TAG) { |
| 161 // If it's a Name, parse the text inside | 198 // If it's a Name, parse the text inside |
| 162 XML_SetCharacterDataHandler(*familyData->parser, textHandler); | 199 XML_SetCharacterDataHandler(*familyData->parser, textHandler); |
| 163 } else if (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILES ET_TAG) { | 200 } else if (len == 4 && strncmp(tag, "file", len) == 0 && familyData->current Tag == FILESET_TAG) { |
| 164 // If it's a file, parse the attributes, then parse the text inside | 201 // If it's a file, parse the attributes, then parse the text inside |
| 165 fontFileElementHandler(familyData, atts); | 202 fontFileElementHandler(familyData, atts); |
| 166 } | 203 } |
| 167 } | 204 } |
| 168 | 205 |
| 169 /** | 206 /** |
| 170 * Handler for the end of tags. We only care about family, nameset, fileset, | 207 * Handler for the end of tags. We only care about family, nameset, fileset, |
| 171 * name, and file. | 208 * name, and file. |
| 172 */ | 209 */ |
| 173 static void endElementHandler(void *data, const char *tag) { | 210 static void endElementHandler(void *data, const char *tag) { |
| 174 FamilyData *familyData = (FamilyData*) data; | 211 FamilyData *familyData = (FamilyData*) data; |
| 175 int len = strlen(tag); | 212 int len = strlen(tag); |
| 176 if (strncmp(tag, "family", len)== 0) { | 213 if (len == 6 && strncmp(tag, "family", len)== 0) { |
| 177 // Done parsing a Family - store the created currentFamily in the famili es array | 214 // Done parsing a Family - store the created currentFamily in the famili es array |
| 178 *familyData->families.append() = familyData->currentFamily; | 215 *familyData->families.append() = familyData->currentFamily; |
| 179 familyData->currentFamily = NULL; | 216 familyData->currentFamily = NULL; |
| 180 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) { | 217 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) { |
| 181 familyData->currentTag = NO_TAG; | 218 familyData->currentTag = NO_TAG; |
| 182 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { | 219 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) { |
| 183 familyData->currentTag = NO_TAG; | 220 familyData->currentTag = NO_TAG; |
| 184 } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAME SET_TAG) || | 221 } else if ((len == 4 && |
| 185 (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET _TAG)) { | 222 strncmp(tag, "name", len) == 0 && |
| 223 familyData->currentTag == NAMESET_TAG) || | |
| 224 (len == 4 && | |
| 225 strncmp(tag, "file", len) == 0 && | |
| 226 familyData->currentTag == FILESET_TAG)) { | |
| 186 // Disable the arbitrary text handler installed to load Name data | 227 // Disable the arbitrary text handler installed to load Name data |
| 187 XML_SetCharacterDataHandler(*familyData->parser, NULL); | 228 XML_SetCharacterDataHandler(*familyData->parser, NULL); |
| 188 } | 229 } |
| 189 } | 230 } |
| 190 | 231 |
| 232 } // namespace jbParser | |
| 233 | |
| 191 /** | 234 /** |
| 192 * This function parses the given filename and stores the results in the given | 235 * This function parses the given filename and stores the results in the given |
| 193 * families array. | 236 * families array. |
| 194 */ | 237 */ |
| 195 static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &famili es) { | 238 static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &famili es) { |
| 196 | 239 |
| 197 FILE* file = NULL; | 240 FILE* file = NULL; |
| 198 | 241 |
| 199 #if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) | 242 #if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) |
| 200 // if we are using a version of Android prior to Android 4.2 (JellyBean MR1 | 243 // if we are using a version of Android prior to Android 4.2 (JellyBean MR1 |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 230 | 273 |
| 231 // Some of the files we attempt to parse (in particular, /vendor/etc/fallbac k_fonts.xml) | 274 // 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. | 275 // are optional - failure here is okay because one of these optional files m ay not exist. |
| 233 if (NULL == file) { | 276 if (NULL == file) { |
| 234 return; | 277 return; |
| 235 } | 278 } |
| 236 | 279 |
| 237 XML_Parser parser = XML_ParserCreate(NULL); | 280 XML_Parser parser = XML_ParserCreate(NULL); |
| 238 FamilyData *familyData = new FamilyData(&parser, families); | 281 FamilyData *familyData = new FamilyData(&parser, families); |
| 239 XML_SetUserData(parser, familyData); | 282 XML_SetUserData(parser, familyData); |
| 240 XML_SetElementHandler(parser, startElementHandler, endElementHandler); | 283 // Start parsing oldschool; switch these in flight if we detect a newer vers ion of the file. |
| 284 XML_SetElementHandler(parser, jbParser::startElementHandler, jbParser::endEl ementHandler); | |
| 241 | 285 |
| 242 char buffer[512]; | 286 char buffer[512]; |
| 243 bool done = false; | 287 bool done = false; |
| 244 while (!done) { | 288 while (!done) { |
| 245 fgets(buffer, sizeof(buffer), file); | 289 fgets(buffer, sizeof(buffer), file); |
| 246 int len = strlen(buffer); | 290 int len = strlen(buffer); |
| 247 if (feof(file) != 0) { | 291 if (feof(file) != 0) { |
| 248 done = true; | 292 done = true; |
| 249 } | 293 } |
| 250 XML_Parse(parser, buffer, len, done); | 294 XML_Parse(parser, buffer, len, done); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 302 *fontFamilies.append() = fallbackFonts[i]; | 346 *fontFamilies.append() = fallbackFonts[i]; |
| 303 } | 347 } |
| 304 } | 348 } |
| 305 | 349 |
| 306 void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*> &fontFamilie s, | 350 void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*> &fontFamilie s, |
| 307 const char* testMainConfigFile, | 351 const char* testMainConfigFile, |
| 308 const char* testFallbackConfigFile) { | 352 const char* testFallbackConfigFile) { |
| 309 parseConfigFile(testMainConfigFile, fontFamilies); | 353 parseConfigFile(testMainConfigFile, fontFamilies); |
| 310 | 354 |
| 311 SkTDArray<FontFamily*> fallbackFonts; | 355 SkTDArray<FontFamily*> fallbackFonts; |
| 312 parseConfigFile(testFallbackConfigFile, fallbackFonts); | 356 if (NULL != testFallbackConfigFile) { |
| 357 parseConfigFile(testFallbackConfigFile, fallbackFonts); | |
| 358 } | |
| 313 | 359 |
| 314 // Append all fallback fonts to system fonts | 360 // Append all fallback fonts to system fonts |
| 315 for (int i = 0; i < fallbackFonts.count(); ++i) { | 361 for (int i = 0; i < fallbackFonts.count(); ++i) { |
| 316 fallbackFonts[i]->fIsFallbackFont = true; | 362 fallbackFonts[i]->fIsFallbackFont = true; |
| 317 *fontFamilies.append() = fallbackFonts[i]; | 363 *fontFamilies.append() = fallbackFonts[i]; |
| 318 } | 364 } |
| 319 } | 365 } |
| 320 | 366 |
| 321 /** | 367 /** |
| 322 * Read the persistent locale. | 368 * Read the persistent locale. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 340 SkString locale(6); | 386 SkString locale(6); |
| 341 char* localeCStr = locale.writable_str(); | 387 char* localeCStr = locale.writable_str(); |
| 342 | 388 |
| 343 strncpy(localeCStr, propLang, 2); | 389 strncpy(localeCStr, propLang, 2); |
| 344 localeCStr[2] = '-'; | 390 localeCStr[2] = '-'; |
| 345 strncpy(&localeCStr[3], propRegn, 2); | 391 strncpy(&localeCStr[3], propRegn, 2); |
| 346 localeCStr[5] = '\0'; | 392 localeCStr[5] = '\0'; |
| 347 | 393 |
| 348 return locale; | 394 return locale; |
| 349 } | 395 } |
| OLD | NEW |