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) {
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 },
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 },
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 },
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);
686 resolvedFilename += c_filename;
687 c_filename = resolvedFilename.
c_str();
692 FcFontSetDestroy(font_set);
699 outFamilyName->
set(post_config_family);
SkStrokeRec::Style fStyle
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)
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
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
DEF_SWITCHES_START aot vmservice shared library name
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
size_t readFromMemory(const void *buffer, size_t length)
size_t writeToMemory(void *buffer=nullptr) const