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