OLD | NEW |
---|---|
(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 } | |
OLD | NEW |