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

zherczeg at webkit.org zherczeg at webkit.org
Wed Dec 22 18:30:10 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 2cc3139ba9a255859577a0dff83250a31b64260f
Author: zherczeg at webkit.org <zherczeg at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Mon Dec 13 10:15:53 2010 +0000

    Better result passing in filter primitives
    https://bugs.webkit.org/show_bug.cgi?id=49907
    
    Reviewed by Dirk Schulze.
    
    SVG filter primitives can use the output of other filters. The
    input and output format of a filter can be a premultiplied or
    unmultiplied RGBA array, or an image buffer. All filter
    primitive results were converted to image buffers before, which
    could be an unecessary (and really costly) operation, if
    a filter expects its input in the same format as the output
    of the input filter primitive. This overhead is removed by
    this patch. All apply() methods are updated according to this
    new filter primitive interface.
    
    Filters do not generate their results twice (or more) anymore,
    when their apply() called multiple times.
    
    The existing tests cover this feature.
    
    * manual-tests/svg-filter-animation.svg: Added.
    * platform/graphics/filters/FEBlend.cpp:
    (WebCore::FEBlend::apply):
    * platform/graphics/filters/FEColorMatrix.cpp:
    (WebCore::FEColorMatrix::apply):
    * platform/graphics/filters/FEComponentTransfer.cpp:
    (WebCore::FEComponentTransfer::apply):
    * platform/graphics/filters/FEComposite.cpp:
    (WebCore::FEComposite::apply):
    * platform/graphics/filters/FEConvolveMatrix.cpp:
    (WebCore::FEConvolveMatrix::apply):
    * platform/graphics/filters/FEDisplacementMap.cpp:
    (WebCore::FEDisplacementMap::apply):
    * platform/graphics/filters/FEFlood.cpp:
    (WebCore::FEFlood::apply):
    * platform/graphics/filters/FEGaussianBlur.cpp:
    (WebCore::FEGaussianBlur::apply):
    * platform/graphics/filters/FELighting.cpp:
    (WebCore::FELighting::apply):
    * platform/graphics/filters/FEMerge.cpp:
    (WebCore::FEMerge::apply):
    * platform/graphics/filters/FEMerge.h:
    * platform/graphics/filters/FEMorphology.cpp:
    (WebCore::FEMorphology::apply):
    * platform/graphics/filters/FEOffset.cpp:
    (WebCore::FEOffset::apply):
    * platform/graphics/filters/FETile.cpp:
    (WebCore::FETile::apply):
    * platform/graphics/filters/FETurbulence.cpp:
    (WebCore::FETurbulence::apply):
    * platform/graphics/filters/FilterEffect.cpp:
    (WebCore::FilterEffect::requestedRegionOfInputImageData):
    (WebCore::FilterEffect::asImageBuffer):
    (WebCore::FilterEffect::asUnmultipliedImage):
    (WebCore::FilterEffect::asPremultipliedImage):
    (WebCore::FilterEffect::copyImageBytes):
    (WebCore::FilterEffect::copyUnmultipliedImage):
    (WebCore::FilterEffect::copyPremultipliedImage):
    (WebCore::FilterEffect::createImageBufferResult):
    (WebCore::FilterEffect::createUnmultipliedImageResult):
    (WebCore::FilterEffect::createPremultipliedImageResult):
    * platform/graphics/filters/FilterEffect.h:
    (WebCore::FilterEffect::hasResult):
    * platform/graphics/filters/SourceAlpha.cpp:
    (WebCore::SourceAlpha::apply):
    * platform/graphics/filters/SourceGraphic.cpp:
    (WebCore::SourceGraphic::apply):
    * platform/graphics/filters/SourceGraphic.h:
    * rendering/RenderSVGResourceFilter.cpp:
    (WebCore::RenderSVGResourceFilter::postApplyResource):
    * svg/graphics/filters/SVGFEImage.cpp:
    (WebCore::FEImage::apply):
    
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@73894 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index ccc2804..eee6c4f 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,78 @@
+2010-12-13  Zoltan Herczeg  <zherczeg at webkit.org>
+
+        Reviewed by Dirk Schulze.
+
+        Better result passing in filter primitives
+        https://bugs.webkit.org/show_bug.cgi?id=49907
+
+        SVG filter primitives can use the output of other filters. The
+        input and output format of a filter can be a premultiplied or
+        unmultiplied RGBA array, or an image buffer. All filter
+        primitive results were converted to image buffers before, which
+        could be an unecessary (and really costly) operation, if
+        a filter expects its input in the same format as the output
+        of the input filter primitive. This overhead is removed by
+        this patch. All apply() methods are updated according to this
+        new filter primitive interface.
+
+        Filters do not generate their results twice (or more) anymore,
+        when their apply() called multiple times.
+
+        The existing tests cover this feature.
+
+        * manual-tests/svg-filter-animation.svg: Added.
+        * platform/graphics/filters/FEBlend.cpp:
+        (WebCore::FEBlend::apply):
+        * platform/graphics/filters/FEColorMatrix.cpp:
+        (WebCore::FEColorMatrix::apply):
+        * platform/graphics/filters/FEComponentTransfer.cpp:
+        (WebCore::FEComponentTransfer::apply):
+        * platform/graphics/filters/FEComposite.cpp:
+        (WebCore::FEComposite::apply):
+        * platform/graphics/filters/FEConvolveMatrix.cpp:
+        (WebCore::FEConvolveMatrix::apply):
+        * platform/graphics/filters/FEDisplacementMap.cpp:
+        (WebCore::FEDisplacementMap::apply):
+        * platform/graphics/filters/FEFlood.cpp:
+        (WebCore::FEFlood::apply):
+        * platform/graphics/filters/FEGaussianBlur.cpp:
+        (WebCore::FEGaussianBlur::apply):
+        * platform/graphics/filters/FELighting.cpp:
+        (WebCore::FELighting::apply):
+        * platform/graphics/filters/FEMerge.cpp:
+        (WebCore::FEMerge::apply):
+        * platform/graphics/filters/FEMerge.h:
+        * platform/graphics/filters/FEMorphology.cpp:
+        (WebCore::FEMorphology::apply):
+        * platform/graphics/filters/FEOffset.cpp:
+        (WebCore::FEOffset::apply):
+        * platform/graphics/filters/FETile.cpp:
+        (WebCore::FETile::apply):
+        * platform/graphics/filters/FETurbulence.cpp:
+        (WebCore::FETurbulence::apply):
+        * platform/graphics/filters/FilterEffect.cpp:
+        (WebCore::FilterEffect::requestedRegionOfInputImageData):
+        (WebCore::FilterEffect::asImageBuffer):
+        (WebCore::FilterEffect::asUnmultipliedImage):
+        (WebCore::FilterEffect::asPremultipliedImage):
+        (WebCore::FilterEffect::copyImageBytes):
+        (WebCore::FilterEffect::copyUnmultipliedImage):
+        (WebCore::FilterEffect::copyPremultipliedImage):
+        (WebCore::FilterEffect::createImageBufferResult):
+        (WebCore::FilterEffect::createUnmultipliedImageResult):
+        (WebCore::FilterEffect::createPremultipliedImageResult):
+        * platform/graphics/filters/FilterEffect.h:
+        (WebCore::FilterEffect::hasResult):
+        * platform/graphics/filters/SourceAlpha.cpp:
+        (WebCore::SourceAlpha::apply):
+        * platform/graphics/filters/SourceGraphic.cpp:
+        (WebCore::SourceGraphic::apply):
+        * platform/graphics/filters/SourceGraphic.h:
+        * rendering/RenderSVGResourceFilter.cpp:
+        (WebCore::RenderSVGResourceFilter::postApplyResource):
+        * svg/graphics/filters/SVGFEImage.cpp:
+        (WebCore::FEImage::apply):
+
 2010-12-13  Csaba Osztrogonác  <ossy at webkit.org>
 
         Unreviewed.
