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