OSDN Git Service

Fixed 2720133. Better lookup with @font-face local
authorRussell Brenner <russellbrenner@google.com>
Wed, 3 Nov 2010 18:06:53 +0000 (11:06 -0700)
committerRussell Brenner <russellbrenner@google.com>
Wed, 3 Nov 2010 20:49:56 +0000 (13:49 -0700)
Using existing Skia APIs, FontCache::createFontPlatformData can detect when
the retrieved font is the Skia default and will reject that choice,
allowing WebCore to try the next font on the CSS fallback list. If the
requested family is a generic family, e.g. "serif" or "monotype", the Skia
default will be accepted.

Change-Id: I8007caae96f26cd58ea1cf5bf2da8170e3ce6d9d
Bug: 2720133

WebCore/platform/graphics/android/FontCacheAndroid.cpp

index 6ec72c9..dac005f 100644 (file)
 #include "SkPaint.h"
 #include "SkTypeface.h"
 #include "SkUtils.h"
+#include <wtf/text/CString.h>
 
 namespace WebCore {
 
+static const char* getFallbackFontName(const FontDescription& fontDescription)
+{
+    switch (fontDescription.genericFamily()) {
+    case FontDescription::StandardFamily:
+    case FontDescription::SerifFamily:
+        return "serif";
+    case FontDescription::SansSerifFamily:
+        return "sans-serif";
+    case FontDescription::MonospaceFamily:
+        return "monospace";
+    case FontDescription::CursiveFamily:
+        return "cursive";
+    case FontDescription::FantasyFamily:
+        return "fantasy";
+    case FontDescription::NoFamily:
+    default:
+        return "";
+    }
+}
+
+static bool isFallbackFamily(String family)
+{
+    return family.startsWith("-webkit-")
+        || equalIgnoringCase(family, "serif")
+        || equalIgnoringCase(family, "sans-serif")
+        || equalIgnoringCase(family, "sans")
+        || equalIgnoringCase(family, "monospace")
+        || equalIgnoringCase(family, "cursive")
+        || equalIgnoringCase(family, "fantasy");
+}
+
+static char* AtomicStringToUTF8String(const AtomicString& utf16)
+{
+    SkASSERT(sizeof(uint16_t) == sizeof(utf16.characters()[0]));
+    const uint16_t* uni = (uint16_t*)utf16.characters();
+
+    size_t bytes = SkUTF16_ToUTF8(uni, utf16.length(), NULL);
+    char*  utf8 = (char*)sk_malloc_throw(bytes + 1);
+
+    (void)SkUTF16_ToUTF8(uni, utf16.length(), utf8);
+    utf8[bytes] = 0;
+    return utf8;
+}
+
+
 void FontCache::platformInit()
 {
 }
@@ -52,57 +98,41 @@ SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
     return 0;
 }
 
-SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& font)
-{
-    static AtomicString str("sans-serif");
-    return getCachedFontData(font, str);
-}
-
-static char* AtomicStringToUTF8String(const AtomicString& utf16)
+SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& description)
 {
-    SkASSERT(sizeof(uint16_t) == sizeof(utf16.characters()[0]));
-    const uint16_t* uni = (uint16_t*)utf16.characters();
+    static const AtomicString sansStr("sans-serif");
+    static const AtomicString serifStr("serif");
+    static const AtomicString monospaceStr("monospace");
 
-    size_t bytes = SkUTF16_ToUTF8(uni, utf16.length(), NULL);
-    char*  utf8 = (char*)sk_malloc_throw(bytes + 1);
+    FontPlatformData* fontPlatformData = 0;
+    switch (description.genericFamily()) {
+    case FontDescription::SerifFamily:
+        fontPlatformData = getCachedFontPlatformData(description, serifStr);
+        break;
+    case FontDescription::MonospaceFamily:
+        fontPlatformData = getCachedFontPlatformData(description, monospaceStr);
+        break;
+    case FontDescription::SansSerifFamily:
+    default:
+        fontPlatformData = getCachedFontPlatformData(description, sansStr);
+        break;
+    }
 
-    (void)SkUTF16_ToUTF8(uni, utf16.length(), utf8);
-    utf8[bytes] = 0;
-    return utf8;
+    ASSERT(fontPlatformData);
+    return getCachedFontData(fontPlatformData);
 }
 
 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
 {
-    char*       storage = 0;
+    char* storage = 0;
     const char* name = 0;
+    FontPlatformData* result = 0;
     
-    if (family.length() == 0) {
-        static const struct {
-            FontDescription::GenericFamilyType  mType;
-            const char*                         mName;
-        } gNames[] = {
-            { FontDescription::SerifFamily,     "serif" },
-            { FontDescription::SansSerifFamily, "sans-serif" },
-            { FontDescription::MonospaceFamily, "monospace" },
-            { FontDescription::CursiveFamily,   "cursive" },
-            { FontDescription::FantasyFamily,   "fantasy" }
-        };
-
-        FontDescription::GenericFamilyType type = fontDescription.genericFamily();
-        for (unsigned i = 0; i < SK_ARRAY_COUNT(gNames); i++)
-        {
-            if (type == gNames[i].mType)
-            {
-                name = gNames[i].mName;
-                break;
-            }
-        }
-        // if we fall out of the loop, its ok for name to still be 0
-    }
-    else {    // convert the name to utf8
+    if (family.length()) {
         storage = AtomicStringToUTF8String(family);
         name = storage;
-    }
+    } else
+        name = getFallbackFontName(fontDescription);
     
     int style = SkTypeface::kNormal;
     if (fontDescription.weight() >= FontWeightBold)
@@ -110,12 +140,22 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
     if (fontDescription.italic())
         style |= SkTypeface::kItalic;
 
+    // CreateFromName always returns a typeface, falling back to a default font
+    // if the one requested is not found. Calling Equal() with a null pointer
+    // serves to compare the returned font against the default. If we detect
+    // the default, we ignore it and allow WebCore to give us the next font on
+    // the CSS fallback list. The only exception is if the family name is a
+    // commonly used generic family, which will be the case when called by
+    // getSimilarFontPlatformData() and getLastResortFallbackFont().
+
     SkTypeface* tf = SkTypeface::CreateFromName(name, (SkTypeface::Style)style);
-    
-    FontPlatformData* result = new FontPlatformData(tf,
-                                                    fontDescription.computedSize(),
-                                                    (style & SkTypeface::kBold) && !tf->isBold(),
-                                                    (style & SkTypeface::kItalic) && !tf->isItalic());
+
+    if (!SkTypeface::Equal(tf, 0) || isFallbackFamily(family.string())) {
+        result = new FontPlatformData(tf, fontDescription.computedSize(),
+            (style & SkTypeface::kBold) && !tf->isBold(),
+            (style & SkTypeface::kItalic) && !tf->isItalic());
+    }
+
     tf->unref();
     sk_free(storage);
     return result;