diff --git a/WebCore/manual-tests/svg-filter-animation.svg b/WebCore/manual-tests/svg-filter-animation.svg
new file mode 100644
index 0000000..5b7c9cc
--- /dev/null
+++ b/WebCore/manual-tests/svg-filter-animation.svg
@@ -0,0 +1,120 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<!--
+  Copyright (C) 2010 University of Szeged
+  Copyright (C) 2010 Zoltan Herczeg
+  Copyright (C) 2010 Gabor Loki
+  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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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.
+-->
+
+<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
+<rect x="0%" y="0%" width="100%" height="100%" fill="black" />
+
+<defs>
+<filter id="filt" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
+    <feTurbulence id="turb" baseFrequency="0.03" numOctaves="4" seed="67" result="turb"/>
+    <feGaussianBlur in="SourceGraphic" primitiveUnits="objectBoundingBox" id="blur" stdDeviation="1" result="blur"/>
+    <feComposite in="turb" in2="blur" operator="arithmetic" k2="0.3" k3="1" result="comp"/>
+    <feDiffuseLighting in="comp" primitiveUnits="objectBoundingBox" id="diff" diffuseConstant="1" lighting-color="white" surfaceScale="10" result="light" >
+        <feSpotLight id="light" x="0" y="300" z="200" pointsAtX="-200" pointsAtY="100" pointsAtZ="0" limitingConeAngle="90" specularExponent="20" />
+    </feDiffuseLighting>
+    <feSpecularLighting in="comp" primitiveUnits="objectBoundingBox" id="diff" diffuseConstant="1" lighting-color="#A66102" surfaceScale="10" result="ambient" >
+        <feDistantLight id="light" azimuth="0" elevation="90" />
+    </feSpecularLighting>
+        <feComposite in="light" in2="ambient" operator="arithmetic" k2="1.2" k3=".8"/>
+</filter>
+</defs>
+
+<g filter="url(#filt)" fill="white" stroke="black" onclick="start()">
+    <rect x="0" y="0" width="400" height="5" />
+    <rect x="0" y="0" width="5" height="200" />
+    <rect x="0" y="195" width="400" height="5" />
+    <rect x="395" y="0" width="5" height="200" />
+    <text font-size="150" font-weight="bold" x="40" y="150">SVG</text>
+</g>
+
+<text id="fps" x="150" y="240" font-size="20" fill="white" stroke="white">afps:</text>
+<text x="30" y="265" font-size="20" font-weight="bold" fill="white" stroke="white">click on the image to start the animation</text>
+
+<script>
+<![CDATA[
+var light_x = document.getElementById('light').x;
+var light_y = document.getElementById('light').y;
+var light_pointsAtX = document.getElementById('light').pointsAtX;
+var light_pointsAtY = document.getElementById('light').pointsAtY;
+var fps = document.getElementById('fps');
+
+var round = Math.round
+
+var startDate = 0;
+var frameCounter = 0;
+var phase = 0;
+function anim() {
+    switch(phase) {
+    case 0:
+        light_pointsAtX.baseVal += 10;
+        if (light_pointsAtX.baseVal >= 380)
+            ++phase;
+        break;
+    case 1:
+        light_x.baseVal += 10;
+        light_pointsAtX.baseVal -= 10;
+        if (light_x.baseVal >= 450) {
+            ++phase;
+            waitCounter = 0;
+        }
+        break;
+    case 2:
+        light_y.baseVal -= 5;
+        if (light_y.baseVal <= -100)
+            ++phase;
+        break;
+    case 3:
+        light_pointsAtX.baseVal += 10;
+        if (light_pointsAtX.baseVal >= 450) {
+            light_x.baseVal = 0;
+            light_pointsAtX.baseVal = -200;
+            light_y.baseVal = 300;
+            light_pointsAtY.baseVal = 100;
+            phase = 0;
+        }
+        break;
+    }
+
+    frameCounter++;
+    fps.textContent = "afps: " +(round(frameCounter * 100000 / (new Date() - startDate)) / 100);
+}
+
+function start() {
+    if (!startDate) {
+        startDate = new Date();
+        setInterval(anim,1);
+    }
+}
+
+//]]>
+</script>
+
+</svg>
diff --git a/WebCore/platform/graphics/filters/FEBlend.cpp b/WebCore/platform/graphics/filters/FEBlend.cpp
index 89b44e0..f863487 100644
--- a/WebCore/platform/graphics/filters/FEBlend.cpp
+++ b/WebCore/platform/graphics/filters/FEBlend.cpp
@@ -88,30 +88,31 @@ static unsigned char lighten(unsigned char colorA, unsigned char colorB, unsigne
 
 void FEBlend::apply()
 {
+    if (hasResult())
+        return;
     FilterEffect* in = inputEffect(0);
     FilterEffect* in2 = inputEffect(1);
     in->apply();
     in2->apply();
-    if (!in->resultImage() || !in2->resultImage())
+    if (!in->hasResult() || !in2->hasResult())
         return;
 
     if (m_mode <= FEBLEND_MODE_UNKNOWN || m_mode > FEBLEND_MODE_LIGHTEN)
         return;
 
-    if (!effectContext())
+    ImageData* resultImage = createPremultipliedImageResult();
+    if (!resultImage)
         return;
 
     IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
-    RefPtr<ImageData> srcImageDataA = in->resultImage()->getPremultipliedImageData(effectADrawingRect);
+    RefPtr<ImageData> srcImageDataA = in->asPremultipliedImage(effectADrawingRect);
     ByteArray* srcPixelArrayA = srcImageDataA->data()->data();
 
     IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
-    RefPtr<ImageData> srcImageDataB = in2->resultImage()->getPremultipliedImageData(effectBDrawingRect);
+    RefPtr<ImageData> srcImageDataB = in2->asPremultipliedImage(effectBDrawingRect);
     ByteArray* srcPixelArrayB = srcImageDataB->data()->data();
 
-    IntRect imageRect(IntPoint(), resultImage()->size());
-    RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height());
-    ByteArray* dstPixelArray = imageData->data()->data();
+    ByteArray* dstPixelArray = resultImage->data()->data();
 
     // Keep synchronized with BlendModeType
     static const BlendType callEffect[] = {unknown, normal, multiply, screen, darken, lighten};
@@ -131,8 +132,6 @@ void FEBlend::apply()
         unsigned char alphaR = 255 - ((255 - alphaA) * (255 - alphaB)) / 255;
         dstPixelArray->set(pixelOffset + 3, alphaR);
     }
-
-    resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint());
 }
 
 void FEBlend::dump()
diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp
index 1c99b1e..38246cf 100644
--- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp
+++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp
@@ -150,19 +150,21 @@ void effectType(ByteArray* pixelArray, const Vector<float>& values)
 
 void FEColorMatrix::apply()
 {
+    if (hasResult())
+        return;
     FilterEffect* in = inputEffect(0);
     in->apply();
-    if (!in->resultImage())
+    if (!in->hasResult())
         return;
 
-    GraphicsContext* filterContext = effectContext();
-    if (!filterContext)
+    ImageBuffer* resultImage = createImageBufferResult();
+    if (!resultImage)
         return;
 
-    filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
+    resultImage->context()->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
 
-    IntRect imageRect(IntPoint(), resultImage()->size());
-    RefPtr<ImageData> imageData = resultImage()->getUnmultipliedImageData(imageRect);
+    IntRect imageRect(IntPoint(), absolutePaintRect().size());
+    RefPtr<ImageData> imageData = resultImage->getUnmultipliedImageData(imageRect);
     ByteArray* pixelArray = imageData->data()->data();
 
     switch (m_type) {
@@ -183,7 +185,7 @@ void FEColorMatrix::apply()
             break;
     }
 
-    resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint());
+    resultImage->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint());
 }
 
 void FEColorMatrix::dump()
diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
index cfab50b..f8f651c 100644
--- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
+++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
@@ -149,12 +149,15 @@ static void gamma(unsigned char* values, const ComponentTransferFunction& transf
 
 void FEComponentTransfer::apply()
 {
+    if (hasResult())
+        return;
     FilterEffect* in = inputEffect(0);
     in->apply();
-    if (!in->resultImage())
+    if (!in->hasResult())
         return;
 
-    if (!effectContext())
+    ImageData* imageData = createUnmultipliedImageResult();
+    if (!imageData)
         return;
 
     unsigned char rValues[256], gValues[256], bValues[256], aValues[256];
@@ -168,7 +171,7 @@ void FEComponentTransfer::apply()
         (*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]);
 
     IntRect drawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
-    RefPtr<ImageData> imageData = in->resultImage()->getUnmultipliedImageData(drawingRect);
+    in->copyUnmultipliedImage(imageData, drawingRect);
     ByteArray* pixelArray = imageData->data()->data();
 
     unsigned pixelArrayLength = pixelArray->length();
@@ -178,8 +181,6 @@ void FEComponentTransfer::apply()
             pixelArray->set(pixelOffset + channel, tables[channel][c]);
         }
     }
-
-    resultImage()->putUnmultipliedImageData(imageData.get(), IntRect(IntPoint(), resultImage()->size()), IntPoint());
 }
 
 void FEComponentTransfer::dump()
diff --git a/WebCore/platform/graphics/filters/FEComposite.cpp b/WebCore/platform/graphics/filters/FEComposite.cpp
index d27321f..010ceef 100644
--- a/WebCore/platform/graphics/filters/FEComposite.cpp
+++ b/WebCore/platform/graphics/filters/FEComposite.cpp
@@ -137,52 +137,55 @@ void FEComposite::determineAbsolutePaintRect()
 
 void FEComposite::apply()
 {
+    if (hasResult())
+        return;
     FilterEffect* in = inputEffect(0);
     FilterEffect* in2 = inputEffect(1);
     in->apply();
     in2->apply();
-    if (!in->resultImage() || !in2->resultImage())
+    if (!in->hasResult() || !in2->hasResult())
         return;
 
-    GraphicsContext* filterContext = effectContext();
-    if (!filterContext)
+    ImageBuffer* resultImage = createImageBufferResult();
+    if (!resultImage)
         return;
+    GraphicsContext* filterContext = resultImage->context();
 
     FloatRect srcRect = FloatRect(0, 0, -1, -1);
     switch (m_type) {
     case FECOMPOSITE_OPERATOR_OVER:
-        filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
-        filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
+        filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
+        filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
         break;
     case FECOMPOSITE_OPERATOR_IN:
         filterContext->save();
-        filterContext->clipToImageBuffer(in2->resultImage(), drawingRegionOfInputImage(in2->absolutePaintRect()));
-        filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
+        filterContext->clipToImageBuffer(in2->asImageBuffer(), drawingRegionOfInputImage(in2->absolutePaintRect()));
+        filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
         filterContext->restore();
         break;
     case FECOMPOSITE_OPERATOR_OUT:
-        filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
-        filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()), srcRect, CompositeDestinationOut);
+        filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
+        filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()), srcRect, CompositeDestinationOut);
         break;
     case FECOMPOSITE_OPERATOR_ATOP:
-        filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
-        filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeSourceAtop);
+        filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
+        filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeSourceAtop);
         break;
     case FECOMPOSITE_OPERATOR_XOR:
-        filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
-        filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeXOR);
+        filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
+        filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeXOR);
         break;
     case FECOMPOSITE_OPERATOR_ARITHMETIC: {
         IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
-        RefPtr<ImageData> srcImageData = in->resultImage()->getPremultipliedImageData(effectADrawingRect);
+        RefPtr<ImageData> srcImageData = in->asImageBuffer()->getPremultipliedImageData(effectADrawingRect);
         ByteArray* srcPixelArrayA = srcImageData->data()->data();
 
         IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
-        RefPtr<ImageData> imageData = in2->resultImage()->getPremultipliedImageData(effectBDrawingRect);
+        RefPtr<ImageData> imageData = in2->asImageBuffer()->getPremultipliedImageData(effectBDrawingRect);
         ByteArray* srcPixelArrayB = imageData->data()->data();
 
         arithmetic(srcPixelArrayA, srcPixelArrayB, m_k1, m_k2, m_k3, m_k4);
-        resultImage()->putPremultipliedImageData(imageData.get(), IntRect(IntPoint(), resultImage()->size()), IntPoint());
+        resultImage->putPremultipliedImageData(imageData.get(), IntRect(IntPoint(), resultImage->size()), IntPoint());
         }
         break;
     default:
