Commit 2cc3139b authored by zherczeg@webkit.org's avatar zherczeg@webkit.org

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
parent fd9d0d7b
2010-12-13 Zoltan Herczeg <zherczeg@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@webkit.org>
Unreviewed.
......
<?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>
......@@ -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()
......
......@@ -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()
......
......@@ -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()
......
......@@ -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:
......
......@@ -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()
......
......@@ -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()
......
......@@ -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()
......
......@@ -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;
}