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