23#include <fontconfig/fontconfig.h>
31static SkMutex& f_c_mutex() {
32 static SkMutex& mutex = *(
new SkMutex);
37 inline static constexpr int FontConfigThreadSafeVersion = 21393;
41 if (FcGetVersion() < FontConfigThreadSafeVersion) {
42 f_c_mutex().acquire();
48 if (FcGetVersion() < FontConfigThreadSafeVersion) {
49 f_c_mutex().release();
54 if (FcGetVersion() < FontConfigThreadSafeVersion) {
55 f_c_mutex().assertHeld();
60using UniqueFCConfig = std::unique_ptr<FcConfig, SkFunctionObject<FcConfigDestroy>>;
66 size +=
sizeof(int32_t) +
sizeof(int32_t) +
sizeof(uint8_t);
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);
99 fString.resize(strLen);
100 (void)
buffer.read(fString.data(), strLen);
121 memset(storage.get(), initValue, size0);
132static void fontconfiginterface_unittest() {
143 test_writeToMemory(iden0, 0);
144 test_writeToMemory(iden0, 0);
151static const char*
get_string(FcPattern* pattern,
const char field[],
int index = 0) {
153 if (FcPatternGetString(pattern, field, index, (FcChar8**)&
name) != FcResultMatch) {
190FontEquivClass GetFontEquivClass(
const char* fontname)
209 struct FontEquivMap {
210 FontEquivClass clazz;
214 static const FontEquivMap kFontEquivMap[] = {
217 { SANS,
"Liberation Sans" },
219 { SERIF,
"Times New Roman" },
221 { SERIF,
"Liberation Serif" },
223 { MONO,
"Courier New" },
225 { MONO,
"Liberation Mono" },
227 { SYMBOL,
"Symbol" },
228 { SYMBOL,
"Symbol Neu" },
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" },
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" },
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" },
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" },
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" },
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" },
276 { SIMHEI,
"Simhei" },
277 { SIMHEI,
"\xe9\xbb\x91\xe4\xbd\x93" },
278 { SIMHEI,
"Noto Sans CJK SC" },
279 { SIMHEI,
"MYingHeiGB18030" },
280 { SIMHEI,
"MYingHeiB5HK" },
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"},
289 { MINGLIU,
"MingLiU"},
290 { MINGLIU,
"\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" },
291 { MINGLIU,
"Noto Serif CJK TC"},
292 { MINGLIU,
"MSung B5HK"},
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"},
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"},
307 { CAMBRIA,
"Cambria" },
308 { CAMBRIA,
"Caladea" },
311 { CALIBRI,
"Calibri" },
312 { CALIBRI,
"Carlito" },
315 static const size_t kFontCount =
316 sizeof(kFontEquivMap)/
sizeof(kFontEquivMap[0]);
320 for (
size_t i = 0; i < kFontCount; ++i) {
321 if (strcasecmp(kFontEquivMap[i].
name, fontname) == 0)
322 return kFontEquivMap[i].clazz;
330bool IsMetricCompatibleReplacement(
const char* font_a,
const char* font_b)
332 FontEquivClass class_a = GetFontEquivClass(font_a);
333 FontEquivClass class_b = GetFontEquivClass(font_b);
335 return class_a != OTHER && class_a == class_b;
342bool IsFallbackFontAllowed(
const SkString& family) {
343 const char* family_cstr = family.
c_str();
345 strcasecmp(family_cstr,
"sans") == 0 ||
346 strcasecmp(family_cstr,
"serif") == 0 ||
347 strcasecmp(family_cstr,
"monospace") == 0;
351static int get_int(FcPattern* pattern,
const char object[],
int missing) {
353 if (FcPatternGetInteger(pattern,
object, 0, &value) != FcResultMatch) {
365 return new_min + ((
value - old_min) * (new_max - new_min) / (old_max - old_min));
375 if (val < ranges[0].old_val) {
376 return ranges[0].new_val;
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);
389 return ranges[rangesCount-1].new_val;
392#ifndef FC_WEIGHT_DEMILIGHT
393#define FC_WEIGHT_DEMILIGHT 65
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 },
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 },
414 weightRanges, std::size(weightRanges));
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 },
428 widthRanges, std::size(widthRanges));
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;
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 },
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 },
458 int weight =
map_ranges(style.
weight(), weightRanges, std::size(weightRanges));
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 },
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;
481 FcPatternAddInteger(pattern, FC_WEIGHT, weight);
482 FcPatternAddInteger(pattern, FC_WIDTH ,
width);
483 FcPatternAddInteger(pattern, FC_SLANT , slant);
490#define kMaxFontFamilyLength 2048
491#ifdef SK_FONT_CONFIG_INTERFACE_ONLY_ALLOW_SFNT_FONTS
492const char* kFontFormatTrueType =
"TrueType";
493const char* kFontFormatCFF =
"CFF";
503 FcConfigDestroy(fFC);
508 if (access(filename, R_OK) != 0) {
514bool SkFontConfigInterfaceDirect::isValidPattern(FcPattern* pattern) {
515#ifdef SK_FONT_CONFIG_INTERFACE_ONLY_ALLOW_SFNT_FONTS
516 const char* font_format =
get_string(pattern, FC_FONTFORMAT);
518 && 0 != strcmp(font_format, kFontFormatTrueType)
519 && 0 != strcmp(font_format, kFontFormatCFF))
526 const char* c_filename =
get_string(pattern, FC_FILE);
532 UniqueFCConfig fcStorage;
534 fcStorage.reset(FcConfigReference(
nullptr));
535 fc = fcStorage.get();
538 const char*
sysroot = (
const char*)FcConfigGetSysRoot(fc);
542 resolvedFilename += c_filename;
543 c_filename = resolvedFilename.
c_str();
549FcPattern* SkFontConfigInterfaceDirect::MatchFont(FcFontSet* font_set,
550 const char* post_config_family,
554 FcPattern*
match =
nullptr;
555 for (
int i = 0; i < font_set->nfont; ++i) {
556 FcPattern* current = font_set->fonts[i];
557 if (this->isValidPattern(current)) {
563 if (
match && !IsFallbackFontAllowed(family)) {
564 bool acceptable_substitute =
false;
565 for (
int id = 0;
id < 255; ++
id) {
567 if (!post_match_family)
569 acceptable_substitute =
570 (strcasecmp(post_config_family, post_match_family) == 0 ||
576 strcasecmp(family.
c_str(), post_match_family) == 0) ||
577 IsMetricCompatibleReplacement(family.
c_str(), post_match_family);
578 if (acceptable_substitute)
581 if (!acceptable_substitute)
593 SkString familyStr(familyName ? familyName :
"");
599 UniqueFCConfig fcStorage;
601 fcStorage.reset(FcConfigReference(
nullptr));
602 fc = fcStorage.get();
606 FcPattern* pattern = FcPatternCreate();
609 FcPatternAddString(pattern, FC_FAMILY, (
const FcChar8*)familyName);
613 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
615 FcConfigSubstitute(fc, pattern, FcMatchPattern);
616 FcDefaultSubstitute(pattern);
647 const char* post_config_family =
get_string(pattern, FC_FAMILY);
648 if (!post_config_family) {
650 post_config_family =
"";
654 FcFontSet* font_set = FcFontSort(fc, pattern, 0,
nullptr, &
result);
656 FcPatternDestroy(pattern);
660 FcPattern*
match = this->MatchFont(font_set, post_config_family, familyStr);
662 FcPatternDestroy(pattern);
663 FcFontSetDestroy(font_set);
667 FcPatternDestroy(pattern);
672 if (!post_config_family) {
673 FcFontSetDestroy(font_set);
679 FcFontSetDestroy(font_set);
682 const char* sysroot = (
const char*)FcConfigGetSysRoot(fc);
685 resolvedFilename = sysroot;
686 resolvedFilename += c_filename;
687 c_filename = resolvedFilename.
c_str();
692 FcFontSetDestroy(font_set);
699 outFamilyName->
set(post_config_family);
SkStrokeRec::Style fStyle
static bool match(const char *needle, const char *haystack)
static uint32_t get_int(const uint8_t *buffer, uint32_t i)
#define kMaxFontFamilyLength
static const char * get_string(FcPattern *pattern, const char field[], int index=0)
#define FC_WEIGHT_DEMILIGHT
static SkFontStyle skfontstyle_from_fcpattern(FcPattern *pattern)
static SkScalar map_ranges(SkScalar val, MapRanges const ranges[], int rangesCount)
static int map_range(SkScalar value, SkScalar old_min, SkScalar old_max, SkScalar new_min, SkScalar new_max)
static void fcpattern_from_skfontstyle(SkFontStyle style, FcPattern *pattern)
#define SkScalarRoundToInt(x)
SkStreamAsset * openStream(const FontIdentity &) override
virtual bool isAccessible(const char *filename)
SkFontConfigInterfaceDirect(FcConfig *fc)
bool matchFamilyName(const char familyName[], SkFontStyle requested, FontIdentity *outFontIdentifier, SkString *outFamilyName, SkFontStyle *outStyle) override
~SkFontConfigInterfaceDirect() override
static std::unique_ptr< SkStreamAsset > MakeFromFile(const char path[])
void set(const SkString &src)
const char * c_str() const
static const uint8_t buffer[]
size_t readFromMemory(const void *buffer, size_t length)
size_t writeToMemory(void *buffer=nullptr) const