[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

mrobinson at webkit.org mrobinson at webkit.org
Wed Dec 22 13:41:19 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 8b82539f111174f39eda1961e0bb9bbb82c9f34b
Author: mrobinson at webkit.org <mrobinson at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu Sep 23 15:51:41 2010 +0000

    2010-09-23  Martin Robinson  <mrobinson at igalia.com>
    
            Reviewed by Ariya Hidayat.
    
            [Cairo] Generalize ContextShadow from the Qt port and use it for shadow code
            https://bugs.webkit.org/show_bug.cgi?id=45599
    
            Make ContextShadow platform-independent and add a Cairo implementation. This is currently
            disabled for Cairo, but will be enabled in a followup patch with new baselines.
    
            No new tests as this does not change functionality.
    
            * GNUmakefile.am: Update source lists.
            * WebCore.pro: Update source lists.
            * platform/graphics/ContextShadow.cpp: Added. A generalized version of Qt's ContextShadow.
            (WebCore::ContextShadow::ContextShadow):
            (WebCore::ContextShadow::clear):
            (WebCore::ContextShadow::blurLayerImage):
            (WebCore::ContextShadow::calculateMinimalLayerRect):
            * platform/graphics/ContextShadow.h: Added.
            (WebCore::ContextShadow::offset):
            * platform/graphics/cairo/CairoUtilities.cpp: Added.
            (WebCore::setSourceRGBAFromColor): A utility to set the source RGBA on a Cairo surface from a WebCore color.
            * platform/graphics/cairo/CairoUtilities.h: Added.
            * platform/graphics/cairo/ContextShadowCairo.cpp: Added.
            (WebCore::purgeScratchBuffer): Static function to purge the shadow buffer.
            (WebCore::PurgeScratchBufferTimer::fired): Timer callback.
            (WebCore::scheduleScratchBufferPurge): Schedule's a WebCore timer to purge the shadow buffer.
            (WebCore::getScratchBuffer): Create or reuse the scratch buffer.
            (WebCore::ContextShadow::beginShadowLayer): Added.
            (WebCore::ContextShadow::endShadowLayer): Added.
            * platform/graphics/gtk/CairoUtilities.cpp: Removed.
            * platform/graphics/gtk/CairoUtilities.h: Removed.
            * platform/graphics/gtk/GdkCairoUtilities.cpp: Renamed from CairoUtilities.cpp.
            (getCairoSurfacePixel):
            (getGdkPixbufPixel):
            (cairoImageSurfaceToGdkPixbuf):
            * platform/graphics/gtk/GdkCairoUtilities.h: Added.
            * platform/graphics/gtk/ImageBufferGtk.cpp:
            * platform/graphics/gtk/ImageGtk.cpp:
            * platform/graphics/qt/ContextShadow.cpp: Removed.
            * platform/graphics/qt/ContextShadow.h: Removed.
            * platform/graphics/qt/ContextShadowQt.cpp: Added. Adapted from code originally in ContextShadow.cpp.
            (WebCore::ShadowBuffer::ShadowBuffer):
            (WebCore::ShadowBuffer::scratchImage):
            (WebCore::ShadowBuffer::schedulePurge):
            (WebCore::ShadowBuffer::timerEvent):
            (WebCore::ContextShadow::beginShadowLayer):
            (WebCore::ContextShadow::endShadowLayer):
            * platform/graphics/qt/FontQt.cpp:
            (WebCore::drawTextCommon): Updated to reflect new ContextShadow members.
            * platform/graphics/qt/GraphicsContextQt.cpp:
            (WebCore::GraphicsContextPlatformPrivate::hasShadow): Updated to reflect new ContextShadow members.
            (WebCore::GraphicsContext::strokeArc): Ditto.
            (WebCore::GraphicsContext::drawConvexPolygon): Ditto.
            (WebCore::GraphicsContext::fillPath): Ditto.
            (WebCore::GraphicsContext::strokePath): Ditto.
            (WebCore::GraphicsContext::fillRect): Ditto.
            (WebCore::GraphicsContext::fillRoundedRect): Ditto.
            (WebCore::GraphicsContext::setPlatformShadow): Ditto.
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@68145 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 8f00923..d5e9776 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,64 @@
+2010-09-23  Martin Robinson  <mrobinson at igalia.com>
+
+        Reviewed by Ariya Hidayat.
+
+        [Cairo] Generalize ContextShadow from the Qt port and use it for shadow code
+        https://bugs.webkit.org/show_bug.cgi?id=45599
+
+        Make ContextShadow platform-independent and add a Cairo implementation. This is currently
+        disabled for Cairo, but will be enabled in a followup patch with new baselines.
+
+        No new tests as this does not change functionality.
+
+        * GNUmakefile.am: Update source lists.
+        * WebCore.pro: Update source lists.
+        * platform/graphics/ContextShadow.cpp: Added. A generalized version of Qt's ContextShadow.
+        (WebCore::ContextShadow::ContextShadow):
+        (WebCore::ContextShadow::clear):
+        (WebCore::ContextShadow::blurLayerImage):
+        (WebCore::ContextShadow::calculateMinimalLayerRect):
+        * platform/graphics/ContextShadow.h: Added.
+        (WebCore::ContextShadow::offset):
+        * platform/graphics/cairo/CairoUtilities.cpp: Added. 
+        (WebCore::setSourceRGBAFromColor): A utility to set the source RGBA on a Cairo surface from a WebCore color.
+        * platform/graphics/cairo/CairoUtilities.h: Added.
+        * platform/graphics/cairo/ContextShadowCairo.cpp: Added.
+        (WebCore::purgeScratchBuffer): Static function to purge the shadow buffer.
+        (WebCore::PurgeScratchBufferTimer::fired): Timer callback.
+        (WebCore::scheduleScratchBufferPurge): Schedule's a WebCore timer to purge the shadow buffer.
+        (WebCore::getScratchBuffer): Create or reuse the scratch buffer.
+        (WebCore::ContextShadow::beginShadowLayer): Added.
+        (WebCore::ContextShadow::endShadowLayer): Added.
+        * platform/graphics/gtk/CairoUtilities.cpp: Removed.
+        * platform/graphics/gtk/CairoUtilities.h: Removed.
+        * platform/graphics/gtk/GdkCairoUtilities.cpp: Renamed from CairoUtilities.cpp.
+        (getCairoSurfacePixel):
+        (getGdkPixbufPixel):
+        (cairoImageSurfaceToGdkPixbuf):
+        * platform/graphics/gtk/GdkCairoUtilities.h: Added.
+        * platform/graphics/gtk/ImageBufferGtk.cpp:
+        * platform/graphics/gtk/ImageGtk.cpp:
+        * platform/graphics/qt/ContextShadow.cpp: Removed.
+        * platform/graphics/qt/ContextShadow.h: Removed.
+        * platform/graphics/qt/ContextShadowQt.cpp: Added. Adapted from code originally in ContextShadow.cpp.
+        (WebCore::ShadowBuffer::ShadowBuffer):
+        (WebCore::ShadowBuffer::scratchImage):
+        (WebCore::ShadowBuffer::schedulePurge):
+        (WebCore::ShadowBuffer::timerEvent):
+        (WebCore::ContextShadow::beginShadowLayer):
+        (WebCore::ContextShadow::endShadowLayer):
+        * platform/graphics/qt/FontQt.cpp:
+        (WebCore::drawTextCommon): Updated to reflect new ContextShadow members.
+        * platform/graphics/qt/GraphicsContextQt.cpp:
+        (WebCore::GraphicsContextPlatformPrivate::hasShadow): Updated to reflect new ContextShadow members.
+        (WebCore::GraphicsContext::strokeArc): Ditto.
+        (WebCore::GraphicsContext::drawConvexPolygon): Ditto.
+        (WebCore::GraphicsContext::fillPath): Ditto.
+        (WebCore::GraphicsContext::strokePath): Ditto.
+        (WebCore::GraphicsContext::fillRect): Ditto.
+        (WebCore::GraphicsContext::fillRoundedRect): Ditto.
+        (WebCore::GraphicsContext::setPlatformShadow): Ditto.
+
 2010-09-23  Patrick Gansterer  <paroga at webkit.org>
 
         Reviewed by Adam Roben.
diff --git a/WebCore/GNUmakefile.am b/WebCore/GNUmakefile.am
index e7265b6..bfe6bdd 100644
--- a/WebCore/GNUmakefile.am
+++ b/WebCore/GNUmakefile.am
@@ -2086,6 +2086,8 @@ webcore_sources += \
 	WebCore/platform/graphics/Color.cpp \
 	WebCore/platform/graphics/Color.h \
 	WebCore/platform/graphics/ColorSpace.h \
+	WebCore/platform/graphics/ContextShadow.cpp \
+	WebCore/platform/graphics/ContextShadow.h \
 	WebCore/platform/graphics/DashArray.h \
 	WebCore/platform/graphics/filters/DistantLightSource.h \
 	WebCore/platform/graphics/filters/FEBlend.cpp \
@@ -3356,6 +3358,7 @@ webcoregtk_sources += \
 	WebCore/platform/graphics/cairo/CairoPath.h \
 	WebCore/platform/graphics/cairo/CairoUtilities.cpp \
 	WebCore/platform/graphics/cairo/CairoUtilities.h \
+	WebCore/platform/graphics/cairo/ContextShadowCairo.cpp \
 	WebCore/platform/graphics/cairo/FontCairo.cpp \
 	WebCore/platform/graphics/cairo/FontCustomPlatformData.h \
 	WebCore/platform/graphics/cairo/FontPlatformData.h \
diff --git a/WebCore/WebCore.pro b/WebCore/WebCore.pro
index 5d3650c..bc1d3db 100644
--- a/WebCore/WebCore.pro
+++ b/WebCore/WebCore.pro
@@ -1095,6 +1095,7 @@ SOURCES += \
     platform/graphics/FontFamily.cpp \
     platform/graphics/BitmapImage.cpp \
     platform/graphics/Color.cpp \
+    platform/graphics/ContextShadow.cpp \
     platform/graphics/FloatPoint3D.cpp \
     platform/graphics/FloatPoint.cpp \
     platform/graphics/FloatQuad.cpp \
@@ -1977,6 +1978,7 @@ HEADERS += \
     platform/mock/SpeechInputClientMock.h \
     platform/graphics/BitmapImage.h \
     platform/graphics/Color.h \
+    platform/graphics/ContextShadow.h \
     platform/graphics/filters/FEBlend.h \
     platform/graphics/filters/FEColorMatrix.h \
     platform/graphics/filters/FEComponentTransfer.h \
@@ -2022,7 +2024,6 @@ HEADERS += \
     platform/graphics/PathTraversalState.h \
     platform/graphics/Pattern.h \
     platform/graphics/Pen.h \
-    platform/graphics/qt/ContextShadow.h \
     platform/graphics/qt/FontCustomPlatformData.h \
     platform/graphics/qt/GraphicsLayerQt.h \
     platform/graphics/qt/ImageDecoderQt.h \
@@ -2536,7 +2537,7 @@ SOURCES += \
     page/qt/FrameQt.cpp \
     platform/graphics/qt/TransformationMatrixQt.cpp \
     platform/graphics/qt/ColorQt.cpp \
-    platform/graphics/qt/ContextShadow.cpp \
+    platform/graphics/qt/ContextShadowQt.cpp \
     platform/graphics/qt/FontQt.cpp \
     platform/graphics/qt/FontPlatformDataQt.cpp \
     platform/graphics/qt/FloatPointQt.cpp \
diff --git a/WebCore/platform/graphics/ContextShadow.cpp b/WebCore/platform/graphics/ContextShadow.cpp
new file mode 100644
index 0000000..1007962
--- /dev/null
+++ b/WebCore/platform/graphics/ContextShadow.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2010 Sencha, Inc.
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * 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 "ContextShadow.h"
+
+#include <wtf/MathExtras.h>
+#include <wtf/Noncopyable.h>
+
+using WTF::min;
+using WTF::max;
+
+namespace WebCore {
+
+ContextShadow::ContextShadow()
+    : m_type(NoShadow)
+    , m_blurRadius(0)
+{
+}
+
+ContextShadow::ContextShadow(const Color& color, float radius, const FloatSize& offset)
+    : m_color(color)
+    , m_blurRadius(round(radius))
+    , m_offset(offset)
+{
+    // See comments in http://webkit.org/b/40793, it seems sensible
+    // to follow Skia's limit of 128 pixels of blur radius
+    m_blurRadius = min(m_blurRadius, 128);
+
+    // The type of shadow is decided by the blur radius, shadow offset, and shadow color.
+    if (!m_color.isValid() || !color.alpha()) {
+        // Can't paint the shadow with invalid or invisible color.
+        m_type = NoShadow;
+    } else if (radius > 0) {
+        // Shadow is always blurred, even the offset is zero.
+        m_type = BlurShadow;
+    } else if (!m_offset.width() && !m_offset.height()) {
+        // Without blur and zero offset means the shadow is fully hidden.
+        m_type = NoShadow;
+    } else {
+        m_type = SolidShadow;
+    }
+}
+
+void ContextShadow::clear()
+{
+    m_type = NoShadow;
+    m_color = Color();
+    m_blurRadius = 0;
+    m_offset = FloatSize();
+}
+
+// Instead of integer division, we use 17.15 for fixed-point division.
+static const int BlurSumShift = 15;
+
+// Check http://www.w3.org/TR/SVG/filters.html#feGaussianBlur.
+// As noted in the SVG filter specification, running box blur 3x
+// approximates a real gaussian blur nicely.
+
+void ContextShadow::blurLayerImage(unsigned char* imageData, const IntSize& size, int rowStride)
+{
+    int channels[4] = { 3, 0, 1, 3 };
+    int dmax = m_blurRadius >> 1;
+    int dmin = dmax - 1 + (m_blurRadius & 1);
+    if (dmin < 0)
+        dmin = 0;
+
+    // Two stages: horizontal and vertical
+    for (int k = 0; k < 2; ++k) {
+
+        unsigned char* pixels = imageData;
+        int stride = (!k) ? 4 : rowStride;
+        int delta = (!k) ? rowStride : 4;
+        int jfinal = (!k) ? size.height() : size.width();
+        int dim = (!k) ? size.width() : size.height();
+
+        for (int j = 0; j < jfinal; ++j, pixels += delta) {
+
+            // For each step, we blur the alpha in a channel and store the result
+            // in another channel for the subsequent step.
+            // We use sliding window algorithm to accumulate the alpha values.
+            // This is much more efficient than computing the sum of each pixels
+            // covered by the box kernel size for each x.
+
+            for (int step = 0; step < 3; ++step) {
+                int side1 = (!step) ? dmin : dmax;
+                int side2 = (step == 1) ? dmin : dmax;
+                int pixelCount = side1 + 1 + side2;
+                int invCount = ((1 << BlurSumShift) + pixelCount - 1) / pixelCount;
+                int ofs = 1 + side2;
+                int alpha1 = pixels[channels[step]];
+                int alpha2 = pixels[(dim - 1) * stride + channels[step]];
+                unsigned char* ptr = pixels + channels[step + 1];
+                unsigned char* prev = pixels + stride + channels[step];
+                unsigned char* next = pixels + ofs * stride + channels[step];
+
+                int i;
+                int sum = side1 * alpha1 + alpha1;
+                int limit = (dim < side2 + 1) ? dim : side2 + 1;
+                for (i = 1; i < limit; ++i, prev += stride)
+                    sum += *prev;
+                if (limit <= side2)
+                    sum += (side2 - limit + 1) * alpha2;
+
+                limit = (side1 < dim) ? side1 : dim;
+                for (i = 0; i < limit; ptr += stride, next += stride, ++i, ++ofs) {
+                    *ptr = (sum * invCount) >> BlurSumShift;
+                    sum += ((ofs < dim) ? *next : alpha2) - alpha1;
+                }
+                prev = pixels + channels[step];
+                for (; ofs < dim; ptr += stride, prev += stride, next += stride, ++i, ++ofs) {
+                    *ptr = (sum * invCount) >> BlurSumShift;
+                    sum += (*next) - (*prev);
+                }
+                for (; i < dim; ptr += stride, prev += stride, ++i) {
+                    *ptr = (sum * invCount) >> BlurSumShift;
+                    sum += alpha2 - (*prev);
+                }
+            }
+        }
+    }
+}
+
+void ContextShadow::calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect)
+{
+    // Calculate the destination of the blurred layer.
+    FloatRect destinationRect(layerArea);
+    destinationRect.move(m_offset);
+    m_layerRect = enclosingIntRect(destinationRect);
+
+    // We expand the area by the blur radius * 2 to give extra space for the blur transition.
+    m_layerRect.inflate((m_type == BlurShadow) ? ceil(m_blurRadius * 2) : 0);
+
+    if (!clipRect.contains(m_layerRect)) {
+        // No need to have the buffer larger than the clip.
+        m_layerRect.intersect(clipRect);
+
+        // If we are totally outside the clip region, we aren't painting at all.
+        if (m_layerRect.isEmpty())
+            return;
+
+        // We adjust again because the pixels at the borders are still
+        // potentially affected by the pixels outside the buffer.
+        if (m_type == BlurShadow)
+            m_layerRect.inflate((m_type == BlurShadow) ? ceil(m_blurRadius * 2) : 0);
+    }
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/ContextShadow.h b/WebCore/platform/graphics/ContextShadow.h
new file mode 100644
index 0000000..ede9336
--- /dev/null
+++ b/WebCore/platform/graphics/ContextShadow.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2010 Sencha, Inc.
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * 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.
+ */
+
+#ifndef ContextShadow_h
+#define ContextShadow_h
+
+#include "Color.h"
+#include "FloatRect.h"
+#include "IntRect.h"
+#include "RefCounted.h"
+
+#if PLATFORM(CAIRO)
+typedef struct _cairo cairo_t;
+typedef struct _cairo_surface cairo_surface_t;
+typedef cairo_surface_t* PlatformImage;
+typedef cairo_t* PlatformContext;
+#elif PLATFORM(QT)
+#include <QImage>
+class QPainter;
+typedef QImage PlatformImage;
+typedef QPainter* PlatformContext;
+#endif
+
+namespace WebCore {
+
+// This is to track and keep the shadow state. We use this rather than
+// using GraphicsContextState to allow possible optimizations (right now
+// only to determine the shadow type, but in future it might covers things
+// like cached scratch image, persistent shader, etc).
+
+// This class should be copyable since GraphicsContextQt keeps a stack of
+// the shadow state for savePlatformState and restorePlatformState.
+
+class ContextShadow {
+public:
+    enum {
+        NoShadow,
+        SolidShadow,
+        BlurShadow
+    } m_type;
+
+    Color m_color;
+    int m_blurRadius;
+    FloatSize m_offset;
+
+    ContextShadow();
+    ContextShadow(const Color&, float radius, const FloatSize& offset);
+
+    void clear();
+
+    // The pair beginShadowLayer and endShadowLayer creates a temporary image
+    // where the caller can draw onto, using the returned context. This context
+    // must be used only to draw between the call to beginShadowLayer and
+    // endShadowLayer.
+    //
+    // Note: multiple/nested shadow layers are NOT allowed.
+    //
+    // The current clip region will be used to optimize the size of the
+    // temporary image. Thus, the original context should not change any
+    // clipping until endShadowLayer. If the shadow will be completely outside
+    // the clipping region, beginShadowLayer will return 0.
+    //
+    // The returned context will have the transformation matrix and clipping
+    // properly initialized to start doing the painting (no need to account for
+    // the shadow offset), however it will not have the same render hints, pen,
+    // brush, etc as the passed context. This is intentional, usually shadows
+    // have different properties than the shapes which cast them.
+    //
+    // Once endShadowLayer is called, the temporary image will be drawn with the
+    // original context. If blur radius is specified, the shadow will be
+    // filtered first.
+
+    PlatformContext beginShadowLayer(PlatformContext, const FloatRect& layerArea);
+    void endShadowLayer(PlatformContext);
+    static void purgeScratchBuffer();
+
+#if PLATFORM(QT)
+    QPointF offset() { return QPointF(m_offset.width(), m_offset.height()); }
+#endif
+
+
+private:
+    IntRect m_layerRect;
+    PlatformImage m_layerImage;
+    PlatformContext m_layerContext;
+
+    void blurLayerImage(unsigned char*, const IntSize& imageSize, int stride);
+    void calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect);
+};
+
+} // namespace WebCore
+
+#endif // ContextShadow_h
diff --git a/WebCore/platform/graphics/cairo/CairoUtilities.cpp b/WebCore/platform/graphics/cairo/CairoUtilities.cpp
index 34b4482..8c2049f 100644
--- a/WebCore/platform/graphics/cairo/CairoUtilities.cpp
+++ b/WebCore/platform/graphics/cairo/CairoUtilities.cpp
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "CairoUtilities.h"
 
+#include "Color.h"
 #include <cairo.h>
 #include <wtf/Vector.h>
 
@@ -48,5 +49,11 @@ void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr)
     cairo_set_fill_rule(dstCr, cairo_get_fill_rule(srcCr));
 }
 
