From fd0bf63b4addb1bcb90de078bbd4700e2545a69f Mon Sep 17 00:00:00 2001 From: Russell Brenner Date: Wed, 3 Nov 2010 11:06:53 -0700 Subject: Fixed 2720133. Better lookup with @font-face local 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 --- .../platform/graphics/android/FontCacheAndroid.cpp | 130 ++++++++++++++------- 1 file changed, 85 insertions(+), 45 deletions(-) diff --git a/WebCore/platform/graphics/android/FontCacheAndroid.cpp b/WebCore/platform/graphics/android/FontCacheAndroid.cpp index 6ec72c9..dac005f 100644 --- a/WebCore/platform/graphics/android/FontCacheAndroid.cpp +++ b/WebCore/platform/graphics/android/FontCacheAndroid.cpp @@ -33,9 +33,55 @@ #include "SkPaint.h" #include "SkTypeface.h" #include "SkUtils.h" +#include 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; -- cgit v1.1