1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/ports/SkFontConfigInterface_android.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,915 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2013 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 +#include "SkFontConfigInterface.h" 1.13 +#include "SkTypeface_android.h" 1.14 + 1.15 +#include "SkFontConfigParser_android.h" 1.16 +#include "SkFontConfigTypeface.h" 1.17 +#include "SkFontMgr.h" 1.18 +#include "SkGlyphCache.h" 1.19 +#include "SkPaint.h" 1.20 +#include "SkString.h" 1.21 +#include "SkStream.h" 1.22 +#include "SkThread.h" 1.23 +#include "SkTypefaceCache.h" 1.24 +#include "SkTArray.h" 1.25 +#include "SkTDict.h" 1.26 +#include "SkTSearch.h" 1.27 + 1.28 +#include <stdio.h> 1.29 +#include <string.h> 1.30 + 1.31 +#ifndef SK_DEBUG_FONTS 1.32 + #define SK_DEBUG_FONTS 0 1.33 +#endif 1.34 + 1.35 +#if SK_DEBUG_FONTS 1.36 + #define DEBUG_FONT(args) SkDebugf args 1.37 +#else 1.38 + #define DEBUG_FONT(args) 1.39 +#endif 1.40 + 1.41 +/////////////////////////////////////////////////////////////////////////////// 1.42 + 1.43 +// For test only. 1.44 +static const char* gTestMainConfigFile = NULL; 1.45 +static const char* gTestFallbackConfigFile = NULL; 1.46 +static const char* gTestFontFilePrefix = NULL; 1.47 + 1.48 +/////////////////////////////////////////////////////////////////////////////// 1.49 + 1.50 +typedef int32_t FontRecID; 1.51 +#define INVALID_FONT_REC_ID -1 1.52 + 1.53 +typedef int32_t FamilyRecID; 1.54 +#define INVALID_FAMILY_REC_ID -1 1.55 + 1.56 +// used to record our notion of the pre-existing fonts 1.57 +struct FontRec { 1.58 + SkRefPtr<SkTypeface> fTypeface; 1.59 + SkString fFileName; 1.60 + SkTypeface::Style fStyle; 1.61 + bool fIsValid; 1.62 + FamilyRecID fFamilyRecID; 1.63 +}; 1.64 + 1.65 +struct FamilyRec { 1.66 + FamilyRec() { 1.67 + memset(fFontRecID, INVALID_FONT_REC_ID, sizeof(fFontRecID)); 1.68 + } 1.69 + 1.70 + static const int FONT_STYLE_COUNT = 4; 1.71 + FontRecID fFontRecID[FONT_STYLE_COUNT]; 1.72 + bool fIsFallbackFont; 1.73 + SkString fFallbackName; 1.74 + SkPaintOptionsAndroid fPaintOptions; 1.75 +}; 1.76 + 1.77 + 1.78 +typedef SkTDArray<FamilyRecID> FallbackFontList; 1.79 + 1.80 +class SkFontConfigInterfaceAndroid : public SkFontConfigInterface { 1.81 +public: 1.82 + SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies); 1.83 + virtual ~SkFontConfigInterfaceAndroid(); 1.84 + 1.85 + virtual bool matchFamilyName(const char familyName[], 1.86 + SkTypeface::Style requested, 1.87 + FontIdentity* outFontIdentifier, 1.88 + SkString* outFamilyName, 1.89 + SkTypeface::Style* outStyle) SK_OVERRIDE; 1.90 + virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE; 1.91 + 1.92 + // new APIs 1.93 + virtual SkDataTable* getFamilyNames() SK_OVERRIDE; 1.94 + virtual bool matchFamilySet(const char inFamilyName[], 1.95 + SkString* outFamilyName, 1.96 + SkTArray<FontIdentity>*) SK_OVERRIDE; 1.97 + 1.98 + /** 1.99 + * Get the family name of the font in the default fallback font list that 1.100 + * contains the specified chararacter. if no font is found, returns false. 1.101 + */ 1.102 + bool getFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* name); 1.103 + /** 1.104 + * 1.105 + */ 1.106 + SkTypeface* getTypefaceForChar(SkUnichar uni, SkTypeface::Style style, 1.107 + SkPaintOptionsAndroid::FontVariant fontVariant); 1.108 + SkTypeface* nextLogicalTypeface(SkFontID currFontID, SkFontID origFontID, 1.109 + const SkPaintOptionsAndroid& options); 1.110 + SkTypeface* getTypefaceForGlyphID(uint16_t glyphID, const SkTypeface* origTypeface, 1.111 + const SkPaintOptionsAndroid& options, 1.112 + int* lowerBounds, int* upperBounds); 1.113 + 1.114 +private: 1.115 + void addFallbackFamily(FamilyRecID fontRecID); 1.116 + SkTypeface* getTypefaceForFontRec(FontRecID fontRecID); 1.117 + FallbackFontList* getCurrentLocaleFallbackFontList(); 1.118 + FallbackFontList* findFallbackFontList(const SkLanguage& lang, bool isOriginal = true); 1.119 + 1.120 + SkTArray<FontRec> fFonts; 1.121 + SkTArray<FamilyRec> fFontFamilies; 1.122 + SkTDict<FamilyRecID> fFamilyNameDict; 1.123 + FamilyRecID fDefaultFamilyRecID; 1.124 + 1.125 + // (SkLanguage)<->(fallback chain index) translation 1.126 + SkTDict<FallbackFontList*> fFallbackFontDict; 1.127 + SkTDict<FallbackFontList*> fFallbackFontAliasDict; 1.128 + FallbackFontList fDefaultFallbackList; 1.129 + 1.130 + // fallback info for current locale 1.131 + SkString fCachedLocale; 1.132 + FallbackFontList* fLocaleFallbackFontList; 1.133 +}; 1.134 + 1.135 +/////////////////////////////////////////////////////////////////////////////// 1.136 + 1.137 +static SkFontConfigInterfaceAndroid* getSingletonInterface() { 1.138 + SK_DECLARE_STATIC_MUTEX(gMutex); 1.139 + static SkFontConfigInterfaceAndroid* gFontConfigInterface; 1.140 + 1.141 + SkAutoMutexAcquire ac(gMutex); 1.142 + if (NULL == gFontConfigInterface) { 1.143 + // load info from a configuration file that we can use to populate the 1.144 + // system/fallback font structures 1.145 + SkTDArray<FontFamily*> fontFamilies; 1.146 + if (!gTestMainConfigFile) { 1.147 + SkFontConfigParser::GetFontFamilies(fontFamilies); 1.148 + } else { 1.149 + SkFontConfigParser::GetTestFontFamilies(fontFamilies, gTestMainConfigFile, 1.150 + gTestFallbackConfigFile); 1.151 + } 1.152 + 1.153 + gFontConfigInterface = new SkFontConfigInterfaceAndroid(fontFamilies); 1.154 + 1.155 + // cleanup the data we received from the parser 1.156 + fontFamilies.deleteAll(); 1.157 + } 1.158 + return gFontConfigInterface; 1.159 +} 1.160 + 1.161 +SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() { 1.162 + return getSingletonInterface(); 1.163 +} 1.164 + 1.165 +/////////////////////////////////////////////////////////////////////////////// 1.166 + 1.167 +static bool has_font(const SkTArray<FontRec>& array, const SkString& filename) { 1.168 + for (int i = 0; i < array.count(); i++) { 1.169 + if (array[i].fFileName == filename) { 1.170 + return true; 1.171 + } 1.172 + } 1.173 + return false; 1.174 +} 1.175 + 1.176 +#ifndef SK_FONT_FILE_PREFIX 1.177 + #define SK_FONT_FILE_PREFIX "/fonts/" 1.178 +#endif 1.179 + 1.180 +static void get_path_for_sys_fonts(SkString* full, const char name[]) { 1.181 + if (gTestFontFilePrefix) { 1.182 + full->set(gTestFontFilePrefix); 1.183 + } else { 1.184 + full->set(getenv("ANDROID_ROOT")); 1.185 + full->append(SK_FONT_FILE_PREFIX); 1.186 + } 1.187 + full->append(name); 1.188 +} 1.189 + 1.190 +static void insert_into_name_dict(SkTDict<FamilyRecID>& familyNameDict, 1.191 + const char* name, FamilyRecID familyRecID) { 1.192 + SkAutoAsciiToLC tolc(name); 1.193 + if (familyNameDict.find(tolc.lc())) { 1.194 + SkDebugf("---- system font attempting to use a the same name [%s] for" 1.195 + "multiple families. skipping subsequent occurrences", tolc.lc()); 1.196 + } else { 1.197 + familyNameDict.set(tolc.lc(), familyRecID); 1.198 + } 1.199 +} 1.200 + 1.201 +// Defined in SkFontHost_FreeType.cpp 1.202 +bool find_name_and_attributes(SkStream* stream, SkString* name, 1.203 + SkTypeface::Style* style, bool* isFixedWidth); 1.204 + 1.205 +/////////////////////////////////////////////////////////////////////////////// 1.206 + 1.207 +SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies) : 1.208 + fFonts(fontFamilies.count()), 1.209 + fFontFamilies(fontFamilies.count() / FamilyRec::FONT_STYLE_COUNT), 1.210 + fFamilyNameDict(1024), 1.211 + fDefaultFamilyRecID(INVALID_FAMILY_REC_ID), 1.212 + fFallbackFontDict(128), 1.213 + fFallbackFontAliasDict(128), 1.214 + fLocaleFallbackFontList(NULL) { 1.215 + 1.216 + for (int i = 0; i < fontFamilies.count(); ++i) { 1.217 + FontFamily* family = fontFamilies[i]; 1.218 + 1.219 + // defer initializing the familyRec until we can be sure that at least 1.220 + // one of it's children contains a valid font file 1.221 + FamilyRec* familyRec = NULL; 1.222 + FamilyRecID familyRecID = INVALID_FAMILY_REC_ID; 1.223 + 1.224 + for (int j = 0; j < family->fFontFiles.count(); ++j) { 1.225 + SkString filename; 1.226 + get_path_for_sys_fonts(&filename, family->fFontFiles[j]->fFileName); 1.227 + 1.228 + if (has_font(fFonts, filename)) { 1.229 + SkDebugf("---- system font and fallback font files specify a duplicate " 1.230 + "font %s, skipping the second occurrence", filename.c_str()); 1.231 + continue; 1.232 + } 1.233 + 1.234 + FontRec& fontRec = fFonts.push_back(); 1.235 + fontRec.fFileName = filename; 1.236 + fontRec.fStyle = SkTypeface::kNormal; 1.237 + fontRec.fIsValid = false; 1.238 + fontRec.fFamilyRecID = familyRecID; 1.239 + 1.240 + const FontRecID fontRecID = fFonts.count() - 1; 1.241 + 1.242 + SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(filename.c_str())); 1.243 + if (stream.get() != NULL) { 1.244 + bool isFixedWidth; 1.245 + SkString name; 1.246 + fontRec.fIsValid = find_name_and_attributes(stream.get(), &name, 1.247 + &fontRec.fStyle, &isFixedWidth); 1.248 + } else { 1.249 + if (!family->fIsFallbackFont) { 1.250 + SkDebugf("---- failed to open <%s> as a font\n", filename.c_str()); 1.251 + } 1.252 + } 1.253 + 1.254 + if (fontRec.fIsValid) { 1.255 + DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s", 1.256 + i, fFonts.count() - 1, family->fIsFallbackFont, filename.c_str())); 1.257 + } else { 1.258 + DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s (INVALID)", 1.259 + i, fFonts.count() - 1, family->fIsFallbackFont, filename.c_str())); 1.260 + continue; 1.261 + } 1.262 + 1.263 + // create a familyRec now that we know that at least one font in 1.264 + // the family is valid 1.265 + if (familyRec == NULL) { 1.266 + familyRec = &fFontFamilies.push_back(); 1.267 + familyRecID = fFontFamilies.count() - 1; 1.268 + fontRec.fFamilyRecID = familyRecID; 1.269 + 1.270 + familyRec->fIsFallbackFont = family->fIsFallbackFont; 1.271 + familyRec->fPaintOptions = family->fFontFiles[j]->fPaintOptions; 1.272 + 1.273 + } else if (familyRec->fPaintOptions != family->fFontFiles[j]->fPaintOptions) { 1.274 + SkDebugf("Every font file within a family must have identical" 1.275 + "language and variant attributes"); 1.276 + sk_throw(); 1.277 + } 1.278 + 1.279 + // add this font to the current familyRec 1.280 + if (INVALID_FONT_REC_ID != familyRec->fFontRecID[fontRec.fStyle]) { 1.281 + DEBUG_FONT(("Overwriting familyRec for style[%d] old,new:(%d,%d)", 1.282 + fontRec.fStyle, familyRec->fFontRecID[fontRec.fStyle], 1.283 + fontRecID)); 1.284 + } 1.285 + familyRec->fFontRecID[fontRec.fStyle] = fontRecID; 1.286 + } 1.287 + 1.288 + if (familyRec) { 1.289 + if (familyRec->fIsFallbackFont) { 1.290 + // add the font to the appropriate fallback chains and also insert a 1.291 + // unique name into the familyNameDict for internal usage 1.292 + addFallbackFamily(familyRecID); 1.293 + } else { 1.294 + // add the names that map to this family to the dictionary for easy lookup 1.295 + const SkTDArray<const char*>& names = family->fNames; 1.296 + if (names.isEmpty()) { 1.297 + SkDEBUGFAIL("ERROR: non-fallback font with no name"); 1.298 + continue; 1.299 + } 1.300 + 1.301 + for (int i = 0; i < names.count(); i++) { 1.302 + insert_into_name_dict(fFamilyNameDict, names[i], familyRecID); 1.303 + } 1.304 + } 1.305 + } 1.306 + } 1.307 + 1.308 + DEBUG_FONT(("---- We have %d system fonts", fFonts.count())); 1.309 + 1.310 + if (fFontFamilies.count() > 0) { 1.311 + fDefaultFamilyRecID = 0; 1.312 + } 1.313 + 1.314 + // scans the default fallback font chain, adding every entry to every other 1.315 + // fallback font chain to which it does not belong. this results in every 1.316 + // language-specific fallback font chain having all of its fallback fonts at 1.317 + // the front of the chain, and everything else at the end. 1.318 + FallbackFontList* fallbackList; 1.319 + SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict); 1.320 + const char* fallbackLang = iter.next(&fallbackList); 1.321 + while(fallbackLang != NULL) { 1.322 + for (int i = 0; i < fDefaultFallbackList.count(); i++) { 1.323 + FamilyRecID familyRecID = fDefaultFallbackList[i]; 1.324 + const SkString& fontLang = fFontFamilies[familyRecID].fPaintOptions.getLanguage().getTag(); 1.325 + if (strcmp(fallbackLang, fontLang.c_str()) != 0) { 1.326 + fallbackList->push(familyRecID); 1.327 + } 1.328 + } 1.329 + // move to the next fallback list in the dictionary 1.330 + fallbackLang = iter.next(&fallbackList); 1.331 + } 1.332 +} 1.333 + 1.334 +SkFontConfigInterfaceAndroid::~SkFontConfigInterfaceAndroid() { 1.335 + // iterate through and cleanup fFallbackFontDict 1.336 + SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict); 1.337 + FallbackFontList* fallbackList; 1.338 + while(iter.next(&fallbackList) != NULL) { 1.339 + SkDELETE(fallbackList); 1.340 + } 1.341 +} 1.342 + 1.343 +void SkFontConfigInterfaceAndroid::addFallbackFamily(FamilyRecID familyRecID) { 1.344 + SkASSERT(familyRecID < fFontFamilies.count()); 1.345 + FamilyRec& familyRec = fFontFamilies[familyRecID]; 1.346 + SkASSERT(familyRec.fIsFallbackFont); 1.347 + 1.348 + // add the fallback family to the name dictionary. This is 1.349 + // needed by getFallbackFamilyNameForChar() so that fallback 1.350 + // families can be identified by a unique name. The unique 1.351 + // identifier that we've chosen is the familyID in hex (e.g. '0F##fallback'). 1.352 + familyRec.fFallbackName.printf("%.2x##fallback", familyRecID); 1.353 + insert_into_name_dict(fFamilyNameDict, familyRec.fFallbackName.c_str(), familyRecID); 1.354 + 1.355 + // add to the default fallback list 1.356 + fDefaultFallbackList.push(familyRecID); 1.357 + 1.358 + // stop here if it is the default language tag 1.359 + const SkString& languageTag = familyRec.fPaintOptions.getLanguage().getTag(); 1.360 + if (languageTag.isEmpty()) { 1.361 + return; 1.362 + } 1.363 + 1.364 + // add to the appropriate language's custom fallback list 1.365 + FallbackFontList* customList = NULL; 1.366 + if (!fFallbackFontDict.find(languageTag.c_str(), &customList)) { 1.367 + DEBUG_FONT(("---- Created fallback list for \"%s\"", languageTag.c_str())); 1.368 + customList = SkNEW(FallbackFontList); 1.369 + fFallbackFontDict.set(languageTag.c_str(), customList); 1.370 + } 1.371 + SkASSERT(customList != NULL); 1.372 + customList->push(familyRecID); 1.373 +} 1.374 + 1.375 + 1.376 +static FontRecID find_best_style(const FamilyRec& family, SkTypeface::Style style) { 1.377 + 1.378 + const FontRecID* fontRecIDs = family.fFontRecID; 1.379 + 1.380 + if (fontRecIDs[style] != INVALID_FONT_REC_ID) { // exact match 1.381 + return fontRecIDs[style]; 1.382 + } 1.383 + // look for a matching bold 1.384 + style = (SkTypeface::Style)(style ^ SkTypeface::kItalic); 1.385 + if (fontRecIDs[style] != INVALID_FONT_REC_ID) { 1.386 + return fontRecIDs[style]; 1.387 + } 1.388 + // look for the plain 1.389 + if (fontRecIDs[SkTypeface::kNormal] != INVALID_FONT_REC_ID) { 1.390 + return fontRecIDs[SkTypeface::kNormal]; 1.391 + } 1.392 + // look for anything 1.393 + for (int i = 0; i < FamilyRec::FONT_STYLE_COUNT; i++) { 1.394 + if (fontRecIDs[i] != INVALID_FONT_REC_ID) { 1.395 + return fontRecIDs[i]; 1.396 + } 1.397 + } 1.398 + // should never get here, since the fontRecID list should not be empty 1.399 + SkDEBUGFAIL("No valid fonts exist for this family"); 1.400 + return -1; 1.401 +} 1.402 + 1.403 +bool SkFontConfigInterfaceAndroid::matchFamilyName(const char familyName[], 1.404 + SkTypeface::Style style, 1.405 + FontIdentity* outFontIdentifier, 1.406 + SkString* outFamilyName, 1.407 + SkTypeface::Style* outStyle) { 1.408 + // clip to legal style bits 1.409 + style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); 1.410 + 1.411 + bool exactNameMatch = false; 1.412 + 1.413 + FamilyRecID familyRecID = INVALID_FAMILY_REC_ID; 1.414 + if (NULL != familyName) { 1.415 + SkAutoAsciiToLC tolc(familyName); 1.416 + if (fFamilyNameDict.find(tolc.lc(), &familyRecID)) { 1.417 + exactNameMatch = true; 1.418 + } 1.419 + } else { 1.420 + familyRecID = fDefaultFamilyRecID; 1.421 + 1.422 + } 1.423 + 1.424 + // If no matching family name is found then return false. This allows clients 1.425 + // to be able to search for other fonts instead of forcing them to use the 1.426 + // default font. 1.427 + if (INVALID_FAMILY_REC_ID == familyRecID) { 1.428 + return false; 1.429 + } 1.430 + 1.431 + FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], style); 1.432 + FontRec& fontRec = fFonts[fontRecID]; 1.433 + 1.434 + if (NULL != outFontIdentifier) { 1.435 + outFontIdentifier->fID = fontRecID; 1.436 + outFontIdentifier->fTTCIndex = 0; 1.437 + outFontIdentifier->fString.set(fontRec.fFileName); 1.438 +// outFontIdentifier->fStyle = fontRec.fStyle; 1.439 + } 1.440 + 1.441 + if (NULL != outFamilyName) { 1.442 + if (exactNameMatch) { 1.443 + outFamilyName->set(familyName); 1.444 + } else { 1.445 + // find familyName from list of names 1.446 + const char* familyName = NULL; 1.447 + SkAssertResult(fFamilyNameDict.findKey(familyRecID, &familyName)); 1.448 + SkASSERT(familyName); 1.449 + outFamilyName->set(familyName); 1.450 + } 1.451 + } 1.452 + 1.453 + if (NULL != outStyle) { 1.454 + *outStyle = fontRec.fStyle; 1.455 + } 1.456 + 1.457 + return true; 1.458 +} 1.459 + 1.460 +SkStream* SkFontConfigInterfaceAndroid::openStream(const FontIdentity& identity) { 1.461 + return SkStream::NewFromFile(identity.fString.c_str()); 1.462 +} 1.463 + 1.464 +SkDataTable* SkFontConfigInterfaceAndroid::getFamilyNames() { 1.465 + SkTDArray<const char*> names; 1.466 + SkTDArray<size_t> sizes; 1.467 + 1.468 + SkTDict<FamilyRecID>::Iter iter(fFamilyNameDict); 1.469 + const char* familyName = iter.next(NULL); 1.470 + while(familyName != NULL) { 1.471 + *names.append() = familyName; 1.472 + *sizes.append() = strlen(familyName) + 1; 1.473 + 1.474 + // move to the next familyName in the dictionary 1.475 + familyName = iter.next(NULL); 1.476 + } 1.477 + 1.478 + return SkDataTable::NewCopyArrays((const void*const*)names.begin(), 1.479 + sizes.begin(), names.count()); 1.480 +} 1.481 + 1.482 +bool SkFontConfigInterfaceAndroid::matchFamilySet(const char inFamilyName[], 1.483 + SkString* outFamilyName, 1.484 + SkTArray<FontIdentity>*) { 1.485 + return false; 1.486 +} 1.487 + 1.488 +static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) { 1.489 + const FontRecID* fontRecID = (const FontRecID*)ctx; 1.490 + FontRecID currFontRecID = ((FontConfigTypeface*)face)->getIdentity().fID; 1.491 + return currFontRecID == *fontRecID; 1.492 +} 1.493 + 1.494 +SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForFontRec(FontRecID fontRecID) { 1.495 + FontRec& fontRec = fFonts[fontRecID]; 1.496 + SkTypeface* face = fontRec.fTypeface.get(); 1.497 + if (!face) { 1.498 + // look for it in the typeface cache 1.499 + face = SkTypefaceCache::FindByProcAndRef(find_proc, &fontRecID); 1.500 + 1.501 + // if it is not in the cache then create it 1.502 + if (!face) { 1.503 + const char* familyName = NULL; 1.504 + SkAssertResult(fFamilyNameDict.findKey(fontRec.fFamilyRecID, &familyName)); 1.505 + SkASSERT(familyName); 1.506 + face = SkTypeface::CreateFromName(familyName, fontRec.fStyle); 1.507 + } 1.508 + 1.509 + // store the result for subsequent lookups 1.510 + fontRec.fTypeface = face; 1.511 + } 1.512 + SkASSERT(face); 1.513 + return face; 1.514 +} 1.515 + 1.516 +bool SkFontConfigInterfaceAndroid::getFallbackFamilyNameForChar(SkUnichar uni, 1.517 + const char* lang, 1.518 + SkString* name) { 1.519 + FallbackFontList* fallbackFontList = NULL; 1.520 + const SkString langTag(lang); 1.521 + if (langTag.isEmpty()) { 1.522 + fallbackFontList = this->getCurrentLocaleFallbackFontList(); 1.523 + } else { 1.524 + fallbackFontList = this->findFallbackFontList(langTag); 1.525 + } 1.526 + 1.527 + for (int i = 0; i < fallbackFontList->count(); i++) { 1.528 + FamilyRecID familyRecID = fallbackFontList->getAt(i); 1.529 + 1.530 + // if it is not one of the accepted variants then move to the next family 1.531 + int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | 1.532 + SkPaintOptionsAndroid::kElegant_Variant; 1.533 + if (!(fFontFamilies[familyRecID].fPaintOptions.getFontVariant() & acceptedVariants)) { 1.534 + continue; 1.535 + } 1.536 + 1.537 + FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], SkTypeface::kNormal); 1.538 + SkTypeface* face = this->getTypefaceForFontRec(fontRecID); 1.539 + 1.540 + SkPaint paint; 1.541 + paint.setTypeface(face); 1.542 + paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); 1.543 + 1.544 + uint16_t glyphID; 1.545 + paint.textToGlyphs(&uni, sizeof(uni), &glyphID); 1.546 + if (glyphID != 0) { 1.547 + name->set(fFontFamilies[familyRecID].fFallbackName); 1.548 + return true; 1.549 + } 1.550 + } 1.551 + return false; 1.552 +} 1.553 + 1.554 +SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForChar(SkUnichar uni, 1.555 + SkTypeface::Style style, 1.556 + SkPaintOptionsAndroid::FontVariant fontVariant) { 1.557 + FontRecID fontRecID = find_best_style(fFontFamilies[fDefaultFamilyRecID], style); 1.558 + SkTypeface* face = this->getTypefaceForFontRec(fontRecID); 1.559 + 1.560 + SkPaintOptionsAndroid paintOptions; 1.561 + paintOptions.setFontVariant(fontVariant); 1.562 + paintOptions.setUseFontFallbacks(true); 1.563 + 1.564 + SkPaint paint; 1.565 + paint.setTypeface(face); 1.566 + paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); 1.567 + paint.setPaintOptionsAndroid(paintOptions); 1.568 + 1.569 + SkAutoGlyphCache autoCache(paint, NULL, NULL); 1.570 + SkGlyphCache* cache = autoCache.getCache(); 1.571 + 1.572 + SkScalerContext* ctx = cache->getScalerContext(); 1.573 + if (ctx) { 1.574 + SkFontID fontID = ctx->findTypefaceIdForChar(uni); 1.575 + return SkTypefaceCache::FindByID(fontID); 1.576 + } 1.577 + return NULL; 1.578 +} 1.579 + 1.580 +FallbackFontList* SkFontConfigInterfaceAndroid::getCurrentLocaleFallbackFontList() { 1.581 + SkString locale = SkFontConfigParser::GetLocale(); 1.582 + if (NULL == fLocaleFallbackFontList || locale != fCachedLocale) { 1.583 + fCachedLocale = locale; 1.584 + fLocaleFallbackFontList = this->findFallbackFontList(locale); 1.585 + } 1.586 + return fLocaleFallbackFontList; 1.587 +} 1.588 + 1.589 +FallbackFontList* SkFontConfigInterfaceAndroid::findFallbackFontList(const SkLanguage& lang, 1.590 + bool isOriginal) { 1.591 + const SkString& langTag = lang.getTag(); 1.592 + if (langTag.isEmpty()) { 1.593 + return &fDefaultFallbackList; 1.594 + } 1.595 + 1.596 + FallbackFontList* fallbackFontList; 1.597 + if (fFallbackFontDict.find(langTag.c_str(), langTag.size(), &fallbackFontList) || 1.598 + fFallbackFontAliasDict.find(langTag.c_str(), langTag.size(), &fallbackFontList)) { 1.599 + return fallbackFontList; 1.600 + } 1.601 + 1.602 + // attempt a recursive fuzzy match 1.603 + SkLanguage parent = lang.getParent(); 1.604 + fallbackFontList = findFallbackFontList(parent, false); 1.605 + 1.606 + // cache the original lang so we don't have to do the recursion again. 1.607 + if (isOriginal) { 1.608 + DEBUG_FONT(("---- Created fallback list alias for \"%s\"", langTag.c_str())); 1.609 + fFallbackFontAliasDict.set(langTag.c_str(), fallbackFontList); 1.610 + } 1.611 + return fallbackFontList; 1.612 +} 1.613 + 1.614 +SkTypeface* SkFontConfigInterfaceAndroid::nextLogicalTypeface(SkFontID currFontID, 1.615 + SkFontID origFontID, 1.616 + const SkPaintOptionsAndroid& opts) { 1.617 + // Skia does not support font fallback by default. This enables clients such 1.618 + // as WebKit to customize their font selection. In any case, clients can use 1.619 + // GetFallbackFamilyNameForChar() to get the fallback font for individual 1.620 + // characters. 1.621 + if (!opts.isUsingFontFallbacks()) { 1.622 + return NULL; 1.623 + } 1.624 + 1.625 + FallbackFontList* currentFallbackList = findFallbackFontList(opts.getLanguage()); 1.626 + SkASSERT(currentFallbackList); 1.627 + 1.628 + SkTypeface::Style origStyle = SkTypeface::kNormal; 1.629 + const SkTypeface* origTypeface = SkTypefaceCache::FindByID(origFontID); 1.630 + if (NULL != origTypeface) { 1.631 + origStyle = origTypeface->style(); 1.632 + } 1.633 + 1.634 + // we must convert currTypeface into a FontRecID 1.635 + FontRecID currFontRecID = INVALID_FONT_REC_ID; 1.636 + const SkTypeface* currTypeface = SkTypefaceCache::FindByID(currFontID); 1.637 + // non-system fonts are not in the font cache so if we are asked to fallback 1.638 + // for a non-system font we will start at the front of the chain. 1.639 + if (NULL != currTypeface) { 1.640 + currFontRecID = ((FontConfigTypeface*)currTypeface)->getIdentity().fID; 1.641 + SkASSERT(INVALID_FONT_REC_ID != currFontRecID); 1.642 + } 1.643 + 1.644 + FamilyRecID currFamilyRecID = INVALID_FAMILY_REC_ID; 1.645 + if (INVALID_FONT_REC_ID != currFontRecID) { 1.646 + currFamilyRecID = fFonts[currFontRecID].fFamilyRecID; 1.647 + } 1.648 + 1.649 + // lookup the index next font in the chain 1.650 + int currFallbackFontIndex = currentFallbackList->find(currFamilyRecID); 1.651 + // We add 1 to the returned index for 2 reasons: (1) if find succeeds it moves 1.652 + // our index to the next entry in the list; (2) if find() fails it returns 1.653 + // -1 and incrementing it will set our starting index to 0 (the head of the list) 1.654 + int nextFallbackFontIndex = currFallbackFontIndex + 1; 1.655 + 1.656 + if(nextFallbackFontIndex >= currentFallbackList->count()) { 1.657 + return NULL; 1.658 + } 1.659 + 1.660 + // If a rec object is set to prefer "kDefault_Variant" it means they have no preference 1.661 + // In this case, we set the value to "kCompact_Variant" 1.662 + SkPaintOptionsAndroid::FontVariant variant = opts.getFontVariant(); 1.663 + if (variant == SkPaintOptionsAndroid::kDefault_Variant) { 1.664 + variant = SkPaintOptionsAndroid::kCompact_Variant; 1.665 + } 1.666 + 1.667 + int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | variant; 1.668 + 1.669 + SkTypeface* nextLogicalTypeface = 0; 1.670 + while (nextFallbackFontIndex < currentFallbackList->count()) { 1.671 + FamilyRecID familyRecID = currentFallbackList->getAt(nextFallbackFontIndex); 1.672 + if ((fFontFamilies[familyRecID].fPaintOptions.getFontVariant() & acceptedVariants) != 0) { 1.673 + FontRecID matchedFont = find_best_style(fFontFamilies[familyRecID], origStyle); 1.674 + nextLogicalTypeface = this->getTypefaceForFontRec(matchedFont); 1.675 + break; 1.676 + } 1.677 + nextFallbackFontIndex++; 1.678 + } 1.679 + 1.680 + DEBUG_FONT(("---- nextLogicalFont: currFontID=%d, origFontID=%d, currRecID=%d, " 1.681 + "lang=%s, variant=%d, nextFallbackIndex[%d,%d] => nextLogicalTypeface=%d", 1.682 + currFontID, origFontID, currFontRecID, opts.getLanguage().getTag().c_str(), 1.683 + variant, nextFallbackFontIndex, currentFallbackList->getAt(nextFallbackFontIndex), 1.684 + (nextLogicalTypeface) ? nextLogicalTypeface->uniqueID() : 0)); 1.685 + return SkSafeRef(nextLogicalTypeface); 1.686 +} 1.687 + 1.688 +SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForGlyphID(uint16_t glyphID, 1.689 + const SkTypeface* origTypeface, 1.690 + const SkPaintOptionsAndroid& opts, 1.691 + int* lBounds, int* uBounds) { 1.692 + // If we aren't using fallbacks then we shouldn't be calling this 1.693 + SkASSERT(opts.isUsingFontFallbacks()); 1.694 + SkASSERT(origTypeface); 1.695 + 1.696 + SkTypeface* currentTypeface = NULL; 1.697 + int lowerBounds = 0; //inclusive 1.698 + int upperBounds = origTypeface->countGlyphs(); //exclusive 1.699 + 1.700 + // check to see if the glyph is in the bounds of the origTypeface 1.701 + if (glyphID < upperBounds) { 1.702 + currentTypeface = const_cast<SkTypeface*>(origTypeface); 1.703 + } else { 1.704 + FallbackFontList* currentFallbackList = findFallbackFontList(opts.getLanguage()); 1.705 + SkASSERT(currentFallbackList); 1.706 + 1.707 + // If an object is set to prefer "kDefault_Variant" it means they have no preference 1.708 + // In this case, we set the value to "kCompact_Variant" 1.709 + SkPaintOptionsAndroid::FontVariant variant = opts.getFontVariant(); 1.710 + if (variant == SkPaintOptionsAndroid::kDefault_Variant) { 1.711 + variant = SkPaintOptionsAndroid::kCompact_Variant; 1.712 + } 1.713 + 1.714 + int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | variant; 1.715 + SkTypeface::Style origStyle = origTypeface->style(); 1.716 + 1.717 + for (int x = 0; x < currentFallbackList->count(); ++x) { 1.718 + const FamilyRecID familyRecID = currentFallbackList->getAt(x); 1.719 + const SkPaintOptionsAndroid& familyOptions = fFontFamilies[familyRecID].fPaintOptions; 1.720 + if ((familyOptions.getFontVariant() & acceptedVariants) != 0) { 1.721 + FontRecID matchedFont = find_best_style(fFontFamilies[familyRecID], origStyle); 1.722 + currentTypeface = this->getTypefaceForFontRec(matchedFont); 1.723 + lowerBounds = upperBounds; 1.724 + upperBounds += currentTypeface->countGlyphs(); 1.725 + if (glyphID < upperBounds) { 1.726 + break; 1.727 + } 1.728 + } 1.729 + } 1.730 + } 1.731 + 1.732 + if (NULL != currentTypeface) { 1.733 + if (lBounds) { 1.734 + *lBounds = lowerBounds; 1.735 + } 1.736 + if (uBounds) { 1.737 + *uBounds = upperBounds; 1.738 + } 1.739 + } 1.740 + return currentTypeface; 1.741 +} 1.742 + 1.743 +/////////////////////////////////////////////////////////////////////////////// 1.744 + 1.745 +bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name) { 1.746 + SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface(); 1.747 + return fontConfig->getFallbackFamilyNameForChar(uni, NULL, name); 1.748 +} 1.749 + 1.750 +bool SkGetFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* name) { 1.751 + SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface(); 1.752 + return fontConfig->getFallbackFamilyNameForChar(uni, lang, name); 1.753 +} 1.754 + 1.755 +void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf, 1.756 + const char* fontsdir) { 1.757 + gTestMainConfigFile = mainconf; 1.758 + gTestFallbackConfigFile = fallbackconf; 1.759 + gTestFontFilePrefix = fontsdir; 1.760 + SkASSERT(gTestMainConfigFile); 1.761 + SkASSERT(gTestFallbackConfigFile); 1.762 + SkASSERT(gTestFontFilePrefix); 1.763 + SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s", 1.764 + gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix)); 1.765 +} 1.766 + 1.767 +SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID, 1.768 + const SkPaintOptionsAndroid& options) { 1.769 + SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface(); 1.770 + return fontConfig->nextLogicalTypeface(currFontID, origFontID, options); 1.771 + 1.772 +} 1.773 + 1.774 +SkTypeface* SkGetTypefaceForGlyphID(uint16_t glyphID, const SkTypeface* origTypeface, 1.775 + const SkPaintOptionsAndroid& options, 1.776 + int* lowerBounds, int* upperBounds) { 1.777 + SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface(); 1.778 + return fontConfig->getTypefaceForGlyphID(glyphID, origTypeface, options, 1.779 + lowerBounds, upperBounds); 1.780 +} 1.781 + 1.782 +/////////////////////////////////////////////////////////////////////////////// 1.783 + 1.784 +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 1.785 + 1.786 +struct HB_UnicodeMapping { 1.787 + hb_script_t script; 1.788 + const SkUnichar unicode; 1.789 +}; 1.790 + 1.791 +/* 1.792 + * The following scripts are not complex fonts and we do not expect them to be parsed by this table 1.793 + * HB_SCRIPT_COMMON, 1.794 + * HB_SCRIPT_GREEK, 1.795 + * HB_SCRIPT_CYRILLIC, 1.796 + * HB_SCRIPT_HANGUL 1.797 + * HB_SCRIPT_INHERITED 1.798 + */ 1.799 + 1.800 +/* Harfbuzz (old) is missing a number of scripts in its table. For these, 1.801 + * we include a value which can never happen. We won't get complex script 1.802 + * shaping in these cases, but the library wouldn't know how to shape 1.803 + * them anyway. */ 1.804 +#define HB_Script_Unknown HB_ScriptCount 1.805 + 1.806 +static HB_UnicodeMapping HB_UnicodeMappingArray[] = { 1.807 + {HB_SCRIPT_ARMENIAN, 0x0531}, 1.808 + {HB_SCRIPT_HEBREW, 0x0591}, 1.809 + {HB_SCRIPT_ARABIC, 0x0600}, 1.810 + {HB_SCRIPT_SYRIAC, 0x0710}, 1.811 + {HB_SCRIPT_THAANA, 0x0780}, 1.812 + {HB_SCRIPT_NKO, 0x07C0}, 1.813 + {HB_SCRIPT_DEVANAGARI, 0x0901}, 1.814 + {HB_SCRIPT_BENGALI, 0x0981}, 1.815 + {HB_SCRIPT_GURMUKHI, 0x0A10}, 1.816 + {HB_SCRIPT_GUJARATI, 0x0A90}, 1.817 + {HB_SCRIPT_ORIYA, 0x0B10}, 1.818 + {HB_SCRIPT_TAMIL, 0x0B82}, 1.819 + {HB_SCRIPT_TELUGU, 0x0C10}, 1.820 + {HB_SCRIPT_KANNADA, 0x0C90}, 1.821 + {HB_SCRIPT_MALAYALAM, 0x0D10}, 1.822 + {HB_SCRIPT_SINHALA, 0x0D90}, 1.823 + {HB_SCRIPT_THAI, 0x0E01}, 1.824 + {HB_SCRIPT_LAO, 0x0E81}, 1.825 + {HB_SCRIPT_TIBETAN, 0x0F00}, 1.826 + {HB_SCRIPT_MYANMAR, 0x1000}, 1.827 + {HB_SCRIPT_GEORGIAN, 0x10A0}, 1.828 + {HB_SCRIPT_ETHIOPIC, 0x1200}, 1.829 + {HB_SCRIPT_CHEROKEE, 0x13A0}, 1.830 + {HB_SCRIPT_OGHAM, 0x1680}, 1.831 + {HB_SCRIPT_RUNIC, 0x16A0}, 1.832 + {HB_SCRIPT_KHMER, 0x1780}, 1.833 + {HB_SCRIPT_TAI_LE, 0x1950}, 1.834 + {HB_SCRIPT_NEW_TAI_LUE, 0x1980}, 1.835 + {HB_SCRIPT_TAI_THAM, 0x1A20}, 1.836 + {HB_SCRIPT_CHAM, 0xAA00}, 1.837 +}; 1.838 + 1.839 +// returns 0 for "Not Found" 1.840 +static SkUnichar getUnicodeFromHBScript(hb_script_t script) { 1.841 + SkUnichar unichar = 0; 1.842 + int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping); 1.843 + for (int i = 0; i < numSupportedFonts; i++) { 1.844 + if (script == HB_UnicodeMappingArray[i].script) { 1.845 + unichar = HB_UnicodeMappingArray[i].unicode; 1.846 + break; 1.847 + } 1.848 + } 1.849 + return unichar; 1.850 +} 1.851 + 1.852 +struct TypefaceLookupStruct { 1.853 + hb_script_t script; 1.854 + SkTypeface::Style style; 1.855 + SkPaintOptionsAndroid::FontVariant fontVariant; 1.856 + SkTypeface* typeface; 1.857 +}; 1.858 + 1.859 +SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex); // This is the mutex for gTypefaceTable 1.860 +static SkTDArray<TypefaceLookupStruct> gTypefaceTable; // This is protected by gTypefaceTableMutex 1.861 + 1.862 +static int typefaceLookupCompare(const TypefaceLookupStruct& first, 1.863 + const TypefaceLookupStruct& second) { 1.864 + if (first.script != second.script) { 1.865 + return (first.script > second.script) ? 1 : -1; 1.866 + } 1.867 + if (first.style != second.style) { 1.868 + return (first.style > second.style) ? 1 : -1; 1.869 + } 1.870 + if (first.fontVariant != second.fontVariant) { 1.871 + return (first.fontVariant > second.fontVariant) ? 1 : -1; 1.872 + } 1.873 + return 0; 1.874 +} 1.875 + 1.876 +SkTypeface* SkCreateTypefaceForScript(hb_script_t script, SkTypeface::Style style, 1.877 + SkPaintOptionsAndroid::FontVariant fontVariant) { 1.878 + SkAutoMutexAcquire ac(gTypefaceTableMutex); 1.879 + 1.880 + TypefaceLookupStruct key; 1.881 + key.script = script; 1.882 + key.style = style; 1.883 + key.fontVariant = fontVariant; 1.884 + 1.885 + int index = SkTSearch<TypefaceLookupStruct>( 1.886 + (const TypefaceLookupStruct*) gTypefaceTable.begin(), 1.887 + gTypefaceTable.count(), key, sizeof(TypefaceLookupStruct), 1.888 + typefaceLookupCompare); 1.889 + 1.890 + SkTypeface* retTypeface = NULL; 1.891 + if (index >= 0) { 1.892 + retTypeface = gTypefaceTable[index].typeface; 1.893 + } 1.894 + else { 1.895 + SkUnichar unichar = getUnicodeFromHBScript(script); 1.896 + if (!unichar) { 1.897 + return NULL; 1.898 + } 1.899 + 1.900 + SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface(); 1.901 + retTypeface = fontConfig->getTypefaceForChar(unichar, style, fontVariant); 1.902 + 1.903 + // add to the lookup table 1.904 + key.typeface = retTypeface; 1.905 + *gTypefaceTable.insert(~index) = key; 1.906 + } 1.907 + 1.908 + // we ref(), the caller is expected to unref when they are done 1.909 + return SkSafeRef(retTypeface); 1.910 +} 1.911 + 1.912 +#endif 1.913 + 1.914 +/////////////////////////////////////////////////////////////////////////////// 1.915 + 1.916 +SkFontMgr* SkFontMgr::Factory() { 1.917 + return NULL; 1.918 +}