diff --git a/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp b/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp
index 198d764..d1f9c7b 100644
--- a/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp
+++ b/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp
@@ -372,35 +372,40 @@ ALWAYS_INLINE void FEConvolveMatrix::setOuterPixels(PaintingData& paintingData,
 
 void FEConvolveMatrix::apply()
 {
+    if (hasResult())
+        return;
     FilterEffect* in = inputEffect(0);
     in->apply();
-    if (!in->resultImage())
+    if (!in->hasResult())
         return;
 
-    if (!effectContext())
+    ImageData* resultImage;
+    if (m_preserveAlpha)
+        resultImage = createUnmultipliedImageResult();
+    else
+        resultImage = createPremultipliedImageResult();
+    if (!resultImage)
         return;
 
-    IntRect imageRect(IntPoint(), resultImage()->size());
     IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
 
     RefPtr<CanvasPixelArray> srcPixelArray;
     if (m_preserveAlpha)
-        srcPixelArray = in->resultImage()->getUnmultipliedImageData(effectDrawingRect)->data();
+        srcPixelArray = in->asUnmultipliedImage(effectDrawingRect)->data();
     else
-        srcPixelArray = in->resultImage()->getPremultipliedImageData(effectDrawingRect)->data();
-
-    RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height());
+        srcPixelArray = in->asPremultipliedImage(effectDrawingRect)->data();
 
+    IntSize paintSize = absolutePaintRect().size();
     PaintingData paintingData;
     paintingData.srcPixelArray = srcPixelArray.get();
-    paintingData.dstPixelArray = imageData->data();
-    paintingData.width = imageRect.width();
-    paintingData.height = imageRect.height();
+    paintingData.dstPixelArray = resultImage->data();
+    paintingData.width = paintSize.width();
+    paintingData.height = paintSize.height();
     paintingData.bias = m_bias * 255;
 
     // Drawing fully covered pixels
-    int clipRight = imageRect.width() - m_kernelSize.width();
-    int clipBottom = imageRect.height() - m_kernelSize.height();
+    int clipRight = paintSize.width() - m_kernelSize.width();
+    int clipBottom = paintSize.height() - m_kernelSize.height();
 
     if (clipRight >= 0 && clipBottom >= 0) {
         setInteriorPixels(paintingData, clipRight, clipBottom);
@@ -408,22 +413,17 @@ void FEConvolveMatrix::apply()
         clipRight += m_targetOffset.x() + 1;
         clipBottom += m_targetOffset.y() + 1;
         if (m_targetOffset.y() > 0)
-            setOuterPixels(paintingData, 0, 0, imageRect.width(), m_targetOffset.y());
-        if (clipBottom < imageRect.height())
-            setOuterPixels(paintingData, 0, clipBottom, imageRect.width(), imageRect.height());
+            setOuterPixels(paintingData, 0, 0, paintSize.width(), m_targetOffset.y());
+        if (clipBottom < paintSize.height())
+            setOuterPixels(paintingData, 0, clipBottom, paintSize.width(), paintSize.height());
         if (m_targetOffset.x() > 0)
             setOuterPixels(paintingData, 0, m_targetOffset.y(), m_targetOffset.x(), clipBottom);
-        if (clipRight < imageRect.width())
-            setOuterPixels(paintingData, clipRight, m_targetOffset.y(), imageRect.width(), clipBottom);
+        if (clipRight < paintSize.width())
+            setOuterPixels(paintingData, clipRight, m_targetOffset.y(), paintSize.width(), clipBottom);
     } else {
         // Rare situation, not optimizied for speed
-        setOuterPixels(paintingData, 0, 0, imageRect.width(), imageRect.height());
+        setOuterPixels(paintingData, 0, 0, paintSize.width(), paintSize.height());
     }
-
-    if (m_preserveAlpha)
-        resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint());
-    else
-        resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint());
 }
 
 void FEConvolveMatrix::dump()
diff --git a/WebCore/platform/graphics/filters/FEDisplacementMap.cpp b/WebCore/platform/graphics/filters/FEDisplacementMap.cpp
index 55321e6..93239c4 100644
--- a/WebCore/platform/graphics/filters/FEDisplacementMap.cpp
+++ b/WebCore/platform/graphics/filters/FEDisplacementMap.cpp
@@ -78,57 +78,57 @@ void FEDisplacementMap::setScale(float scale)
 
 void FEDisplacementMap::apply()
 {
+    if (hasResult())
+        return;
     FilterEffect* in = inputEffect(0);
     FilterEffect* in2 = inputEffect(1);
     in->apply();
     in2->apply();
-    if (!in->resultImage() || !in2->resultImage())
+    if (!in->hasResult() || !in2->hasResult())
         return;
 
     if (m_xChannelSelector == CHANNEL_UNKNOWN || m_yChannelSelector == CHANNEL_UNKNOWN)
         return;
 
-    if (!effectContext())
+    ImageData* resultImage = createPremultipliedImageResult();
+    if (!resultImage)
         return;
 
     IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
-    RefPtr<ImageData> srcImageDataA = in->resultImage()->getPremultipliedImageData(effectADrawingRect);
-    ByteArray* srcPixelArrayA = srcImageDataA->data()->data() ;
+    RefPtr<ImageData> srcImageDataA = in->asPremultipliedImage(effectADrawingRect);
+    ByteArray* srcPixelArrayA = srcImageDataA->data()->data();
 
     IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
-    RefPtr<ImageData> srcImageDataB = in2->resultImage()->getUnmultipliedImageData(effectBDrawingRect);
+    RefPtr<ImageData> srcImageDataB = in2->asUnmultipliedImage(effectBDrawingRect);
     ByteArray* srcPixelArrayB = srcImageDataB->data()->data();
 
-    IntRect imageRect(IntPoint(), resultImage()->size());
-    RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height());
-    ByteArray* dstPixelArray = imageData->data()->data();
+    ByteArray* dstPixelArray = resultImage->data()->data();
 
     ASSERT(srcPixelArrayA->length() == srcPixelArrayB->length());
 
     Filter* filter = this->filter();
+    IntSize paintSize = absolutePaintRect().size();
     float scaleX = filter->applyHorizontalScale(m_scale / 255);
     float scaleY = filter->applyVerticalScale(m_scale / 255);
     float scaleAdjustmentX = filter->applyHorizontalScale(0.5f - 0.5f * m_scale);
     float scaleAdjustmentY = filter->applyVerticalScale(0.5f - 0.5f * m_scale);
-    int stride = imageRect.width() * 4;
-    for (int y = 0; y < imageRect.height(); ++y) {
+    int stride = paintSize.width() * 4;
+    for (int y = 0; y < paintSize.height(); ++y) {
         int line = y * stride;
-        for (int x = 0; x < imageRect.width(); ++x) {
+        for (int x = 0; x < paintSize.width(); ++x) {
             int dstIndex = line + x * 4;
             int srcX = x + static_cast<int>(scaleX * srcPixelArrayB->get(dstIndex + m_xChannelSelector - 1) + scaleAdjustmentX);
             int srcY = y + static_cast<int>(scaleY * srcPixelArrayB->get(dstIndex + m_yChannelSelector - 1) + scaleAdjustmentY);
             for (unsigned channel = 0; channel < 4; ++channel) {
-                if (srcX < 0 || srcX >= imageRect.width() || srcY < 0 || srcY >= imageRect.height())
+                if (srcX < 0 || srcX >= paintSize.width() || srcY < 0 || srcY >= paintSize.height())
                     dstPixelArray->set(dstIndex + channel, static_cast<unsigned char>(0));
                 else {
                     unsigned char pixelValue = srcPixelArrayA->get(srcY * stride + srcX * 4 + channel);
                     dstPixelArray->set(dstIndex + channel, pixelValue);
                 }
             }
-
         }
     }
-    resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint());
 }
 
 void FEDisplacementMap::dump()
diff --git a/WebCore/platform/graphics/filters/FEFlood.cpp b/WebCore/platform/graphics/filters/FEFlood.cpp
index bc6721b..8bfdef8 100644
--- a/WebCore/platform/graphics/filters/FEFlood.cpp
+++ b/WebCore/platform/graphics/filters/FEFlood.cpp
@@ -64,12 +64,14 @@ void FEFlood::setFloodOpacity(float floodOpacity)
 
 void FEFlood::apply()
 {
-    GraphicsContext* filterContext = effectContext();
-    if (!filterContext)
+    if (hasResult())
+        return;
+    ImageBuffer* resultImage = createImageBufferResult();
+    if (!resultImage)
         return;
 
     Color color = colorWithOverrideAlpha(floodColor().rgb(), floodOpacity());
-    filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()), color, ColorSpaceDeviceRGB);
+    resultImage->context()->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()), color, ColorSpaceDeviceRGB);
 }
 
 void FEFlood::dump()
diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp
index 876e4b3..e1ffcb7 100644
--- a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp
+++ b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp
@@ -164,34 +164,35 @@ void FEGaussianBlur::determineAbsolutePaintRect()
 
 void FEGaussianBlur::apply()
 {
+    if (hasResult())
+        return;
     FilterEffect* in = inputEffect(0);
     in->apply();
-    if (!in->resultImage())
+    if (!in->hasResult())
         return;
 
-    if (!effectContext())
+    ImageData* resultImage = createPremultipliedImageResult();
+    if (!resultImage)
         return;
 
     setIsAlphaImage(in->isAlphaImage());
 
     IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
-    RefPtr<ImageData> srcImageData = in->resultImage()->getPremultipliedImageData(effectDrawingRect);
-    IntRect imageRect(IntPoint(), resultImage()->size());
+    in->copyPremultipliedImage(resultImage, effectDrawingRect);
 
-    if (!m_stdX && !m_stdY) {
-        resultImage()->putPremultipliedImageData(srcImageData.get(), imageRect, IntPoint());
+    if (!m_stdX && !m_stdY)
         return;
-    }
 
     unsigned kernelSizeX = 0;
     unsigned kernelSizeY = 0;
     calculateKernelSize(filter(), kernelSizeX, kernelSizeY, m_stdX, m_stdY);
 
-    ByteArray* srcPixelArray = srcImageData->data()->data();
-    RefPtr<ImageData> tmpImageData = ImageData::create(imageRect.width(), imageRect.height());
+    IntSize paintSize = absolutePaintRect().size();
+    ByteArray* srcPixelArray = resultImage->data()->data();
+    RefPtr<ImageData> tmpImageData = ImageData::create(paintSize.width(), paintSize.height());
     ByteArray* tmpPixelArray = tmpImageData->data()->data();
 
-    int stride = 4 * imageRect.width();
+    int stride = 4 * paintSize.width();
     int dxLeft = 0;
     int dxRight = 0;
     int dyLeft = 0;
@@ -199,7 +200,7 @@ void FEGaussianBlur::apply()
     for (int i = 0; i < 3; ++i) {
         if (kernelSizeX) {
             kernelPosition(i, kernelSizeX, dxLeft, dxRight);
-            boxBlur(srcPixelArray, tmpPixelArray, kernelSizeX, dxLeft, dxRight, 4, stride, imageRect.width(), imageRect.height(), isAlphaImage());
+            boxBlur(srcPixelArray, tmpPixelArray, kernelSizeX, dxLeft, dxRight, 4, stride, paintSize.width(), paintSize.height(), isAlphaImage());
         } else {
             ByteArray* auxPixelArray = tmpPixelArray;
             tmpPixelArray = srcPixelArray;
@@ -208,15 +209,13 @@ void FEGaussianBlur::apply()
 
         if (kernelSizeY) {
             kernelPosition(i, kernelSizeY, dyLeft, dyRight);
-            boxBlur(tmpPixelArray, srcPixelArray, kernelSizeY, dyLeft, dyRight, stride, 4, imageRect.height(), imageRect.width(), isAlphaImage());
+            boxBlur(tmpPixelArray, srcPixelArray, kernelSizeY, dyLeft, dyRight, stride, 4, paintSize.height(), paintSize.width(), isAlphaImage());
         } else {
             ByteArray* auxPixelArray = tmpPixelArray;
             tmpPixelArray = srcPixelArray;
             srcPixelArray = auxPixelArray;
         }
     }
-
-    resultImage()->putPremultipliedImageData(srcImageData.get(), imageRect, IntPoint());
 }
 
 void FEGaussianBlur::dump()
diff --git a/WebCore/platform/graphics/filters/FELighting.cpp b/WebCore/platform/graphics/filters/FELighting.cpp
index 812920c..4db40f1 100644
--- a/WebCore/platform/graphics/filters/FELighting.cpp
+++ b/WebCore/platform/graphics/filters/FELighting.cpp
@@ -331,19 +331,22 @@ bool FELighting::drawLighting(ByteArray* pixels, int width, int height)
 
 void FELighting::apply()
 {
+    if (hasResult())
+        return;
     FilterEffect* in = inputEffect(0);
     in->apply();
-    if (!in->resultImage())
+    if (!in->hasResult())
         return;
 
-    if (!effectContext())
+    ImageData* resultImage = createUnmultipliedImageResult();
+    if (!resultImage)
         return;
 
     setIsAlphaImage(false);
 
     IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
-    RefPtr<ImageData> srcImageData = in->resultImage()->getUnmultipliedImageData(effectDrawingRect);
-    ByteArray* srcPixelArray = srcImageData->data()->data();
+    in->copyUnmultipliedImage(resultImage, effectDrawingRect);
+    ByteArray* srcPixelArray = resultImage->data()->data();
 
     // FIXME: support kernelUnitLengths other than (1,1). The issue here is that the W3
     // standard has no test case for them, and other browsers (like Firefox) has strange
@@ -351,8 +354,7 @@ void FELighting::apply()
     // Anyway, feConvolveMatrix should also use the implementation
 
     IntSize absolutePaintSize = absolutePaintRect().size();
-    if (drawLighting(srcPixelArray, absolutePaintSize.width(), absolutePaintSize.height()))
-        resultImage()->putUnmultipliedImageData(srcImageData.get(), IntRect(IntPoint(), absolutePaintSize), IntPoint());
+    drawLighting(srcPixelArray, absolutePaintSize.width(), absolutePaintSize.height());
 }
 
 } // namespace WebCore
diff --git a/WebCore/platform/graphics/filters/FEMerge.cpp b/WebCore/platform/graphics/filters/FEMerge.cpp
index ca53a86..4395321 100644
--- a/WebCore/platform/graphics/filters/FEMerge.cpp
+++ b/WebCore/platform/graphics/filters/FEMerge.cpp
@@ -41,22 +41,25 @@ PassRefPtr<FEMerge> FEMerge::create(Filter* filter)
 
 void FEMerge::apply()
 {
+    if (hasResult())
+        return;
     unsigned size = numberOfEffectInputs();
     ASSERT(size > 0);
     for (unsigned i = 0; i < size; ++i) {
         FilterEffect* in = inputEffect(i);
         in->apply();
-        if (!in->resultImage())
+        if (!in->hasResult())
             return;
     }
 
-    GraphicsContext* filterContext = effectContext();
-    if (!filterContext)
+    ImageBuffer* resultImage = createImageBufferResult();
+    if (!resultImage)
         return;
 
+    GraphicsContext* filterContext = resultImage->context();
     for (unsigned i = 0; i < size; ++i) {
         FilterEffect* in = inputEffect(i);
-        filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
+        filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
     }
 }
 
diff --git a/WebCore/platform/graphics/filters/FEMerge.h b/WebCore/platform/graphics/filters/FEMerge.h
index 24d071e..dbee610 100644
--- a/WebCore/platform/graphics/filters/FEMerge.h
+++ b/WebCore/platform/graphics/filters/FEMerge.h
@@ -20,7 +20,7 @@
  */
 
 #ifndef FEMerge_h
-#define EMerge_h
+#define FEMerge_h
 
 #if ENABLE(FILTERS)
 #include "FilterEffect.h"
