OLD | NEW |
(Empty) | |
| 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 "SkPaintOptionsAndroid.h" |
| 18 #include "SkString.h" |
| 19 #include "SkStream.h" |
| 20 #include "SkThread.h" |
| 21 #include "SkTypefaceCache.h" |
| 22 #include "SkTArray.h" |
| 23 #include "SkTDict.h" |
| 24 #include "SkTSearch.h" |
| 25 |
| 26 #include <stdio.h> |
| 27 #include <string.h> |
| 28 |
| 29 #ifndef SK_DEBUG_FONTS |
| 30 #define SK_DEBUG_FONTS 0 |
| 31 #endif |
| 32 |
| 33 #if SK_DEBUG_FONTS |
| 34 #define DEBUG_FONT(args) SkDebugf args |
| 35 #else |
| 36 #define DEBUG_FONT(args) |
| 37 #endif |
| 38 |
| 39 /////////////////////////////////////////////////////////////////////////////// |
| 40 |
| 41 // For test only. |
| 42 static const char* gTestMainConfigFile = NULL; |
| 43 static const char* gTestFallbackConfigFile = NULL; |
| 44 static const char* gTestFontFilePrefix = NULL; |
| 45 |
| 46 /////////////////////////////////////////////////////////////////////////////// |
| 47 |
| 48 // used to record our notion of the pre-existing fonts |
| 49 struct FontRec { |
| 50 SkRefPtr<SkTypeface> fTypeface; |
| 51 SkString fFileName; |
| 52 SkTypeface::Style fStyle; |
| 53 SkPaintOptionsAndroid fPaintOptions; |
| 54 bool fIsFallbackFont; |
| 55 bool fIsValid; |
| 56 }; |
| 57 |
| 58 typedef int32_t FontRecID; |
| 59 #define INVALID_FONT_REC_ID -1 |
| 60 |
| 61 struct FamilyRec { |
| 62 FamilyRec() { |
| 63 memset(fFontRecID, INVALID_FONT_REC_ID, sizeof(fFontRecID)); |
| 64 } |
| 65 |
| 66 static const int FONT_STYLE_COUNT = 4; |
| 67 FontRecID fFontRecID[FONT_STYLE_COUNT]; |
| 68 }; |
| 69 |
| 70 typedef int32_t FamilyRecID; |
| 71 #define INVALID_FAMILY_REC_ID -1 |
| 72 |
| 73 typedef SkTDArray<FontRecID> FallbackFontList; |
| 74 |
| 75 class SkFontConfigInterfaceAndroid : public SkFontConfigInterface { |
| 76 public: |
| 77 SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies); |
| 78 virtual ~SkFontConfigInterfaceAndroid(); |
| 79 |
| 80 virtual bool matchFamilyName(const char familyName[], |
| 81 SkTypeface::Style requested, |
| 82 FontIdentity* outFontIdentifier, |
| 83 SkString* outFamilyName, |
| 84 SkTypeface::Style* outStyle) SK_OVERRIDE; |
| 85 virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE; |
| 86 |
| 87 // new APIs |
| 88 virtual SkDataTable* getFamilyNames() SK_OVERRIDE; |
| 89 virtual bool matchFamilySet(const char inFamilyName[], |
| 90 SkString* outFamilyName, |
| 91 SkTArray<FontIdentity>*) SK_OVERRIDE; |
| 92 |
| 93 /** |
| 94 * Get the family name of the font in the default fallback font list that |
| 95 * contains the specified chararacter. if no font is found, returns false. |
| 96 */ |
| 97 bool getFallbackFamilyNameForChar(SkUnichar uni, SkString* name); |
| 98 /** |
| 99 * |
| 100 */ |
| 101 SkTypeface* getTypefaceForChar(SkUnichar uni, SkTypeface::Style style, |
| 102 SkPaintOptionsAndroid::FontVariant fontVarian
t); |
| 103 SkTypeface* nextLogicalTypeface(SkFontID currFontID, SkFontID origFontID, |
| 104 const SkPaintOptionsAndroid& options); |
| 105 |
| 106 private: |
| 107 void addFallbackFont(FontRecID fontRecID); |
| 108 FallbackFontList* findFallbackFontList(const SkLanguage& lang); |
| 109 |
| 110 SkTArray<FontRec> fFonts; |
| 111 SkTArray<FamilyRec> fFontFamilies; |
| 112 SkTDict<FamilyRecID> fFamilyNameDict; |
| 113 FamilyRecID fDefaultFamilyRecID; |
| 114 |
| 115 // (SkLanguage)<->(fallback chain index) translation |
| 116 SkTDict<FallbackFontList*> fFallbackFontDict; |
| 117 FallbackFontList fDefaultFallbackList; |
| 118 }; |
| 119 |
| 120 /////////////////////////////////////////////////////////////////////////////// |
| 121 |
| 122 static SkFontConfigInterfaceAndroid* getSingletonInterface() { |
| 123 SK_DECLARE_STATIC_MUTEX(gMutex); |
| 124 static SkFontConfigInterfaceAndroid* gFontConfigInterface; |
| 125 |
| 126 SkAutoMutexAcquire ac(gMutex); |
| 127 if (NULL == gFontConfigInterface) { |
| 128 // load info from a configuration file that we can use to populate the |
| 129 // system/fallback font structures |
| 130 SkTDArray<FontFamily*> fontFamilies; |
| 131 if (!gTestMainConfigFile) { |
| 132 SkFontConfigParser::GetFontFamilies(fontFamilies); |
| 133 } else { |
| 134 SkFontConfigParser::GetTestFontFamilies(fontFamilies, gTestMainConfi
gFile, |
| 135 gTestFallbackConfigFile); |
| 136 } |
| 137 |
| 138 gFontConfigInterface = new SkFontConfigInterfaceAndroid(fontFamilies); |
| 139 |
| 140 // cleanup the data we received from the parser |
| 141 fontFamilies.deleteAll(); |
| 142 } |
| 143 return gFontConfigInterface; |
| 144 } |
| 145 |
| 146 SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() { |
| 147 return getSingletonInterface(); |
| 148 } |
| 149 |
| 150 /////////////////////////////////////////////////////////////////////////////// |
| 151 |
| 152 static bool has_font(const SkTArray<FontRec>& array, const SkString& filename) { |
| 153 for (int i = 0; i < array.count(); i++) { |
| 154 if (array[i].fFileName == filename) { |
| 155 return true; |
| 156 } |
| 157 } |
| 158 return false; |
| 159 } |
| 160 |
| 161 #ifndef SK_FONT_FILE_PREFIX |
| 162 #define SK_FONT_FILE_PREFIX "/fonts/" |
| 163 #endif |
| 164 |
| 165 static void get_path_for_sys_fonts(SkString* full, const char name[]) { |
| 166 if (gTestFontFilePrefix) { |
| 167 full->set(gTestFontFilePrefix); |
| 168 } else { |
| 169 full->set(getenv("ANDROID_ROOT")); |
| 170 full->append(SK_FONT_FILE_PREFIX); |
| 171 } |
| 172 full->append(name); |
| 173 } |
| 174 |
| 175 static void insert_into_name_dict(SkTDict<FamilyRecID>& familyNameDict, |
| 176 const char* name, FamilyRecID familyRecID) { |
| 177 SkAutoAsciiToLC tolc(name); |
| 178 familyNameDict.set(tolc.lc(), familyRecID); |
| 179 } |
| 180 |
| 181 // Defined in SkFontHost_FreeType.cpp |
| 182 bool find_name_and_attributes(SkStream* stream, SkString* name, |
| 183 SkTypeface::Style* style, bool* isFixedWidth); |
| 184 |
| 185 /////////////////////////////////////////////////////////////////////////////// |
| 186 |
| 187 SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*
>& fontFamilies) : |
| 188 fFonts(fontFamilies.count()), |
| 189 fFontFamilies(fontFamilies.count() / FamilyRec::FONT_STYLE_COUNT), |
| 190 fFamilyNameDict(1024), |
| 191 fDefaultFamilyRecID(INVALID_FAMILY_REC_ID), |
| 192 fFallbackFontDict(128) { |
| 193 |
| 194 for (int i = 0; i < fontFamilies.count(); ++i) { |
| 195 FontFamily* family = fontFamilies[i]; |
| 196 |
| 197 // defer initializing the familyRec until we can be sure that at least |
| 198 // one of it's children contains a valid font file |
| 199 FamilyRec* familyRec = NULL; |
| 200 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID; |
| 201 |
| 202 for (int j = 0; j < family->fFontFiles.count(); ++j) { |
| 203 SkString filename; |
| 204 get_path_for_sys_fonts(&filename, family->fFontFiles[j]->fFileName); |
| 205 |
| 206 if (has_font(fFonts, filename)) { |
| 207 SkDebugf("---- system font and fallback font files specify a dup
licate " |
| 208 "font %s, skipping the second occurrence", filename.c_st
r()); |
| 209 continue; |
| 210 } |
| 211 |
| 212 FontRec& fontRec = fFonts.push_back(); |
| 213 fontRec.fFileName = filename; |
| 214 fontRec.fStyle = SkTypeface::kNormal; |
| 215 fontRec.fPaintOptions = family->fFontFiles[j]->fPaintOptions; |
| 216 fontRec.fIsFallbackFont = family->fIsFallbackFont; |
| 217 fontRec.fIsValid = false; |
| 218 |
| 219 const FontRecID fontRecID = fFonts.count() - 1; |
| 220 |
| 221 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(filename.c_str()
)); |
| 222 if (stream.get() != NULL) { |
| 223 bool isFixedWidth; |
| 224 SkString name; |
| 225 fontRec.fIsValid = find_name_and_attributes(stream.get(), &name, |
| 226 &fontRec.fStyle, &is
FixedWidth); |
| 227 } else { |
| 228 if (!fontRec.fIsFallbackFont) { |
| 229 SkDebugf("---- failed to open <%s> as a font\n", filename.c_
str()); |
| 230 } |
| 231 } |
| 232 |
| 233 if (fontRec.fIsValid) { |
| 234 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s", |
| 235 i, fFonts.count() - 1, fontRec.fIsFallbackFont, filen
ame.c_str())); |
| 236 } else { |
| 237 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s (INVAL
ID)", |
| 238 i, fFonts.count() - 1, fontRec.fIsFallbackFont, filen
ame.c_str())); |
| 239 continue; |
| 240 } |
| 241 |
| 242 // create a familyRec now that we know that at least one font in |
| 243 // the family is valid |
| 244 if (familyRec == NULL) { |
| 245 familyRec = &fFontFamilies.push_back(); |
| 246 familyRecID = fFontFamilies.count() - 1; |
| 247 } |
| 248 |
| 249 // add this font to the current familyRec |
| 250 if (INVALID_FONT_REC_ID != familyRec->fFontRecID[fontRec.fStyle]) { |
| 251 DEBUG_FONT(("Overwriting familyRec for style[%d] old,new:(%d,%d)
", |
| 252 fontRec.fStyle, familyRec->fFontRecID[fontRec.fStyle
], |
| 253 fontRecID)); |
| 254 } |
| 255 familyRec->fFontRecID[fontRec.fStyle] = fontRecID; |
| 256 |
| 257 // if this is a fallback font then add it to the appropriate fallbac
k chains |
| 258 if (fontRec.fIsFallbackFont) { |
| 259 addFallbackFont(fontRecID); |
| 260 } |
| 261 |
| 262 // add the fallback file name to the name dictionary. This is neede
d |
| 263 // by getFallbackFamilyNameForChar() so that fallback families can b
e |
| 264 // requested by the filenames of the fonts they contain. |
| 265 if (family->fIsFallbackFont && familyRec) { |
| 266 insert_into_name_dict(fFamilyNameDict, fontRec.fFileName.c_str()
, familyRecID); |
| 267 } |
| 268 } |
| 269 |
| 270 // add the names that map to this family to the dictionary for easy look
up |
| 271 if (familyRec && !family->fIsFallbackFont) { |
| 272 SkTDArray<const char*> names = family->fNames; |
| 273 if (names.isEmpty()) { |
| 274 SkDEBUGFAIL("ERROR: non-fallback font with no name"); |
| 275 continue; |
| 276 } |
| 277 |
| 278 for (int i = 0; i < names.count(); i++) { |
| 279 insert_into_name_dict(fFamilyNameDict, names[i], familyRecID); |
| 280 } |
| 281 } |
| 282 |
| 283 } |
| 284 |
| 285 DEBUG_FONT(("---- We have %d system fonts", fFonts.count())); |
| 286 |
| 287 if (fFontFamilies.count() > 0) { |
| 288 fDefaultFamilyRecID = 0; |
| 289 } |
| 290 |
| 291 // scans the default fallback font chain, adding every entry to every other |
| 292 // fallback font chain to which it does not belong. this results in every |
| 293 // language-specific fallback font chain having all of its fallback fonts at |
| 294 // the front of the chain, and everything else at the end. |
| 295 FallbackFontList* fallbackList; |
| 296 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict); |
| 297 const char* fallbackLang = iter.next(&fallbackList); |
| 298 while(fallbackLang != NULL) { |
| 299 for (int i = 0; i < fDefaultFallbackList.count(); i++) { |
| 300 FontRecID fontRecID = fDefaultFallbackList[i]; |
| 301 const SkString& fontLang = fFonts[fontRecID].fPaintOptions.getLangua
ge().getTag(); |
| 302 if (strcmp(fallbackLang, fontLang.c_str()) != 0) { |
| 303 fallbackList->push(fontRecID); |
| 304 } |
| 305 } |
| 306 // move to the next fallback list in the dictionary |
| 307 fallbackLang = iter.next(&fallbackList); |
| 308 } |
| 309 } |
| 310 |
| 311 SkFontConfigInterfaceAndroid::~SkFontConfigInterfaceAndroid() { |
| 312 // iterate through and cleanup fFallbackFontDict |
| 313 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict); |
| 314 FallbackFontList* fallbackList; |
| 315 while(iter.next(&fallbackList) != NULL) { |
| 316 SkDELETE(fallbackList); |
| 317 } |
| 318 } |
| 319 |
| 320 void SkFontConfigInterfaceAndroid::addFallbackFont(FontRecID fontRecID) { |
| 321 SkASSERT(fontRecID < fFonts.count()); |
| 322 const FontRec& fontRec = fFonts[fontRecID]; |
| 323 SkASSERT(fontRec.fIsFallbackFont); |
| 324 |
| 325 // add to the default fallback list |
| 326 fDefaultFallbackList.push(fontRecID); |
| 327 |
| 328 // stop here if it is the default language tag |
| 329 const SkString& languageTag = fontRec.fPaintOptions.getLanguage().getTag(); |
| 330 if (languageTag.isEmpty()) { |
| 331 return; |
| 332 } |
| 333 |
| 334 // add to the appropriate language's custom fallback list |
| 335 FallbackFontList* customList = NULL; |
| 336 if (!fFallbackFontDict.find(languageTag.c_str(), &customList)) { |
| 337 DEBUG_FONT(("---- Created fallback list for \"%s\"", languageTag.c_str(
))); |
| 338 customList = SkNEW(FallbackFontList); |
| 339 fFallbackFontDict.set(languageTag.c_str(), customList); |
| 340 } |
| 341 SkASSERT(customList != NULL); |
| 342 customList->push(fontRecID); |
| 343 } |
| 344 |
| 345 |
| 346 static FontRecID find_best_style(const FamilyRec& family, SkTypeface::Style styl
e) { |
| 347 |
| 348 const FontRecID* fontRecIDs = family.fFontRecID; |
| 349 |
| 350 if (fontRecIDs[style] != INVALID_FONT_REC_ID) { // exact match |
| 351 return fontRecIDs[style]; |
| 352 } |
| 353 // look for a matching bold |
| 354 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic); |
| 355 if (fontRecIDs[style] != INVALID_FONT_REC_ID) { |
| 356 return fontRecIDs[style]; |
| 357 } |
| 358 // look for the plain |
| 359 if (fontRecIDs[SkTypeface::kNormal] != INVALID_FONT_REC_ID) { |
| 360 return fontRecIDs[SkTypeface::kNormal]; |
| 361 } |
| 362 // look for anything |
| 363 for (int i = 0; i < FamilyRec::FONT_STYLE_COUNT; i++) { |
| 364 if (fontRecIDs[i] != INVALID_FONT_REC_ID) { |
| 365 return fontRecIDs[i]; |
| 366 } |
| 367 } |
| 368 // should never get here, since the fontRecID list should not be empty |
| 369 SkDEBUGFAIL("No valid fonts exist for this family"); |
| 370 return -1; |
| 371 } |
| 372 |
| 373 bool SkFontConfigInterfaceAndroid::matchFamilyName(const char familyName[], |
| 374 SkTypeface::Style style, |
| 375 FontIdentity* outFontIdentifi
er, |
| 376 SkString* outFamilyName, |
| 377 SkTypeface::Style* outStyle)
SK_OVERRIDE { |
| 378 // clip to legal style bits |
| 379 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); |
| 380 |
| 381 bool exactNameMatch = false; |
| 382 |
| 383 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID; |
| 384 if (NULL != familyName) { |
| 385 if (fFamilyNameDict.find(familyName, &familyRecID)) { |
| 386 exactNameMatch = true; |
| 387 } |
| 388 } else { |
| 389 familyRecID = fDefaultFamilyRecID; |
| 390 |
| 391 } |
| 392 |
| 393 if (INVALID_FAMILY_REC_ID == familyRecID) { |
| 394 //TODO this ensures that we always return something |
| 395 familyRecID = fDefaultFamilyRecID; |
| 396 //return false; |
| 397 } |
| 398 |
| 399 FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], style); |
| 400 FontRec& fontRec = fFonts[fontRecID]; |
| 401 |
| 402 if (NULL != outFontIdentifier) { |
| 403 outFontIdentifier->fID = fontRecID; |
| 404 outFontIdentifier->fTTCIndex = 0; |
| 405 outFontIdentifier->fString.set(fontRec.fFileName); |
| 406 // outFontIdentifier->fStyle = fontRec.fStyle; |
| 407 } |
| 408 |
| 409 if (NULL != outFamilyName) { |
| 410 if (exactNameMatch) { |
| 411 outFamilyName->set(familyName); |
| 412 } else { |
| 413 // find familyName from list of names |
| 414 const char* familyName = NULL; |
| 415 bool found = fFamilyNameDict.findKey(familyRecID, &familyName); |
| 416 SkASSERT(found && familyName); |
| 417 outFamilyName->set(familyName); |
| 418 } |
| 419 } |
| 420 |
| 421 if (NULL != outStyle) { |
| 422 *outStyle = fontRec.fStyle; |
| 423 } |
| 424 |
| 425 return true; |
| 426 } |
| 427 |
| 428 SkStream* SkFontConfigInterfaceAndroid::openStream(const FontIdentity& identity)
SK_OVERRIDE { |
| 429 return SkStream::NewFromFile(identity.fString.c_str()); |
| 430 } |
| 431 |
| 432 SkDataTable* SkFontConfigInterfaceAndroid::getFamilyNames() SK_OVERRIDE { |
| 433 SkTDArray<const char*> names; |
| 434 SkTDArray<size_t> sizes; |
| 435 |
| 436 SkTDict<FamilyRecID>::Iter iter(fFamilyNameDict); |
| 437 const char* familyName = iter.next(NULL); |
| 438 while(familyName != NULL) { |
| 439 *names.append() = familyName; |
| 440 *sizes.append() = strlen(familyName) + 1; |
| 441 |
| 442 // move to the next familyName in the dictionary |
| 443 familyName = iter.next(NULL); |
| 444 } |
| 445 |
| 446 return SkDataTable::NewCopyArrays((const void*const*)names.begin(), |
| 447 sizes.begin(), names.count()); |
| 448 } |
| 449 |
| 450 bool SkFontConfigInterfaceAndroid::matchFamilySet(const char inFamilyName[], |
| 451 SkString* outFamilyName, |
| 452 SkTArray<FontIdentity>*) SK_OV
ERRIDE { |
| 453 return false; |
| 454 } |
| 455 |
| 456 static SkTypeface* get_typeface_for_rec(FontRec& fontRec) { |
| 457 SkTypeface* face = fontRec.fTypeface.get(); |
| 458 if (!face) { |
| 459 // TODO look for it in the typeface cache |
| 460 |
| 461 // if it is not in the cache then create it |
| 462 face = SkTypeface::CreateFromFile(fontRec.fFileName.c_str()); |
| 463 |
| 464 // store the result for subsequent lookups |
| 465 fontRec.fTypeface = face; |
| 466 } |
| 467 SkASSERT(face); |
| 468 return face; |
| 469 } |
| 470 |
| 471 bool SkFontConfigInterfaceAndroid::getFallbackFamilyNameForChar(SkUnichar uni, S
kString* name) { |
| 472 for (int i = 0; i < fDefaultFallbackList.count(); i++) { |
| 473 FontRecID fontRecID = fDefaultFallbackList[i]; |
| 474 SkTypeface* face = get_typeface_for_rec(fFonts[fontRecID]); |
| 475 |
| 476 SkPaint paint; |
| 477 paint.setTypeface(face); |
| 478 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); |
| 479 |
| 480 uint16_t glyphID; |
| 481 paint.textToGlyphs(&uni, sizeof(uni), &glyphID); |
| 482 if (glyphID != 0) { |
| 483 name->set(fFonts[fontRecID].fFileName); |
| 484 return true; |
| 485 } |
| 486 } |
| 487 return false; |
| 488 } |
| 489 |
| 490 SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForChar(SkUnichar uni, |
| 491 SkTypeface::Style s
tyle, |
| 492 SkPaintOptionsAndro
id::FontVariant fontVariant) { |
| 493 FontRecID fontRecID = find_best_style(fFontFamilies[fDefaultFamilyRecID], st
yle); |
| 494 SkTypeface* face = get_typeface_for_rec(fFonts[fontRecID]); |
| 495 |
| 496 SkPaintOptionsAndroid paintOptions; |
| 497 paintOptions.setFontVariant(fontVariant); |
| 498 paintOptions.setUseFontFallbacks(true); |
| 499 |
| 500 SkPaint paint; |
| 501 paint.setTypeface(face); |
| 502 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); |
| 503 paint.setPaintOptionsAndroid(paintOptions); |
| 504 |
| 505 SkAutoGlyphCache autoCache(paint, NULL, NULL); |
| 506 SkGlyphCache* cache = autoCache.getCache(); |
| 507 |
| 508 SkScalerContext* ctx = cache->getScalerContext(); |
| 509 if (ctx) { |
| 510 SkFontID fontID = ctx->findTypefaceIdForChar(uni); |
| 511 return SkTypefaceCache::FindByID(fontID); |
| 512 } |
| 513 return NULL; |
| 514 } |
| 515 |
| 516 FallbackFontList* SkFontConfigInterfaceAndroid::findFallbackFontList(const SkLan
guage& lang) { |
| 517 const SkString& langTag = lang.getTag(); |
| 518 if (langTag.isEmpty()) { |
| 519 return &fDefaultFallbackList; |
| 520 } |
| 521 |
| 522 FallbackFontList* fallbackFontList; |
| 523 if (fFallbackFontDict.find(langTag.c_str(), langTag.size(), &fallbackFontLis
t)) { |
| 524 return fallbackFontList; |
| 525 } |
| 526 |
| 527 // attempt a recursive fuzzy match |
| 528 // TODO we could cache the intermediate parent so that we don't have to do |
| 529 // the recursion again. |
| 530 SkLanguage parent = lang.getParent(); |
| 531 return findFallbackFontList(parent); |
| 532 } |
| 533 |
| 534 SkTypeface* SkFontConfigInterfaceAndroid::nextLogicalTypeface(SkFontID currFontI
D, |
| 535 SkFontID origFontI
D, |
| 536 const SkPaintOptio
nsAndroid& opts) { |
| 537 // Skia does not support font fallback by default. This enables clients such |
| 538 // as WebKit to customize their font selection. In any case, clients can use |
| 539 // GetFallbackFamilyNameForChar() to get the fallback font for individual |
| 540 // characters. |
| 541 if (!opts.isUsingFontFallbacks()) { |
| 542 return NULL; |
| 543 } |
| 544 |
| 545 const SkTypeface* origTypeface = SkTypefaceCache::FindByID(origFontID); |
| 546 const SkTypeface* currTypeface = SkTypefaceCache::FindByID(currFontID); |
| 547 |
| 548 FallbackFontList* currentFallbackList = findFallbackFontList(opts.getLanguag
e()); |
| 549 SkASSERT(currentFallbackList); |
| 550 |
| 551 SkASSERT(origTypeface != 0); |
| 552 SkASSERT(currTypeface != 0); |
| 553 |
| 554 // we must convert currTypeface into a FontRecID |
| 555 FontRecID currFontRecID = ((FontConfigTypeface*)currTypeface)->getIdentity()
.fID; |
| 556 |
| 557 // TODO lookup the index next font in the chain |
| 558 int currFallbackFontIndex = currentFallbackList->find(currFontRecID); |
| 559 int nextFallbackFontIndex = currFallbackFontIndex + 1; |
| 560 SkASSERT(-1 == nextFallbackFontIndex); |
| 561 |
| 562 if(nextFallbackFontIndex >= currentFallbackList->count() && -1 == currFallba
ckFontIndex) { |
| 563 return NULL; |
| 564 } |
| 565 |
| 566 // If a rec object is set to prefer "kDefault_Variant" it means they have no
preference |
| 567 // In this case, we set the value to "kCompact_Variant" |
| 568 SkPaintOptionsAndroid::FontVariant variant = opts.getFontVariant(); |
| 569 if (variant == SkPaintOptionsAndroid::kDefault_Variant) { |
| 570 variant = SkPaintOptionsAndroid::kCompact_Variant; |
| 571 } |
| 572 |
| 573 int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | variant
; |
| 574 |
| 575 SkTypeface* nextLogicalTypeface = 0; |
| 576 while (nextFallbackFontIndex < currentFallbackList->count()) { |
| 577 FontRecID fontRecID = currentFallbackList->getAt(nextFallbackFontIndex); |
| 578 if (fFonts[fontRecID].fPaintOptions.getFontVariant() & acceptedVariants)
{ |
| 579 nextLogicalTypeface = get_typeface_for_rec(fFonts[fontRecID]); |
| 580 break; |
| 581 } |
| 582 nextFallbackFontIndex++; |
| 583 } |
| 584 |
| 585 DEBUG_FONT(("---- nextLogicalFont: currFontID=%d, origFontID=%d, currRecID=%
d, " |
| 586 "lang=%s, variant=%d, nextFallbackIndex=%d => nextLogicalTypefac
e=%d", |
| 587 currFontID, origFontID, currFontRecID, opts.getLanguage().getTag
().c_str(), |
| 588 variant, nextFallbackFontIndex, |
| 589 (nextLogicalTypeface) ? nextLogicalTypeface->uniqueID() : 0)); |
| 590 return SkSafeRef(nextLogicalTypeface); |
| 591 } |
| 592 |
| 593 /////////////////////////////////////////////////////////////////////////////// |
| 594 |
| 595 bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name) { |
| 596 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface(); |
| 597 return fontConfig->getFallbackFamilyNameForChar(uni, name); |
| 598 } |
| 599 |
| 600 void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf, |
| 601 const char* fontsdir) { |
| 602 gTestMainConfigFile = mainconf; |
| 603 gTestFallbackConfigFile = fallbackconf; |
| 604 gTestFontFilePrefix = fontsdir; |
| 605 SkASSERT(gTestMainConfigFile); |
| 606 SkASSERT(gTestFallbackConfigFile); |
| 607 SkASSERT(gTestFontFilePrefix); |
| 608 SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s", |
| 609 gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix)
); |
| 610 } |
| 611 |
| 612 SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontI
D, |
| 613 const SkPaintOptionsAndroid& options) { |
| 614 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface(); |
| 615 return fontConfig->nextLogicalTypeface(currFontID, origFontID, options); |
| 616 |
| 617 } |
| 618 |
| 619 /////////////////////////////////////////////////////////////////////////////// |
| 620 |
| 621 SkFontMgr* SkFontMgr::Factory() { |
| 622 return NULL; |
| 623 } |
OLD | NEW |