gfx/skia/trunk/src/ports/SkFontConfigInterface_direct.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 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 }

mercurial