diff --git a/WebCore/platform/graphics/filters/FEMorphology.cpp b/WebCore/platform/graphics/filters/FEMorphology.cpp
index dd7659a..b20adc5 100644
--- a/WebCore/platform/graphics/filters/FEMorphology.cpp
+++ b/WebCore/platform/graphics/filters/FEMorphology.cpp
@@ -91,12 +91,15 @@ void FEMorphology::setRadiusY(float radiusY)
 
 void FEMorphology::apply()
 {
+    if (hasResult())
+        return;
     FilterEffect* in = inputEffect(0);
     in->apply();
-    if (!in->resultImage())
+    if (!in->hasResult())
         return;
 
-    if (!effectContext())
+    ImageData* resultImage = createPremultipliedImageResult();
+    if (!resultImage)
         return;
 
     setIsAlphaImage(in->isAlphaImage());
@@ -107,12 +110,10 @@ void FEMorphology::apply()
     int radiusX = static_cast<int>(floorf(filter->applyHorizontalScale(m_radiusX)));
     int radiusY = static_cast<int>(floorf(filter->applyVerticalScale(m_radiusY)));
 
-    IntRect imageRect(IntPoint(), resultImage()->size());
     IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
-    RefPtr<ImageData> srcImageData = in->resultImage()->getPremultipliedImageData(effectDrawingRect);
+    RefPtr<ImageData> srcImageData = in->asPremultipliedImage(effectDrawingRect);
     ByteArray* srcPixelArray = srcImageData->data()->data();
-    RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height());
-    ByteArray* dstPixelArray = imageData->data()->data();
+    ByteArray* dstPixelArray = resultImage->data()->data();
 
     int effectWidth = effectDrawingRect.width() * 4;
     
@@ -162,7 +163,6 @@ void FEMorphology::apply()
             }
         }
     }
-    resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint());
 }
 
 void FEMorphology::dump()
diff --git a/WebCore/platform/graphics/filters/FEOffset.cpp b/WebCore/platform/graphics/filters/FEOffset.cpp
index b640054..f1d5914 100644
--- a/WebCore/platform/graphics/filters/FEOffset.cpp
+++ b/WebCore/platform/graphics/filters/FEOffset.cpp
@@ -74,13 +74,15 @@ void FEOffset::determineAbsolutePaintRect()
 
 void FEOffset::apply()
 {
+    if (hasResult())
+        return;
     FilterEffect* in = inputEffect(0);
     in->apply();
-    if (!in->resultImage())
+    if (!in->hasResult())
         return;
 
-    GraphicsContext* filterContext = effectContext();
-    if (!filterContext)
+    ImageBuffer* resultImage = createImageBufferResult();
+    if (!resultImage)
         return;
 
     setIsAlphaImage(in->isAlphaImage());
@@ -88,7 +90,7 @@ void FEOffset::apply()
     FloatRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect());
     Filter* filter = this->filter();
     drawingRegion.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy));
-    filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegion);
+    resultImage->context()->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegion);
 }
 
 void FEOffset::dump()
diff --git a/WebCore/platform/graphics/filters/FETile.cpp b/WebCore/platform/graphics/filters/FETile.cpp
index 6b11401..e516c7e 100644
--- a/WebCore/platform/graphics/filters/FETile.cpp
+++ b/WebCore/platform/graphics/filters/FETile.cpp
@@ -45,13 +45,15 @@ void FETile::apply()
 {
 // FIXME: See bug 47315. This is a hack to work around a compile failure, but is incorrect behavior otherwise.
 #if ENABLE(SVG)
+    if (hasResult())
+        return;
     FilterEffect* in = inputEffect(0);
     in->apply();
-    if (!in->resultImage())
+    if (!in->hasResult())
         return;
 
-    GraphicsContext* filterContext = effectContext();
-    if (!filterContext)
+    ImageBuffer* resultImage = createImageBufferResult();
+    if (!resultImage)
         return;
 
     setIsAlphaImage(in->isAlphaImage());
@@ -73,13 +75,14 @@ void FETile::apply()
 
     GraphicsContext* tileImageContext = tileImage->context();
     tileImageContext->translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y());
-    tileImageContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, in->absolutePaintRect().location());
+    tileImageContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, in->absolutePaintRect().location());
 
     RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(), true, true);
 
     AffineTransform patternTransform;
     patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y());
     pattern->setPatternSpaceTransform(patternTransform);
+    GraphicsContext* filterContext = resultImage->context();
     filterContext->setFillPattern(pattern);
     filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()));
 #endif
diff --git a/WebCore/platform/graphics/filters/FETurbulence.cpp b/WebCore/platform/graphics/filters/FETurbulence.cpp
index 8914db7..becf784 100644
--- a/WebCore/platform/graphics/filters/FETurbulence.cpp
+++ b/WebCore/platform/graphics/filters/FETurbulence.cpp
@@ -320,15 +320,16 @@ unsigned char FETurbulence::calculateTurbulenceValueForPoint(PaintingData& paint
 
 void FETurbulence::apply()
 {
-    if (!effectContext())
+    if (hasResult())
+        return;
+    ImageData* resultImage = createUnmultipliedImageResult();
+    if (!resultImage)
         return;
 
-    IntRect imageRect(IntPoint(), resultImage()->size());
-    if (!imageRect.size().width() || !imageRect.size().height())
+    if (absolutePaintRect().isEmpty())
         return;
 
-    RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height());
-    ByteArray* pixelArray = imageData->data()->data();
+    ByteArray* pixelArray = resultImage->data()->data();
     PaintingData paintingData(m_seed, roundedIntSize(filterPrimitiveSubregion().size()));
     initPaint(paintingData);
 
@@ -336,16 +337,15 @@ void FETurbulence::apply()
     FloatPoint point;
     point.setY(filterRegion.y());
     int indexOfPixelChannel = 0;
-    for (int y = 0; y < imageRect.height(); ++y) {
+    for (int y = 0; y < absolutePaintRect().height(); ++y) {
         point.setY(point.y() + 1);
         point.setX(filterRegion.x());
-        for (int x = 0; x < imageRect.width(); ++x) {
+        for (int x = 0; x < absolutePaintRect().width(); ++x) {
             point.setX(point.x() + 1);
             for (paintingData.channel = 0; paintingData.channel < 4; ++paintingData.channel, ++indexOfPixelChannel)
                 pixelArray->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(paintingData, filter()->mapAbsolutePointToLocalPoint(point)));
         }
     }
-    resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint());
 }
 
 void FETurbulence::dump()
diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp
index c228731..ebc6af0 100644
--- a/WebCore/platform/graphics/filters/FilterEffect.cpp
+++ b/WebCore/platform/graphics/filters/FilterEffect.cpp
@@ -23,6 +23,7 @@
 
 #if ENABLE(FILTERS)
 #include "FilterEffect.h"
+#include "ImageData.h"
 
 namespace WebCore {
 
@@ -54,10 +55,10 @@ void FilterEffect::determineAbsolutePaintRect()
 
 IntRect FilterEffect::requestedRegionOfInputImageData(const IntRect& effectRect) const
 {
-    ASSERT(m_effectBuffer);
+    ASSERT(hasResult());
     IntPoint location = m_absolutePaintRect.location();
     location.move(-effectRect.x(), -effectRect.y());
-    return IntRect(location, m_effectBuffer->size());
+    return IntRect(location, m_absolutePaintRect.size());
 }
 
 IntRect FilterEffect::drawingRegionOfInputImage(const IntRect& srcRect) const
@@ -72,15 +73,170 @@ FilterEffect* FilterEffect::inputEffect(unsigned number) const
     return m_inputEffects.at(number).get();
 }
 
