Flutter Engine
The Flutter Engine
SkFontMgr_fontconfig.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2014 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
25#include "src/base/SkTSort.h"
28#include "src/core/SkOSFile.h"
32
33#include <fontconfig/fontconfig.h>
34
35#include <string.h>
36#include <array>
37#include <cstddef>
38#include <cstdint>
39#include <memory>
40#include <utility>
41
42class SkData;
43
44using namespace skia_private;
45
46// FC_POSTSCRIPT_NAME was added with b561ff20 which ended up in 2.10.92
47// Ubuntu 14.04 is on 2.11.0
48// Debian 8 and 9 are on 2.11
49// OpenSUSE Leap 42.1 is on 2.11.0 (42.3 is on 2.11.1)
50// Fedora 24 is on 2.11.94
51#ifndef FC_POSTSCRIPT_NAME
52# define FC_POSTSCRIPT_NAME "postscriptname"
53#endif
54
55/** Since FontConfig is poorly documented, this gives a high level overview:
56 *
57 * FcConfig is a handle to a FontConfig configuration instance. Each 'configuration' is independent
58 * from any others which may exist. There exists a default global configuration which is created
59 * and destroyed by FcInit and FcFini, but this default should not normally be used.
60 * Instead, one should use FcConfigCreate and FcInit* to have a named local state.
61 *
62 * FcPatterns are {objectName -> [element]} (maps from object names to a list of elements).
63 * Each element is some internal data plus an FcValue which is a variant (a union with a type tag).
64 * Lists of elements are not typed, except by convention. Any collection of FcValues must be
65 * assumed to be heterogeneous by the code, but the code need not do anything particularly
66 * interesting if the values go against convention.
67 *
68 * Somewhat like DirectWrite, FontConfig supports synthetics through FC_EMBOLDEN and FC_MATRIX.
69 * Like all synthetic information, such information must be passed with the font data.
70 */
71
72namespace {
73
74// FontConfig was thread antagonistic until 2.10.91 with known thread safety issues until 2.13.93.
75// Before that, lock with a global mutex.
76// See https://bug.skia.org/1497 and cl/339089311 for background.
77static SkMutex& f_c_mutex() {
78 static SkMutex& mutex = *(new SkMutex);
79 return mutex;
80}
81
82class FCLocker {
83 inline static constexpr int FontConfigThreadSafeVersion = 21393;
84
85 // Assume FcGetVersion() has always been thread safe.
86 static void lock() SK_NO_THREAD_SAFETY_ANALYSIS {
87 if (FcGetVersion() < FontConfigThreadSafeVersion) {
88 f_c_mutex().acquire();
89 }
90 }
91 static void unlock() SK_NO_THREAD_SAFETY_ANALYSIS {
92 AssertHeld();
93 if (FcGetVersion() < FontConfigThreadSafeVersion) {
94 f_c_mutex().release();
95 }
96 }
97
98public:
99 FCLocker() { lock(); }
100 ~FCLocker() { unlock(); }
101
102 static void AssertHeld() { SkDEBUGCODE(
103 if (FcGetVersion() < FontConfigThreadSafeVersion) {
104 f_c_mutex().assertHeld();
105 }
106 ) }
107};
108
109} // namespace
110
111template<typename T, void (*D)(T*)> void FcTDestroy(T* t) {
112 FCLocker::AssertHeld();
113 D(t);
114}
115template <typename T, T* (*C)(), void (*D)(T*)> class SkAutoFc
116 : public SkAutoTCallVProc<T, FcTDestroy<T, D>> {
118public:
120 T* obj = this->operator T*();
121 SkASSERT_RELEASE(nullptr != obj);
122 }
123 explicit SkAutoFc(T* obj) : inherited(obj) {}
124 SkAutoFc(const SkAutoFc&) = delete;
125 SkAutoFc(SkAutoFc&& that) : inherited(std::move(that)) {}
126};
127
134
135static bool get_bool(FcPattern* pattern, const char object[], bool missing = false) {
136 FcBool value;
137 if (FcPatternGetBool(pattern, object, 0, &value) != FcResultMatch) {
138 return missing;
139 }
140 return value;
141}
142
143static int get_int(FcPattern* pattern, const char object[], int missing) {
144 int value;
145 if (FcPatternGetInteger(pattern, object, 0, &value) != FcResultMatch) {
146 return missing;
147 }
148 return value;
149}
150
151static const char* get_string(FcPattern* pattern, const char object[], const char* missing = "") {
152 FcChar8* value;
153 if (FcPatternGetString(pattern, object, 0, &value) != FcResultMatch) {
154 return missing;
155 }
156 return (const char*)value;
157}
158
159static const FcMatrix* get_matrix(FcPattern* pattern, const char object[]) {
160 FcMatrix* matrix;
161 if (FcPatternGetMatrix(pattern, object, 0, &matrix) != FcResultMatch) {
162 return nullptr;
163 }
164 return matrix;
165}
166
172/** Ideally there would exist a call like
173 * FcResult FcPatternIsWeak(pattern, object, id, FcBool* isWeak);
174 * Sometime after 2.12.4 FcPatternGetWithBinding was added which can retrieve the binding.
175 *
176 * However, there is no such call and as of Fc 2.11.0 even FcPatternEquals ignores the weak bit.
177 * Currently, the only reliable way of finding the weak bit is by its effect on matching.
178 * The weak bit only affects the matching of FC_FAMILY and FC_POSTSCRIPT_NAME object values.
179 * A element with the weak bit is scored after FC_LANG, without the weak bit is scored before.
180 * Note that the weak bit is stored on the element, not on the value it holds.
181 */
182static SkWeakReturn is_weak(FcPattern* pattern, const char object[], int id) {
183 FCLocker::AssertHeld();
184
185 FcResult result;
186
187 // Create a copy of the pattern with only the value 'pattern'['object'['id']] in it.
188 // Internally, FontConfig pattern objects are linked lists, so faster to remove from head.
189 SkAutoFcObjectSet requestedObjectOnly(FcObjectSetBuild(object, nullptr));
190 SkAutoFcPattern minimal(FcPatternFilter(pattern, requestedObjectOnly));
191 FcBool hasId = true;
192 for (int i = 0; hasId && i < id; ++i) {
193 hasId = FcPatternRemove(minimal, object, 0);
194 }
195 if (!hasId) {
196 return kNoId_WeakReturn;
197 }
198 FcValue value;
199 result = FcPatternGet(minimal, object, 0, &value);
200 if (result != FcResultMatch) {
201 return kNoId_WeakReturn;
202 }
203 while (hasId) {
204 hasId = FcPatternRemove(minimal, object, 1);
205 }
206
207 // Create a font set with two patterns.
208 // 1. the same 'object' as minimal and a lang object with only 'nomatchlang'.
209 // 2. a different 'object' from minimal and a lang object with only 'matchlang'.
210 SkAutoFcFontSet fontSet;
211
212 SkAutoFcLangSet strongLangSet;
213 FcLangSetAdd(strongLangSet, (const FcChar8*)"nomatchlang");
214 SkAutoFcPattern strong(FcPatternDuplicate(minimal));
215 FcPatternAddLangSet(strong, FC_LANG, strongLangSet);
216
217 SkAutoFcLangSet weakLangSet;
218 FcLangSetAdd(weakLangSet, (const FcChar8*)"matchlang");
219 SkAutoFcPattern weak;
220 FcPatternAddString(weak, object, (const FcChar8*)"nomatchstring");
221 FcPatternAddLangSet(weak, FC_LANG, weakLangSet);
222
223 FcFontSetAdd(fontSet, strong.release());
224 FcFontSetAdd(fontSet, weak.release());
225
226 // Add 'matchlang' to the copy of the pattern.
227 FcPatternAddLangSet(minimal, FC_LANG, weakLangSet);
228
229 // Run a match against the copy of the pattern.
230 // If the 'id' was weak, then we should match the pattern with 'matchlang'.
231 // If the 'id' was strong, then we should match the pattern with 'nomatchlang'.
232
233 // Note that this config is only used for FcFontRenderPrepare, which we don't even want.
234 // However, there appears to be no way to match/sort without it.
235 SkAutoFcConfig config;
236 FcFontSet* fontSets[1] = { fontSet };
237 SkAutoFcPattern match(FcFontSetMatch(config, fontSets, std::size(fontSets),
238 minimal, &result));
239
240 FcLangSet* matchLangSet;
241 FcPatternGetLangSet(match, FC_LANG, 0, &matchLangSet);
242 return FcLangEqual == FcLangSetHasLang(matchLangSet, (const FcChar8*)"matchlang")
244}
245
246/** Removes weak elements from either FC_FAMILY or FC_POSTSCRIPT_NAME objects in the property.
247 * This can be quite expensive, and should not be used more than once per font lookup.
248 * This removes all of the weak elements after the last strong element.
249 */
250static void remove_weak(FcPattern* pattern, const char object[]) {
251 FCLocker::AssertHeld();
252
253 SkAutoFcObjectSet requestedObjectOnly(FcObjectSetBuild(object, nullptr));
254 SkAutoFcPattern minimal(FcPatternFilter(pattern, requestedObjectOnly));
255
256 int lastStrongId = -1;
257 int numIds;
259 for (int id = 0; ; ++id) {
260 result = is_weak(minimal, object, 0);
261 if (kNoId_WeakReturn == result) {
262 numIds = id;
263 break;
264 }
266 lastStrongId = id;
267 }
268 SkAssertResult(FcPatternRemove(minimal, object, 0));
269 }
270
271 // If they were all weak, then leave the pattern alone.
272 if (lastStrongId < 0) {
273 return;
274 }
275
276 // Remove everything after the last strong.
277 for (int id = lastStrongId + 1; id < numIds; ++id) {
278 SkAssertResult(FcPatternRemove(pattern, object, lastStrongId + 1));
279 }
280}
281
283 SkScalar old_min, SkScalar old_max,
284 SkScalar new_min, SkScalar new_max)
285{
286 SkASSERT(old_min < old_max);
287 SkASSERT(new_min <= new_max);
288 return new_min + ((value - old_min) * (new_max - new_min) / (old_max - old_min));
289}
290
291struct MapRanges {
294};
295
296static SkScalar map_ranges(SkScalar val, MapRanges const ranges[], int rangesCount) {
297 // -Inf to [0]
298 if (val < ranges[0].old_val) {
299 return ranges[0].new_val;
300 }
301
302 // Linear from [i] to [i+1]
303 for (int i = 0; i < rangesCount - 1; ++i) {
304 if (val < ranges[i+1].old_val) {
305 return map_range(val, ranges[i].old_val, ranges[i+1].old_val,
306 ranges[i].new_val, ranges[i+1].new_val);
307 }
308 }
309
310 // From [n] to +Inf
311 // if (fcweight < Inf)
312 return ranges[rangesCount-1].new_val;
313}
314
315#ifndef FC_WEIGHT_DEMILIGHT
316#define FC_WEIGHT_DEMILIGHT 65
317#endif
318
319static SkFontStyle skfontstyle_from_fcpattern(FcPattern* pattern) {
320 typedef SkFontStyle SkFS;
321
322 // FcWeightToOpenType was buggy until 2.12.4
323 static constexpr MapRanges weightRanges[] = {
324 { FC_WEIGHT_THIN, SkFS::kThin_Weight },
325 { FC_WEIGHT_EXTRALIGHT, SkFS::kExtraLight_Weight },
326 { FC_WEIGHT_LIGHT, SkFS::kLight_Weight },
327 { FC_WEIGHT_DEMILIGHT, 350 },
328 { FC_WEIGHT_BOOK, 380 },
329 { FC_WEIGHT_REGULAR, SkFS::kNormal_Weight },
330 { FC_WEIGHT_MEDIUM, SkFS::kMedium_Weight },
331 { FC_WEIGHT_DEMIBOLD, SkFS::kSemiBold_Weight },
332 { FC_WEIGHT_BOLD, SkFS::kBold_Weight },
333 { FC_WEIGHT_EXTRABOLD, SkFS::kExtraBold_Weight },
334 { FC_WEIGHT_BLACK, SkFS::kBlack_Weight },
335 { FC_WEIGHT_EXTRABLACK, SkFS::kExtraBlack_Weight },
336 };
337 SkScalar weight = map_ranges(get_int(pattern, FC_WEIGHT, FC_WEIGHT_REGULAR),
338 weightRanges, std::size(weightRanges));
339
340 static constexpr MapRanges widthRanges[] = {
341 { FC_WIDTH_ULTRACONDENSED, SkFS::kUltraCondensed_Width },
342 { FC_WIDTH_EXTRACONDENSED, SkFS::kExtraCondensed_Width },
343 { FC_WIDTH_CONDENSED, SkFS::kCondensed_Width },
344 { FC_WIDTH_SEMICONDENSED, SkFS::kSemiCondensed_Width },
345 { FC_WIDTH_NORMAL, SkFS::kNormal_Width },
346 { FC_WIDTH_SEMIEXPANDED, SkFS::kSemiExpanded_Width },
347 { FC_WIDTH_EXPANDED, SkFS::kExpanded_Width },
348 { FC_WIDTH_EXTRAEXPANDED, SkFS::kExtraExpanded_Width },
349 { FC_WIDTH_ULTRAEXPANDED, SkFS::kUltraExpanded_Width },
350 };
351 SkScalar width = map_ranges(get_int(pattern, FC_WIDTH, FC_WIDTH_NORMAL),
352 widthRanges, std::size(widthRanges));
353
354 SkFS::Slant slant = SkFS::kUpright_Slant;
355 switch (get_int(pattern, FC_SLANT, FC_SLANT_ROMAN)) {
356 case FC_SLANT_ROMAN: slant = SkFS::kUpright_Slant; break;
357 case FC_SLANT_ITALIC : slant = SkFS::kItalic_Slant ; break;
358 case FC_SLANT_OBLIQUE: slant = SkFS::kOblique_Slant; break;
359 default: SkASSERT(false); break;
360 }
361
363}
364
365static void fcpattern_from_skfontstyle(SkFontStyle style, FcPattern* pattern) {
366 FCLocker::AssertHeld();
367
368 typedef SkFontStyle SkFS;
369
370 // FcWeightFromOpenType was buggy until 2.12.4
371 static constexpr MapRanges weightRanges[] = {
372 { SkFS::kThin_Weight, FC_WEIGHT_THIN },
373 { SkFS::kExtraLight_Weight, FC_WEIGHT_EXTRALIGHT },
374 { SkFS::kLight_Weight, FC_WEIGHT_LIGHT },
375 { 350, FC_WEIGHT_DEMILIGHT },
376 { 380, FC_WEIGHT_BOOK },
377 { SkFS::kNormal_Weight, FC_WEIGHT_REGULAR },
378 { SkFS::kMedium_Weight, FC_WEIGHT_MEDIUM },
379 { SkFS::kSemiBold_Weight, FC_WEIGHT_DEMIBOLD },
380 { SkFS::kBold_Weight, FC_WEIGHT_BOLD },
381 { SkFS::kExtraBold_Weight, FC_WEIGHT_EXTRABOLD },
382 { SkFS::kBlack_Weight, FC_WEIGHT_BLACK },
383 { SkFS::kExtraBlack_Weight, FC_WEIGHT_EXTRABLACK },
384 };
385 int weight = map_ranges(style.weight(), weightRanges, std::size(weightRanges));
386
387 static constexpr MapRanges widthRanges[] = {
388 { SkFS::kUltraCondensed_Width, FC_WIDTH_ULTRACONDENSED },
389 { SkFS::kExtraCondensed_Width, FC_WIDTH_EXTRACONDENSED },
390 { SkFS::kCondensed_Width, FC_WIDTH_CONDENSED },
391 { SkFS::kSemiCondensed_Width, FC_WIDTH_SEMICONDENSED },
392 { SkFS::kNormal_Width, FC_WIDTH_NORMAL },
393 { SkFS::kSemiExpanded_Width, FC_WIDTH_SEMIEXPANDED },
394 { SkFS::kExpanded_Width, FC_WIDTH_EXPANDED },
395 { SkFS::kExtraExpanded_Width, FC_WIDTH_EXTRAEXPANDED },
396 { SkFS::kUltraExpanded_Width, FC_WIDTH_ULTRAEXPANDED },
397 };
398 int width = map_ranges(style.width(), widthRanges, std::size(widthRanges));
399
400 int slant = FC_SLANT_ROMAN;
401 switch (style.slant()) {
402 case SkFS::kUpright_Slant: slant = FC_SLANT_ROMAN ; break;
403 case SkFS::kItalic_Slant : slant = FC_SLANT_ITALIC ; break;
404 case SkFS::kOblique_Slant: slant = FC_SLANT_OBLIQUE; break;
405 default: SkASSERT(false); break;
406 }
407
408 FcPatternAddInteger(pattern, FC_WEIGHT, weight);
409 FcPatternAddInteger(pattern, FC_WIDTH , width);
410 FcPatternAddInteger(pattern, FC_SLANT , slant);
411}
412
414public:
416 return sk_sp<SkTypeface_fontconfig>(new SkTypeface_fontconfig(std::move(pattern),
417 std::move(sysroot)));
418 }
419 mutable SkAutoFcPattern fPattern; // Mutable for passing to FontConfig API.
421
422 void onGetFamilyName(SkString* familyName) const override {
423 *familyName = get_string(fPattern, FC_FAMILY);
424 }
425
426 void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override {
427 // TODO: need to serialize FC_MATRIX and FC_EMBOLDEN
428 FCLocker lock;
429 desc->setFamilyName(get_string(fPattern, FC_FAMILY));
430 desc->setFullName(get_string(fPattern, FC_FULLNAME));
431 desc->setPostscriptName(get_string(fPattern, FC_POSTSCRIPT_NAME));
432 desc->setStyle(this->fontStyle());
434 *serialize = false;
435 }
436
437 std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override {
438 FCLocker lock;
439 *ttcIndex = get_int(fPattern, FC_INDEX, 0);
440 const char* filename = get_string(fPattern, FC_FILE);
441 // See FontAccessible for note on searching sysroot then non-sysroot path.
442 SkString resolvedFilename;
443 if (!fSysroot.isEmpty()) {
444 resolvedFilename = fSysroot;
445 resolvedFilename += filename;
446 if (sk_exists(resolvedFilename.c_str(), kRead_SkFILE_Flag)) {
447 filename = resolvedFilename.c_str();
448 }
449 }
450 return SkStream::MakeFromFile(filename);
451 }
452
453 void onFilterRec(SkScalerContextRec* rec) const override {
454 // FontConfig provides 10-scale-bitmap-fonts.conf which applies an inverse "pixelsize"
455 // matrix. It is not known if this .conf is active or not, so it is not clear if
456 // "pixelsize" should be applied before this matrix. Since using a matrix with a bitmap
457 // font isn't a great idea, only apply the matrix to outline fonts.
458 const FcMatrix* fcMatrix = get_matrix(fPattern, FC_MATRIX);
459 bool fcOutline = get_bool(fPattern, FC_OUTLINE, true);
460 if (fcOutline && fcMatrix) {
461 // fPost2x2 is column-major, left handed (y down).
462 // FcMatrix is column-major, right handed (y up).
463 SkMatrix fm;
464 fm.setAll(fcMatrix->xx,-fcMatrix->xy, 0,
465 -fcMatrix->yx, fcMatrix->yy, 0,
466 0 , 0 , 1);
467
468 SkMatrix sm;
469 rec->getMatrixFrom2x2(&sm);
470
471 sm.preConcat(fm);
472 rec->fPost2x2[0][0] = sm.getScaleX();
473 rec->fPost2x2[0][1] = sm.getSkewX();
474 rec->fPost2x2[1][0] = sm.getSkewY();
475 rec->fPost2x2[1][1] = sm.getScaleY();
476 }
477 if (get_bool(fPattern, FC_EMBOLDEN)) {
479 }
480 this->INHERITED::onFilterRec(rec);
481 }
482
483 std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override {
484 std::unique_ptr<SkAdvancedTypefaceMetrics> info =
486
487 // Simulated fonts shouldn't be considered to be of the type of their data.
488 if (get_matrix(fPattern, FC_MATRIX) || get_bool(fPattern, FC_EMBOLDEN)) {
490 }
491 return info;
492 }
493
495 SkFontStyle style = this->fontStyle();
496 std::unique_ptr<SkFontData> data = this->cloneFontData(args, &style);
497 if (!data) {
498 return nullptr;
499 }
500
501 // TODO: need to clone FC_MATRIX and FC_EMBOLDEN
502 SkString familyName;
503 this->getFamilyName(&familyName);
504 return sk_make_sp<SkTypeface_FreeTypeStream>(
505 std::move(data), familyName, style, this->isFixedPitch());
506 }
507
508 std::unique_ptr<SkFontData> onMakeFontData() const override {
509 int index;
510 std::unique_ptr<SkStreamAsset> stream(this->onOpenStream(&index));
511 if (!stream) {
512 return nullptr;
513 }
514 // TODO: FC_VARIABLE and FC_FONT_VARIATIONS
515 return std::make_unique<SkFontData>(std::move(stream), index, 0, nullptr, 0, nullptr, 0);
516 }
517
519 // Hold the lock while unrefing the pattern.
520 FCLocker lock;
521 fPattern.reset();
522 }
523
524private:
526 : INHERITED(skfontstyle_from_fcpattern(pattern),
527 FC_PROPORTIONAL != get_int(pattern, FC_SPACING, FC_PROPORTIONAL))
528 , fPattern(std::move(pattern))
529 , fSysroot(std::move(sysroot))
530 { }
531
532 using INHERITED = SkTypeface_FreeType;
533};
534
536 mutable SkAutoFcConfig fFC; // Only mutable to avoid const cast when passed to FontConfig API.
537 const SkString fSysroot;
538 const sk_sp<SkDataTable> fFamilyNames;
539
540 class StyleSet : public SkFontStyleSet {
541 public:
542 StyleSet(sk_sp<SkFontMgr_fontconfig> parent, SkAutoFcFontSet fontSet)
543 : fFontMgr(std::move(parent))
544 , fFontSet(std::move(fontSet))
545 { }
546
547 ~StyleSet() override {
548 // Hold the lock while unrefing the font set.
549 FCLocker lock;
550 fFontSet.reset();
551 }
552
553 int count() override { return fFontSet->nfont; }
554
555 void getStyle(int index, SkFontStyle* style, SkString* styleName) override {
556 if (index < 0 || fFontSet->nfont <= index) {
557 return;
558 }
559
560 FCLocker lock;
561 if (style) {
562 *style = skfontstyle_from_fcpattern(fFontSet->fonts[index]);
563 }
564 if (styleName) {
565 *styleName = get_string(fFontSet->fonts[index], FC_STYLE);
566 }
567 }
568
569 sk_sp<SkTypeface> createTypeface(int index) override {
570 if (index < 0 || fFontSet->nfont <= index) {
571 return nullptr;
572 }
573 SkAutoFcPattern match([this, &index]() {
574 FCLocker lock;
575 FcPatternReference(fFontSet->fonts[index]);
576 return fFontSet->fonts[index];
577 }());
578 return fFontMgr->createTypefaceFromFcPattern(std::move(match));
579 }
580
581 sk_sp<SkTypeface> matchStyle(const SkFontStyle& style) override {
582 SkAutoFcPattern match([this, &style]() {
583 FCLocker lock;
584
585 SkAutoFcPattern pattern;
586 fcpattern_from_skfontstyle(style, pattern);
587 FcConfigSubstitute(fFontMgr->fFC, pattern, FcMatchPattern);
588 FcDefaultSubstitute(pattern);
589
590 FcResult result;
591 FcFontSet* fontSets[1] = { fFontSet };
592 return FcFontSetMatch(fFontMgr->fFC,
593 fontSets, std::size(fontSets),
594 pattern, &result);
595
596 }());
597 return fFontMgr->createTypefaceFromFcPattern(std::move(match));
598 }
599
600 private:
602 SkAutoFcFontSet fFontSet;
603 };
604
605 static bool FindName(const SkTDArray<const char*>& list, const char* str) {
606 int count = list.size();
607 for (int i = 0; i < count; ++i) {
608 if (!strcmp(list[i], str)) {
609 return true;
610 }
611 }
612 return false;
613 }
614
615 static sk_sp<SkDataTable> GetFamilyNames(FcConfig* fcconfig) {
616 FCLocker lock;
617
619 SkTDArray<size_t> sizes;
620
621 static const FcSetName fcNameSet[] = { FcSetSystem, FcSetApplication };
622 for (int setIndex = 0; setIndex < (int)std::size(fcNameSet); ++setIndex) {
623 // Return value of FcConfigGetFonts must not be destroyed.
624 FcFontSet* allFonts(FcConfigGetFonts(fcconfig, fcNameSet[setIndex]));
625 if (nullptr == allFonts) {
626 continue;
627 }
628
629 for (int fontIndex = 0; fontIndex < allFonts->nfont; ++fontIndex) {
630 FcPattern* current = allFonts->fonts[fontIndex];
631 for (int id = 0; ; ++id) {
632 FcChar8* fcFamilyName;
633 FcResult result = FcPatternGetString(current, FC_FAMILY, id, &fcFamilyName);
634 if (FcResultNoId == result) {
635 break;
636 }
637 if (FcResultMatch != result) {
638 continue;
639 }
640 const char* familyName = reinterpret_cast<const char*>(fcFamilyName);
641 if (familyName && !FindName(names, familyName)) {
642 *names.append() = familyName;
643 *sizes.append() = strlen(familyName) + 1;
644 }
645 }
646 }
647 }
648
649 return SkDataTable::MakeCopyArrays((void const *const *)names.begin(),
650 sizes.begin(), names.size());
651 }
652
653 static bool FindByFcPattern(SkTypeface* cached, void* ctx) {
654 SkTypeface_fontconfig* cshFace = static_cast<SkTypeface_fontconfig*>(cached);
655 FcPattern* ctxPattern = static_cast<FcPattern*>(ctx);
656 return FcTrue == FcPatternEqual(cshFace->fPattern, ctxPattern);
657 }
658
659 mutable SkMutex fTFCacheMutex;
660 mutable SkTypefaceCache fTFCache;
661 /** Creates a typeface using a typeface cache.
662 * @param pattern a complete pattern from FcFontRenderPrepare.
663 */
664 sk_sp<SkTypeface> createTypefaceFromFcPattern(SkAutoFcPattern pattern) const {
665 if (!pattern) {
666 return nullptr;
667 }
668 // Cannot hold FCLocker when calling fTFCache.add; an evicted typeface may need to lock.
669 // Must hold fTFCacheMutex when interacting with fTFCache.
670 SkAutoMutexExclusive ama(fTFCacheMutex);
671 sk_sp<SkTypeface> face = [&]() {
672 FCLocker lock;
673 sk_sp<SkTypeface> face = fTFCache.findByProcAndRef(FindByFcPattern, pattern);
674 if (face) {
675 pattern.reset();
676 }
677 return face;
678 }();
679 if (!face) {
680 face = SkTypeface_fontconfig::Make(std::move(pattern), fSysroot);
681 if (face) {
682 // Cannot hold FCLocker in fTFCache.add; evicted typefaces may need to lock.
683 fTFCache.add(face);
684 }
685 }
686 return face;
687 }
688
689public:
690 /** Takes control of the reference to 'config'. */
691 explicit SkFontMgr_fontconfig(FcConfig* config)
692 : fFC(config ? config : FcInitLoadConfigAndFonts())
693 , fSysroot(reinterpret_cast<const char*>(FcConfigGetSysRoot(fFC)))
694 , fFamilyNames(GetFamilyNames(fFC)) { }
695
697 // Hold the lock while unrefing the config.
698 FCLocker lock;
699 fFC.reset();
700 }
701
702protected:
703 int onCountFamilies() const override {
704 return fFamilyNames->count();
705 }
706
707 void onGetFamilyName(int index, SkString* familyName) const override {
708 familyName->set(fFamilyNames->atStr(index));
709 }
710
711 sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override {
712 return this->onMatchFamily(fFamilyNames->atStr(index));
713 }
714
715 /** True if any string object value in the font is the same
716 * as a string object value in the pattern.
717 */
718 static bool AnyStringMatching(FcPattern* font, FcPattern* pattern, const char* object) {
719 auto getStrings = [](FcPattern* p, const char* object, STArray<32, FcChar8*>& strings) {
720 // Set an arbitrary (but high) limit on the number of pattern object values to consider.
721 static constexpr const int maxId = 65536;
722 for (int patternId = 0; patternId < maxId; ++patternId) {
723 FcChar8* patternString;
724 FcResult result = FcPatternGetString(p, object, patternId, &patternString);
725 if (result == FcResultNoId) {
726 break;
727 }
728 if (result == FcResultMatch) {
729 strings.push_back(patternString);
730 }
731 }
732 };
733 auto compareStrings = [](FcChar8* a, FcChar8* b) -> bool {
734 return FcStrCmpIgnoreCase(a, b) < 0;
735 };
736
737 STArray<32, FcChar8*> fontStrings;
738 STArray<32, FcChar8*> patternStrings;
739 getStrings(font, object, fontStrings);
740 getStrings(pattern, object, patternStrings);
741
742 SkTQSort(fontStrings.begin(), fontStrings.end(), compareStrings);
743 SkTQSort(patternStrings.begin(), patternStrings.end(), compareStrings);
744
745 FcChar8** fontString = fontStrings.begin();
746 FcChar8** patternString = patternStrings.begin();
747 while (fontString != fontStrings.end() && patternString != patternStrings.end()) {
748 int cmp = FcStrCmpIgnoreCase(*fontString, *patternString);
749 if (cmp < 0) {
750 ++fontString;
751 } else if (cmp > 0) {
752 ++patternString;
753 } else {
754 return true;
755 }
756 }
757 return false;
758 }
759
760 bool FontAccessible(FcPattern* font) const {
761 // FontConfig can return fonts which are unreadable.
762 const char* filename = get_string(font, FC_FILE, nullptr);
763 if (nullptr == filename) {
764 return false;
765 }
766
767 // When sysroot was implemented in e96d7760886a3781a46b3271c76af99e15cb0146 (before 2.11.0)
768 // it was broken; mostly fixed in d17f556153fbaf8fe57fdb4fc1f0efa4313f0ecf (after 2.11.1).
769 // This leaves Debian 8 and 9 with broken support for this feature.
770 // As a result, this feature should not be used until at least 2.11.91.
771 // The broken support is mostly around not making all paths relative to the sysroot.
772 // However, even at 2.13.1 it is possible to get a mix of sysroot and non-sysroot paths,
773 // as any added file path not lexically starting with the sysroot will be unchanged.
774 // To allow users to add local app files outside the sysroot,
775 // prefer the sysroot but also look without the sysroot.
776 if (!fSysroot.isEmpty()) {
777 SkString resolvedFilename;
778 resolvedFilename = fSysroot;
779 resolvedFilename += filename;
780 if (sk_exists(resolvedFilename.c_str(), kRead_SkFILE_Flag)) {
781 return true;
782 }
783 }
784 return sk_exists(filename, kRead_SkFILE_Flag);
785 }
786
787 static bool FontFamilyNameMatches(FcPattern* font, FcPattern* pattern) {
788 return AnyStringMatching(font, pattern, FC_FAMILY);
789 }
790
791 static bool FontContainsCharacter(FcPattern* font, uint32_t character) {
792 FcResult result;
793 FcCharSet* matchCharSet;
794 for (int charSetId = 0; ; ++charSetId) {
795 result = FcPatternGetCharSet(font, FC_CHARSET, charSetId, &matchCharSet);
796 if (FcResultNoId == result) {
797 break;
798 }
799 if (FcResultMatch != result) {
800 continue;
801 }
802 if (FcCharSetHasChar(matchCharSet, character)) {
803 return true;
804 }
805 }
806 return false;
807 }
808
809 sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override {
810 if (!familyName) {
811 return nullptr;
812 }
813 FCLocker lock;
814
815 SkAutoFcPattern pattern;
816 FcPatternAddString(pattern, FC_FAMILY, (const FcChar8*)familyName);
817 FcConfigSubstitute(fFC, pattern, FcMatchPattern);
818 FcDefaultSubstitute(pattern);
819
820 FcPattern* matchPattern;
821 SkAutoFcPattern strongPattern(nullptr);
822 if (familyName) {
823 strongPattern.reset(FcPatternDuplicate(pattern));
824 remove_weak(strongPattern, FC_FAMILY);
825 matchPattern = strongPattern;
826 } else {
827 matchPattern = pattern;
828 }
829
831 // TODO: Some families have 'duplicates' due to symbolic links.
832 // The patterns are exactly the same except for the FC_FILE.
833 // It should be possible to collapse these patterns by normalizing.
834 static const FcSetName fcNameSet[] = { FcSetSystem, FcSetApplication };
835 for (int setIndex = 0; setIndex < (int)std::size(fcNameSet); ++setIndex) {
836 // Return value of FcConfigGetFonts must not be destroyed.
837 FcFontSet* allFonts(FcConfigGetFonts(fFC, fcNameSet[setIndex]));
838 if (nullptr == allFonts) {
839 continue;
840 }
841
842 for (int fontIndex = 0; fontIndex < allFonts->nfont; ++fontIndex) {
843 FcPattern* font = allFonts->fonts[fontIndex];
844 if (FontAccessible(font) && FontFamilyNameMatches(font, matchPattern)) {
845 FcFontSetAdd(matches, FcFontRenderPrepare(fFC, pattern, font));
846 }
847 }
848 }
849
850 return sk_sp<SkFontStyleSet>(new StyleSet(sk_ref_sp(this), std::move(matches)));
851 }
852
853 sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[],
854 const SkFontStyle& style) const override
855 {
856 SkAutoFcPattern font([this, &familyName, &style]() {
857 FCLocker lock;
858
859 SkAutoFcPattern pattern;
860 FcPatternAddString(pattern, FC_FAMILY, (const FcChar8*)familyName);
861 fcpattern_from_skfontstyle(style, pattern);
862 FcConfigSubstitute(fFC, pattern, FcMatchPattern);
863 FcDefaultSubstitute(pattern);
864
865 // We really want to match strong (preferred) and same (acceptable) only here.
866 // If a family name was specified, assume that any weak matches after the last strong
867 // match are weak (default) and ignore them.
868 // After substitution the pattern for 'sans-serif' looks like "wwwwwwwwwwwwwwswww" where
869 // there are many weak but preferred names, followed by defaults.
870 // So it is possible to have weakly matching but preferred names.
871 // In aliases, bindings are weak by default, so this is easy and common.
872 // If no family name was specified, we'll probably only get weak matches, but that's ok.
873 FcPattern* matchPattern;
874 SkAutoFcPattern strongPattern(nullptr);
875 if (familyName) {
876 strongPattern.reset(FcPatternDuplicate(pattern));
877 remove_weak(strongPattern, FC_FAMILY);
878 matchPattern = strongPattern;
879 } else {
880 matchPattern = pattern;
881 }
882
883 FcResult result;
884 SkAutoFcPattern font(FcFontMatch(fFC, pattern, &result));
885 if (!font || !FontAccessible(font) || !FontFamilyNameMatches(font, matchPattern)) {
886 font.reset();
887 }
888 return font;
889 }());
890 return createTypefaceFromFcPattern(std::move(font));
891 }
892
894 const SkFontStyle& style,
895 const char* bcp47[],
896 int bcp47Count,
897 SkUnichar character) const override
898 {
899 SkAutoFcPattern font([&](){
900 FCLocker lock;
901
902 SkAutoFcPattern pattern;
903 if (familyName) {
904 FcValue familyNameValue;
905 familyNameValue.type = FcTypeString;
906 familyNameValue.u.s = reinterpret_cast<const FcChar8*>(familyName);
907 FcPatternAddWeak(pattern, FC_FAMILY, familyNameValue, FcFalse);
908 }
909 fcpattern_from_skfontstyle(style, pattern);
910
911 SkAutoFcCharSet charSet;
912 FcCharSetAddChar(charSet, character);
913 FcPatternAddCharSet(pattern, FC_CHARSET, charSet);
914
915 if (bcp47Count > 0) {
916 SkASSERT(bcp47);
917 SkAutoFcLangSet langSet;
918 for (int i = bcp47Count; i --> 0;) {
919 FcLangSetAdd(langSet, (const FcChar8*)bcp47[i]);
920 }
921 FcPatternAddLangSet(pattern, FC_LANG, langSet);
922 }
923
924 FcConfigSubstitute(fFC, pattern, FcMatchPattern);
925 FcDefaultSubstitute(pattern);
926
927 FcResult result;
928 SkAutoFcPattern font(FcFontMatch(fFC, pattern, &result));
930 font.reset();
931 }
932 return font;
933 }());
934 return createTypefaceFromFcPattern(std::move(font));
935 }
936
937 sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
938 int ttcIndex) const override {
939 return this->makeFromStream(std::move(stream),
940 SkFontArguments().setCollectionIndex(ttcIndex));
941 }
942
943 sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
944 const SkFontArguments& args) const override {
945 const size_t length = stream->getLength();
946 if (length <= 0 || (1u << 30) < length) {
947 return nullptr;
948 }
950 }
951
952 sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
953 return this->makeFromStream(std::make_unique<SkMemoryStream>(std::move(data)), ttcIndex);
954 }
955
956 sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
957 return this->makeFromStream(SkStream::MakeFromFile(path), ttcIndex);
958 }
959
960 sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override {
961 sk_sp<SkTypeface> typeface(this->matchFamilyStyle(familyName, style));
962 if (typeface) {
963 return typeface;
964 }
965
966 return sk_sp<SkTypeface>(this->matchFamilyStyle(nullptr, style));
967 }
968};
969
971 return sk_make_sp<SkFontMgr_fontconfig>(fc);
972}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
int count
Definition: FontMgrTest.cpp:50
#define SkASSERT_RELEASE(cond)
Definition: SkAssert.h:100
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkAutoFc< FcFontSet, FcFontSetCreate, FcFontSetDestroy > SkAutoFcFontSet
static const FcMatrix * get_matrix(FcPattern *pattern, const char object[])
static void remove_weak(FcPattern *pattern, const char object[])
static bool get_bool(FcPattern *pattern, const char object[], bool missing=false)
static int get_int(FcPattern *pattern, const char object[], int missing)
SkAutoFc< FcPattern, FcPatternCreate, FcPatternDestroy > SkAutoFcPattern
#define FC_POSTSCRIPT_NAME
static SkFontStyle skfontstyle_from_fcpattern(FcPattern *pattern)
void FcTDestroy(T *t)
#define FC_WEIGHT_DEMILIGHT
static SkWeakReturn is_weak(FcPattern *pattern, const char object[], int id)
SkAutoFc< FcConfig, FcConfigCreate, FcConfigDestroy > SkAutoFcConfig
sk_sp< SkFontMgr > SkFontMgr_New_FontConfig(FcConfig *fc)
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)
SkAutoFc< FcObjectSet, FcObjectSetCreate, FcObjectSetDestroy > SkAutoFcObjectSet
@ kIsWeak_WeakReturn
@ kIsStrong_WeakReturn
@ kNoId_WeakReturn
SkAutoFc< FcLangSet, FcLangSetCreate, FcLangSetDestroy > SkAutoFcLangSet
SkAutoFc< FcCharSet, FcCharSetCreate, FcCharSetDestroy > SkAutoFcCharSet
static const char * get_string(FcPattern *pattern, const char object[], const char *missing="")
bool sk_exists(const char *path, SkFILE_Flags=(SkFILE_Flags) 0)
@ kRead_SkFILE_Flag
Definition: SkOSFile.h:20
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
#define SkScalarRoundToInt(x)
Definition: SkScalar.h:37
void SkTQSort(T *begin, T *end, const C &lessThan)
Definition: SkTSort.h:194
#define SK_NO_THREAD_SAFETY_ANALYSIS
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
int32_t SkUnichar
Definition: SkTypes.h:175
SkAutoFc(const SkAutoFc &)=delete
SkAutoFc(SkAutoFc &&that)
int count() const
Definition: SkDataTable.h:33
const char * atStr(int index) const
Definition: SkDataTable.h:59
static sk_sp< SkDataTable > MakeCopyArrays(const void *const *ptrs, const size_t sizes[], int count)
Definition: SkDataTable.cpp:92
Definition: SkData.h:25
void setFactoryId(SkTypeface::FactoryId factoryId)
bool FontAccessible(FcPattern *font) const
sk_sp< SkTypeface > onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override
void onGetFamilyName(int index, SkString *familyName) const override
sk_sp< SkTypeface > onMakeFromStreamIndex(std::unique_ptr< SkStreamAsset > stream, int ttcIndex) const override
sk_sp< SkFontStyleSet > onMatchFamily(const char familyName[]) const override
SkFontMgr_fontconfig(FcConfig *config)
sk_sp< SkTypeface > onMakeFromData(sk_sp< SkData > data, int ttcIndex) const override
sk_sp< SkTypeface > onMatchFamilyStyle(const char familyName[], const SkFontStyle &style) const override
sk_sp< SkFontStyleSet > onCreateStyleSet(int index) const override
static bool FontFamilyNameMatches(FcPattern *font, FcPattern *pattern)
static bool FontContainsCharacter(FcPattern *font, uint32_t character)
sk_sp< SkTypeface > onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle &style, const char *bcp47[], int bcp47Count, SkUnichar character) const override
int onCountFamilies() const override
sk_sp< SkTypeface > onMakeFromFile(const char path[], int ttcIndex) const override
sk_sp< SkTypeface > onMakeFromStreamArgs(std::unique_ptr< SkStreamAsset > stream, const SkFontArguments &args) const override
static bool AnyStringMatching(FcPattern *font, FcPattern *pattern, const char *object)
sk_sp< SkTypeface > makeFromStream(std::unique_ptr< SkStreamAsset >, int ttcIndex=0) const
Definition: SkFontMgr.cpp:127
sk_sp< SkTypeface > matchFamilyStyle(const char familyName[], const SkFontStyle &) const
Definition: SkFontMgr.cpp:109
Slant slant() const
Definition: SkFontStyle.h:64
int width() const
Definition: SkFontStyle.h:63
int weight() const
Definition: SkFontStyle.h:62
SkScalar getSkewY() const
Definition: SkMatrix.h:430
SkMatrix & setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2)
Definition: SkMatrix.h:562
SkScalar getSkewX() const
Definition: SkMatrix.h:438
SkScalar getScaleX() const
Definition: SkMatrix.h:415
SkMatrix & preConcat(const SkMatrix &other)
Definition: SkMatrix.cpp:674
SkScalar getScaleY() const
Definition: SkMatrix.h:422
static std::unique_ptr< SkStreamAsset > MakeFromFile(const char path[])
Definition: SkStream.cpp:922
void set(const SkString &src)
Definition: SkString.h:186
bool isEmpty() const
Definition: SkString.h:130
const char * c_str() const
Definition: SkString.h:133
int size() const
Definition: SkTDArray.h:138
T * begin()
Definition: SkTDArray.h:150
T * append()
Definition: SkTDArray.h:191
sk_sp< SkTypeface > findByProcAndRef(FindProc proc, void *ctx) const
void add(sk_sp< SkTypeface >)
std::unique_ptr< SkAdvancedTypefaceMetrics > onGetAdvancedMetrics() const override
std::unique_ptr< SkFontData > cloneFontData(const SkFontArguments &, SkFontStyle *style) const
void onFilterRec(SkScalerContextRec *) const override
SkTypeface_FreeType(const SkFontStyle &style, bool isFixedPitch)
static sk_sp< SkTypeface > MakeFromStream(std::unique_ptr< SkStreamAsset >, const SkFontArguments &)
std::unique_ptr< SkFontData > onMakeFontData() const override
void onFilterRec(SkScalerContextRec *rec) const override
void onGetFontDescriptor(SkFontDescriptor *desc, bool *serialize) const override
static sk_sp< SkTypeface_fontconfig > Make(SkAutoFcPattern pattern, SkString sysroot)
void onGetFamilyName(SkString *familyName) const override
std::unique_ptr< SkStreamAsset > onOpenStream(int *ttcIndex) const override
std::unique_ptr< SkAdvancedTypefaceMetrics > onGetAdvancedMetrics() const override
sk_sp< SkTypeface > onMakeClone(const SkFontArguments &args) const override
void getFamilyName(SkString *name) const
Definition: SkTypeface.cpp:459
SkFontStyle fontStyle() const
Definition: SkTypeface.h:55
void serialize(SkWStream *, SerializeBehavior=SerializeBehavior::kIncludeDataIfLocal) const
Definition: SkTypeface.cpp:202
bool isFixedPitch() const
Definition: SkTypeface.h:68
SkFourByteTag FactoryId
Definition: SkTypeface.h:335
void reset(T *ptr=nullptr)
Definition: SkRefCnt.h:310
#define C(TEST_CATEGORY)
Definition: colrv1.cpp:248
float SkScalar
Definition: extension.cpp:12
static bool b
struct MyStruct a[10]
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint8_t value
GAsyncResult * result
size_t length
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
def match(bench, filt)
Definition: benchmark.py:23
static const char *const names[]
Definition: symbols.cc:24
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
Definition: switches.h:57
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
Definition: switches.h:259
def matches(file)
Definition: gen_manifest.py:38
font
Font Metadata and Metrics.
Definition: ref_ptr.h:256
#define T
Definition: precompiler.cc:65
int32_t width
void getMatrixFrom2x2(SkMatrix *) const
SkScalar fPost2x2[2][2]
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
const uintptr_t id