blob: 3baec41cb541d0a0a5b2a40f9423f35431cd14e3 [file] [log] [blame]
bungemana6785cc2014-08-25 12:00:49 -07001/*
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 "SkDataTable.h"
9#include "SkFontDescriptor.h"
10#include "SkFontHost_FreeType_common.h"
11#include "SkFontMgr.h"
12#include "SkFontStyle.h"
13#include "SkMath.h"
14#include "SkString.h"
15#include "SkStream.h"
16#include "SkTDArray.h"
17#include "SkThread.h"
18#include "SkTypefaceCache.h"
19#include "SkOSFile.h"
20
21#include <fontconfig/fontconfig.h>
22
23// FC_POSTSCRIPT_NAME was added with b561ff20 which ended up in 2.10.92
24// Ubuntu 12.04 is on 2.8.0, 13.10 is on 2.10.93
25// Debian 7 is on 2.9.0, 8 is on 2.11
26// OpenSUSE 12.2 is on 2.9.0, 12.3 is on 2.10.2, 13.1 2.11.0
27// Fedora 19 is on 2.10.93
28#ifndef FC_POSTSCRIPT_NAME
29# define FC_POSTSCRIPT_NAME "postscriptname"
30#endif
31
32#ifdef SK_DEBUG
33# include "SkTLS.h"
34#endif
35
36/** Since FontConfig is poorly documented, this gives a high level overview:
37 *
38 * FcConfig is a handle to a FontConfig configuration instance. Each 'configuration' is independent
39 * from any others which may exist. There exists a default global configuration which is created
40 * and destroyed by FcInit and FcFini, but this default should not normally be used.
41 * Instead, one should use FcConfigCreate and FcInit* to have a named local state.
42 *
43 * FcPatterns are {objectName -> [element]} (maps from object names to a list of elements).
44 * Each element is some internal data plus an FcValue which is a variant (a union with a type tag).
45 * Lists of elements are not typed, except by convention. Any collection of FcValues must be
46 * assumed to be heterogeneous by the code, but the code need not do anything particularly
47 * interesting if the values go against convention.
48 *
49 * Somewhat like DirectWrite, FontConfig supports synthetics through FC_EMBOLDEN and FC_MATRIX.
50 * Like all synthetic information, such information must be passed with the font data.
51 */
52
53namespace {
54
55// Fontconfig is not threadsafe before 2.10.91. Before that, we lock with a global mutex.
56// See http://skbug.com/1497 for background.
57SK_DECLARE_STATIC_MUTEX(gFCMutex);
58
59#ifdef SK_DEBUG
bungemanf87650c2014-08-26 13:47:20 -070060 void *CreateThreadFcLocked() { return SkNEW_ARGS(bool, (false)); }
bungemana6785cc2014-08-25 12:00:49 -070061 void DeleteThreadFcLocked(void* v) { SkDELETE(static_cast<bool*>(v)); }
62# define THREAD_FC_LOCKED \
63 static_cast<bool*>(SkTLS::Get(CreateThreadFcLocked, DeleteThreadFcLocked))
64#endif
65
66struct FCLocker {
67 // Assume FcGetVersion() has always been thread safe.
68
69 FCLocker() {
70 if (FcGetVersion() < 21091) {
71 gFCMutex.acquire();
72 } else {
73 SkDEBUGCODE(bool* threadLocked = THREAD_FC_LOCKED);
74 SkASSERT(false == *threadLocked);
75 SkDEBUGCODE(*threadLocked = true);
76 }
77 }
78
79 ~FCLocker() {
80 AssertHeld();
81 if (FcGetVersion() < 21091) {
82 gFCMutex.release();
83 } else {
84 SkDEBUGCODE(*THREAD_FC_LOCKED = false);
85 }
86 }
87
88 static void AssertHeld() { SkDEBUGCODE(
89 if (FcGetVersion() < 21091) {
90 gFCMutex.assertHeld();
91 } else {
92 SkASSERT(true == *THREAD_FC_LOCKED);
93 }
94 ) }
95};
96
97} // namespace
98
bungeman6bc2c942014-09-09 12:50:36 -070099template<typename T, void (*D)(T*)> void FcTDestroy(T* t) {
bungemana6785cc2014-08-25 12:00:49 -0700100 FCLocker::AssertHeld();
bungeman6bc2c942014-09-09 12:50:36 -0700101 D(t);
bungemana6785cc2014-08-25 12:00:49 -0700102}
bungeman6bc2c942014-09-09 12:50:36 -0700103template <typename T, T* (*C)(), void (*D)(T*)> class SkAutoFc
104 : public SkAutoTCallVProc<T, FcTDestroy<T, D> > {
bungemana6785cc2014-08-25 12:00:49 -0700105public:
bungeman6bc2c942014-09-09 12:50:36 -0700106 SkAutoFc() : SkAutoTCallVProc<T, FcTDestroy<T, D> >(C()) {
107 T* obj = this->operator T*();
108 SK_ALWAYSBREAK(NULL != obj);
109 }
110 explicit SkAutoFc(T* obj) : SkAutoTCallVProc<T, FcTDestroy<T, D> >(obj) {}
bungemana6785cc2014-08-25 12:00:49 -0700111};
112
bungeman6bc2c942014-09-09 12:50:36 -0700113typedef SkAutoFc<FcCharSet, FcCharSetCreate, FcCharSetDestroy> SkAutoFcCharSet;
114typedef SkAutoFc<FcConfig, FcConfigCreate, FcConfigDestroy> SkAutoFcConfig;
115typedef SkAutoFc<FcFontSet, FcFontSetCreate, FcFontSetDestroy> SkAutoFcFontSet;
116typedef SkAutoFc<FcLangSet, FcLangSetCreate, FcLangSetDestroy> SkAutoFcLangSet;
117typedef SkAutoFc<FcObjectSet, FcObjectSetCreate, FcObjectSetDestroy> SkAutoFcObjectSet;
118typedef SkAutoFc<FcPattern, FcPatternCreate, FcPatternDestroy> SkAutoFcPattern;
bungemana6785cc2014-08-25 12:00:49 -0700119
120static int get_int(FcPattern* pattern, const char object[], int missing) {
121 int value;
122 if (FcPatternGetInteger(pattern, object, 0, &value) != FcResultMatch) {
123 return missing;
124 }
125 return value;
126}
127
128static const char* get_string(FcPattern* pattern, const char object[], const char* missing = "") {
129 FcChar8* value;
130 if (FcPatternGetString(pattern, object, 0, &value) != FcResultMatch) {
131 return missing;
132 }
133 return (const char*)value;
134}
135
136enum SkWeakReturn {
137 kIsWeak_WeakReturn,
138 kIsStrong_WeakReturn,
139 kNoId_WeakReturn
140};
141/** Ideally there would exist a call like
142 * FcResult FcPatternIsWeak(pattern, object, id, FcBool* isWeak);
143 *
144 * However, there is no such call and as of Fc 2.11.0 even FcPatternEquals ignores the weak bit.
145 * Currently, the only reliable way of finding the weak bit is by its effect on matching.
146 * The weak bit only affects the matching of FC_FAMILY and FC_POSTSCRIPT_NAME object values.
147 * A element with the weak bit is scored after FC_LANG, without the weak bit is scored before.
148 * Note that the weak bit is stored on the element, not on the value it holds.
149 */
150static SkWeakReturn is_weak(FcPattern* pattern, const char object[], int id) {
151 FCLocker::AssertHeld();
152
153 FcResult result;
154
155 // Create a copy of the pattern with only the value 'pattern'['object'['id']] in it.
156 // Internally, FontConfig pattern objects are linked lists, so faster to remove from head.
157 SkAutoFcObjectSet requestedObjectOnly(FcObjectSetBuild(object, NULL));
158 SkAutoFcPattern minimal(FcPatternFilter(pattern, requestedObjectOnly));
159 FcBool hasId = true;
160 for (int i = 0; hasId && i < id; ++i) {
161 hasId = FcPatternRemove(minimal, object, 0);
162 }
163 if (!hasId) {
164 return kNoId_WeakReturn;
165 }
166 FcValue value;
167 result = FcPatternGet(minimal, object, 0, &value);
168 if (result != FcResultMatch) {
169 return kNoId_WeakReturn;
170 }
171 while (hasId) {
172 hasId = FcPatternRemove(minimal, object, 1);
173 }
174
175 // Create a font set with two patterns.
176 // 1. the same 'object' as minimal and a lang object with only 'nomatchlang'.
177 // 2. a different 'object' from minimal and a lang object with only 'matchlang'.
bungeman6bc2c942014-09-09 12:50:36 -0700178 SkAutoFcFontSet fontSet;
bungemana6785cc2014-08-25 12:00:49 -0700179
bungeman6bc2c942014-09-09 12:50:36 -0700180 SkAutoFcLangSet strongLangSet;
bungemana6785cc2014-08-25 12:00:49 -0700181 FcLangSetAdd(strongLangSet, (const FcChar8*)"nomatchlang");
182 SkAutoFcPattern strong(FcPatternDuplicate(minimal));
183 FcPatternAddLangSet(strong, FC_LANG, strongLangSet);
184
bungeman6bc2c942014-09-09 12:50:36 -0700185 SkAutoFcLangSet weakLangSet;
bungemana6785cc2014-08-25 12:00:49 -0700186 FcLangSetAdd(weakLangSet, (const FcChar8*)"matchlang");
bungeman6bc2c942014-09-09 12:50:36 -0700187 SkAutoFcPattern weak;
bungemana6785cc2014-08-25 12:00:49 -0700188 FcPatternAddString(weak, object, (const FcChar8*)"nomatchstring");
189 FcPatternAddLangSet(weak, FC_LANG, weakLangSet);
190
191 FcFontSetAdd(fontSet, strong.detach());
192 FcFontSetAdd(fontSet, weak.detach());
193
194 // Add 'matchlang' to the copy of the pattern.
195 FcPatternAddLangSet(minimal, FC_LANG, weakLangSet);
196
197 // Run a match against the copy of the pattern.
198 // If the 'id' was weak, then we should match the pattern with 'matchlang'.
199 // If the 'id' was strong, then we should match the pattern with 'nomatchlang'.
200
201 // Note that this config is only used for FcFontRenderPrepare, which we don't even want.
202 // However, there appears to be no way to match/sort without it.
bungeman6bc2c942014-09-09 12:50:36 -0700203 SkAutoFcConfig config;
bungemana6785cc2014-08-25 12:00:49 -0700204 FcFontSet* fontSets[1] = { fontSet };
205 SkAutoFcPattern match(FcFontSetMatch(config, fontSets, SK_ARRAY_COUNT(fontSets),
206 minimal, &result));
207
208 FcLangSet* matchLangSet;
209 FcPatternGetLangSet(match, FC_LANG, 0, &matchLangSet);
210 return FcLangEqual == FcLangSetHasLang(matchLangSet, (const FcChar8*)"matchlang")
211 ? kIsWeak_WeakReturn : kIsStrong_WeakReturn;
212}
213
214/** Removes weak elements from either FC_FAMILY or FC_POSTSCRIPT_NAME objects in the property.
215 * This can be quite expensive, and should not be used more than once per font lookup.
216 * This removes all of the weak elements after the last strong element.
217 */
218static void remove_weak(FcPattern* pattern, const char object[]) {
219 FCLocker::AssertHeld();
220
221 SkAutoFcObjectSet requestedObjectOnly(FcObjectSetBuild(object, NULL));
222 SkAutoFcPattern minimal(FcPatternFilter(pattern, requestedObjectOnly));
223
224 int lastStrongId = -1;
225 int numIds;
226 SkWeakReturn result;
227 for (int id = 0; ; ++id) {
228 result = is_weak(minimal, object, 0);
229 if (kNoId_WeakReturn == result) {
230 numIds = id;
231 break;
232 }
233 if (kIsStrong_WeakReturn == result) {
234 lastStrongId = id;
235 }
236 SkAssertResult(FcPatternRemove(minimal, object, 0));
237 }
238
239 // If they were all weak, then leave the pattern alone.
240 if (lastStrongId < 0) {
241 return;
242 }
243
244 // Remove everything after the last strong.
245 for (int id = lastStrongId + 1; id < numIds; ++id) {
246 SkAssertResult(FcPatternRemove(pattern, object, lastStrongId + 1));
247 }
248}
249
250static int map_range(SkFixed value,
251 SkFixed old_min, SkFixed old_max,
252 SkFixed new_min, SkFixed new_max)
253{
254 SkASSERT(old_min < old_max);
255 SkASSERT(new_min <= new_max);
256 return new_min + SkMulDiv(value - old_min, new_max - new_min, old_max - old_min);
257}
258
259static int ave(SkFixed a, SkFixed b) {
260 return SkFixedAve(a, b);
261}
262
263struct MapRanges {
264 SkFixed old_val;
265 SkFixed new_val;
266};
267
268static SkFixed map_ranges_fixed(SkFixed val, MapRanges const ranges[], int rangesCount) {
269 // -Inf to [0]
270 if (val < ranges[0].old_val) {
271 return ranges[0].new_val;
272 }
273
274 // Linear from [i] to ave([i], [i+1]), then from ave([i], [i+1]) to [i+1]
275 for (int i = 0; i < rangesCount - 1; ++i) {
276 if (val < ave(ranges[i].old_val, ranges[i+1].old_val)) {
277 return map_range(val, ranges[i].old_val, ave(ranges[i].old_val, ranges[i+1].old_val),
278 ranges[i].new_val, ave(ranges[i].new_val, ranges[i+1].new_val));
279 }
280 if (val < ranges[i+1].old_val) {
281 return map_range(val, ave(ranges[i].old_val, ranges[i+1].old_val), ranges[i+1].old_val,
282 ave(ranges[i].new_val, ranges[i+1].new_val), ranges[i+1].new_val);
283 }
284 }
285
286 // From [n] to +Inf
287 // if (fcweight < Inf)
288 return ranges[rangesCount-1].new_val;
289}
290
291static int map_ranges(int val, MapRanges const ranges[], int rangesCount) {
292 return SkFixedRoundToInt(map_ranges_fixed(SkIntToFixed(val), ranges, rangesCount));
293}
294
295template<int n> struct SkTFixed {
296 SK_COMPILE_ASSERT(-32768 <= n && n <= 32767, SkTFixed_n_not_in_range);
297 static const SkFixed value = static_cast<SkFixed>(n << 16);
298};
299
300static SkFontStyle skfontstyle_from_fcpattern(FcPattern* pattern) {
301 typedef SkFontStyle SkFS;
302
303 static const MapRanges weightRanges[] = {
304 { SkTFixed<FC_WEIGHT_THIN>::value, SkTFixed<SkFS::kThin_Weight>::value },
305 { SkTFixed<FC_WEIGHT_EXTRALIGHT>::value, SkTFixed<SkFS::kExtraLight_Weight>::value },
306 { SkTFixed<FC_WEIGHT_LIGHT>::value, SkTFixed<SkFS::kLight_Weight>::value },
307 { SkTFixed<FC_WEIGHT_REGULAR>::value, SkTFixed<SkFS::kNormal_Weight>::value },
308 { SkTFixed<FC_WEIGHT_MEDIUM>::value, SkTFixed<SkFS::kMedium_Weight>::value },
309 { SkTFixed<FC_WEIGHT_DEMIBOLD>::value, SkTFixed<SkFS::kSemiBold_Weight>::value },
310 { SkTFixed<FC_WEIGHT_BOLD>::value, SkTFixed<SkFS::kBold_Weight>::value },
311 { SkTFixed<FC_WEIGHT_EXTRABOLD>::value, SkTFixed<SkFS::kExtraBold_Weight>::value },
312 { SkTFixed<FC_WEIGHT_BLACK>::value, SkTFixed<SkFS::kBlack_Weight>::value },
313 { SkTFixed<FC_WEIGHT_EXTRABLACK>::value, SkTFixed<1000>::value },
314 };
315 int weight = map_ranges(get_int(pattern, FC_WEIGHT, FC_WEIGHT_REGULAR),
316 weightRanges, SK_ARRAY_COUNT(weightRanges));
317
318 static const MapRanges widthRanges[] = {
319 { SkTFixed<FC_WIDTH_ULTRACONDENSED>::value, SkTFixed<SkFS::kUltraCondensed_Width>::value },
320 { SkTFixed<FC_WIDTH_EXTRACONDENSED>::value, SkTFixed<SkFS::kExtraCondensed_Width>::value },
321 { SkTFixed<FC_WIDTH_CONDENSED>::value, SkTFixed<SkFS::kCondensed_Width>::value },
322 { SkTFixed<FC_WIDTH_SEMICONDENSED>::value, SkTFixed<SkFS::kSemiCondensed_Width>::value },
323 { SkTFixed<FC_WIDTH_NORMAL>::value, SkTFixed<SkFS::kNormal_Width>::value },
324 { SkTFixed<FC_WIDTH_SEMIEXPANDED>::value, SkTFixed<SkFS::kSemiExpanded_Width>::value },
325 { SkTFixed<FC_WIDTH_EXPANDED>::value, SkTFixed<SkFS::kExpanded_Width>::value },
326 { SkTFixed<FC_WIDTH_EXTRAEXPANDED>::value, SkTFixed<SkFS::kExtraExpanded_Width>::value },
327 { SkTFixed<FC_WIDTH_ULTRAEXPANDED>::value, SkTFixed<SkFS::kUltaExpanded_Width>::value },
328 };
329 int width = map_ranges(get_int(pattern, FC_WIDTH, FC_WIDTH_NORMAL),
330 widthRanges, SK_ARRAY_COUNT(widthRanges));
331
332 SkFS::Slant slant = get_int(pattern, FC_SLANT, FC_SLANT_ROMAN) > 0
333 ? SkFS::kItalic_Slant
334 : SkFS::kUpright_Slant;
335
336 return SkFontStyle(weight, width, slant);
337}
338
339static void fcpattern_from_skfontstyle(SkFontStyle style, FcPattern* pattern) {
340 FCLocker::AssertHeld();
341
342 typedef SkFontStyle SkFS;
343
344 static const MapRanges weightRanges[] = {
345 { SkTFixed<SkFS::kThin_Weight>::value, SkTFixed<FC_WEIGHT_THIN>::value },
346 { SkTFixed<SkFS::kExtraLight_Weight>::value, SkTFixed<FC_WEIGHT_EXTRALIGHT>::value },
347 { SkTFixed<SkFS::kLight_Weight>::value, SkTFixed<FC_WEIGHT_LIGHT>::value },
348 { SkTFixed<SkFS::kNormal_Weight>::value, SkTFixed<FC_WEIGHT_REGULAR>::value },
349 { SkTFixed<SkFS::kMedium_Weight>::value, SkTFixed<FC_WEIGHT_MEDIUM>::value },
350 { SkTFixed<SkFS::kSemiBold_Weight>::value, SkTFixed<FC_WEIGHT_DEMIBOLD>::value },
351 { SkTFixed<SkFS::kBold_Weight>::value, SkTFixed<FC_WEIGHT_BOLD>::value },
352 { SkTFixed<SkFS::kExtraBold_Weight>::value, SkTFixed<FC_WEIGHT_EXTRABOLD>::value },
353 { SkTFixed<SkFS::kBlack_Weight>::value, SkTFixed<FC_WEIGHT_BLACK>::value },
354 { SkTFixed<1000>::value, SkTFixed<FC_WEIGHT_EXTRABLACK>::value },
355 };
356 int weight = map_ranges(style.weight(), weightRanges, SK_ARRAY_COUNT(weightRanges));
357
358 static const MapRanges widthRanges[] = {
359 { SkTFixed<SkFS::kUltraCondensed_Width>::value, SkTFixed<FC_WIDTH_ULTRACONDENSED>::value },
360 { SkTFixed<SkFS::kExtraCondensed_Width>::value, SkTFixed<FC_WIDTH_EXTRACONDENSED>::value },
361 { SkTFixed<SkFS::kCondensed_Width>::value, SkTFixed<FC_WIDTH_CONDENSED>::value },
362 { SkTFixed<SkFS::kSemiCondensed_Width>::value, SkTFixed<FC_WIDTH_SEMICONDENSED>::value },
363 { SkTFixed<SkFS::kNormal_Width>::value, SkTFixed<FC_WIDTH_NORMAL>::value },
364 { SkTFixed<SkFS::kSemiExpanded_Width>::value, SkTFixed<FC_WIDTH_SEMIEXPANDED>::value },
365 { SkTFixed<SkFS::kExpanded_Width>::value, SkTFixed<FC_WIDTH_EXPANDED>::value },
366 { SkTFixed<SkFS::kExtraExpanded_Width>::value, SkTFixed<FC_WIDTH_EXTRAEXPANDED>::value },
367 { SkTFixed<SkFS::kUltaExpanded_Width>::value, SkTFixed<FC_WIDTH_ULTRAEXPANDED>::value },
368 };
369 int width = map_ranges(style.width(), widthRanges, SK_ARRAY_COUNT(widthRanges));
370
371 FcPatternAddInteger(pattern, FC_WEIGHT, weight);
372 FcPatternAddInteger(pattern, FC_WIDTH, width);
373 FcPatternAddInteger(pattern, FC_SLANT, style.isItalic() ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
374}
375
bungemana6785cc2014-08-25 12:00:49 -0700376class SkTypeface_stream : public SkTypeface_FreeType {
377public:
bungeman05773ed2015-05-13 10:57:09 -0700378 /** @param data takes ownership of the font data.*/
379 SkTypeface_stream(SkFontData* data, const SkFontStyle& style, bool fixedWidth)
bungemana6785cc2014-08-25 12:00:49 -0700380 : INHERITED(style, SkTypefaceCache::NewFontID(), fixedWidth)
bungeman05773ed2015-05-13 10:57:09 -0700381 , fData(data)
bungemana6785cc2014-08-25 12:00:49 -0700382 { };
383
mtklein36352bf2015-03-25 18:17:31 -0700384 void onGetFamilyName(SkString* familyName) const override {
bungemanb374d6a2014-09-17 07:48:59 -0700385 familyName->reset();
386 }
387
mtklein36352bf2015-03-25 18:17:31 -0700388 void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override {
bungemana6785cc2014-08-25 12:00:49 -0700389 *serialize = true;
390 }
391
mtklein36352bf2015-03-25 18:17:31 -0700392 SkStreamAsset* onOpenStream(int* ttcIndex) const override {
bungeman05773ed2015-05-13 10:57:09 -0700393 *ttcIndex = fData->getIndex();
394 return fData->duplicateStream();
395 }
396
397 SkFontData* onCreateFontData() const override {
398 return new SkFontData(*fData.get());
bungemana6785cc2014-08-25 12:00:49 -0700399 }
400
401private:
bungeman05773ed2015-05-13 10:57:09 -0700402 const SkAutoTDelete<const SkFontData> fData;
bungemana6785cc2014-08-25 12:00:49 -0700403
404 typedef SkTypeface_FreeType INHERITED;
405};
406
407class SkTypeface_fontconfig : public SkTypeface_FreeType {
408public:
409 /** @param pattern takes ownership of the reference. */
410 static SkTypeface_fontconfig* Create(FcPattern* pattern) {
411 return SkNEW_ARGS(SkTypeface_fontconfig, (pattern));
412 }
413 mutable SkAutoFcPattern fPattern;
414
mtklein36352bf2015-03-25 18:17:31 -0700415 void onGetFamilyName(SkString* familyName) const override {
bungemanb374d6a2014-09-17 07:48:59 -0700416 *familyName = get_string(fPattern, FC_FAMILY);
417 }
418
mtklein36352bf2015-03-25 18:17:31 -0700419 void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override {
bungemana6785cc2014-08-25 12:00:49 -0700420 FCLocker lock;
421 desc->setFamilyName(get_string(fPattern, FC_FAMILY));
bungemana6785cc2014-08-25 12:00:49 -0700422 desc->setFullName(get_string(fPattern, FC_FULLNAME));
423 desc->setPostscriptName(get_string(fPattern, FC_POSTSCRIPT_NAME));
bungemana6785cc2014-08-25 12:00:49 -0700424 *serialize = false;
425 }
426
mtklein36352bf2015-03-25 18:17:31 -0700427 SkStreamAsset* onOpenStream(int* ttcIndex) const override {
bungemana6785cc2014-08-25 12:00:49 -0700428 FCLocker lock;
429 *ttcIndex = get_int(fPattern, FC_INDEX, 0);
430 return SkStream::NewFromFile(get_string(fPattern, FC_FILE));
431 }
432
433 virtual ~SkTypeface_fontconfig() {
434 // Hold the lock while unrefing the pattern.
435 FCLocker lock;
436 fPattern.reset();
437 }
438
439private:
440 /** @param pattern takes ownership of the reference. */
441 SkTypeface_fontconfig(FcPattern* pattern)
bungemana4c4a2d2014-10-20 13:33:19 -0700442 : INHERITED(skfontstyle_from_fcpattern(pattern),
bungemana6785cc2014-08-25 12:00:49 -0700443 SkTypefaceCache::NewFontID(),
444 FC_PROPORTIONAL != get_int(pattern, FC_SPACING, FC_PROPORTIONAL))
445 , fPattern(pattern)
446 { };
447
448 typedef SkTypeface_FreeType INHERITED;
449};
450
451class SkFontMgr_fontconfig : public SkFontMgr {
452 mutable SkAutoFcConfig fFC;
453 SkAutoTUnref<SkDataTable> fFamilyNames;
bungeman14df8332014-10-28 15:07:23 -0700454 SkTypeface_FreeType::Scanner fScanner;
bungemana6785cc2014-08-25 12:00:49 -0700455
456 class StyleSet : public SkFontStyleSet {
457 public:
458 /** @param parent does not take ownership of the reference.
459 * @param fontSet takes ownership of the reference.
460 */
461 StyleSet(const SkFontMgr_fontconfig* parent, FcFontSet* fontSet)
462 : fFontMgr(SkRef(parent)), fFontSet(fontSet)
463 { }
464
465 virtual ~StyleSet() {
466 // Hold the lock while unrefing the font set.
467 FCLocker lock;
468 fFontSet.reset();
469 }
470
mtklein36352bf2015-03-25 18:17:31 -0700471 int count() override { return fFontSet->nfont; }
bungemana6785cc2014-08-25 12:00:49 -0700472
mtklein36352bf2015-03-25 18:17:31 -0700473 void getStyle(int index, SkFontStyle* style, SkString* styleName) override {
bungemana6785cc2014-08-25 12:00:49 -0700474 if (index < 0 || fFontSet->nfont <= index) {
475 return;
476 }
477
478 FCLocker lock;
479 if (style) {
480 *style = skfontstyle_from_fcpattern(fFontSet->fonts[index]);
481 }
482 if (styleName) {
483 *styleName = get_string(fFontSet->fonts[index], FC_STYLE);
484 }
485 }
486
mtklein36352bf2015-03-25 18:17:31 -0700487 SkTypeface* createTypeface(int index) override {
bungemana6785cc2014-08-25 12:00:49 -0700488 FCLocker lock;
489
490 FcPattern* match = fFontSet->fonts[index];
491 return fFontMgr->createTypefaceFromFcPattern(match);
492 }
493
mtklein36352bf2015-03-25 18:17:31 -0700494 SkTypeface* matchStyle(const SkFontStyle& style) override {
bungemana6785cc2014-08-25 12:00:49 -0700495 FCLocker lock;
496
bungeman6bc2c942014-09-09 12:50:36 -0700497 SkAutoFcPattern pattern;
bungemana6785cc2014-08-25 12:00:49 -0700498 fcpattern_from_skfontstyle(style, pattern);
499 FcConfigSubstitute(fFontMgr->fFC, pattern, FcMatchPattern);
500 FcDefaultSubstitute(pattern);
501
502 FcResult result;
503 FcFontSet* fontSets[1] = { fFontSet };
504 SkAutoFcPattern match(FcFontSetMatch(fFontMgr->fFC,
505 fontSets, SK_ARRAY_COUNT(fontSets),
506 pattern, &result));
507 if (NULL == match) {
508 return NULL;
509 }
510
511 return fFontMgr->createTypefaceFromFcPattern(match);
512 }
513
514 private:
515 SkAutoTUnref<const SkFontMgr_fontconfig> fFontMgr;
516 SkAutoFcFontSet fFontSet;
517 };
518
519 static bool FindName(const SkTDArray<const char*>& list, const char* str) {
520 int count = list.count();
521 for (int i = 0; i < count; ++i) {
522 if (!strcmp(list[i], str)) {
523 return true;
524 }
525 }
526 return false;
527 }
528
529 static SkDataTable* GetFamilyNames(FcConfig* fcconfig) {
530 FCLocker lock;
531
532 SkTDArray<const char*> names;
533 SkTDArray<size_t> sizes;
534
535 static const FcSetName fcNameSet[] = { FcSetSystem, FcSetApplication };
536 for (int setIndex = 0; setIndex < (int)SK_ARRAY_COUNT(fcNameSet); ++setIndex) {
537 // Return value of FcConfigGetFonts must not be destroyed.
538 FcFontSet* allFonts(FcConfigGetFonts(fcconfig, fcNameSet[setIndex]));
539 if (NULL == allFonts) {
540 continue;
541 }
542
543 for (int fontIndex = 0; fontIndex < allFonts->nfont; ++fontIndex) {
544 FcPattern* current = allFonts->fonts[fontIndex];
545 for (int id = 0; ; ++id) {
546 FcChar8* fcFamilyName;
547 FcResult result = FcPatternGetString(current, FC_FAMILY, id, &fcFamilyName);
548 if (FcResultNoId == result) {
549 break;
550 }
551 if (FcResultMatch != result) {
552 continue;
553 }
554 const char* familyName = reinterpret_cast<const char*>(fcFamilyName);
555 if (familyName && !FindName(names, familyName)) {
556 *names.append() = familyName;
557 *sizes.append() = strlen(familyName) + 1;
558 }
559 }
560 }
561 }
562
563 return SkDataTable::NewCopyArrays((void const *const *)names.begin(),
564 sizes.begin(), names.count());
565 }
566
bungemana4c4a2d2014-10-20 13:33:19 -0700567 static bool FindByFcPattern(SkTypeface* cached, const SkFontStyle&, void* ctx) {
bungemana6785cc2014-08-25 12:00:49 -0700568 SkTypeface_fontconfig* cshFace = static_cast<SkTypeface_fontconfig*>(cached);
569 FcPattern* ctxPattern = static_cast<FcPattern*>(ctx);
570 return FcTrue == FcPatternEqual(cshFace->fPattern, ctxPattern);
571 }
572
573 mutable SkMutex fTFCacheMutex;
574 mutable SkTypefaceCache fTFCache;
575 /** Creates a typeface using a typeface cache.
576 * @param pattern a complete pattern from FcFontRenderPrepare.
577 */
578 SkTypeface* createTypefaceFromFcPattern(FcPattern* pattern) const {
579 FCLocker::AssertHeld();
580 SkAutoMutexAcquire ama(fTFCacheMutex);
581 SkTypeface* face = fTFCache.findByProcAndRef(FindByFcPattern, pattern);
582 if (NULL == face) {
583 FcPatternReference(pattern);
584 face = SkTypeface_fontconfig::Create(pattern);
585 if (face) {
mtklein60b6e9d2014-10-24 10:43:15 -0700586 fTFCache.add(face, SkFontStyle());
bungemana6785cc2014-08-25 12:00:49 -0700587 }
588 }
589 return face;
590 }
591
592public:
593 SkFontMgr_fontconfig()
594 : fFC(FcInitLoadConfigAndFonts())
595 , fFamilyNames(GetFamilyNames(fFC)) { }
596
597 /** Takes control of the reference to 'config'. */
598 explicit SkFontMgr_fontconfig(FcConfig* config)
599 : fFC(config)
600 , fFamilyNames(GetFamilyNames(fFC)) { }
601
602 virtual ~SkFontMgr_fontconfig() {
603 // Hold the lock while unrefing the config.
604 FCLocker lock;
605 fFC.reset();
606 }
607
608protected:
mtklein36352bf2015-03-25 18:17:31 -0700609 int onCountFamilies() const override {
bungemana6785cc2014-08-25 12:00:49 -0700610 return fFamilyNames->count();
611 }
612
mtklein36352bf2015-03-25 18:17:31 -0700613 void onGetFamilyName(int index, SkString* familyName) const override {
bungemana6785cc2014-08-25 12:00:49 -0700614 familyName->set(fFamilyNames->atStr(index));
615 }
616
mtklein36352bf2015-03-25 18:17:31 -0700617 SkFontStyleSet* onCreateStyleSet(int index) const override {
bungemana6785cc2014-08-25 12:00:49 -0700618 return this->onMatchFamily(fFamilyNames->atStr(index));
619 }
620
621 /** True if any string object value in the font is the same
622 * as a string object value in the pattern.
623 */
624 static bool AnyMatching(FcPattern* font, FcPattern* pattern, const char* object) {
625 FcChar8* fontString;
626 FcChar8* patternString;
627 FcResult result;
628 // Set an arbitrary limit on the number of pattern object values to consider.
629 // TODO: re-write this to avoid N*M
630 static const int maxId = 16;
631 for (int patternId = 0; patternId < maxId; ++patternId) {
632 result = FcPatternGetString(pattern, object, patternId, &patternString);
633 if (FcResultNoId == result) {
634 break;
635 }
636 if (FcResultMatch != result) {
637 continue;
638 }
639 for (int fontId = 0; fontId < maxId; ++fontId) {
640 result = FcPatternGetString(font, object, fontId, &fontString);
641 if (FcResultNoId == result) {
642 break;
643 }
644 if (FcResultMatch != result) {
645 continue;
646 }
647 if (0 == FcStrCmpIgnoreCase(patternString, fontString)) {
648 return true;
649 }
650 }
651 }
652 return false;
653 }
654
bungeman6bc2c942014-09-09 12:50:36 -0700655 static bool FontAccessible(FcPattern* font) {
bungemana6785cc2014-08-25 12:00:49 -0700656 // FontConfig can return fonts which are unreadable.
bungeman6bc2c942014-09-09 12:50:36 -0700657 const char* filename = get_string(font, FC_FILE, NULL);
bungemana6785cc2014-08-25 12:00:49 -0700658 if (NULL == filename) {
659 return false;
660 }
661 return sk_exists(filename, kRead_SkFILE_Flag);
662 }
663
bungeman6bc2c942014-09-09 12:50:36 -0700664 static bool FontFamilyNameMatches(FcPattern* font, FcPattern* pattern) {
665 return AnyMatching(font, pattern, FC_FAMILY);
666 }
667
668 static bool FontContainsCharacter(FcPattern* font, uint32_t character) {
669 FcResult result;
670 FcCharSet* matchCharSet;
671 for (int charSetId = 0; ; ++charSetId) {
672 result = FcPatternGetCharSet(font, FC_CHARSET, charSetId, &matchCharSet);
673 if (FcResultNoId == result) {
674 break;
675 }
676 if (FcResultMatch != result) {
677 continue;
678 }
679 if (FcCharSetHasChar(matchCharSet, character)) {
680 return true;
681 }
682 }
683 return false;
bungemana6785cc2014-08-25 12:00:49 -0700684 }
685
mtklein36352bf2015-03-25 18:17:31 -0700686 SkFontStyleSet* onMatchFamily(const char familyName[]) const override {
bungemana6785cc2014-08-25 12:00:49 -0700687 FCLocker lock;
688
bungeman6bc2c942014-09-09 12:50:36 -0700689 SkAutoFcPattern pattern;
bungemana6785cc2014-08-25 12:00:49 -0700690 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
691 FcConfigSubstitute(fFC, pattern, FcMatchPattern);
692 FcDefaultSubstitute(pattern);
693
694 FcPattern* matchPattern;
695 SkAutoFcPattern strongPattern(NULL);
696 if (familyName) {
697 strongPattern.reset(FcPatternDuplicate(pattern));
698 remove_weak(strongPattern, FC_FAMILY);
699 matchPattern = strongPattern;
700 } else {
701 matchPattern = pattern;
702 }
703
bungeman6bc2c942014-09-09 12:50:36 -0700704 SkAutoFcFontSet matches;
bungemana6785cc2014-08-25 12:00:49 -0700705 // TODO: Some families have 'duplicates' due to symbolic links.
706 // The patterns are exactly the same except for the FC_FILE.
707 // It should be possible to collapse these patterns by normalizing.
708 static const FcSetName fcNameSet[] = { FcSetSystem, FcSetApplication };
709 for (int setIndex = 0; setIndex < (int)SK_ARRAY_COUNT(fcNameSet); ++setIndex) {
710 // Return value of FcConfigGetFonts must not be destroyed.
711 FcFontSet* allFonts(FcConfigGetFonts(fFC, fcNameSet[setIndex]));
712 if (NULL == allFonts) {
713 continue;
714 }
715
716 for (int fontIndex = 0; fontIndex < allFonts->nfont; ++fontIndex) {
bungeman6bc2c942014-09-09 12:50:36 -0700717 FcPattern* font = allFonts->fonts[fontIndex];
718 if (FontAccessible(font) && FontFamilyNameMatches(font, matchPattern)) {
719 FcFontSetAdd(matches, FcFontRenderPrepare(fFC, pattern, font));
bungemana6785cc2014-08-25 12:00:49 -0700720 }
721 }
722 }
723
724 return SkNEW_ARGS(StyleSet, (this, matches.detach()));
725 }
726
727 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
mtklein36352bf2015-03-25 18:17:31 -0700728 const SkFontStyle& style) const override
bungemana6785cc2014-08-25 12:00:49 -0700729 {
730 FCLocker lock;
731
bungeman6bc2c942014-09-09 12:50:36 -0700732 SkAutoFcPattern pattern;
bungemana6785cc2014-08-25 12:00:49 -0700733 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
734 fcpattern_from_skfontstyle(style, pattern);
735 FcConfigSubstitute(fFC, pattern, FcMatchPattern);
736 FcDefaultSubstitute(pattern);
737
738 // We really want to match strong (prefered) and same (acceptable) only here.
739 // If a family name was specified, assume that any weak matches after the last strong match
740 // are weak (default) and ignore them.
741 // The reason for is that after substitution the pattern for 'sans-serif' looks like
742 // "wwwwwwwwwwwwwwswww" where there are many weak but preferred names, followed by defaults.
743 // So it is possible to have weakly matching but preferred names.
744 // In aliases, bindings are weak by default, so this is easy and common.
745 // If no family name was specified, we'll probably only get weak matches, but that's ok.
746 FcPattern* matchPattern;
747 SkAutoFcPattern strongPattern(NULL);
748 if (familyName) {
749 strongPattern.reset(FcPatternDuplicate(pattern));
750 remove_weak(strongPattern, FC_FAMILY);
751 matchPattern = strongPattern;
752 } else {
753 matchPattern = pattern;
754 }
755
756 FcResult result;
bungeman6bc2c942014-09-09 12:50:36 -0700757 SkAutoFcPattern font(FcFontMatch(fFC, pattern, &result));
758 if (NULL == font || !FontAccessible(font) || !FontFamilyNameMatches(font, matchPattern)) {
bungemana6785cc2014-08-25 12:00:49 -0700759 return NULL;
760 }
761
bungeman6bc2c942014-09-09 12:50:36 -0700762 return createTypefaceFromFcPattern(font);
763 }
764
765 virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
766 const SkFontStyle& style,
bungemanc20386e2014-10-23 07:08:05 -0700767 const char* bcp47[],
768 int bcp47Count,
mtklein36352bf2015-03-25 18:17:31 -0700769 SkUnichar character) const override
bungeman6bc2c942014-09-09 12:50:36 -0700770 {
771 FCLocker lock;
772
773 SkAutoFcPattern pattern;
bungeman6837b382015-04-29 14:35:49 -0700774 if (familyName) {
775 FcValue familyNameValue;
776 familyNameValue.type = FcTypeString;
777 familyNameValue.u.s = reinterpret_cast<const FcChar8*>(familyName);
778 FcPatternAddWeak(pattern, FC_FAMILY, familyNameValue, FcFalse);
779 }
bungeman6bc2c942014-09-09 12:50:36 -0700780 fcpattern_from_skfontstyle(style, pattern);
781
782 SkAutoFcCharSet charSet;
783 FcCharSetAddChar(charSet, character);
784 FcPatternAddCharSet(pattern, FC_CHARSET, charSet);
785
bungemanc20386e2014-10-23 07:08:05 -0700786 if (bcp47Count > 0) {
787 SkASSERT(bcp47);
bungeman6bc2c942014-09-09 12:50:36 -0700788 SkAutoFcLangSet langSet;
bungemanc20386e2014-10-23 07:08:05 -0700789 for (int i = bcp47Count; i --> 0;) {
790 FcLangSetAdd(langSet, (const FcChar8*)bcp47[i]);
791 }
bungeman6bc2c942014-09-09 12:50:36 -0700792 FcPatternAddLangSet(pattern, FC_LANG, langSet);
793 }
794
795 FcConfigSubstitute(fFC, pattern, FcMatchPattern);
796 FcDefaultSubstitute(pattern);
797
798 FcResult result;
799 SkAutoFcPattern font(FcFontMatch(fFC, pattern, &result));
800 if (NULL == font || !FontAccessible(font) || !FontContainsCharacter(font, character)) {
801 return NULL;
802 }
803
804 return createTypefaceFromFcPattern(font);
bungemana6785cc2014-08-25 12:00:49 -0700805 }
806
807 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* typeface,
mtklein36352bf2015-03-25 18:17:31 -0700808 const SkFontStyle& style) const override
bungemana6785cc2014-08-25 12:00:49 -0700809 {
810 //TODO: should the SkTypeface_fontconfig know its family?
bungemanb14e4a02014-09-18 13:57:20 -0700811 const SkTypeface_fontconfig* fcTypeface =
bungeman9db50922014-09-12 12:14:14 -0700812 static_cast<const SkTypeface_fontconfig*>(typeface);
bungemanb14e4a02014-09-18 13:57:20 -0700813 return this->matchFamilyStyle(get_string(fcTypeface->fPattern, FC_FAMILY), style);
bungemana6785cc2014-08-25 12:00:49 -0700814 }
815
mtklein36352bf2015-03-25 18:17:31 -0700816 SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
bungeman5f213d92015-01-27 05:39:10 -0800817 SkAutoTDelete<SkStreamAsset> stream(bareStream);
bungemana6785cc2014-08-25 12:00:49 -0700818 const size_t length = stream->getLength();
819 if (length <= 0 || (1u << 30) < length) {
820 return NULL;
821 }
822
bungemana4c4a2d2014-10-20 13:33:19 -0700823 SkFontStyle style;
bungemana6785cc2014-08-25 12:00:49 -0700824 bool isFixedWidth = false;
bungeman05773ed2015-05-13 10:57:09 -0700825 if (!fScanner.scanFont(stream, ttcIndex, NULL, &style, &isFixedWidth, NULL)) {
bungemana6785cc2014-08-25 12:00:49 -0700826 return NULL;
827 }
828
bungeman05773ed2015-05-13 10:57:09 -0700829 return SkNEW_ARGS(SkTypeface_stream, (new SkFontData(stream.detach(), ttcIndex, NULL, 0),
830 style, isFixedWidth));
bungemana6785cc2014-08-25 12:00:49 -0700831 }
832
mtklein36352bf2015-03-25 18:17:31 -0700833 SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
scroggoa1193e42015-01-21 12:09:53 -0800834 return this->createFromStream(SkNEW_ARGS(SkMemoryStream, (data)), ttcIndex);
bungemana6785cc2014-08-25 12:00:49 -0700835 }
836
mtklein36352bf2015-03-25 18:17:31 -0700837 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
scroggoa1193e42015-01-21 12:09:53 -0800838 return this->createFromStream(SkStream::NewFromFile(path), ttcIndex);
bungemana6785cc2014-08-25 12:00:49 -0700839 }
840
bungeman05773ed2015-05-13 10:57:09 -0700841 SkTypeface* onCreateFromFontData(SkFontData* fontData) const override {
842 SkStreamAsset* stream(fontData->getStream());
843 const size_t length = stream->getLength();
844 if (length <= 0 || (1u << 30) < length) {
845 return NULL;
846 }
847
848 const int ttcIndex = fontData->getIndex();
849 SkFontStyle style;
850 bool isFixedWidth = false;
851 if (!fScanner.scanFont(stream, ttcIndex, NULL, &style, &isFixedWidth, NULL)) {
852 return NULL;
853 }
854
855 return SkNEW_ARGS(SkTypeface_stream, (fontData, style, isFixedWidth));
856 }
857
bungemana6785cc2014-08-25 12:00:49 -0700858 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
mtklein36352bf2015-03-25 18:17:31 -0700859 unsigned styleBits) const override {
bungemana6785cc2014-08-25 12:00:49 -0700860 bool bold = styleBits & SkTypeface::kBold;
861 bool italic = styleBits & SkTypeface::kItalic;
862 SkFontStyle style = SkFontStyle(bold ? SkFontStyle::kBold_Weight
863 : SkFontStyle::kNormal_Weight,
864 SkFontStyle::kNormal_Width,
865 italic ? SkFontStyle::kItalic_Slant
866 : SkFontStyle::kUpright_Slant);
867 SkAutoTUnref<SkTypeface> typeface(this->matchFamilyStyle(familyName, style));
bsalomon49f085d2014-09-05 13:34:00 -0700868 if (typeface.get()) {
bungemana6785cc2014-08-25 12:00:49 -0700869 return typeface.detach();
870 }
871
872 return this->matchFamilyStyle(NULL, style);
873 }
874};
875
876SkFontMgr* SkFontMgr::Factory() {
877 return SkNEW(SkFontMgr_fontconfig);
878}