-GraphicsContext* FilterEffect::effectContext()
+ImageBuffer* FilterEffect::asImageBuffer()
 {
+    if (!hasResult())
+        return 0;
+    if (m_imageBufferResult)
+        return m_imageBufferResult.get();
+    m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB);
+    IntRect destinationRect(IntPoint(), m_absolutePaintRect.size());
+    if (m_premultipliedImageResult)
+        m_imageBufferResult->putPremultipliedImageData(m_premultipliedImageResult.get(), destinationRect, IntPoint());
+    else
+        m_imageBufferResult->putUnmultipliedImageData(m_unmultipliedImageResult.get(), destinationRect, IntPoint());
+    return m_imageBufferResult.get();
+}
+
+PassRefPtr<ImageData> FilterEffect::asUnmultipliedImage(const IntRect& rect)
+{
+    RefPtr<ImageData> imageData = ImageData::create(rect.width(), rect.height());
+    copyUnmultipliedImage(imageData.get(), rect);
+    return imageData.release();
+}
+
+PassRefPtr<ImageData> FilterEffect::asPremultipliedImage(const IntRect& rect)
+{
+    RefPtr<ImageData> imageData = ImageData::create(rect.width(), rect.height());
+    copyPremultipliedImage(imageData.get(), rect);
+    return imageData.release();
+}
+
+inline void FilterEffect::copyImageBytes(ImageData* source, ImageData* destination, const IntRect& rect)
+{
+    // Copy the necessary lines.
+    ASSERT(IntSize(destination->width(), destination->height()) == rect.size());
+    if (rect.x() < 0 || rect.y() < 0 || rect.bottom() > m_absolutePaintRect.width() || rect.bottom() > m_absolutePaintRect.height())
+        memset(destination->data()->data()->data(), 0, destination->data()->length());
+
+    int xOrigin = rect.x();
+    int xDest = 0;
+    if (xOrigin < 0) {
+        xDest = -xOrigin;
+        xOrigin = 0;
+    }
+    int xEnd = rect.right();
+    if (xEnd > m_absolutePaintRect.width())
+        xEnd = m_absolutePaintRect.width();
+
+    int yOrigin = rect.y();
+    int yDest = 0;
+    if (yOrigin < 0) {
+        yDest = -yOrigin;
+        yOrigin = 0;
+    }
+    int yEnd = rect.bottom();
+    if (yEnd > m_absolutePaintRect.height())
+        yEnd = m_absolutePaintRect.height();
+
+    int size = (xEnd - xOrigin) * 4;
+    int destinationScanline = rect.width() * 4;
+    int sourceScanline = m_absolutePaintRect.width() * 4;
+    unsigned char *destinationPixel = destination->data()->data()->data() + ((yDest * rect.width()) + xDest) * 4;
+    unsigned char *sourcePixel = source->data()->data()->data() + ((yOrigin * m_absolutePaintRect.width()) + xOrigin) * 4;
+
+    while (yOrigin < yEnd) {
+        memcpy(destinationPixel, sourcePixel, size);
+        destinationPixel += destinationScanline;
+        sourcePixel += sourceScanline;
+        ++yOrigin;
+    }
+}
+
+void FilterEffect::copyUnmultipliedImage(ImageData* destination, const IntRect& rect)
+{
+    ASSERT(hasResult());
+
+    if (!m_unmultipliedImageResult) {
+        // We prefer a conversion from the image buffer.
+        if (m_imageBufferResult)
+            m_unmultipliedImageResult = m_imageBufferResult->getUnmultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
+        else {
+            m_unmultipliedImageResult = ImageData::create(m_absolutePaintRect.width(), m_absolutePaintRect.height());
+            unsigned char* sourceComponent = m_premultipliedImageResult->data()->data()->data();
+            unsigned char* destinationComponent = m_unmultipliedImageResult->data()->data()->data();
+            unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
+            while (sourceComponent < end) {
+                int alpha = sourceComponent[3];
+                if (alpha) {
+                    destinationComponent[0] = static_cast<int>(sourceComponent[0]) * 255 / alpha;
+                    destinationComponent[1] = static_cast<int>(sourceComponent[1]) * 255 / alpha;
+                    destinationComponent[2] = static_cast<int>(sourceComponent[2]) * 255 / alpha;
+                } else {
+                    destinationComponent[0] = 0;
+                    destinationComponent[1] = 0;
+                    destinationComponent[2] = 0;
+                }
+                destinationComponent[3] = alpha;
+                sourceComponent += 4;
+                destinationComponent += 4;
+            }
+        }
+    }
+    copyImageBytes(m_unmultipliedImageResult.get(), destination, rect);
+}
+
+void FilterEffect::copyPremultipliedImage(ImageData* destination, const IntRect& rect)
+{
+    ASSERT(hasResult());
+
+    if (!m_premultipliedImageResult) {
+        // We prefer a conversion from the image buffer.
+        if (m_imageBufferResult)
+            m_premultipliedImageResult = m_imageBufferResult->getPremultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
+        else {
+            m_premultipliedImageResult = ImageData::create(m_absolutePaintRect.width(), m_absolutePaintRect.height());
+            unsigned char* sourceComponent = m_unmultipliedImageResult->data()->data()->data();
+            unsigned char* destinationComponent = m_premultipliedImageResult->data()->data()->data();
+            unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
+            while (sourceComponent < end) {
+                int alpha = sourceComponent[3];
+                destinationComponent[0] = static_cast<int>(sourceComponent[0]) * alpha / 255;
+                destinationComponent[1] = static_cast<int>(sourceComponent[1]) * alpha / 255;
+                destinationComponent[2] = static_cast<int>(sourceComponent[2]) * alpha / 255;
+                destinationComponent[3] = alpha;
+                sourceComponent += 4;
+                destinationComponent += 4;
+            }
+        }
+    }
+    copyImageBytes(m_premultipliedImageResult.get(), destination, rect);
+}
+
+ImageBuffer* FilterEffect::createImageBufferResult()
+{
+    // Only one result type is allowed.
+    ASSERT(!hasResult());
+    determineAbsolutePaintRect();
+    if (m_absolutePaintRect.isEmpty())
+        return 0;
+    m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB);
+    if (!m_imageBufferResult)
+        return 0;
+    ASSERT(m_imageBufferResult->context());
+    return m_imageBufferResult.get();
+}
+
+ImageData* FilterEffect::createUnmultipliedImageResult()
+{
+    // Only one result type is allowed.
+    ASSERT(!hasResult());
     determineAbsolutePaintRect();
     if (m_absolutePaintRect.isEmpty())
         return 0;
-    m_effectBuffer = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB);
-    if (!m_effectBuffer)
+    m_unmultipliedImageResult = ImageData::create(m_absolutePaintRect.width(), m_absolutePaintRect.height());
+    return m_unmultipliedImageResult.get();
+}
+
+ImageData* FilterEffect::createPremultipliedImageResult()
+{
+    // Only one result type is allowed.
+    ASSERT(!hasResult());
+    determineAbsolutePaintRect();
+    if (m_absolutePaintRect.isEmpty())
         return 0;
-    return m_effectBuffer->context();
+    m_premultipliedImageResult = ImageData::create(m_absolutePaintRect.width(), m_absolutePaintRect.height());
+    return m_premultipliedImageResult.get();
 }
 
 TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const
diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h
index f9674e2..81d5409 100644
--- a/WebCore/platform/graphics/filters/FilterEffect.h
+++ b/WebCore/platform/graphics/filters/FilterEffect.h
@@ -50,13 +50,12 @@ class FilterEffect : public RefCounted<FilterEffect> {
 public:
     virtual ~FilterEffect();
 
-    // The result is bounded to the size of the filter primitive to save resources.
-    ImageBuffer* resultImage() const { return m_effectBuffer.get(); }
-    void setEffectBuffer(PassOwnPtr<ImageBuffer> effectBuffer) { m_effectBuffer = effectBuffer; }
-
-    // Creates the ImageBuffer for the current filter primitive result in the size of the
-    // repaintRect. Gives back the GraphicsContext of the own ImageBuffer.
-    GraphicsContext* effectContext();
+    bool hasResult() const { return m_imageBufferResult || m_unmultipliedImageResult || m_premultipliedImageResult; }
+    ImageBuffer* asImageBuffer();
+    PassRefPtr<ImageData> asUnmultipliedImage(const IntRect&);
+    PassRefPtr<ImageData> asPremultipliedImage(const IntRect&);
+    void copyUnmultipliedImage(ImageData* destination, const IntRect&);
+    void copyPremultipliedImage(ImageData* destination, const IntRect&);
 
     FilterEffectVector& inputEffects() { return m_inputEffects; }
     FilterEffect* inputEffect(unsigned) const;
@@ -110,8 +109,14 @@ public:
 protected:
     FilterEffect(Filter*);
 
+    ImageBuffer* createImageBufferResult();
+    ImageData* createUnmultipliedImageResult();
+    ImageData* createPremultipliedImageResult();
+
 private:
-    OwnPtr<ImageBuffer> m_effectBuffer;
+    OwnPtr<ImageBuffer> m_imageBufferResult;
+    RefPtr<ImageData> m_unmultipliedImageResult;
+    RefPtr<ImageData> m_premultipliedImageResult;
     FilterEffectVector m_inputEffects;
 
     bool m_alphaImage;
@@ -124,6 +129,8 @@ private:
     Filter* m_filter;
 
 private:
+    inline void copyImageBytes(ImageData* source, ImageData* destination, const IntRect&);
+
     // The following member variables are SVG specific and will move to RenderSVGResourceFilterPrimitive.
     // See bug https://bugs.webkit.org/show_bug.cgi?id=45614.
 
diff --git a/WebCore/platform/graphics/filters/SourceAlpha.cpp b/WebCore/platform/graphics/filters/SourceAlpha.cpp
index a505b4b..2d2de00 100644
--- a/WebCore/platform/graphics/filters/SourceAlpha.cpp
+++ b/WebCore/platform/graphics/filters/SourceAlpha.cpp
@@ -52,14 +52,17 @@ void SourceAlpha::determineAbsolutePaintRect()
 
 void SourceAlpha::apply()
 {
-    GraphicsContext* filterContext = effectContext();
+    if (hasResult())
+        return;
+    ImageBuffer* resultImage = createImageBufferResult();
     Filter* filter = this->filter();
-    if (!filterContext || !filter->sourceImage())
+    if (!resultImage || !filter->sourceImage())
         return;
 
     setIsAlphaImage(true);
 
     FloatRect imageRect(FloatPoint(), absolutePaintRect().size());
+    GraphicsContext* filterContext = resultImage->context();
     filterContext->save();
     filterContext->clipToImageBuffer(filter->sourceImage(), imageRect);
     filterContext->fillRect(imageRect, Color::black, ColorSpaceDeviceRGB);
diff --git a/WebCore/platform/graphics/filters/SourceGraphic.cpp b/WebCore/platform/graphics/filters/SourceGraphic.cpp
index 6aac367..04082ad 100644
--- a/WebCore/platform/graphics/filters/SourceGraphic.cpp
+++ b/WebCore/platform/graphics/filters/SourceGraphic.cpp
@@ -51,12 +51,14 @@ void SourceGraphic::determineAbsolutePaintRect()
 
 void SourceGraphic::apply()
 {
-    GraphicsContext* filterContext = effectContext();
+    if (hasResult())
+        return;
+    ImageBuffer* resultImage = createImageBufferResult();
     Filter* filter = this->filter();
-    if (!filterContext || !filter->sourceImage())
+    if (!resultImage || !filter->sourceImage())
         return;
 
-    filterContext->drawImageBuffer(filter->sourceImage(), ColorSpaceDeviceRGB, IntPoint());
+    resultImage->context()->drawImageBuffer(filter->sourceImage(), ColorSpaceDeviceRGB, IntPoint());
 }
 
 void SourceGraphic::dump()
diff --git a/WebCore/platform/graphics/filters/SourceGraphic.h b/WebCore/platform/graphics/filters/SourceGraphic.h
index fa47f12..97d6882 100644
--- a/WebCore/platform/graphics/filters/SourceGraphic.h
+++ b/WebCore/platform/graphics/filters/SourceGraphic.h
@@ -19,7 +19,7 @@
  */
 
 #ifndef SourceGraphic_h
-#define SourceGrahpic_h
+#define SourceGraphic_h
 
 #if ENABLE(FILTERS)
 #include "FilterEffect.h"
diff --git a/WebCore/rendering/RenderSVGResourceFilter.cpp b/WebCore/rendering/RenderSVGResourceFilter.cpp
index 2ed92bd..8aa9370 100644
--- a/WebCore/rendering/RenderSVGResourceFilter.cpp
+++ b/WebCore/rendering/RenderSVGResourceFilter.cpp
@@ -293,14 +293,14 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo
             filterData->filter->setSourceImage(filterData->sourceGraphicBuffer.release());
             lastEffect->apply();
 #if !PLATFORM(CG)
-            ImageBuffer* resultImage = lastEffect->resultImage();
+            ImageBuffer* resultImage = lastEffect->asImageBuffer();
             if (resultImage)
                 resultImage->transformColorSpace(ColorSpaceLinearRGB, ColorSpaceDeviceRGB);
 #endif
             filterData->builded = true;
         }
 
-        ImageBuffer* resultImage = lastEffect->resultImage();
+        ImageBuffer* resultImage = lastEffect->asImageBuffer();
         if (resultImage) {
             context->concatCTM(filterData->shearFreeAbsoluteTransform.inverse());
 
diff --git a/WebCore/svg/graphics/filters/SVGFEImage.cpp b/WebCore/svg/graphics/filters/SVGFEImage.cpp
index 6a1914a..b5ae466 100644
--- a/WebCore/svg/graphics/filters/SVGFEImage.cpp
+++ b/WebCore/svg/graphics/filters/SVGFEImage.cpp
@@ -59,8 +59,8 @@ void FEImage::apply()
     if (!m_image.get())
         return;
 
-    GraphicsContext* filterContext = effectContext();
-    if (!filterContext)
+    ImageBuffer* resultImage = createImageBufferResult();
+    if (!resultImage)
         return;
 
     FloatRect srcRect(FloatPoint(), m_image->size());
@@ -70,7 +70,7 @@ void FEImage::apply()
     IntPoint paintLocation = absolutePaintRect().location();
     destRect.move(-paintLocation.x(), -paintLocation.y());
 
-    filterContext->drawImage(m_image.get(), ColorSpaceDeviceRGB, destRect, srcRect);
+    resultImage->context()->drawImage(m_image.get(), ColorSpaceDeviceRGB, destRect, srcRect);
 }
 
 void FEImage::dump()

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list