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

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