Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(22)

Side by Side Diff: src/ports/SkFontMgr_fontconfig.cpp

Issue 396143004: Add a working SkFontMgr_fontconfig. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Remove T& operator* from SkAutoTCallVProc. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « include/core/SkTemplates.h ('k') | tests/FontHostTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "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 'configura tion' 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 sta te.
42 *
43 * FcPatterns are {objectName -> [element]} (maps from object names to a list o f elements).
44 * Each element is some internal data plus an FcValue which is a variant (a uni on with a type tag).
45 * Lists of elements are not typed, except by convention. Any collection of FcV alues must be
46 * assumed to be heterogeneous by the code, but the code need not do anything p articularly
47 * interesting if the values go against convention.
48 *
49 * Somewhat like DirectWrite, FontConfig supports synthetics through FC_EMBOLDE N and FC_MATRIX.
50 * Like all synthetic information, such information must be passed with the fon t data.
51 */
52
53 namespace {
54
55 // Fontconfig is not threadsafe before 2.10.91. Before that, we lock with a glob al mutex.
56 // See http://skbug.com/1497 for background.
57 SK_DECLARE_STATIC_MUTEX(gFCMutex);
58
59 #ifdef SK_DEBUG
60 void *CreateThreadFcLocked() { return SkNEW(bool); }
61 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
66 struct 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
99 template<typename T, void (*P)(T*)> void FcTDestroy(T* t) {
100 FCLocker::AssertHeld();
101 P(t);
102 }
103 template <typename T, void (*P)(T*)> class SkAutoFc
104 : public SkAutoTCallVProc<T, FcTDestroy<T, P> > {
105 public:
106 SkAutoFc(T* obj) : SkAutoTCallVProc<T, FcTDestroy<T, P> >(obj) {}
107 };
108
109 typedef SkAutoFc<FcConfig, FcConfigDestroy> SkAutoFcConfig;
110 typedef SkAutoFc<FcFontSet, FcFontSetDestroy> SkAutoFcFontSet;
111 typedef SkAutoFc<FcLangSet, FcLangSetDestroy> SkAutoFcLangSet;
112 typedef SkAutoFc<FcObjectSet, FcObjectSetDestroy> SkAutoFcObjectSet;
113 typedef SkAutoFc<FcPattern, FcPatternDestroy> SkAutoFcPattern;
114
115 static int get_int(FcPattern* pattern, const char object[], int missing) {
116 int value;
117 if (FcPatternGetInteger(pattern, object, 0, &value) != FcResultMatch) {
118 return missing;
119 }
120 return value;
121 }
122
123 static const char* get_string(FcPattern* pattern, const char object[], const cha r* missing = "") {
124 FcChar8* value;
125 if (FcPatternGetString(pattern, object, 0, &value) != FcResultMatch) {
126 return missing;
127 }
128 return (const char*)value;
129 }
130
131 enum SkWeakReturn {
132 kIsWeak_WeakReturn,
133 kIsStrong_WeakReturn,
134 kNoId_WeakReturn
135 };
136 /** Ideally there would exist a call like
137 * FcResult FcPatternIsWeak(pattern, object, id, FcBool* isWeak);
138 *
139 * However, there is no such call and as of Fc 2.11.0 even FcPatternEquals igno res the weak bit.
140 * Currently, the only reliable way of finding the weak bit is by its effect on matching.
141 * The weak bit only affects the matching of FC_FAMILY and FC_POSTSCRIPT_NAME o bject values.
142 * A element with the weak bit is scored after FC_LANG, without the weak bit is scored before.
143 * Note that the weak bit is stored on the element, not on the value it holds.
144 */
145 static SkWeakReturn is_weak(FcPattern* pattern, const char object[], int id) {
146 FCLocker::AssertHeld();
147
148 FcResult result;
149
150 // Create a copy of the pattern with only the value 'pattern'['object'['id'] ] in it.
151 // Internally, FontConfig pattern objects are linked lists, so faster to rem ove from head.
152 SkAutoFcObjectSet requestedObjectOnly(FcObjectSetBuild(object, NULL));
153 SkAutoFcPattern minimal(FcPatternFilter(pattern, requestedObjectOnly));
154 FcBool hasId = true;
155 for (int i = 0; hasId && i < id; ++i) {
156 hasId = FcPatternRemove(minimal, object, 0);
157 }
158 if (!hasId) {
159 return kNoId_WeakReturn;
160 }
161 FcValue value;
162 result = FcPatternGet(minimal, object, 0, &value);
163 if (result != FcResultMatch) {
164 return kNoId_WeakReturn;
165 }
166 while (hasId) {
167 hasId = FcPatternRemove(minimal, object, 1);
168 }
169
170 // Create a font set with two patterns.
171 // 1. the same 'object' as minimal and a lang object with only 'nomatchlang' .
172 // 2. a different 'object' from minimal and a lang object with only 'matchla ng'.
173 SkAutoFcFontSet fontSet(FcFontSetCreate());
174
175 SkAutoFcLangSet strongLangSet(FcLangSetCreate());
176 FcLangSetAdd(strongLangSet, (const FcChar8*)"nomatchlang");
177 SkAutoFcPattern strong(FcPatternDuplicate(minimal));
178 FcPatternAddLangSet(strong, FC_LANG, strongLangSet);
179
180 SkAutoFcLangSet weakLangSet(FcLangSetCreate());
181 FcLangSetAdd(weakLangSet, (const FcChar8*)"matchlang");
182 SkAutoFcPattern weak(FcPatternCreate());
183 FcPatternAddString(weak, object, (const FcChar8*)"nomatchstring");
184 FcPatternAddLangSet(weak, FC_LANG, weakLangSet);
185
186 FcFontSetAdd(fontSet, strong.detach());
187 FcFontSetAdd(fontSet, weak.detach());
188
189 // Add 'matchlang' to the copy of the pattern.
190 FcPatternAddLangSet(minimal, FC_LANG, weakLangSet);
191
192 // Run a match against the copy of the pattern.
193 // If the 'id' was weak, then we should match the pattern with 'matchlang'.
194 // If the 'id' was strong, then we should match the pattern with 'nomatchlan g'.
195
196 // Note that this config is only used for FcFontRenderPrepare, which we don' t even want.
197 // However, there appears to be no way to match/sort without it.
198 SkAutoFcConfig config(FcConfigCreate());
199 FcFontSet* fontSets[1] = { fontSet };
200 SkAutoFcPattern match(FcFontSetMatch(config, fontSets, SK_ARRAY_COUNT(fontSe ts),
201 minimal, &result));
202
203 FcLangSet* matchLangSet;
204 FcPatternGetLangSet(match, FC_LANG, 0, &matchLangSet);
205 return FcLangEqual == FcLangSetHasLang(matchLangSet, (const FcChar8*)"matchl ang")
206 ? kIsWeak_WeakReturn : kIsStrong_WeakReturn;
207 }
208
209 /** Removes weak elements from either FC_FAMILY or FC_POSTSCRIPT_NAME objects in the property.
210 * This can be quite expensive, and should not be used more than once per font lookup.
211 * This removes all of the weak elements after the last strong element.
212 */
213 static void remove_weak(FcPattern* pattern, const char object[]) {
214 FCLocker::AssertHeld();
215
216 SkAutoFcObjectSet requestedObjectOnly(FcObjectSetBuild(object, NULL));
217 SkAutoFcPattern minimal(FcPatternFilter(pattern, requestedObjectOnly));
218
219 int lastStrongId = -1;
220 int numIds;
221 SkWeakReturn result;
222 for (int id = 0; ; ++id) {
223 result = is_weak(minimal, object, 0);
224 if (kNoId_WeakReturn == result) {
225 numIds = id;
226 break;
227 }
228 if (kIsStrong_WeakReturn == result) {
229 lastStrongId = id;
230 }
231 SkAssertResult(FcPatternRemove(minimal, object, 0));
232 }
233
234 // If they were all weak, then leave the pattern alone.
235 if (lastStrongId < 0) {
236 return;
237 }
238
239 // Remove everything after the last strong.
240 for (int id = lastStrongId + 1; id < numIds; ++id) {
241 SkAssertResult(FcPatternRemove(pattern, object, lastStrongId + 1));
242 }
243 }
244
245 static int map_range(SkFixed value,
246 SkFixed old_min, SkFixed old_max,
247 SkFixed new_min, SkFixed new_max)
248 {
249 SkASSERT(old_min < old_max);
250 SkASSERT(new_min <= new_max);
251 return new_min + SkMulDiv(value - old_min, new_max - new_min, old_max - old_ min);
252 }
253
254 static int ave(SkFixed a, SkFixed b) {
255 return SkFixedAve(a, b);
256 }
257
258 struct MapRanges {
259 SkFixed old_val;
260 SkFixed new_val;
261 };
262
263 static SkFixed map_ranges_fixed(SkFixed val, MapRanges const ranges[], int range sCount) {
264 // -Inf to [0]
265 if (val < ranges[0].old_val) {
266 return ranges[0].new_val;
267 }
268
269 // Linear from [i] to ave([i], [i+1]), then from ave([i], [i+1]) to [i+1]
270 for (int i = 0; i < rangesCount - 1; ++i) {
271 if (val < ave(ranges[i].old_val, ranges[i+1].old_val)) {
272 return map_range(val, ranges[i].old_val, ave(ranges[i].old_val, rang es[i+1].old_val),
273 ranges[i].new_val, ave(ranges[i].new_val, rang es[i+1].new_val));
274 }
275 if (val < ranges[i+1].old_val) {
276 return map_range(val, ave(ranges[i].old_val, ranges[i+1].old_val), r anges[i+1].old_val,
277 ave(ranges[i].new_val, ranges[i+1].new_val), r anges[i+1].new_val);
278 }
279 }
280
281 // From [n] to +Inf
282 // if (fcweight < Inf)
283 return ranges[rangesCount-1].new_val;
284 }
285
286 static int map_ranges(int val, MapRanges const ranges[], int rangesCount) {
287 return SkFixedRoundToInt(map_ranges_fixed(SkIntToFixed(val), ranges, rangesC ount));
288 }
289
290 template<int n> struct SkTFixed {
291 SK_COMPILE_ASSERT(-32768 <= n && n <= 32767, SkTFixed_n_not_in_range);
292 static const SkFixed value = static_cast<SkFixed>(n << 16);
293 };
294
295 static SkFontStyle skfontstyle_from_fcpattern(FcPattern* pattern) {
296 typedef SkFontStyle SkFS;
297
298 static const MapRanges weightRanges[] = {
299 { SkTFixed<FC_WEIGHT_THIN>::value, SkTFixed<SkFS::kThin_Weight>::v alue },
300 { SkTFixed<FC_WEIGHT_EXTRALIGHT>::value, SkTFixed<SkFS::kExtraLight_Weig ht>::value },
301 { SkTFixed<FC_WEIGHT_LIGHT>::value, SkTFixed<SkFS::kLight_Weight>:: value },
302 { SkTFixed<FC_WEIGHT_REGULAR>::value, SkTFixed<SkFS::kNormal_Weight>: :value },
303 { SkTFixed<FC_WEIGHT_MEDIUM>::value, SkTFixed<SkFS::kMedium_Weight>: :value },
304 { SkTFixed<FC_WEIGHT_DEMIBOLD>::value, SkTFixed<SkFS::kSemiBold_Weight >::value },
305 { SkTFixed<FC_WEIGHT_BOLD>::value, SkTFixed<SkFS::kBold_Weight>::v alue },
306 { SkTFixed<FC_WEIGHT_EXTRABOLD>::value, SkTFixed<SkFS::kExtraBold_Weigh t>::value },
307 { SkTFixed<FC_WEIGHT_BLACK>::value, SkTFixed<SkFS::kBlack_Weight>:: value },
308 { SkTFixed<FC_WEIGHT_EXTRABLACK>::value, SkTFixed<1000>::value },
309 };
310 int weight = map_ranges(get_int(pattern, FC_WEIGHT, FC_WEIGHT_REGULAR),
311 weightRanges, SK_ARRAY_COUNT(weightRanges));
312
313 static const MapRanges widthRanges[] = {
314 { SkTFixed<FC_WIDTH_ULTRACONDENSED>::value, SkTFixed<SkFS::kUltraCondens ed_Width>::value },
315 { SkTFixed<FC_WIDTH_EXTRACONDENSED>::value, SkTFixed<SkFS::kExtraCondens ed_Width>::value },
316 { SkTFixed<FC_WIDTH_CONDENSED>::value, SkTFixed<SkFS::kCondensed_Wi dth>::value },
317 { SkTFixed<FC_WIDTH_SEMICONDENSED>::value, SkTFixed<SkFS::kSemiCondense d_Width>::value },
318 { SkTFixed<FC_WIDTH_NORMAL>::value, SkTFixed<SkFS::kNormal_Width >::value },
319 { SkTFixed<FC_WIDTH_SEMIEXPANDED>::value, SkTFixed<SkFS::kSemiExpanded _Width>::value },
320 { SkTFixed<FC_WIDTH_EXPANDED>::value, SkTFixed<SkFS::kExpanded_Wid th>::value },
321 { SkTFixed<FC_WIDTH_EXTRAEXPANDED>::value, SkTFixed<SkFS::kExtraExpande d_Width>::value },
322 { SkTFixed<FC_WIDTH_ULTRAEXPANDED>::value, SkTFixed<SkFS::kUltaExpanded _Width>::value },
323 };
324 int width = map_ranges(get_int(pattern, FC_WIDTH, FC_WIDTH_NORMAL),
325 widthRanges, SK_ARRAY_COUNT(widthRanges));
326
327 SkFS::Slant slant = get_int(pattern, FC_SLANT, FC_SLANT_ROMAN) > 0
328 ? SkFS::kItalic_Slant
329 : SkFS::kUpright_Slant;
330
331 return SkFontStyle(weight, width, slant);
332 }
333
334 static void fcpattern_from_skfontstyle(SkFontStyle style, FcPattern* pattern) {
335 FCLocker::AssertHeld();
336
337 typedef SkFontStyle SkFS;
338
339 static const MapRanges weightRanges[] = {
340 { SkTFixed<SkFS::kThin_Weight>::value, SkTFixed<FC_WEIGHT_THIN>::v alue },
341 { SkTFixed<SkFS::kExtraLight_Weight>::value, SkTFixed<FC_WEIGHT_EXTRALIG HT>::value },
342 { SkTFixed<SkFS::kLight_Weight>::value, SkTFixed<FC_WEIGHT_LIGHT>:: value },
343 { SkTFixed<SkFS::kNormal_Weight>::value, SkTFixed<FC_WEIGHT_REGULAR> ::value },
344 { SkTFixed<SkFS::kMedium_Weight>::value, SkTFixed<FC_WEIGHT_MEDIUM>: :value },
345 { SkTFixed<SkFS::kSemiBold_Weight>::value, SkTFixed<FC_WEIGHT_DEMIBOLD >::value },
346 { SkTFixed<SkFS::kBold_Weight>::value, SkTFixed<FC_WEIGHT_BOLD>::v alue },
347 { SkTFixed<SkFS::kExtraBold_Weight>::value, SkTFixed<FC_WEIGHT_EXTRABOL D>::value },
348 { SkTFixed<SkFS::kBlack_Weight>::value, SkTFixed<FC_WEIGHT_BLACK>:: value },
349 { SkTFixed<1000>::value, SkTFixed<FC_WEIGHT_EXTRABLA CK>::value },
350 };
351 int weight = map_ranges(style.weight(), weightRanges, SK_ARRAY_COUNT(weightR anges));
352
353 static const MapRanges widthRanges[] = {
354 { SkTFixed<SkFS::kUltraCondensed_Width>::value, SkTFixed<FC_WIDTH_ULTRAC ONDENSED>::value },
355 { SkTFixed<SkFS::kExtraCondensed_Width>::value, SkTFixed<FC_WIDTH_EXTRAC ONDENSED>::value },
356 { SkTFixed<SkFS::kCondensed_Width>::value, SkTFixed<FC_WIDTH_CONDEN SED>::value },
357 { SkTFixed<SkFS::kSemiCondensed_Width>::value, SkTFixed<FC_WIDTH_SEMICO NDENSED>::value },
358 { SkTFixed<SkFS::kNormal_Width>::value, SkTFixed<FC_WIDTH_NORMAL >::value },
359 { SkTFixed<SkFS::kSemiExpanded_Width>::value, SkTFixed<FC_WIDTH_SEMIEX PANDED>::value },
360 { SkTFixed<SkFS::kExpanded_Width>::value, SkTFixed<FC_WIDTH_EXPAND ED>::value },
361 { SkTFixed<SkFS::kExtraExpanded_Width>::value, SkTFixed<FC_WIDTH_EXTRAE XPANDED>::value },
362 { SkTFixed<SkFS::kUltaExpanded_Width>::value, SkTFixed<FC_WIDTH_ULTRAE XPANDED>::value },
363 };
364 int width = map_ranges(style.width(), widthRanges, SK_ARRAY_COUNT(widthRange s));
365
366 FcPatternAddInteger(pattern, FC_WEIGHT, weight);
367 FcPatternAddInteger(pattern, FC_WIDTH, width);
368 FcPatternAddInteger(pattern, FC_SLANT, style.isItalic() ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
369 }
370
371 static SkTypeface::Style sktypefacestyle_from_fcpattern(FcPattern* pattern) {
372 int fcweight = get_int(pattern, FC_WEIGHT, FC_WEIGHT_REGULAR);
373 int fcslant = get_int(pattern, FC_SLANT, FC_SLANT_ROMAN);
374 return (SkTypeface::Style)((fcweight >= FC_WEIGHT_BOLD ? SkTypeface::kBold : 0) |
375 (fcslant > FC_SLANT_ROMAN ? SkTypeface::kItalic : 0));
376 }
377
378 class SkTypeface_stream : public SkTypeface_FreeType {
379 public:
380 /** @param stream does not take ownership of the reference, does take owners hip of the stream.*/
381 SkTypeface_stream(SkTypeface::Style style, bool fixedWidth, int ttcIndex, Sk StreamAsset* stream)
382 : INHERITED(style, SkTypefaceCache::NewFontID(), fixedWidth)
383 , fStream(SkRef(stream))
384 , fIndex(ttcIndex)
385 { };
386
387 virtual void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) co nst SK_OVERRIDE {
388 desc->setStyle(this->style());
389 *serialize = true;
390 }
391
392 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
393 *ttcIndex = fIndex;
394 return fStream->duplicate();
395 }
396
397 private:
398 SkAutoTUnref<SkStreamAsset> fStream;
399 int fIndex;
400
401 typedef SkTypeface_FreeType INHERITED;
402 };
403
404 class SkTypeface_fontconfig : public SkTypeface_FreeType {
405 public:
406 /** @param pattern takes ownership of the reference. */
407 static SkTypeface_fontconfig* Create(FcPattern* pattern) {
408 return SkNEW_ARGS(SkTypeface_fontconfig, (pattern));
409 }
410 mutable SkAutoFcPattern fPattern;
411
412 virtual void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) co nst SK_OVERRIDE {
413 FCLocker lock;
414 desc->setFamilyName(get_string(fPattern, FC_FAMILY));
415 desc->setFontFileName(get_string(fPattern, FC_FILE));
416 desc->setFullName(get_string(fPattern, FC_FULLNAME));
417 desc->setPostscriptName(get_string(fPattern, FC_POSTSCRIPT_NAME));
418 desc->setStyle(this->style());
419 *serialize = false;
420 }
421
422 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
423 FCLocker lock;
424 *ttcIndex = get_int(fPattern, FC_INDEX, 0);
425 return SkStream::NewFromFile(get_string(fPattern, FC_FILE));
426 }
427
428 virtual ~SkTypeface_fontconfig() {
429 // Hold the lock while unrefing the pattern.
430 FCLocker lock;
431 fPattern.reset();
432 }
433
434 private:
435 /** @param pattern takes ownership of the reference. */
436 SkTypeface_fontconfig(FcPattern* pattern)
437 : INHERITED(sktypefacestyle_from_fcpattern(pattern),
438 SkTypefaceCache::NewFontID(),
439 FC_PROPORTIONAL != get_int(pattern, FC_SPACING, FC_PROPORTIO NAL))
440 , fPattern(pattern)
441 { };
442
443 typedef SkTypeface_FreeType INHERITED;
444 };
445
446 class SkFontMgr_fontconfig : public SkFontMgr {
447 mutable SkAutoFcConfig fFC;
448 SkAutoTUnref<SkDataTable> fFamilyNames;
449
450 class StyleSet : public SkFontStyleSet {
451 public:
452 /** @param parent does not take ownership of the reference.
453 * @param fontSet takes ownership of the reference.
454 */
455 StyleSet(const SkFontMgr_fontconfig* parent, FcFontSet* fontSet)
456 : fFontMgr(SkRef(parent)), fFontSet(fontSet)
457 { }
458
459 virtual ~StyleSet() {
460 // Hold the lock while unrefing the font set.
461 FCLocker lock;
462 fFontSet.reset();
463 }
464
465 virtual int count() SK_OVERRIDE { return fFontSet->nfont; }
466
467 virtual void getStyle(int index, SkFontStyle* style, SkString* styleName ) SK_OVERRIDE {
468 if (index < 0 || fFontSet->nfont <= index) {
469 return;
470 }
471
472 FCLocker lock;
473 if (style) {
474 *style = skfontstyle_from_fcpattern(fFontSet->fonts[index]);
475 }
476 if (styleName) {
477 *styleName = get_string(fFontSet->fonts[index], FC_STYLE);
478 }
479 }
480
481 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
482 FCLocker lock;
483
484 FcPattern* match = fFontSet->fonts[index];
485 return fFontMgr->createTypefaceFromFcPattern(match);
486 }
487
488 virtual SkTypeface* matchStyle(const SkFontStyle& style) SK_OVERRIDE {
489 FCLocker lock;
490
491 SkAutoFcPattern pattern(FcPatternCreate());
492 if (NULL == pattern) {
493 return NULL;
494 }
495
496 fcpattern_from_skfontstyle(style, pattern);
497 FcConfigSubstitute(fFontMgr->fFC, pattern, FcMatchPattern);
498 FcDefaultSubstitute(pattern);
499
500 FcResult result;
501 FcFontSet* fontSets[1] = { fFontSet };
502 SkAutoFcPattern match(FcFontSetMatch(fFontMgr->fFC,
503 fontSets, SK_ARRAY_COUNT(fontSe ts),
504 pattern, &result));
505 if (NULL == match) {
506 return NULL;
507 }
508
509 return fFontMgr->createTypefaceFromFcPattern(match);
510 }
511
512 private:
513 SkAutoTUnref<const SkFontMgr_fontconfig> fFontMgr;
514 SkAutoFcFontSet fFontSet;
515 };
516
517 static bool FindName(const SkTDArray<const char*>& list, const char* str) {
518 int count = list.count();
519 for (int i = 0; i < count; ++i) {
520 if (!strcmp(list[i], str)) {
521 return true;
522 }
523 }
524 return false;
525 }
526
527 static SkDataTable* GetFamilyNames(FcConfig* fcconfig) {
528 FCLocker lock;
529
530 SkTDArray<const char*> names;
531 SkTDArray<size_t> sizes;
532
533 static const FcSetName fcNameSet[] = { FcSetSystem, FcSetApplication };
534 for (int setIndex = 0; setIndex < (int)SK_ARRAY_COUNT(fcNameSet); ++setI ndex) {
535 // Return value of FcConfigGetFonts must not be destroyed.
536 FcFontSet* allFonts(FcConfigGetFonts(fcconfig, fcNameSet[setIndex])) ;
537 if (NULL == allFonts) {
538 continue;
539 }
540
541 for (int fontIndex = 0; fontIndex < allFonts->nfont; ++fontIndex) {
542 FcPattern* current = allFonts->fonts[fontIndex];
543 for (int id = 0; ; ++id) {
544 FcChar8* fcFamilyName;
545 FcResult result = FcPatternGetString(current, FC_FAMILY, id, &fcFamilyName);
546 if (FcResultNoId == result) {
547 break;
548 }
549 if (FcResultMatch != result) {
550 continue;
551 }
552 const char* familyName = reinterpret_cast<const char*>(fcFam ilyName);
553 if (familyName && !FindName(names, familyName)) {
554 *names.append() = familyName;
555 *sizes.append() = strlen(familyName) + 1;
556 }
557 }
558 }
559 }
560
561 return SkDataTable::NewCopyArrays((void const *const *)names.begin(),
562 sizes.begin(), names.count());
563 }
564
565 static bool FindByFcPattern(SkTypeface* cached, SkTypeface::Style, void* ctx ) {
566 SkTypeface_fontconfig* cshFace = static_cast<SkTypeface_fontconfig*>(cac hed);
567 FcPattern* ctxPattern = static_cast<FcPattern*>(ctx);
568 return FcTrue == FcPatternEqual(cshFace->fPattern, ctxPattern);
569 }
570
571 mutable SkMutex fTFCacheMutex;
572 mutable SkTypefaceCache fTFCache;
573 /** Creates a typeface using a typeface cache.
574 * @param pattern a complete pattern from FcFontRenderPrepare.
575 */
576 SkTypeface* createTypefaceFromFcPattern(FcPattern* pattern) const {
577 FCLocker::AssertHeld();
578 SkAutoMutexAcquire ama(fTFCacheMutex);
579 SkTypeface* face = fTFCache.findByProcAndRef(FindByFcPattern, pattern);
580 if (NULL == face) {
581 FcPatternReference(pattern);
582 face = SkTypeface_fontconfig::Create(pattern);
583 if (face) {
584 fTFCache.add(face, SkTypeface::kNormal, true);
585 }
586 }
587 return face;
588 }
589
590 public:
591 SkFontMgr_fontconfig()
592 : fFC(FcInitLoadConfigAndFonts())
593 , fFamilyNames(GetFamilyNames(fFC)) { }
594
595 /** Takes control of the reference to 'config'. */
596 explicit SkFontMgr_fontconfig(FcConfig* config)
597 : fFC(config)
598 , fFamilyNames(GetFamilyNames(fFC)) { }
599
600 virtual ~SkFontMgr_fontconfig() {
601 // Hold the lock while unrefing the config.
602 FCLocker lock;
603 fFC.reset();
604 }
605
606 protected:
607 virtual int onCountFamilies() const SK_OVERRIDE {
608 return fFamilyNames->count();
609 }
610
611 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERR IDE {
612 familyName->set(fFamilyNames->atStr(index));
613 }
614
615 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
616 return this->onMatchFamily(fFamilyNames->atStr(index));
617 }
618
619 /** True if any string object value in the font is the same
620 * as a string object value in the pattern.
621 */
622 static bool AnyMatching(FcPattern* font, FcPattern* pattern, const char* obj ect) {
623 FcChar8* fontString;
624 FcChar8* patternString;
625 FcResult result;
626 // Set an arbitrary limit on the number of pattern object values to cons ider.
627 // TODO: re-write this to avoid N*M
628 static const int maxId = 16;
629 for (int patternId = 0; patternId < maxId; ++patternId) {
630 result = FcPatternGetString(pattern, object, patternId, &patternStri ng);
631 if (FcResultNoId == result) {
632 break;
633 }
634 if (FcResultMatch != result) {
635 continue;
636 }
637 for (int fontId = 0; fontId < maxId; ++fontId) {
638 result = FcPatternGetString(font, object, fontId, &fontString);
639 if (FcResultNoId == result) {
640 break;
641 }
642 if (FcResultMatch != result) {
643 continue;
644 }
645 if (0 == FcStrCmpIgnoreCase(patternString, fontString)) {
646 return true;
647 }
648 }
649 }
650 return false;
651 }
652
653 static bool ValidPattern(FcPattern* pattern) {
654 // FontConfig can return fonts which are unreadable.
655 const char* filename = get_string(pattern, FC_FILE, NULL);
656 if (NULL == filename) {
657 return false;
658 }
659 return sk_exists(filename, kRead_SkFILE_Flag);
660 }
661
662 static bool FontMatches(FcPattern* font, FcPattern* pattern) {
663 return ValidPattern(font) && AnyMatching(font, pattern, FC_FAMILY);
664 }
665
666 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVER RIDE {
667 FCLocker lock;
668
669 SkAutoFcPattern pattern(FcPatternCreate());
670 if (NULL == pattern) {
671 return NULL;
672 }
673
674 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
675 FcConfigSubstitute(fFC, pattern, FcMatchPattern);
676 FcDefaultSubstitute(pattern);
677
678 FcPattern* matchPattern;
679 SkAutoFcPattern strongPattern(NULL);
680 if (familyName) {
681 strongPattern.reset(FcPatternDuplicate(pattern));
682 remove_weak(strongPattern, FC_FAMILY);
683 matchPattern = strongPattern;
684 } else {
685 matchPattern = pattern;
686 }
687
688 SkAutoFcFontSet matches(FcFontSetCreate());
689 // TODO: Some families have 'duplicates' due to symbolic links.
690 // The patterns are exactly the same except for the FC_FILE.
691 // It should be possible to collapse these patterns by normalizing.
692 static const FcSetName fcNameSet[] = { FcSetSystem, FcSetApplication };
693 for (int setIndex = 0; setIndex < (int)SK_ARRAY_COUNT(fcNameSet); ++setI ndex) {
694 // Return value of FcConfigGetFonts must not be destroyed.
695 FcFontSet* allFonts(FcConfigGetFonts(fFC, fcNameSet[setIndex]));
696 if (NULL == allFonts) {
697 continue;
698 }
699
700 for (int fontIndex = 0; fontIndex < allFonts->nfont; ++fontIndex) {
701 if (FontMatches(allFonts->fonts[fontIndex], matchPattern)) {
702 FcFontSetAdd(matches,
703 FcFontRenderPrepare(fFC, pattern, allFonts->fon ts[fontIndex]));
djsollen 2014/08/26 13:05:07 Valgrind is picking up a leak here!
704 }
705 }
706 }
707
708 return SkNEW_ARGS(StyleSet, (this, matches.detach()));
709 }
710
711 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
712 const SkFontStyle& style) const SK_OV ERRIDE
713 {
714 FCLocker lock;
715
716 SkAutoFcPattern pattern(FcPatternCreate());
717 if (NULL == pattern) {
718 return NULL;
719 }
720
721 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
722 fcpattern_from_skfontstyle(style, pattern);
723 FcConfigSubstitute(fFC, pattern, FcMatchPattern);
724 FcDefaultSubstitute(pattern);
725
726 // We really want to match strong (prefered) and same (acceptable) only here.
727 // If a family name was specified, assume that any weak matches after th e last strong match
728 // are weak (default) and ignore them.
729 // The reason for is that after substitution the pattern for 'sans-serif ' looks like
730 // "wwwwwwwwwwwwwwswww" where there are many weak but preferred names, f ollowed by defaults.
731 // So it is possible to have weakly matching but preferred names.
732 // In aliases, bindings are weak by default, so this is easy and common.
733 // If no family name was specified, we'll probably only get weak matches , but that's ok.
734 FcPattern* matchPattern;
735 SkAutoFcPattern strongPattern(NULL);
736 if (familyName) {
737 strongPattern.reset(FcPatternDuplicate(pattern));
738 remove_weak(strongPattern, FC_FAMILY);
739 matchPattern = strongPattern;
740 } else {
741 matchPattern = pattern;
742 }
743
744 FcResult result;
745 SkAutoFcPattern match(FcFontMatch(fFC, pattern, &result));
746 if (NULL == match || !FontMatches(match, matchPattern)) {
747 return NULL;
748 }
749
750 return createTypefaceFromFcPattern(match);
751 }
752
753 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* typeface,
754 const SkFontStyle& style) const SK_OVER RIDE
755 {
756 //TODO: should the SkTypeface_fontconfig know its family?
757 const SkTypeface_fontconfig* fcTypeface =
758 static_cast<const SkTypeface_fontconfig*>(typeface);
759 return this->matchFamilyStyle(get_string(fcTypeface->fPattern, FC_FAMILY ), style);
760 }
761
762 /** @param stream does not take ownership of the reference. */
763 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
764 const size_t length = stream->getLength();
765 if (length <= 0 || (1u << 30) < length) {
766 return NULL;
767 }
768
769 SkTypeface::Style style = SkTypeface::kNormal;
770 bool isFixedWidth = false;
771 if (!SkTypeface_FreeType::ScanFont(stream, ttcIndex, NULL, &style, &isFi xedWidth)) {
772 return NULL;
773 }
774
775 return SkNEW_ARGS(SkTypeface_stream, (style, isFixedWidth, ttcIndex,
776 static_cast<SkStreamAsset*>(stream )));
777 }
778
779 virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OV ERRIDE {
780 SkAutoTUnref<SkStreamAsset> stream(SkNEW_ARGS(SkMemoryStream, (data)));
781 return this->createFromStream(stream, ttcIndex);
782 }
783
784 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
785 SkAutoTUnref<SkStreamAsset> stream(SkStream::NewFromFile(path));
786 return this->createFromStream(stream, ttcIndex);
787 }
788
789 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
790 unsigned styleBits) const SK_OVER RIDE {
791 bool bold = styleBits & SkTypeface::kBold;
792 bool italic = styleBits & SkTypeface::kItalic;
793 SkFontStyle style = SkFontStyle(bold ? SkFontStyle::kBold_Weight
794 : SkFontStyle::kNormal_Weight,
795 SkFontStyle::kNormal_Width,
796 italic ? SkFontStyle::kItalic_Slant
797 : SkFontStyle::kUpright_Slant);
798 SkAutoTUnref<SkTypeface> typeface(this->matchFamilyStyle(familyName, sty le));
799 if (NULL != typeface.get()) {
800 return typeface.detach();
801 }
802
803 return this->matchFamilyStyle(NULL, style);
804 }
805 };
806
807 SkFontMgr* SkFontMgr::Factory() {
808 return SkNEW(SkFontMgr_fontconfig);
809 }
OLDNEW
« no previous file with comments | « include/core/SkTemplates.h ('k') | tests/FontHostTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698