summaryrefslogtreecommitdiffstats
path: root/WebCore/platform
diff options
context:
space:
mode:
authorRussell Brenner <russellbrenner@google.com>2011-03-03 18:29:26 -0800
committerRussell Brenner <russellbrenner@google.com>2011-03-16 15:36:43 -0700
commitcbcc214ef5f642d9b14ee5a542cc573441e6fb43 (patch)
treec431491220edac23d44239525d361c3a885c71cf /WebCore/platform
parent49fff159362adc0289fe593ac113a8d0a0671edf (diff)
downloadexternal_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.cpp141
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;