SkFontMgr_android.cpp revision 802ad83dca2efd57fde6c7ba666555ea78b5324c
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 "SkFontConfigParser_android.h" 9#include "SkFontDescriptor.h" 10#include "SkFontHost_FreeType_common.h" 11#include "SkFontMgr.h" 12#include "SkFontStyle.h" 13#include "SkStream.h" 14#include "SkTDArray.h" 15#include "SkTSearch.h" 16#include "SkTypeface.h" 17#include "SkTypeface_android.h" 18#include "SkTypefaceCache.h" 19 20#include <limits> 21#include <stdlib.h> 22 23#ifndef SK_FONT_FILE_PREFIX 24# define SK_FONT_FILE_PREFIX "/fonts/" 25#endif 26 27#ifndef SK_DEBUG_FONTS 28 #define SK_DEBUG_FONTS 0 29#endif 30 31#if SK_DEBUG_FONTS 32# define DEBUG_FONT(args) SkDebugf args 33#else 34# define DEBUG_FONT(args) 35#endif 36 37// For test only. 38static const char* gTestMainConfigFile = NULL; 39static const char* gTestFallbackConfigFile = NULL; 40static const char* gTestFontFilePrefix = NULL; 41 42class SkTypeface_Android : public SkTypeface_FreeType { 43public: 44 SkTypeface_Android(int index, 45 Style style, 46 bool isFixedPitch, 47 const SkString familyName) 48 : INHERITED(style, SkTypefaceCache::NewFontID(), isFixedPitch) 49 , fIndex(index) 50 , fFamilyName(familyName) { } 51 52protected: 53 virtual void onGetFamilyName(SkString* familyName) const SK_OVERRIDE { 54 *familyName = fFamilyName; 55 } 56 57 int fIndex; 58 SkString fFamilyName; 59 60private: 61 typedef SkTypeface_FreeType INHERITED; 62}; 63 64class SkTypeface_AndroidSystem : public SkTypeface_Android { 65public: 66 SkTypeface_AndroidSystem(const SkString pathName, 67 int index, 68 Style style, 69 bool isFixedPitch, 70 const SkString familyName, 71 const SkLanguage& lang, 72 FontVariant variantStyle) 73 : INHERITED(index, style, isFixedPitch, familyName) 74 , fPathName(pathName) 75 , fLang(lang) 76 , fVariantStyle(variantStyle) { } 77 78 virtual void onGetFontDescriptor(SkFontDescriptor* desc, 79 bool* serialize) const SK_OVERRIDE { 80 SkASSERT(desc); 81 SkASSERT(serialize); 82 desc->setFamilyName(fFamilyName.c_str()); 83 desc->setFontFileName(fPathName.c_str()); 84 desc->setFontIndex(fIndex); 85 *serialize = false; 86 } 87 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE { 88 *ttcIndex = fIndex; 89 return SkStream::NewFromFile(fPathName.c_str()); 90 } 91 92 const SkString fPathName; 93 const SkLanguage fLang; 94 const FontVariant fVariantStyle; 95 96 typedef SkTypeface_Android INHERITED; 97}; 98 99class SkTypeface_AndroidStream : public SkTypeface_Android { 100public: 101 SkTypeface_AndroidStream(SkStream* stream, 102 int index, 103 Style style, 104 bool isFixedPitch, 105 const SkString familyName) 106 : INHERITED(index, style, isFixedPitch, familyName) 107 , fStream(SkRef(stream)) { } 108 109 virtual void onGetFontDescriptor(SkFontDescriptor* desc, 110 bool* serialize) const SK_OVERRIDE { 111 SkASSERT(desc); 112 SkASSERT(serialize); 113 desc->setFamilyName(fFamilyName.c_str()); 114 desc->setFontFileName(NULL); 115 *serialize = true; 116 } 117 118 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE { 119 *ttcIndex = fIndex; 120 return fStream->duplicate(); 121 } 122 123private: 124 SkAutoTUnref<SkStream> fStream; 125 126 typedef SkTypeface_Android INHERITED; 127}; 128 129void get_path_for_sys_fonts(const char* basePath, const SkString& name, SkString* full) { 130 if (basePath) { 131 full->set(basePath); 132 } else { 133 full->set(getenv("ANDROID_ROOT")); 134 full->append(SK_FONT_FILE_PREFIX); 135 } 136 full->append(name); 137} 138 139class SkFontStyleSet_Android : public SkFontStyleSet { 140public: 141 explicit SkFontStyleSet_Android(const FontFamily& family, const char* basePath) { 142 const SkString* cannonicalFamilyName = NULL; 143 if (family.fNames.count() > 0) { 144 cannonicalFamilyName = &family.fNames[0]; 145 } 146 // TODO? make this lazy 147 for (int i = 0; i < family.fFonts.count(); ++i) { 148 const FontFileInfo& fontFile = family.fFonts[i]; 149 150 SkString pathName; 151 get_path_for_sys_fonts(basePath, fontFile.fFileName, &pathName); 152 153 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(pathName.c_str())); 154 if (!stream.get()) { 155 DEBUG_FONT(("---- SystemFonts[%d] file=%s (NOT EXIST)", i, pathName.c_str())); 156 continue; 157 } 158 159 const int ttcIndex = fontFile.fIndex; 160 SkString familyName; 161 SkTypeface::Style style; 162 bool isFixedWidth; 163 if (!SkTypeface_FreeType::ScanFont(stream.get(), ttcIndex, 164 &familyName, &style, &isFixedWidth)) { 165 DEBUG_FONT(("---- SystemFonts[%d] file=%s (INVALID)", i, pathName.c_str())); 166 continue; 167 } 168 169 const SkLanguage& lang = family.fLanguage; 170 uint32_t variant = family.fVariant; 171 if (kDefault_FontVariant == variant) { 172 variant = kCompact_FontVariant | kElegant_FontVariant; 173 } 174 175 // The first specified family name overrides the family name found in the font. 176 // TODO: SkTypeface_AndroidSystem::onCreateFamilyNameIterator should return 177 // all of the specified family names in addition to the names found in the font. 178 if (cannonicalFamilyName != NULL) { 179 familyName = *cannonicalFamilyName; 180 } 181 182 fStyles.push_back().reset(SkNEW_ARGS(SkTypeface_AndroidSystem, 183 (pathName, ttcIndex, 184 style, isFixedWidth, familyName, 185 lang, variant))); 186 } 187 } 188 189 virtual int count() SK_OVERRIDE { 190 return fStyles.count(); 191 } 192 virtual void getStyle(int index, SkFontStyle* style, SkString* name) SK_OVERRIDE { 193 if (index < 0 || fStyles.count() <= index) { 194 return; 195 } 196 if (style) { 197 *style = this->style(index); 198 } 199 if (name) { 200 name->reset(); 201 } 202 } 203 virtual SkTypeface_AndroidSystem* createTypeface(int index) SK_OVERRIDE { 204 if (index < 0 || fStyles.count() <= index) { 205 return NULL; 206 } 207 return SkRef(fStyles[index].get()); 208 } 209 210 /** Find the typeface in this style set that most closely matches the given pattern. 211 * TODO: consider replacing with SkStyleSet_Indirect::matchStyle(); 212 * this simpler version using match_score() passes all our tests. 213 */ 214 virtual SkTypeface_AndroidSystem* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE { 215 if (0 == fStyles.count()) { 216 return NULL; 217 } 218 SkTypeface_AndroidSystem* closest = fStyles[0]; 219 int minScore = std::numeric_limits<int>::max(); 220 for (int i = 0; i < fStyles.count(); ++i) { 221 SkFontStyle style = this->style(i); 222 int score = match_score(pattern, style); 223 if (score < minScore) { 224 closest = fStyles[i]; 225 minScore = score; 226 } 227 } 228 return SkRef(closest); 229 } 230 231private: 232 SkFontStyle style(int index) { 233 return SkFontStyle(this->weight(index), SkFontStyle::kNormal_Width, 234 this->slant(index)); 235 } 236 SkFontStyle::Weight weight(int index) { 237 if (fStyles[index]->isBold()) return SkFontStyle::kBold_Weight; 238 return SkFontStyle::kNormal_Weight; 239 } 240 SkFontStyle::Slant slant(int index) { 241 if (fStyles[index]->isItalic()) return SkFontStyle::kItalic_Slant; 242 return SkFontStyle::kUpright_Slant; 243 } 244 static int match_score(const SkFontStyle& pattern, const SkFontStyle& candidate) { 245 int score = 0; 246 score += abs((pattern.width() - candidate.width()) * 100); 247 score += abs((pattern.isItalic() == candidate.isItalic()) ? 0 : 1000); 248 score += abs(pattern.weight() - candidate.weight()); 249 return score; 250 } 251 252 SkTArray<SkAutoTUnref<SkTypeface_AndroidSystem>, true> fStyles; 253 254 friend struct NameToFamily; 255 friend class SkFontMgr_Android; 256 257 typedef SkFontStyleSet INHERITED; 258}; 259 260/** On Android a single family can have many names, but our API assumes unique names. 261 * Map names to the back end so that all names for a given family refer to the same 262 * (non-replicated) set of typefaces. 263 * SkTDict<> doesn't let us do index-based lookup, so we write our own mapping. 264 */ 265struct NameToFamily { 266 SkString name; 267 SkFontStyleSet_Android* styleSet; 268}; 269 270class SkFontMgr_Android : public SkFontMgr { 271public: 272 SkFontMgr_Android() { 273 SkTDArray<FontFamily*> fontFamilies; 274 SkFontConfigParser::GetFontFamilies(fontFamilies); 275 this->buildNameToFamilyMap(fontFamilies, NULL); 276 this->findDefaultFont(); 277 } 278 SkFontMgr_Android(const char* mainConfigFile, const char* fallbackConfigFile, 279 const char* basePath) 280 { 281 SkTDArray<FontFamily*> fontFamilies; 282 SkFontConfigParser::GetTestFontFamilies(fontFamilies, mainConfigFile, fallbackConfigFile); 283 this->buildNameToFamilyMap(fontFamilies, basePath); 284 this->findDefaultFont(); 285 } 286 287protected: 288 /** Returns not how many families we have, but how many unique names 289 * exist among the families. 290 */ 291 virtual int onCountFamilies() const SK_OVERRIDE { 292 return fNameToFamilyMap.count(); 293 } 294 295 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE { 296 if (index < 0 || fNameToFamilyMap.count() <= index) { 297 familyName->reset(); 298 return; 299 } 300 familyName->set(fNameToFamilyMap[index].name); 301 } 302 303 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE { 304 if (index < 0 || fNameToFamilyMap.count() <= index) { 305 return NULL; 306 } 307 return SkRef(fNameToFamilyMap[index].styleSet); 308 } 309 310 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE { 311 if (!familyName) { 312 return NULL; 313 } 314 SkAutoAsciiToLC tolc(familyName); 315 for (int i = 0; i < fNameToFamilyMap.count(); ++i) { 316 if (fNameToFamilyMap[i].name.equals(tolc.lc())) { 317 return SkRef(fNameToFamilyMap[i].styleSet); 318 } 319 } 320 // TODO: eventually we should not need to name fallback families. 321 for (int i = 0; i < fFallbackNameToFamilyMap.count(); ++i) { 322 if (fFallbackNameToFamilyMap[i].name.equals(tolc.lc())) { 323 return SkRef(fFallbackNameToFamilyMap[i].styleSet); 324 } 325 } 326 return NULL; 327 } 328 329 virtual SkTypeface* onMatchFamilyStyle(const char familyName[], 330 const SkFontStyle& style) const SK_OVERRIDE { 331 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName)); 332 return sset->matchStyle(style); 333 } 334 335 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* typeface, 336 const SkFontStyle& style) const SK_OVERRIDE { 337 for (int i = 0; i < fFontStyleSets.count(); ++i) { 338 for (int j = 0; j < fFontStyleSets[i]->fStyles.count(); ++j) { 339 if (fFontStyleSets[i]->fStyles[j] == typeface) { 340 return fFontStyleSets[i]->matchStyle(style); 341 } 342 } 343 } 344 return NULL; 345 } 346 347 virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], 348 const SkFontStyle& style, 349 const char bpc47[], 350 uint32_t character) const SK_OVERRIDE 351 { 352 // The variant 'elegant' is 'not squashed', 'compact' is 'stays in ascent/descent'. 353 // The variant 'default' means 'compact and elegant'. 354 // As a result, it is not possible to know the variant context from the font alone. 355 // TODO: add 'is_elegant' and 'is_compact' bits to 'style' request. 356 357 // For compatibility, try 'elegant' fonts first in fallback. 358 uint32_t variantMask = kElegant_FontVariant; 359 360 // The first time match anything in the mask, second time anything not in the mask. 361 for (bool maskMatches = true; maskMatches != false; maskMatches = false) { 362 SkLanguage lang(bpc47); 363 // Match against the language, removing a segment each time. 364 // The last time through the loop, the language will be empty. 365 // The empty language is special, and matches all languages. 366 do { 367 const SkString& langTag = lang.getTag(); 368 for (int i = 0; i < fFallbackNameToFamilyMap.count(); ++i) { 369 SkFontStyleSet_Android* family = fFallbackNameToFamilyMap[i].styleSet; 370 SkAutoTUnref<SkTypeface_AndroidSystem> face(family->matchStyle(style)); 371 372 if (!langTag.isEmpty() && langTag != face->fLang.getTag()) { 373 continue; 374 } 375 376 if (SkToBool(face->fVariantStyle & variantMask) != maskMatches) { 377 continue; 378 } 379 380 SkPaint paint; 381 paint.setTypeface(face); 382 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); 383 384 uint16_t glyphID; 385 paint.textToGlyphs(&character, sizeof(character), &glyphID); 386 if (glyphID != 0) { 387 return face.detach(); 388 } 389 } 390 } while (!lang.getTag().isEmpty() && (lang = lang.getParent(), true)); 391 } 392 return NULL; 393 } 394 395 virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE { 396 SkAutoTUnref<SkStream> stream(new SkMemoryStream(data)); 397 return this->createFromStream(stream, ttcIndex); 398 } 399 400 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE { 401 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path)); 402 return stream.get() ? this->createFromStream(stream, ttcIndex) : NULL; 403 } 404 405 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE { 406 bool isFixedPitch; 407 SkTypeface::Style style; 408 SkString name; 409 if (!SkTypeface_FreeType::ScanFont(stream, ttcIndex, &name, &style, &isFixedPitch)) { 410 return NULL; 411 } 412 return SkNEW_ARGS(SkTypeface_AndroidStream, (stream, ttcIndex, 413 style, isFixedPitch, name)); 414 } 415 416 417 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[], 418 unsigned styleBits) const SK_OVERRIDE { 419 SkTypeface::Style oldStyle = (SkTypeface::Style)styleBits; 420 SkFontStyle style = SkFontStyle(oldStyle & SkTypeface::kBold 421 ? SkFontStyle::kBold_Weight 422 : SkFontStyle::kNormal_Weight, 423 SkFontStyle::kNormal_Width, 424 oldStyle & SkTypeface::kItalic 425 ? SkFontStyle::kItalic_Slant 426 : SkFontStyle::kUpright_Slant); 427 428 if (familyName) { 429 // On Android, we must return NULL when we can't find the requested 430 // named typeface so that the system/app can provide their own recovery 431 // mechanism. On other platforms we'd provide a typeface from the 432 // default family instead. 433 return this->onMatchFamilyStyle(familyName, style); 434 } 435 return fDefaultFamily->matchStyle(style); 436 } 437 438 439private: 440 441 SkTArray<SkAutoTUnref<SkFontStyleSet_Android>, true> fFontStyleSets; 442 SkFontStyleSet* fDefaultFamily; 443 SkTypeface* fDefaultTypeface; 444 445 SkTDArray<NameToFamily> fNameToFamilyMap; 446 SkTDArray<NameToFamily> fFallbackNameToFamilyMap; 447 448 void buildNameToFamilyMap(SkTDArray<FontFamily*> families, const char* basePath) { 449 for (int i = 0; i < families.count(); i++) { 450 FontFamily& family = *families[i]; 451 452 SkTDArray<NameToFamily>* nameToFamily = &fNameToFamilyMap; 453 if (family.fIsFallbackFont) { 454 nameToFamily = &fFallbackNameToFamilyMap; 455 456 if (0 == family.fNames.count()) { 457 SkString& fallbackName = family.fNames.push_back(); 458 fallbackName.printf("%.2x##fallback", i); 459 } 460 } 461 462 SkFontStyleSet_Android* newSet = SkNEW_ARGS(SkFontStyleSet_Android, (family, basePath)); 463 if (0 == newSet->count()) { 464 SkDELETE(newSet); 465 continue; 466 } 467 fFontStyleSets.push_back().reset(newSet); 468 469 for (int j = 0; j < family.fNames.count(); j++) { 470 NameToFamily* nextEntry = nameToFamily->append(); 471 SkNEW_PLACEMENT_ARGS(&nextEntry->name, SkString, (family.fNames[j])); 472 nextEntry->styleSet = newSet; 473 } 474 } 475 } 476 477 void findDefaultFont() { 478 SkASSERT(!fFontStyleSets.empty()); 479 480 static const char* gDefaultNames[] = { "sans-serif" }; 481 for (size_t i = 0; i < SK_ARRAY_COUNT(gDefaultNames); ++i) { 482 SkFontStyleSet* set = this->onMatchFamily(gDefaultNames[i]); 483 if (NULL == set) { 484 continue; 485 } 486 SkTypeface* tf = set->matchStyle(SkFontStyle()); 487 if (NULL == tf) { 488 continue; 489 } 490 fDefaultFamily = set; 491 fDefaultTypeface = tf; 492 break; 493 } 494 if (NULL == fDefaultTypeface) { 495 fDefaultFamily = fFontStyleSets[0]; 496 fDefaultTypeface = fDefaultFamily->createTypeface(0); 497 } 498 SkASSERT(fDefaultFamily); 499 SkASSERT(fDefaultTypeface); 500 } 501 502 typedef SkFontMgr INHERITED; 503}; 504 505/////////////////////////////////////////////////////////////////////////////// 506 507SkFontMgr* SkFontMgr::Factory() { 508 // The call to SkGetTestFontConfiguration is so that Chromium can override the environment. 509 // TODO: these globals need to be removed, in favor of a constructor / separate Factory 510 // which can be used instead. 511 const char* mainConfigFile; 512 const char* fallbackConfigFile; 513 const char* basePath; 514 SkGetTestFontConfiguration(&mainConfigFile, &fallbackConfigFile, &basePath); 515 if (mainConfigFile) { 516 return SkNEW_ARGS(SkFontMgr_Android, (mainConfigFile, fallbackConfigFile, basePath)); 517 } 518 519 return SkNEW(SkFontMgr_Android); 520} 521 522void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf, 523 const char* fontsdir) { 524 gTestMainConfigFile = mainconf; 525 gTestFallbackConfigFile = fallbackconf; 526 gTestFontFilePrefix = fontsdir; 527 SkASSERT(gTestMainConfigFile); 528 SkASSERT(gTestFallbackConfigFile); 529 SkASSERT(gTestFontFilePrefix); 530 SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s", 531 gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix)); 532} 533 534void SkGetTestFontConfiguration(const char** mainconf, const char** fallbackconf, 535 const char** fontsdir) { 536 *mainconf = gTestMainConfigFile; 537 *fallbackconf = gTestFallbackConfigFile; 538 *fontsdir = gTestFontFilePrefix; 539} 540