1 2 /* 3 * Copyright 2013 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 #include "SkFontConfigInterface.h" 10 #include "SkTypeface_android.h" 11 12 #include "SkFontConfigParser_android.h" 13 #include "SkFontConfigTypeface.h" 14 #include "SkFontMgr.h" 15 #include "SkGlyphCache.h" 16 #include "SkPaint.h" 17 #include "SkString.h" 18 #include "SkStream.h" 19 #include "SkThread.h" 20 #include "SkTypefaceCache.h" 21 #include "SkTArray.h" 22 #include "SkTDict.h" 23 #include "SkTSearch.h" 24 25 #include <stdio.h> 26 #include <string.h> 27 28 #ifndef SK_DEBUG_FONTS 29 #define SK_DEBUG_FONTS 0 30 #endif 31 32 #if SK_DEBUG_FONTS 33 #define DEBUG_FONT(args) SkDebugf args 34 #else 35 #define DEBUG_FONT(args) 36 #endif 37 38 /////////////////////////////////////////////////////////////////////////////// 39 40 // For test only. 41 static const char* gTestMainConfigFile = NULL; 42 static const char* gTestFallbackConfigFile = NULL; 43 static const char* gTestFontFilePrefix = NULL; 44 45 /////////////////////////////////////////////////////////////////////////////// 46 47 typedef int32_t FontRecID; 48 #define INVALID_FONT_REC_ID -1 49 50 typedef int32_t FamilyRecID; 51 #define INVALID_FAMILY_REC_ID -1 52 53 // used to record our notion of the pre-existing fonts 54 struct FontRec { 55 SkRefPtr<SkTypeface> fTypeface; 56 SkString fFileName; 57 SkTypeface::Style fStyle; 58 SkPaintOptionsAndroid fPaintOptions; 59 bool fIsFallbackFont; 60 bool fIsValid; 61 FamilyRecID fFamilyRecID; 62 }; 63 64 struct FamilyRec { 65 FamilyRec() { 66 memset(fFontRecID, INVALID_FONT_REC_ID, sizeof(fFontRecID)); 67 } 68 69 static const int FONT_STYLE_COUNT = 4; 70 FontRecID fFontRecID[FONT_STYLE_COUNT]; 71 }; 72 73 74 typedef SkTDArray<FontRecID> FallbackFontList; 75 76 class SkFontConfigInterfaceAndroid : public SkFontConfigInterface { 77 public: 78 SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies); 79 virtual ~SkFontConfigInterfaceAndroid(); 80 81 virtual bool matchFamilyName(const char familyName[], 82 SkTypeface::Style requested, 83 FontIdentity* outFontIdentifier, 84 SkString* outFamilyName, 85 SkTypeface::Style* outStyle) SK_OVERRIDE; 86 virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE; 87 88 // new APIs 89 virtual SkDataTable* getFamilyNames() SK_OVERRIDE; 90 virtual bool matchFamilySet(const char inFamilyName[], 91 SkString* outFamilyName, 92 SkTArray<FontIdentity>*) SK_OVERRIDE; 93 94 /** 95 * Get the family name of the font in the default fallback font list that 96 * contains the specified chararacter. if no font is found, returns false. 97 */ 98 bool getFallbackFamilyNameForChar(SkUnichar uni, SkString* name); 99 /** 100 * 101 */ 102 SkTypeface* getTypefaceForChar(SkUnichar uni, SkTypeface::Style style, 103 SkPaintOptionsAndroid::FontVariant fontVariant); 104 SkTypeface* nextLogicalTypeface(SkFontID currFontID, SkFontID origFontID, 105 const SkPaintOptionsAndroid& options); 106 107 private: 108 void addFallbackFont(FontRecID fontRecID); 109 SkTypeface* getTypefaceForFontRec(FontRecID fontRecID); 110 FallbackFontList* getCurrentLocaleFallbackFontList(); 111 FallbackFontList* findFallbackFontList(const SkLanguage& lang, bool isOriginal = true); 112 113 SkTArray<FontRec> fFonts; 114 SkTArray<FamilyRec> fFontFamilies; 115 SkTDict<FamilyRecID> fFamilyNameDict; 116 FamilyRecID fDefaultFamilyRecID; 117 118 // (SkLanguage)<->(fallback chain index) translation 119 SkTDict<FallbackFontList*> fFallbackFontDict; 120 SkTDict<FallbackFontList*> fFallbackFontAliasDict; 121 FallbackFontList fDefaultFallbackList; 122 123 // fallback info for current locale 124 SkString fCachedLocale; 125 FallbackFontList* fLocaleFallbackFontList; 126 }; 127 128 /////////////////////////////////////////////////////////////////////////////// 129 130 static SkFontConfigInterfaceAndroid* getSingletonInterface() { 131 SK_DECLARE_STATIC_MUTEX(gMutex); 132 static SkFontConfigInterfaceAndroid* gFontConfigInterface; 133 134 SkAutoMutexAcquire ac(gMutex); 135 if (NULL == gFontConfigInterface) { 136 // load info from a configuration file that we can use to populate the 137 // system/fallback font structures 138 SkTDArray<FontFamily*> fontFamilies; 139 if (!gTestMainConfigFile) { 140 SkFontConfigParser::GetFontFamilies(fontFamilies); 141 } else { 142 SkFontConfigParser::GetTestFontFamilies(fontFamilies, gTestMainConfigFile, 143 gTestFallbackConfigFile); 144 } 145 146 gFontConfigInterface = new SkFontConfigInterfaceAndroid(fontFamilies); 147 148 // cleanup the data we received from the parser 149 fontFamilies.deleteAll(); 150 } 151 return gFontConfigInterface; 152 } 153 154 SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() { 155 return getSingletonInterface(); 156 } 157 158 /////////////////////////////////////////////////////////////////////////////// 159 160 static bool has_font(const SkTArray<FontRec>& array, const SkString& filename) { 161 for (int i = 0; i < array.count(); i++) { 162 if (array[i].fFileName == filename) { 163 return true; 164 } 165 } 166 return false; 167 } 168 169 #ifndef SK_FONT_FILE_PREFIX 170 #define SK_FONT_FILE_PREFIX "/fonts/" 171 #endif 172 173 static void get_path_for_sys_fonts(SkString* full, const char name[]) { 174 if (gTestFontFilePrefix) { 175 full->set(gTestFontFilePrefix); 176 } else { 177 full->set(getenv("ANDROID_ROOT")); 178 full->append(SK_FONT_FILE_PREFIX); 179 } 180 full->append(name); 181 } 182 183 static void insert_into_name_dict(SkTDict<FamilyRecID>& familyNameDict, 184 const char* name, FamilyRecID familyRecID) { 185 SkAutoAsciiToLC tolc(name); 186 if (familyNameDict.find(tolc.lc())) { 187 SkDebugf("---- system font attempting to use a the same name [%s] for" 188 "multiple families. skipping subsequent occurrences", tolc.lc()); 189 } else { 190 familyNameDict.set(tolc.lc(), familyRecID); 191 } 192 } 193 194 // Defined in SkFontHost_FreeType.cpp 195 bool find_name_and_attributes(SkStream* stream, SkString* name, 196 SkTypeface::Style* style, bool* isFixedWidth); 197 198 /////////////////////////////////////////////////////////////////////////////// 199 200 SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies) : 201 fFonts(fontFamilies.count()), 202 fFontFamilies(fontFamilies.count() / FamilyRec::FONT_STYLE_COUNT), 203 fFamilyNameDict(1024), 204 fDefaultFamilyRecID(INVALID_FAMILY_REC_ID), 205 fFallbackFontDict(128), 206 fFallbackFontAliasDict(128), 207 fLocaleFallbackFontList(NULL) { 208 209 for (int i = 0; i < fontFamilies.count(); ++i) { 210 FontFamily* family = fontFamilies[i]; 211 212 // defer initializing the familyRec until we can be sure that at least 213 // one of it's children contains a valid font file 214 FamilyRec* familyRec = NULL; 215 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID; 216 217 for (int j = 0; j < family->fFontFiles.count(); ++j) { 218 SkString filename; 219 get_path_for_sys_fonts(&filename, family->fFontFiles[j]->fFileName); 220 221 if (has_font(fFonts, filename)) { 222 SkDebugf("---- system font and fallback font files specify a duplicate " 223 "font %s, skipping the second occurrence", filename.c_str()); 224 continue; 225 } 226 227 FontRec& fontRec = fFonts.push_back(); 228 fontRec.fFileName = filename; 229 fontRec.fStyle = SkTypeface::kNormal; 230 fontRec.fPaintOptions = family->fFontFiles[j]->fPaintOptions; 231 fontRec.fIsFallbackFont = family->fIsFallbackFont; 232 fontRec.fIsValid = false; 233 fontRec.fFamilyRecID = familyRecID; 234 235 const FontRecID fontRecID = fFonts.count() - 1; 236 237 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(filename.c_str())); 238 if (stream.get() != NULL) { 239 bool isFixedWidth; 240 SkString name; 241 fontRec.fIsValid = find_name_and_attributes(stream.get(), &name, 242 &fontRec.fStyle, &isFixedWidth); 243 } else { 244 if (!fontRec.fIsFallbackFont) { 245 SkDebugf("---- failed to open <%s> as a font\n", filename.c_str()); 246 } 247 } 248 249 if (fontRec.fIsValid) { 250 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s", 251 i, fFonts.count() - 1, fontRec.fIsFallbackFont, filename.c_str())); 252 } else { 253 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s (INVALID)", 254 i, fFonts.count() - 1, fontRec.fIsFallbackFont, filename.c_str())); 255 continue; 256 } 257 258 // create a familyRec now that we know that at least one font in 259 // the family is valid 260 if (familyRec == NULL) { 261 familyRec = &fFontFamilies.push_back(); 262 familyRecID = fFontFamilies.count() - 1; 263 fontRec.fFamilyRecID = familyRecID; 264 } 265 266 // add this font to the current familyRec 267 if (INVALID_FONT_REC_ID != familyRec->fFontRecID[fontRec.fStyle]) { 268 DEBUG_FONT(("Overwriting familyRec for style[%d] old,new:(%d,%d)", 269 fontRec.fStyle, familyRec->fFontRecID[fontRec.fStyle], 270 fontRecID)); 271 } 272 familyRec->fFontRecID[fontRec.fStyle] = fontRecID; 273 274 // if this is a fallback font then add it to the appropriate fallback chains 275 if (fontRec.fIsFallbackFont) { 276 addFallbackFont(fontRecID); 277 } 278 279 // add the fallback file name to the name dictionary. This is needed 280 // by getFallbackFamilyNameForChar() so that fallback families can be 281 // requested by the filenames of the fonts they contain. 282 if (family->fIsFallbackFont && familyRec) { 283 insert_into_name_dict(fFamilyNameDict, fontRec.fFileName.c_str(), familyRecID); 284 } 285 } 286 287 // add the names that map to this family to the dictionary for easy lookup 288 if (familyRec && !family->fIsFallbackFont) { 289 SkTDArray<const char*> names = family->fNames; 290 if (names.isEmpty()) { 291 SkDEBUGFAIL("ERROR: non-fallback font with no name"); 292 continue; 293 } 294 295 for (int i = 0; i < names.count(); i++) { 296 insert_into_name_dict(fFamilyNameDict, names[i], familyRecID); 297 } 298 } 299 300 } 301 302 DEBUG_FONT(("---- We have %d system fonts", fFonts.count())); 303 304 if (fFontFamilies.count() > 0) { 305 fDefaultFamilyRecID = 0; 306 } 307 308 // scans the default fallback font chain, adding every entry to every other 309 // fallback font chain to which it does not belong. this results in every 310 // language-specific fallback font chain having all of its fallback fonts at 311 // the front of the chain, and everything else at the end. 312 FallbackFontList* fallbackList; 313 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict); 314 const char* fallbackLang = iter.next(&fallbackList); 315 while(fallbackLang != NULL) { 316 for (int i = 0; i < fDefaultFallbackList.count(); i++) { 317 FontRecID fontRecID = fDefaultFallbackList[i]; 318 const SkString& fontLang = fFonts[fontRecID].fPaintOptions.getLanguage().getTag(); 319 if (strcmp(fallbackLang, fontLang.c_str()) != 0) { 320 fallbackList->push(fontRecID); 321 } 322 } 323 // move to the next fallback list in the dictionary 324 fallbackLang = iter.next(&fallbackList); 325 } 326 } 327 328 SkFontConfigInterfaceAndroid::~SkFontConfigInterfaceAndroid() { 329 // iterate through and cleanup fFallbackFontDict 330 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict); 331 FallbackFontList* fallbackList; 332 while(iter.next(&fallbackList) != NULL) { 333 SkDELETE(fallbackList); 334 } 335 } 336 337 void SkFontConfigInterfaceAndroid::addFallbackFont(FontRecID fontRecID) { 338 SkASSERT(fontRecID < fFonts.count()); 339 const FontRec& fontRec = fFonts[fontRecID]; 340 SkASSERT(fontRec.fIsFallbackFont); 341 342 // add to the default fallback list 343 fDefaultFallbackList.push(fontRecID); 344 345 // stop here if it is the default language tag 346 const SkString& languageTag = fontRec.fPaintOptions.getLanguage().getTag(); 347 if (languageTag.isEmpty()) { 348 return; 349 } 350 351 // add to the appropriate language's custom fallback list 352 FallbackFontList* customList = NULL; 353 if (!fFallbackFontDict.find(languageTag.c_str(), &customList)) { 354 DEBUG_FONT(("---- Created fallback list for \"%s\"", languageTag.c_str())); 355 customList = SkNEW(FallbackFontList); 356 fFallbackFontDict.set(languageTag.c_str(), customList); 357 } 358 SkASSERT(customList != NULL); 359 customList->push(fontRecID); 360 } 361 362 363 static FontRecID find_best_style(const FamilyRec& family, SkTypeface::Style style) { 364 365 const FontRecID* fontRecIDs = family.fFontRecID; 366 367 if (fontRecIDs[style] != INVALID_FONT_REC_ID) { // exact match 368 return fontRecIDs[style]; 369 } 370 // look for a matching bold 371 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic); 372 if (fontRecIDs[style] != INVALID_FONT_REC_ID) { 373 return fontRecIDs[style]; 374 } 375 // look for the plain 376 if (fontRecIDs[SkTypeface::kNormal] != INVALID_FONT_REC_ID) { 377 return fontRecIDs[SkTypeface::kNormal]; 378 } 379 // look for anything 380 for (int i = 0; i < FamilyRec::FONT_STYLE_COUNT; i++) { 381 if (fontRecIDs[i] != INVALID_FONT_REC_ID) { 382 return fontRecIDs[i]; 383 } 384 } 385 // should never get here, since the fontRecID list should not be empty 386 SkDEBUGFAIL("No valid fonts exist for this family"); 387 return -1; 388 } 389 390 bool SkFontConfigInterfaceAndroid::matchFamilyName(const char familyName[], 391 SkTypeface::Style style, 392 FontIdentity* outFontIdentifier, 393 SkString* outFamilyName, 394 SkTypeface::Style* outStyle) { 395 // clip to legal style bits 396 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); 397 398 bool exactNameMatch = false; 399 400 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID; 401 if (NULL != familyName) { 402 SkAutoAsciiToLC tolc(familyName); 403 if (fFamilyNameDict.find(tolc.lc(), &familyRecID)) { 404 exactNameMatch = true; 405 } 406 } else { 407 familyRecID = fDefaultFamilyRecID; 408 409 } 410 411 if (INVALID_FAMILY_REC_ID == familyRecID) { 412 //TODO this ensures that we always return something 413 familyRecID = fDefaultFamilyRecID; 414 //return false; 415 } 416 417 FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], style); 418 FontRec& fontRec = fFonts[fontRecID]; 419 420 if (NULL != outFontIdentifier) { 421 outFontIdentifier->fID = fontRecID; 422 outFontIdentifier->fTTCIndex = 0; 423 outFontIdentifier->fString.set(fontRec.fFileName); 424 // outFontIdentifier->fStyle = fontRec.fStyle; 425 } 426 427 if (NULL != outFamilyName) { 428 if (exactNameMatch) { 429 outFamilyName->set(familyName); 430 } else { 431 // find familyName from list of names 432 const char* familyName = NULL; 433 SkAssertResult(fFamilyNameDict.findKey(familyRecID, &familyName)); 434 SkASSERT(familyName); 435 outFamilyName->set(familyName); 436 } 437 } 438 439 if (NULL != outStyle) { 440 *outStyle = fontRec.fStyle; 441 } 442 443 return true; 444 } 445 446 SkStream* SkFontConfigInterfaceAndroid::openStream(const FontIdentity& identity) { 447 return SkStream::NewFromFile(identity.fString.c_str()); 448 } 449 450 SkDataTable* SkFontConfigInterfaceAndroid::getFamilyNames() { 451 SkTDArray<const char*> names; 452 SkTDArray<size_t> sizes; 453 454 SkTDict<FamilyRecID>::Iter iter(fFamilyNameDict); 455 const char* familyName = iter.next(NULL); 456 while(familyName != NULL) { 457 *names.append() = familyName; 458 *sizes.append() = strlen(familyName) + 1; 459 460 // move to the next familyName in the dictionary 461 familyName = iter.next(NULL); 462 } 463 464 return SkDataTable::NewCopyArrays((const void*const*)names.begin(), 465 sizes.begin(), names.count()); 466 } 467 468 bool SkFontConfigInterfaceAndroid::matchFamilySet(const char inFamilyName[], 469 SkString* outFamilyName, 470 SkTArray<FontIdentity>*) { 471 return false; 472 } 473 474 static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) { 475 const FontRecID* fontRecID = (const FontRecID*)ctx; 476 FontRecID currFontRecID = ((FontConfigTypeface*)face)->getIdentity().fID; 477 return currFontRecID == *fontRecID; 478 } 479 480 SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForFontRec(FontRecID fontRecID) { 481 FontRec& fontRec = fFonts[fontRecID]; 482 SkTypeface* face = fontRec.fTypeface.get(); 483 if (!face) { 484 // look for it in the typeface cache 485 face = SkTypefaceCache::FindByProcAndRef(find_proc, &fontRecID); 486 487 // if it is not in the cache then create it 488 if (!face) { 489 const char* familyName = NULL; 490 SkAssertResult(fFamilyNameDict.findKey(fontRec.fFamilyRecID, &familyName)); 491 SkASSERT(familyName); 492 face = SkTypeface::CreateFromName(familyName, fontRec.fStyle); 493 } 494 495 // store the result for subsequent lookups 496 fontRec.fTypeface = face; 497 } 498 SkASSERT(face); 499 return face; 500 } 501 502 bool SkFontConfigInterfaceAndroid::getFallbackFamilyNameForChar(SkUnichar uni, SkString* name) { 503 FallbackFontList* fallbackFontList = this->getCurrentLocaleFallbackFontList(); 504 for (int i = 0; i < fallbackFontList->count(); i++) { 505 FontRecID fontRecID = fallbackFontList->getAt(i); 506 SkTypeface* face = this->getTypefaceForFontRec(fontRecID); 507 508 SkPaint paint; 509 paint.setTypeface(face); 510 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); 511 512 uint16_t glyphID; 513 paint.textToGlyphs(&uni, sizeof(uni), &glyphID); 514 if (glyphID != 0) { 515 name->set(fFonts[fontRecID].fFileName); 516 return true; 517 } 518 } 519 return false; 520 } 521 522 SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForChar(SkUnichar uni, 523 SkTypeface::Style style, 524 SkPaintOptionsAndroid::FontVariant fontVariant) { 525 FontRecID fontRecID = find_best_style(fFontFamilies[fDefaultFamilyRecID], style); 526 SkTypeface* face = this->getTypefaceForFontRec(fontRecID); 527 528 SkPaintOptionsAndroid paintOptions; 529 paintOptions.setFontVariant(fontVariant); 530 paintOptions.setUseFontFallbacks(true); 531 532 SkPaint paint; 533 paint.setTypeface(face); 534 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); 535 paint.setPaintOptionsAndroid(paintOptions); 536 537 SkAutoGlyphCache autoCache(paint, NULL, NULL); 538 SkGlyphCache* cache = autoCache.getCache(); 539 540 SkScalerContext* ctx = cache->getScalerContext(); 541 if (ctx) { 542 SkFontID fontID = ctx->findTypefaceIdForChar(uni); 543 return SkTypefaceCache::FindByID(fontID); 544 } 545 return NULL; 546 } 547 548 FallbackFontList* SkFontConfigInterfaceAndroid::getCurrentLocaleFallbackFontList() { 549 SkString locale = SkFontConfigParser::GetLocale(); 550 if (NULL == fLocaleFallbackFontList || locale != fCachedLocale) { 551 fCachedLocale = locale; 552 fLocaleFallbackFontList = this->findFallbackFontList(locale); 553 } 554 return fLocaleFallbackFontList; 555 } 556 557 FallbackFontList* SkFontConfigInterfaceAndroid::findFallbackFontList(const SkLanguage& lang, 558 bool isOriginal) { 559 const SkString& langTag = lang.getTag(); 560 if (langTag.isEmpty()) { 561 return &fDefaultFallbackList; 562 } 563 564 FallbackFontList* fallbackFontList; 565 if (fFallbackFontDict.find(langTag.c_str(), langTag.size(), &fallbackFontList) || 566 fFallbackFontAliasDict.find(langTag.c_str(), langTag.size(), &fallbackFontList)) { 567 return fallbackFontList; 568 } 569 570 // attempt a recursive fuzzy match 571 SkLanguage parent = lang.getParent(); 572 fallbackFontList = findFallbackFontList(parent, false); 573 574 // cache the original lang so we don't have to do the recursion again. 575 if (isOriginal) { 576 DEBUG_FONT(("---- Created fallback list alias for \"%s\"", langTag.c_str())); 577 fFallbackFontAliasDict.set(langTag.c_str(), fallbackFontList); 578 } 579 return fallbackFontList; 580 } 581 582 SkTypeface* SkFontConfigInterfaceAndroid::nextLogicalTypeface(SkFontID currFontID, 583 SkFontID origFontID, 584 const SkPaintOptionsAndroid& opts) { 585 // Skia does not support font fallback by default. This enables clients such 586 // as WebKit to customize their font selection. In any case, clients can use 587 // GetFallbackFamilyNameForChar() to get the fallback font for individual 588 // characters. 589 if (!opts.isUsingFontFallbacks()) { 590 return NULL; 591 } 592 593 FallbackFontList* currentFallbackList = findFallbackFontList(opts.getLanguage()); 594 SkASSERT(currentFallbackList); 595 596 // we must convert currTypeface into a FontRecID 597 FontRecID currFontRecID = INVALID_FONT_REC_ID; 598 const SkTypeface* currTypeface = SkTypefaceCache::FindByID(currFontID); 599 // non-system fonts are not in the font cache so if we are asked to fallback 600 // for a non-system font we will start at the front of the chain. 601 if (NULL != currTypeface && currFontID != origFontID) { 602 currFontRecID = ((FontConfigTypeface*)currTypeface)->getIdentity().fID; 603 SkASSERT(INVALID_FONT_REC_ID != currFontRecID); 604 } 605 606 // lookup the index next font in the chain 607 int currFallbackFontIndex = currentFallbackList->find(currFontRecID); 608 // We add 1 to the returned index for 2 reasons: (1) if find succeeds it moves 609 // our index to the next entry in the list; (2) if find() fails it returns 610 // -1 and incrementing it will set our starting index to 0 (the head of the list) 611 int nextFallbackFontIndex = currFallbackFontIndex + 1; 612 613 if(nextFallbackFontIndex >= currentFallbackList->count()) { 614 return NULL; 615 } 616 617 // If a rec object is set to prefer "kDefault_Variant" it means they have no preference 618 // In this case, we set the value to "kCompact_Variant" 619 SkPaintOptionsAndroid::FontVariant variant = opts.getFontVariant(); 620 if (variant == SkPaintOptionsAndroid::kDefault_Variant) { 621 variant = SkPaintOptionsAndroid::kCompact_Variant; 622 } 623 624 int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | variant; 625 626 SkTypeface* nextLogicalTypeface = 0; 627 while (nextFallbackFontIndex < currentFallbackList->count()) { 628 FontRecID fontRecID = currentFallbackList->getAt(nextFallbackFontIndex); 629 if ((fFonts[fontRecID].fPaintOptions.getFontVariant() & acceptedVariants) != 0) { 630 nextLogicalTypeface = this->getTypefaceForFontRec(fontRecID); 631 break; 632 } 633 nextFallbackFontIndex++; 634 } 635 636 DEBUG_FONT(("---- nextLogicalFont: currFontID=%d, origFontID=%d, currRecID=%d, " 637 "lang=%s, variant=%d, nextFallbackIndex[%d,%d] => nextLogicalTypeface=%d", 638 currFontID, origFontID, currFontRecID, opts.getLanguage().getTag().c_str(), 639 variant, nextFallbackFontIndex, currentFallbackList->getAt(nextFallbackFontIndex), 640 (nextLogicalTypeface) ? nextLogicalTypeface->uniqueID() : 0)); 641 return SkSafeRef(nextLogicalTypeface); 642 } 643 644 /////////////////////////////////////////////////////////////////////////////// 645 646 bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name) { 647 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface(); 648 return fontConfig->getFallbackFamilyNameForChar(uni, name); 649 } 650 651 void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf, 652 const char* fontsdir) { 653 gTestMainConfigFile = mainconf; 654 gTestFallbackConfigFile = fallbackconf; 655 gTestFontFilePrefix = fontsdir; 656 SkASSERT(gTestMainConfigFile); 657 SkASSERT(gTestFallbackConfigFile); 658 SkASSERT(gTestFontFilePrefix); 659 SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s", 660 gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix)); 661 } 662 663 SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID, 664 const SkPaintOptionsAndroid& options) { 665 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface(); 666 return fontConfig->nextLogicalTypeface(currFontID, origFontID, options); 667 668 } 669 670 /////////////////////////////////////////////////////////////////////////////// 671 672 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 673 674 struct HB_UnicodeMapping { 675 // TODO: when the WebView no longer needs harfbuzz_old, remove 676 HB_Script script_old; 677 hb_script_t script; 678 const SkUnichar unicode; 679 }; 680 681 /* 682 * The following scripts are not complex fonts and we do not expect them to be parsed by this table 683 * HB_SCRIPT_COMMON, 684 * HB_SCRIPT_GREEK, 685 * HB_SCRIPT_CYRILLIC, 686 * HB_SCRIPT_HANGUL 687 * HB_SCRIPT_INHERITED 688 */ 689 690 /* Harfbuzz (old) is missing a number of scripts in its table. For these, 691 * we include a value which can never happen. We won't get complex script 692 * shaping in these cases, but the library wouldn't know how to shape 693 * them anyway. */ 694 #define HB_Script_Unknown HB_ScriptCount 695 696 static HB_UnicodeMapping HB_UnicodeMappingArray[] = { 697 {HB_Script_Armenian, HB_SCRIPT_ARMENIAN, 0x0531}, 698 {HB_Script_Hebrew, HB_SCRIPT_HEBREW, 0x0591}, 699 {HB_Script_Arabic, HB_SCRIPT_ARABIC, 0x0600}, 700 {HB_Script_Syriac, HB_SCRIPT_SYRIAC, 0x0710}, 701 {HB_Script_Thaana, HB_SCRIPT_THAANA, 0x0780}, 702 {HB_Script_Nko, HB_SCRIPT_NKO, 0x07C0}, 703 {HB_Script_Devanagari, HB_SCRIPT_DEVANAGARI, 0x0901}, 704 {HB_Script_Bengali, HB_SCRIPT_BENGALI, 0x0981}, 705 {HB_Script_Gurmukhi, HB_SCRIPT_GURMUKHI, 0x0A10}, 706 {HB_Script_Gujarati, HB_SCRIPT_GUJARATI, 0x0A90}, 707 {HB_Script_Oriya, HB_SCRIPT_ORIYA, 0x0B10}, 708 {HB_Script_Tamil, HB_SCRIPT_TAMIL, 0x0B82}, 709 {HB_Script_Telugu, HB_SCRIPT_TELUGU, 0x0C10}, 710 {HB_Script_Kannada, HB_SCRIPT_KANNADA, 0x0C90}, 711 {HB_Script_Malayalam, HB_SCRIPT_MALAYALAM, 0x0D10}, 712 {HB_Script_Sinhala, HB_SCRIPT_SINHALA, 0x0D90}, 713 {HB_Script_Thai, HB_SCRIPT_THAI, 0x0E01}, 714 {HB_Script_Lao, HB_SCRIPT_LAO, 0x0E81}, 715 {HB_Script_Tibetan, HB_SCRIPT_TIBETAN, 0x0F00}, 716 {HB_Script_Myanmar, HB_SCRIPT_MYANMAR, 0x1000}, 717 {HB_Script_Georgian, HB_SCRIPT_GEORGIAN, 0x10A0}, 718 {HB_Script_Unknown, HB_SCRIPT_ETHIOPIC, 0x1200}, 719 {HB_Script_Unknown, HB_SCRIPT_CHEROKEE, 0x13A0}, 720 {HB_Script_Ogham, HB_SCRIPT_OGHAM, 0x1680}, 721 {HB_Script_Runic, HB_SCRIPT_RUNIC, 0x16A0}, 722 {HB_Script_Khmer, HB_SCRIPT_KHMER, 0x1780}, 723 {HB_Script_Unknown, HB_SCRIPT_TAI_LE, 0x1950}, 724 {HB_Script_Unknown, HB_SCRIPT_NEW_TAI_LUE, 0x1980}, 725 {HB_Script_Unknown, HB_SCRIPT_TAI_THAM, 0x1A20}, 726 {HB_Script_Unknown, HB_SCRIPT_CHAM, 0xAA00}, 727 }; 728 729 static hb_script_t getHBScriptFromHBScriptOld(HB_Script script_old) { 730 hb_script_t script = HB_SCRIPT_INVALID; 731 int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping); 732 for (int i = 0; i < numSupportedFonts; i++) { 733 if (script_old == HB_UnicodeMappingArray[i].script_old) { 734 script = HB_UnicodeMappingArray[i].script; 735 break; 736 } 737 } 738 return script; 739 } 740 741 // returns 0 for "Not Found" 742 static SkUnichar getUnicodeFromHBScript(hb_script_t script) { 743 SkUnichar unichar = 0; 744 int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping); 745 for (int i = 0; i < numSupportedFonts; i++) { 746 if (script == HB_UnicodeMappingArray[i].script) { 747 unichar = HB_UnicodeMappingArray[i].unicode; 748 break; 749 } 750 } 751 return unichar; 752 } 753 754 struct TypefaceLookupStruct { 755 hb_script_t script; 756 SkTypeface::Style style; 757 SkPaintOptionsAndroid::FontVariant fontVariant; 758 SkTypeface* typeface; 759 }; 760 761 SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex); // This is the mutex for gTypefaceTable 762 static SkTDArray<TypefaceLookupStruct> gTypefaceTable; // This is protected by gTypefaceTableMutex 763 764 static int typefaceLookupCompare(const TypefaceLookupStruct& first, 765 const TypefaceLookupStruct& second) { 766 if (first.script != second.script) { 767 return (first.script > second.script) ? 1 : -1; 768 } 769 if (first.style != second.style) { 770 return (first.style > second.style) ? 1 : -1; 771 } 772 if (first.fontVariant != second.fontVariant) { 773 return (first.fontVariant > second.fontVariant) ? 1 : -1; 774 } 775 return 0; 776 } 777 778 SkTypeface* SkCreateTypefaceForScriptNG(hb_script_t script, SkTypeface::Style style, 779 SkPaintOptionsAndroid::FontVariant fontVariant) { 780 SkAutoMutexAcquire ac(gTypefaceTableMutex); 781 782 TypefaceLookupStruct key; 783 key.script = script; 784 key.style = style; 785 key.fontVariant = fontVariant; 786 787 int index = SkTSearch<TypefaceLookupStruct>( 788 (const TypefaceLookupStruct*) gTypefaceTable.begin(), 789 gTypefaceTable.count(), key, sizeof(TypefaceLookupStruct), 790 typefaceLookupCompare); 791 792 SkTypeface* retTypeface = NULL; 793 if (index >= 0) { 794 retTypeface = gTypefaceTable[index].typeface; 795 } 796 else { 797 SkUnichar unichar = getUnicodeFromHBScript(script); 798 if (!unichar) { 799 return NULL; 800 } 801 802 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface(); 803 retTypeface = fontConfig->getTypefaceForChar(unichar, style, fontVariant); 804 805 // add to the lookup table 806 key.typeface = retTypeface; 807 *gTypefaceTable.insert(~index) = key; 808 } 809 810 // we ref(), the caller is expected to unref when they are done 811 return SkSafeRef(retTypeface); 812 } 813 814 SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style, 815 SkPaintOptionsAndroid::FontVariant fontVariant) { 816 return SkCreateTypefaceForScriptNG(getHBScriptFromHBScriptOld(script), style, fontVariant); 817 } 818 819 #endif 820 821 /////////////////////////////////////////////////////////////////////////////// 822 823 SkFontMgr* SkFontMgr::Factory() { 824 return NULL; 825 } 826