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