diff options
author | Russell Brenner <russellbrenner@google.com> | 2011-03-03 18:29:26 -0800 |
---|---|---|
committer | Russell Brenner <russellbrenner@google.com> | 2011-03-16 15:36:43 -0700 |
commit | cbcc214ef5f642d9b14ee5a542cc573441e6fb43 (patch) | |
tree | c431491220edac23d44239525d361c3a885c71cf /WebCore/platform | |
parent | 49fff159362adc0289fe593ac113a8d0a0671edf (diff) | |
download | external_webkit-cbcc214ef5f642d9b14ee5a542cc573441e6fb43.zip external_webkit-cbcc214ef5f642d9b14ee5a542cc573441e6fb43.tar.gz external_webkit-cbcc214ef5f642d9b14ee5a542cc573441e6fb43.tar.bz2 |
Fix crash in WebCore::GlyphPageTreeNode::getChild
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.
A prior attempt at this fix was not properly handling bold and italic
stylings, which could eventually lead to dangling references to freed
font data used for layout while custom fonts were loading, causing
segfaults in getChild and elsewhere during page rendering.
Bug: 3469204
Bug: 2720133
Change-Id: I3a9e746e18fd27848d0c4b9e1232392df33254a6
Diffstat (limited to 'WebCore/platform')
-rw-r--r-- | WebCore/platform/graphics/android/FontCacheAndroid.cpp | 141 |
1 files changed, 95 insertions, 46 deletions
diff --git a/WebCore/platform/graphics/android/FontCacheAndroid.cpp b/WebCore/platform/graphics/android/FontCacheAndroid.cpp index 798077f..428628c 100644 --- a/WebCore/platform/graphics/android/FontCacheAndroid.cpp +++ b/WebCore/platform/graphics/android/FontCacheAndroid.cpp @@ -34,9 +34,55 @@ #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(), 0); + char* utf8 = (char*)sk_malloc_throw(bytes + 1); + + (void)SkUTF16_ToUTF8(uni, utf16.length(), utf8); + utf8[bytes] = 0; + return utf8; +} + + void FontCache::platformInit() { } @@ -53,57 +99,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(); - - size_t bytes = SkUTF16_ToUTF8(uni, utf16.length(), 0); - char* utf8 = (char*)sk_malloc_throw(bytes + 1); + static const AtomicString sansStr("sans-serif"); + static const AtomicString serifStr("serif"); + static const AtomicString monospaceStr("monospace"); + + 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) @@ -111,12 +141,31 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD if (fontDescription.italic()) style |= SkTypeface::kItalic; - SkTypeface* tf = SkTypeface::CreateFromName(name, (SkTypeface::Style)style); + // 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, with the caveat + // that the default is always of normal style. 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, as when called by getSimilarFontPlatformData() and + // getLastResortFallbackFont(). In this case, the default font is an + // acceptable result. + + SkTypeface* tf = SkTypeface::CreateFromName(name, SkTypeface::kNormal); + + if (!SkTypeface::Equal(tf, 0) || isFallbackFamily(family.string())) { + // We had to use normal styling to see if this was a default font. If + // we need bold or italic, replace with the corrected typeface. + if (style != SkTypeface::kNormal) { + tf->unref(); + tf = SkTypeface::CreateFromName(name, (SkTypeface::Style)style); + } + + result = new FontPlatformData(tf, fontDescription.computedSize(), + (style & SkTypeface::kBold) && !tf->isBold(), + (style & SkTypeface::kItalic) && !tf->isItalic()); + } - FontPlatformData* result = new FontPlatformData(tf, - fontDescription.computedSize(), - (style & SkTypeface::kBold) && !tf->isBold(), - (style & SkTypeface::kItalic) && !tf->isItalic()); tf->unref(); sk_free(storage); return result; |