diff options
Diffstat (limited to 'src/ports/SkFontHost_android.cpp')
-rw-r--r-- | src/ports/SkFontHost_android.cpp | 499 |
1 files changed, 385 insertions, 114 deletions
diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp index 2c58079..dddadd0 100644 --- a/src/ports/SkFontHost_android.cpp +++ b/src/ports/SkFontHost_android.cpp @@ -27,6 +27,12 @@ #include "FontHostConfiguration_android.h" #include <stdio.h> #include <string.h> +#include "SkGlyphCache.h" +#include "SkLanguage.h" +#include "SkTypeface_android.h" +#include "SkTArray.h" +#include "SkTDict.h" +#include "SkTSearch.h" //#define SkDEBUGF(args ) SkDebugf args @@ -73,9 +79,10 @@ static SkTypeface* createTypefaceLocked(const SkTypeface* familyFace, SkTypeface::Style style); static SkStream* openStreamLocked(uint32_t fontID); static size_t getFileNameLocked(SkFontID fontID, char path[], size_t length, int32_t* index); -static SkFontID nextLogicalFontLocked(SkFontID currFontID, SkFontID origFontID); +static SkFontID nextLogicalFontLocked(const SkScalerContext::Rec& rec); static SkTypeface* createTypefaceFromStreamLocked(SkStream* stream); + /////////////////////////////////////////////////////////////////////////////// struct FamilyRec; @@ -147,6 +154,12 @@ static SkTypeface* findBestFaceLocked(const FamilyRec* family, return NULL; } +static SkTypeface* FindBestFace(const FamilyRec* family, + SkTypeface::Style style) { + SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex); + return findBestFaceLocked(family, style); +} + static FamilyRec* findFamilyLocked(const SkTypeface* member) { FamilyRec* curr = gFamilyHead; while (curr != NULL) { @@ -177,6 +190,14 @@ static SkTypeface* findFromUniqueIDLocked(uint32_t uniqueID) { return NULL; } +/* Returns the matching typeface, or NULL. If a typeface is found, its refcnt + is not modified. + */ +static SkTypeface* FindFromUniqueID(uint32_t uniqueID) { + SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex); + return findFromUniqueIDLocked(uniqueID); +} + /* Remove reference to this face from its family. If the resulting family is empty (has no faces), return that family, otherwise return NULL */ @@ -394,26 +415,40 @@ private: // used to record our notion of the pre-existing fonts struct FontInitRec { - const char* fFileName; - const char* const* fNames; // null-terminated list + const char* fFileName; + const char* const* fNames; // null-terminated list + SkPaint::FontVariant fVariant; + SkLanguage fLanguage; +}; + +//used to record information about the fallback fonts +struct FallbackFontRec { + SkFontID fFontID; + SkPaint::FontVariant fVariant; +}; + +struct FallbackFontList { + FallbackFontList(const SkLanguage& language) : fLanguage(language) { } + SkTDArray<FallbackFontRec> fList; + SkLanguage fLanguage; }; // deliberately empty, but we use the address to identify fallback fonts static const char* gFBNames[] = { NULL }; - /* Fonts are grouped by family, with the first font in a family having the list of names (even if that list is empty), and the following members having null for the list. The names list must be NULL-terminated. */ -static SkTDArray<FontInitRec> gSystemFonts; -static SkTDArray<SkFontID> gFallbackFonts; +static SkTArray<FontInitRec> gSystemFonts; +static SkTDArray<FallbackFontList*> gFallbackFontLists; // these globals are assigned (once) by loadSystemFontsLocked() static FamilyRec* gDefaultFamily = NULL; static SkTypeface* gDefaultNormal = NULL; static char** gDefaultNames = NULL; +static FallbackFontList* getFallbackFontListLocked(const SkLanguage& lang); static void dumpGlobalsLocked() { SkDebugf("gDefaultNormal=%p id=%u refCnt=%d", gDefaultNormal, gDefaultNormal ? gDefaultNormal->uniqueID() : 0, @@ -434,8 +469,11 @@ static void dumpGlobalsLocked() { SkDebugf("gDefaultFamily=%p", gDefaultFamily); } - SkDebugf("gSystemFonts.count()=%d gFallbackFonts.count()=%d", - gSystemFonts.count(), gFallbackFonts.count()); + FallbackFontList* defaultFallbackList = + getFallbackFontListLocked(SkLanguage()); + SkASSERT(defaultFallbackList != NULL); + SkDebugf("gSystemFonts.count()=%d defaultFallbackList->fList.count()=%d", + gSystemFonts.count(), defaultFallbackList->fList.count()); for (int i = 0; i < gSystemFonts.count(); ++i) { SkDebugf("gSystemFonts[%d] fileName=%s", i, gSystemFonts[i].fFileName); @@ -480,9 +518,164 @@ static bool haveSystemFont(const char* filename) { return false; } +// (SkLanguage)<->(fallback chain index) translation +static const size_t kLangDictSize = 128; +static SkTDict<FallbackFontList*> gLangTagToFallbackFontList(kLangDictSize); +static bool gIsOKToUseFallbackFontListCache = false; + +// crawl fallback font lists by hand looking for a specific language +static FallbackFontList* getFallbackFontListNoCacheLocked( + const SkLanguage& lang) { + unsigned int numLists = gFallbackFontLists.count(); + for (unsigned int listIdx = 0; listIdx < numLists; ++listIdx) { + FallbackFontList* list = gFallbackFontLists[listIdx]; + SkASSERT(list != NULL); + if (list->fLanguage == lang) { + return list; + } + } + return NULL; +} + +// perform fancy fuzzy-matching memoized query for a fallback font list. +// should only be called after fallback font lists are fully loaded. +static FallbackFontList* getFallbackFontListLocked(const SkLanguage& lang) { + SkASSERT(gIsOKToUseFallbackFontListCache); + const SkString& langTag = lang.getTag(); + FallbackFontList* fallbackFontList; + if (gLangTagToFallbackFontList.find(langTag.c_str(), langTag.size(), + &fallbackFontList)) { + // cache hit! + return fallbackFontList; + } + + // try again without the cache + fallbackFontList = getFallbackFontListNoCacheLocked(lang); + if (fallbackFontList != NULL) { + // found it - cache and return + gLangTagToFallbackFontList.set(langTag.c_str(), langTag.size(), + fallbackFontList); + SkDEBUGF(("new fallback cache entry: \"%s\"", langTag.c_str())); + return fallbackFontList; + } + + // no hit - can we fuzzy-match? + if (lang.getTag().isEmpty()) { + // nope! this happens if attempting to direct match with no default + return NULL; + } + + // attempt fuzzy match + SkLanguage parent = lang.getParent(); + fallbackFontList = getFallbackFontListLocked(parent); + if (fallbackFontList != NULL) { + // found it - cache and return + gLangTagToFallbackFontList.set(langTag.c_str(), langTag.size(), + fallbackFontList); + SkDEBUGF(("new fallback cache entry: \"%s\" -> \"%s\"", langTag.c_str(), + fallbackFontList->fLanguage.getTag().c_str())); + return fallbackFontList; + } + + // utter failure. this happens if attempting to fuzzy-match with no default + SkASSERT(fallbackFontList != NULL); + return NULL; +} + +// creates a new fallback font list for the specified language +static FallbackFontList* createFallbackFontListLocked(const SkLanguage& lang) { + SkASSERT(!gIsOKToUseFallbackFontListCache); + SkDEBUGF(("new fallback list: \"%s\"", lang.getTag().c_str())); + FallbackFontList* fallbackFontList = new FallbackFontList(lang); + gFallbackFontLists.push(fallbackFontList); + return fallbackFontList; +} + +// adds a fallback font record to both the default fallback chain and the +// language-specific fallback chain to which it belongs, if any +static void addFallbackFontLocked(const FallbackFontRec& fallbackRec, + const SkLanguage& lang) { + SkASSERT(!gIsOKToUseFallbackFontListCache); + SkDEBUGF(("new fallback font: %d, in \"%s\"", fallbackRec.fFontID, + lang.getTag().c_str())); + // add to the default fallback list + FallbackFontList* fallbackList = + getFallbackFontListNoCacheLocked(SkLanguage()); + if (fallbackList == NULL) { + // oops! no default list yet. create one. + fallbackList = createFallbackFontListLocked(SkLanguage()); + } + SkASSERT(fallbackList != NULL); + fallbackList->fList.push(fallbackRec); + if (lang.getTag().isEmpty()) { + return; + } + // also add to the appropriate language's fallback list + fallbackList = getFallbackFontListNoCacheLocked(lang); + if (fallbackList == NULL) { + // first entry for this list! + fallbackList = createFallbackFontListLocked(lang); + } + SkASSERT(fallbackList != NULL); + fallbackList->fList.push(fallbackRec); +} + +static int getSystemFontIndexForFontID(SkFontID fontID) { + // font unique id = one-based index in system font table + SkASSERT(fontID - 1 < gSystemFonts.count()); + return fontID - 1; +} + +// scans the default fallback font chain, adding every entry to every other +// fallback font chain to which it does not belong. this results in every +// language-specific fallback font chain having all of its fallback fonts at +// the front of the chain, and everything else at the end. after this has been +// run, it is ok to use the fallback font chain lookup table. +static void finaliseFallbackFontListsLocked() { + SkASSERT(!gIsOKToUseFallbackFontListCache); + // if we have more than one list, we need to finalise non-default lists + unsigned int numLists = gFallbackFontLists.count(); + if (numLists > 1) { + // pull fonts off of the default list... + FallbackFontList* defaultList = getFallbackFontListNoCacheLocked( + SkLanguage()); + SkASSERT(defaultList != NULL); + int numDefaultFonts = defaultList->fList.count(); + for (int fontIdx = 0; fontIdx < numDefaultFonts; ++fontIdx) { + // figure out which language they represent + SkFontID fontID = defaultList->fList[fontIdx].fFontID; + int sysFontIdx = getSystemFontIndexForFontID(fontID); + const SkLanguage& lang = gSystemFonts[sysFontIdx].fLanguage; + for (unsigned int listIdx = 0; listIdx < numLists; ++listIdx) { + // and add them to every other language's list + FallbackFontList* thisList = gFallbackFontLists[listIdx]; + SkASSERT(thisList != NULL); + if (thisList != defaultList && thisList->fLanguage != lang) { + thisList->fList.push(defaultList->fList[fontIdx]); + } + } + } + } + gIsOKToUseFallbackFontListCache = true; +} + +static void resetFallbackFontListsLocked() { + // clear cache + gLangTagToFallbackFontList.reset(); + // clear the data it pointed at + int numFallbackLists = gFallbackFontLists.count(); + for (int fallbackIdx = 0; fallbackIdx < numFallbackLists; ++fallbackIdx) { + delete gFallbackFontLists[fallbackIdx]; + } + gFallbackFontLists.reset(); + gIsOKToUseFallbackFontListCache = false; +} + /* Load info from a configuration file that populates the system/fallback font structures */ static void loadFontInfoLocked() { + resetFallbackFontListsLocked(); + SkTDArray<FontFamily*> fontFamilies; getFontFamilies(fontFamilies); @@ -490,8 +683,8 @@ static void loadFontInfoLocked() { for (int i = 0; i < fontFamilies.count(); ++i) { FontFamily *family = fontFamilies[i]; - for (int j = 0; j < family->fFileNames.count(); ++j) { - const char* filename = family->fFileNames[j]; + for (int j = 0; j < family->fFontFileArray.count(); ++j) { + const char* filename = family->fFontFileArray[j]->fFileName; if (haveSystemFont(filename)) { SkDebugf("---- system font and fallback font files specify a duplicate " "font %s, skipping the second occurrence", filename); @@ -500,6 +693,8 @@ static void loadFontInfoLocked() { FontInitRec fontInfoRecord; fontInfoRecord.fFileName = filename; + fontInfoRecord.fVariant = family->fFontFileArray[j]->fVariant; + fontInfoRecord.fLanguage = family->fFontFileArray[j]->fLanguage; if (j == 0) { if (family->fNames.count() == 0) { // Fallback font @@ -524,7 +719,7 @@ static void loadFontInfoLocked() { } else { fontInfoRecord.fNames = NULL; } - *gSystemFonts.append() = fontInfoRecord; + gSystemFonts.push_back(fontInfoRecord); } } fontFamilies.deleteAll(); @@ -535,7 +730,6 @@ static void loadFontInfoLocked() { } } - /* * Called once (ensured by the sentinel check at the beginning of our body). * Initializes all the globals, and register the system fonts. @@ -550,8 +744,6 @@ static void initSystemFontsLocked() { loadFontInfoLocked(); - gFallbackFonts.reset(); - SkTypeface* firstInFamily = NULL; for (int i = 0; i < gSystemFonts.count(); i++) { // if we're the first in a new family, clear firstInFamily @@ -590,9 +782,11 @@ static void initSystemFontsLocked() { if (names != NULL) { // see if this is one of our fallback fonts if (names == gFBNames) { - SkDEBUGF(("---- adding %s as fallback[%d] fontID %d\n", - gSystemFonts[i].fFileName, gFallbackFonts.count(), tf->uniqueID())); - *gFallbackFonts.append() = tf->uniqueID(); + // add to appropriate fallback chains + FallbackFontRec fallbackRec; + fallbackRec.fFontID = tf->uniqueID(); + fallbackRec.fVariant = gSystemFonts[i].fVariant; + addFallbackFontLocked(fallbackRec, gSystemFonts[i].fLanguage); } firstInFamily = tf; @@ -609,6 +803,7 @@ static void initSystemFontsLocked() { } } } + finaliseFallbackFontListsLocked(); // do this after all fonts are loaded. This is our default font, and it // acts as a sentinel so we only execute loadSystemFontsLocked() once @@ -617,100 +812,19 @@ static void initSystemFontsLocked() { SkDEBUGCODE(dumpGlobalsLocked()); } -static SkFontID findUniqueIDLocked(const char* filename) { - // uniqueID is the index, offset by one, of the associated element in - // gSystemFonts[] (assumes system fonts are loaded before external fonts) - // return 0 if not found - for (int i = 0; i < gSystemFonts.count(); i++) { - if (strcmp(gSystemFonts[i].fFileName, filename) == 0) { - return i + 1; // assume unique id of i'th system font is i + 1 - } - } - return 0; -} - -static int findFallbackFontIndex(SkFontID fontId) { - for (int i = 0; i < gFallbackFonts.count(); i++) { - if (gFallbackFonts[i] == fontId) { +static int findFallbackFontIndex(SkFontID fontId, FallbackFontList* currentFallbackList) { + for (int i = 0; i < currentFallbackList->fList.count(); i++) { + if (currentFallbackList->fList[i].fFontID == fontId) { return i; } } return -1; } -static void reloadFallbackFontsLocked() { - SkGraphics::PurgeFontCache(); - - SkTDArray<FontFamily*> fallbackFamilies; - getFallbackFontFamilies(fallbackFamilies); - - gFallbackFonts.reset(); - - for (int i = 0; i < fallbackFamilies.count(); ++i) { - FontFamily *family = fallbackFamilies[i]; - - for (int j = 0; j < family->fFileNames.count(); ++j) { - const char* filename = family->fFileNames[j]; - if (filename) { - if (!haveSystemFont(filename)) { - SkDebugf("---- skipping fallback font %s because it was not " - "previously loaded as a system font", filename); - continue; - } - - // ensure the fallback font exists before adding it to the list - bool isFixedWidth; - SkString name; - SkTypeface::Style style; - if (!getNameAndStyle(filename, &name, &style, - &isFixedWidth, false)) { - continue; - } - - SkFontID uniqueID = findUniqueIDLocked(filename); - SkASSERT(uniqueID != 0); - if (findFallbackFontIndex(uniqueID) >= 0) { - SkDebugf("---- system font and fallback font files specify a duplicate " - "font %s, skipping the second occurrence", filename); - continue; - } - - SkDEBUGF(("---- reload %s as fallback[%d] fontID %d\n", - filename, gFallbackFonts.count(), uniqueID)); - - *gFallbackFonts.append() = uniqueID; - break; // The fallback set contains only the first font of each family - } - } - } - - fallbackFamilies.deleteAll(); -} - static void loadSystemFontsLocked() { -#if !defined(SK_BUILD_FOR_ANDROID_NDK) - static char prevLanguage[3]; - static char prevRegion[3]; - char language[3] = ""; - char region[3] = ""; - - getLocale(language, region); - if (!gDefaultNormal) { - strncpy(prevLanguage, language, 2); - strncpy(prevRegion, region, 2); initSystemFontsLocked(); - } else if (strncmp(language, prevLanguage, 2) || strncmp(region, prevRegion, 2)) { - strncpy(prevLanguage, language, 2); - strncpy(prevRegion, region, 2); - reloadFallbackFontsLocked(); } -#else - if (!gDefaultNormal) { - initSystemFontsLocked(); - reloadFallbackFontsLocked(); - } -#endif } /////////////////////////////////////////////////////////////////////////////// @@ -883,16 +997,20 @@ static size_t getFileNameLocked(SkFontID fontID, char path[], size_t length, int } } -SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { +SkFontID SkFontHost::NextLogicalFont(const SkScalerContext::Rec& rec) { SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex); - return nextLogicalFontLocked(currFontID, origFontID); + return nextLogicalFontLocked(rec); } -static SkFontID nextLogicalFontLocked(SkFontID currFontID, SkFontID origFontID) { +static SkFontID nextLogicalFontLocked(const SkScalerContext::Rec& rec) { loadSystemFontsLocked(); - const SkTypeface* origTypeface = findFromUniqueIDLocked(origFontID); - const SkTypeface* currTypeface = findFromUniqueIDLocked(currFontID); + const SkTypeface* origTypeface = findFromUniqueIDLocked(rec.fOrigFontID); + const SkTypeface* currTypeface = findFromUniqueIDLocked(rec.fFontID); + + FallbackFontList* currentFallbackList = + getFallbackFontListLocked(rec.fLanguage); + SkASSERT(currentFallbackList); SkASSERT(origTypeface != 0); SkASSERT(currTypeface != 0); @@ -906,19 +1024,32 @@ static SkFontID nextLogicalFontLocked(SkFontID currFontID, SkFontID origFontID) in our list. Note: list is zero-terminated, and returning zero means we have no more fonts to use for fallbacks. */ - int plainFallbackFontIndex = findFallbackFontIndex(plainFontID); + int plainFallbackFontIndex = findFallbackFontIndex(plainFontID, currentFallbackList); int nextFallbackFontIndex = plainFallbackFontIndex + 1; - SkFontID nextFontID; - if (nextFallbackFontIndex == gFallbackFonts.count()) { - nextFontID = 0; // no more fallbacks - } else { - const SkTypeface* nextTypeface = findFromUniqueIDLocked(gFallbackFonts[nextFallbackFontIndex]); - nextFontID = findTypefaceLocked(nextTypeface, origTypeface->style())->uniqueID(); + + // If a rec object is set to prefer "kDefault_Variant" it means they have no preference + // In this case, we set the value to "kCompact_Variant" + SkPaint::FontVariant recPreference = rec.fFontVariant; + if (recPreference == SkPaint::kDefault_Variant) { + recPreference = SkPaint::kCompact_Variant; + } + SkFontID nextFontID = 0; + while (nextFallbackFontIndex < currentFallbackList->fList.count()) { + bool normalFont = + (currentFallbackList->fList[nextFallbackFontIndex].fVariant == SkPaint::kDefault_Variant); + bool fontChosen = (currentFallbackList->fList[nextFallbackFontIndex].fVariant == recPreference); + if (normalFont || fontChosen) { + const SkTypeface* nextTypeface = + findFromUniqueIDLocked(currentFallbackList->fList[nextFallbackFontIndex].fFontID); + nextFontID = findTypefaceLocked(nextTypeface, origTypeface->style())->uniqueID(); + break; + } + nextFallbackFontIndex++; } SkDEBUGF(("---- nextLogicalFont: currFontID=%d, origFontID=%d, plainFontID=%d, " "plainFallbackFontIndex=%d, nextFallbackFontIndex=%d " - "=> nextFontID=%d", currFontID, origFontID, plainFontID, + "=> nextFontID=%d", rec.fFontID, rec.fOrigFontID, plainFontID, plainFallbackFontIndex, nextFallbackFontIndex, nextFontID)); return nextFontID; } @@ -958,3 +1089,143 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { stream->unref(); return face; } + +/////////////////////////////////////////////////////////////////////////////// +// Function from SkTypeface_android.h +/////////////////////////////////////////////////////////////////////////////// + +static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style, + SkPaint::FontVariant fontVariant) { + SkTypeface* face = FindBestFace(gDefaultFamily, style); + if (!face) { + return 0; + } + + SkPaint paint; + paint.setTypeface(face); + paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + paint.setFontVariant(fontVariant); + + SkAutoGlyphCache autoCache(paint, NULL); + SkGlyphCache* cache = autoCache.getCache(); + SkFontID fontID = 0; + + SkScalerContext* ctx = cache->getScalerContext(); + if (ctx) { + return ctx->findTypefaceIdForChar(uni); + } + return 0; +} + +struct HB_UnicodeMapping { + HB_Script script; + const SkUnichar unicode; +}; + +/* + * The following scripts are not complex fonts and we do not expect them to be parsed by this table + * HB_Script_Common, + * HB_Script_Greek, + * HB_Script_Cyrillic, + * HB_Script_Hangul + * HB_Script_Inherited + */ + +static HB_UnicodeMapping HB_UnicodeMappingArray[] { + {HB_Script_Armenian, 0x0531}, + {HB_Script_Hebrew, 0x0591}, + {HB_Script_Arabic, 0x0600}, + {HB_Script_Syriac, 0x0710}, + {HB_Script_Thaana, 0x0780}, + {HB_Script_Nko, 0x07C0}, + {HB_Script_Devanagari, 0x0901}, + {HB_Script_Bengali, 0x0981}, + {HB_Script_Gurmukhi, 0x0A10}, + {HB_Script_Gujarati, 0x0A90}, + {HB_Script_Oriya, 0x0B10}, + {HB_Script_Tamil, 0x0B82}, + {HB_Script_Telugu, 0x0C10}, + {HB_Script_Kannada, 0x0C90}, + {HB_Script_Malayalam, 0x0D10}, + {HB_Script_Sinhala, 0x0D90}, + {HB_Script_Thai, 0x0E01}, + {HB_Script_Lao, 0x0E81}, + {HB_Script_Tibetan, 0x0F00}, + {HB_Script_Myanmar, 0x1000}, + {HB_Script_Georgian, 0x10A0}, + // we don't currently support HB_Script_Ethiopic, it is a placeholder for an upstream merge + //{HB_Script_Ethiopic, 0x1200}, + {HB_Script_Ogham, 0x1680}, + {HB_Script_Runic, 0x16A0}, + {HB_Script_Khmer, 0x1780}, +}; + +// returns 0 for "Not Found" +static SkUnichar getUnicodeFromHBScript(HB_Script script) { + SkUnichar unichar = 0; + int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping); + for (int i = 0; i < numSupportedFonts; i++) { + if (script == HB_UnicodeMappingArray[i].script) { + unichar = HB_UnicodeMappingArray[i].unicode; + break; + } + } + return unichar; +} + +struct TypefaceLookupStruct { + HB_Script script; + SkTypeface::Style style; + SkPaint::FontVariant fontVariant; + SkTypeface* typeface; +}; + +SK_DECLARE_STATIC_MUTEX(gTypefaceTableMutex); // This is the mutex for gTypefaceTable +static SkTDArray<TypefaceLookupStruct> gTypefaceTable; // This is protected by gTypefaceTableMutex + +static int typefaceLookupCompare(const TypefaceLookupStruct& first, + const TypefaceLookupStruct& second) { + if (first.script != second.script) { + return (first.script > second.script) ? 1 : -1; + } + if (first.style != second.style) { + return (first.style > second.style) ? 1 : -1; + } + if (first.fontVariant != second.fontVariant) { + return (first.fontVariant > second.fontVariant) ? 1 : -1; + } + return 0; +} + +SK_API SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style, + SkPaint::FontVariant fontVariant) { + SkTypeface* retTypeface = NULL; + + SkAutoMutexAcquire ac(gTypefaceTableMutex); // Note: NOT gFamilyHeadAndNameListMutex + TypefaceLookupStruct key; + key.script = script; + key.style = style; + key.fontVariant = fontVariant; + int index = SkTSearch<TypefaceLookupStruct>( + (const TypefaceLookupStruct*) gTypefaceTable.begin(), + gTypefaceTable.count(), key, sizeof(TypefaceLookupStruct), + &typefaceLookupCompare); + if (index >= 0) { + retTypeface = gTypefaceTable[index].typeface; + } + else { + SkUnichar unichar = getUnicodeFromHBScript(script); + if (!unichar) { + return NULL; + } + SkFontID newFontID = findFontIDForChar(unichar, style, fontVariant); + // retrieve the typeface that corresponds to this fontID + retTypeface = FindFromUniqueID(newFontID); + key.typeface = retTypeface; + index = ~index; + *gTypefaceTable.insert(index) = key; + } + // we ref(), the caller is expected to unref when they are done + SkSafeRef(retTypeface); + return retTypeface; +} |