-} // namespace WebCore
+void setSourceRGBAFromColor(cairo_t* context, const Color& color)
+{
+    float red, green, blue, alpha;
+    color.getRGBA(red, green, blue, alpha);
+    cairo_set_source_rgba(context, red, green, blue, alpha);
+}
 
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/cairo/CairoUtilities.h b/WebCore/platform/graphics/cairo/CairoUtilities.h
index 2efe9ea..0675b90 100644
--- a/WebCore/platform/graphics/cairo/CairoUtilities.h
+++ b/WebCore/platform/graphics/cairo/CairoUtilities.h
@@ -29,8 +29,11 @@
 typedef struct _cairo cairo_t;
 
 namespace WebCore {
+class Color;
 
 void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr);
+void setSourceRGBAFromColor(cairo_t*, const Color&);
+
 } // namespace WebCore
 
 #endif // CairoUtilities_h
diff --git a/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp b/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp
new file mode 100644
index 0000000..4b94cb3
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2010 Sencha, Inc.
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * 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 "ContextShadow.h"
+
+#include "CairoUtilities.h"
+#include "Timer.h"
+#include <cairo.h>
+
+namespace WebCore {
+
+static cairo_surface_t* scratchBuffer = 0;
+static void purgeScratchBuffer()
+{
+    cairo_surface_destroy(scratchBuffer);
+    scratchBuffer = 0;
+}
+
+// ContextShadow needs a scratch image as the buffer for the blur filter.
+// Instead of creating and destroying the buffer for every operation,
+// we create a buffer which will be automatically purged via a timer.
+class PurgeScratchBufferTimer : public TimerBase {
+private:
+    virtual void fired() { purgeScratchBuffer(); }
+};
+static PurgeScratchBufferTimer purgeScratchBufferTimer;
+static void scheduleScratchBufferPurge()
+{
+    if (purgeScratchBufferTimer.isActive())
+        purgeScratchBufferTimer.stop();
+    purgeScratchBufferTimer.startOneShot(2);
+}
+
+static cairo_surface_t* getScratchBuffer(const IntSize& size)
+{
+    int width = size.width();
+    int height = size.height();
+    int scratchWidth = scratchBuffer ? cairo_image_surface_get_width(scratchBuffer) : 0;
+    int scratchHeight = scratchBuffer ? cairo_image_surface_get_height(scratchBuffer) : 0;
+
+    // We do not need to recreate the buffer if the current buffer is large enough.
+    if (scratchBuffer && scratchWidth >= width && scratchHeight >= height)
+        return scratchBuffer;
+
+    purgeScratchBuffer();
+
+    // Round to the nearest 32 pixels so we do not grow the buffer for similar sized requests.
+    width = (1 + (width >> 5)) << 5;
+    height = (1 + (height >> 5)) << 5;
+    scratchBuffer = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+    return scratchBuffer;
+}
+
+PlatformContext ContextShadow::beginShadowLayer(PlatformContext context, const FloatRect& layerArea)
+{
+    double x1, x2, y1, y2;
+    cairo_clip_extents(context, &x1, &y1, &x2, &y2);
+    calculateLayerBoundingRect(layerArea, IntRect(x1, y1, x2 - x1, y2 - y1));
+
+    // Don't paint if we are totally outside the clip region.
+    if (m_layerRect.isEmpty())
+        return 0;
+
+    m_layerImage = getScratchBuffer(m_layerRect.size());
+    m_layerContext = cairo_create(m_layerImage);
+
+    // Always clear the surface first.
+    cairo_set_operator(m_layerContext, CAIRO_OPERATOR_CLEAR);
+    cairo_paint(m_layerContext);
+    cairo_set_operator(m_layerContext, CAIRO_OPERATOR_OVER);
+
+    cairo_translate(m_layerContext, m_offset.width(), m_offset.height());
+    cairo_translate(m_layerContext, -m_layerRect.x(), -m_layerRect.y());
+    return m_layerContext;
+}
+
+void ContextShadow::endShadowLayer(cairo_t* cr)
+{
+    cairo_destroy(m_layerContext);
+    m_layerContext = 0;
+
+    if (m_type == BlurShadow)
+        blurLayerImage(cairo_image_surface_get_data(m_layerImage),
+                       IntSize(cairo_image_surface_get_width(m_layerImage), cairo_image_surface_get_height(m_layerImage)),
+                       cairo_image_surface_get_stride(m_layerImage));
+
+    cairo_save(cr);
+    setSourceRGBAFromColor(cr, m_color);
+    cairo_mask_surface(cr, m_layerImage, m_layerRect.x(), m_layerRect.y());
+    cairo_restore(cr);
+
+    // Schedule a purge of the scratch buffer. We do not need to destroy the surface.
+    scheduleScratchBufferPurge();
+}
+
+}
diff --git a/WebCore/platform/graphics/qt/ContextShadow.cpp b/WebCore/platform/graphics/qt/ContextShadow.cpp
deleted file mode 100644
index b8fa914..0000000
--- a/WebCore/platform/graphics/qt/ContextShadow.cpp
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Copyright (C) 2010 Sencha, 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 "ContextShadow.h"
-
-#include <QTimerEvent>
-#include <wtf/Noncopyable.h>
-
-namespace WebCore {
-
-// ContextShadow needs a scratch image as the buffer for the blur filter.
-// Instead of creating and destroying the buffer for every operation,
-// we create a buffer which will be automatically purged via a timer.
-
-class ShadowBuffer: public QObject {
-public:
-    ShadowBuffer(QObject* parent = 0);
-
-    QImage* scratchImage(const QSize& size);
-
-    void schedulePurge();
-
-protected:
-    void timerEvent(QTimerEvent* event);
-
-private:
-    QImage image;
-    int timerId;
-};
-
-ShadowBuffer::ShadowBuffer(QObject* parent)
-    : QObject(parent)
-    , timerId(0)
-{
-}
-
-QImage* ShadowBuffer::scratchImage(const QSize& size)
-{
-    int width = size.width();
-    int height = size.height();
-
-    // We do not need to recreate the buffer if the buffer is reasonably
-    // larger than the requested size. However, if the requested size is
-    // much smaller than our buffer, reduce our buffer so that we will not
-    // keep too many allocated pixels for too long.
-    if (!image.isNull() && (image.width() > width) && (image.height() > height))
-        if (((2 * width) > image.width()) && ((2 * height) > image.height())) {
-            image.fill(Qt::transparent);
-            return &image;
-        }
-
-    // Round to the nearest 32 pixels so we do not grow the buffer everytime
-    // there is larger request by 1 pixel.
-    width = (1 + (width >> 5)) << 5;
-    height = (1 + (height >> 5)) << 5;
-
-    image = QImage(width, height, QImage::Format_ARGB32_Premultiplied);
-    image.fill(Qt::transparent);
-    return &image;
-}
-
-void ShadowBuffer::schedulePurge()
-{
-    static const double BufferPurgeDelay = 2; // seconds
-    killTimer(timerId);
-    timerId = startTimer(BufferPurgeDelay * 1000);
-}
-
-void ShadowBuffer::timerEvent(QTimerEvent* event)
-{
-    if (event->timerId() == timerId) {
-        killTimer(timerId);
-        image = QImage();
-    }
-    QObject::timerEvent(event);
-}
-
-Q_GLOBAL_STATIC(ShadowBuffer, scratchShadowBuffer)
-
-ContextShadow::ContextShadow()
-    : type(NoShadow)
-    , blurRadius(0)
-{
-}
-
-ContextShadow::ContextShadow(const QColor& c, float r, qreal dx, qreal dy)
-    : color(c)
-    , blurRadius(qRound(r))
-    , offset(dx, dy)
-{
-    // The type of shadow is decided by the blur radius, shadow offset, and shadow color.
-    if (!color.isValid() || !color.alpha()) {
-        // Can't paint the shadow with invalid or invisible color.
-        type = NoShadow;
-    } else if (r > 0) {
-        // Shadow is always blurred, even the offset is zero.
-        type = BlurShadow;
-    } else if (offset.isNull()) {
-        // Without blur and zero offset means the shadow is fully hidden.
-        type = NoShadow;
-    } else {
-        if (color.alpha() > 0)
-            type = AlphaSolidShadow;
-        else
-            type = OpaqueSolidShadow;
-    }
-}
-
-void ContextShadow::clear()
-{
-    type = NoShadow;
-    color = QColor();
-    blurRadius = 0;
-    offset = QPointF(0, 0);
-}
-
-// Instead of integer division, we use 17.15 for fixed-point division.
-static const int BlurSumShift = 15;
-
-// Check http://www.w3.org/TR/SVG/filters.html#feGaussianBlur.
-// As noted in the SVG filter specification, running box blur 3x
-// approximates a real gaussian blur nicely.
-
-void shadowBlur(QImage& image, int radius, const QColor& shadowColor)
-{
-    // See comments in http://webkit.org/b/40793, it seems sensible
-    // to follow Skia's limit of 128 pixels for the blur radius.
-    if (radius > 128)
-        radius = 128;
-
-    int channels[4] = { 3, 0, 1, 3 };
-    int dmax = radius >> 1;
-    int dmin = dmax - 1 + (radius & 1);
-    if (dmin < 0)
-        dmin = 0;
-
-    // Two stages: horizontal and vertical
-    for (int k = 0; k < 2; ++k) {
-
-        unsigned char* pixels = image.bits();
-        int stride = (!k) ? 4 : image.bytesPerLine();
-        int delta = (!k) ? image.bytesPerLine() : 4;
-        int jfinal = (!k) ? image.height() : image.width();
-        int dim = (!k) ? image.width() : image.height();
-
-        for (int j = 0; j < jfinal; ++j, pixels += delta) {
-
-            // For each step, we blur the alpha in a channel and store the result
-            // in another channel for the subsequent step.
-            // We use sliding window algorithm to accumulate the alpha values.
-            // This is much more efficient than computing the sum of each pixels
-            // covered by the box kernel size for each x.
-
-            for (int step = 0; step < 3; ++step) {
-                int side1 = (!step) ? dmin : dmax;
-                int side2 = (step == 1) ? dmin : dmax;
-                int pixelCount = side1 + 1 + side2;
-                int invCount = ((1 << BlurSumShift) + pixelCount - 1) / pixelCount;
-                int ofs = 1 + side2;
-                int alpha1 = pixels[channels[step]];
-                int alpha2 = pixels[(dim - 1) * stride + channels[step]];
-                unsigned char* ptr = pixels + channels[step + 1];
-                unsigned char* prev = pixels + stride + channels[step];
-                unsigned char* next = pixels + ofs * stride + channels[step];
-
-                int i;
-                int sum = side1 * alpha1 + alpha1;
-                int limit = (dim < side2 + 1) ? dim : side2 + 1;
-                for (i = 1; i < limit; ++i, prev += stride)
-                    sum += *prev;
-                if (limit <= side2)
-                    sum += (side2 - limit + 1) * alpha2;
-
-                limit = (side1 < dim) ? side1 : dim;
-                for (i = 0; i < limit; ptr += stride, next += stride, ++i, ++ofs) {
-                    *ptr = (sum * invCount) >> BlurSumShift;
-                    sum += ((ofs < dim) ? *next : alpha2) - alpha1;
-                }
-                prev = pixels + channels[step];
-                for (; ofs < dim; ptr += stride, prev += stride, next += stride, ++i, ++ofs) {
-                    *ptr = (sum * invCount) >> BlurSumShift;
-                    sum += (*next) - (*prev);
-                }
-                for (; i < dim; ptr += stride, prev += stride, ++i) {
-                    *ptr = (sum * invCount) >> BlurSumShift;
-                    sum += alpha2 - (*prev);
-                }
-            }
-        }
-    }
-
-    // "Colorize" with the right shadow color.
-    QPainter p(&image);
-    p.setCompositionMode(QPainter::CompositionMode_SourceIn);
-    p.fillRect(image.rect(), shadowColor.rgb());
-    p.end();
-}
-
-QPainter* ContextShadow::beginShadowLayer(QPainter* p, const QRectF &rect)
-{
-    // We expand the area by the blur radius * 2 to give extra space
-    // for the blur transition.
-    int extra = (type == BlurShadow) ? blurRadius * 2 : 0;
-
-    QRectF shadowRect = rect.translated(offset);
-    QRectF bufferRect = shadowRect.adjusted(-extra, -extra, extra, extra);
-    m_layerRect = bufferRect.toAlignedRect();
-
-    QRect clipRect;
-    if (p->hasClipping())
-#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
-        clipRect = p->clipBoundingRect().toAlignedRect();
-#else
-        clipRect = p->clipRegion().boundingRect();
-#endif
-    else
-        clipRect = p->transform().inverted().mapRect(p->window());
-
-    if (!clipRect.contains(m_layerRect)) {
-
-        // No need to have the buffer larger than the clip.
-        m_layerRect = m_layerRect.intersected(clipRect);
-        if (m_layerRect.isEmpty())
-            return 0;
-
-        // We adjust again because the pixels at the borders are still
-        // potentially affected by the pixels outside the buffer.
-        if (type == BlurShadow)
-            m_layerRect.adjust(-extra, -extra, extra, extra);
-    }
-
-    ShadowBuffer* shadowBuffer = scratchShadowBuffer();
-    QImage* shadowImage = shadowBuffer->scratchImage(m_layerRect.size());
-    m_layerImage = QImage(*shadowImage);
-
-    m_layerPainter = new QPainter;
-    m_layerPainter->begin(&m_layerImage);
-    m_layerPainter->setFont(p->font());
-    m_layerPainter->translate(offset);
-
-    // The origin is now the top left corner of the scratch image.
-    m_layerPainter->translate(-m_layerRect.topLeft());
-
-    return m_layerPainter;
-}
-
-void ContextShadow::endShadowLayer(QPainter* p)
-{
-    m_layerPainter->end();
-    delete m_layerPainter;
-    m_layerPainter = 0;
-
-    if (type == BlurShadow)
-        shadowBlur(m_layerImage, blurRadius, color);
-
-    p->drawImage(m_layerRect.topLeft(), m_layerImage);
-
-    scratchShadowBuffer()->schedulePurge();
-}
-
-}
diff --git a/WebCore/platform/graphics/qt/ContextShadow.h b/WebCore/platform/graphics/qt/ContextShadow.h
deleted file mode 100644
index 7140340..0000000
--- a/WebCore/platform/graphics/qt/ContextShadow.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2010 Sencha, 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.
- */
-
-#ifndef ContextShadow_h
-#define ContextShadow_h
-
-#include <QPainter>
-
-namespace WebCore {
-
-// This is to track and keep the shadow state. We use this rather than
-// using GraphicsContextState to allow possible optimizations (right now
-// only to determine the shadow type, but in future it might covers things
-// like cached scratch image, persistent shader, etc).
-
-// This class should be copyable since GraphicsContextQt keeps a stack of
-// the shadow state for savePlatformState and restorePlatformState.
-
-class ContextShadow {
-public:
-    enum {
-        NoShadow,
-        OpaqueSolidShadow,
-        AlphaSolidShadow,
-        BlurShadow
-    } type;
-
-    QColor color;
-    int blurRadius;
-    QPointF offset;
-
-    ContextShadow();
-    ContextShadow(const QColor& c, float r, qreal dx, qreal dy);
-
-    void clear();
-
-    // The pair beginShadowLayer and endShadowLayer creates a temporary image
-    // where the caller can draw onto, using the returned QPainter. This
-    // QPainter instance must be used only to draw between the call to
-    // beginShadowLayer and endShadowLayer.
-    //
-    // Note: multiple/nested shadow layer is NOT allowed.
-    //
-    // The current clip region will be used to optimize the size of the
-    // temporary image. Thus, the original painter should not change any
-    // clipping until endShadowLayer.
-    // If the shadow will be completely outside the clipping region,
-    // beginShadowLayer will return 0.
-    //
-    // The returned QPainter will have the transformation matrix and clipping
-    // properly initialized to start doing the painting (no need to account
-    // for the shadow offset), however it will not have the same render hints,
-    // pen, brush, etc as the passed QPainter. This is intentional, usually
-    // shadow has different properties than the shape which casts the shadow.
-    //
-    // Once endShadowLayer is called, the temporary image will be drawn
-    // with the original painter. If blur radius is specified, the shadow
-    // will be filtered first.
-    QPainter* beginShadowLayer(QPainter* p, const QRectF& rect);
-    void endShadowLayer(QPainter* p);
-
-private:
-    QRect m_layerRect;
-    QImage m_layerImage;
-    QPainter* m_layerPainter;
-};
-
-} // namespace WebCore
-
-#endif // ContextShadow_h
diff --git a/WebCore/platform/graphics/qt/ContextShadowQt.cpp b/WebCore/platform/graphics/qt/ContextShadowQt.cpp
new file mode 100644
index 0000000..342e027
--- /dev/null
+++ b/WebCore/platform/graphics/qt/ContextShadowQt.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2010 Sencha, 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 "ContextShadow.h"
+
+#include <QPainter>
+#include <QTimerEvent>
+
+namespace WebCore {
+
+// ContextShadow needs a scratch image as the buffer for the blur filter.
+// Instead of creating and destroying the buffer for every operation,
+// we create a buffer which will be automatically purged via a timer.
+
+class ShadowBuffer: public QObject {
+public:
+    ShadowBuffer(QObject* parent = 0);
+
+    QImage* scratchImage(const QSize& size);
+
+    void schedulePurge();
+
+protected:
+    void timerEvent(QTimerEvent* event);
+
+private:
+    QImage image;
+    int timerId;
+};
+
+ShadowBuffer::ShadowBuffer(QObject* parent)
+    : QObject(parent)
+    , timerId(0)
+{
+}
+
+QImage* ShadowBuffer::scratchImage(const QSize& size)
+{
+    int width = size.width();
+    int height = size.height();
+
+    // We do not need to recreate the buffer if the buffer is reasonably
+    // larger than the requested size. However, if the requested size is
+    // much smaller than our buffer, reduce our buffer so that we will not
+    // keep too many allocated pixels for too long.
+    if (!image.isNull() && (image.width() > width) && (image.height() > height))
+        if (((2 * width) > image.width()) && ((2 * height) > image.height())) {
+            image.fill(Qt::transparent);
+            return &image;
+        }
+
+    // Round to the nearest 32 pixels so we do not grow the buffer everytime
+    // there is larger request by 1 pixel.
+    width = (1 + (width >> 5)) << 5;
+    height = (1 + (height >> 5)) << 5;
+
+    image = QImage(width, height, QImage::Format_ARGB32_Premultiplied);
+    image.fill(Qt::transparent);
+    return &image;
+}
+
+void ShadowBuffer::schedulePurge()
+{
+    static const double BufferPurgeDelay = 2; // seconds
+    killTimer(timerId);
+    timerId = startTimer(BufferPurgeDelay * 1000);
+}
+
+void ShadowBuffer::timerEvent(QTimerEvent* event)
+{
+    if (event->timerId() == timerId) {
+        killTimer(timerId);
+        image = QImage();
+    }
+    QObject::timerEvent(event);
+}
+
+Q_GLOBAL_STATIC(ShadowBuffer, scratchShadowBuffer)
+
+PlatformContext ContextShadow::beginShadowLayer(PlatformContext p, const FloatRect& layerArea)
+{
+    QRect clipRect;
+    if (p->hasClipping())
+#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
+        clipRect = p->clipBoundingRect().toAlignedRect();
+#else
+        clipRect = p->clipRegion().boundingRect();
+#endif
+    else
+        clipRect = p->transform().inverted().mapRect(p->window());
+
+    calculateLayerBoundingRect(layerArea, IntRect(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height()));
+
+    // Don't paint if we are totally outside the clip region.
+    if (m_layerRect.isEmpty())
+        return 0;
+
+    ShadowBuffer* shadowBuffer = scratchShadowBuffer();
+    QImage* shadowImage = shadowBuffer->scratchImage(m_layerRect.size());
+    m_layerImage = QImage(*shadowImage);
+
+    m_layerContext = new QPainter;
+    m_layerContext->begin(&m_layerImage);
+    m_layerContext->setFont(p->font());
+    m_layerContext->translate(m_offset.width(), m_offset.height());
+
+    // The origin is now the top left corner of the scratch image.
+    m_layerContext->translate(-m_layerRect.x(), -m_layerRect.y());
+
+    return m_layerContext;
+}
+
+void ContextShadow::endShadowLayer(PlatformContext p)
+{
+    m_layerContext->end();
+    delete m_layerContext;
+    m_layerContext = 0;
+
+    if (m_type == BlurShadow) {
+        blurLayerImage(m_layerImage.bits(), IntSize(m_layerImage.width(), m_layerImage.height()),
+                       m_layerImage.bytesPerLine());
+
+        // "Colorize" with the right shadow color.
+        QPainter p(&m_layerImage);
+        p.setCompositionMode(QPainter::CompositionMode_SourceIn);
+        p.fillRect(m_layerImage.rect(), m_color.rgb());
+        p.end();
+    }
+
+    p->drawImage(m_layerRect.topLeft(), m_layerImage);
+    scratchShadowBuffer()->schedulePurge();
+}
+
+}
diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp
index 2b246de..db9d7e8 100644
--- a/WebCore/platform/graphics/qt/FontQt.cpp
+++ b/WebCore/platform/graphics/qt/FontQt.cpp
@@ -125,37 +125,38 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float
 
             ContextShadow* ctxShadow = ctx->contextShadow();
 
