OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2008 Google Inc. | 2 * Copyright 2008 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 #include "SkFontConfigInterface.h" | 8 #include "SkFontConfigInterface.h" |
9 #include "SkFontDescriptor.h" | 9 #include "SkFontDescriptor.h" |
10 #include "SkFontHost.h" | 10 #include "SkFontHost.h" |
(...skipping 29 matching lines...) Expand all Loading... |
40 for (;;) { | 40 for (;;) { |
41 SkFontConfigInterface* fci = SkFontConfigInterface::RefGlobal(); | 41 SkFontConfigInterface* fci = SkFontConfigInterface::RefGlobal(); |
42 if (fci) { | 42 if (fci) { |
43 return fci; | 43 return fci; |
44 } | 44 } |
45 fci = SkFontConfigInterface::GetSingletonDirectInterface(); | 45 fci = SkFontConfigInterface::GetSingletonDirectInterface(); |
46 SkFontConfigInterface::SetGlobal(fci); | 46 SkFontConfigInterface::SetGlobal(fci); |
47 } | 47 } |
48 } | 48 } |
49 | 49 |
| 50 // export this to SkFontMgr_fontconfig.cpp until this file just goes away. |
| 51 SkFontConfigInterface* SkFontHost_fontconfig_ref_global(); |
| 52 SkFontConfigInterface* SkFontHost_fontconfig_ref_global() { |
| 53 return RefFCI(); |
| 54 } |
| 55 |
| 56 /////////////////////////////////////////////////////////////////////////////// |
| 57 |
50 class FontConfigTypeface : public SkTypeface_FreeType { | 58 class FontConfigTypeface : public SkTypeface_FreeType { |
51 SkFontConfigInterface::FontIdentity fIdentity; | 59 SkFontConfigInterface::FontIdentity fIdentity; |
52 SkString fFamilyName; | 60 SkString fFamilyName; |
53 SkStream* fLocalStream; | 61 SkStream* fLocalStream; |
54 | 62 |
55 public: | 63 public: |
56 FontConfigTypeface(Style style, | 64 FontConfigTypeface(Style style, |
57 const SkFontConfigInterface::FontIdentity& fi, | 65 const SkFontConfigInterface::FontIdentity& fi, |
58 const SkString& familyName) | 66 const SkString& familyName) |
59 : INHERITED(style, SkTypefaceCache::NewFontID(), false) | 67 : INHERITED(style, SkTypefaceCache::NewFontID(), false) |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 } | 226 } |
219 | 227 |
220 void FontConfigTypeface::onGetFontDescriptor(SkFontDescriptor* desc, | 228 void FontConfigTypeface::onGetFontDescriptor(SkFontDescriptor* desc, |
221 bool* isLocalStream) const { | 229 bool* isLocalStream) const { |
222 desc->setFamilyName(this->getFamilyName()); | 230 desc->setFamilyName(this->getFamilyName()); |
223 *isLocalStream = SkToBool(this->getLocalStream()); | 231 *isLocalStream = SkToBool(this->getLocalStream()); |
224 } | 232 } |
225 | 233 |
226 /////////////////////////////////////////////////////////////////////////////// | 234 /////////////////////////////////////////////////////////////////////////////// |
227 | 235 |
228 // look for the last substring after a '/' and return that, or return null. | |
229 static const char* find_just_name(const char* str) { | |
230 const char* last = strrchr(str, '/'); | |
231 return last ? last + 1 : NULL; | |
232 } | |
233 | |
234 static bool is_lower(char c) { | |
235 return c >= 'a' && c <= 'z'; | |
236 } | |
237 | |
238 #include "SkFontMgr.h" | |
239 #include <fontconfig/fontconfig.h> | |
240 #include <unistd.h> | |
241 | |
242 static int get_int(FcPattern* pattern, const char field[]) { | |
243 int value; | |
244 if (FcPatternGetInteger(pattern, field, 0, &value) != FcResultMatch) { | |
245 value = SK_MinS32; | |
246 } | |
247 return value; | |
248 } | |
249 | |
250 static const char* get_name(FcPattern* pattern, const char field[]) { | |
251 const char* name; | |
252 if (FcPatternGetString(pattern, field, 0, (FcChar8**)&name) != FcResultMatch
) { | |
253 name = ""; | |
254 } | |
255 return name; | |
256 } | |
257 | |
258 static bool valid_pattern(FcPattern* pattern) { | |
259 FcBool is_scalable; | |
260 if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch
|| !is_scalable) { | |
261 return false; | |
262 } | |
263 | |
264 // fontconfig can also return fonts which are unreadable | |
265 const char* c_filename = get_name(pattern, FC_FILE); | |
266 if (0 == *c_filename) { | |
267 return false; | |
268 } | |
269 if (access(c_filename, R_OK) != 0) { | |
270 return false; | |
271 } | |
272 return true; | |
273 } | |
274 | |
275 static bool match_name(FcPattern* pattern, const char family_name[]) { | |
276 return !strcasecmp(family_name, get_name(pattern, FC_FAMILY)); | |
277 } | |
278 | |
279 static FcPattern** MatchFont(FcFontSet* font_set, | |
280 const char post_config_family[], | |
281 int* count) { | |
282 // Older versions of fontconfig have a bug where they cannot select | |
283 // only scalable fonts so we have to manually filter the results. | |
284 | |
285 FcPattern** iter = font_set->fonts; | |
286 FcPattern** stop = iter + font_set->nfont; | |
287 // find the first good match | |
288 for (; iter < stop; ++iter) { | |
289 if (valid_pattern(*iter)) { | |
290 break; | |
291 } | |
292 } | |
293 | |
294 if (iter == stop || !match_name(*iter, post_config_family)) { | |
295 return NULL; | |
296 } | |
297 | |
298 FcPattern** firstIter = iter++; | |
299 for (; iter < stop; ++iter) { | |
300 if (!valid_pattern(*iter) || !match_name(*iter, post_config_family)) { | |
301 break; | |
302 } | |
303 } | |
304 | |
305 *count = iter - firstIter; | |
306 return firstIter; | |
307 } | |
308 | |
309 class SkFontStyleSet_FC : public SkFontStyleSet { | |
310 public: | |
311 SkFontStyleSet_FC(FcPattern** matches, int count); | |
312 virtual ~SkFontStyleSet_FC(); | |
313 | |
314 virtual int count() SK_OVERRIDE { return fRecCount; } | |
315 virtual void getStyle(int index, SkFontStyle*, SkString* style) SK_OVERRIDE; | |
316 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE; | |
317 virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE; | |
318 | |
319 private: | |
320 struct Rec { | |
321 SkString fStyleName; | |
322 SkString fFileName; | |
323 SkFontStyle fStyle; | |
324 }; | |
325 Rec* fRecs; | |
326 int fRecCount; | |
327 }; | |
328 | |
329 static int map_range(int value, | |
330 int old_min, int old_max, int new_min, int new_max) { | |
331 SkASSERT(old_min < old_max); | |
332 SkASSERT(new_min < new_max); | |
333 return new_min + SkMulDiv(value - old_min, | |
334 new_max - new_min, old_max - old_min); | |
335 } | |
336 | |
337 static SkFontStyle make_fontconfig_style(FcPattern* match) { | |
338 int weight = get_int(match, FC_WEIGHT); | |
339 int width = get_int(match, FC_WIDTH); | |
340 int slant = get_int(match, FC_SLANT); | |
341 // SkDebugf("old weight %d new weight %d\n", weight, map_range(weight, 0, 80,
0, 400)); | |
342 | |
343 // fontconfig weight seems to be 0..200 or so, so we remap it here | |
344 weight = map_range(weight, 0, 80, 0, 400); | |
345 width = map_range(width, 0, 200, 0, 9); | |
346 return SkFontStyle(weight, width, slant > 0 ? SkFontStyle::kItalic_Slant | |
347 : SkFontStyle::kUpright_Slant); | |
348 } | |
349 | |
350 SkFontStyleSet_FC::SkFontStyleSet_FC(FcPattern** matches, int count) { | |
351 fRecCount = count; | |
352 fRecs = SkNEW_ARRAY(Rec, count); | |
353 for (int i = 0; i < count; ++i) { | |
354 fRecs[i].fStyleName.set(get_name(matches[i], FC_STYLE)); | |
355 fRecs[i].fFileName.set(get_name(matches[i], FC_FILE)); | |
356 fRecs[i].fStyle = make_fontconfig_style(matches[i]); | |
357 } | |
358 } | |
359 | |
360 SkFontStyleSet_FC::~SkFontStyleSet_FC() { | |
361 SkDELETE_ARRAY(fRecs); | |
362 } | |
363 | |
364 void SkFontStyleSet_FC::getStyle(int index, SkFontStyle* style, | |
365 SkString* styleName) { | |
366 SkASSERT((unsigned)index < (unsigned)fRecCount); | |
367 if (style) { | |
368 *style = fRecs[index].fStyle; | |
369 } | |
370 if (styleName) { | |
371 *styleName = fRecs[index].fStyleName; | |
372 } | |
373 } | |
374 | |
375 SkTypeface* SkFontStyleSet_FC::createTypeface(int index) { | |
376 return NULL; | |
377 } | |
378 | |
379 SkTypeface* SkFontStyleSet_FC::matchStyle(const SkFontStyle& pattern) { | |
380 return NULL; | |
381 } | |
382 | |
383 class SkFontMgr_fontconfig : public SkFontMgr { | |
384 SkAutoTUnref<SkFontConfigInterface> fFCI; | |
385 SkDataTable* fFamilyNames; | |
386 | |
387 void init() { | |
388 if (!fFamilyNames) { | |
389 fFamilyNames = fFCI->getFamilyNames(); | |
390 } | |
391 } | |
392 | |
393 public: | |
394 SkFontMgr_fontconfig(SkFontConfigInterface* fci) | |
395 : fFCI(fci) | |
396 , fFamilyNames(NULL) {} | |
397 | |
398 virtual ~SkFontMgr_fontconfig() { | |
399 SkSafeUnref(fFamilyNames); | |
400 } | |
401 | |
402 protected: | |
403 virtual int onCountFamilies() { | |
404 this->init(); | |
405 return fFamilyNames->count(); | |
406 } | |
407 | |
408 virtual void onGetFamilyName(int index, SkString* familyName) { | |
409 this->init(); | |
410 familyName->set(fFamilyNames->atStr(index)); | |
411 } | |
412 | |
413 virtual SkFontStyleSet* onCreateStyleSet(int index) { | |
414 this->init(); | |
415 return this->onMatchFamily(fFamilyNames->atStr(index)); | |
416 } | |
417 | |
418 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) { | |
419 this->init(); | |
420 | |
421 FcPattern* pattern = FcPatternCreate(); | |
422 | |
423 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); | |
424 #if 0 | |
425 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); | |
426 #endif | |
427 FcConfigSubstitute(NULL, pattern, FcMatchPattern); | |
428 FcDefaultSubstitute(pattern); | |
429 | |
430 const char* post_config_family = get_name(pattern, FC_FAMILY); | |
431 | |
432 FcResult result; | |
433 FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); | |
434 if (!font_set) { | |
435 FcPatternDestroy(pattern); | |
436 return NULL; | |
437 } | |
438 | |
439 int count; | |
440 FcPattern** match = MatchFont(font_set, post_config_family, &count); | |
441 if (!match) { | |
442 FcPatternDestroy(pattern); | |
443 FcFontSetDestroy(font_set); | |
444 return NULL; | |
445 } | |
446 | |
447 FcPatternDestroy(pattern); | |
448 | |
449 SkTDArray<FcPattern*> trimmedMatches; | |
450 for (int i = 0; i < count; ++i) { | |
451 const char* justName = find_just_name(get_name(match[i], FC_FILE)); | |
452 if (!is_lower(*justName)) { | |
453 *trimmedMatches.append() = match[i]; | |
454 } | |
455 } | |
456 | |
457 SkFontStyleSet_FC* sset = SkNEW_ARGS(SkFontStyleSet_FC, | |
458 (trimmedMatches.begin(), | |
459 trimmedMatches.count())); | |
460 return sset; | |
461 } | |
462 | |
463 virtual SkTypeface* onMatchFamilyStyle(const char familyName[], | |
464 const SkFontStyle&) { return NULL; } | |
465 virtual SkTypeface* onMatchFaceStyle(const SkTypeface*, | |
466 const SkFontStyle&) { return NULL; } | |
467 | |
468 virtual SkTypeface* onCreateFromData(SkData*, int ttcIndex) { return NULL; } | |
469 virtual SkTypeface* onCreateFromStream(SkStream*, int ttcIndex) { | |
470 return NULL; | |
471 } | |
472 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) { | |
473 return NULL; | |
474 } | |
475 }; | |
476 | |
477 SkFontMgr* SkFontMgr::Factory() { | |
478 SkFontConfigInterface* fci = RefFCI(); | |
479 return fci ? SkNEW_ARGS(SkFontMgr_fontconfig, (fci)) : NULL; | |
480 } | |
OLD | NEW |