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

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: 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
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 #ifdef SK_DEBUG
24 # include "SkTLS.h"
25 #endif
26
27 /** Since FontConfig is poorly documented, a short overview primer:
28 *
29 * FcConfig is a library state. There exists a default global state which is af fected by
tomhudson 2014/07/17 21:14:46 Nit: Not sure what you mean by a "library state".
bungeman-skia 2014/07/17 22:08:27 Yeah, I wan't entirely sure what to call it. FreeT
30 * FcInit and FcFini, but this default should not normally be used.
31 * Instead, one should use FcConfigCreate and FcInit* to have a named local sta te.
32 *
33 * FcPatterns are {objectName -> [element]} (maps from object names to a list o f elements).
34 * Each element is some custom data plus an FcValue which is a variant (a union with a type tag).
35 * Any documentation which states that a given object maps to a given type actu ally means that
36 * it is expected that all the values in the list mapped to by objectName will be of that type.
37 * However, there is actually no real enforcement.
tomhudson 2014/07/17 21:14:46 Nit: The previous sentence is just a bit awkward,
bungeman-skia 2014/07/17 22:08:27 Hmmm... yes. The list isn't typed at all, except b
38 *
39 * Somewhat like DirectWrite, FontConfig supports synthetics through FC_EMBOLDE N and FC_MATRIX.
40 * Like all synthetic information, such information must be passed with the fon t data.
41 */
42
43 namespace {
44
45 // Fontconfig is not threadsafe before 2.10.91. Before that, we lock with a glob al mutex.
46 // See skia:1497 for background.
tomhudson 2014/07/17 21:14:46 Nit: please spell out the link to http://skbug.com
bungeman-skia 2014/07/17 22:08:27 Done.
47 SK_DECLARE_STATIC_MUTEX(gFCMutex);
48
49 #ifdef SK_DEBUG
50 void *CreateThreadFcLocked() { return SkNEW(bool); }
51 void DeleteThreadFcLocked(void* v) { SkDELETE(reinterpret_cast<bool*>(v)); }
52 # define THREAD_FC_LOCKED \
53 reinterpret_cast<bool*>(SkTLS::Get(CreateThreadFcLocked, DeleteThreadFcL ocked))
54 #endif
55
56 struct FCLocker {
57 // Assume FcGetVersion() has always been thread safe.
58
59 FCLocker() {
60 if (FcGetVersion() < 21091) {
61 gFCMutex.acquire();
62 fUnlock = true;
63 } else {
64 SkDEBUGCODE(bool* threadLocked = THREAD_FC_LOCKED);
65 SkASSERT(0 == *threadLocked);
66 SkDEBUGCODE(*threadLocked = true);
67 }
68 }
69
70 ~FCLocker() {
71 if (FcGetVersion() < 21091) {
72 if (fUnlock) {
73 gFCMutex.release();
74 }
75 } else {
76 SkDEBUGCODE(bool* threadLocked = THREAD_FC_LOCKED);
77 SkASSERT(1 == *threadLocked);
78 SkDEBUGCODE(*threadLocked = false);
79 }
80 }
81
82 static void AssertHeld() { SkDEBUGCODE(
83 if (FcGetVersion() < 21091) {
84 gFCMutex.assertHeld();
85 } else {
86 SkASSERT(true == *THREAD_FC_LOCKED);
87 }
88 ) }
89
90 private:
91 bool fUnlock;
92 };
93
94 } // namespace
95
96 template<typename T, void (*P)(T*)> void FcTDestroy(T* t) {
97 FCLocker::AssertHeld();
98 P(t);
99 }
100 typedef SkAutoTCallVProc<FcConfig, FcTDestroy<FcConfig, FcConfigDestroy> > SkAut oFcConfig;
101 typedef SkAutoTCallVProc<FcFontSet, FcTDestroy<FcFontSet, FcFontSetDestroy> > Sk AutoFcFontSet;
102 typedef SkAutoTCallVProc<FcLangSet, FcTDestroy<FcLangSet, FcLangSetDestroy> > Sk AutoFcLangSet;
103 typedef SkAutoTCallVProc<FcObjectSet, FcTDestroy<FcObjectSet, FcObjectSetDestroy > > SkAutoFcObjectSet;
104 typedef SkAutoTCallVProc<FcPattern, FcTDestroy<FcPattern, FcPatternDestroy> > Sk AutoFcPattern;
105
106 static int get_int(FcPattern* pattern, const char object[], int missing) {
107 int value;
108 if (FcPatternGetInteger(pattern, object, 0, &value) != FcResultMatch) {
109 return missing;
110 }
111 return value;
112 }
113
114 static const char* get_string(FcPattern* pattern, const char object[], const cha r* missing = "") {
115 FcChar8* value;
116 if (FcPatternGetString(pattern, object, 0, &value) != FcResultMatch) {
117 return missing;
118 }
119 return (const char*)value;
120 }
121
122 enum is_weak_return {
123 isWeak, isStrong, noId
124 };
125 /** Ideally there would exist a call like
126 * FcResult FcPatternIsWeak(pattern, object, id, FcBool* isWeak);
127 *
128 * However, there is no such call and as of Fc 2.11.0 even FcPatternEquals igno res the weak bit.
129 * Currently, the only reliable way of finding the weak bit is by its effect on matching.
130 * The weak bit only affects the matching of FC_FAMILY and FC_POSTSCRIPT_NAME o bject values.
131 * A element with the weak bit is scored after FC_LANG, without the weak bit is scored before.
132 * Note that the weak bit is stored on the element, not on the value it holds.
133 */
134 static is_weak_return is_weak(FcPattern* pattern, const char object[], int id) {
135 FCLocker::AssertHeld();
136
137 FcResult result;
138
139 // Create a copy of the pattern with only the value 'pattern'['object'['id'] ] in it.
140 // Internally, FontConfig pattern objects are linked lists, so faster to rem ove from head.
141 SkAutoFcObjectSet requestedObjectOnly(FcObjectSetBuild(object, NULL));
142 SkAutoFcPattern minimal(FcPatternFilter(pattern, requestedObjectOnly));
143 FcBool hasId = true;
144 for (int i = 0; hasId && i < id; ++i) {
145 hasId = FcPatternRemove(minimal, object, 0);
146 }
147 if (!hasId) {
148 return noId;
149 }
150 FcValue value;
151 result = FcPatternGet(minimal, object, 0, &value);
152 if (result != FcResultMatch) {
153 return noId;
154 }
155 while (hasId) {
156 hasId = FcPatternRemove(minimal, object, 1);
157 }
158
159 // Create a font set with two patterns.
160 // 1. the same 'object' as minimal and a lang object with only 'nomatchlang' .
161 // 2. a different 'object' from minimal and a lang object with only 'matchla ng'.
162 SkAutoFcFontSet fontSet(FcFontSetCreate());
163
164 SkAutoFcLangSet strongLangSet(FcLangSetCreate());
165 FcLangSetAdd(strongLangSet, (const FcChar8*)"nomatchlang");
166 SkAutoFcPattern strong(FcPatternDuplicate(minimal));
167 FcPatternAddLangSet(strong, FC_LANG, strongLangSet);
168
169 SkAutoFcLangSet weakLangSet(FcLangSetCreate());
170 FcLangSetAdd(weakLangSet, (const FcChar8*)"matchlang");
171 SkAutoFcPattern weak(FcPatternCreate());
172 FcPatternAddString(weak, object, (const FcChar8*)"nomatchstring");
173 FcPatternAddLangSet(weak, FC_LANG, weakLangSet);
174
175 FcFontSetAdd(fontSet, strong);
176 FcFontSetAdd(fontSet, weak);
177
178 // Add 'matchlang' to the copy of the pattern.
179 FcPatternAddLangSet(minimal, FC_LANG, weakLangSet);
180
181 // Run a match against the copy of the pattern.
182 // If the 'id' was weak, then we should match the pattern with 'matchlang'.
183 // If the 'id' was strong, then we should match the pattern with 'nomatchlan g'.
184
185 // Note that this config is only used for FcFontRenderPrepare, which we don' t even want.
186 // However, there appears to be no way to match/sort without it.
187 SkAutoFcConfig config(FcConfigCreate());
188 SkAutoFcPattern match(FcFontSetMatch(config, &fontSet, 1, minimal, &result)) ;
189
190 FcLangSet* matchLangSet;
191 FcPatternGetLangSet(match, FC_LANG, 0, &matchLangSet);
192 return FcLangEqual == FcLangSetHasLang(matchLangSet, (const FcChar8*)"matchl ang")
193 ? isWeak : isStrong;
194 }
195
196 /** Removes weak elements from either FC_FAMILY or FC_POSTSCRIPT_NAME objects in the property.
197 * This can be quite expensive, and should not be used more than once per font lookup.
198 * This removes all of the weak elements after the last strong element.
199 */
200 static void remove_weak(FcPattern* pattern, const char object[]) {
201 FCLocker::AssertHeld();
202
203 SkAutoFcObjectSet requestedObjectOnly(FcObjectSetBuild(object, NULL));
204 SkAutoFcPattern minimal(FcPatternFilter(pattern, requestedObjectOnly));
205
206 int lastStrongId = -1;
207 int numIds;
208 is_weak_return result;
209 for (int id = 0; ; ++id) {
210 result = is_weak(minimal, object, 0);
211 if (noId == result) {
212 numIds = id;
213 break;
214 }
215 if (isStrong == result) {
216 lastStrongId = id;
217 }
218 SkAssertResult(FcPatternRemove(minimal, object, 0));
219 }
220
221 // If they were all weak, then leave the pattern alone.
222 if (lastStrongId < 0) {
223 return;
224 }
225
226 // Remove everything after the last strong.
227 for (int id = lastStrongId + 1; id < numIds; ++id) {
228 SkAssertResult(FcPatternRemove(pattern, object, lastStrongId + 1));
229 }
230 }
231
232 static int map_range(SkFixed value,
233 SkFixed old_min, SkFixed old_max,
234 SkFixed new_min, SkFixed new_max)
235 {
236 SkASSERT(old_min < old_max);
237 SkASSERT(new_min <= new_max);
238 return new_min + SkMulDiv(value - old_min, new_max - new_min,
239 old_max - old_min);
240 }
241
242 static int ave(SkFixed a, SkFixed b) {
243 return SkFixedAve(a, b);
244 }
245
246 struct MapRanges {
247 SkFixed old_val;
248 SkFixed new_val;
249 };
250
251 static SkFixed map_ranges_fixed(SkFixed val, MapRanges const ranges[], int range sCount) {
252 // -Inf to [0]
253 if (val < ranges[0].old_val)
254 return ranges[0].new_val;
255
256 // Linear from [i] to ave([i], [i+1]), then from ave([i], [i+1]) to [i+1]
257 for (int i = 0; i < rangesCount - 1; ++i) {
258 if (val < ave(ranges[i].old_val, ranges[i+1].old_val))
259 return map_range(val, ranges[i].old_val, ave(ranges[i].old_val, rang es[i+1].old_val),
260 ranges[i].new_val, ave(ranges[i].new_val, rang es[i+1].new_val));
261 if (val < ranges[i+1].old_val)
262 return map_range(val, ave(ranges[i].old_val, ranges[i+1].old_val), r anges[i+1].old_val,
263 ave(ranges[i].new_val, ranges[i+1].new_val), r anges[i+1].new_val);
264 }
265
266 // From [n] to +Inf
267 // if (fcweight < Inf)
268 return ranges[rangesCount-1].new_val;
269 }
270
271 static int map_ranges(int val, MapRanges const ranges[], int rangesCount) {
272 return SkFixedRoundToInt(map_ranges_fixed(SkIntToFixed(val), ranges, rangesC ount));
273 }
274
275 template<int n> struct SkTIntToFixed {
276 SK_COMPILE_ASSERT(-32768 <= n && n <= 32767, SkTIntToFixed_n_not_in_range);
277 static const SkFixed value = static_cast<SkFixed>(n << 16);
278 };
279
280 static SkFontStyle skfontstyle_from_fcpattern(FcPattern* pattern) {
tomhudson 2014/07/17 21:14:46 Nit: line lengths?
bungeman-skia 2014/07/17 22:08:27 Done.
281 static const MapRanges weightRanges[] = {
282 { SkTIntToFixed<FC_WEIGHT_THIN>::value, SkTIntToFixed<SkFontStyle::kThin _Weight>::value },
283 { SkTIntToFixed<FC_WEIGHT_EXTRALIGHT>::value, SkTIntToFixed<SkFontStyle: :kExtraLight_Weight>::value },
284 { SkTIntToFixed<FC_WEIGHT_LIGHT>::value, SkTIntToFixed<SkFontStyle::kLig ht_Weight>::value },
285 { SkTIntToFixed<FC_WEIGHT_REGULAR>::value, SkTIntToFixed<SkFontStyle::kN ormal_Weight>::value },
286 { SkTIntToFixed<FC_WEIGHT_MEDIUM>::value, SkTIntToFixed<SkFontStyle::kMe dium_Weight>::value },
287 { SkTIntToFixed<FC_WEIGHT_DEMIBOLD>::value, SkTIntToFixed<SkFontStyle::k SemiBold_Weight>::value },
288 { SkTIntToFixed<FC_WEIGHT_BOLD>::value, SkTIntToFixed<SkFontStyle::kBold _Weight>::value },
289 { SkTIntToFixed<FC_WEIGHT_EXTRABOLD>::value, SkTIntToFixed<SkFontStyle:: kExtraBold_Weight>::value },
290 { SkTIntToFixed<FC_WEIGHT_BLACK>::value, SkTIntToFixed<SkFontStyle::kBla ck_Weight>::value },
291 { SkTIntToFixed<FC_WEIGHT_EXTRABLACK>::value, SkTIntToFixed<1000>::value },
292 };
293 int weight = map_ranges(get_int(pattern, FC_WEIGHT, FC_WEIGHT_REGULAR),
294 weightRanges, SK_ARRAY_COUNT(weightRanges));
295
296 static const MapRanges widthRanges[] = {
297 { SkTIntToFixed<FC_WIDTH_ULTRACONDENSED>::value, SkTIntToFixed<SkFontSty le::kUltraCondensed_Width>::value },
298 { SkTIntToFixed<FC_WIDTH_EXTRACONDENSED>::value, SkTIntToFixed<SkFontSty le::kExtraCondensed_Width>::value },
299 { SkTIntToFixed<FC_WIDTH_CONDENSED>::value, SkTIntToFixed<SkFontStyle::k Condensed_Width>::value },
300 { SkTIntToFixed<FC_WIDTH_SEMICONDENSED>::value, SkTIntToFixed<SkFontStyl e::kSemiCondensed_Width>::value },
301 { SkTIntToFixed<FC_WIDTH_NORMAL>::value, SkTIntToFixed<SkFontStyle::kNor mal_Width>::value },
302 { SkTIntToFixed<FC_WIDTH_SEMIEXPANDED>::value, SkTIntToFixed<SkFontStyle ::kSemiExpanded_Width>::value },
303 { SkTIntToFixed<FC_WIDTH_EXPANDED>::value, SkTIntToFixed<SkFontStyle::kE xpanded_Width>::value },
304 { SkTIntToFixed<FC_WIDTH_EXTRAEXPANDED>::value, SkTIntToFixed<SkFontStyl e::kExtraExpanded_Width>::value },
305 { SkTIntToFixed<FC_WIDTH_ULTRAEXPANDED>::value, SkTIntToFixed<SkFontStyl e::kUltaExpanded_Width>::value },
306 };
307 int width = map_ranges(get_int(pattern, FC_WIDTH, FC_WIDTH_NORMAL),
308 widthRanges, SK_ARRAY_COUNT(widthRanges));
309
310 SkFontStyle::Slant slant = get_int(pattern, FC_SLANT, FC_SLANT_ROMAN) > 0
311 ? SkFontStyle::kItalic_Slant
312 : SkFontStyle::kUpright_Slant;
313
314 return SkFontStyle(weight, width, slant);
315 }
316
317 static void fcpattern_from_skfontstyle(SkFontStyle style, FcPattern* pattern) {
318 FCLocker::AssertHeld();
319
320 static const MapRanges weightRanges[] = {
321 { SkTIntToFixed<SkFontStyle::kThin_Weight>::value, SkTIntToFixed<FC_WEIG HT_THIN>::value },
322 { SkTIntToFixed<SkFontStyle::kExtraLight_Weight>::value, SkTIntToFixed<F C_WEIGHT_EXTRALIGHT>::value },
323 { SkTIntToFixed<SkFontStyle::kLight_Weight>::value, SkTIntToFixed<FC_WEI GHT_LIGHT>::value },
324 { SkTIntToFixed<SkFontStyle::kNormal_Weight>::value, SkTIntToFixed<FC_WE IGHT_REGULAR>::value },
325 { SkTIntToFixed<SkFontStyle::kMedium_Weight>::value, SkTIntToFixed<FC_WE IGHT_MEDIUM>::value },
326 { SkTIntToFixed<SkFontStyle::kSemiBold_Weight>::value, SkTIntToFixed<FC_ WEIGHT_DEMIBOLD>::value },
327 { SkTIntToFixed<SkFontStyle::kBold_Weight>::value, SkTIntToFixed<FC_WEIG HT_BOLD>::value },
328 { SkTIntToFixed<SkFontStyle::kExtraBold_Weight>::value, SkTIntToFixed<FC _WEIGHT_EXTRABOLD>::value },
329 { SkTIntToFixed<SkFontStyle::kBlack_Weight>::value, SkTIntToFixed<FC_WEI GHT_BLACK>::value },
330 { SkTIntToFixed<1000>::value, SkTIntToFixed<FC_WEIGHT_EXTRABLACK>::value },
331 };
332 int weight = map_ranges(style.weight(), weightRanges, SK_ARRAY_COUNT(weightR anges));
333
334 static const MapRanges widthRanges[] = {
335 { SkTIntToFixed<SkFontStyle::kUltraCondensed_Width>::value, SkTIntToFixe d<FC_WIDTH_ULTRACONDENSED>::value },
336 { SkTIntToFixed<SkFontStyle::kExtraCondensed_Width>::value, SkTIntToFixe d<FC_WIDTH_EXTRACONDENSED>::value },
337 { SkTIntToFixed<SkFontStyle::kCondensed_Width>::value, SkTIntToFixed<FC_ WIDTH_CONDENSED>::value },
338 { SkTIntToFixed<SkFontStyle::kSemiCondensed_Width>::value, SkTIntToFixed <FC_WIDTH_SEMICONDENSED>::value },
339 { SkTIntToFixed<SkFontStyle::kNormal_Width>::value, SkTIntToFixed<FC_WID TH_NORMAL>::value },
340 { SkTIntToFixed<SkFontStyle::kSemiExpanded_Width>::value, SkTIntToFixed< FC_WIDTH_SEMIEXPANDED>::value },
341 { SkTIntToFixed<SkFontStyle::kExpanded_Width>::value, SkTIntToFixed<FC_W IDTH_EXPANDED>::value },
342 { SkTIntToFixed<SkFontStyle::kExtraExpanded_Width>::value, SkTIntToFixed <FC_WIDTH_EXTRAEXPANDED>::value },
343 { SkTIntToFixed<SkFontStyle::kUltaExpanded_Width>::value, SkTIntToFixed< FC_WIDTH_ULTRAEXPANDED>::value },
344 };
345 int width = map_ranges(style.width(), widthRanges, SK_ARRAY_COUNT(widthRange s));
346
347 FcPatternAddInteger(pattern, FC_WEIGHT, weight);
348 FcPatternAddInteger(pattern, FC_WIDTH, width);
349 FcPatternAddInteger(pattern, FC_SLANT, style.isItalic() ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
350 }
351
352 class SkTypeface_stream : public SkTypeface_FreeType {
353 public:
354 /** @param stream does not ownership of the reference, does take ownership o f the stream. */
355 SkTypeface_stream(SkTypeface::Style style, bool fixedWidth, int ttcIndex, Sk StreamAsset* stream)
356 : INHERITED(style, SkTypefaceCache::NewFontID(), fixedWidth)
357 , fStream(SkRef(stream))
358 , fIndex(ttcIndex)
359 { };
360
361 virtual void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) co nst SK_OVERRIDE {
362 *serialize = true;
363 }
364
365 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
366 return fStream->duplicate();
367 }
368
369 private:
370 SkAutoTUnref<SkStreamAsset> fStream;
371 int fIndex;
372
373 typedef SkTypeface_FreeType INHERITED;
374 };
375
376 class SkTypeface_fontconfig : public SkTypeface_FreeType {
377 public:
378 /** @param pattern takes ownership of the reference. */
379 static SkTypeface_fontconfig* Create(FcPattern* pattern) {
380 return SkNEW_ARGS(SkTypeface_fontconfig, (pattern));
381 }
382 mutable SkAutoFcPattern fPattern;
383
384 virtual void onGetFontDescriptor(SkFontDescriptor* desc, bool* serialize) co nst SK_OVERRIDE {
385 FCLocker lock;
386 *serialize = false;
387 desc->setFamilyName(get_string(fPattern, FC_FAMILY));
388 desc->setFontFileName(get_string(fPattern, FC_FILE));
389 desc->setFullName(get_string(fPattern, FC_FULLNAME));
390 desc->setPostscriptName(get_string(fPattern, FC_POSTSCRIPT_NAME));
391 }
392
393 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE {
394 FCLocker lock;
395 *ttcIndex = get_int(fPattern, FC_INDEX, 0);
396 return SkStream::NewFromFile(get_string(fPattern, FC_FILE));
397 }
398
399 virtual ~SkTypeface_fontconfig() {
400 // Hold the lock while unrefing the pattern.
401 FCLocker lock;
402 fPattern.reset();
403 }
404
405 private:
406 static SkTypeface::Style TypefaceStyleFromFcPattern(FcPattern* pattern) {
407 int fcweight = get_int(pattern, FC_WEIGHT, FC_WEIGHT_REGULAR);
408 int fcslant = get_int(pattern, FC_SLANT, FC_SLANT_ROMAN);
409 return (SkTypeface::Style)((fcweight >= FC_WEIGHT_BOLD ? SkTypeface::kBo ld : 0) |
410 (fcslant > FC_SLANT_ROMAN ? SkTypeface::kItal ic : 0));
411 }
412
413 /** @param pattern takes ownership of the reference. */
414 SkTypeface_fontconfig(FcPattern* pattern)
415 : INHERITED(TypefaceStyleFromFcPattern(pattern),
416 SkTypefaceCache::NewFontID(),
417 FC_PROPORTIONAL != get_int(pattern, FC_SPACING, FC_PROPORTIO NAL))
418 , fPattern(pattern)
419 { };
420
421 typedef SkTypeface_FreeType INHERITED;
422 };
423
424 class SkFontMgr_fontconfig : public SkFontMgr {
425 mutable SkAutoFcConfig fFC;
426 SkAutoTUnref<SkDataTable> fFamilyNames;
427
428 class StyleSet : public SkFontStyleSet {
429 public:
430 /** @param parent does not take ownership of the reference.
431 * @param fontSet takes ownership of the reference.
432 */
433 StyleSet(const SkFontMgr_fontconfig* parent, FcFontSet* fontSet)
434 : fFontMgr(SkRef(parent)), fFontSet(fontSet)
435 { }
436
437 virtual ~StyleSet() {
438 // Hold the lock while unrefing the font set.
439 FCLocker lock;
440 fFontSet.reset();
441 }
442
443 virtual int count() SK_OVERRIDE { return fFontSet->nfont; }
444
445 virtual void getStyle(int index, SkFontStyle* style, SkString* styleName ) SK_OVERRIDE {
446 if (index < 0 || fFontSet->nfont <= index) {
447 return;
448 }
449
450 FCLocker lock;
451 if (style) {
452 *style = skfontstyle_from_fcpattern(fFontSet->fonts[index]);
453 }
454 if (styleName) {
455 *styleName = get_string(fFontSet->fonts[index], FC_STYLE);
456 }
457 }
458
459 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
460 FCLocker lock;
461
462 FcPattern* match = fFontSet->fonts[index];
463 return fFontMgr->createTypefaceFromFcPattern(match);
464 }
465
466 virtual SkTypeface* matchStyle(const SkFontStyle& style) SK_OVERRIDE {
467 FCLocker lock;
468
469 SkAutoFcPattern pattern(FcPatternCreate());
470 if (NULL == pattern) {
471 return NULL;
472 }
473
474 fcpattern_from_skfontstyle(style, pattern);
475 FcConfigSubstitute(fFontMgr->fFC, pattern, FcMatchPattern);
476 FcDefaultSubstitute(pattern);
477
478 FcResult result;
479 SkAutoFcPattern match(FcFontSetMatch(fFontMgr->fFC, &fFontSet, 1, pa ttern, &result));
480 if (NULL == match) {
481 return NULL;
482 }
483
484 return fFontMgr->createTypefaceFromFcPattern(match);
485 }
486
487 private:
488 SkAutoTUnref<const SkFontMgr_fontconfig> fFontMgr;
489 SkAutoFcFontSet fFontSet;
490 };
491
492 static bool find_name(const SkTDArray<const char*>& list, const char* str) {
493 int count = list.count();
494 for (int i = 0; i < count; ++i) {
495 if (!strcmp(list[i], str)) {
496 return true;
497 }
498 }
499 return false;
500 }
501
502 SkDataTable* get_family_names() {
503 FCLocker lock;
504
505 SkTDArray<const char*> names;
506 SkTDArray<size_t> sizes;
507
508 static const FcSetName fcNameSet[] = { FcSetSystem, FcSetApplication };
509 for (int setIndex = 0; setIndex < (int)SK_ARRAY_COUNT(fcNameSet); ++setI ndex) {
510 // Return value of FcConfigGetFonts must not be destroyed.
511 FcFontSet* allFonts(FcConfigGetFonts(fFC, fcNameSet[setIndex]));
512 if (NULL == allFonts) {
513 continue;
514 }
515
516 for (int fontIndex = 0; fontIndex < allFonts->nfont; ++fontIndex) {
517 FcPattern* current = allFonts->fonts[fontIndex];
518 for (int id = 0; ; ++id) {
519 FcChar8* fcFamilyName;
520 FcResult result = FcPatternGetString(current, FC_FAMILY, id, &fcFamilyName);
521 if (FcResultNoId == result) {
522 break;
523 }
524 if (FcResultMatch != result) {
525 continue;
526 }
527 const char* familyName = reinterpret_cast<const char*>(fcFam ilyName);
528 if (familyName && !find_name(names, familyName)) {
529 *names.append() = familyName;
530 *sizes.append() = strlen(familyName) + 1;
531 }
532 }
533 }
534 }
535
536 return SkDataTable::NewCopyArrays((void *const *const)names.begin(),
537 sizes.begin(), names.count());
538 }
539
540 static bool find_by_fc_pattern(SkTypeface* cached, SkTypeface::Style, void* ctx) {
541 SkTypeface_fontconfig* cshFace = reinterpret_cast<SkTypeface_fontconfig* >(cached);
542 FcPattern* ctxPattern = reinterpret_cast<FcPattern*>(ctx);
543 return FcTrue == FcPatternEqual(cshFace->fPattern, ctxPattern);
544 }
545
546 mutable SkMutex fTFCacheMutex;
547 mutable SkTypefaceCache fTFCache;
548 /** Creates a typeface using a typeface cache.
549 * @param pattern a complete pattern from FcFontRenderPrepare.
550 */
551 SkTypeface* createTypefaceFromFcPattern(FcPattern* pattern) const {
552 FCLocker::AssertHeld();
553 SkAutoMutexAcquire ama(fTFCacheMutex);
554 SkTypeface* face = fTFCache.findByProcAndRef(find_by_fc_pattern, pattern );
555 if (NULL == face) {
556 FcPatternReference(pattern);
557 face = SkTypeface_fontconfig::Create(pattern);
558 if (face) {
559 fTFCache.add(face, SkTypeface::kNormal, true);
560 }
561 }
562 return face;
563 }
564
565 public:
566 SkFontMgr_fontconfig()
567 : fFC(FcInitLoadConfigAndFonts())
568 , fFamilyNames(get_family_names()) { }
569
570 /** Takes control of the reference to 'config'. */
571 explicit SkFontMgr_fontconfig(FcConfig* config)
572 : fFC(config)
573 , fFamilyNames(get_family_names()) { }
574
575 virtual ~SkFontMgr_fontconfig() {
576 // Hold the lock while unrefing the config.
577 FCLocker lock;
578 fFC.reset();
579 }
580
581 protected:
582 virtual int onCountFamilies() const SK_OVERRIDE {
583 return fFamilyNames->count();
584 }
585
586 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERR IDE {
587 familyName->set(fFamilyNames->atStr(index));
588 }
589
590 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
591 return this->onMatchFamily(fFamilyNames->atStr(index));
592 }
593
594 /** True if any string object value in the font is the same
595 * as a string object value in the pattern.
596 */
597 static bool any_matching(FcPattern* font, FcPattern* pattern, const char* ob ject) {
598 FcChar8* fontString;
599 FcChar8* patternString;
600 FcResult result;
601 // Set an arbitrary limit on the number of pattern object values to cons ider.
602 static const int maxId = 16;
603 for (int patternId = 0; patternId < maxId; ++patternId) {
604 result = FcPatternGetString(pattern, object, patternId, &patternStri ng);
605 if (FcResultNoId == result) {
606 break;
607 }
608 if (FcResultMatch != result) {
609 continue;
610 }
611 for (int fontId = 0; fontId < maxId; ++fontId) {
612 result = FcPatternGetString(font, object, fontId, &fontString);
613 if (FcResultNoId == result) {
614 break;
615 }
616 if (FcResultMatch != result) {
617 continue;
618 }
619 if (0 == FcStrCmpIgnoreCase(patternString, fontString)) {
620 return true;
621 }
622 }
623 }
624 return false;
625 }
626
627 static bool valid_pattern(FcPattern* pattern) {
628 // FontConfig can return fonts which are unreadable.
629 const char* filename = get_string(pattern, FC_FILE, NULL);
630 if (NULL == filename) {
631 return false;
632 }
633 return sk_exists(filename, kRead_SkFILE_Flag);
634 }
635
636 static bool font_matches(FcPattern* font, FcPattern* pattern) {
637 return valid_pattern(font) && any_matching(font, pattern, FC_FAMILY);
638 }
639
640 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVER RIDE {
641 FCLocker lock;
642
643 SkAutoFcPattern pattern(FcPatternCreate());
644 if (NULL == pattern) {
645 return NULL;
646 }
647
648 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
649 FcConfigSubstitute(fFC, pattern, FcMatchPattern);
650 FcDefaultSubstitute(pattern);
651
652 FcPattern* matchPattern;
653 SkAutoFcPattern strongPattern(NULL);
654 if (familyName) {
655 strongPattern.reset(FcPatternDuplicate(pattern));
656 remove_weak(strongPattern, FC_FAMILY);
657 matchPattern = strongPattern;
658 } else {
659 matchPattern = pattern;
660 }
661
662 SkAutoFcFontSet matches(FcFontSetCreate());
663 // TODO: Some families have 'duplicates' due to symbolic links.
664 // The patterns are exactly the same except for the FC_FILE.
665 // It should be possible to collapse these patterns by normalizing.
666 static const FcSetName fcNameSet[] = { FcSetSystem, FcSetApplication };
667 for (int setIndex = 0; setIndex < (int)SK_ARRAY_COUNT(fcNameSet); ++setI ndex) {
668 // Return value of FcConfigGetFonts must not be destroyed.
669 FcFontSet* allFonts(FcConfigGetFonts(fFC, fcNameSet[setIndex]));
670 if (NULL == allFonts) {
671 continue;
672 }
673
674 for (int fontIndex = 0; fontIndex < allFonts->nfont; ++fontIndex) {
675 if (font_matches(allFonts->fonts[fontIndex], matchPattern)) {
676 FcFontSetAdd(matches,
677 FcFontRenderPrepare(fFC, pattern, allFonts->fon ts[fontIndex]));
678 }
679 }
680 }
681
682 return SkNEW_ARGS(StyleSet, (this, matches.detach()));
683 }
684
685 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
686 const SkFontStyle& style) const SK_OV ERRIDE
687 {
688 FCLocker lock;
689
690 SkAutoFcPattern pattern(FcPatternCreate());
691 if (NULL == pattern) {
692 return NULL;
693 }
694
695 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
696 fcpattern_from_skfontstyle(style, pattern);
697 FcConfigSubstitute(fFC, pattern, FcMatchPattern);
698 FcDefaultSubstitute(pattern);
699
700 // We really want to match strong (prefered) and same (acceptable) only here.
701 // If a family name was specified, assume that any weak matches after th e last strong match
702 // are weak (default) and ignore them.
703 // The reason for is that after substitution the pattern for 'sans-serif ' looks like
704 // "wwwwwwwwwwwwwwswww" where there are many weak but preferred names, f ollowed by defaults.
705 // So it is possible to have weakly matching but preferred names.
706 // In aliases, bindings are weak by default, so this is easy and common.
707 // If no family name was specified, we'll probably only get weak matches , but that's ok.
708 FcPattern* matchPattern;
709 SkAutoFcPattern strongPattern(NULL);
710 if (familyName) {
711 strongPattern.reset(FcPatternDuplicate(pattern));
712 remove_weak(strongPattern, FC_FAMILY);
713 matchPattern = strongPattern;
714 } else {
715 matchPattern = pattern;
716 }
717
718 FcResult result;
719 SkAutoFcPattern match(FcFontMatch(fFC, pattern, &result));
720 if (NULL == match || !font_matches(match, matchPattern)) {
721 return NULL;
722 }
723
724 return createTypefaceFromFcPattern(match);
725 }
726
727 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* typeface,
728 const SkFontStyle& style) const SK_OVER RIDE
729 {
730 //TODO: should the SkTypeface_fontconfig know its family?
731 const SkTypeface_fontconfig* fcTypeface =
732 reinterpret_cast<const SkTypeface_fontconfig*>(typeface);
733 return this->matchFamilyStyle(get_string(fcTypeface->fPattern, FC_FAMILY ), style);
734 }
735
736 /** @param stream does not take ownership of the reference. */
737 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
738 const size_t length = stream->getLength();
739 if (!(0 < length && length < (1u << 30))) {
740 return NULL;
741 }
742
743 SkTypeface::Style style = SkTypeface::kNormal;
744 bool isFixedWidth = false;
745 if (!SkTypeface_FreeType::ScanFont(stream, ttcIndex, NULL, &style, &isFi xedWidth)) {
746 return NULL;
747 }
748
749 return SkNEW_ARGS(SkTypeface_stream, (style, isFixedWidth, ttcIndex,
750 reinterpret_cast<SkStreamAsset*>(s tream)));
751 }
752
753 virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OV ERRIDE {
754 SkAutoTUnref<SkStreamAsset> stream(SkNEW_ARGS(SkMemoryStream, (data)));
755 return this->createFromStream(stream, ttcIndex);
756 }
757
758 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
759 SkAutoTUnref<SkStreamAsset> stream(SkStream::NewFromFile(path));
760 return this->createFromStream(stream, ttcIndex);
761 }
762
763 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
764 unsigned styleBits) const SK_OVER RIDE {
765 bool bold = styleBits & SkTypeface::kBold;
766 bool italic = styleBits & SkTypeface::kItalic;
767 SkFontStyle style = SkFontStyle(bold ? SkFontStyle::kBold_Weight
768 : SkFontStyle::kNormal_Weight,
769 SkFontStyle::kNormal_Width,
770 italic ? SkFontStyle::kItalic_Slant
771 : SkFontStyle::kUpright_Slant);
772 SkAutoTUnref<SkTypeface> typeface(this->matchFamilyStyle(familyName, sty le));
773 if (NULL != typeface.get()) {
774 return typeface.detach();
775 }
776
777 return this->matchFamilyStyle(NULL, style);
778 }
779 };
780
781 SkFontMgr* SkFontMgr::Factory() {
782 return SkNEW_ARGS(SkFontMgr_fontconfig, ());
783 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698