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