|
1 /* |
|
2 * Copyright 2009 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 /* migrated from chrome/src/skia/ext/SkFontHost_fontconfig_direct.cpp */ |
|
9 |
|
10 #include <string> |
|
11 #include <unistd.h> |
|
12 #include <fcntl.h> |
|
13 |
|
14 #include <fontconfig/fontconfig.h> |
|
15 |
|
16 #include "SkBuffer.h" |
|
17 #include "SkFontConfigInterface.h" |
|
18 #include "SkStream.h" |
|
19 |
|
20 size_t SkFontConfigInterface::FontIdentity::writeToMemory(void* addr) const { |
|
21 size_t size = sizeof(fID) + sizeof(fTTCIndex); |
|
22 size += sizeof(int32_t) + sizeof(int32_t) + sizeof(uint8_t); // weight, width, italic |
|
23 size += sizeof(int32_t) + fString.size(); // store length+data |
|
24 if (addr) { |
|
25 SkWBuffer buffer(addr, size); |
|
26 |
|
27 buffer.write32(fID); |
|
28 buffer.write32(fTTCIndex); |
|
29 buffer.write32(fString.size()); |
|
30 buffer.write32(fStyle.weight()); |
|
31 buffer.write32(fStyle.width()); |
|
32 buffer.write8(fStyle.slant()); |
|
33 buffer.write(fString.c_str(), fString.size()); |
|
34 buffer.padToAlign4(); |
|
35 |
|
36 SkASSERT(buffer.pos() == size); |
|
37 } |
|
38 return size; |
|
39 } |
|
40 |
|
41 size_t SkFontConfigInterface::FontIdentity::readFromMemory(const void* addr, |
|
42 size_t size) { |
|
43 SkRBuffer buffer(addr, size); |
|
44 |
|
45 (void)buffer.readU32(&fID); |
|
46 (void)buffer.readS32(&fTTCIndex); |
|
47 uint32_t strLen, weight, width; |
|
48 (void)buffer.readU32(&strLen); |
|
49 (void)buffer.readU32(&weight); |
|
50 (void)buffer.readU32(&width); |
|
51 uint8_t u8; |
|
52 (void)buffer.readU8(&u8); |
|
53 SkFontStyle::Slant slant = (SkFontStyle::Slant)u8; |
|
54 fStyle = SkFontStyle(weight, width, slant); |
|
55 fString.resize(strLen); |
|
56 (void)buffer.read(fString.writable_str(), strLen); |
|
57 buffer.skipToAlign4(); |
|
58 |
|
59 return buffer.pos(); // the actual number of bytes read |
|
60 } |
|
61 |
|
62 #ifdef SK_DEBUG |
|
63 static void make_iden(SkFontConfigInterface::FontIdentity* iden) { |
|
64 iden->fID = 10; |
|
65 iden->fTTCIndex = 2; |
|
66 iden->fString.set("Hello world"); |
|
67 iden->fStyle = SkFontStyle(300, 6, SkFontStyle::kItalic_Slant); |
|
68 } |
|
69 |
|
70 static void test_writeToMemory(const SkFontConfigInterface::FontIdentity& iden0, |
|
71 int initValue) { |
|
72 SkFontConfigInterface::FontIdentity iden1; |
|
73 |
|
74 size_t size0 = iden0.writeToMemory(NULL); |
|
75 |
|
76 SkAutoMalloc storage(size0); |
|
77 memset(storage.get(), initValue, size0); |
|
78 |
|
79 size_t size1 = iden0.writeToMemory(storage.get()); |
|
80 SkASSERT(size0 == size1); |
|
81 |
|
82 SkASSERT(iden0 != iden1); |
|
83 size_t size2 = iden1.readFromMemory(storage.get(), size1); |
|
84 SkASSERT(size2 == size1); |
|
85 SkASSERT(iden0 == iden1); |
|
86 } |
|
87 |
|
88 static void fontconfiginterface_unittest() { |
|
89 SkFontConfigInterface::FontIdentity iden0, iden1; |
|
90 |
|
91 SkASSERT(iden0 == iden1); |
|
92 |
|
93 make_iden(&iden0); |
|
94 SkASSERT(iden0 != iden1); |
|
95 |
|
96 make_iden(&iden1); |
|
97 SkASSERT(iden0 == iden1); |
|
98 |
|
99 test_writeToMemory(iden0, 0); |
|
100 test_writeToMemory(iden0, 0); |
|
101 } |
|
102 #endif |
|
103 |
|
104 class SkFontConfigInterfaceDirect : public SkFontConfigInterface { |
|
105 public: |
|
106 SkFontConfigInterfaceDirect(); |
|
107 virtual ~SkFontConfigInterfaceDirect(); |
|
108 |
|
109 virtual bool matchFamilyName(const char familyName[], |
|
110 SkTypeface::Style requested, |
|
111 FontIdentity* outFontIdentifier, |
|
112 SkString* outFamilyName, |
|
113 SkTypeface::Style* outStyle) SK_OVERRIDE; |
|
114 virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE; |
|
115 |
|
116 // new APIs |
|
117 virtual SkDataTable* getFamilyNames() SK_OVERRIDE; |
|
118 virtual bool matchFamilySet(const char inFamilyName[], |
|
119 SkString* outFamilyName, |
|
120 SkTArray<FontIdentity>*) SK_OVERRIDE; |
|
121 |
|
122 private: |
|
123 SkMutex mutex_; |
|
124 }; |
|
125 |
|
126 SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() { |
|
127 static SkFontConfigInterface* gDirect; |
|
128 if (NULL == gDirect) { |
|
129 static SkMutex gMutex; |
|
130 SkAutoMutexAcquire ac(gMutex); |
|
131 |
|
132 if (NULL == gDirect) { |
|
133 gDirect = new SkFontConfigInterfaceDirect; |
|
134 } |
|
135 } |
|
136 return gDirect; |
|
137 } |
|
138 |
|
139 /////////////////////////////////////////////////////////////////////////////// |
|
140 |
|
141 // Returns the string from the pattern, or NULL |
|
142 static const char* get_name(FcPattern* pattern, const char field[], |
|
143 int index = 0) { |
|
144 const char* name; |
|
145 if (FcPatternGetString(pattern, field, index, |
|
146 (FcChar8**)&name) != FcResultMatch) { |
|
147 name = NULL; |
|
148 } |
|
149 return name; |
|
150 } |
|
151 |
|
152 /////////////////////////////////////////////////////////////////////////////// |
|
153 |
|
154 namespace { |
|
155 |
|
156 // Equivalence classes, used to match the Liberation and other fonts |
|
157 // with their metric-compatible replacements. See the discussion in |
|
158 // GetFontEquivClass(). |
|
159 enum FontEquivClass |
|
160 { |
|
161 OTHER, |
|
162 SANS, |
|
163 SERIF, |
|
164 MONO, |
|
165 SYMBOL, |
|
166 PGOTHIC, |
|
167 GOTHIC, |
|
168 PMINCHO, |
|
169 MINCHO, |
|
170 SIMSUN, |
|
171 NSIMSUN, |
|
172 SIMHEI, |
|
173 PMINGLIU, |
|
174 MINGLIU, |
|
175 PMINGLIUHK, |
|
176 MINGLIUHK, |
|
177 CAMBRIA, |
|
178 CALIBRI, |
|
179 }; |
|
180 |
|
181 // Match the font name against a whilelist of fonts, returning the equivalence |
|
182 // class. |
|
183 FontEquivClass GetFontEquivClass(const char* fontname) |
|
184 { |
|
185 // It would be nice for fontconfig to tell us whether a given suggested |
|
186 // replacement is a "strong" match (that is, an equivalent font) or |
|
187 // a "weak" match (that is, fontconfig's next-best attempt at finding a |
|
188 // substitute). However, I played around with the fontconfig API for |
|
189 // a good few hours and could not make it reveal this information. |
|
190 // |
|
191 // So instead, we hardcode. Initially this function emulated |
|
192 // /etc/fonts/conf.d/30-metric-aliases.conf |
|
193 // from my Ubuntu system, but we're better off being very conservative. |
|
194 |
|
195 // Arimo, Tinos and Cousine are a set of fonts metric-compatible with |
|
196 // Arial, Times New Roman and Courier New with a character repertoire |
|
197 // much larger than Liberation. Note that Cousine is metrically |
|
198 // compatible with Courier New, but the former is sans-serif while |
|
199 // the latter is serif. |
|
200 |
|
201 |
|
202 struct FontEquivMap { |
|
203 FontEquivClass clazz; |
|
204 const char name[40]; |
|
205 }; |
|
206 |
|
207 static const FontEquivMap kFontEquivMap[] = { |
|
208 { SANS, "Arial" }, |
|
209 { SANS, "Arimo" }, |
|
210 { SANS, "Liberation Sans" }, |
|
211 |
|
212 { SERIF, "Times New Roman" }, |
|
213 { SERIF, "Tinos" }, |
|
214 { SERIF, "Liberation Serif" }, |
|
215 |
|
216 { MONO, "Courier New" }, |
|
217 { MONO, "Cousine" }, |
|
218 { MONO, "Liberation Mono" }, |
|
219 |
|
220 { SYMBOL, "Symbol" }, |
|
221 { SYMBOL, "Symbol Neu" }, |
|
222 |
|
223 // MS Pゴシック |
|
224 { PGOTHIC, "MS PGothic" }, |
|
225 { PGOTHIC, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0" |
|
226 "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" }, |
|
227 { PGOTHIC, "IPAPGothic" }, |
|
228 { PGOTHIC, "MotoyaG04Gothic" }, |
|
229 |
|
230 // MS ゴシック |
|
231 { GOTHIC, "MS Gothic" }, |
|
232 { GOTHIC, "\xef\xbc\xad\xef\xbc\xb3 " |
|
233 "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" }, |
|
234 { GOTHIC, "IPAGothic" }, |
|
235 { GOTHIC, "MotoyaG04GothicMono" }, |
|
236 |
|
237 // MS P明朝 |
|
238 { PMINCHO, "MS PMincho" }, |
|
239 { PMINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0" |
|
240 "\xe6\x98\x8e\xe6\x9c\x9d"}, |
|
241 { PMINCHO, "IPAPMincho" }, |
|
242 { PMINCHO, "MotoyaG04Mincho" }, |
|
243 |
|
244 // MS 明朝 |
|
245 { MINCHO, "MS Mincho" }, |
|
246 { MINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xe6\x98\x8e\xe6\x9c\x9d" }, |
|
247 { MINCHO, "IPAMincho" }, |
|
248 { MINCHO, "MotoyaG04MinchoMono" }, |
|
249 |
|
250 // 宋体 |
|
251 { SIMSUN, "Simsun" }, |
|
252 { SIMSUN, "\xe5\xae\x8b\xe4\xbd\x93" }, |
|
253 { SIMSUN, "MSung GB18030" }, |
|
254 { SIMSUN, "Song ASC" }, |
|
255 |
|
256 // 新宋体 |
|
257 { NSIMSUN, "NSimsun" }, |
|
258 { NSIMSUN, "\xe6\x96\xb0\xe5\xae\x8b\xe4\xbd\x93" }, |
|
259 { NSIMSUN, "MSung GB18030" }, |
|
260 { NSIMSUN, "N Song ASC" }, |
|
261 |
|
262 // 黑体 |
|
263 { SIMHEI, "Simhei" }, |
|
264 { SIMHEI, "\xe9\xbb\x91\xe4\xbd\x93" }, |
|
265 { SIMHEI, "MYingHeiGB18030" }, |
|
266 { SIMHEI, "MYingHeiB5HK" }, |
|
267 |
|
268 // 新細明體 |
|
269 { PMINGLIU, "PMingLiU"}, |
|
270 { PMINGLIU, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" }, |
|
271 { PMINGLIU, "MSung B5HK"}, |
|
272 |
|
273 // 細明體 |
|
274 { MINGLIU, "MingLiU"}, |
|
275 { MINGLIU, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" }, |
|
276 { MINGLIU, "MSung B5HK"}, |
|
277 |
|
278 // 新細明體 |
|
279 { PMINGLIUHK, "PMingLiU_HKSCS"}, |
|
280 { PMINGLIUHK, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" }, |
|
281 { PMINGLIUHK, "MSung B5HK"}, |
|
282 |
|
283 // 細明體 |
|
284 { MINGLIUHK, "MingLiU_HKSCS"}, |
|
285 { MINGLIUHK, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" }, |
|
286 { MINGLIUHK, "MSung B5HK"}, |
|
287 |
|
288 // Cambria |
|
289 { CAMBRIA, "Cambria" }, |
|
290 { CAMBRIA, "Caladea" }, |
|
291 |
|
292 // Calibri |
|
293 { CALIBRI, "Calibri" }, |
|
294 { CALIBRI, "Carlito" }, |
|
295 }; |
|
296 |
|
297 static const size_t kFontCount = |
|
298 sizeof(kFontEquivMap)/sizeof(kFontEquivMap[0]); |
|
299 |
|
300 // TODO(jungshik): If this loop turns out to be hot, turn |
|
301 // the array to a static (hash)map to speed it up. |
|
302 for (size_t i = 0; i < kFontCount; ++i) { |
|
303 if (strcasecmp(kFontEquivMap[i].name, fontname) == 0) |
|
304 return kFontEquivMap[i].clazz; |
|
305 } |
|
306 return OTHER; |
|
307 } |
|
308 |
|
309 |
|
310 // Return true if |font_a| and |font_b| are visually and at the metrics |
|
311 // level interchangeable. |
|
312 bool IsMetricCompatibleReplacement(const char* font_a, const char* font_b) |
|
313 { |
|
314 FontEquivClass class_a = GetFontEquivClass(font_a); |
|
315 FontEquivClass class_b = GetFontEquivClass(font_b); |
|
316 |
|
317 return class_a != OTHER && class_a == class_b; |
|
318 } |
|
319 |
|
320 // Normally we only return exactly the font asked for. In last-resort |
|
321 // cases, the request either doesn't specify a font or is one of the |
|
322 // basic font names like "Sans", "Serif" or "Monospace". This function |
|
323 // tells you whether a given request is for such a fallback. |
|
324 bool IsFallbackFontAllowed(const std::string& family) { |
|
325 const char* family_cstr = family.c_str(); |
|
326 return family.empty() || |
|
327 strcasecmp(family_cstr, "sans") == 0 || |
|
328 strcasecmp(family_cstr, "serif") == 0 || |
|
329 strcasecmp(family_cstr, "monospace") == 0; |
|
330 } |
|
331 |
|
332 static bool valid_pattern(FcPattern* pattern) { |
|
333 #ifdef SK_FONT_CONFIG_ONLY_ALLOW_SCALABLE_FONTS |
|
334 FcBool is_scalable; |
|
335 if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch |
|
336 || !is_scalable) { |
|
337 return false; |
|
338 } |
|
339 #endif |
|
340 |
|
341 // fontconfig can also return fonts which are unreadable |
|
342 const char* c_filename = get_name(pattern, FC_FILE); |
|
343 if (!c_filename) { |
|
344 return false; |
|
345 } |
|
346 if (access(c_filename, R_OK) != 0) { |
|
347 return false; |
|
348 } |
|
349 return true; |
|
350 } |
|
351 |
|
352 // Find matching font from |font_set| for the given font family. |
|
353 FcPattern* MatchFont(FcFontSet* font_set, |
|
354 const char* post_config_family, |
|
355 const std::string& family) { |
|
356 // Older versions of fontconfig have a bug where they cannot select |
|
357 // only scalable fonts so we have to manually filter the results. |
|
358 FcPattern* match = NULL; |
|
359 for (int i = 0; i < font_set->nfont; ++i) { |
|
360 FcPattern* current = font_set->fonts[i]; |
|
361 if (valid_pattern(current)) { |
|
362 match = current; |
|
363 break; |
|
364 } |
|
365 } |
|
366 |
|
367 if (match && !IsFallbackFontAllowed(family)) { |
|
368 bool acceptable_substitute = false; |
|
369 for (int id = 0; id < 255; ++id) { |
|
370 const char* post_match_family = get_name(match, FC_FAMILY, id); |
|
371 if (!post_match_family) |
|
372 break; |
|
373 acceptable_substitute = |
|
374 (strcasecmp(post_config_family, post_match_family) == 0 || |
|
375 // Workaround for Issue 12530: |
|
376 // requested family: "Bitstream Vera Sans" |
|
377 // post_config_family: "Arial" |
|
378 // post_match_family: "Bitstream Vera Sans" |
|
379 // -> We should treat this case as a good match. |
|
380 strcasecmp(family.c_str(), post_match_family) == 0) || |
|
381 IsMetricCompatibleReplacement(family.c_str(), post_match_family); |
|
382 if (acceptable_substitute) |
|
383 break; |
|
384 } |
|
385 if (!acceptable_substitute) |
|
386 return NULL; |
|
387 } |
|
388 |
|
389 return match; |
|
390 } |
|
391 |
|
392 // Retrieves |is_bold|, |is_italic| and |font_family| properties from |font|. |
|
393 SkTypeface::Style GetFontStyle(FcPattern* font) { |
|
394 int resulting_bold; |
|
395 if (FcPatternGetInteger(font, FC_WEIGHT, 0, &resulting_bold)) |
|
396 resulting_bold = FC_WEIGHT_NORMAL; |
|
397 |
|
398 int resulting_italic; |
|
399 if (FcPatternGetInteger(font, FC_SLANT, 0, &resulting_italic)) |
|
400 resulting_italic = FC_SLANT_ROMAN; |
|
401 |
|
402 // If we ask for an italic font, fontconfig might take a roman font and set |
|
403 // the undocumented property FC_MATRIX to a skew matrix. It'll then say |
|
404 // that the font is italic or oblique. So, if we see a matrix, we don't |
|
405 // believe that it's italic. |
|
406 FcValue matrix; |
|
407 const bool have_matrix = FcPatternGet(font, FC_MATRIX, 0, &matrix) == 0; |
|
408 |
|
409 // If we ask for an italic font, fontconfig might take a roman font and set |
|
410 // FC_EMBOLDEN. |
|
411 FcValue embolden; |
|
412 const bool have_embolden = FcPatternGet(font, FC_EMBOLDEN, 0, &embolden) == 0; |
|
413 |
|
414 int styleBits = 0; |
|
415 if (resulting_bold > FC_WEIGHT_MEDIUM && !have_embolden) { |
|
416 styleBits |= SkTypeface::kBold; |
|
417 } |
|
418 if (resulting_italic > FC_SLANT_ROMAN && !have_matrix) { |
|
419 styleBits |= SkTypeface::kItalic; |
|
420 } |
|
421 |
|
422 return (SkTypeface::Style)styleBits; |
|
423 } |
|
424 |
|
425 } // anonymous namespace |
|
426 |
|
427 /////////////////////////////////////////////////////////////////////////////// |
|
428 |
|
429 #define kMaxFontFamilyLength 2048 |
|
430 |
|
431 SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() { |
|
432 SkAutoMutexAcquire ac(mutex_); |
|
433 |
|
434 FcInit(); |
|
435 |
|
436 SkDEBUGCODE(fontconfiginterface_unittest();) |
|
437 } |
|
438 |
|
439 SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() { |
|
440 } |
|
441 |
|
442 bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[], |
|
443 SkTypeface::Style style, |
|
444 FontIdentity* outIdentity, |
|
445 SkString* outFamilyName, |
|
446 SkTypeface::Style* outStyle) { |
|
447 std::string familyStr(familyName ? familyName : ""); |
|
448 if (familyStr.length() > kMaxFontFamilyLength) { |
|
449 return false; |
|
450 } |
|
451 |
|
452 SkAutoMutexAcquire ac(mutex_); |
|
453 |
|
454 FcPattern* pattern = FcPatternCreate(); |
|
455 |
|
456 if (familyName) { |
|
457 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); |
|
458 } |
|
459 FcPatternAddInteger(pattern, FC_WEIGHT, |
|
460 (style & SkTypeface::kBold) ? FC_WEIGHT_BOLD |
|
461 : FC_WEIGHT_NORMAL); |
|
462 FcPatternAddInteger(pattern, FC_SLANT, |
|
463 (style & SkTypeface::kItalic) ? FC_SLANT_ITALIC |
|
464 : FC_SLANT_ROMAN); |
|
465 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); |
|
466 |
|
467 FcConfigSubstitute(NULL, pattern, FcMatchPattern); |
|
468 FcDefaultSubstitute(pattern); |
|
469 |
|
470 // Font matching: |
|
471 // CSS often specifies a fallback list of families: |
|
472 // font-family: a, b, c, serif; |
|
473 // However, fontconfig will always do its best to find *a* font when asked |
|
474 // for something so we need a way to tell if the match which it has found is |
|
475 // "good enough" for us. Otherwise, we can return NULL which gets piped up |
|
476 // and lets WebKit know to try the next CSS family name. However, fontconfig |
|
477 // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we |
|
478 // wish to support that. |
|
479 // |
|
480 // Thus, if a specific family is requested we set @family_requested. Then we |
|
481 // record two strings: the family name after config processing and the |
|
482 // family name after resolving. If the two are equal, it's a good match. |
|
483 // |
|
484 // So consider the case where a user has mapped Arial to Helvetica in their |
|
485 // config. |
|
486 // requested family: "Arial" |
|
487 // post_config_family: "Helvetica" |
|
488 // post_match_family: "Helvetica" |
|
489 // -> good match |
|
490 // |
|
491 // and for a missing font: |
|
492 // requested family: "Monaco" |
|
493 // post_config_family: "Monaco" |
|
494 // post_match_family: "Times New Roman" |
|
495 // -> BAD match |
|
496 // |
|
497 // However, we special-case fallback fonts; see IsFallbackFontAllowed(). |
|
498 |
|
499 const char* post_config_family = get_name(pattern, FC_FAMILY); |
|
500 if (!post_config_family) { |
|
501 // we can just continue with an empty name, e.g. default font |
|
502 post_config_family = ""; |
|
503 } |
|
504 |
|
505 FcResult result; |
|
506 FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); |
|
507 if (!font_set) { |
|
508 FcPatternDestroy(pattern); |
|
509 return false; |
|
510 } |
|
511 |
|
512 FcPattern* match = MatchFont(font_set, post_config_family, familyStr); |
|
513 if (!match) { |
|
514 FcPatternDestroy(pattern); |
|
515 FcFontSetDestroy(font_set); |
|
516 return false; |
|
517 } |
|
518 |
|
519 FcPatternDestroy(pattern); |
|
520 |
|
521 // From here out we just extract our results from 'match' |
|
522 |
|
523 post_config_family = get_name(match, FC_FAMILY); |
|
524 if (!post_config_family) { |
|
525 FcFontSetDestroy(font_set); |
|
526 return false; |
|
527 } |
|
528 |
|
529 const char* c_filename = get_name(match, FC_FILE); |
|
530 if (!c_filename) { |
|
531 FcFontSetDestroy(font_set); |
|
532 return false; |
|
533 } |
|
534 |
|
535 int face_index; |
|
536 if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) { |
|
537 FcFontSetDestroy(font_set); |
|
538 return false; |
|
539 } |
|
540 |
|
541 FcFontSetDestroy(font_set); |
|
542 |
|
543 if (outIdentity) { |
|
544 outIdentity->fTTCIndex = face_index; |
|
545 outIdentity->fString.set(c_filename); |
|
546 } |
|
547 if (outFamilyName) { |
|
548 outFamilyName->set(post_config_family); |
|
549 } |
|
550 if (outStyle) { |
|
551 *outStyle = GetFontStyle(match); |
|
552 } |
|
553 return true; |
|
554 } |
|
555 |
|
556 SkStream* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) { |
|
557 return SkStream::NewFromFile(identity.fString.c_str()); |
|
558 } |
|
559 |
|
560 /////////////////////////////////////////////////////////////////////////////// |
|
561 |
|
562 static bool find_name(const SkTDArray<const char*>& list, const char* str) { |
|
563 int count = list.count(); |
|
564 for (int i = 0; i < count; ++i) { |
|
565 if (!strcmp(list[i], str)) { |
|
566 return true; |
|
567 } |
|
568 } |
|
569 return false; |
|
570 } |
|
571 |
|
572 SkDataTable* SkFontConfigInterfaceDirect::getFamilyNames() { |
|
573 SkAutoMutexAcquire ac(mutex_); |
|
574 |
|
575 FcPattern* pat = FcPatternCreate(); |
|
576 SkAutoTCallVProc<FcPattern, FcPatternDestroy> autoDestroyPat(pat); |
|
577 if (NULL == pat) { |
|
578 return NULL; |
|
579 } |
|
580 |
|
581 FcObjectSet* os = FcObjectSetBuild(FC_FAMILY, (char *)0); |
|
582 SkAutoTCallVProc<FcObjectSet, FcObjectSetDestroy> autoDestroyOs(os); |
|
583 if (NULL == os) { |
|
584 return NULL; |
|
585 } |
|
586 |
|
587 FcFontSet* fs = FcFontList(NULL, pat, os); |
|
588 SkAutoTCallVProc<FcFontSet, FcFontSetDestroy> autoDestroyFs(fs); |
|
589 if (NULL == fs) { |
|
590 return NULL; |
|
591 } |
|
592 |
|
593 SkTDArray<const char*> names; |
|
594 SkTDArray<size_t> sizes; |
|
595 for (int i = 0; i < fs->nfont; ++i) { |
|
596 FcPattern* match = fs->fonts[i]; |
|
597 const char* famName = get_name(match, FC_FAMILY); |
|
598 if (famName && !find_name(names, famName)) { |
|
599 *names.append() = famName; |
|
600 *sizes.append() = strlen(famName) + 1; |
|
601 } |
|
602 } |
|
603 |
|
604 return SkDataTable::NewCopyArrays((const void*const*)names.begin(), |
|
605 sizes.begin(), names.count()); |
|
606 } |
|
607 |
|
608 bool SkFontConfigInterfaceDirect::matchFamilySet(const char inFamilyName[], |
|
609 SkString* outFamilyName, |
|
610 SkTArray<FontIdentity>* ids) { |
|
611 SkAutoMutexAcquire ac(mutex_); |
|
612 |
|
613 #if 0 |
|
614 std::string familyStr(familyName ? familyName : ""); |
|
615 if (familyStr.length() > kMaxFontFamilyLength) { |
|
616 return false; |
|
617 } |
|
618 |
|
619 SkAutoMutexAcquire ac(mutex_); |
|
620 |
|
621 FcPattern* pattern = FcPatternCreate(); |
|
622 |
|
623 if (familyName) { |
|
624 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); |
|
625 } |
|
626 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); |
|
627 |
|
628 FcConfigSubstitute(NULL, pattern, FcMatchPattern); |
|
629 FcDefaultSubstitute(pattern); |
|
630 |
|
631 // Font matching: |
|
632 // CSS often specifies a fallback list of families: |
|
633 // font-family: a, b, c, serif; |
|
634 // However, fontconfig will always do its best to find *a* font when asked |
|
635 // for something so we need a way to tell if the match which it has found is |
|
636 // "good enough" for us. Otherwise, we can return NULL which gets piped up |
|
637 // and lets WebKit know to try the next CSS family name. However, fontconfig |
|
638 // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we |
|
639 // wish to support that. |
|
640 // |
|
641 // Thus, if a specific family is requested we set @family_requested. Then we |
|
642 // record two strings: the family name after config processing and the |
|
643 // family name after resolving. If the two are equal, it's a good match. |
|
644 // |
|
645 // So consider the case where a user has mapped Arial to Helvetica in their |
|
646 // config. |
|
647 // requested family: "Arial" |
|
648 // post_config_family: "Helvetica" |
|
649 // post_match_family: "Helvetica" |
|
650 // -> good match |
|
651 // |
|
652 // and for a missing font: |
|
653 // requested family: "Monaco" |
|
654 // post_config_family: "Monaco" |
|
655 // post_match_family: "Times New Roman" |
|
656 // -> BAD match |
|
657 // |
|
658 // However, we special-case fallback fonts; see IsFallbackFontAllowed(). |
|
659 |
|
660 const char* post_config_family = get_name(pattern, FC_FAMILY); |
|
661 |
|
662 FcResult result; |
|
663 FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); |
|
664 if (!font_set) { |
|
665 FcPatternDestroy(pattern); |
|
666 return false; |
|
667 } |
|
668 |
|
669 FcPattern* match = MatchFont(font_set, post_config_family, familyStr); |
|
670 if (!match) { |
|
671 FcPatternDestroy(pattern); |
|
672 FcFontSetDestroy(font_set); |
|
673 return false; |
|
674 } |
|
675 |
|
676 FcPatternDestroy(pattern); |
|
677 |
|
678 // From here out we just extract our results from 'match' |
|
679 |
|
680 if (FcPatternGetString(match, FC_FAMILY, 0, &post_config_family) != FcResultMatch) { |
|
681 FcFontSetDestroy(font_set); |
|
682 return false; |
|
683 } |
|
684 |
|
685 FcChar8* c_filename; |
|
686 if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) { |
|
687 FcFontSetDestroy(font_set); |
|
688 return false; |
|
689 } |
|
690 |
|
691 int face_index; |
|
692 if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) { |
|
693 FcFontSetDestroy(font_set); |
|
694 return false; |
|
695 } |
|
696 |
|
697 FcFontSetDestroy(font_set); |
|
698 |
|
699 if (outIdentity) { |
|
700 outIdentity->fTTCIndex = face_index; |
|
701 outIdentity->fString.set((const char*)c_filename); |
|
702 } |
|
703 if (outFamilyName) { |
|
704 outFamilyName->set((const char*)post_config_family); |
|
705 } |
|
706 if (outStyle) { |
|
707 *outStyle = GetFontStyle(match); |
|
708 } |
|
709 return true; |
|
710 |
|
711 //////////////////// |
|
712 |
|
713 int count; |
|
714 FcPattern** match = MatchFont(font_set, post_config_family, &count); |
|
715 if (!match) { |
|
716 FcPatternDestroy(pattern); |
|
717 FcFontSetDestroy(font_set); |
|
718 return NULL; |
|
719 } |
|
720 |
|
721 FcPatternDestroy(pattern); |
|
722 |
|
723 SkTDArray<FcPattern*> trimmedMatches; |
|
724 for (int i = 0; i < count; ++i) { |
|
725 const char* justName = find_just_name(get_name(match[i], FC_FILE)); |
|
726 if (!is_lower(*justName)) { |
|
727 *trimmedMatches.append() = match[i]; |
|
728 } |
|
729 } |
|
730 |
|
731 SkFontStyleSet_FC* sset = SkNEW_ARGS(SkFontStyleSet_FC, |
|
732 (trimmedMatches.begin(), |
|
733 trimmedMatches.count())); |
|
734 #endif |
|
735 return false; |
|
736 } |