[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 ℑ
- }
-
- // 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 ℑ
-}
-
-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 ℑ
+ }
+
+ // 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 ℑ
+}
+
+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