gfx/skia/trunk/src/ports/SkFontConfigParser_android.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /*
michael@0 2 * Copyright 2011 The Android Open Source Project
michael@0 3 *
michael@0 4 * Use of this source code is governed by a BSD-style license that can be
michael@0 5 * found in the LICENSE file.
michael@0 6 */
michael@0 7
michael@0 8 #include "SkFontConfigParser_android.h"
michael@0 9 #include "SkTDArray.h"
michael@0 10 #include "SkTypeface.h"
michael@0 11
michael@0 12 #include <expat.h>
michael@0 13 #include <stdio.h>
michael@0 14 #include <sys/system_properties.h>
michael@0 15
michael@0 16 #define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml"
michael@0 17 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml"
michael@0 18 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml"
michael@0 19
michael@0 20 // These defines are used to determine the kind of tag that we're currently
michael@0 21 // populating with data. We only care about the sibling tags nameset and fileset
michael@0 22 // for now.
michael@0 23 #define NO_TAG 0
michael@0 24 #define NAMESET_TAG 1
michael@0 25 #define FILESET_TAG 2
michael@0 26
michael@0 27 /**
michael@0 28 * The FamilyData structure is passed around by the parser so that each handler
michael@0 29 * can read these variables that are relevant to the current parsing.
michael@0 30 */
michael@0 31 struct FamilyData {
michael@0 32 FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef) :
michael@0 33 parser(parserRef),
michael@0 34 families(familiesRef),
michael@0 35 currentFamily(NULL),
michael@0 36 currentFontInfo(NULL),
michael@0 37 currentTag(NO_TAG) {};
michael@0 38
michael@0 39 XML_Parser *parser; // The expat parser doing the work
michael@0 40 SkTDArray<FontFamily*> &families; // The array that each family is put into as it is parsed
michael@0 41 FontFamily *currentFamily; // The current family being created
michael@0 42 FontFileInfo *currentFontInfo; // The current fontInfo being created
michael@0 43 int currentTag; // A flag to indicate whether we're in nameset/fileset tags
michael@0 44 };
michael@0 45
michael@0 46 /**
michael@0 47 * Handler for arbitrary text. This is used to parse the text inside each name
michael@0 48 * or file tag. The resulting strings are put into the fNames or FontFileInfo arrays.
michael@0 49 */
michael@0 50 static void textHandler(void *data, const char *s, int len) {
michael@0 51 FamilyData *familyData = (FamilyData*) data;
michael@0 52 // Make sure we're in the right state to store this name information
michael@0 53 if (familyData->currentFamily &&
michael@0 54 (familyData->currentTag == NAMESET_TAG || familyData->currentTag == FILESET_TAG)) {
michael@0 55 // Malloc new buffer to store the string
michael@0 56 char *buff;
michael@0 57 buff = (char*) malloc((len + 1) * sizeof(char));
michael@0 58 strncpy(buff, s, len);
michael@0 59 buff[len] = '\0';
michael@0 60 switch (familyData->currentTag) {
michael@0 61 case NAMESET_TAG:
michael@0 62 *(familyData->currentFamily->fNames.append()) = buff;
michael@0 63 break;
michael@0 64 case FILESET_TAG:
michael@0 65 if (familyData->currentFontInfo) {
michael@0 66 familyData->currentFontInfo->fFileName = buff;
michael@0 67 }
michael@0 68 break;
michael@0 69 default:
michael@0 70 // Noop - don't care about any text that's not in the Fonts or Names list
michael@0 71 break;
michael@0 72 }
michael@0 73 }
michael@0 74 }
michael@0 75
michael@0 76 /**
michael@0 77 * Handler for font files. This processes the attributes for language and
michael@0 78 * variants then lets textHandler handle the actual file name
michael@0 79 */
michael@0 80 static void fontFileElementHandler(FamilyData *familyData, const char **attributes) {
michael@0 81 FontFileInfo* newFileInfo = new FontFileInfo();
michael@0 82 if (attributes) {
michael@0 83 int currentAttributeIndex = 0;
michael@0 84 while (attributes[currentAttributeIndex]) {
michael@0 85 const char* attributeName = attributes[currentAttributeIndex];
michael@0 86 const char* attributeValue = attributes[currentAttributeIndex+1];
michael@0 87 int nameLength = strlen(attributeName);
michael@0 88 int valueLength = strlen(attributeValue);
michael@0 89 if (strncmp(attributeName, "variant", nameLength) == 0) {
michael@0 90 if (strncmp(attributeValue, "elegant", valueLength) == 0) {
michael@0 91 newFileInfo->fPaintOptions.setFontVariant(SkPaintOptionsAndroid::kElegant_Variant);
michael@0 92 } else if (strncmp(attributeValue, "compact", valueLength) == 0) {
michael@0 93 newFileInfo->fPaintOptions.setFontVariant(SkPaintOptionsAndroid::kCompact_Variant);
michael@0 94 }
michael@0 95 } else if (strncmp(attributeName, "lang", nameLength) == 0) {
michael@0 96 newFileInfo->fPaintOptions.setLanguage(attributeValue);
michael@0 97 }
michael@0 98 //each element is a pair of attributeName/attributeValue string pairs
michael@0 99 currentAttributeIndex += 2;
michael@0 100 }
michael@0 101 }
michael@0 102 *(familyData->currentFamily->fFontFiles.append()) = newFileInfo;
michael@0 103 familyData->currentFontInfo = newFileInfo;
michael@0 104 XML_SetCharacterDataHandler(*familyData->parser, textHandler);
michael@0 105 }
michael@0 106
michael@0 107 /**
michael@0 108 * Handler for the start of a tag. The only tags we expect are family, nameset,
michael@0 109 * fileset, name, and file.
michael@0 110 */
michael@0 111 static void startElementHandler(void *data, const char *tag, const char **atts) {
michael@0 112 FamilyData *familyData = (FamilyData*) data;
michael@0 113 int len = strlen(tag);
michael@0 114 if (strncmp(tag, "family", len)== 0) {
michael@0 115 familyData->currentFamily = new FontFamily();
michael@0 116 familyData->currentFamily->order = -1;
michael@0 117 // The Family tag has an optional "order" attribute with an integer value >= 0
michael@0 118 // If this attribute does not exist, the default value is -1
michael@0 119 for (int i = 0; atts[i] != NULL; i += 2) {
michael@0 120 const char* valueString = atts[i+1];
michael@0 121 int value;
michael@0 122 int len = sscanf(valueString, "%d", &value);
michael@0 123 if (len > 0) {
michael@0 124 familyData->currentFamily->order = value;
michael@0 125 }
michael@0 126 }
michael@0 127 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) {
michael@0 128 familyData->currentTag = NAMESET_TAG;
michael@0 129 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
michael@0 130 familyData->currentTag = FILESET_TAG;
michael@0 131 } else if (strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) {
michael@0 132 // If it's a Name, parse the text inside
michael@0 133 XML_SetCharacterDataHandler(*familyData->parser, textHandler);
michael@0 134 } else if (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG) {
michael@0 135 // If it's a file, parse the attributes, then parse the text inside
michael@0 136 fontFileElementHandler(familyData, atts);
michael@0 137 }
michael@0 138 }
michael@0 139
michael@0 140 /**
michael@0 141 * Handler for the end of tags. We only care about family, nameset, fileset,
michael@0 142 * name, and file.
michael@0 143 */
michael@0 144 static void endElementHandler(void *data, const char *tag) {
michael@0 145 FamilyData *familyData = (FamilyData*) data;
michael@0 146 int len = strlen(tag);
michael@0 147 if (strncmp(tag, "family", len)== 0) {
michael@0 148 // Done parsing a Family - store the created currentFamily in the families array
michael@0 149 *familyData->families.append() = familyData->currentFamily;
michael@0 150 familyData->currentFamily = NULL;
michael@0 151 } else if (len == 7 && strncmp(tag, "nameset", len) == 0) {
michael@0 152 familyData->currentTag = NO_TAG;
michael@0 153 } else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
michael@0 154 familyData->currentTag = NO_TAG;
michael@0 155 } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) ||
michael@0 156 (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG)) {
michael@0 157 // Disable the arbitrary text handler installed to load Name data
michael@0 158 XML_SetCharacterDataHandler(*familyData->parser, NULL);
michael@0 159 }
michael@0 160 }
michael@0 161
michael@0 162 /**
michael@0 163 * This function parses the given filename and stores the results in the given
michael@0 164 * families array.
michael@0 165 */
michael@0 166 static void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) {
michael@0 167
michael@0 168 FILE* file = NULL;
michael@0 169
michael@0 170 #if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
michael@0 171 // if we are using a version of Android prior to Android 4.2 (JellyBean MR1
michael@0 172 // at API Level 17) then we need to look for files with a different suffix.
michael@0 173 char sdkVersion[PROP_VALUE_MAX];
michael@0 174 __system_property_get("ro.build.version.sdk", sdkVersion);
michael@0 175 const int sdkVersionInt = atoi(sdkVersion);
michael@0 176
michael@0 177 if (0 != *sdkVersion && sdkVersionInt < 17) {
michael@0 178 SkString basename;
michael@0 179 SkString updatedFilename;
michael@0 180 SkString locale = SkFontConfigParser::GetLocale();
michael@0 181
michael@0 182 basename.set(filename);
michael@0 183 // Remove the .xml suffix. We'll add it back in a moment.
michael@0 184 if (basename.endsWith(".xml")) {
michael@0 185 basename.resize(basename.size()-4);
michael@0 186 }
michael@0 187 // Try first with language and region
michael@0 188 updatedFilename.printf("%s-%s.xml", basename.c_str(), locale.c_str());
michael@0 189 file = fopen(updatedFilename.c_str(), "r");
michael@0 190 if (!file) {
michael@0 191 // If not found, try next with just language
michael@0 192 updatedFilename.printf("%s-%.2s.xml", basename.c_str(), locale.c_str());
michael@0 193 file = fopen(updatedFilename.c_str(), "r");
michael@0 194 }
michael@0 195 }
michael@0 196 #endif
michael@0 197
michael@0 198 if (NULL == file) {
michael@0 199 file = fopen(filename, "r");
michael@0 200 }
michael@0 201
michael@0 202 // Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml)
michael@0 203 // are optional - failure here is okay because one of these optional files may not exist.
michael@0 204 if (NULL == file) {
michael@0 205 return;
michael@0 206 }
michael@0 207
michael@0 208 XML_Parser parser = XML_ParserCreate(NULL);
michael@0 209 FamilyData *familyData = new FamilyData(&parser, families);
michael@0 210 XML_SetUserData(parser, familyData);
michael@0 211 XML_SetElementHandler(parser, startElementHandler, endElementHandler);
michael@0 212
michael@0 213 char buffer[512];
michael@0 214 bool done = false;
michael@0 215 while (!done) {
michael@0 216 fgets(buffer, sizeof(buffer), file);
michael@0 217 int len = strlen(buffer);
michael@0 218 if (feof(file) != 0) {
michael@0 219 done = true;
michael@0 220 }
michael@0 221 XML_Parse(parser, buffer, len, done);
michael@0 222 }
michael@0 223 XML_ParserFree(parser);
michael@0 224 fclose(file);
michael@0 225 }
michael@0 226
michael@0 227 static void getSystemFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
michael@0 228 parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies);
michael@0 229 }
michael@0 230
michael@0 231 static void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts) {
michael@0 232 SkTDArray<FontFamily*> vendorFonts;
michael@0 233 parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts);
michael@0 234 parseConfigFile(VENDOR_FONTS_FILE, vendorFonts);
michael@0 235
michael@0 236 // This loop inserts the vendor fallback fonts in the correct order in the
michael@0 237 // overall fallbacks list.
michael@0 238 int currentOrder = -1;
michael@0 239 for (int i = 0; i < vendorFonts.count(); ++i) {
michael@0 240 FontFamily* family = vendorFonts[i];
michael@0 241 int order = family->order;
michael@0 242 if (order < 0) {
michael@0 243 if (currentOrder < 0) {
michael@0 244 // Default case - just add it to the end of the fallback list
michael@0 245 *fallbackFonts.append() = family;
michael@0 246 } else {
michael@0 247 // no order specified on this font, but we're incrementing the order
michael@0 248 // based on an earlier order insertion request
michael@0 249 *fallbackFonts.insert(currentOrder++) = family;
michael@0 250 }
michael@0 251 } else {
michael@0 252 // Add the font into the fallback list in the specified order. Set
michael@0 253 // currentOrder for correct placement of other fonts in the vendor list.
michael@0 254 *fallbackFonts.insert(order) = family;
michael@0 255 currentOrder = order + 1;
michael@0 256 }
michael@0 257 }
michael@0 258 }
michael@0 259
michael@0 260 /**
michael@0 261 * Loads data on font families from various expected configuration files. The
michael@0 262 * resulting data is returned in the given fontFamilies array.
michael@0 263 */
michael@0 264 void SkFontConfigParser::GetFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
michael@0 265
michael@0 266 getSystemFontFamilies(fontFamilies);
michael@0 267
michael@0 268 // Append all the fallback fonts to system fonts
michael@0 269 SkTDArray<FontFamily*> fallbackFonts;
michael@0 270 getFallbackFontFamilies(fallbackFonts);
michael@0 271 for (int i = 0; i < fallbackFonts.count(); ++i) {
michael@0 272 fallbackFonts[i]->fIsFallbackFont = true;
michael@0 273 *fontFamilies.append() = fallbackFonts[i];
michael@0 274 }
michael@0 275 }
michael@0 276
michael@0 277 void SkFontConfigParser::GetTestFontFamilies(SkTDArray<FontFamily*> &fontFamilies,
michael@0 278 const char* testMainConfigFile,
michael@0 279 const char* testFallbackConfigFile) {
michael@0 280 parseConfigFile(testMainConfigFile, fontFamilies);
michael@0 281
michael@0 282 SkTDArray<FontFamily*> fallbackFonts;
michael@0 283 parseConfigFile(testFallbackConfigFile, fallbackFonts);
michael@0 284
michael@0 285 // Append all fallback fonts to system fonts
michael@0 286 for (int i = 0; i < fallbackFonts.count(); ++i) {
michael@0 287 fallbackFonts[i]->fIsFallbackFont = true;
michael@0 288 *fontFamilies.append() = fallbackFonts[i];
michael@0 289 }
michael@0 290 }
michael@0 291
michael@0 292 /**
michael@0 293 * Read the persistent locale.
michael@0 294 */
michael@0 295 SkString SkFontConfigParser::GetLocale()
michael@0 296 {
michael@0 297 char propLang[PROP_VALUE_MAX], propRegn[PROP_VALUE_MAX];
michael@0 298 __system_property_get("persist.sys.language", propLang);
michael@0 299 __system_property_get("persist.sys.country", propRegn);
michael@0 300
michael@0 301 if (*propLang == 0 && *propRegn == 0) {
michael@0 302 /* Set to ro properties, default is en_US */
michael@0 303 __system_property_get("ro.product.locale.language", propLang);
michael@0 304 __system_property_get("ro.product.locale.region", propRegn);
michael@0 305 if (*propLang == 0 && *propRegn == 0) {
michael@0 306 strcpy(propLang, "en");
michael@0 307 strcpy(propRegn, "US");
michael@0 308 }
michael@0 309 }
michael@0 310
michael@0 311 SkString locale(6);
michael@0 312 char* localeCStr = locale.writable_str();
michael@0 313
michael@0 314 strncpy(localeCStr, propLang, 2);
michael@0 315 localeCStr[2] = '-';
michael@0 316 strncpy(&localeCStr[3], propRegn, 2);
michael@0 317 localeCStr[5] = '\0';
michael@0 318
michael@0 319 return locale;
michael@0 320 }

mercurial