summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/chromium
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics/chromium')
-rw-r--r--WebCore/platform/graphics/chromium/ColorChromium.cpp42
-rw-r--r--WebCore/platform/graphics/chromium/ColorChromiumMac.mm132
-rw-r--r--WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp2
-rw-r--r--WebCore/platform/graphics/chromium/FontCacheLinux.cpp46
-rw-r--r--WebCore/platform/graphics/chromium/FontChromiumWin.cpp43
-rw-r--r--WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp63
-rw-r--r--WebCore/platform/graphics/chromium/FontCustomPlatformData.h10
-rw-r--r--WebCore/platform/graphics/chromium/FontLinux.cpp496
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp9
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h5
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp51
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformDataLinux.h38
-rw-r--r--WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp5
-rw-r--r--WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp248
-rw-r--r--WebCore/platform/graphics/chromium/HarfbuzzSkia.h44
-rw-r--r--WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp6
-rw-r--r--WebCore/platform/graphics/chromium/TransparencyWin.cpp36
-rw-r--r--WebCore/platform/graphics/chromium/TransparencyWin.h11
18 files changed, 1034 insertions, 253 deletions
diff --git a/WebCore/platform/graphics/chromium/ColorChromium.cpp b/WebCore/platform/graphics/chromium/ColorChromium.cpp
deleted file mode 100644
index 647169c..0000000
--- a/WebCore/platform/graphics/chromium/ColorChromium.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2008 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Color.h"
-
-namespace WebCore {
-
-#if !PLATFORM(DARWIN)
-// On OS X, there's code to monitor changes in the focus color system setting.
-// On Windows/Linux there is no equivalent system setting and therefore a static
-// color is all we need.
-Color focusRingColor()
-{
- static Color focusRingColor(229, 151, 0, 255);
- return focusRingColor;
-}
-#endif
-
-} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/ColorChromiumMac.mm b/WebCore/platform/graphics/chromium/ColorChromiumMac.mm
deleted file mode 100644
index 01dff7e..0000000
--- a/WebCore/platform/graphics/chromium/ColorChromiumMac.mm
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Color.h"
-
-#import <AppKit/NSColor.h>
-#import <wtf/Assertions.h>
-#import <wtf/StdLibExtras.h>
-#import <wtf/RetainPtr.h>
-
-namespace WebCore {
-
-Color focusRingColor()
-{
- // To avoid the Mac Chromium build having to rebasline 500+ layout tests and
- // continue to do this w/ new tests that get landed in WebKit, we want to
- // run the layout tests w/ the same color that stock WebKit uses.
- //
- // FIXME: For now we've hard coded the color that WebKit uses for layout
- // tests. We need to revisit this and do either of the following:
- // A. Fully honor the color from the UI, which means collecting the color
- // (and change notifications) in the browser process, and messaging the
- // color to the render process.
- // B. Adding a "layout tests" flag, to control the orage vs. blue colors
- // depending if we're running layout tests.
- // To see the WebKit implementation of using the UI color and/or a flag for
- // layout tests see WebKit/WebCore/platform/graphics/mac/ColorMac.mm.
- // (Reality is we just need an api to override the focus color and both
- // of the above are covered for what this file needs to provide, the
- // two options would be details that happen in other places.)
-
- // From WebKit:
- // static RGBA32 oldAquaFocusRingColorRGBA = 0xFF7DADD9;
- static Color oldAquaFocusRingColor(0x7D, 0xAD, 0xD9, 0xFF);
- return oldAquaFocusRingColor;
-}
-
-// createCGColor() and the functions it calls are verbatum copies of
-// graphics/mac/ColorMac.mm. These are copied here so that we don't need to
-// include ColorMac.mm in the Chromium build.
-// FIXME: Check feasibility of using pure CG calls and unifying this copy with
-// ColorMac.mm's under graphics/cg.
-
-NSColor* nsColor(const Color& color)
-{
- unsigned c = color.rgb();
- switch (c) {
- case 0: {
- // Need this to avoid returning nil because cachedRGBAValues will default to 0.
- DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, clearColor, ([NSColor colorWithDeviceRed:0.0f green:0.0f blue:0.0f alpha:0.0f]));
- return clearColor.get();
- }
- case Color::black: {
- DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, blackColor, ([NSColor colorWithDeviceRed:0.0f green:0.0f blue:0.0f alpha:1.0f]));
- return blackColor.get();
- }
- case Color::white: {
- DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, whiteColor, ([NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:1.0f]));
- return whiteColor.get();
- }
- default: {
- const int cacheSize = 32;
- static unsigned cachedRGBAValues[cacheSize];
- static RetainPtr<NSColor>* cachedColors = new RetainPtr<NSColor>[cacheSize];
-
- for (int i = 0; i != cacheSize; ++i)
- if (cachedRGBAValues[i] == c)
- return cachedColors[i].get();
-
- NSColor* result = [NSColor colorWithDeviceRed:color.red() / 255.0f
- green:color.green() / 255.0f
- blue:color.blue() / 255.0f
- alpha:color.alpha() /255.0f];
-
- static int cursor;
- cachedRGBAValues[cursor] = c;
- cachedColors[cursor] = result;
- if (++cursor == cacheSize)
- cursor = 0;
- return result;
- }
- }
-}
-
-static CGColorRef CGColorFromNSColor(NSColor* color)
-{
- // This needs to always use device colorspace so it can de-calibrate the color for
- // CGColor to possibly recalibrate it.
- NSColor* deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
- CGFloat red = [deviceColor redComponent];
- CGFloat green = [deviceColor greenComponent];
- CGFloat blue = [deviceColor blueComponent];
- CGFloat alpha = [deviceColor alphaComponent];
- const CGFloat components[4] = { red, green, blue, alpha };
- static CGColorSpaceRef deviceRGBColorSpace = CGColorSpaceCreateDeviceRGB();
- CGColorRef cgColor = CGColorCreate(deviceRGBColorSpace, components);
- return cgColor;
-}
-
-CGColorRef createCGColor(const Color& c)
-{
- // We could directly create a CGColor here, but that would
- // skip any RGB caching the nsColor method does. A direct
- // creation could be investigated for a possible performance win.
- return CGColorFromNSColor(nsColor(c));
-}
-
-} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
index bf1cd2e..9252ae0 100644
--- a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
@@ -288,7 +288,7 @@ static bool fontContainsCharacter(const FontPlatformData* fontData,
if (count == 0 && ChromiumBridge::ensureFontLoaded(hfont))
count = GetFontUnicodeRanges(hdc, 0);
if (count == 0) {
- ASSERT_NOT_REACHED();
+ LOG_ERROR("Unable to get the font unicode range after second attempt");
SelectObject(hdc, oldFont);
ReleaseDC(0, hdc);
return true;
diff --git a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
index 797825e..3fe1561 100644
--- a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
@@ -31,9 +31,8 @@
#include "config.h"
#include "FontCache.h"
-#include <fontconfig/fontconfig.h>
-
#include "AtomicString.h"
+#include "ChromiumBridge.h"
#include "CString.h"
#include "Font.h"
#include "FontDescription.h"
@@ -46,6 +45,7 @@
#include "SkTypeface.h"
#include "SkUtils.h"
+#include <unicode/utf16.h>
#include <wtf/Assertions.h>
namespace WebCore {
@@ -58,38 +58,12 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font,
const UChar* characters,
int length)
{
- FcCharSet* cset = FcCharSetCreate();
- for (int i = 0; i < length; ++i)
- FcCharSetAddChar(cset, characters[i]);
-
- FcPattern* pattern = FcPatternCreate();
-
- FcValue fcvalue;
- fcvalue.type = FcTypeCharSet;
- fcvalue.u.c = cset;
- FcPatternAdd(pattern, FC_CHARSET, fcvalue, 0);
-
- FcConfigSubstitute(0, pattern, FcMatchPattern);
- FcDefaultSubstitute(pattern);
-
- FcResult result;
- FcPattern* match = FcFontMatch(0, pattern, &result);
- FcPatternDestroy(pattern);
-
- SimpleFontData* ret = 0;
-
- if (match) {
- FcChar8* family;
- if (FcPatternGetString(match, FC_FAMILY, 0, &family) == FcResultMatch) {
- AtomicString fontFamily(reinterpret_cast<char*>(family));
- ret = getCachedFontData(getCachedFontPlatformData(font.fontDescription(), fontFamily, false));
- }
- FcPatternDestroy(match);
- }
-
- FcCharSetDestroy(cset);
+ String family = ChromiumBridge::getFontFamilyForCharacters(characters, length);
+ if (family.isEmpty())
+ return 0;
- return ret;
+ AtomicString atomicFamily(family);
+ return getCachedFontData(getCachedFontPlatformData(font.fontDescription(), atomicFamily, false));
}
FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
@@ -165,13 +139,7 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
if (fontDescription.italic())
style |= SkTypeface::kItalic;
- // FIXME: This #ifdef can go away once we're firmly using the new Skia.
- // During the transition, this makes the code compatible with both versions.
-#ifdef SK_USE_OLD_255_TO_256
SkTypeface* tf = SkTypeface::CreateFromName(name, static_cast<SkTypeface::Style>(style));
-#else
- SkTypeface* tf = SkTypeface::Create(name, static_cast<SkTypeface::Style>(style));
-#endif
if (!tf)
return 0;
diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
index 4710245..3d67992 100644
--- a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
@@ -146,17 +146,23 @@ void TransparencyAwareFontPainter::initializeForGDI()
// know everything is opaque so don't need to do anything special.
layerMode = TransparencyWin::NoLayer;
}
- m_transparency.init(m_graphicsContext, layerMode, TransparencyWin::KeepTransform, layerRect);
+
+ // Bug 26088 - init() might fail if layerRect is invalid. Given this, we
+ // need to be careful to check for null pointers everywhere after this call
+ m_transparency.init(m_graphicsContext, layerMode,
+ TransparencyWin::KeepTransform, layerRect);
// Set up the DC, using the one from the transparency helper.
- m_hdc = m_transparency.platformContext()->canvas()->beginPlatformPaint();
- SetTextColor(m_hdc, skia::SkColorToCOLORREF(color));
- SetBkMode(m_hdc, TRANSPARENT);
+ if (m_transparency.platformContext()) {
+ m_hdc = m_transparency.platformContext()->canvas()->beginPlatformPaint();
+ SetTextColor(m_hdc, skia::SkColorToCOLORREF(color));
+ SetBkMode(m_hdc, TRANSPARENT);
+ }
}
TransparencyAwareFontPainter::~TransparencyAwareFontPainter()
{
- if (!m_useGDI)
+ if (!m_useGDI || !m_graphicsContext || !m_platformContext)
return; // Nothing to do.
m_transparency.composite();
if (m_createdTransparencyLayer)
@@ -208,12 +214,13 @@ TransparencyAwareGlyphPainter::TransparencyAwareGlyphPainter(
{
init();
- m_oldFont = ::SelectObject(m_hdc, m_font->platformData().hfont());
+ if (m_hdc)
+ m_oldFont = ::SelectObject(m_hdc, m_font->platformData().hfont());
}
TransparencyAwareGlyphPainter::~TransparencyAwareGlyphPainter()
{
- if (m_useGDI)
+ if (m_useGDI && m_hdc)
::SelectObject(m_hdc, m_oldFont);
}
@@ -245,6 +252,9 @@ bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs,
numGlyphs, glyphs, advances, 0, &origin);
}
+ if (!m_graphicsContext || !m_hdc)
+ return true;
+
// Windows' origin is the top-left of the bounding box, so we have
// to subtract off the font ascent to get it.
int x = lroundf(m_point.x() + startAdvance);
@@ -265,7 +275,7 @@ bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs,
COLORREF savedTextColor = GetTextColor(m_hdc);
SetTextColor(m_hdc, textColor);
ExtTextOut(m_hdc, x + shadowSize.width(), y + shadowSize.height(), ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
- SetTextColor(m_hdc, savedTextColor);
+ SetTextColor(m_hdc, savedTextColor);
}
return !!ExtTextOut(m_hdc, x, y, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
@@ -379,6 +389,17 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext,
for (int i = 0; i < curLen; ++i, ++glyphIndex) {
glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex);
advances[i] = static_cast<int>(glyphBuffer.advanceAt(from + glyphIndex));
+
+ // Bug 26088 - very large positive or negative runs can fail to
+ // render so we clamp the size here. In the specs, negative
+ // letter-spacing is implementation-defined, so this should be
+ // fine, and it matches Safari's implementation. The call actually
+ // seems to crash if kMaxNegativeRun is set to somewhere around
+ // -32830, so we give ourselves a little breathing room.
+ const int maxNegativeRun = -32768;
+ const int maxPositiveRun = 32768;
+ if ((curWidth + advances[i] < maxNegativeRun) || (curWidth + advances[i] > maxPositiveRun))
+ advances[i] = 0;
curWidth += advances[i];
}
@@ -394,7 +415,9 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext,
break;
}
- ASSERT(success);
+ if (!success)
+ LOG_ERROR("Unable to draw the glyphs after second attempt");
+
curAdvance += curWidth;
}
}
@@ -436,6 +459,8 @@ void Font::drawComplexText(GraphicsContext* graphicsContext,
TransparencyAwareUniscribePainter painter(graphicsContext, this, run, from, to, point);
HDC hdc = painter.hdc();
+ if (!hdc)
+ return;
// TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
// Enforce non-transparent color.
diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
index e99c12a..88035d5 100644
--- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
@@ -36,6 +36,8 @@
#include "Base64.h"
#include "ChromiumBridge.h"
#include "OpenTypeUtilities.h"
+#elif PLATFORM(LINUX)
+#include "SkStream.h"
#endif
#include "FontPlatformData.h"
@@ -46,6 +48,8 @@
#include <objbase.h>
#include <t2embapi.h>
#pragma comment(lib, "t2embed")
+#elif PLATFORM(LINUX)
+#include <cstring>
#endif
namespace WebCore {
@@ -60,6 +64,9 @@ FontCustomPlatformData::~FontCustomPlatformData()
} else
RemoveFontMemResourceEx(m_fontReference);
}
+#elif PLATFORM(LINUX)
+ if (m_fontReference)
+ m_fontReference->unref();
#endif
}
@@ -102,6 +109,9 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b
HFONT hfont = CreateFontIndirect(&logFont);
return FontPlatformData(hfont, size);
+#elif PLATFORM(LINUX)
+ ASSERT(m_fontReference);
+ return FontPlatformData(m_fontReference, size, bold && !m_fontReference->isBold(), italic && !m_fontReference->isItalic());
#else
notImplemented();
return FontPlatformData();
@@ -186,6 +196,51 @@ static String createUniqueFontName()
}
#endif
+#if PLATFORM(LINUX)
+class RemoteFontStream : public SkStream {
+public:
+ explicit RemoteFontStream(PassRefPtr<SharedBuffer> buffer)
+ : m_buffer(buffer)
+ , m_offset(0)
+ {
+ }
+
+ virtual ~RemoteFontStream()
+ {
+ }
+
+ virtual bool rewind()
+ {
+ m_offset = 0;
+ return true;
+ }
+
+ virtual size_t read(void* buffer, size_t size)
+ {
+ if (!buffer && !size) {
+ // This is request for the length of the stream.
+ return m_buffer->size();
+ }
+ if (!buffer) {
+ // This is a request to skip bytes. This operation is not supported.
+ return 0;
+ }
+ // This is a request to read bytes.
+ if (!m_buffer->data() || !m_buffer->size())
+ return 0;
+ size_t left = m_buffer->size() - m_offset;
+ size_t toRead = (left > size) ? size : left;
+ std::memcpy(buffer, m_buffer->data() + m_offset, toRead);
+ m_offset += toRead;
+ return toRead;
+ }
+
+private:
+ RefPtr<SharedBuffer> m_buffer;
+ size_t m_offset;
+};
+#endif
+
FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
{
ASSERT_ARG(buffer, buffer);
@@ -223,8 +278,14 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
}
return new FontCustomPlatformData(fontReference, fontName);
+#elif PLATFORM(LINUX)
+ RemoteFontStream stream(buffer);
+ SkTypeface* typeface = SkTypeface::CreateFromStream(&stream);
+ if (!typeface)
+ return 0;
+ return new FontCustomPlatformData(typeface);
#else
- notImplemented();;
+ notImplemented();
return 0;
#endif
}
diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.h b/WebCore/platform/graphics/chromium/FontCustomPlatformData.h
index 2f1a597..a42f1ec 100644
--- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.h
+++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.h
@@ -32,12 +32,14 @@
#ifndef FontCustomPlatformData_h
#define FontCustomPlatformData_h
+#include "FontRenderingMode.h"
#include <wtf/Noncopyable.h>
#if PLATFORM(WIN_OS)
-#include "FontRenderingMode.h"
#include "PlatformString.h"
#include <windows.h>
+#elif PLATFORM(LINUX)
+#include "SkTypeface.h"
#endif
namespace WebCore {
@@ -51,6 +53,10 @@ struct FontCustomPlatformData : Noncopyable {
: m_fontReference(fontReference)
, m_name(name)
{}
+#elif PLATFORM(LINUX)
+ explicit FontCustomPlatformData(SkTypeface* typeface)
+ : m_fontReference(typeface)
+ {}
#endif
~FontCustomPlatformData();
@@ -61,6 +67,8 @@ struct FontCustomPlatformData : Noncopyable {
#if PLATFORM(WIN_OS)
HANDLE m_fontReference;
String m_name;
+#elif PLATFORM(LINUX)
+ SkTypeface* m_fontReference;
#endif
};
diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp
index a952685..d4e45fb 100644
--- a/WebCore/platform/graphics/chromium/FontLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontLinux.cpp
@@ -34,6 +34,7 @@
#include "FloatRect.h"
#include "GlyphBuffer.h"
#include "GraphicsContext.h"
+#include "HarfbuzzSkia.h"
#include "NotImplemented.h"
#include "PlatformContextSkia.h"
#include "SimpleFontData.h"
@@ -54,7 +55,7 @@ bool Font::canReturnFallbackFontsForComplexText()
void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
const GlyphBuffer& glyphBuffer, int from, int numGlyphs,
const FloatPoint& point) const {
- SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
+ SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
SkScalar x = SkFloatToScalar(point.x());
@@ -96,7 +97,6 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
SkPaint paint;
gc->platformContext()->setupPaintForStroking(&paint, 0, 0);
font->platformData().setupPaint(&paint);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setColor(gc->strokeColor().rgb());
@@ -110,31 +110,503 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
}
}
-void Font::drawComplexText(GraphicsContext* context, const TextRun& run,
+// Harfbuzz uses 26.6 fixed point values for pixel offsets. However, we don't
+// handle subpixel positioning so this function is used to truncate Harfbuzz
+// values to a number of pixels.
+static int truncateFixedPointToInteger(HB_Fixed value)
+{
+ return value >> 6;
+}
+
+// TextRunWalker walks a TextRun and presents each script run in sequence. A
+// TextRun is a sequence of code-points with the same embedding level (i.e. they
+// are all left-to-right or right-to-left). A script run is a subsequence where
+// all the characters have the same script (e.g. Arabic, Thai etc). Shaping is
+// only ever done with script runs since the shapers only know how to deal with
+// a single script.
+//
+// After creating it, the script runs are either iterated backwards or forwards.
+// It defaults to backwards for RTL and forwards otherwise (which matches the
+// presentation order), however you can set it with |setBackwardsIteration|.
+//
+// Once you have setup the object, call |nextScriptRun| to get the first script
+// run. This will return false when the iteration is complete. At any time you
+// can call |reset| to start over again.
+class TextRunWalker {
+public:
+ TextRunWalker(const TextRun& run, unsigned startingX, const Font* font)
+ : m_font(font)
+ , m_run(run)
+ , m_startingX(startingX)
+ , m_offsetX(m_startingX)
+ , m_iterateBackwards(run.rtl())
+ {
+ memset(&m_item, 0, sizeof(m_item));
+ // We cannot know, ahead of time, how many glyphs a given script run
+ // will produce. We take a guess that script runs will not produce more
+ // than twice as many glyphs as there are code points and fallback if
+ // we find that we are wrong.
+ m_maxGlyphs = run.length() * 2;
+ createGlyphArrays();
+
+ m_item.log_clusters = new unsigned short[run.length()];
+
+ m_item.face = 0;
+ m_item.font = allocHarfbuzzFont();
+
+ m_item.string = run.characters();
+ m_item.stringLength = run.length();
+ m_item.item.bidiLevel = run.rtl();
+
+ reset();
+ }
+
+ ~TextRunWalker()
+ {
+ fastFree(m_item.font);
+ deleteGlyphArrays();
+ delete[] m_item.log_clusters;
+ }
+
+ void reset()
+ {
+ if (m_iterateBackwards)
+ m_indexOfNextScriptRun = m_run.length() - 1;
+ else
+ m_indexOfNextScriptRun = 0;
+ m_offsetX = m_startingX;
+ }
+
+ // Set the x offset for the next script run. This affects the values in
+ // |xPositions|
+ void setXOffsetToZero()
+ {
+ m_offsetX = 0;
+ }
+
+ bool rtl() const
+ {
+ return m_run.rtl();
+ }
+
+ void setBackwardsIteration(bool isBackwards)
+ {
+ m_iterateBackwards = isBackwards;
+ reset();
+ }
+
+ // Advance to the next script run, returning false when the end of the
+ // TextRun has been reached.
+ bool nextScriptRun()
+ {
+ if (m_iterateBackwards) {
+ // In right-to-left mode we need to render the shaped glyph backwards and
+ // also render the script runs themselves backwards. So given a TextRun:
+ // AAAAAAACTTTTTTT (A = Arabic, C = Common, T = Thai)
+ // we render:
+ // TTTTTTCAAAAAAA
+ // (and the glyphs in each A, C and T section are backwards too)
+ if (!hb_utf16_script_run_prev(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun))
+ return false;
+ } else {
+ if (!hb_utf16_script_run_next(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun))
+ return false;
+ }
+
+ setupFontForScriptRun();
+
+ if (!shapeGlyphs())
+ return false;
+ setGlyphXPositions(rtl());
+ return true;
+ }
+
+ const uint16_t* glyphs() const
+ {
+ return m_glyphs16;
+ }
+
+ // Return the length of the array returned by |glyphs|
+ const unsigned length() const
+ {
+ return m_item.num_glyphs;
+ }
+
+ // Return the x offset for each of the glyphs. Note that this is translated
+ // by the current x offset and that the x offset is updated for each script
+ // run.
+ const SkScalar* xPositions() const
+ {
+ return m_xPositions;
+ }
+
+ // Get the advances (widths) for each glyph.
+ const HB_Fixed* advances() const
+ {
+ return m_item.advances;
+ }
+
+ // Return the width (in px) of the current script run.
+ const unsigned width() const
+ {
+ return m_pixelWidth;
+ }
+
+ // Return the cluster log for the current script run. For example:
+ // script run: f i a n c é (fi gets ligatured)
+ // log clutrs: 0 0 1 2 3 4
+ // So, for each input code point, the log tells you which output glyph was
+ // generated for it.
+ const unsigned short* logClusters() const
+ {
+ return m_item.log_clusters;
+ }
+
+ // return the number of code points in the current script run
+ const unsigned numCodePoints() const
+ {
+ return m_numCodePoints;
+ }
+
+ const FontPlatformData* fontPlatformDataForScriptRun()
+ {
+ return reinterpret_cast<FontPlatformData*>(m_item.font->userData);
+ }
+
+ float widthOfFullRun()
+ {
+ float widthSum = 0;
+ while (nextScriptRun())
+ widthSum += width();
+
+ return widthSum;
+ }
+
+private:
+ void setupFontForScriptRun()
+ {
+ const FontData* fontData = m_font->fontDataAt(0);
+ if (!fontData->containsCharacters(m_item.string + m_item.item.pos, m_item.item.length))
+ fontData = m_font->fontDataForCharacters(m_item.string + m_item.item.pos, m_item.item.length);
+ const FontPlatformData& platformData = fontData->fontDataForCharacter(' ')->platformData();
+ m_item.face = platformData.harfbuzzFace();
+ void* opaquePlatformData = const_cast<FontPlatformData*>(&platformData);
+ m_item.font->userData = opaquePlatformData;
+ }
+
+ HB_FontRec* allocHarfbuzzFont()
+ {
+ HB_FontRec* font = reinterpret_cast<HB_FontRec*>(fastMalloc(sizeof(HB_FontRec)));
+ memset(font, 0, sizeof(HB_FontRec));
+ font->klass = &harfbuzzSkiaClass;
+ font->userData = 0;
+ // The values which harfbuzzSkiaClass returns are already scaled to
+ // pixel units, so we just set all these to one to disable further
+ // scaling.
+ font->x_ppem = 1;
+ font->y_ppem = 1;
+ font->x_scale = 1;
+ font->y_scale = 1;
+
+ return font;
+ }
+
+ void deleteGlyphArrays()
+ {
+ delete[] m_item.glyphs;
+ delete[] m_item.attributes;
+ delete[] m_item.advances;
+ delete[] m_item.offsets;
+ delete[] m_glyphs16;
+ delete[] m_xPositions;
+ }
+
+ bool createGlyphArrays()
+ {
+ m_item.glyphs = new HB_Glyph[m_maxGlyphs];
+ m_item.attributes = new HB_GlyphAttributes[m_maxGlyphs];
+ m_item.advances = new HB_Fixed[m_maxGlyphs];
+ m_item.offsets = new HB_FixedPoint[m_maxGlyphs];
+ m_glyphs16 = new uint16_t[m_maxGlyphs];
+ m_xPositions = new SkScalar[m_maxGlyphs];
+
+ return m_item.glyphs
+ && m_item.attributes
+ && m_item.advances
+ && m_item.offsets
+ && m_glyphs16
+ && m_xPositions;
+ }
+
+ bool expandGlyphArrays()
+ {
+ deleteGlyphArrays();
+ m_maxGlyphs <<= 1;
+ return createGlyphArrays();
+ }
+
+ bool shapeGlyphs()
+ {
+ for (;;) {
+ m_item.num_glyphs = m_maxGlyphs;
+ HB_ShapeItem(&m_item);
+ if (m_item.num_glyphs < m_maxGlyphs)
+ break;
+
+ // We overflowed our arrays. Resize and retry.
+ if (!expandGlyphArrays())
+ return false;
+ }
+
+ return true;
+ }
+
+ void setGlyphXPositions(bool isRTL)
+ {
+ m_pixelWidth = 0;
+ for (unsigned i = 0; i < m_item.num_glyphs; ++i) {
+ int index;
+ if (isRTL)
+ index = m_item.num_glyphs - (i + 1);
+ else
+ index = i;
+
+ m_glyphs16[i] = m_item.glyphs[i];
+ m_xPositions[index] = m_offsetX + m_pixelWidth;
+ m_pixelWidth += truncateFixedPointToInteger(m_item.advances[index]);
+ }
+ m_offsetX += m_pixelWidth;
+ }
+
+ const Font* const m_font;
+ const TextRun& m_run;
+ HB_ShaperItem m_item;
+ uint16_t* m_glyphs16; // A vector of 16-bit glyph ids.
+ SkScalar* m_xPositions; // A vector of x positions for each glyph.
+ ssize_t m_indexOfNextScriptRun; // Indexes the script run in |m_run|.
+ const unsigned m_startingX; // Offset in pixels of the first script run.
+ unsigned m_offsetX; // Offset in pixels to the start of the next script run.
+ unsigned m_pixelWidth; // Width (in px) of the current script run.
+ unsigned m_numCodePoints; // Code points in current script run.
+ unsigned m_maxGlyphs; // Current size of all the Harfbuzz arrays.
+ bool m_iterateBackwards;
+};
+
+static void setupForTextPainting(SkPaint* paint, SkColor color)
+{
+ paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint->setColor(color);
+}
+
+void Font::drawComplexText(GraphicsContext* gc, const TextRun& run,
const FloatPoint& point, int from, int to) const
{
- notImplemented();
+ if (!run.length())
+ return;
+
+ SkCanvas* canvas = gc->platformContext()->canvas();
+ int textMode = gc->platformContext()->getTextDrawingMode();
+ bool fill = textMode & cTextFill;
+ bool stroke = (textMode & cTextStroke)
+ && gc->platformContext()->getStrokeStyle() != NoStroke
+ && gc->platformContext()->getStrokeThickness() > 0;
+
+ if (!fill && !stroke)
+ return;
+
+ SkPaint strokePaint, fillPaint;
+ if (fill) {
+ gc->platformContext()->setupPaintForFilling(&fillPaint);
+ setupForTextPainting(&fillPaint, gc->fillColor().rgb());
+ }
+ if (stroke) {
+ gc->platformContext()->setupPaintForStroking(&strokePaint, 0, 0);
+ setupForTextPainting(&strokePaint, gc->strokeColor().rgb());
+ }
+
+ TextRunWalker walker(run, point.x(), this);
+
+ while (walker.nextScriptRun()) {
+ if (fill) {
+ walker.fontPlatformDataForScriptRun()->setupPaint(&fillPaint);
+ canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), fillPaint);
+ }
+
+ if (stroke) {
+ walker.fontPlatformDataForScriptRun()->setupPaint(&strokePaint);
+ canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), strokePaint);
+ }
+ }
}
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */) const
{
- notImplemented();
- return 0;
+ TextRunWalker walker(run, 0, this);
+ return walker.widthOfFullRun();
}
+static int glyphIndexForXPositionInScriptRun(const TextRunWalker& walker, int x)
+{
+ const HB_Fixed* advances = walker.advances();
+ int glyphIndex;
+ if (walker.rtl()) {
+ for (glyphIndex = walker.length() - 1; glyphIndex >= 0; --glyphIndex) {
+ if (x < truncateFixedPointToInteger(advances[glyphIndex]))
+ break;
+ x -= truncateFixedPointToInteger(advances[glyphIndex]);
+ }
+ } else {
+ for (glyphIndex = 0; glyphIndex < walker.length(); ++glyphIndex) {
+ if (x < truncateFixedPointToInteger(advances[glyphIndex]))
+ break;
+ x -= truncateFixedPointToInteger(advances[glyphIndex]);
+ }
+ }
+
+ return glyphIndex;
+}
+
+// Return the code point index for the given |x| offset into the text run.
int Font::offsetForPositionForComplexText(const TextRun& run, int x,
bool includePartialGlyphs) const
{
- notImplemented();
- return 0;
+ // (Mac code ignores includePartialGlyphs, and they don't know what it's
+ // supposed to do, so we just ignore it as well.)
+ TextRunWalker walker(run, 0, this);
+
+ // If this is RTL text, the first glyph from the left is actually the last
+ // code point. So we need to know how many code points there are total in
+ // order to subtract. This is different from the length of the TextRun
+ // because UTF-16 surrogate pairs are a single code point, but 32-bits long.
+ // In LTR we leave this as 0 so that we get the correct value for
+ // |basePosition|, below.
+ unsigned totalCodePoints = 0;
+ if (walker.rtl()) {
+ ssize_t offset = 0;
+ while (offset < run.length()) {
+ utf16_to_code_point(run.characters(), run.length(), &offset);
+ totalCodePoints++;
+ }
+ }
+
+ unsigned basePosition = totalCodePoints;
+
+ // For RTL:
+ // code-point order: abcd efg hijkl
+ // on screen: lkjih gfe dcba
+ // ^ ^
+ // | |
+ // basePosition--| |
+ // totalCodePoints----|
+ // Since basePosition is currently the total number of code-points, the
+ // first thing we do is decrement it so that it's pointing to the start of
+ // the current script-run.
+ //
+ // For LTR, basePosition is zero so it already points to the start of the
+ // first script run.
+ while (walker.nextScriptRun()) {
+ if (walker.rtl())
+ basePosition -= walker.numCodePoints();
+
+ if (x < walker.width()) {
+ // The x value in question is within this script run. We consider
+ // each glyph in presentation order and stop when we find the one
+ // covering this position.
+ const int glyphIndex = glyphIndexForXPositionInScriptRun(walker, x);
+
+ // Now that we have a glyph index, we have to turn that into a
+ // code-point index. Because of ligatures, several code-points may
+ // have gone into a single glyph. We iterate over the clusters log
+ // and find the first code-point which contributed to the glyph.
+
+ // Some shapers (i.e. Khmer) will produce cluster logs which report
+ // that /no/ code points contributed to certain glyphs. Because of
+ // this, we take any code point which contributed to the glyph in
+ // question, or any subsequent glyph. If we run off the end, then
+ // we take the last code point.
+ const unsigned short* log = walker.logClusters();
+ for (unsigned j = 0; j < walker.numCodePoints(); ++j) {
+ if (log[j] >= glyphIndex)
+ return basePosition + j;
+ }
+
+ return basePosition + walker.numCodePoints() - 1;
+ }
+
+ x -= walker.width();
+
+ if (!walker.rtl())
+ basePosition += walker.numCodePoints();
+ }
+
+ return basePosition;
}
+// Return the rectangle for selecting the given range of code-points in the TextRun.
FloatRect Font::selectionRectForComplexText(const TextRun& run,
- const IntPoint& point, int h,
+ const IntPoint& point, int height,
int from, int to) const
{
- notImplemented();
- return FloatRect();
+ int fromX = -1, toX = -1, fromAdvance = -1, toAdvance = -1;
+ TextRunWalker walker(run, 0, this);
+
+ // Base will point to the x offset for the current script run. Note that, in
+ // the LTR case, width will be 0.
+ int base = walker.rtl() ? walker.widthOfFullRun() : 0;
+ const int leftEdge = base;
+
+ // We want to enumerate the script runs in code point order in the following
+ // code. This call also resets |walker|.
+ walker.setBackwardsIteration(false);
+
+ while (walker.nextScriptRun() && (fromX == -1 || toX == -1)) {
+ // TextRunWalker will helpfully accululate the x offsets for different
+ // script runs for us. For this code, however, we always want the x offsets
+ // to start from zero so we call this before each script run.
+ walker.setXOffsetToZero();
+
+ if (walker.rtl())
+ base -= walker.width();
+
+ if (fromX == -1 && from < walker.numCodePoints()) {
+ // |from| is within this script run. So we index the clusters log to
+ // find which glyph this code-point contributed to and find its x
+ // position.
+ int glyph = walker.logClusters()[from];
+ fromX = base + walker.xPositions()[glyph];
+ fromAdvance = walker.advances()[glyph];
+ } else
+ from -= walker.numCodePoints();
+
+ if (toX == -1 && to < walker.numCodePoints()) {
+ int glyph = walker.logClusters()[to];
+ toX = base + walker.xPositions()[glyph];
+ toAdvance = walker.advances()[glyph];
+ } else
+ to -= walker.numCodePoints();
+
+ if (!walker.rtl())
+ base += walker.width();
+ }
+
+ // The position in question might be just after the text.
+ const int rightEdge = base;
+ if (fromX == -1 && !from)
+ fromX = leftEdge;
+ else if (walker.rtl())
+ fromX += truncateFixedPointToInteger(fromAdvance);
+
+ if (toX == -1 && !to)
+ toX = rightEdge;
+ else if (!walker.rtl())
+ toX += truncateFixedPointToInteger(toAdvance);
+
+ ASSERT(fromX != -1 && toX != -1);
+
+ if (fromX < toX)
+ return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
+
+ return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
}
-} // namespace WebCore
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp
index 767fe76..d6c83ec 100644
--- a/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp
@@ -141,7 +141,7 @@ SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const
hr = ScriptGetFontProperties(dc, scriptCache(),
m_scriptFontProperties);
if (S_OK != hr) {
- ASSERT_NOT_REACHED();
+ LOG_ERROR("Unable to get the font properties after second attempt");
}
}
}
@@ -153,4 +153,11 @@ SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const
return m_scriptFontProperties;
}
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
}
diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h
index ce15a93..25c9cf8 100644
--- a/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h
+++ b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h
@@ -45,6 +45,7 @@ typedef struct HFONT__ *HFONT;
namespace WebCore {
class FontDescription;
+class String;
class FontPlatformData {
public:
@@ -78,6 +79,10 @@ public:
return m_font == other.m_font && m_size == other.m_size;
}
+#ifndef NDEBUG
+ String description() const;
+#endif
+
SCRIPT_FONTPROPERTIES* scriptFontProperties() const;
SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; }
diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
index e6a61f6..bf4697f 100644
--- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
@@ -31,19 +31,45 @@
#include "config.h"
#include "FontPlatformData.h"
-#include "StringImpl.h"
+#include "HarfbuzzSkia.h"
#include "NotImplemented.h"
+#include "PlatformString.h"
+#include "StringImpl.h"
#include "SkPaint.h"
#include "SkTypeface.h"
namespace WebCore {
+static SkPaint::Hinting skiaHinting = SkPaint::kNormal_Hinting;
+static bool isSkiaAntiAlias = true, isSkiaSubpixelGlyphs;
+
+void FontPlatformData::setHinting(SkPaint::Hinting hinting)
+{
+ skiaHinting = hinting;
+}
+
+void FontPlatformData::setAntiAlias(bool isAntiAlias)
+{
+ isSkiaAntiAlias = isAntiAlias;
+}
+
+void FontPlatformData::setSubpixelGlyphs(bool isSubpixelGlyphs)
+{
+ isSkiaSubpixelGlyphs = isSubpixelGlyphs;
+}
+
+FontPlatformData::RefCountedHarfbuzzFace::~RefCountedHarfbuzzFace()
+{
+ HB_FreeFace(m_harfbuzzFace);
+}
+
FontPlatformData::FontPlatformData(const FontPlatformData& src)
: m_typeface(src.m_typeface)
, m_textSize(src.m_textSize)
, m_fakeBold(src.m_fakeBold)
, m_fakeItalic(src.m_fakeItalic)
+ , m_harfbuzzFace(src.m_harfbuzzFace)
{
m_typeface->safeRef();
}
@@ -62,6 +88,7 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize)
, m_textSize(textSize)
, m_fakeBold(src.m_fakeBold)
, m_fakeItalic(src.m_fakeItalic)
+ , m_harfbuzzFace(src.m_harfbuzzFace)
{
m_typeface->safeRef();
}
@@ -78,21 +105,29 @@ FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src)
m_textSize = src.m_textSize;
m_fakeBold = src.m_fakeBold;
m_fakeItalic = src.m_fakeItalic;
+ m_harfbuzzFace = src.m_harfbuzzFace;
return *this;
}
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
void FontPlatformData::setupPaint(SkPaint* paint) const
{
const float ts = m_textSize > 0 ? m_textSize : 12;
- paint->setAntiAlias(true);
- paint->setSubpixelText(false);
+ paint->setAntiAlias(isSkiaAntiAlias);
+ paint->setHinting(skiaHinting);
+ paint->setLCDRenderText(isSkiaSubpixelGlyphs);
paint->setTextSize(SkFloatToScalar(ts));
paint->setTypeface(m_typeface);
paint->setFakeBoldText(m_fakeBold);
paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0);
- paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
}
SkFontID FontPlatformData::uniqueID() const
@@ -141,4 +176,12 @@ bool FontPlatformData::isFixedPitch() const
return false;
}
+HB_FaceRec_* FontPlatformData::harfbuzzFace() const
+{
+ if (!m_harfbuzzFace)
+ m_harfbuzzFace = RefCountedHarfbuzzFace::create(HB_NewFace(const_cast<FontPlatformData*>(this), harfbuzzSkiaGetTable));
+
+ return m_harfbuzzFace->face();
+}
+
} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h
index c63a860..29ce8e7 100644
--- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h
+++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h
@@ -33,14 +33,17 @@
#include "StringImpl.h"
#include <wtf/RefPtr.h>
+#include <SkPaint.h>
-class SkPaint;
class SkTypeface;
typedef uint32_t SkFontID;
+struct HB_FaceRec_;
+
namespace WebCore {
class FontDescription;
+class String;
// -----------------------------------------------------------------------------
// FontPlatformData is the handle which WebKit has on a specific face. A face
@@ -104,12 +107,45 @@ public:
FontPlatformData& operator=(const FontPlatformData&);
bool isHashTableDeletedValue() const { return m_typeface == hashTableDeletedFontValue(); }
+#ifndef NDEBUG
+ String description() const;
+#endif
+
+ HB_FaceRec_* harfbuzzFace() const;
+
+ // -------------------------------------------------------------------------
+ // Global font preferences...
+
+ static void setHinting(SkPaint::Hinting);
+ static void setAntiAlias(bool on);
+ static void setSubpixelGlyphs(bool on);
+
private:
+ class RefCountedHarfbuzzFace : public RefCounted<RefCountedHarfbuzzFace> {
+ public:
+ static PassRefPtr<RefCountedHarfbuzzFace> create(HB_FaceRec_* harfbuzzFace)
+ {
+ return adoptRef(new RefCountedHarfbuzzFace(harfbuzzFace));
+ }
+
+ ~RefCountedHarfbuzzFace();
+
+ HB_FaceRec_* face() const { return m_harfbuzzFace; }
+
+ private:
+ RefCountedHarfbuzzFace(HB_FaceRec_* harfbuzzFace) : m_harfbuzzFace(harfbuzzFace)
+ {
+ }
+
+ HB_FaceRec_* m_harfbuzzFace;
+ };
+
// FIXME: Could SkAutoUnref be used here?
SkTypeface* m_typeface;
float m_textSize;
bool m_fakeBold;
bool m_fakeItalic;
+ mutable RefPtr<RefCountedHarfbuzzFace> m_harfbuzzFace;
SkTypeface* hashTableDeletedFontValue() const { return reinterpret_cast<SkTypeface*>(-1); }
};
diff --git a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
index 2cb1cc5..e2c47c1 100644
--- a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
@@ -87,10 +87,9 @@ static bool fillBMPGlyphs(unsigned offset,
return false;
}
} else {
- // FIXME: This should never happen. We want to crash the
- // process and receive a crash dump. We should revisit this code later.
+ // FIXME: Handle gracefully the error if this call also fails.
// See http://crbug.com/6401
- ASSERT_NOT_REACHED();
+ LOG_ERROR("Unable to get the text metrics after second attempt");
fillEmptyGlyphs(page);
return false;
}
diff --git a/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp b/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp
new file mode 100644
index 0000000..621d674
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Font.h"
+#include "FontPlatformData.h"
+#include "wtf/OwnArrayPtr.h"
+
+#include "SkFontHost.h"
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkPoint.h"
+#include "SkRect.h"
+
+extern "C" {
+#include "harfbuzz-shaper.h"
+#include "harfbuzz-unicode.h"
+}
+
+// This file implements the callbacks which Harfbuzz requires by using Skia
+// calls. See the Harfbuzz source for references about what these callbacks do.
+
+namespace WebCore {
+
+static HB_Fixed SkiaScalarToHarfbuzzFixed(SkScalar value)
+{
+ // HB_Fixed is a 26.6 fixed point format.
+ return value * 64;
+}
+
+static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length, HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), reinterpret_cast<uint16_t*>(glyphs));
+
+ // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our
+ // |glyphs| array needs to be converted.
+ // Additionally, if the CSS white-space property is inhibiting line
+ // breaking, we might find end-of-line charactors rendered via the complex
+ // text path. Fonts don't provide glyphs for these code points so, if we
+ // find one, we simulate the space glyph being interposed in this case.
+ // Because the input is variable-length per code point, we walk the input
+ // in step with the output.
+ // FIXME: it seems that this logic is duplicated in CoreTextController and UniscribeController
+ ssize_t indexOfNextCodePoint = 0;
+ uint16_t spaceGlyphNumber = 0;
+ for (int i = numGlyphs - 1; i >= 0; --i) {
+ const uint32_t currentCodePoint = utf16_to_code_point(characters, length, &indexOfNextCodePoint);
+
+ uint16_t value;
+ // We use a memcpy to avoid breaking strict aliasing rules.
+ memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(uint16_t));
+
+ if (!value && Font::treatAsSpace(currentCodePoint)) {
+ static const uint16_t spaceUTF16 = ' ';
+ if (!spaceGlyphNumber)
+ paint.textToGlyphs(&spaceUTF16, sizeof(spaceUTF16), &spaceGlyphNumber);
+ value = spaceGlyphNumber;
+ }
+
+ glyphs[i] = value;
+ }
+
+ *glyphsSize = numGlyphs;
+ return 1;
+}
+
+static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs, HB_Fixed* advances, int flags)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ OwnArrayPtr<uint16_t> glyphs16(new uint16_t[numGlyphs]);
+ if (!glyphs16.get())
+ return;
+ for (unsigned i = 0; i < numGlyphs; ++i)
+ glyphs16[i] = glyphs[i];
+ paint.getTextWidths(glyphs16.get(), numGlyphs * sizeof(uint16_t), reinterpret_cast<SkScalar*>(advances));
+
+ // The |advances| values which Skia outputs are SkScalars, which are floats
+ // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format.
+ // These two formats are both 32-bits long.
+ for (unsigned i = 0; i < numGlyphs; ++i) {
+ float value;
+ // We use a memcpy to avoid breaking strict aliasing rules.
+ memcpy(&value, reinterpret_cast<char*>(advances) + sizeof(float) * i, sizeof(float));
+ advances[i] = SkiaScalarToHarfbuzzFixed(value);
+ }
+}
+
+static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ OwnArrayPtr<uint16_t> glyphs16(new uint16_t[length]);
+ if (!glyphs16.get())
+ return 0;
+ int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), glyphs16.get());
+
+ bool canRender = true;
+ for (int i = 0; i < numGlyphs; ++i) {
+ if (!glyphs16[i]) {
+ canRender = false;
+ break;
+ }
+ }
+
+ return canRender;
+}
+
+static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ if (flags & HB_ShaperFlag_UseDesignMetrics)
+ return HB_Err_Invalid_Argument; // This is requesting pre-hinted positions. We can't support this.
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ uint16_t glyph16 = glyph;
+ SkPath path;
+ paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path);
+ int numPoints = path.getPoints(NULL, 0);
+ if (point >= numPoints)
+ return HB_Err_Invalid_SubTable;
+ SkPoint* points = reinterpret_cast<SkPoint*>(fastMalloc(sizeof(SkPoint) * (point + 1)));
+ if (!points)
+ return HB_Err_Invalid_SubTable;
+ // Skia does let us get a single point from the path.
+ path.getPoints(points, point + 1);
+ *xPos = SkiaScalarToHarfbuzzFixed(points[point].fX);
+ *yPos = SkiaScalarToHarfbuzzFixed(points[point].fY);
+ *resultingNumPoints = numPoints;
+ fastFree(points);
+
+ return HB_Err_Ok;
+}
+
+static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ uint16_t glyph16 = glyph;
+ SkScalar width;
+ SkRect bounds;
+ paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
+
+ metrics->x = SkiaScalarToHarfbuzzFixed(width);
+ // We can't actually get the |y| correct because Skia doesn't export
+ // the vertical advance. However, nor we do ever render vertical text at
+ // the moment so it's unimportant.
+ metrics->y = 0;
+ metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width());
+ metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height());
+ metrics->xOffset = SkiaScalarToHarfbuzzFixed(bounds.fLeft);
+ metrics->yOffset = SkiaScalarToHarfbuzzFixed(bounds.fTop);
+}
+
+static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ SkPaint::FontMetrics skiaMetrics;
+ paint.getFontMetrics(&skiaMetrics);
+
+ switch (metric) {
+ case HB_FontAscent:
+ return SkiaScalarToHarfbuzzFixed(-skiaMetrics.fAscent);
+ // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them.
+ default:
+ return 0;
+ }
+}
+
+HB_FontClass harfbuzzSkiaClass = {
+ stringToGlyphs,
+ glyphsToAdvances,
+ canRender,
+ getOutlinePoint,
+ getGlyphMetrics,
+ getFontMetric,
+};
+
+HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(voidface);
+
+ const size_t tableSize = SkFontHost::GetTableSize(font->uniqueID(), tag);
+ if (!tableSize)
+ return HB_Err_Invalid_Argument;
+ // If Harfbuzz specified a NULL buffer then it's asking for the size of the table.
+ if (!buffer) {
+ *len = tableSize;
+ return HB_Err_Ok;
+ }
+
+ if (*len < tableSize)
+ return HB_Err_Invalid_Argument;
+ SkFontHost::GetTableData(font->uniqueID(), tag, 0, tableSize, buffer);
+ return HB_Err_Ok;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/HarfbuzzSkia.h b/WebCore/platform/graphics/chromium/HarfbuzzSkia.h
new file mode 100644
index 0000000..f7e0496
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/HarfbuzzSkia.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HarfbuzzSkia_h
+#define HarfbuzzSkia_h
+
+extern "C" {
+#include "harfbuzz-shaper.h"
+#include "harfbuzz-unicode.h"
+}
+
+namespace WebCore {
+ HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len);
+ extern const HB_FontClass harfbuzzSkiaClass;
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp
index 6f5ce90..3d68ea8 100644
--- a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp
@@ -63,7 +63,7 @@ void SimpleFontData::platformInit()
// FIXME: Handle gracefully the error if this call also fails.
// See http://crbug.com/6401.
if (!GetTextMetrics(dc, &textMetric))
- ASSERT_NOT_REACHED();
+ LOG_ERROR("Unable to get the text metrics after second attempt");
}
}
@@ -141,7 +141,7 @@ void SimpleFontData::determinePitch()
// FIXME: Handle gracefully the error if this call also fails.
// See http://crbug.com/6401.
if (!GetTextMetrics(dc, &textMetric))
- ASSERT_NOT_REACHED();
+ LOG_ERROR("Unable to get the text metrics after second attempt");
}
}
@@ -163,7 +163,7 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
// FIXME: Handle gracefully the error if this call also fails.
// See http://crbug.com/6401.
if (!GetCharWidthI(dc, glyph, 1, 0, &width))
- ASSERT_NOT_REACHED();
+ LOG_ERROR("Unable to get the char width after second attempt");
}
}
diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/WebCore/platform/graphics/chromium/TransparencyWin.cpp
index d3ced81..7957d5a 100644
--- a/WebCore/platform/graphics/chromium/TransparencyWin.cpp
+++ b/WebCore/platform/graphics/chromium/TransparencyWin.cpp
@@ -109,7 +109,7 @@ class TransparencyWin::OwnedBuffers {
public:
OwnedBuffers(const IntSize& size, bool needReferenceBuffer)
{
- m_destBitmap = ImageBuffer::create(size, false);
+ m_destBitmap = ImageBuffer::create(size);
if (needReferenceBuffer) {
m_referenceBitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
@@ -152,6 +152,7 @@ TransparencyWin::TransparencyWin()
, m_savedOnDrawContext(false)
, m_layerBuffer(0)
, m_referenceBitmap(0)
+ , m_validLayer(false)
{
}
@@ -237,11 +238,14 @@ void TransparencyWin::setupLayer()
void TransparencyWin::setupLayerForNoLayer()
{
m_drawContext = m_destContext; // Draw to the source context.
+ m_validLayer = true;
}
void TransparencyWin::setupLayerForOpaqueCompositeLayer()
{
initializeNewContext();
+ if (!m_validLayer)
+ return;
TransformationMatrix mapping;
mapping.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y());
@@ -268,6 +272,9 @@ void TransparencyWin::setupLayerForTextComposite()
void TransparencyWin::setupLayerForWhiteLayer()
{
initializeNewContext();
+ if (!m_validLayer)
+ return;
+
m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white);
// Layer rect represents the part of the original layer.
}
@@ -289,6 +296,9 @@ void TransparencyWin::setupTransform(const IntRect& region)
void TransparencyWin::setupTransformForKeepTransform(const IntRect& region)
{
+ if (!m_validLayer)
+ return;
+
if (m_layerMode != NoLayer) {
// Need to save things since we're modifying the transform.
m_drawContext->save();
@@ -319,6 +329,9 @@ void TransparencyWin::setupTransformForUntransform()
void TransparencyWin::setupTransformForScaleTransform()
{
+ if (!m_validLayer)
+ return;
+
if (m_layerMode == NoLayer) {
// Need to save things since we're modifying the layer.
m_drawContext->save();
@@ -345,16 +358,22 @@ void TransparencyWin::setTextCompositeColor(Color color)
void TransparencyWin::initializeNewContext()
{
int pixelSize = m_layerSize.width() * m_layerSize.height();
+ if (pixelSize <= 0)
+ return;
+
if (pixelSize > maxCachedBufferPixelSize) {
// Create a 1-off buffer for drawing into. We only need the reference
// buffer if we're making an OpaqueCompositeLayer.
bool needReferenceBitmap = m_layerMode == OpaqueCompositeLayer;
m_ownedBuffers.set(new OwnedBuffers(m_layerSize, needReferenceBitmap));
-
m_layerBuffer = m_ownedBuffers->destBitmap();
+ if (!m_layerBuffer)
+ return;
+
m_drawContext = m_layerBuffer->context();
if (needReferenceBitmap)
m_referenceBitmap = m_ownedBuffers->referenceBitmap();
+ m_validLayer = true;
return;
}
@@ -366,6 +385,7 @@ void TransparencyWin::initializeNewContext()
bitmapForContext(*m_drawContext).eraseARGB(0, 0, 0, 0);
m_referenceBitmap = m_cachedBuffers->referenceBitmap();
m_referenceBitmap->eraseARGB(0, 0, 0, 0);
+ m_validLayer = true;
return;
}
@@ -377,10 +397,14 @@ void TransparencyWin::initializeNewContext()
m_layerBuffer = m_cachedBuffers->destBitmap();
m_drawContext = m_cachedBuffers->destBitmap()->context();
m_referenceBitmap = m_cachedBuffers->referenceBitmap();
+ m_validLayer = true;
}
void TransparencyWin::compositeOpaqueComposite()
{
+ if (!m_validLayer)
+ return;
+
SkCanvas* destCanvas = canvasForContext(*m_destContext);
destCanvas->save();
@@ -436,6 +460,9 @@ void TransparencyWin::compositeOpaqueComposite()
void TransparencyWin::compositeTextComposite()
{
+ if (!m_validLayer)
+ return;
+
const SkBitmap& bitmap = m_layerBuffer->context()->platformContext()->canvas()->getTopPlatformDevice().accessBitmap(true);
SkColor textColor = m_textCompositeColor.rgb();
for (int y = 0; y < m_layerSize.height(); y++) {
@@ -451,6 +478,7 @@ void TransparencyWin::compositeTextComposite()
// Now the layer has text with the proper color and opacity.
SkCanvas* destCanvas = canvasForContext(*m_destContext);
+ destCanvas->save();
// We want to use Untransformed space (see above)
SkMatrix identity;
@@ -467,6 +495,9 @@ void TransparencyWin::compositeTextComposite()
void TransparencyWin::makeLayerOpaque()
{
+ if (!m_validLayer)
+ return;
+
SkBitmap& bitmap = const_cast<SkBitmap&>(m_drawContext->platformContext()->
canvas()->getTopPlatformDevice().accessBitmap(true));
for (int y = 0; y < m_layerSize.height(); y++) {
@@ -477,4 +508,3 @@ void TransparencyWin::makeLayerOpaque()
}
} // namespace WebCore
-
diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.h b/WebCore/platform/graphics/chromium/TransparencyWin.h
index e1963b3..ab75375 100644
--- a/WebCore/platform/graphics/chromium/TransparencyWin.h
+++ b/WebCore/platform/graphics/chromium/TransparencyWin.h
@@ -135,13 +135,16 @@ public:
const IntRect& region);
// Combines the source and destination bitmaps using the given mode.
+ // Calling this function before the destructor runs is mandatory in most
+ // cases, and harmless otherwise. The mandatory cases are:
+ // (m_layerMode != NoLayer) || (m_transformMode == ScaleTransform)
void composite();
// Returns the context for drawing into, which may be the destination
// context, or a temporary one.
GraphicsContext* context() const { return m_drawContext; }
- PlatformGraphicsContext* platformContext() const { return m_drawContext->platformContext(); }
+ PlatformGraphicsContext* platformContext() const { return m_drawContext ? m_drawContext->platformContext() : 0; }
// When the mode is TextComposite, this sets the color that the text will
// get. See the enum above for more.
@@ -245,6 +248,12 @@ private:
// m_layerBuffer, which will either point to this object, or the statically
// cached one. Don't access directly.
OwnPtr<OwnedBuffers> m_ownedBuffers;
+
+ // Sometimes we're asked to create layers that have negative dimensions.
+ // This API is not designed to fail to initialize, so we hide the fact
+ // that they are illegal and can't be rendered (failing silently, drawing
+ // nothing).
+ bool m_validLayer;
};
} // namespace WebCore