blob: bd6a5a2a2a6b95cc4c08e52f4d1b565ad8f9b3d5 [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"
bungemanf20488b2015-07-29 11:49:40 -07009#include "SkFixed.h"
bungemana6785cc2014-08-25 12:00:49 -070010#include "SkFontDescriptor.h"
11#include "SkFontHost_FreeType_common.h"
12#include "SkFontMgr.h"
13#include "SkFontStyle.h"
14#include "SkMath.h"
mtklein1b249332015-07-07 12:21:21 -070015#include "SkMutex.h"
bungemana6785cc2014-08-25 12:00:49 -070016#include "SkOSFile.h"
bungemanf20488b2015-07-29 11:49:40 -070017#include "SkRefCnt.h"
18#include "SkStream.h"
19#include "SkString.h"
20#include "SkTDArray.h"
21#include "SkTemplates.h"
22#include "SkTypeface.h"
23#include "SkTypefaceCache.h"
24#include "SkTypes.h"
bungemana6785cc2014-08-25 12:00:49 -070025
26#include <fontconfig/fontconfig.h>
bungemanf20488b2015-07-29 11:49:40 -070027#include <string.h>
28
29class SkData;
bungemana6785cc2014-08-25 12:00:49 -070030
31// FC_POSTSCRIPT_NAME was added with b561ff20 which ended up in 2.10.92
32// Ubuntu 12.04 is on 2.8.0, 13.10 is on 2.10.93
33// Debian 7 is on 2.9.0, 8 is on 2.11
34// OpenSUSE 12.2 is on 2.9.0, 12.3 is on 2.10.2, 13.1 2.11.0
35// Fedora 19 is on 2.10.93
36#ifndef FC_POSTSCRIPT_NAME
37# define FC_POSTSCRIPT_NAME "postscriptname"
38#endif
39
40#ifdef SK_DEBUG
41# include "SkTLS.h"
42#endif
43
44/** Since FontConfig is poorly documented, this gives a high level overview:
45 *
46 * FcConfig is a handle to a FontConfig configuration instance. Each 'configuration' is independent
47 * from any others which may exist. There exists a default global configuration which is created
48 * and destroyed by FcInit and FcFini, but this default should not normally be used.
49 * Instead, one should use FcConfigCreate and FcInit* to have a named local state.
50 *
51 * FcPatterns are {objectName -> [element]} (maps from object names to a list of elements).
52 * Each element is some internal data plus an FcValue which is a variant (a union with a type tag).
53 * Lists of elements are not typed, except by convention. Any collection of FcValues must be
54 * assumed to be heterogeneous by the code, but the code need not do anything particularly
55 * interesting if the values go against convention.
56 *
57 * Somewhat like DirectWrite, FontConfig supports synthetics through FC_EMBOLDEN and FC_MATRIX.
58 * Like all synthetic information, such information must be passed with the font data.
59 */
60
61namespace {
62
63// Fontconfig is not threadsafe before 2.10.91. Before that, we lock with a global mutex.
halcanary6950de62015-11-07 05:29:00 -080064// See https://bug.skia.org/1497 for background.
bungemana6785cc2014-08-25 12:00:49 -070065SK_DECLARE_STATIC_MUTEX(gFCMutex);
66
67#ifdef SK_DEBUG
halcanary385fe4d2015-08-26 13:07:48 -070068void* CreateThreadFcLocked() { return new bool(false); }
69void DeleteThreadFcLocked(void* v) { delete static_cast<bool*>(v); }
bungemana6785cc2014-08-25 12:00:49 -070070# define THREAD_FC_LOCKED \
71 static_cast<bool*>(SkTLS::Get(CreateThreadFcLocked, DeleteThreadFcLocked))
72#endif
73
74struct FCLocker {
75 // Assume FcGetVersion() has always been thread safe.
76
77 FCLocker() {
78 if (FcGetVersion() < 21091) {
79 gFCMutex.acquire();
80 } else {
81 SkDEBUGCODE(bool* threadLocked = THREAD_FC_LOCKED);
82 SkASSERT(false == *threadLocked);
83 SkDEBUGCODE(*threadLocked = true);
84 }
85 }
86
87 ~FCLocker() {
88 AssertHeld();
89 if (FcGetVersion() < 21091) {
90 gFCMutex.release();
91 } else {
92 SkDEBUGCODE(*THREAD_FC_LOCKED = false);
93 }
94 }
95
96 static void AssertHeld() { SkDEBUGCODE(
97 if (FcGetVersion() < 21091) {
98 gFCMutex.assertHeld();
99 } else {
100 SkASSERT(true == *THREAD_FC_LOCKED);
101 }
102 ) }
103};
104
105} // namespace
106
bungeman6bc2c942014-09-09 12:50:36 -0700107template<typename T, void (*D)(T*)> void FcTDestroy(T* t) {
bungemana6785cc2014-08-25 12:00:49 -0700108 FCLocker::AssertHeld();
bungeman6bc2c942014-09-09 12:50:36 -0700109 D(t);
bungemana6785cc2014-08-25 12:00:49 -0700110}
bungeman6bc2c942014-09-09 12:50:36 -0700111template <typename T, T* (*C)(), void (*D)(T*)> class SkAutoFc
112 : public SkAutoTCallVProc<T, FcTDestroy<T, D> > {
bungemana6785cc2014-08-25 12:00:49 -0700113public:
bungeman6bc2c942014-09-09 12:50:36 -0700114 SkAutoFc() : SkAutoTCallVProc<T, FcTDestroy<T, D> >(C()) {
115 T* obj = this->operator T*();
djsollenf2b340f2016-01-29 08:51:04 -0800116 SkASSERT_RELEASE(nullptr != obj);
bungeman6bc2c942014-09-09 12:50:36 -0700117 }
118 explicit SkAutoFc(T* obj) : SkAutoTCallVProc<T, FcTDestroy<T, D> >(obj) {}
bungemana6785cc2014-08-25 12:00:49 -0700119};
120
bungeman6bc2c942014-09-09 12:50:36 -0700121typedef SkAutoFc<FcCharSet, FcCharSetCreate, FcCharSetDestroy> SkAutoFcCharSet;
122typedef SkAutoFc<FcConfig, FcConfigCreate, FcConfigDestroy> SkAutoFcConfig;
123typedef SkAutoFc<FcFontSet, FcFontSetCreate, FcFontSetDestroy> SkAutoFcFontSet;
124typedef SkAutoFc<FcLangSet, FcLangSetCreate, FcLangSetDestroy> SkAutoFcLangSet;
125typedef SkAutoFc<FcObjectSet, FcObjectSetCreate, FcObjectSetDestroy> SkAutoFcObjectSet;
126typedef SkAutoFc<FcPattern, FcPatternCreate, FcPatternDestroy> SkAutoFcPattern;
bungemana6785cc2014-08-25 12:00:49 -0700127
128static int get_int(FcPattern* pattern, const char object[], int missing) {
129 int value;
130 if (FcPatternGetInteger(pattern, object, 0, &value) != FcResultMatch) {
131 return missing;
132 }
133 return value;
134}
135
136static const char* get_string(FcPattern* pattern, const char object[], const char* missing = "") {
137 FcChar8* value;
138 if (FcPatternGetString(pattern, object, 0, &value) != FcResultMatch) {
139 return missing;
140 }
141 return (const char*)value;
142}
143
144enum SkWeakReturn {
145 kIsWeak_WeakReturn,
146 kIsStrong_WeakReturn,
147 kNoId_WeakReturn
148};
149/** Ideally there would exist a call like
150 * FcResult FcPatternIsWeak(pattern, object, id, FcBool* isWeak);
151 *
152 * However, there is no such call and as of Fc 2.11.0 even FcPatternEquals ignores the weak bit.
153 * Currently, the only reliable way of finding the weak bit is by its effect on matching.
154 * The weak bit only affects the matching of FC_FAMILY and FC_POSTSCRIPT_NAME object values.
155 * A element with the weak bit is scored after FC_LANG, without the weak bit is scored before.
156 * Note that the weak bit is stored on the element, not on the value it holds.
157 */
158static SkWeakReturn is_weak(FcPattern* pattern, const char object[], int id) {
159 FCLocker::AssertHeld();
160
161 FcResult result;
162
163 // Create a copy of the pattern with only the value 'pattern'['object'['id']] in it.
164 // Internally, FontConfig pattern objects are linked lists, so faster to remove from head.
halcanary96fcdcc2015-08-27 07:41:13 -0700165 SkAutoFcObjectSet requestedObjectOnly(FcObjectSetBuild(object, nullptr));
bungemana6785cc2014-08-25 12:00:49 -0700166 SkAutoFcPattern minimal(FcPatternFilter(pattern, requestedObjectOnly));
167 FcBool hasId = true;
168 for (int i = 0; hasId && i < id; ++i) {
169 hasId = FcPatternRemove(minimal, object, 0);
170 }
171 if (!hasId) {
172 return kNoId_WeakReturn;
173 }
174 FcValue value;
175 result = FcPatternGet(minimal, object, 0, &value);
176 if (result != FcResultMatch) {
177 return kNoId_WeakReturn;
178 }
179 while (hasId) {
180 hasId = FcPatternRemove(minimal, object, 1);
181 }
182
183 // Create a font set with two patterns.
184 // 1. the same 'object' as minimal and a lang object with only 'nomatchlang'.
185 // 2. a different 'object' from minimal and a lang object with only 'matchlang'.
bungeman6bc2c942014-09-09 12:50:36 -0700186 SkAutoFcFontSet fontSet;
bungemana6785cc2014-08-25 12:00:49 -0700187
bungeman6bc2c942014-09-09 12:50:36 -0700188 SkAutoFcLangSet strongLangSet;
bungemana6785cc2014-08-25 12:00:49 -0700189 FcLangSetAdd(strongLangSet, (const FcChar8*)"nomatchlang");
190 SkAutoFcPattern strong(FcPatternDuplicate(minimal));
191 FcPatternAddLangSet(strong, FC_LANG, strongLangSet);
192
bungeman6bc2c942014-09-09 12:50:36 -0700193 SkAutoFcLangSet weakLangSet;
bungemana6785cc2014-08-25 12:00:49 -0700194 FcLangSetAdd(weakLangSet, (const FcChar8*)"matchlang");
bungeman6bc2c942014-09-09 12:50:36 -0700195 SkAutoFcPattern weak;
bungemana6785cc2014-08-25 12:00:49 -0700196 FcPatternAddString(weak, object, (const FcChar8*)"nomatchstring");
197 FcPatternAddLangSet(weak, FC_LANG, weakLangSet);
198
199 FcFontSetAdd(fontSet, strong.detach());
200 FcFontSetAdd(fontSet, weak.detach());
201
202 // Add 'matchlang' to the copy of the pattern.
203 FcPatternAddLangSet(minimal, FC_LANG, weakLangSet);
204
205 // Run a match against the copy of the pattern.
206 // If the 'id' was weak, then we should match the pattern with 'matchlang'.
207 // If the 'id' was strong, then we should match the pattern with 'nomatchlang'.
208
209 // Note that this config is only used for FcFontRenderPrepare, which we don't even want.
210 // However, there appears to be no way to match/sort without it.
bungeman6bc2c942014-09-09 12:50:36 -0700211 SkAutoFcConfig config;
bungemana6785cc2014-08-25 12:00:49 -0700212 FcFontSet* fontSets[1] = { fontSet };
213 SkAutoFcPattern match(FcFontSetMatch(config, fontSets, SK_ARRAY_COUNT(fontSets),
214 minimal, &result));
215
216 FcLangSet* matchLangSet;
217 FcPatternGetLangSet(match, FC_LANG, 0, &matchLangSet);
218 return FcLangEqual == FcLangSetHasLang(matchLangSet, (const FcChar8*)"matchlang")
219 ? kIsWeak_WeakReturn : kIsStrong_WeakReturn;
220}
221
222/** Removes weak elements from either FC_FAMILY or FC_POSTSCRIPT_NAME objects in the property.
223 * This can be quite expensive, and should not be used more than once per font lookup.
224 * This removes all of the weak elements after the last strong element.
225 */
226static void remove_weak(FcPattern* pattern, const char object[]) {
227 FCLocker::AssertHeld();
228
halcanary96fcdcc2015-08-27 07:41:13 -0700229 SkAutoFcObjectSet requestedObjectOnly(FcObjectSetBuild(object, nullptr));
bungemana6785cc2014-08-25 12:00:49 -0700230 SkAutoFcPattern minimal(FcPatternFilter(pattern, requestedObjectOnly));
231
232 int lastStrongId = -1;
233 int numIds;
234 SkWeakReturn result;
235 for (int id = 0; ; ++id) {
236 result = is_weak(minimal, object, 0);
237 if (kNoId_WeakReturn == result) {
238 numIds = id;
239 break;
240 }
241 if (kIsStrong_WeakReturn == result) {
242 lastStrongId = id;
243 }
244 SkAssertResult(FcPatternRemove(minimal, object, 0));
245 }
246
247 // If they were all weak, then leave the pattern alone.
248 if (lastStrongId < 0) {
249 return;
250 }
251
252 // Remove everything after the last strong.
253 for (int id = lastStrongId + 1; id < numIds; ++id) {
254 SkAssertResult(FcPatternRemove(pattern, object, lastStrongId + 1));
255 }
256}
257
258static int map_range(SkFixed value,
259 SkFixed old_min, SkFixed old_max,
260 SkFixed new_min, SkFixed new_max)
261{
262 SkASSERT(old_min < old_max);
263 SkASSERT(new_min <= new_max);
264 return new_min + SkMulDiv(value - old_min, new_max - new_min, old_max - old_min);
265}
266
267static int ave(SkFixed a, SkFixed b) {
268 return SkFixedAve(a, b);
269}
270
271struct MapRanges {
272 SkFixed old_val;
273 SkFixed new_val;
274};
275
276static SkFixed map_ranges_fixed(SkFixed val, MapRanges const ranges[], int rangesCount) {
277 // -Inf to [0]
278 if (val < ranges[0].old_val) {
279 return ranges[0].new_val;
280 }
281
282 // Linear from [i] to ave([i], [i+1]), then from ave([i], [i+1]) to [i+1]
283 for (int i = 0; i < rangesCount - 1; ++i) {
284 if (val < ave(ranges[i].old_val, ranges[i+1].old_val)) {
285 return map_range(val, ranges[i].old_val, ave(ranges[i].old_val, ranges[i+1].old_val),
286 ranges[i].new_val, ave(ranges[i].new_val, ranges[i+1].new_val));
287 }
288 if (val < ranges[i+1].old_val) {
289 return map_range(val, ave(ranges[i].old_val, ranges[i+1].old_val), ranges[i+1].old_val,
290 ave(ranges[i].new_val, ranges[i+1].new_val), ranges[i+1].new_val);
291 }
292 }
293
294 // From [n] to +Inf
295 // if (fcweight < Inf)
296 return ranges[rangesCount-1].new_val;
297}
298
299static int map_ranges(int val, MapRanges const ranges[], int rangesCount) {
300 return SkFixedRoundToInt(map_ranges_fixed(SkIntToFixed(val), ranges, rangesCount));
301}
302
303template<int n> struct SkTFixed {
bungeman99fe8222015-08-20 07:57:51 -0700304 static_assert(-32768 <= n && n <= 32767, "SkTFixed_n_not_in_range");
bungemana6785cc2014-08-25 12:00:49 -0700305 static const SkFixed value = static_cast<SkFixed>(n << 16);
306};
307
308static SkFontStyle skfontstyle_from_fcpattern(FcPattern* pattern) {
309 typedef SkFontStyle SkFS;
310
311 static const MapRanges weightRanges[] = {
312 { SkTFixed<FC_WEIGHT_THIN>::value, SkTFixed<SkFS::kThin_Weight>::value },
313 { SkTFixed<FC_WEIGHT_EXTRALIGHT>::value, SkTFixed<SkFS::kExtraLight_Weight>::value },
314 { SkTFixed<FC_WEIGHT_LIGHT>::value, SkTFixed<SkFS::kLight_Weight>::value },
315 { SkTFixed<FC_WEIGHT_REGULAR>::value, SkTFixed<SkFS::kNormal_Weight>::value },
316 { SkTFixed<FC_WEIGHT_MEDIUM>::value, SkTFixed<SkFS::kMedium_Weight>::value },
317 { SkTFixed<FC_WEIGHT_DEMIBOLD>::value, SkTFixed<SkFS::kSemiBold_Weight>::value },
318 { SkTFixed<FC_WEIGHT_BOLD>::value, SkTFixed<SkFS::kBold_Weight>::value },
319 { SkTFixed<FC_WEIGHT_EXTRABOLD>::value, SkTFixed<SkFS::kExtraBold_Weight>::value },
320 { SkTFixed<FC_WEIGHT_BLACK>::value, SkTFixed<SkFS::kBlack_Weight>::value },
321 { SkTFixed<FC_WEIGHT_EXTRABLACK>::value, SkTFixed<1000>::value },
322 };
323 int weight = map_ranges(get_int(pattern, FC_WEIGHT, FC_WEIGHT_REGULAR),
324 weightRanges, SK_ARRAY_COUNT(weightRanges));
325
326 static const MapRanges widthRanges[] = {
327 { SkTFixed<FC_WIDTH_ULTRACONDENSED>::value, SkTFixed<SkFS::kUltraCondensed_Width>::value },
328 { SkTFixed<FC_WIDTH_EXTRACONDENSED>::value, SkTFixed<SkFS::kExtraCondensed_Width>::value },
329 { SkTFixed<FC_WIDTH_CONDENSED>::value, SkTFixed<SkFS::kCondensed_Width>::value },
330 { SkTFixed<FC_WIDTH_SEMICONDENSED>::value, SkTFixed<SkFS::kSemiCondensed_Width>::value },
331 { SkTFixed<FC_WIDTH_NORMAL>::value, SkTFixed<SkFS::kNormal_Width>::value },
332 { SkTFixed<FC_WIDTH_SEMIEXPANDED>::value, SkTFixed<SkFS::kSemiExpanded_Width>::value },
333 { SkTFixed<FC_WIDTH_EXPANDED>::value, SkTFixed<SkFS::kExpanded_Width>::value },
334 { SkTFixed<FC_WIDTH_EXTRAEXPANDED>::value, SkTFixed<SkFS::kExtraExpanded_Width>::value },
335 { SkTFixed<FC_WIDTH_ULTRAEXPANDED>::value, SkTFixed<SkFS::kUltaExpanded_Width>::value },
336 };
337 int width = map_ranges(get_int(pattern, FC_WIDTH, FC_WIDTH_NORMAL),
338 widthRanges, SK_ARRAY_COUNT(widthRanges));
339
340 SkFS::Slant slant = get_int(pattern, FC_SLANT, FC_SLANT_ROMAN) > 0
341 ? SkFS::kItalic_Slant
342 : SkFS::kUpright_Slant;
343
344 return SkFontStyle(weight, width, slant);
345}
346
347static void fcpattern_from_skfontstyle(SkFontStyle style, FcPattern* pattern) {
348 FCLocker::AssertHeld();
349
350 typedef SkFontStyle SkFS;
351
352 static const MapRanges weightRanges[] = {
353 { SkTFixed<SkFS::kThin_Weight>::value, SkTFixed<FC_WEIGHT_THIN>::value },
354 { SkTFixed<SkFS::kExtraLight_Weight>::value, SkTFixed<FC_WEIGHT_EXTRALIGHT>::value },
355 { SkTFixed<SkFS::kLight_Weight>::value, SkTFixed<FC_WEIGHT_LIGHT>::value },
356 { SkTFixed<SkFS::kNormal_Weight>::value, SkTFixed<FC_WEIGHT_REGULAR>::value },
357 { SkTFixed<SkFS::kMedium_Weight>::value, SkTFixed<FC_WEIGHT_MEDIUM>::value },
358 { SkTFixed<SkFS::kSemiBold_Weight>::value, SkTFixed<FC_WEIGHT_DEMIBOLD>::value },
359 { SkTFixed<SkFS::kBold_Weight>::value, SkTFixed<FC_WEIGHT_BOLD>::value },
360 { SkTFixed<SkFS::kExtraBold_Weight>::value, SkTFixed<FC_WEIGHT_EXTRABOLD>::value },
361 { SkTFixed<SkFS::kBlack_Weight>::value, SkTFixed<FC_WEIGHT_BLACK>::value },
362 { SkTFixed<1000>::value, SkTFixed<FC_WEIGHT_EXTRABLACK>::value },
363 };
364 int weight = map_ranges(style.weight(), weightRanges, SK_ARRAY_COUNT(weightRanges));
365
366 static const MapRanges widthRanges[] = {
367 { SkTFixed<SkFS::kUltraCondensed_Width>::value, SkTFixed<FC_WIDTH_ULTRACONDENSED>::value },
368 { SkTFixed<SkFS::kExtraCondensed_Width>::value, SkTFixed<FC_WIDTH_EXTRACONDENSED>::value },
369 { SkTFixed<SkFS::kCondensed_Width>::value, SkTFixed<FC_WIDTH_CONDENSED>::value },
370 { SkTFixed<SkFS::kSemiCondensed_Width>::value, SkTFixed<FC_WIDTH_SEMICONDENSED>::value },
371 { SkTFixed<SkFS::kNormal_Width>::value, SkTFixed<FC_WIDTH_NORMAL>::value },
372 { SkTFixed<SkFS::kSemiExpanded_Width>::value, SkTFixed<FC_WIDTH_SEMIEXPANDED>::value },
373 { SkTFixed<SkFS::kExpanded_Width>::value, SkTFixed<FC_WIDTH_EXPANDED>::value },
374 { SkTFixed<SkFS::kExtraExpanded_Width>::value, SkTFixed<FC_WIDTH_EXTRAEXPANDED>::value },
375 { SkTFixed<SkFS::kUltaExpanded_Width>::value, SkTFixed<FC_WIDTH_ULTRAEXPANDED>::value },
376 };
377 int width = map_ranges(style.width(), widthRanges, SK_ARRAY_COUNT(widthRanges));
378
379 FcPatternAddInteger(pattern, FC_WEIGHT, weight);
380 FcPatternAddInteger(pattern, FC_WIDTH, width);
381 FcPatternAddInteger(pattern, FC_SLANT, style.isItalic() ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
382}
383
bungemana6785cc2014-08-25 12:00:49 -0700384class SkTypeface_stream : public SkTypeface_FreeType {
385public:
bungeman41868fe2015-05-20 09:21:04 -0700386 /** @param data takes ownership of the font data.*/
387 SkTypeface_stream(SkFontData* data, const SkFontStyle& style, bool fixedWidth)
bungemana6785cc2014-08-25 12:00:49 -0700388 : INHERITED(style, SkTypefaceCache::NewFontID(), fixedWidth)
bungeman41868fe2015-05-20 09:21:04 -0700389 , fData(data)
bungemana6785cc2014-08-25 12:00:49 -0700390 { };
391
mtklein36352bf2015-03-25 18:17:31 -0700392 void onGetFamilyName(SkString* familyName) const override {
bungemanb374d6a2014-09-17 07:48:59 -0700393 familyName->reset();
394 }
395
mtklein36352bf2015-03-25 18:17:31 -0700396 void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override {
bungemana6785cc2014-08-25 12:00:49 -0700397 *serialize = true;
398 }
399
mtklein36352bf2015-03-25 18:17:31 -0700400 SkStreamAsset* onOpenStream(int* ttcIndex) const override {
bungeman41868fe2015-05-20 09:21:04 -0700401 *ttcIndex = fData->getIndex();
402 return fData->duplicateStream();
403 }
404
405 SkFontData* onCreateFontData() const override {
406 return new SkFontData(*fData.get());
bungemana6785cc2014-08-25 12:00:49 -0700407 }
408
409private:
bungeman41868fe2015-05-20 09:21:04 -0700410 const SkAutoTDelete<const SkFontData> fData;
bungemana6785cc2014-08-25 12:00:49 -0700411
412 typedef SkTypeface_FreeType INHERITED;
413};
414
415class SkTypeface_fontconfig : public SkTypeface_FreeType {
416public:
417 /** @param pattern takes ownership of the reference. */
418 static SkTypeface_fontconfig* Create(FcPattern* pattern) {
halcanary385fe4d2015-08-26 13:07:48 -0700419 return new SkTypeface_fontconfig(pattern);
bungemana6785cc2014-08-25 12:00:49 -0700420 }
421 mutable SkAutoFcPattern fPattern;
422
mtklein36352bf2015-03-25 18:17:31 -0700423 void onGetFamilyName(SkString* familyName) const override {
bungemanb374d6a2014-09-17 07:48:59 -0700424 *familyName = get_string(fPattern, FC_FAMILY);
425 }
426
mtklein36352bf2015-03-25 18:17:31 -0700427 void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) const override {
bungemana6785cc2014-08-25 12:00:49 -0700428 FCLocker lock;
429 desc->setFamilyName(get_string(fPattern, FC_FAMILY));
bungemana6785cc2014-08-25 12:00:49 -0700430 desc->setFullName(get_string(fPattern, FC_FULLNAME));
431 desc->setPostscriptName(get_string(fPattern, FC_POSTSCRIPT_NAME));
bungemana6785cc2014-08-25 12:00:49 -0700432 *serialize = false;
433 }
434
mtklein36352bf2015-03-25 18:17:31 -0700435 SkStreamAsset* onOpenStream(int* ttcIndex) const override {
bungemana6785cc2014-08-25 12:00:49 -0700436 FCLocker lock;
437 *ttcIndex = get_int(fPattern, FC_INDEX, 0);
438 return SkStream::NewFromFile(get_string(fPattern, FC_FILE));
439 }
440
441 virtual ~SkTypeface_fontconfig() {
442 // Hold the lock while unrefing the pattern.
443 FCLocker lock;
444 fPattern.reset();
445 }
446
447private:
448 /** @param pattern takes ownership of the reference. */
449 SkTypeface_fontconfig(FcPattern* pattern)
bungemana4c4a2d2014-10-20 13:33:19 -0700450 : INHERITED(skfontstyle_from_fcpattern(pattern),
bungemana6785cc2014-08-25 12:00:49 -0700451 SkTypefaceCache::NewFontID(),
452 FC_PROPORTIONAL != get_int(pattern, FC_SPACING, FC_PROPORTIONAL))
453 , fPattern(pattern)
454 { };
455
456 typedef SkTypeface_FreeType INHERITED;
457};
458
459class SkFontMgr_fontconfig : public SkFontMgr {
460 mutable SkAutoFcConfig fFC;
461 SkAutoTUnref<SkDataTable> fFamilyNames;
bungeman14df8332014-10-28 15:07:23 -0700462 SkTypeface_FreeType::Scanner fScanner;
bungemana6785cc2014-08-25 12:00:49 -0700463
464 class StyleSet : public SkFontStyleSet {
465 public:
466 /** @param parent does not take ownership of the reference.
467 * @param fontSet takes ownership of the reference.
468 */
469 StyleSet(const SkFontMgr_fontconfig* parent, FcFontSet* fontSet)
470 : fFontMgr(SkRef(parent)), fFontSet(fontSet)
471 { }
472
473 virtual ~StyleSet() {
474 // Hold the lock while unrefing the font set.
475 FCLocker lock;
476 fFontSet.reset();
477 }
478
mtklein36352bf2015-03-25 18:17:31 -0700479 int count() override { return fFontSet->nfont; }
bungemana6785cc2014-08-25 12:00:49 -0700480
mtklein36352bf2015-03-25 18:17:31 -0700481 void getStyle(int index, SkFontStyle* style, SkString* styleName) override {
bungemana6785cc2014-08-25 12:00:49 -0700482 if (index < 0 || fFontSet->nfont <= index) {
483 return;
484 }
485
486 FCLocker lock;
487 if (style) {
488 *style = skfontstyle_from_fcpattern(fFontSet->fonts[index]);
489 }
490 if (styleName) {
491 *styleName = get_string(fFontSet->fonts[index], FC_STYLE);
492 }
493 }
494
mtklein36352bf2015-03-25 18:17:31 -0700495 SkTypeface* createTypeface(int index) override {
bungemana6785cc2014-08-25 12:00:49 -0700496 FCLocker lock;
497
498 FcPattern* match = fFontSet->fonts[index];
499 return fFontMgr->createTypefaceFromFcPattern(match);
500 }
501
mtklein36352bf2015-03-25 18:17:31 -0700502 SkTypeface* matchStyle(const SkFontStyle& style) override {
bungemana6785cc2014-08-25 12:00:49 -0700503 FCLocker lock;
504
bungeman6bc2c942014-09-09 12:50:36 -0700505 SkAutoFcPattern pattern;
bungemana6785cc2014-08-25 12:00:49 -0700506 fcpattern_from_skfontstyle(style, pattern);
507 FcConfigSubstitute(fFontMgr->fFC, pattern, FcMatchPattern);
508 FcDefaultSubstitute(pattern);
509
510 FcResult result;
511 FcFontSet* fontSets[1] = { fFontSet };
512 SkAutoFcPattern match(FcFontSetMatch(fFontMgr->fFC,
513 fontSets, SK_ARRAY_COUNT(fontSets),
514 pattern, &result));
halcanary96fcdcc2015-08-27 07:41:13 -0700515 if (nullptr == match) {
516 return nullptr;
bungemana6785cc2014-08-25 12:00:49 -0700517 }
518
519 return fFontMgr->createTypefaceFromFcPattern(match);
520 }
521
522 private:
523 SkAutoTUnref<const SkFontMgr_fontconfig> fFontMgr;
524 SkAutoFcFontSet fFontSet;
525 };
526
527 static bool FindName(const SkTDArray<const char*>& list, const char* str) {
528 int count = list.count();
529 for (int i = 0; i < count; ++i) {
530 if (!strcmp(list[i], str)) {
531 return true;
532 }
533 }
534 return false;
535 }
536
537 static SkDataTable* GetFamilyNames(FcConfig* fcconfig) {
538 FCLocker lock;
539
540 SkTDArray<const char*> names;
541 SkTDArray<size_t> sizes;
542
543 static const FcSetName fcNameSet[] = { FcSetSystem, FcSetApplication };
544 for (int setIndex = 0; setIndex < (int)SK_ARRAY_COUNT(fcNameSet); ++setIndex) {
545 // Return value of FcConfigGetFonts must not be destroyed.
546 FcFontSet* allFonts(FcConfigGetFonts(fcconfig, fcNameSet[setIndex]));
halcanary96fcdcc2015-08-27 07:41:13 -0700547 if (nullptr == allFonts) {
bungemana6785cc2014-08-25 12:00:49 -0700548 continue;
549 }
550
551 for (int fontIndex = 0; fontIndex < allFonts->nfont; ++fontIndex) {
552 FcPattern* current = allFonts->fonts[fontIndex];
553 for (int id = 0; ; ++id) {
554 FcChar8* fcFamilyName;
555 FcResult result = FcPatternGetString(current, FC_FAMILY, id, &fcFamilyName);
556 if (FcResultNoId == result) {
557 break;
558 }
559 if (FcResultMatch != result) {
560 continue;
561 }
562 const char* familyName = reinterpret_cast<const char*>(fcFamilyName);
563 if (familyName && !FindName(names, familyName)) {
564 *names.append() = familyName;
565 *sizes.append() = strlen(familyName) + 1;
566 }
567 }
568 }
569 }
570
571 return SkDataTable::NewCopyArrays((void const *const *)names.begin(),
572 sizes.begin(), names.count());
573 }
574
bungemana4c4a2d2014-10-20 13:33:19 -0700575 static bool FindByFcPattern(SkTypeface* cached, const SkFontStyle&, void* ctx) {
bungemana6785cc2014-08-25 12:00:49 -0700576 SkTypeface_fontconfig* cshFace = static_cast<SkTypeface_fontconfig*>(cached);
577 FcPattern* ctxPattern = static_cast<FcPattern*>(ctx);
578 return FcTrue == FcPatternEqual(cshFace->fPattern, ctxPattern);
579 }
580
581 mutable SkMutex fTFCacheMutex;
582 mutable SkTypefaceCache fTFCache;
583 /** Creates a typeface using a typeface cache.
584 * @param pattern a complete pattern from FcFontRenderPrepare.
585 */
586 SkTypeface* createTypefaceFromFcPattern(FcPattern* pattern) const {
587 FCLocker::AssertHeld();
588 SkAutoMutexAcquire ama(fTFCacheMutex);
589 SkTypeface* face = fTFCache.findByProcAndRef(FindByFcPattern, pattern);
halcanary96fcdcc2015-08-27 07:41:13 -0700590 if (nullptr == face) {
bungemana6785cc2014-08-25 12:00:49 -0700591 FcPatternReference(pattern);
592 face = SkTypeface_fontconfig::Create(pattern);
593 if (face) {
mtklein60b6e9d2014-10-24 10:43:15 -0700594 fTFCache.add(face, SkFontStyle());
bungemana6785cc2014-08-25 12:00:49 -0700595 }
596 }
597 return face;
598 }
599
600public:
bungemana6785cc2014-08-25 12:00:49 -0700601 /** Takes control of the reference to 'config'. */
602 explicit SkFontMgr_fontconfig(FcConfig* config)
bungeman0b1de262015-06-17 07:55:59 -0700603 : fFC(config ? config : FcInitLoadConfigAndFonts())
bungemana6785cc2014-08-25 12:00:49 -0700604 , fFamilyNames(GetFamilyNames(fFC)) { }
605
606 virtual ~SkFontMgr_fontconfig() {
607 // Hold the lock while unrefing the config.
608 FCLocker lock;
609 fFC.reset();
610 }
611
612protected:
mtklein36352bf2015-03-25 18:17:31 -0700613 int onCountFamilies() const override {
bungemana6785cc2014-08-25 12:00:49 -0700614 return fFamilyNames->count();
615 }
616
mtklein36352bf2015-03-25 18:17:31 -0700617 void onGetFamilyName(int index, SkString* familyName) const override {
bungemana6785cc2014-08-25 12:00:49 -0700618 familyName->set(fFamilyNames->atStr(index));
619 }
620
mtklein36352bf2015-03-25 18:17:31 -0700621 SkFontStyleSet* onCreateStyleSet(int index) const override {
bungemana6785cc2014-08-25 12:00:49 -0700622 return this->onMatchFamily(fFamilyNames->atStr(index));
623 }
624
625 /** True if any string object value in the font is the same
626 * as a string object value in the pattern.
627 */
628 static bool AnyMatching(FcPattern* font, FcPattern* pattern, const char* object) {
629 FcChar8* fontString;
630 FcChar8* patternString;
631 FcResult result;
632 // Set an arbitrary limit on the number of pattern object values to consider.
633 // TODO: re-write this to avoid N*M
634 static const int maxId = 16;
635 for (int patternId = 0; patternId < maxId; ++patternId) {
636 result = FcPatternGetString(pattern, object, patternId, &patternString);
637 if (FcResultNoId == result) {
638 break;
639 }
640 if (FcResultMatch != result) {
641 continue;
642 }
643 for (int fontId = 0; fontId < maxId; ++fontId) {
644 result = FcPatternGetString(font, object, fontId, &fontString);
645 if (FcResultNoId == result) {
646 break;
647 }
648 if (FcResultMatch != result) {
649 continue;
650 }
651 if (0 == FcStrCmpIgnoreCase(patternString, fontString)) {
652 return true;
653 }
654 }
655 }
656 return false;
657 }
658
bungeman6bc2c942014-09-09 12:50:36 -0700659 static bool FontAccessible(FcPattern* font) {
bungemana6785cc2014-08-25 12:00:49 -0700660 // FontConfig can return fonts which are unreadable.
halcanary96fcdcc2015-08-27 07:41:13 -0700661 const char* filename = get_string(font, FC_FILE, nullptr);
662 if (nullptr == filename) {
bungemana6785cc2014-08-25 12:00:49 -0700663 return false;
664 }
665 return sk_exists(filename, kRead_SkFILE_Flag);
666 }
667
bungeman6bc2c942014-09-09 12:50:36 -0700668 static bool FontFamilyNameMatches(FcPattern* font, FcPattern* pattern) {
669 return AnyMatching(font, pattern, FC_FAMILY);
670 }
671
672 static bool FontContainsCharacter(FcPattern* font, uint32_t character) {
673 FcResult result;
674 FcCharSet* matchCharSet;
675 for (int charSetId = 0; ; ++charSetId) {
676 result = FcPatternGetCharSet(font, FC_CHARSET, charSetId, &matchCharSet);
677 if (FcResultNoId == result) {
678 break;
679 }
680 if (FcResultMatch != result) {
681 continue;
682 }
683 if (FcCharSetHasChar(matchCharSet, character)) {
684 return true;
685 }
686 }
687 return false;
bungemana6785cc2014-08-25 12:00:49 -0700688 }
689
mtklein36352bf2015-03-25 18:17:31 -0700690 SkFontStyleSet* onMatchFamily(const char familyName[]) const override {
bungemana6785cc2014-08-25 12:00:49 -0700691 FCLocker lock;
692
bungeman6bc2c942014-09-09 12:50:36 -0700693 SkAutoFcPattern pattern;
bungemana6785cc2014-08-25 12:00:49 -0700694 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
695 FcConfigSubstitute(fFC, pattern, FcMatchPattern);
696 FcDefaultSubstitute(pattern);
697
698 FcPattern* matchPattern;
halcanary96fcdcc2015-08-27 07:41:13 -0700699 SkAutoFcPattern strongPattern(nullptr);
bungemana6785cc2014-08-25 12:00:49 -0700700 if (familyName) {
701 strongPattern.reset(FcPatternDuplicate(pattern));
702 remove_weak(strongPattern, FC_FAMILY);
703 matchPattern = strongPattern;
704 } else {
705 matchPattern = pattern;
706 }
707
bungeman6bc2c942014-09-09 12:50:36 -0700708 SkAutoFcFontSet matches;
bungemana6785cc2014-08-25 12:00:49 -0700709 // TODO: Some families have 'duplicates' due to symbolic links.
710 // The patterns are exactly the same except for the FC_FILE.
711 // It should be possible to collapse these patterns by normalizing.
712 static const FcSetName fcNameSet[] = { FcSetSystem, FcSetApplication };
713 for (int setIndex = 0; setIndex < (int)SK_ARRAY_COUNT(fcNameSet); ++setIndex) {
714 // Return value of FcConfigGetFonts must not be destroyed.
715 FcFontSet* allFonts(FcConfigGetFonts(fFC, fcNameSet[setIndex]));
halcanary96fcdcc2015-08-27 07:41:13 -0700716 if (nullptr == allFonts) {
bungemana6785cc2014-08-25 12:00:49 -0700717 continue;
718 }
719
720 for (int fontIndex = 0; fontIndex < allFonts->nfont; ++fontIndex) {
bungeman6bc2c942014-09-09 12:50:36 -0700721 FcPattern* font = allFonts->fonts[fontIndex];
722 if (FontAccessible(font) && FontFamilyNameMatches(font, matchPattern)) {
723 FcFontSetAdd(matches, FcFontRenderPrepare(fFC, pattern, font));
bungemana6785cc2014-08-25 12:00:49 -0700724 }
725 }
726 }
727
halcanary385fe4d2015-08-26 13:07:48 -0700728 return new StyleSet(this, matches.detach());
bungemana6785cc2014-08-25 12:00:49 -0700729 }
730
731 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
mtklein36352bf2015-03-25 18:17:31 -0700732 const SkFontStyle& style) const override
bungemana6785cc2014-08-25 12:00:49 -0700733 {
734 FCLocker lock;
735
bungeman6bc2c942014-09-09 12:50:36 -0700736 SkAutoFcPattern pattern;
bungemana6785cc2014-08-25 12:00:49 -0700737 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
738 fcpattern_from_skfontstyle(style, pattern);
739 FcConfigSubstitute(fFC, pattern, FcMatchPattern);
740 FcDefaultSubstitute(pattern);
741
742 // We really want to match strong (prefered) and same (acceptable) only here.
743 // If a family name was specified, assume that any weak matches after the last strong match
744 // are weak (default) and ignore them.
745 // The reason for is that after substitution the pattern for 'sans-serif' looks like
746 // "wwwwwwwwwwwwwwswww" where there are many weak but preferred names, followed by defaults.
747 // So it is possible to have weakly matching but preferred names.
748 // In aliases, bindings are weak by default, so this is easy and common.
749 // If no family name was specified, we'll probably only get weak matches, but that's ok.
750 FcPattern* matchPattern;
halcanary96fcdcc2015-08-27 07:41:13 -0700751 SkAutoFcPattern strongPattern(nullptr);
bungemana6785cc2014-08-25 12:00:49 -0700752 if (familyName) {
753 strongPattern.reset(FcPatternDuplicate(pattern));
754 remove_weak(strongPattern, FC_FAMILY);
755 matchPattern = strongPattern;
756 } else {
757 matchPattern = pattern;
758 }
759
760 FcResult result;
bungeman6bc2c942014-09-09 12:50:36 -0700761 SkAutoFcPattern font(FcFontMatch(fFC, pattern, &result));
halcanary96fcdcc2015-08-27 07:41:13 -0700762 if (nullptr == font || !FontAccessible(font) || !FontFamilyNameMatches(font, matchPattern)) {
763 return nullptr;
bungemana6785cc2014-08-25 12:00:49 -0700764 }
765
bungeman6bc2c942014-09-09 12:50:36 -0700766 return createTypefaceFromFcPattern(font);
767 }
768
769 virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
770 const SkFontStyle& style,
bungemanc20386e2014-10-23 07:08:05 -0700771 const char* bcp47[],
772 int bcp47Count,
mtklein36352bf2015-03-25 18:17:31 -0700773 SkUnichar character) const override
bungeman6bc2c942014-09-09 12:50:36 -0700774 {
775 FCLocker lock;
776
777 SkAutoFcPattern pattern;
bungeman6837b382015-04-29 14:35:49 -0700778 if (familyName) {
779 FcValue familyNameValue;
780 familyNameValue.type = FcTypeString;
781 familyNameValue.u.s = reinterpret_cast<const FcChar8*>(familyName);
782 FcPatternAddWeak(pattern, FC_FAMILY, familyNameValue, FcFalse);
783 }
bungeman6bc2c942014-09-09 12:50:36 -0700784 fcpattern_from_skfontstyle(style, pattern);
785
786 SkAutoFcCharSet charSet;
787 FcCharSetAddChar(charSet, character);
788 FcPatternAddCharSet(pattern, FC_CHARSET, charSet);
789
bungemanc20386e2014-10-23 07:08:05 -0700790 if (bcp47Count > 0) {
791 SkASSERT(bcp47);
bungeman6bc2c942014-09-09 12:50:36 -0700792 SkAutoFcLangSet langSet;
bungemanc20386e2014-10-23 07:08:05 -0700793 for (int i = bcp47Count; i --> 0;) {
794 FcLangSetAdd(langSet, (const FcChar8*)bcp47[i]);
795 }
bungeman6bc2c942014-09-09 12:50:36 -0700796 FcPatternAddLangSet(pattern, FC_LANG, langSet);
797 }
798
799 FcConfigSubstitute(fFC, pattern, FcMatchPattern);
800 FcDefaultSubstitute(pattern);
801
802 FcResult result;
803 SkAutoFcPattern font(FcFontMatch(fFC, pattern, &result));
halcanary96fcdcc2015-08-27 07:41:13 -0700804 if (nullptr == font || !FontAccessible(font) || !FontContainsCharacter(font, character)) {
805 return nullptr;
bungeman6bc2c942014-09-09 12:50:36 -0700806 }
807
808 return createTypefaceFromFcPattern(font);
bungemana6785cc2014-08-25 12:00:49 -0700809 }
810
811 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* typeface,
mtklein36352bf2015-03-25 18:17:31 -0700812 const SkFontStyle& style) const override
bungemana6785cc2014-08-25 12:00:49 -0700813 {
814 //TODO: should the SkTypeface_fontconfig know its family?
bungemanb14e4a02014-09-18 13:57:20 -0700815 const SkTypeface_fontconfig* fcTypeface =
bungeman9db50922014-09-12 12:14:14 -0700816 static_cast<const SkTypeface_fontconfig*>(typeface);
bungemanb14e4a02014-09-18 13:57:20 -0700817 return this->matchFamilyStyle(get_string(fcTypeface->fPattern, FC_FAMILY), style);
bungemana6785cc2014-08-25 12:00:49 -0700818 }
819
mtklein36352bf2015-03-25 18:17:31 -0700820 SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
bungeman5f213d92015-01-27 05:39:10 -0800821 SkAutoTDelete<SkStreamAsset> stream(bareStream);
bungemana6785cc2014-08-25 12:00:49 -0700822 const size_t length = stream->getLength();
823 if (length <= 0 || (1u << 30) < length) {
halcanary96fcdcc2015-08-27 07:41:13 -0700824 return nullptr;
bungemana6785cc2014-08-25 12:00:49 -0700825 }
826
bungemana4c4a2d2014-10-20 13:33:19 -0700827 SkFontStyle style;
bungemana6785cc2014-08-25 12:00:49 -0700828 bool isFixedWidth = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700829 if (!fScanner.scanFont(stream, ttcIndex, nullptr, &style, &isFixedWidth, nullptr)) {
830 return nullptr;
bungemana6785cc2014-08-25 12:00:49 -0700831 }
832
halcanary96fcdcc2015-08-27 07:41:13 -0700833 return new SkTypeface_stream(new SkFontData(stream.detach(), ttcIndex, nullptr, 0), style,
halcanary385fe4d2015-08-26 13:07:48 -0700834 isFixedWidth);
bungemana6785cc2014-08-25 12:00:49 -0700835 }
836
bungemanf6c71072016-01-21 14:17:47 -0800837 SkTypeface* onCreateFromStream(SkStreamAsset* s, const FontParameters& params) const override {
838 using Scanner = SkTypeface_FreeType::Scanner;
839 SkAutoTDelete<SkStreamAsset> stream(s);
840 bool isFixedPitch;
841 SkFontStyle style;
842 SkString name;
843 Scanner::AxisDefinitions axisDefinitions;
844 if (!fScanner.scanFont(stream, params.getCollectionIndex(), &name, &style, &isFixedPitch,
845 &axisDefinitions))
846 {
847 return nullptr;
848 }
849
850 int paramAxisCount;
851 const FontParameters::Axis* paramAxes = params.getAxes(&paramAxisCount);
852 SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
853 Scanner::computeAxisValues(axisDefinitions, paramAxes, paramAxisCount, axisValues, name);
854
855 SkFontData* data(new SkFontData(stream.detach(), params.getCollectionIndex(),
856 axisValues.get(), axisDefinitions.count()));
857 return new SkTypeface_stream(data, style, isFixedPitch);
858 }
859
mtklein36352bf2015-03-25 18:17:31 -0700860 SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
halcanary385fe4d2015-08-26 13:07:48 -0700861 return this->createFromStream(new SkMemoryStream(data), ttcIndex);
bungemana6785cc2014-08-25 12:00:49 -0700862 }
863
mtklein36352bf2015-03-25 18:17:31 -0700864 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
scroggoa1193e42015-01-21 12:09:53 -0800865 return this->createFromStream(SkStream::NewFromFile(path), ttcIndex);
bungemana6785cc2014-08-25 12:00:49 -0700866 }
867
bungeman41868fe2015-05-20 09:21:04 -0700868 SkTypeface* onCreateFromFontData(SkFontData* fontData) const override {
869 SkStreamAsset* stream(fontData->getStream());
870 const size_t length = stream->getLength();
871 if (length <= 0 || (1u << 30) < length) {
halcanary96fcdcc2015-08-27 07:41:13 -0700872 return nullptr;
bungeman41868fe2015-05-20 09:21:04 -0700873 }
874
875 const int ttcIndex = fontData->getIndex();
876 SkFontStyle style;
877 bool isFixedWidth = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700878 if (!fScanner.scanFont(stream, ttcIndex, nullptr, &style, &isFixedWidth, nullptr)) {
879 return nullptr;
bungeman41868fe2015-05-20 09:21:04 -0700880 }
881
halcanary385fe4d2015-08-26 13:07:48 -0700882 return new SkTypeface_stream(fontData, style, isFixedWidth);
bungeman41868fe2015-05-20 09:21:04 -0700883 }
884
bungemana6785cc2014-08-25 12:00:49 -0700885 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
mtklein36352bf2015-03-25 18:17:31 -0700886 unsigned styleBits) const override {
bungemana6785cc2014-08-25 12:00:49 -0700887 bool bold = styleBits & SkTypeface::kBold;
888 bool italic = styleBits & SkTypeface::kItalic;
889 SkFontStyle style = SkFontStyle(bold ? SkFontStyle::kBold_Weight
890 : SkFontStyle::kNormal_Weight,
891 SkFontStyle::kNormal_Width,
892 italic ? SkFontStyle::kItalic_Slant
893 : SkFontStyle::kUpright_Slant);
894 SkAutoTUnref<SkTypeface> typeface(this->matchFamilyStyle(familyName, style));
bsalomon49f085d2014-09-05 13:34:00 -0700895 if (typeface.get()) {
bungemana6785cc2014-08-25 12:00:49 -0700896 return typeface.detach();
897 }
898
halcanary96fcdcc2015-08-27 07:41:13 -0700899 return this->matchFamilyStyle(nullptr, style);
bungemana6785cc2014-08-25 12:00:49 -0700900 }
901};
902
bungeman0b1de262015-06-17 07:55:59 -0700903SK_API SkFontMgr* SkFontMgr_New_FontConfig(FcConfig* fc) {
904 return new SkFontMgr_fontconfig(fc);
bungemana6785cc2014-08-25 12:00:49 -0700905}