| 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 |