Sat, 03 Jan 2015 20:18:00 +0100
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 2009 Google Inc. |
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 | /* migrated from chrome/src/skia/ext/SkFontHost_fontconfig_direct.cpp */ |
michael@0 | 9 | |
michael@0 | 10 | #include <string> |
michael@0 | 11 | #include <unistd.h> |
michael@0 | 12 | #include <fcntl.h> |
michael@0 | 13 | |
michael@0 | 14 | #include <fontconfig/fontconfig.h> |
michael@0 | 15 | |
michael@0 | 16 | #include "SkBuffer.h" |
michael@0 | 17 | #include "SkFontConfigInterface.h" |
michael@0 | 18 | #include "SkStream.h" |
michael@0 | 19 | |
michael@0 | 20 | size_t SkFontConfigInterface::FontIdentity::writeToMemory(void* addr) const { |
michael@0 | 21 | size_t size = sizeof(fID) + sizeof(fTTCIndex); |
michael@0 | 22 | size += sizeof(int32_t) + sizeof(int32_t) + sizeof(uint8_t); // weight, width, italic |
michael@0 | 23 | size += sizeof(int32_t) + fString.size(); // store length+data |
michael@0 | 24 | if (addr) { |
michael@0 | 25 | SkWBuffer buffer(addr, size); |
michael@0 | 26 | |
michael@0 | 27 | buffer.write32(fID); |
michael@0 | 28 | buffer.write32(fTTCIndex); |
michael@0 | 29 | buffer.write32(fString.size()); |
michael@0 | 30 | buffer.write32(fStyle.weight()); |
michael@0 | 31 | buffer.write32(fStyle.width()); |
michael@0 | 32 | buffer.write8(fStyle.slant()); |
michael@0 | 33 | buffer.write(fString.c_str(), fString.size()); |
michael@0 | 34 | buffer.padToAlign4(); |
michael@0 | 35 | |
michael@0 | 36 | SkASSERT(buffer.pos() == size); |
michael@0 | 37 | } |
michael@0 | 38 | return size; |
michael@0 | 39 | } |
michael@0 | 40 | |
michael@0 | 41 | size_t SkFontConfigInterface::FontIdentity::readFromMemory(const void* addr, |
michael@0 | 42 | size_t size) { |
michael@0 | 43 | SkRBuffer buffer(addr, size); |
michael@0 | 44 | |
michael@0 | 45 | (void)buffer.readU32(&fID); |
michael@0 | 46 | (void)buffer.readS32(&fTTCIndex); |
michael@0 | 47 | uint32_t strLen, weight, width; |
michael@0 | 48 | (void)buffer.readU32(&strLen); |
michael@0 | 49 | (void)buffer.readU32(&weight); |
michael@0 | 50 | (void)buffer.readU32(&width); |
michael@0 | 51 | uint8_t u8; |
michael@0 | 52 | (void)buffer.readU8(&u8); |
michael@0 | 53 | SkFontStyle::Slant slant = (SkFontStyle::Slant)u8; |
michael@0 | 54 | fStyle = SkFontStyle(weight, width, slant); |
michael@0 | 55 | fString.resize(strLen); |
michael@0 | 56 | (void)buffer.read(fString.writable_str(), strLen); |
michael@0 | 57 | buffer.skipToAlign4(); |
michael@0 | 58 | |
michael@0 | 59 | return buffer.pos(); // the actual number of bytes read |
michael@0 | 60 | } |
michael@0 | 61 | |
michael@0 | 62 | #ifdef SK_DEBUG |
michael@0 | 63 | static void make_iden(SkFontConfigInterface::FontIdentity* iden) { |
michael@0 | 64 | iden->fID = 10; |
michael@0 | 65 | iden->fTTCIndex = 2; |
michael@0 | 66 | iden->fString.set("Hello world"); |
michael@0 | 67 | iden->fStyle = SkFontStyle(300, 6, SkFontStyle::kItalic_Slant); |
michael@0 | 68 | } |
michael@0 | 69 | |
michael@0 | 70 | static void test_writeToMemory(const SkFontConfigInterface::FontIdentity& iden0, |
michael@0 | 71 | int initValue) { |
michael@0 | 72 | SkFontConfigInterface::FontIdentity iden1; |
michael@0 | 73 | |
michael@0 | 74 | size_t size0 = iden0.writeToMemory(NULL); |
michael@0 | 75 | |
michael@0 | 76 | SkAutoMalloc storage(size0); |
michael@0 | 77 | memset(storage.get(), initValue, size0); |
michael@0 | 78 | |
michael@0 | 79 | size_t size1 = iden0.writeToMemory(storage.get()); |
michael@0 | 80 | SkASSERT(size0 == size1); |
michael@0 | 81 | |
michael@0 | 82 | SkASSERT(iden0 != iden1); |
michael@0 | 83 | size_t size2 = iden1.readFromMemory(storage.get(), size1); |
michael@0 | 84 | SkASSERT(size2 == size1); |
michael@0 | 85 | SkASSERT(iden0 == iden1); |
michael@0 | 86 | } |
michael@0 | 87 | |
michael@0 | 88 | static void fontconfiginterface_unittest() { |
michael@0 | 89 | SkFontConfigInterface::FontIdentity iden0, iden1; |
michael@0 | 90 | |
michael@0 | 91 | SkASSERT(iden0 == iden1); |
michael@0 | 92 | |
michael@0 | 93 | make_iden(&iden0); |
michael@0 | 94 | SkASSERT(iden0 != iden1); |
michael@0 | 95 | |
michael@0 | 96 | make_iden(&iden1); |
michael@0 | 97 | SkASSERT(iden0 == iden1); |
michael@0 | 98 | |
michael@0 | 99 | test_writeToMemory(iden0, 0); |
michael@0 | 100 | test_writeToMemory(iden0, 0); |
michael@0 | 101 | } |
michael@0 | 102 | #endif |
michael@0 | 103 | |
michael@0 | 104 | class SkFontConfigInterfaceDirect : public SkFontConfigInterface { |
michael@0 | 105 | public: |
michael@0 | 106 | SkFontConfigInterfaceDirect(); |
michael@0 | 107 | virtual ~SkFontConfigInterfaceDirect(); |
michael@0 | 108 | |
michael@0 | 109 | virtual bool matchFamilyName(const char familyName[], |
michael@0 | 110 | SkTypeface::Style requested, |
michael@0 | 111 | FontIdentity* outFontIdentifier, |
michael@0 | 112 | SkString* outFamilyName, |
michael@0 | 113 | SkTypeface::Style* outStyle) SK_OVERRIDE; |
michael@0 | 114 | virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE; |
michael@0 | 115 | |
michael@0 | 116 | // new APIs |
michael@0 | 117 | virtual SkDataTable* getFamilyNames() SK_OVERRIDE; |
michael@0 | 118 | virtual bool matchFamilySet(const char inFamilyName[], |
michael@0 | 119 | SkString* outFamilyName, |
michael@0 | 120 | SkTArray<FontIdentity>*) SK_OVERRIDE; |
michael@0 | 121 | |
michael@0 | 122 | private: |
michael@0 | 123 | SkMutex mutex_; |
michael@0 | 124 | }; |
michael@0 | 125 | |
michael@0 | 126 | SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() { |
michael@0 | 127 | static SkFontConfigInterface* gDirect; |
michael@0 | 128 | if (NULL == gDirect) { |
michael@0 | 129 | static SkMutex gMutex; |
michael@0 | 130 | SkAutoMutexAcquire ac(gMutex); |
michael@0 | 131 | |
michael@0 | 132 | if (NULL == gDirect) { |
michael@0 | 133 | gDirect = new SkFontConfigInterfaceDirect; |
michael@0 | 134 | } |
michael@0 | 135 | } |
michael@0 | 136 | return gDirect; |
michael@0 | 137 | } |
michael@0 | 138 | |
michael@0 | 139 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 140 | |
michael@0 | 141 | // Returns the string from the pattern, or NULL |
michael@0 | 142 | static const char* get_name(FcPattern* pattern, const char field[], |
michael@0 | 143 | int index = 0) { |
michael@0 | 144 | const char* name; |
michael@0 | 145 | if (FcPatternGetString(pattern, field, index, |
michael@0 | 146 | (FcChar8**)&name) != FcResultMatch) { |
michael@0 | 147 | name = NULL; |
michael@0 | 148 | } |
michael@0 | 149 | return name; |
michael@0 | 150 | } |
michael@0 | 151 | |
michael@0 | 152 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 153 | |
michael@0 | 154 | namespace { |
michael@0 | 155 | |
michael@0 | 156 | // Equivalence classes, used to match the Liberation and other fonts |
michael@0 | 157 | // with their metric-compatible replacements. See the discussion in |
michael@0 | 158 | // GetFontEquivClass(). |
michael@0 | 159 | enum FontEquivClass |
michael@0 | 160 | { |
michael@0 | 161 | OTHER, |
michael@0 | 162 | SANS, |
michael@0 | 163 | SERIF, |
michael@0 | 164 | MONO, |
michael@0 | 165 | SYMBOL, |
michael@0 | 166 | PGOTHIC, |
michael@0 | 167 | GOTHIC, |
michael@0 | 168 | PMINCHO, |
michael@0 | 169 | MINCHO, |
michael@0 | 170 | SIMSUN, |
michael@0 | 171 | NSIMSUN, |
michael@0 | 172 | SIMHEI, |
michael@0 | 173 | PMINGLIU, |
michael@0 | 174 | MINGLIU, |
michael@0 | 175 | PMINGLIUHK, |
michael@0 | 176 | MINGLIUHK, |
michael@0 | 177 | CAMBRIA, |
michael@0 | 178 | CALIBRI, |
michael@0 | 179 | }; |
michael@0 | 180 | |
michael@0 | 181 | // Match the font name against a whilelist of fonts, returning the equivalence |
michael@0 | 182 | // class. |
michael@0 | 183 | FontEquivClass GetFontEquivClass(const char* fontname) |
michael@0 | 184 | { |
michael@0 | 185 | // It would be nice for fontconfig to tell us whether a given suggested |
michael@0 | 186 | // replacement is a "strong" match (that is, an equivalent font) or |
michael@0 | 187 | // a "weak" match (that is, fontconfig's next-best attempt at finding a |
michael@0 | 188 | // substitute). However, I played around with the fontconfig API for |
michael@0 | 189 | // a good few hours and could not make it reveal this information. |
michael@0 | 190 | // |
michael@0 | 191 | // So instead, we hardcode. Initially this function emulated |
michael@0 | 192 | // /etc/fonts/conf.d/30-metric-aliases.conf |
michael@0 | 193 | // from my Ubuntu system, but we're better off being very conservative. |
michael@0 | 194 | |
michael@0 | 195 | // Arimo, Tinos and Cousine are a set of fonts metric-compatible with |
michael@0 | 196 | // Arial, Times New Roman and Courier New with a character repertoire |
michael@0 | 197 | // much larger than Liberation. Note that Cousine is metrically |
michael@0 | 198 | // compatible with Courier New, but the former is sans-serif while |
michael@0 | 199 | // the latter is serif. |
michael@0 | 200 | |
michael@0 | 201 | |
michael@0 | 202 | struct FontEquivMap { |
michael@0 | 203 | FontEquivClass clazz; |
michael@0 | 204 | const char name[40]; |
michael@0 | 205 | }; |
michael@0 | 206 | |
michael@0 | 207 | static const FontEquivMap kFontEquivMap[] = { |
michael@0 | 208 | { SANS, "Arial" }, |
michael@0 | 209 | { SANS, "Arimo" }, |
michael@0 | 210 | { SANS, "Liberation Sans" }, |
michael@0 | 211 | |
michael@0 | 212 | { SERIF, "Times New Roman" }, |
michael@0 | 213 | { SERIF, "Tinos" }, |
michael@0 | 214 | { SERIF, "Liberation Serif" }, |
michael@0 | 215 | |
michael@0 | 216 | { MONO, "Courier New" }, |
michael@0 | 217 | { MONO, "Cousine" }, |
michael@0 | 218 | { MONO, "Liberation Mono" }, |
michael@0 | 219 | |
michael@0 | 220 | { SYMBOL, "Symbol" }, |
michael@0 | 221 | { SYMBOL, "Symbol Neu" }, |
michael@0 | 222 | |
michael@0 | 223 | // MS Pゴシック |
michael@0 | 224 | { PGOTHIC, "MS PGothic" }, |
michael@0 | 225 | { PGOTHIC, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0" |
michael@0 | 226 | "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" }, |
michael@0 | 227 | { PGOTHIC, "IPAPGothic" }, |
michael@0 | 228 | { PGOTHIC, "MotoyaG04Gothic" }, |
michael@0 | 229 | |
michael@0 | 230 | // MS ゴシック |
michael@0 | 231 | { GOTHIC, "MS Gothic" }, |
michael@0 | 232 | { GOTHIC, "\xef\xbc\xad\xef\xbc\xb3 " |
michael@0 | 233 | "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" }, |
michael@0 | 234 | { GOTHIC, "IPAGothic" }, |
michael@0 | 235 | { GOTHIC, "MotoyaG04GothicMono" }, |
michael@0 | 236 | |
michael@0 | 237 | // MS P明朝 |
michael@0 | 238 | { PMINCHO, "MS PMincho" }, |
michael@0 | 239 | { PMINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0" |
michael@0 | 240 | "\xe6\x98\x8e\xe6\x9c\x9d"}, |
michael@0 | 241 | { PMINCHO, "IPAPMincho" }, |
michael@0 | 242 | { PMINCHO, "MotoyaG04Mincho" }, |
michael@0 | 243 | |
michael@0 | 244 | // MS 明朝 |
michael@0 | 245 | { MINCHO, "MS Mincho" }, |
michael@0 | 246 | { MINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xe6\x98\x8e\xe6\x9c\x9d" }, |
michael@0 | 247 | { MINCHO, "IPAMincho" }, |
michael@0 | 248 | { MINCHO, "MotoyaG04MinchoMono" }, |
michael@0 | 249 | |
michael@0 | 250 | // 宋体 |
michael@0 | 251 | { SIMSUN, "Simsun" }, |
michael@0 | 252 | { SIMSUN, "\xe5\xae\x8b\xe4\xbd\x93" }, |
michael@0 | 253 | { SIMSUN, "MSung GB18030" }, |
michael@0 | 254 | { SIMSUN, "Song ASC" }, |
michael@0 | 255 | |
michael@0 | 256 | // 新宋体 |
michael@0 | 257 | { NSIMSUN, "NSimsun" }, |
michael@0 | 258 | { NSIMSUN, "\xe6\x96\xb0\xe5\xae\x8b\xe4\xbd\x93" }, |
michael@0 | 259 | { NSIMSUN, "MSung GB18030" }, |
michael@0 | 260 | { NSIMSUN, "N Song ASC" }, |
michael@0 | 261 | |
michael@0 | 262 | // 黑体 |
michael@0 | 263 | { SIMHEI, "Simhei" }, |
michael@0 | 264 | { SIMHEI, "\xe9\xbb\x91\xe4\xbd\x93" }, |
michael@0 | 265 | { SIMHEI, "MYingHeiGB18030" }, |
michael@0 | 266 | { SIMHEI, "MYingHeiB5HK" }, |
michael@0 | 267 | |
michael@0 | 268 | // 新細明體 |
michael@0 | 269 | { PMINGLIU, "PMingLiU"}, |
michael@0 | 270 | { PMINGLIU, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" }, |
michael@0 | 271 | { PMINGLIU, "MSung B5HK"}, |
michael@0 | 272 | |
michael@0 | 273 | // 細明體 |
michael@0 | 274 | { MINGLIU, "MingLiU"}, |
michael@0 | 275 | { MINGLIU, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" }, |
michael@0 | 276 | { MINGLIU, "MSung B5HK"}, |
michael@0 | 277 | |
michael@0 | 278 | // 新細明體 |
michael@0 | 279 | { PMINGLIUHK, "PMingLiU_HKSCS"}, |
michael@0 | 280 | { PMINGLIUHK, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" }, |
michael@0 | 281 | { PMINGLIUHK, "MSung B5HK"}, |
michael@0 | 282 | |
michael@0 | 283 | // 細明體 |
michael@0 | 284 | { MINGLIUHK, "MingLiU_HKSCS"}, |
michael@0 | 285 | { MINGLIUHK, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" }, |
michael@0 | 286 | { MINGLIUHK, "MSung B5HK"}, |
michael@0 | 287 | |
michael@0 | 288 | // Cambria |
michael@0 | 289 | { CAMBRIA, "Cambria" }, |
michael@0 | 290 | { CAMBRIA, "Caladea" }, |
michael@0 | 291 | |
michael@0 | 292 | // Calibri |
michael@0 | 293 | { CALIBRI, "Calibri" }, |
michael@0 | 294 | { CALIBRI, "Carlito" }, |
michael@0 | 295 | }; |
michael@0 | 296 | |
michael@0 | 297 | static const size_t kFontCount = |
michael@0 | 298 | sizeof(kFontEquivMap)/sizeof(kFontEquivMap[0]); |
michael@0 | 299 | |
michael@0 | 300 | // TODO(jungshik): If this loop turns out to be hot, turn |
michael@0 | 301 | // the array to a static (hash)map to speed it up. |
michael@0 | 302 | for (size_t i = 0; i < kFontCount; ++i) { |
michael@0 | 303 | if (strcasecmp(kFontEquivMap[i].name, fontname) == 0) |
michael@0 | 304 | return kFontEquivMap[i].clazz; |
michael@0 | 305 | } |
michael@0 | 306 | return OTHER; |
michael@0 | 307 | } |
michael@0 | 308 | |
michael@0 | 309 | |
michael@0 | 310 | // Return true if |font_a| and |font_b| are visually and at the metrics |
michael@0 | 311 | // level interchangeable. |
michael@0 | 312 | bool IsMetricCompatibleReplacement(const char* font_a, const char* font_b) |
michael@0 | 313 | { |
michael@0 | 314 | FontEquivClass class_a = GetFontEquivClass(font_a); |
michael@0 | 315 | FontEquivClass class_b = GetFontEquivClass(font_b); |
michael@0 | 316 | |
michael@0 | 317 | return class_a != OTHER && class_a == class_b; |
michael@0 | 318 | } |
michael@0 | 319 | |
michael@0 | 320 | // Normally we only return exactly the font asked for. In last-resort |
michael@0 | 321 | // cases, the request either doesn't specify a font or is one of the |
michael@0 | 322 | // basic font names like "Sans", "Serif" or "Monospace". This function |
michael@0 | 323 | // tells you whether a given request is for such a fallback. |
michael@0 | 324 | bool IsFallbackFontAllowed(const std::string& family) { |
michael@0 | 325 | const char* family_cstr = family.c_str(); |
michael@0 | 326 | return family.empty() || |
michael@0 | 327 | strcasecmp(family_cstr, "sans") == 0 || |
michael@0 | 328 | strcasecmp(family_cstr, "serif") == 0 || |
michael@0 | 329 | strcasecmp(family_cstr, "monospace") == 0; |
michael@0 | 330 | } |
michael@0 | 331 | |
michael@0 | 332 | static bool valid_pattern(FcPattern* pattern) { |
michael@0 | 333 | #ifdef SK_FONT_CONFIG_ONLY_ALLOW_SCALABLE_FONTS |
michael@0 | 334 | FcBool is_scalable; |
michael@0 | 335 | if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch |
michael@0 | 336 | || !is_scalable) { |
michael@0 | 337 | return false; |
michael@0 | 338 | } |
michael@0 | 339 | #endif |
michael@0 | 340 | |
michael@0 | 341 | // fontconfig can also return fonts which are unreadable |
michael@0 | 342 | const char* c_filename = get_name(pattern, FC_FILE); |
michael@0 | 343 | if (!c_filename) { |
michael@0 | 344 | return false; |
michael@0 | 345 | } |
michael@0 | 346 | if (access(c_filename, R_OK) != 0) { |
michael@0 | 347 | return false; |
michael@0 | 348 | } |
michael@0 | 349 | return true; |
michael@0 | 350 | } |
michael@0 | 351 | |
michael@0 | 352 | // Find matching font from |font_set| for the given font family. |
michael@0 | 353 | FcPattern* MatchFont(FcFontSet* font_set, |
michael@0 | 354 | const char* post_config_family, |
michael@0 | 355 | const std::string& family) { |
michael@0 | 356 | // Older versions of fontconfig have a bug where they cannot select |
michael@0 | 357 | // only scalable fonts so we have to manually filter the results. |
michael@0 | 358 | FcPattern* match = NULL; |
michael@0 | 359 | for (int i = 0; i < font_set->nfont; ++i) { |
michael@0 | 360 | FcPattern* current = font_set->fonts[i]; |
michael@0 | 361 | if (valid_pattern(current)) { |
michael@0 | 362 | match = current; |
michael@0 | 363 | break; |
michael@0 | 364 | } |
michael@0 | 365 | } |
michael@0 | 366 | |
michael@0 | 367 | if (match && !IsFallbackFontAllowed(family)) { |
michael@0 | 368 | bool acceptable_substitute = false; |
michael@0 | 369 | for (int id = 0; id < 255; ++id) { |
michael@0 | 370 | const char* post_match_family = get_name(match, FC_FAMILY, id); |
michael@0 | 371 | if (!post_match_family) |
michael@0 | 372 | break; |
michael@0 | 373 | acceptable_substitute = |
michael@0 | 374 | (strcasecmp(post_config_family, post_match_family) == 0 || |
michael@0 | 375 | // Workaround for Issue 12530: |
michael@0 | 376 | // requested family: "Bitstream Vera Sans" |
michael@0 | 377 | // post_config_family: "Arial" |
michael@0 | 378 | // post_match_family: "Bitstream Vera Sans" |
michael@0 | 379 | // -> We should treat this case as a good match. |
michael@0 | 380 | strcasecmp(family.c_str(), post_match_family) == 0) || |
michael@0 | 381 | IsMetricCompatibleReplacement(family.c_str(), post_match_family); |
michael@0 | 382 | if (acceptable_substitute) |
michael@0 | 383 | break; |
michael@0 | 384 | } |
michael@0 | 385 | if (!acceptable_substitute) |
michael@0 | 386 | return NULL; |
michael@0 | 387 | } |
michael@0 | 388 | |
michael@0 | 389 | return match; |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | // Retrieves |is_bold|, |is_italic| and |font_family| properties from |font|. |
michael@0 | 393 | SkTypeface::Style GetFontStyle(FcPattern* font) { |
michael@0 | 394 | int resulting_bold; |
michael@0 | 395 | if (FcPatternGetInteger(font, FC_WEIGHT, 0, &resulting_bold)) |
michael@0 | 396 | resulting_bold = FC_WEIGHT_NORMAL; |
michael@0 | 397 | |
michael@0 | 398 | int resulting_italic; |
michael@0 | 399 | if (FcPatternGetInteger(font, FC_SLANT, 0, &resulting_italic)) |
michael@0 | 400 | resulting_italic = FC_SLANT_ROMAN; |
michael@0 | 401 | |
michael@0 | 402 | // If we ask for an italic font, fontconfig might take a roman font and set |
michael@0 | 403 | // the undocumented property FC_MATRIX to a skew matrix. It'll then say |
michael@0 | 404 | // that the font is italic or oblique. So, if we see a matrix, we don't |
michael@0 | 405 | // believe that it's italic. |
michael@0 | 406 | FcValue matrix; |
michael@0 | 407 | const bool have_matrix = FcPatternGet(font, FC_MATRIX, 0, &matrix) == 0; |
michael@0 | 408 | |
michael@0 | 409 | // If we ask for an italic font, fontconfig might take a roman font and set |
michael@0 | 410 | // FC_EMBOLDEN. |
michael@0 | 411 | FcValue embolden; |
michael@0 | 412 | const bool have_embolden = FcPatternGet(font, FC_EMBOLDEN, 0, &embolden) == 0; |
michael@0 | 413 | |
michael@0 | 414 | int styleBits = 0; |
michael@0 | 415 | if (resulting_bold > FC_WEIGHT_MEDIUM && !have_embolden) { |
michael@0 | 416 | styleBits |= SkTypeface::kBold; |
michael@0 | 417 | } |
michael@0 | 418 | if (resulting_italic > FC_SLANT_ROMAN && !have_matrix) { |
michael@0 | 419 | styleBits |= SkTypeface::kItalic; |
michael@0 | 420 | } |
michael@0 | 421 | |
michael@0 | 422 | return (SkTypeface::Style)styleBits; |
michael@0 | 423 | } |
michael@0 | 424 | |
michael@0 | 425 | } // anonymous namespace |
michael@0 | 426 | |
michael@0 | 427 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 428 | |
michael@0 | 429 | #define kMaxFontFamilyLength 2048 |
michael@0 | 430 | |
michael@0 | 431 | SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() { |
michael@0 | 432 | SkAutoMutexAcquire ac(mutex_); |
michael@0 | 433 | |
michael@0 | 434 | FcInit(); |
michael@0 | 435 | |
michael@0 | 436 | SkDEBUGCODE(fontconfiginterface_unittest();) |
michael@0 | 437 | } |
michael@0 | 438 | |
michael@0 | 439 | SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() { |
michael@0 | 440 | } |
michael@0 | 441 | |
michael@0 | 442 | bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[], |
michael@0 | 443 | SkTypeface::Style style, |
michael@0 | 444 | FontIdentity* outIdentity, |
michael@0 | 445 | SkString* outFamilyName, |
michael@0 | 446 | SkTypeface::Style* outStyle) { |
michael@0 | 447 | std::string familyStr(familyName ? familyName : ""); |
michael@0 | 448 | if (familyStr.length() > kMaxFontFamilyLength) { |
michael@0 | 449 | return false; |
michael@0 | 450 | } |
michael@0 | 451 | |
michael@0 | 452 | SkAutoMutexAcquire ac(mutex_); |
michael@0 | 453 | |
michael@0 | 454 | FcPattern* pattern = FcPatternCreate(); |
michael@0 | 455 | |
michael@0 | 456 | if (familyName) { |
michael@0 | 457 | FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); |
michael@0 | 458 | } |
michael@0 | 459 | FcPatternAddInteger(pattern, FC_WEIGHT, |
michael@0 | 460 | (style & SkTypeface::kBold) ? FC_WEIGHT_BOLD |
michael@0 | 461 | : FC_WEIGHT_NORMAL); |
michael@0 | 462 | FcPatternAddInteger(pattern, FC_SLANT, |
michael@0 | 463 | (style & SkTypeface::kItalic) ? FC_SLANT_ITALIC |
michael@0 | 464 | : FC_SLANT_ROMAN); |
michael@0 | 465 | FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); |
michael@0 | 466 | |
michael@0 | 467 | FcConfigSubstitute(NULL, pattern, FcMatchPattern); |
michael@0 | 468 | FcDefaultSubstitute(pattern); |
michael@0 | 469 | |
michael@0 | 470 | // Font matching: |
michael@0 | 471 | // CSS often specifies a fallback list of families: |
michael@0 | 472 | // font-family: a, b, c, serif; |
michael@0 | 473 | // However, fontconfig will always do its best to find *a* font when asked |
michael@0 | 474 | // for something so we need a way to tell if the match which it has found is |
michael@0 | 475 | // "good enough" for us. Otherwise, we can return NULL which gets piped up |
michael@0 | 476 | // and lets WebKit know to try the next CSS family name. However, fontconfig |
michael@0 | 477 | // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we |
michael@0 | 478 | // wish to support that. |
michael@0 | 479 | // |
michael@0 | 480 | // Thus, if a specific family is requested we set @family_requested. Then we |
michael@0 | 481 | // record two strings: the family name after config processing and the |
michael@0 | 482 | // family name after resolving. If the two are equal, it's a good match. |
michael@0 | 483 | // |
michael@0 | 484 | // So consider the case where a user has mapped Arial to Helvetica in their |
michael@0 | 485 | // config. |
michael@0 | 486 | // requested family: "Arial" |
michael@0 | 487 | // post_config_family: "Helvetica" |
michael@0 | 488 | // post_match_family: "Helvetica" |
michael@0 | 489 | // -> good match |
michael@0 | 490 | // |
michael@0 | 491 | // and for a missing font: |
michael@0 | 492 | // requested family: "Monaco" |
michael@0 | 493 | // post_config_family: "Monaco" |
michael@0 | 494 | // post_match_family: "Times New Roman" |
michael@0 | 495 | // -> BAD match |
michael@0 | 496 | // |
michael@0 | 497 | // However, we special-case fallback fonts; see IsFallbackFontAllowed(). |
michael@0 | 498 | |
michael@0 | 499 | const char* post_config_family = get_name(pattern, FC_FAMILY); |
michael@0 | 500 | if (!post_config_family) { |
michael@0 | 501 | // we can just continue with an empty name, e.g. default font |
michael@0 | 502 | post_config_family = ""; |
michael@0 | 503 | } |
michael@0 | 504 | |
michael@0 | 505 | FcResult result; |
michael@0 | 506 | FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); |
michael@0 | 507 | if (!font_set) { |
michael@0 | 508 | FcPatternDestroy(pattern); |
michael@0 | 509 | return false; |
michael@0 | 510 | } |
michael@0 | 511 | |
michael@0 | 512 | FcPattern* match = MatchFont(font_set, post_config_family, familyStr); |
michael@0 | 513 | if (!match) { |
michael@0 | 514 | FcPatternDestroy(pattern); |
michael@0 | 515 | FcFontSetDestroy(font_set); |
michael@0 | 516 | return false; |
michael@0 | 517 | } |
michael@0 | 518 | |
michael@0 | 519 | FcPatternDestroy(pattern); |
michael@0 | 520 | |
michael@0 | 521 | // From here out we just extract our results from 'match' |
michael@0 | 522 | |
michael@0 | 523 | post_config_family = get_name(match, FC_FAMILY); |
michael@0 | 524 | if (!post_config_family) { |
michael@0 | 525 | FcFontSetDestroy(font_set); |
michael@0 | 526 | return false; |
michael@0 | 527 | } |
michael@0 | 528 | |
michael@0 | 529 | const char* c_filename = get_name(match, FC_FILE); |
michael@0 | 530 | if (!c_filename) { |
michael@0 | 531 | FcFontSetDestroy(font_set); |
michael@0 | 532 | return false; |
michael@0 | 533 | } |
michael@0 | 534 | |
michael@0 | 535 | int face_index; |
michael@0 | 536 | if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) { |
michael@0 | 537 | FcFontSetDestroy(font_set); |
michael@0 | 538 | return false; |
michael@0 | 539 | } |
michael@0 | 540 | |
michael@0 | 541 | FcFontSetDestroy(font_set); |
michael@0 | 542 | |
michael@0 | 543 | if (outIdentity) { |
michael@0 | 544 | outIdentity->fTTCIndex = face_index; |
michael@0 | 545 | outIdentity->fString.set(c_filename); |
michael@0 | 546 | } |
michael@0 | 547 | if (outFamilyName) { |
michael@0 | 548 | outFamilyName->set(post_config_family); |
michael@0 | 549 | } |
michael@0 | 550 | if (outStyle) { |
michael@0 | 551 | *outStyle = GetFontStyle(match); |
michael@0 | 552 | } |
michael@0 | 553 | return true; |
michael@0 | 554 | } |
michael@0 | 555 | |
michael@0 | 556 | SkStream* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) { |
michael@0 | 557 | return SkStream::NewFromFile(identity.fString.c_str()); |
michael@0 | 558 | } |
michael@0 | 559 | |
michael@0 | 560 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 561 | |
michael@0 | 562 | static bool find_name(const SkTDArray<const char*>& list, const char* str) { |
michael@0 | 563 | int count = list.count(); |
michael@0 | 564 | for (int i = 0; i < count; ++i) { |
michael@0 | 565 | if (!strcmp(list[i], str)) { |
michael@0 | 566 | return true; |
michael@0 | 567 | } |
michael@0 | 568 | } |
michael@0 | 569 | return false; |
michael@0 | 570 | } |
michael@0 | 571 | |
michael@0 | 572 | SkDataTable* SkFontConfigInterfaceDirect::getFamilyNames() { |
michael@0 | 573 | SkAutoMutexAcquire ac(mutex_); |
michael@0 | 574 | |
michael@0 | 575 | FcPattern* pat = FcPatternCreate(); |
michael@0 | 576 | SkAutoTCallVProc<FcPattern, FcPatternDestroy> autoDestroyPat(pat); |
michael@0 | 577 | if (NULL == pat) { |
michael@0 | 578 | return NULL; |
michael@0 | 579 | } |
michael@0 | 580 | |
michael@0 | 581 | FcObjectSet* os = FcObjectSetBuild(FC_FAMILY, (char *)0); |
michael@0 | 582 | SkAutoTCallVProc<FcObjectSet, FcObjectSetDestroy> autoDestroyOs(os); |
michael@0 | 583 | if (NULL == os) { |
michael@0 | 584 | return NULL; |
michael@0 | 585 | } |
michael@0 | 586 | |
michael@0 | 587 | FcFontSet* fs = FcFontList(NULL, pat, os); |
michael@0 | 588 | SkAutoTCallVProc<FcFontSet, FcFontSetDestroy> autoDestroyFs(fs); |
michael@0 | 589 | if (NULL == fs) { |
michael@0 | 590 | return NULL; |
michael@0 | 591 | } |
michael@0 | 592 | |
michael@0 | 593 | SkTDArray<const char*> names; |
michael@0 | 594 | SkTDArray<size_t> sizes; |
michael@0 | 595 | for (int i = 0; i < fs->nfont; ++i) { |
michael@0 | 596 | FcPattern* match = fs->fonts[i]; |
michael@0 | 597 | const char* famName = get_name(match, FC_FAMILY); |
michael@0 | 598 | if (famName && !find_name(names, famName)) { |
michael@0 | 599 | *names.append() = famName; |
michael@0 | 600 | *sizes.append() = strlen(famName) + 1; |
michael@0 | 601 | } |
michael@0 | 602 | } |
michael@0 | 603 | |
michael@0 | 604 | return SkDataTable::NewCopyArrays((const void*const*)names.begin(), |
michael@0 | 605 | sizes.begin(), names.count()); |
michael@0 | 606 | } |
michael@0 | 607 | |
michael@0 | 608 | bool SkFontConfigInterfaceDirect::matchFamilySet(const char inFamilyName[], |
michael@0 | 609 | SkString* outFamilyName, |
michael@0 | 610 | SkTArray<FontIdentity>* ids) { |
michael@0 | 611 | SkAutoMutexAcquire ac(mutex_); |
michael@0 | 612 | |
michael@0 | 613 | #if 0 |
michael@0 | 614 | std::string familyStr(familyName ? familyName : ""); |
michael@0 | 615 | if (familyStr.length() > kMaxFontFamilyLength) { |
michael@0 | 616 | return false; |
michael@0 | 617 | } |
michael@0 | 618 | |
michael@0 | 619 | SkAutoMutexAcquire ac(mutex_); |
michael@0 | 620 | |
michael@0 | 621 | FcPattern* pattern = FcPatternCreate(); |
michael@0 | 622 | |
michael@0 | 623 | if (familyName) { |
michael@0 | 624 | FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); |
michael@0 | 625 | } |
michael@0 | 626 | FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); |
michael@0 | 627 | |
michael@0 | 628 | FcConfigSubstitute(NULL, pattern, FcMatchPattern); |
michael@0 | 629 | FcDefaultSubstitute(pattern); |
michael@0 | 630 | |
michael@0 | 631 | // Font matching: |
michael@0 | 632 | // CSS often specifies a fallback list of families: |
michael@0 | 633 | // font-family: a, b, c, serif; |
michael@0 | 634 | // However, fontconfig will always do its best to find *a* font when asked |
michael@0 | 635 | // for something so we need a way to tell if the match which it has found is |
michael@0 | 636 | // "good enough" for us. Otherwise, we can return NULL which gets piped up |
michael@0 | 637 | // and lets WebKit know to try the next CSS family name. However, fontconfig |
michael@0 | 638 | // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we |
michael@0 | 639 | // wish to support that. |
michael@0 | 640 | // |
michael@0 | 641 | // Thus, if a specific family is requested we set @family_requested. Then we |
michael@0 | 642 | // record two strings: the family name after config processing and the |
michael@0 | 643 | // family name after resolving. If the two are equal, it's a good match. |
michael@0 | 644 | // |
michael@0 | 645 | // So consider the case where a user has mapped Arial to Helvetica in their |
michael@0 | 646 | // config. |
michael@0 | 647 | // requested family: "Arial" |
michael@0 | 648 | // post_config_family: "Helvetica" |
michael@0 | 649 | // post_match_family: "Helvetica" |
michael@0 | 650 | // -> good match |
michael@0 | 651 | // |
michael@0 | 652 | // and for a missing font: |
michael@0 | 653 | // requested family: "Monaco" |
michael@0 | 654 | // post_config_family: "Monaco" |
michael@0 | 655 | // post_match_family: "Times New Roman" |
michael@0 | 656 | // -> BAD match |
michael@0 | 657 | // |
michael@0 | 658 | // However, we special-case fallback fonts; see IsFallbackFontAllowed(). |
michael@0 | 659 | |
michael@0 | 660 | const char* post_config_family = get_name(pattern, FC_FAMILY); |
michael@0 | 661 | |
michael@0 | 662 | FcResult result; |
michael@0 | 663 | FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); |
michael@0 | 664 | if (!font_set) { |
michael@0 | 665 | FcPatternDestroy(pattern); |
michael@0 | 666 | return false; |
michael@0 | 667 | } |
michael@0 | 668 | |
michael@0 | 669 | FcPattern* match = MatchFont(font_set, post_config_family, familyStr); |
michael@0 | 670 | if (!match) { |
michael@0 | 671 | FcPatternDestroy(pattern); |
michael@0 | 672 | FcFontSetDestroy(font_set); |
michael@0 | 673 | return false; |
michael@0 | 674 | } |
michael@0 | 675 | |
michael@0 | 676 | FcPatternDestroy(pattern); |
michael@0 | 677 | |
michael@0 | 678 | // From here out we just extract our results from 'match' |
michael@0 | 679 | |
michael@0 | 680 | if (FcPatternGetString(match, FC_FAMILY, 0, &post_config_family) != FcResultMatch) { |
michael@0 | 681 | FcFontSetDestroy(font_set); |
michael@0 | 682 | return false; |
michael@0 | 683 | } |
michael@0 | 684 | |
michael@0 | 685 | FcChar8* c_filename; |
michael@0 | 686 | if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) { |
michael@0 | 687 | FcFontSetDestroy(font_set); |
michael@0 | 688 | return false; |
michael@0 | 689 | } |
michael@0 | 690 | |
michael@0 | 691 | int face_index; |
michael@0 | 692 | if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) { |
michael@0 | 693 | FcFontSetDestroy(font_set); |
michael@0 | 694 | return false; |
michael@0 | 695 | } |
michael@0 | 696 | |
michael@0 | 697 | FcFontSetDestroy(font_set); |
michael@0 | 698 | |
michael@0 | 699 | if (outIdentity) { |
michael@0 | 700 | outIdentity->fTTCIndex = face_index; |
michael@0 | 701 | outIdentity->fString.set((const char*)c_filename); |
michael@0 | 702 | } |
michael@0 | 703 | if (outFamilyName) { |
michael@0 | 704 | outFamilyName->set((const char*)post_config_family); |
michael@0 | 705 | } |
michael@0 | 706 | if (outStyle) { |
michael@0 | 707 | *outStyle = GetFontStyle(match); |
michael@0 | 708 | } |
michael@0 | 709 | return true; |
michael@0 | 710 | |
michael@0 | 711 | //////////////////// |
michael@0 | 712 | |
michael@0 | 713 | int count; |
michael@0 | 714 | FcPattern** match = MatchFont(font_set, post_config_family, &count); |
michael@0 | 715 | if (!match) { |
michael@0 | 716 | FcPatternDestroy(pattern); |
michael@0 | 717 | FcFontSetDestroy(font_set); |
michael@0 | 718 | return NULL; |
michael@0 | 719 | } |
michael@0 | 720 | |
michael@0 | 721 | FcPatternDestroy(pattern); |
michael@0 | 722 | |
michael@0 | 723 | SkTDArray<FcPattern*> trimmedMatches; |
michael@0 | 724 | for (int i = 0; i < count; ++i) { |
michael@0 | 725 | const char* justName = find_just_name(get_name(match[i], FC_FILE)); |
michael@0 | 726 | if (!is_lower(*justName)) { |
michael@0 | 727 | *trimmedMatches.append() = match[i]; |
michael@0 | 728 | } |
michael@0 | 729 | } |
michael@0 | 730 | |
michael@0 | 731 | SkFontStyleSet_FC* sset = SkNEW_ARGS(SkFontStyleSet_FC, |
michael@0 | 732 | (trimmedMatches.begin(), |
michael@0 | 733 | trimmedMatches.count())); |
michael@0 | 734 | #endif |
michael@0 | 735 | return false; |
michael@0 | 736 | } |