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