Index: src/ports/SkFontConfigInterface_android.cpp |
diff --git a/src/ports/SkFontConfigInterface_android.cpp b/src/ports/SkFontConfigInterface_android.cpp |
index 6cf7507844735f9529939ab3827bc48b7d9d3055..8039906ab678d89d4755293aed1ea1a9ac2e3c0a 100644 |
--- a/src/ports/SkFontConfigInterface_android.cpp |
+++ b/src/ports/SkFontConfigInterface_android.cpp |
@@ -14,7 +14,6 @@ |
#include "SkFontMgr.h" |
#include "SkGlyphCache.h" |
#include "SkPaint.h" |
-#include "SkPaintOptionsAndroid.h" |
#include "SkString.h" |
#include "SkStream.h" |
#include "SkThread.h" |
@@ -45,6 +44,12 @@ static const char* gTestFontFilePrefix = NULL; |
/////////////////////////////////////////////////////////////////////////////// |
+typedef int32_t FontRecID; |
+#define INVALID_FONT_REC_ID -1 |
+ |
+typedef int32_t FamilyRecID; |
+#define INVALID_FAMILY_REC_ID -1 |
+ |
// used to record our notion of the pre-existing fonts |
struct FontRec { |
SkRefPtr<SkTypeface> fTypeface; |
@@ -53,11 +58,9 @@ struct FontRec { |
SkPaintOptionsAndroid fPaintOptions; |
bool fIsFallbackFont; |
bool fIsValid; |
+ FamilyRecID fFamilyRecID; |
}; |
-typedef int32_t FontRecID; |
-#define INVALID_FONT_REC_ID -1 |
- |
struct FamilyRec { |
FamilyRec() { |
memset(fFontRecID, INVALID_FONT_REC_ID, sizeof(fFontRecID)); |
@@ -67,8 +70,6 @@ struct FamilyRec { |
FontRecID fFontRecID[FONT_STYLE_COUNT]; |
}; |
-typedef int32_t FamilyRecID; |
-#define INVALID_FAMILY_REC_ID -1 |
typedef SkTDArray<FontRecID> FallbackFontList; |
@@ -105,7 +106,8 @@ public: |
private: |
void addFallbackFont(FontRecID fontRecID); |
- FallbackFontList* findFallbackFontList(const SkLanguage& lang); |
+ SkTypeface* getTypefaceForFontRec(FontRecID fontRecID); |
+ FallbackFontList* findFallbackFontList(const SkLanguage& lang, bool isOriginal = true); |
SkTArray<FontRec> fFonts; |
SkTArray<FamilyRec> fFontFamilies; |
@@ -114,6 +116,7 @@ private: |
// (SkLanguage)<->(fallback chain index) translation |
SkTDict<FallbackFontList*> fFallbackFontDict; |
+ SkTDict<FallbackFontList*> fFallbackFontAliasDict; |
FallbackFontList fDefaultFallbackList; |
}; |
@@ -189,7 +192,8 @@ SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArray<FontFamily* |
fFontFamilies(fontFamilies.count() / FamilyRec::FONT_STYLE_COUNT), |
fFamilyNameDict(1024), |
fDefaultFamilyRecID(INVALID_FAMILY_REC_ID), |
- fFallbackFontDict(128) { |
+ fFallbackFontDict(128), |
+ fFallbackFontAliasDict(128) { |
for (int i = 0; i < fontFamilies.count(); ++i) { |
FontFamily* family = fontFamilies[i]; |
@@ -215,6 +219,7 @@ SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArray<FontFamily* |
fontRec.fPaintOptions = family->fFontFiles[j]->fPaintOptions; |
fontRec.fIsFallbackFont = family->fIsFallbackFont; |
fontRec.fIsValid = false; |
+ fontRec.fFamilyRecID = familyRecID; |
const FontRecID fontRecID = fFonts.count() - 1; |
@@ -244,6 +249,7 @@ SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArray<FontFamily* |
if (familyRec == NULL) { |
familyRec = &fFontFamilies.push_back(); |
familyRecID = fFontFamilies.count() - 1; |
+ fontRec.fFamilyRecID = familyRecID; |
} |
// add this font to the current familyRec |
@@ -454,13 +460,26 @@ bool SkFontConfigInterfaceAndroid::matchFamilySet(const char inFamilyName[], |
return false; |
} |
-static SkTypeface* get_typeface_for_rec(FontRec& fontRec) { |
+static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) { |
+ const FontRecID* fontRecID = (const FontRecID*)ctx; |
+ FontRecID currFontRecID = ((FontConfigTypeface*)face)->getIdentity().fID; |
+ return currFontRecID == *fontRecID; |
+} |
+ |
+SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForFontRec(FontRecID fontRecID) { |
+ FontRec& fontRec = fFonts[fontRecID]; |
SkTypeface* face = fontRec.fTypeface.get(); |
if (!face) { |
- // TODO look for it in the typeface cache |
+ // look for it in the typeface cache |
+ face = SkTypefaceCache::FindByProcAndRef(find_proc, &fontRecID); |
// if it is not in the cache then create it |
- face = SkTypeface::CreateFromFile(fontRec.fFileName.c_str()); |
+ if (!face) { |
+ const char* familyName = NULL; |
+ SkAssertResult(fFamilyNameDict.findKey(fontRec.fFamilyRecID, &familyName)); |
+ SkASSERT(familyName); |
+ face = SkTypeface::CreateFromName(familyName, fontRec.fStyle); |
+ } |
// store the result for subsequent lookups |
fontRec.fTypeface = face; |
@@ -472,7 +491,7 @@ static SkTypeface* get_typeface_for_rec(FontRec& fontRec) { |
bool SkFontConfigInterfaceAndroid::getFallbackFamilyNameForChar(SkUnichar uni, SkString* name) { |
for (int i = 0; i < fDefaultFallbackList.count(); i++) { |
FontRecID fontRecID = fDefaultFallbackList[i]; |
- SkTypeface* face = get_typeface_for_rec(fFonts[fontRecID]); |
+ SkTypeface* face = this->getTypefaceForFontRec(fontRecID); |
SkPaint paint; |
paint.setTypeface(face); |
@@ -492,7 +511,7 @@ SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForChar(SkUnichar uni, |
SkTypeface::Style style, |
SkPaintOptionsAndroid::FontVariant fontVariant) { |
FontRecID fontRecID = find_best_style(fFontFamilies[fDefaultFamilyRecID], style); |
- SkTypeface* face = get_typeface_for_rec(fFonts[fontRecID]); |
+ SkTypeface* face = this->getTypefaceForFontRec(fontRecID); |
SkPaintOptionsAndroid paintOptions; |
paintOptions.setFontVariant(fontVariant); |
@@ -514,22 +533,29 @@ SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForChar(SkUnichar uni, |
return NULL; |
} |
-FallbackFontList* SkFontConfigInterfaceAndroid::findFallbackFontList(const SkLanguage& lang) { |
+FallbackFontList* SkFontConfigInterfaceAndroid::findFallbackFontList(const SkLanguage& lang, |
+ bool isOriginal) { |
const SkString& langTag = lang.getTag(); |
if (langTag.isEmpty()) { |
return &fDefaultFallbackList; |
} |
FallbackFontList* fallbackFontList; |
- if (fFallbackFontDict.find(langTag.c_str(), langTag.size(), &fallbackFontList)) { |
+ if (fFallbackFontDict.find(langTag.c_str(), langTag.size(), &fallbackFontList) || |
+ fFallbackFontAliasDict.find(langTag.c_str(), langTag.size(), &fallbackFontList)) { |
return fallbackFontList; |
} |
// attempt a recursive fuzzy match |
- // TODO we could cache the intermediate parent so that we don't have to do |
- // the recursion again. |
SkLanguage parent = lang.getParent(); |
- return findFallbackFontList(parent); |
+ fallbackFontList = findFallbackFontList(parent, false); |
+ |
+ // cache the original lang so we don't have to do the recursion again. |
+ if (isOriginal) { |
+ DEBUG_FONT(("---- Created fallback list alias for \"%s\"", langTag.c_str())); |
+ fFallbackFontAliasDict.set(langTag.c_str(), fallbackFontList); |
+ } |
+ return fallbackFontList; |
} |
SkTypeface* SkFontConfigInterfaceAndroid::nextLogicalTypeface(SkFontID currFontID, |
@@ -544,21 +570,20 @@ SkTypeface* SkFontConfigInterfaceAndroid::nextLogicalTypeface(SkFontID currFontI |
} |
const SkTypeface* currTypeface = SkTypefaceCache::FindByID(currFontID); |
+ SkASSERT(currTypeface != 0); |
FallbackFontList* currentFallbackList = findFallbackFontList(opts.getLanguage()); |
SkASSERT(currentFallbackList); |
- SkASSERT(currTypeface != 0); |
- |
// we must convert currTypeface into a FontRecID |
FontRecID currFontRecID = ((FontConfigTypeface*)currTypeface)->getIdentity().fID; |
+ SkASSERT(INVALID_FONT_REC_ID != currFontRecID); |
// TODO lookup the index next font in the chain |
int currFallbackFontIndex = currentFallbackList->find(currFontRecID); |
int nextFallbackFontIndex = currFallbackFontIndex + 1; |
- SkASSERT(-1 == nextFallbackFontIndex); |
- if(nextFallbackFontIndex >= currentFallbackList->count() && -1 == currFallbackFontIndex) { |
+ if(nextFallbackFontIndex >= currentFallbackList->count()) { |
return NULL; |
} |
@@ -574,17 +599,17 @@ SkTypeface* SkFontConfigInterfaceAndroid::nextLogicalTypeface(SkFontID currFontI |
SkTypeface* nextLogicalTypeface = 0; |
while (nextFallbackFontIndex < currentFallbackList->count()) { |
FontRecID fontRecID = currentFallbackList->getAt(nextFallbackFontIndex); |
- if (fFonts[fontRecID].fPaintOptions.getFontVariant() & acceptedVariants) { |
- nextLogicalTypeface = get_typeface_for_rec(fFonts[fontRecID]); |
+ if ((fFonts[fontRecID].fPaintOptions.getFontVariant() & acceptedVariants) != 0) { |
+ nextLogicalTypeface = this->getTypefaceForFontRec(fontRecID); |
break; |
} |
nextFallbackFontIndex++; |
} |
DEBUG_FONT(("---- nextLogicalFont: currFontID=%d, origFontID=%d, currRecID=%d, " |
- "lang=%s, variant=%d, nextFallbackIndex=%d => nextLogicalTypeface=%d", |
+ "lang=%s, variant=%d, nextFallbackIndex[%d,%d] => nextLogicalTypeface=%d", |
currFontID, origFontID, currFontRecID, opts.getLanguage().getTag().c_str(), |
- variant, nextFallbackFontIndex, |
+ variant, nextFallbackFontIndex, currentFallbackList->getAt(nextFallbackFontIndex), |
(nextLogicalTypeface) ? nextLogicalTypeface->uniqueID() : 0)); |
return SkSafeRef(nextLogicalTypeface); |
} |
@@ -617,6 +642,157 @@ SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontI |
/////////////////////////////////////////////////////////////////////////////// |
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK |
+ |
+struct HB_UnicodeMapping { |
+ // TODO: when the WebView no longer needs harfbuzz_old, remove |
+ HB_Script script_old; |
+ hb_script_t 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 |
+ */ |
+ |
+/* Harfbuzz (old) is missing a number of scripts in its table. For these, |
+ * we include a value which can never happen. We won't get complex script |
+ * shaping in these cases, but the library wouldn't know how to shape |
+ * them anyway. */ |
+#define HB_Script_Unknown HB_ScriptCount |
+ |
+static HB_UnicodeMapping HB_UnicodeMappingArray[] = { |
+ {HB_Script_Armenian, HB_SCRIPT_ARMENIAN, 0x0531}, |
+ {HB_Script_Hebrew, HB_SCRIPT_HEBREW, 0x0591}, |
+ {HB_Script_Arabic, HB_SCRIPT_ARABIC, 0x0600}, |
+ {HB_Script_Syriac, HB_SCRIPT_SYRIAC, 0x0710}, |
+ {HB_Script_Thaana, HB_SCRIPT_THAANA, 0x0780}, |
+ {HB_Script_Nko, HB_SCRIPT_NKO, 0x07C0}, |
+ {HB_Script_Devanagari, HB_SCRIPT_DEVANAGARI, 0x0901}, |
+ {HB_Script_Bengali, HB_SCRIPT_BENGALI, 0x0981}, |
+ {HB_Script_Gurmukhi, HB_SCRIPT_GURMUKHI, 0x0A10}, |
+ {HB_Script_Gujarati, HB_SCRIPT_GUJARATI, 0x0A90}, |
+ {HB_Script_Oriya, HB_SCRIPT_ORIYA, 0x0B10}, |
+ {HB_Script_Tamil, HB_SCRIPT_TAMIL, 0x0B82}, |
+ {HB_Script_Telugu, HB_SCRIPT_TELUGU, 0x0C10}, |
+ {HB_Script_Kannada, HB_SCRIPT_KANNADA, 0x0C90}, |
+ {HB_Script_Malayalam, HB_SCRIPT_MALAYALAM, 0x0D10}, |
+ {HB_Script_Sinhala, HB_SCRIPT_SINHALA, 0x0D90}, |
+ {HB_Script_Thai, HB_SCRIPT_THAI, 0x0E01}, |
+ {HB_Script_Lao, HB_SCRIPT_LAO, 0x0E81}, |
+ {HB_Script_Tibetan, HB_SCRIPT_TIBETAN, 0x0F00}, |
+ {HB_Script_Myanmar, HB_SCRIPT_MYANMAR, 0x1000}, |
+ {HB_Script_Georgian, HB_SCRIPT_GEORGIAN, 0x10A0}, |
+ {HB_Script_Unknown, HB_SCRIPT_ETHIOPIC, 0x1200}, |
+ {HB_Script_Unknown, HB_SCRIPT_CHEROKEE, 0x13A0}, |
+ {HB_Script_Ogham, HB_SCRIPT_OGHAM, 0x1680}, |
+ {HB_Script_Runic, HB_SCRIPT_RUNIC, 0x16A0}, |
+ {HB_Script_Khmer, HB_SCRIPT_KHMER, 0x1780}, |
+ {HB_Script_Unknown, HB_SCRIPT_TAI_LE, 0x1950}, |
+ {HB_Script_Unknown, HB_SCRIPT_NEW_TAI_LUE, 0x1980}, |
+ {HB_Script_Unknown, HB_SCRIPT_TAI_THAM, 0x1A20}, |
+ {HB_Script_Unknown, HB_SCRIPT_CHAM, 0xAA00}, |
+}; |
+ |
+static hb_script_t getHBScriptFromHBScriptOld(HB_Script script_old) { |
+ hb_script_t script = HB_SCRIPT_INVALID; |
+ int numSupportedFonts = sizeof(HB_UnicodeMappingArray) / sizeof(HB_UnicodeMapping); |
+ for (int i = 0; i < numSupportedFonts; i++) { |
+ if (script_old == HB_UnicodeMappingArray[i].script_old) { |
+ script = HB_UnicodeMappingArray[i].script; |
+ break; |
+ } |
+ } |
+ return script; |
+} |
+ |
+// returns 0 for "Not Found" |
+static SkUnichar getUnicodeFromHBScript(hb_script_t 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_t script; |
+ SkTypeface::Style style; |
+ SkPaintOptionsAndroid::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; |
+} |
+ |
+SkTypeface* SkCreateTypefaceForScriptNG(hb_script_t script, SkTypeface::Style style, |
+ SkPaintOptionsAndroid::FontVariant fontVariant) { |
+ SkAutoMutexAcquire ac(gTypefaceTableMutex); |
+ |
+ 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); |
+ |
+ SkTypeface* retTypeface = NULL; |
+ if (index >= 0) { |
+ retTypeface = gTypefaceTable[index].typeface; |
+ } |
+ else { |
+ SkUnichar unichar = getUnicodeFromHBScript(script); |
+ if (!unichar) { |
+ return NULL; |
+ } |
+ |
+ SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface(); |
+ retTypeface = fontConfig->getTypefaceForChar(unichar, style, fontVariant); |
+ |
+ // add to the lookup table |
+ key.typeface = retTypeface; |
+ *gTypefaceTable.insert(~index) = key; |
+ } |
+ |
+ // we ref(), the caller is expected to unref when they are done |
+ return SkSafeRef(retTypeface); |
+} |
+ |
+SkTypeface* SkCreateTypefaceForScript(HB_Script script, SkTypeface::Style style, |
+ SkPaintOptionsAndroid::FontVariant fontVariant) { |
+ return SkCreateTypefaceForScriptNG(getHBScriptFromHBScriptOld(script), style, fontVariant); |
+} |
+ |
+#endif |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
SkFontMgr* SkFontMgr::Factory() { |
return NULL; |
} |