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

Side by Side Diff: src/ports/SkFontConfigInterface_direct.cpp

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

Powered by Google App Engine
This is Rietveld 408576698