WebCore: [CAIRO] shadow support for Canvas and SVG.
authorbfulgham@webkit.org <bfulgham@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 13 Nov 2009 01:47:45 +0000 (01:47 +0000)
committerbfulgham@webkit.org <bfulgham@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 13 Nov 2009 01:47:45 +0000 (01:47 +0000)
[https://bugs.webkit.org/show_bug.cgi?id=30960]

Reviewed by Simon Fraser.

Implement Canvas/SVG shadow support for Cairo.  This patch
uses the filter code from SVG Filters.  That means that it is
necessary to activate filters to see the shadows.

Test: fast/canvas/canvas-shadow.html

* GNUmakefile.am:
* WebCore.vcproj/WebCore.vcproj: Add new ImageBufferFilter files.
* platform/graphics/GraphicsContext.h:
* platform/graphics/cairo/GraphicsContextCairo.cpp:
(GraphicsContext::calculateShadowBufferDimensions): New helper routine.
(WebCore::setPlatformFill):
(WebCore::setPlatformStroke):
(WebCore::copyContextProperties):
(WebCore::drawPathShadow):
(WebCore::GraphicsContext::fillPath):
(WebCore::GraphicsContext::strokePath):
(WebCore::GraphicsContext::drawPath):
(WebCore::GraphicsContext::setPlatformShadow):
(WebCore::GraphicsContext::createPlatformShadow):
* platform/graphics/cairo/ImageCairo.cpp:
(WebCore::BitmapImage::draw): Add filter effect.
* platform/graphics/filters/Filter.h: Correct 'const' signatures.
* platform/graphics/filters/ImageBufferFilter.cpp: Added.
* platform/graphics/filters/ImageBufferFilter.h: Added.
* svg/graphics/filters/SVGFilter.cpp: Correct 'const' signatures.
* svg/graphics/filters/SVGFilter.h: Correct 'const' signatures.

LayoutTests: Some tests for canvas shadow.

Patch by Dirk Schulze <krit@webkit.org> on 2009-11-11
Reviewed by Simon Fraser.

* fast/canvas/canvas-shadow-expected.txt: Added.
* fast/canvas/canvas-shadow.html: Added.
* fast/canvas/script-tests/canvas-shadow.js: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@50920 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/canvas/canvas-shadow-expected.txt [new file with mode: 0644]
LayoutTests/fast/canvas/canvas-shadow.html [new file with mode: 0644]
LayoutTests/fast/canvas/script-tests/canvas-shadow.js [new file with mode: 0644]
WebCore/ChangeLog
WebCore/GNUmakefile.am
WebCore/WebCore.vcproj/WebCore.vcproj
WebCore/platform/graphics/GraphicsContext.h
WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
WebCore/platform/graphics/cairo/ImageCairo.cpp
WebCore/platform/graphics/filters/Filter.h
WebCore/platform/graphics/filters/ImageBufferFilter.cpp [new file with mode: 0644]
WebCore/platform/graphics/filters/ImageBufferFilter.h [new file with mode: 0644]
WebCore/svg/graphics/filters/SVGFilter.cpp
WebCore/svg/graphics/filters/SVGFilter.h

index 1d28e81..bca520c 100644 (file)
@@ -1,3 +1,13 @@
+2009-11-11  Dirk Schulze  <krit@webkit.org>
+
+        Reviewed by Simon Fraser.
+
+        Some tests for canvas shadow.
+
+        * fast/canvas/canvas-shadow-expected.txt: Added.
+        * fast/canvas/canvas-shadow.html: Added.
+        * fast/canvas/script-tests/canvas-shadow.js: Added.
+
 2009-11-12  Brian Weinstein  <bweinstein@apple.com>
 
         Rubber-stamped by Steve Falkenburg.
diff --git a/LayoutTests/fast/canvas/canvas-shadow-expected.txt b/LayoutTests/fast/canvas/canvas-shadow-expected.txt
new file mode 100644 (file)
index 0000000..dd3f8e9
--- /dev/null
@@ -0,0 +1,15 @@
+Some tests for Canvas shadows
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS imgdata[4] is 0
+PASS imgdata[5] is 128
+PASS imgdata[6] is 0
+PASS imgdata[4] is 0
+PASS imgdata[5] is 128
+PASS imgdata[6] is 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/canvas/canvas-shadow.html b/LayoutTests/fast/canvas/canvas-shadow.html
new file mode 100644 (file)
index 0000000..2934c39
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../js/resources/js-test-style.css">
+<script src="../js/resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/canvas-shadow.js"></script>
+<script src="../js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/canvas/script-tests/canvas-shadow.js b/LayoutTests/fast/canvas/script-tests/canvas-shadow.js
new file mode 100644 (file)
index 0000000..019d73a
--- /dev/null
@@ -0,0 +1,34 @@
+description("Some tests for Canvas shadows");
+var ctx = document.createElement('canvas').getContext('2d');
+
+ctx.fillStyle = "green";
+ctx.fillRect(0,0,100,100);
+
+ctx.shadowColor = "green";
+ctx.shadowOffsetX = 0;
+ctx.shadowOffsetY = 0;
+ctx.shadowBlur = 0;
+
+var imageData = ctx.getImageData(0, 0, 200, 50);
+var imgdata = imageData.data;
+shouldBe("imgdata[4]", "0");
+shouldBe("imgdata[5]", "128");
+shouldBe("imgdata[6]", "0");
+
+ctx.clearRect(0,0,200,50);
+
+ctx.shadowColor = "green";
+ctx.shadowOffsetX = 100;
+ctx.shadowOffsetY = 0;
+ctx.shadowBlur = 2;
+
+ctx.fillStyle = "green";
+ctx.fillRect(0,0,100,50);
+
+imageData = ctx.getImageData(110, 10, 80, 30);
+imgdata = imageData.data;
+shouldBe("imgdata[4]", "0");
+shouldBe("imgdata[5]", "128");
+shouldBe("imgdata[6]", "0");
+
+var successfullyParsed = true;
index cfdc4af..69cadfb 100644 (file)
@@ -1,3 +1,38 @@
+2009-11-12  Brent Fulgham  <bfulgham@webkit.org>
+
+        Reviewed by Simon Fraser.
+
+        [CAIRO] shadow support for Canvas and SVG.
+        [https://bugs.webkit.org/show_bug.cgi?id=30960]
+
+        Implement Canvas/SVG shadow support for Cairo.  This patch
+        uses the filter code from SVG Filters.  That means that it is
+        necessary to activate filters to see the shadows.
+
+        Test: fast/canvas/canvas-shadow.html
+
+        * GNUmakefile.am:
+        * WebCore.vcproj/WebCore.vcproj: Add new ImageBufferFilter files.
+        * platform/graphics/GraphicsContext.h:
+        * platform/graphics/cairo/GraphicsContextCairo.cpp:
+        (GraphicsContext::calculateShadowBufferDimensions): New helper routine.
+        (WebCore::setPlatformFill):
+        (WebCore::setPlatformStroke):
+        (WebCore::copyContextProperties):
+        (WebCore::drawPathShadow):
+        (WebCore::GraphicsContext::fillPath):
+        (WebCore::GraphicsContext::strokePath):
+        (WebCore::GraphicsContext::drawPath):
+        (WebCore::GraphicsContext::setPlatformShadow):
+        (WebCore::GraphicsContext::createPlatformShadow):
+        * platform/graphics/cairo/ImageCairo.cpp:
+        (WebCore::BitmapImage::draw): Add filter effect.
+        * platform/graphics/filters/Filter.h: Correct 'const' signatures.
+        * platform/graphics/filters/ImageBufferFilter.cpp: Added.
+        * platform/graphics/filters/ImageBufferFilter.h: Added.
+        * svg/graphics/filters/SVGFilter.cpp: Correct 'const' signatures.
+        * svg/graphics/filters/SVGFilter.h: Correct 'const' signatures.
+
 2009-11-12  Dmitry Titov  <dimich@chromium.org>
 
         Reviewed by Alexey Proskuryakov.
index 3b99419..37b65b7 100644 (file)
@@ -2625,6 +2625,8 @@ webcore_sources += \
        WebCore/platform/graphics/filters/Filter.h \
        WebCore/platform/graphics/filters/FilterEffect.cpp \
        WebCore/platform/graphics/filters/FilterEffect.h \
+       WebCore/platform/graphics/filters/ImageBufferFilter.cpp \
+       WebCore/platform/graphics/filters/ImageBufferFilter.h \
        WebCore/platform/graphics/filters/SourceAlpha.cpp \
        WebCore/platform/graphics/filters/SourceAlpha.h \
        WebCore/platform/graphics/filters/SourceGraphic.cpp \
index 9315e35..becd798 100644 (file)
                        <File\r
                                RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSInspectorBackend.cpp"\r
                                >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSInspectorBackend.cpp"\r
-                               >\r
                                <FileConfiguration\r
                                        Name="Debug|Win32"\r
                                        ExcludedFromBuild="true"\r
                                </FileConfiguration>\r
                        </File>\r
                        <File\r
+                               RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSInspectorBackend.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSInspectorBackend.h"\r
                                >\r
                        </File>\r
                                        RelativePath="..\platform\graphics\Color.h"\r
                                        >\r
                                </File>\r
-                <File\r
+                               <File\r
                                        RelativePath="..\platform\graphics\ColorPath.h"\r
                                        >\r
                                </File>\r
                                                >\r
                                        </File>\r
                                        <File\r
+                                               RelativePath="..\platform\graphics\filters\ImageBufferFilter.cpp"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
+                                               RelativePath="..\platform\graphics\filters\ImageBufferFilter.h"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath="..\platform\graphics\filters\SourceAlpha.cpp"\r
                                                >\r
                                        </File>\r
index 7aac04b..d6ed2e8 100644 (file)
@@ -282,6 +282,8 @@ namespace WebCore {
         void setAlpha(float);
 #if PLATFORM(CAIRO)
         float getAlpha();
+        void createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float kernelSize);
+        static void calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& kernelSize, const FloatRect& sourceRect, const IntSize& shadowSize, int shadowBlur);
 #endif
 
         void setCompositeOperation(CompositeOperator);
index f0b05bc..bad6ef1 100644 (file)
@@ -1,8 +1,9 @@
 /*
  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
- * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de>
+ * Copyright (C) 2008, 2009 Dirk Schulze <krit@webkit.org>
  * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #if PLATFORM(CAIRO)
 
 #include "CairoPath.h"
+#include "FEGaussianBlur.h"
 #include "FloatRect.h"
 #include "Font.h"
 #include "ImageBuffer.h"
+#include "ImageBufferFilter.h"
 #include "IntRect.h"
 #include "NotImplemented.h"
 #include "Path.h"
 #include "Pattern.h"
 #include "SimpleFontData.h"
+#include "SourceGraphic.h"
 #include "TransformationMatrix.h"
 
 #include <cairo.h>
@@ -69,6 +73,55 @@ static inline void setColor(cairo_t* cr, const Color& col)
     cairo_set_source_rgba(cr, red, green, blue, alpha);
 }
 
+static inline void setPlatformFill(GraphicsContext* context, cairo_t* cr, GraphicsContextPrivate* gcp)
+{
+    switch (gcp->state.fillType) {
+    case SolidColorType: {
+        Color fillColor = colorWithOverrideAlpha(context->fillColor().rgb(), context->fillColor().alpha() / 255.f * gcp->state.globalAlpha);
+        setColor(cr, fillColor);
+        cairo_fill_preserve(cr);
+        break;
+    }
+    case PatternType: {
+        TransformationMatrix affine;
+        cairo_set_source(cr, gcp->state.fillPattern->createPlatformPattern(affine));
+        cairo_clip_preserve(cr);
+        cairo_paint_with_alpha(cr, gcp->state.globalAlpha);
+        break;
+    }
+    case GradientType:
+        cairo_set_source(cr, gcp->state.fillGradient->platformGradient());
+        cairo_clip_preserve(cr);
+        cairo_paint_with_alpha(cr, gcp->state.globalAlpha);
+        break;
+    }
+}
+
+static inline void setPlatformStroke(GraphicsContext* context, cairo_t* cr, GraphicsContextPrivate* gcp)
+{
+    switch (gcp->state.strokeType) {
+    case SolidColorType: {
+        Color strokeColor = colorWithOverrideAlpha(context->strokeColor().rgb(), context->strokeColor().alpha() / 255.f * gcp->state.globalAlpha);
+        setColor(cr, strokeColor);
+        break;
+    }
+    case PatternType: {
+        TransformationMatrix affine;
+        cairo_set_source(cr, gcp->state.strokePattern->createPlatformPattern(affine));
+        break;
+    }
+    case GradientType:
+        cairo_set_source(cr, gcp->state.strokeGradient->platformGradient());
+        break;
+    }
+    if (gcp->state.globalAlpha < 1.0f && gcp->state.strokeType != SolidColorType) {
+        cairo_push_group(cr);
+        cairo_paint_with_alpha(cr, gcp->state.globalAlpha);
+        cairo_pop_group_to_source(cr);
+    }
+    cairo_stroke_preserve(cr);
+}
+
 // A fillRect helper
 static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const Color& col)
 {
@@ -78,6 +131,74 @@ static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const
     cairo_fill(cr);
 }
 
+static inline void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr)
+{
+    cairo_set_antialias(dstCr, cairo_get_antialias(srcCr));
+    double dashes, offset;
+    cairo_get_dash(srcCr, &dashes, &offset);
+    cairo_set_dash(dstCr, &dashes, cairo_get_dash_count(srcCr), offset);
+    cairo_set_line_cap(dstCr, cairo_get_line_cap(srcCr));
+    cairo_set_line_join(dstCr, cairo_get_line_join(srcCr));
+    cairo_set_line_width(dstCr, cairo_get_line_width(srcCr));
+    cairo_set_miter_limit(dstCr, cairo_get_miter_limit(srcCr));
+    cairo_set_fill_rule(dstCr, cairo_get_fill_rule(srcCr));
+}
+
+void GraphicsContext::calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& kernelSize, const FloatRect& sourceRect, const IntSize& shadowSize, int shadowBlur)
+{
+#if ENABLE(FILTERS)
+    // calculate the kernel size according to the HTML5 canvas shadow specification
+    kernelSize = (shadowBlur < 8 ? shadowBlur / 2.f : sqrt(shadowBlur * 2.f));
+    int blurRadius = ceil(kernelSize);
+
+    shadowBufferSize = IntSize(sourceRect.width() + blurRadius * 2, sourceRect.height() + blurRadius * 2);
+
+    // determine dimensions of shadow rect
+    shadowRect = FloatRect(sourceRect.location(), shadowBufferSize);
+    shadowRect.move(shadowSize.width() - kernelSize, shadowSize.height() - kernelSize);
+#endif
+}
+
+static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPrivate* gcp, bool fillShadow, bool strokeShadow)
+{
+#if ENABLE(FILTERS)
+    IntSize shadowSize;
+    int shadowBlur;
+    Color shadowColor;
+    if (!context->getShadow(shadowSize, shadowBlur, shadowColor))
+        return;
+    
+    //calculate filter values
+    cairo_t* cr = context->platformContext();
+    cairo_path_t* path = cairo_copy_path(cr);
+    double x0, x1, y0, y1;
+    cairo_stroke_extents(cr, &x0, &y0, &x1, &y1);
+    FloatRect rect(x0, y0, x1 - x0, y1 - y0);
+
+    IntSize shadowBufferSize;
+    FloatRect shadowRect;
+    float kernelSize (0.0);
+    GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur);
+
+    // create suitably-sized ImageBuffer to hold the shadow
+    OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize);
+
+    //draw shadow into a new ImageBuffer
+    cairo_t* shadowContext = shadowBuffer->context()->platformContext();
+    copyContextProperties(cr, shadowContext);
+    cairo_translate(shadowContext, -rect.x() + kernelSize, -rect.y() + kernelSize);
+    cairo_new_path(shadowContext);
+    cairo_append_path(shadowContext, path);
+
+    if (fillShadow)
+        setPlatformFill(context, shadowContext, gcp);
+    if (strokeShadow)
+        setPlatformStroke(context, shadowContext, gcp);
+
+    context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize);
+#endif
+}
+
 GraphicsContext::GraphicsContext(PlatformGraphicsContext* cr)
     : m_common(createGraphicsContextPrivate())
     , m_data(new GraphicsContextPlatformPrivate)
@@ -387,30 +508,12 @@ void GraphicsContext::fillPath()
         return;
 
     cairo_t* cr = m_data->cr;
-    cairo_save(cr);
 
     cairo_set_fill_rule(cr, fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
-    switch (m_common->state.fillType) {
-    case SolidColorType:
-        setColor(cr, fillColor());
-        cairo_clip(cr);
-        cairo_paint_with_alpha(cr, m_common->state.globalAlpha);
-        break;
-    case PatternType: {
-        TransformationMatrix affine;
-        cairo_set_source(cr, m_common->state.fillPattern->createPlatformPattern(affine));
-        cairo_clip(cr);
-        cairo_paint_with_alpha(cr, m_common->state.globalAlpha);
-        break;
-    }
-    case GradientType:
-        cairo_pattern_t* pattern = m_common->state.fillGradient->platformGradient();
-        cairo_set_source(cr, pattern);
-        cairo_clip(cr);
-        cairo_paint_with_alpha(cr, m_common->state.globalAlpha);
-        break;
-    }
-    cairo_restore(cr);
+    drawPathShadow(this, m_common, true, false);
+
+    setPlatformFill(this, cr, m_common);
+    cairo_new_path(cr);
 }
 
 void GraphicsContext::strokePath()
@@ -419,45 +522,26 @@ void GraphicsContext::strokePath()
         return;
 
     cairo_t* cr = m_data->cr;
-    cairo_save(cr);
-    switch (m_common->state.strokeType) {
-    case SolidColorType:
-        float red, green, blue, alpha;
-        strokeColor().getRGBA(red, green, blue, alpha);
-        if (m_common->state.globalAlpha < 1.0f)
-            alpha *= m_common->state.globalAlpha;
-        cairo_set_source_rgba(cr, red, green, blue, alpha);
-        cairo_stroke(cr);
-        break;
-    case PatternType: {
-        TransformationMatrix affine;
-        cairo_set_source(cr, m_common->state.strokePattern->createPlatformPattern(affine));
-        if (m_common->state.globalAlpha < 1.0f) {
-            cairo_push_group(cr);
-            cairo_paint_with_alpha(cr, m_common->state.globalAlpha);
-            cairo_pop_group_to_source(cr);
-        }
-        cairo_stroke(cr);
-        break;
-    }
-    case GradientType:
-        cairo_pattern_t* pattern = m_common->state.strokeGradient->platformGradient();
-        cairo_set_source(cr, pattern);
-        if (m_common->state.globalAlpha < 1.0f) {
-            cairo_push_group(cr);
-            cairo_paint_with_alpha(cr, m_common->state.globalAlpha);
-            cairo_pop_group_to_source(cr);
-        }
-        cairo_stroke(cr);
-        break;
-    }
-    cairo_restore(cr);
+    drawPathShadow(this, m_common, false, true);
+
+    setPlatformStroke(this, cr, m_common);
+    cairo_new_path(cr);
+
 }
 
 void GraphicsContext::drawPath()
 {
-    fillPath();
-    strokePath();
+    if (paintingDisabled())
+        return;
+
+    cairo_t* cr = m_data->cr;
+
+    cairo_set_fill_rule(cr, fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
+    drawPathShadow(this, m_common, true, true);
+
+    setPlatformFill(this, cr, m_common);
+    setPlatformStroke(this, cr, m_common);
+    cairo_new_path(cr);
 }
 
 void GraphicsContext::fillRect(const FloatRect& rect)
@@ -726,9 +810,48 @@ void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer
     notImplemented();
 }
 
-void GraphicsContext::setPlatformShadow(IntSize const&, int, Color const&, ColorSpace)
+void GraphicsContext::setPlatformShadow(IntSize const& size, int, Color const&, ColorSpace)
 {
-    notImplemented();
+    // Cairo doesn't support shadows natively, they are drawn manually in the draw*
+    // functions
+
+    if (m_common->state.shadowsIgnoreTransforms) {
+        // 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.shadowSize = IntSize(size.width(), -size.height());
+    }
+}
+
+void GraphicsContext::createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float kernelSize)
+{
+#if ENABLE(FILTERS)
+    cairo_t* cr = m_data->cr;
+
+    // draw the shadow without blurring, if kernelSize is zero
+    if (!kernelSize) {
+        setColor(cr, shadowColor);
+        cairo_mask_surface(cr, buffer->image()->nativeImageForCurrentFrame(), shadowRect.x(), shadowRect.y());
+        return;
+    }
+
+    // limit kernel size to 1000, this is what CG is doing.
+    kernelSize = std::min(1000.f, kernelSize);
+
+    // create filter
+    RefPtr<Filter> filter = ImageBufferFilter::create();
+    filter->setSourceImage(buffer.release());
+    RefPtr<FilterEffect> source = SourceGraphic::create();
+    source->setSubRegion(FloatRect(FloatPoint(), shadowRect.size()));
+    source->setIsAlphaImage(true);
+    RefPtr<FilterEffect> blur = FEGaussianBlur::create(source.get(), kernelSize, kernelSize);
+    blur->setSubRegion(FloatRect(FloatPoint(), shadowRect.size()));
+    blur->apply(filter.get());
+
+    // Mask the filter with the shadow color and draw it to the context.
+    // Masking makes it possible to just blur the alpha channel.
+    setColor(cr, shadowColor);
+    cairo_mask_surface(cr, blur->resultImage()->image()->nativeImageForCurrentFrame(), shadowRect.x(), shadowRect.y());
+#endif
 }
 
 void GraphicsContext::clearPlatformShadow()
index 7d187c7..615aa36 100644 (file)
@@ -132,6 +132,30 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo
     cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, srcRect.x(), srcRect.y() };
     cairo_pattern_set_matrix(pattern, &matrix);
 
+    // Draw the shadow
+#if ENABLE(FILTERS)
+    IntSize shadowSize;
+    int shadowBlur;
+    Color shadowColor;
+    if (context->getShadow(shadowSize, shadowBlur, shadowColor)) {
+        IntSize shadowBufferSize;
+        FloatRect shadowRect;
+        float kernelSize (0.0);
+        GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, dstRect, shadowSize, shadowBlur);
+        shadowColor = colorWithOverrideAlpha(shadowColor.rgb(), (shadowColor.alpha() *  context->getAlpha()) / 255.f);
+
+        //draw shadow into a new ImageBuffer
+        OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize);
+        cairo_t* shadowContext = shadowBuffer->context()->platformContext();
+        cairo_set_source(shadowContext, pattern);
+        cairo_translate(shadowContext, -dstRect.x(), -dstRect.y());
+        cairo_rectangle(shadowContext, 0, 0, dstRect.width(), dstRect.height());
+        cairo_fill(shadowContext);
+
+        context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize);
+    }
+#endif
+
     // Draw the image.
     cairo_translate(cr, dstRect.x(), dstRect.y());
     cairo_set_source(cr, pattern);
index ee97afc..0728e84 100644 (file)
@@ -40,12 +40,12 @@ namespace WebCore {
         void setSourceImage(PassOwnPtr<ImageBuffer> sourceImage) { m_sourceImage = sourceImage; }
         ImageBuffer* sourceImage() { return m_sourceImage.get(); }
 
-        virtual FloatRect sourceImageRect() = 0;
-        virtual FloatRect filterRegion() = 0;
+        virtual FloatRect sourceImageRect() const = 0;
+        virtual FloatRect filterRegion() const = 0;
 
         // SVG specific
-        virtual void calculateEffectSubRegion(FilterEffect*) = 0;
-        virtual bool effectBoundingBoxMode() = 0;
+        virtual void calculateEffectSubRegion(FilterEffect*) const = 0;
+        virtual bool effectBoundingBoxMode() const = 0;
 
     private:
         OwnPtr<ImageBuffer> m_sourceImage;
diff --git a/WebCore/platform/graphics/filters/ImageBufferFilter.cpp b/WebCore/platform/graphics/filters/ImageBufferFilter.cpp
new file mode 100644 (file)
index 0000000..ddb3af8
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *  Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org>
+ *
+ *   This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  aint with this library; see the file COPYING.LIB.  If not, write to
+ *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "ImageBufferFilter.h"
+
+namespace WebCore {
+
+ImageBufferFilter::ImageBufferFilter()
+    : Filter()
+{
+}
+
+PassRefPtr<ImageBufferFilter> ImageBufferFilter::create()
+{
+    return adoptRef(new ImageBufferFilter());
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/WebCore/platform/graphics/filters/ImageBufferFilter.h b/WebCore/platform/graphics/filters/ImageBufferFilter.h
new file mode 100644 (file)
index 0000000..ef972d9
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *  Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org>
+ *
+ *   This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  aint with this library; see the file COPYING.LIB.  If not, write to
+ *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ */
+
+#ifndef ImageBufferFilter_h
+#define ImageBufferFilter_h
+
+#if ENABLE(FILTERS)
+#include "Filter.h"
+#include "FilterEffect.h"
+#include "FloatRect.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class ImageBufferFilter : public Filter {
+public:
+    static PassRefPtr<ImageBufferFilter> create();
+
+    virtual FloatRect filterRegion() const { return FloatRect(); }
+    virtual FloatRect sourceImageRect() const { return FloatRect(); }
+
+    // SVG specific
+    virtual bool effectBoundingBoxMode() const { return false; }
+    virtual void calculateEffectSubRegion(FilterEffect*) const { }
+
+private:
+    ImageBufferFilter();
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // ImageBufferFilter_h
index 6bfcf39..e684135 100644 (file)
@@ -32,7 +32,7 @@ SVGFilter::SVGFilter(const FloatRect& itemBox, const FloatRect& filterRect, bool
 {
 }
 
-void SVGFilter::calculateEffectSubRegion(FilterEffect* effect)
+void SVGFilter::calculateEffectSubRegion(FilterEffect* effect) const
 {
     FloatRect subRegionBBox = effect->subRegion();
     FloatRect useBBox = effect->unionOfChildEffectSubregions();
index f23d1ea..a5da050 100644 (file)
@@ -35,11 +35,11 @@ namespace WebCore {
     public:
         static PassRefPtr<SVGFilter> create(const FloatRect&, const FloatRect&, bool);
 
-        bool effectBoundingBoxMode() { return m_effectBBoxMode; }
+        bool effectBoundingBoxMode() const { return m_effectBBoxMode; }
 
-        FloatRect filterRegion() { return m_filterRect; }
-        FloatRect sourceImageRect() { return m_itemBox; }
-        void calculateEffectSubRegion(FilterEffect*);
+        FloatRect filterRegion() const { return m_filterRect; }
+        FloatRect sourceImageRect() const { return m_itemBox; }
+        void calculateEffectSubRegion(FilterEffect*) const;
 
     private:
         SVGFilter(const FloatRect& itemBox, const FloatRect& filterRect, bool effectBBoxMode);