Source code

Revision control

Other Tools

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