-            if (ctxShadow->type != ContextShadow::NoShadow) {
+            if (ctxShadow->m_type != ContextShadow::NoShadow) {
                 qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0;
-                if (ctxShadow->offset.x() > 0)
-                    dx2 = ctxShadow->offset.x();
+                if (ctxShadow->offset().x() > 0)
+                    dx2 = ctxShadow->offset().x();
                 else
-                    dx1 = -ctxShadow->offset.x();
-                if (ctxShadow->offset.y() > 0)
-                    dy2 = ctxShadow->offset.y();
+                    dx1 = -ctxShadow->offset().x();
+                if (ctxShadow->offset().y() > 0)
+                    dy2 = ctxShadow->offset().y();
                 else
-                    dy1 = -ctxShadow->offset.y();
+                    dy1 = -ctxShadow->offset().y();
                 // expand the clip rect to include the text shadow as well
                 clip.adjust(dx1, dx2, dy1, dy2);
-                clip.adjust(-ctxShadow->blurRadius, -ctxShadow->blurRadius, ctxShadow->blurRadius, ctxShadow->blurRadius);
+                clip.adjust(-ctxShadow->m_blurRadius, -ctxShadow->m_blurRadius, ctxShadow->m_blurRadius, ctxShadow->m_blurRadius);
             }
             p->save();
             p->setClipRect(clip.toRect(), Qt::IntersectClip);
             pt.setY(pt.y() - ascent);
 
-            if (ctxShadow->type != ContextShadow::NoShadow) {
+            if (ctxShadow->m_type != ContextShadow::NoShadow) {
                 ContextShadow* ctxShadow = ctx->contextShadow();
-                if (ctxShadow->type != ContextShadow::BlurShadow) {
+                if (ctxShadow->m_type != ContextShadow::BlurShadow) {
                     p->save();
-                    p->setPen(ctxShadow->color);
-                    p->translate(ctxShadow->offset);
+                    p->setPen(ctxShadow->m_color);
+                    p->translate(ctxShadow->offset());
                     line.draw(p, pt);
                     p->restore();
                 } else {
                     QPainter* shadowPainter = ctxShadow->beginShadowLayer(p, boundingRect);
                     if (shadowPainter) {
                         // Since it will be blurred anyway, we don't care about render hints.
-                        shadowPainter->setPen(ctxShadow->color);
+                        shadowPainter->setFont(p->font());
+                        shadowPainter->setPen(ctxShadow->m_color);
                         line.draw(shadowPainter, pt);
                         ctxShadow->endShadowLayer(p);
                     }
@@ -181,12 +182,12 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float
     if (!isComplexText && !(ctx->textDrawingMode() & cTextStroke))
         flags |= Qt::TextBypassShaping;
 #endif
-    if (ctx->contextShadow()->type != ContextShadow::NoShadow) {
+    if (ctx->contextShadow()->m_type != ContextShadow::NoShadow) {
         ContextShadow* ctxShadow = ctx->contextShadow();
-        if (ctxShadow->type != ContextShadow::BlurShadow) {
+        if (ctxShadow->m_type != ContextShadow::BlurShadow) {
             p->save();
-            p->setPen(ctxShadow->color);
-            p->translate(ctxShadow->offset);
+            p->setPen(ctxShadow->m_color);
+            p->translate(ctxShadow->offset());
             p->drawText(pt, string, flags, run.padding());
             p->restore();
         } else {
@@ -196,7 +197,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float
             if (shadowPainter) {
                 // Since it will be blurred anyway, we don't care about render hints.
                 shadowPainter->setFont(p->font());
-                shadowPainter->setPen(ctxShadow->color);
+                shadowPainter->setPen(ctxShadow->m_color);
                 shadowPainter->drawText(pt, string, flags, run.padding());
                 ctxShadow->endShadowLayer(p);
             }
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index 5a29ad4..73ecefb 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -201,7 +201,7 @@ public:
 
     bool hasShadow() const
     {
-        return shadow.type != ContextShadow::NoShadow;
+        return shadow.m_type != ContextShadow::NoShadow;
     }
 
     QRectF clipBoundingRect() const
@@ -440,9 +440,9 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp
 
     if (m_data->hasShadow()) {
         p->save();
-        p->translate(m_data->shadow.offset);
+        p->translate(m_data->shadow.offset());
         QPen pen(p->pen());
-        pen.setColor(m_data->shadow.color);
+        pen.setColor(m_data->shadow.m_color);
         p->setPen(pen);
         p->drawArc(rect, startAngle, angleSpan);
         p->restore();
@@ -470,12 +470,12 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points
     p->setRenderHint(QPainter::Antialiasing, shouldAntialias);
     if (m_data->hasShadow()) {
         p->save();
-        p->translate(m_data->shadow.offset);
+        p->translate(m_data->shadow.offset());
         if (p->brush().style() != Qt::NoBrush)
-            p->setBrush(QBrush(m_data->shadow.color));
+            p->setBrush(QBrush(m_data->shadow.m_color));
         QPen pen(p->pen());
         if (pen.style() != Qt::NoPen) {
-            pen.setColor(m_data->shadow.color);
+            pen.setColor(m_data->shadow.m_color);
             p->setPen(pen);
         }
         p->drawConvexPolygon(polygon);
@@ -519,9 +519,9 @@ void GraphicsContext::fillPath()
     path.setFillRule(toQtFillRule(fillRule()));
 
     if (m_data->hasShadow()) {
-        p->translate(m_data->shadow.offset);
-        p->fillPath(path, m_data->shadow.color);
-        p->translate(-m_data->shadow.offset);
+        p->translate(m_data->shadow.offset());
+        p->fillPath(path, QColor(m_data->shadow.m_color));
+        p->translate(-m_data->shadow.offset());
     }
     if (m_common->state.fillPattern) {
         AffineTransform affine;
@@ -547,11 +547,11 @@ void GraphicsContext::strokePath()
     path.setFillRule(toQtFillRule(fillRule()));
 
     if (m_data->hasShadow()) {
-        p->translate(m_data->shadow.offset);
+        p->translate(m_data->shadow.offset());
         QPen shadowPen(pen);
-        shadowPen.setColor(m_data->shadow.color);
+        shadowPen.setColor(m_data->shadow.m_color);
         p->strokePath(path, shadowPen);
-        p->translate(-m_data->shadow.offset);
+        p->translate(-m_data->shadow.offset());
     }
     if (m_common->state.strokePattern) {
         AffineTransform affine;
@@ -653,7 +653,7 @@ void GraphicsContext::fillRect(const FloatRect& rect)
         if (shadowPainter) {
             drawRepeatPattern(shadowPainter, image, normalizedRect, m_common->state.fillPattern->repeatX(), m_common->state.fillPattern->repeatY());
             shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn);
-            shadowPainter->fillRect(normalizedRect, shadow->color);
+            shadowPainter->fillRect(normalizedRect, shadow->m_color);
             shadow->endShadowLayer(p);
         }
         drawRepeatPattern(p, image, normalizedRect, m_common->state.fillPattern->repeatX(), m_common->state.fillPattern->repeatY());
@@ -664,13 +664,13 @@ void GraphicsContext::fillRect(const FloatRect& rect)
         if (shadowPainter) {
             shadowPainter->fillRect(normalizedRect, brush);
             shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn);
-            shadowPainter->fillRect(normalizedRect, shadow->color);
+            shadowPainter->fillRect(normalizedRect, shadow->m_color);
             shadow->endShadowLayer(p);
         }
         p->fillRect(normalizedRect, brush);
     } else {
         if (m_data->hasShadow()) {
-            if (shadow->type == ContextShadow::BlurShadow) {
+            if (shadow->m_type == ContextShadow::BlurShadow) {
                 QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect);
                 if (shadowPainter) {
                     shadowPainter->fillRect(normalizedRect, p->brush());
@@ -679,9 +679,9 @@ void GraphicsContext::fillRect(const FloatRect& rect)
             } else {
                 // Solid rectangle fill with no blur shadow can be done faster
                 // without using the shadow layer at all.
-                QColor shadowColor = shadow->color;
+                QColor shadowColor = shadow->m_color;
                 shadowColor.setAlphaF(shadowColor.alphaF() * p->brush().color().alphaF());
-                p->fillRect(normalizedRect.translated(shadow->offset), shadowColor);
+                p->fillRect(normalizedRect.translated(shadow->offset()), shadowColor);
             }
         }
         p->fillRect(normalizedRect, p->brush());
@@ -701,14 +701,14 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS
     if (m_data->hasShadow()) {
         ContextShadow* shadow = contextShadow();
 
-        if (shadow->type != ContextShadow::BlurShadow) {
+        if (shadow->m_type != ContextShadow::BlurShadow) {
             // We do not need any layer for simple shadow.
-            p->fillRect(normalizedRect.translated(shadow->offset), shadow->color);
+            p->fillRect(normalizedRect.translated(shadow->offset()), shadow->m_color);
         } else {
             QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect);
             if (shadowPainter) {
                 shadowPainter->setCompositionMode(QPainter::CompositionMode_Source);
-                shadowPainter->fillRect(normalizedRect, shadow->color);
+                shadowPainter->fillRect(normalizedRect, shadow->m_color);
                 shadow->endShadowLayer(p);
             }
         }
@@ -725,9 +725,9 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
     Path path = Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight);
     QPainter* p = m_data->p();
     if (m_data->hasShadow()) {
-        p->translate(m_data->shadow.offset);
-        p->fillPath(path.platformPath(), m_data->shadow.color);
-        p->translate(-m_data->shadow.offset);
+        p->translate(m_data->shadow.offset());
+        p->fillPath(path.platformPath(), QColor(m_data->shadow.m_color));
+        p->translate(-m_data->shadow.offset());
     }
     p->fillPath(path.platformPath(), QColor(color));
 }
@@ -884,9 +884,9 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const
         // Meaning that this graphics context is associated with a CanvasRenderingContext
         // We flip the height since CG and HTML5 Canvas have opposite Y axis
         m_common->state.shadowOffset = FloatSize(size.width(), -size.height());
-        m_data->shadow = ContextShadow(color, blur, size.width(), -size.height());
+        m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height()));
     } else {
-        m_data->shadow = ContextShadow(color, blur, size.width(), size.height());
+        m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height()));
     }
 }
 

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list