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