1 /*
2 Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3 2004, 2005 Rob Buis <buis@kde.org>
4 2005 Eric Seidel <eric@webkit.org>
5 2009 Dirk Schulze <krit@webkit.org>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 aint with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21 */
22
23 #include "config.h"
24
25 #if ENABLE(FILTERS)
26 #include "FEGaussianBlur.h"
27
28 #include "CanvasPixelArray.h"
29 #include "Filter.h"
30 #include "GraphicsContext.h"
31 #include "ImageData.h"
32 #include <math.h>
33 #include <wtf/MathExtras.h>
34
35 using std::max;
36
37 namespace WebCore {
38
FEGaussianBlur(FilterEffect * in,const float & x,const float & y)39 FEGaussianBlur::FEGaussianBlur(FilterEffect* in, const float& x, const float& y)
40 : FilterEffect()
41 , m_in(in)
42 , m_x(x)
43 , m_y(y)
44 {
45 }
46
create(FilterEffect * in,const float & x,const float & y)47 PassRefPtr<FEGaussianBlur> FEGaussianBlur::create(FilterEffect* in, const float& x, const float& y)
48 {
49 return adoptRef(new FEGaussianBlur(in, x, y));
50 }
51
stdDeviationX() const52 float FEGaussianBlur::stdDeviationX() const
53 {
54 return m_x;
55 }
56
setStdDeviationX(float x)57 void FEGaussianBlur::setStdDeviationX(float x)
58 {
59 m_x = x;
60 }
61
stdDeviationY() const62 float FEGaussianBlur::stdDeviationY() const
63 {
64 return m_y;
65 }
66
setStdDeviationY(float y)67 void FEGaussianBlur::setStdDeviationY(float y)
68 {
69 m_y = y;
70 }
71
boxBlur(CanvasPixelArray * & srcPixelArray,CanvasPixelArray * & dstPixelArray,unsigned dx,int stride,int strideLine,int effectWidth,int effectHeight,bool alphaImage)72 static void boxBlur(CanvasPixelArray*& srcPixelArray, CanvasPixelArray*& dstPixelArray,
73 unsigned dx, int stride, int strideLine, int effectWidth, int effectHeight, bool alphaImage)
74 {
75 int dxLeft = dx / 2;
76 int dxRight = dx - dxLeft;
77
78 for (int y = 0; y < effectHeight; ++y) {
79 int line = y * strideLine;
80 for (int channel = 3; channel >= 0; --channel) {
81 int sum = 0;
82 // Fill the kernel
83 int maxKernelSize = std::min(dxRight, effectWidth);
84 for (int i = 0; i < maxKernelSize; ++i)
85 sum += srcPixelArray->get(line + i * stride + channel);
86
87 // Blurring
88 for (int x = 0; x < effectWidth; ++x) {
89 int pixelByteOffset = line + x * stride + channel;
90 dstPixelArray->set(pixelByteOffset, static_cast<unsigned char>(sum / dx));
91 if (x >= dxLeft)
92 sum -= srcPixelArray->get(pixelByteOffset - dxLeft * stride);
93 if (x + dxRight < effectWidth)
94 sum += srcPixelArray->get(pixelByteOffset + dxRight * stride);
95 }
96 if (alphaImage) // Source image is black, it just has different alpha values
97 break;
98 }
99 }
100 }
101
apply(Filter * filter)102 void FEGaussianBlur::apply(Filter* filter)
103 {
104 m_in->apply(filter);
105 if (!m_in->resultImage())
106 return;
107
108 if (!getEffectContext())
109 return;
110
111 setIsAlphaImage(m_in->isAlphaImage());
112
113 if (m_x == 0 || m_y == 0)
114 return;
115
116 unsigned sdx = static_cast<unsigned>(floor(m_x * filter->filterResolution().width() * 3 * sqrt(2 * piDouble) / 4.f + 0.5f));
117 unsigned sdy = static_cast<unsigned>(floor(m_y * filter->filterResolution().height() * 3 * sqrt(2 * piDouble) / 4.f + 0.5f));
118 sdx = max(sdx, static_cast<unsigned>(1));
119 sdy = max(sdy, static_cast<unsigned>(1));
120
121 IntRect effectDrawingRect = calculateDrawingIntRect(m_in->scaledSubRegion());
122 RefPtr<ImageData> srcImageData(m_in->resultImage()->getPremultipliedImageData(effectDrawingRect));
123 CanvasPixelArray* srcPixelArray(srcImageData->data());
124
125 IntRect imageRect(IntPoint(), resultImage()->size());
126 RefPtr<ImageData> tmpImageData = ImageData::create(imageRect.width(), imageRect.height());
127 CanvasPixelArray* tmpPixelArray(tmpImageData->data());
128
129 int stride = 4 * imageRect.width();
130 for (int i = 0; i < 3; ++i) {
131 boxBlur(srcPixelArray, tmpPixelArray, sdx, 4, stride, imageRect.width(), imageRect.height(), isAlphaImage());
132 boxBlur(tmpPixelArray, srcPixelArray, sdy, stride, 4, imageRect.height(), imageRect.width(), isAlphaImage());
133 }
134
135 resultImage()->putPremultipliedImageData(srcImageData.get(), imageRect, IntPoint());
136 }
137
dump()138 void FEGaussianBlur::dump()
139 {
140 }
141
142 } // namespace WebCore
143
144 #endif // ENABLE(FILTERS)
145