diff --git a/include/ports/SkTypeface_android.h b/include/ports/SkTypeface_android.h index 7e32fa3e2..1ee17e6ea 100644 --- a/include/ports/SkTypeface_android.h +++ b/include/ports/SkTypeface_android.h @@ -58,6 +58,19 @@ SK_API const char* SkGetFallbackScriptID(FallbackScripts script); */ SK_API FallbackScripts SkGetFallbackScriptFromID(const char* id); +/** + * Return a new typeface of the font in the fallback font list containing + * the specified chararacter. If no typeface is found, returns null. + */ +SK_API SkTypeface* SkCreateFallbackTypefaceForChar(SkUnichar uni, + SkTypeface::Style style); + +/** + * Get the family name of the font in the fallback font list containing + * the specified chararacter. if no font is found, returns false. + */ +SK_API bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name); + /** * For test only. * Load font config from given xml files, instead of those from Android system. diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp index 2b78f314f..9f1bd56c6 100644 --- a/src/ports/SkFontHost_android.cpp +++ b/src/ports/SkFontHost_android.cpp @@ -17,7 +17,6 @@ #include "SkFontHost.h" #include "SkFontDescriptor.h" -#include "SkGlyphCache.h" #include "SkGraphics.h" #include "SkDescriptor.h" #include "SkMMapStream.h" @@ -547,6 +546,7 @@ static void load_font_info() { malloc((names.count() + 1) * sizeof(char*)); if (nameList == NULL) { // shouldn't get here + SkDEBUGFAIL("Failed to allocate nameList"); break; } if (gDefaultNames == NULL) { @@ -602,7 +602,7 @@ static void init_system_fonts() { load_font_info(); - const FontInitRec* rec = gSystemFonts; + FontInitRec* rec = gSystemFonts; SkTypeface* firstInFamily = NULL; int fallbackCount = 0; @@ -647,6 +647,17 @@ static void init_system_fonts() { rec[i].fFileName, fallbackCount, tf->uniqueID()); #endif gFallbackFonts[fallbackCount++] = tf->uniqueID(); + + // Use the font file name as the name of the typeface. + const char **nameList = (const char**)malloc(2 * sizeof(char*)); + if (nameList == NULL) { + // shouldn't get here + SkDEBUGFAIL("Failed to allocate nameList"); + break; + } + nameList[0] = rec[i].fFileName; + nameList[1] = NULL; + rec[i].fNames = nameList; } firstInFamily = tf; @@ -882,6 +893,13 @@ size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, } SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { +#ifdef SK_BUILD_FOR_ANDROID_NDK + // Skia does not support font fallback for ndk applications in order to + // enable clients such as WebKit to customize their font selection. + // Clients can use GetFallbackFamilyNameForChar() to get the fallback + // font for individual characters. + return 0; +#else SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex); load_system_fonts(); @@ -917,6 +935,7 @@ SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { // i.e. gFallbackFonts[0] != 0. const SkTypeface* firstTypeface = find_from_uniqueID(list[0]); return find_typeface(firstTypeface, origTypeface->style())->uniqueID(); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -926,10 +945,6 @@ SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { return NULL; } - // Make sure system fonts are loaded first to comply with the assumption - // that the font's uniqueID can be found using the find_uniqueID method. - load_system_fonts(); - bool isFixedWidth; SkTypeface::Style style; @@ -990,30 +1005,36 @@ static const int gFBScriptInfoCount = sizeof(gFBScriptInfo) / sizeof(FBScriptInf // ensure that if any value is added to the public enum it is also added here SK_COMPILE_ASSERT(gFBScriptInfoCount == kFallbackScriptNumber, FBScript_count_mismatch); -// this function can't be called if the gFamilyHeadAndNameListMutex is already locked -static SkFontID findFontIDForChar(SkUnichar uni, SkTypeface::Style style) { - gFamilyHeadAndNameListMutex.acquire(); - SkTypeface* face = find_best_face(gDefaultFamily, style); - gFamilyHeadAndNameListMutex.release(); - if (!face) { - return 0; - } - +static bool typefaceContainsChar(SkTypeface* face, SkUnichar uni) { SkPaint paint; paint.setTypeface(face); paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); - SkAutoGlyphCache autoCache(paint, NULL); - SkGlyphCache* cache = autoCache.getCache(); - SkFontID fontID = 0; + uint16_t glyphID; + paint.textToGlyphs(&uni, sizeof(uni), &glyphID); + return glyphID != 0; +} - SkScalerContext* ctx = cache->getScalerContext(); - if (ctx) { - return ctx->findTypefaceIdForChar(uni); +static SkTypeface* findFallbackTypefaceForChar(SkUnichar uni) { + SkASSERT(gFallbackFonts); + const uint32_t* list = gFallbackFonts; + for (int i = 0; list[i] != 0; i++) { + SkTypeface* face = find_from_uniqueID(list[i]); + if (typefaceContainsChar(face, uni)) { + return face; + } } return 0; } +static SkFontID findFallbackFontIDForChar(SkUnichar uni, SkTypeface::Style style) { + const SkTypeface* tf = findFallbackTypefaceForChar(uni); + if (!tf) { + return 0; + } + return find_typeface(tf, style)->uniqueID(); +} + // this function can't be called if the gFamilyHeadAndNameListMutex is already locked static void initFBScriptInfo() { if (gFBScriptInitialized) { @@ -1030,7 +1051,7 @@ static void initFBScriptInfo() { // selects the best available style for the desired font. However, if // bold is requested and no bold font exists for the typeface containing // the character the next best style is chosen (e.g. normal). - scriptInfo.fFontID = findFontIDForChar(scriptInfo.fChar, scriptInfo.fStyle); + scriptInfo.fFontID = findFallbackFontIDForChar(scriptInfo.fChar, scriptInfo.fStyle); #if SK_DEBUG_FONTS SkDebugf("gFBScriptInfo[%s] --> %d", scriptInfo.fScriptID, scriptInfo.fFontID); #endif @@ -1084,6 +1105,34 @@ FallbackScripts SkGetFallbackScriptFromID(const char* id) { return kFallbackScriptNumber; // Use kFallbackScriptNumber as an invalid value. } +SkTypeface* SkCreateFallbackTypefaceForChar(SkUnichar uni, + SkTypeface::Style style) { + SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex); + load_system_fonts(); + + SkTypeface* tf = findFallbackTypefaceForChar(uni); + if (!tf) { + return NULL; + } + tf = find_typeface(tf, style); + // we ref(), since the semantic is to return a new instance + tf->ref(); + return tf; +} + +bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name) { + SkASSERT(name); + SkAutoMutexAcquire ac(gFamilyHeadAndNameListMutex); + load_system_fonts(); + + const SkTypeface* tf = findFallbackTypefaceForChar(uni); + if (!tf) { + return false; + } + name->set(find_family_name(tf)); + return true; +} + void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf, const char* fontsdir) { gTestMainConfigFile = mainconf;