Home | History | Annotate | Download | only in filters
      1 /*
      2     Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann (at) kde.org>
      3                   2004, 2005 Rob Buis <buis (at) kde.org>
      4                   2005 Eric Seidel <eric (at) webkit.org>
      5                   2009 Dirk Schulze <krit (at) 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 
     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 
     47 PassRefPtr<FEGaussianBlur> FEGaussianBlur::create(FilterEffect* in, const float& x, const float& y)
     48 {
     49     return adoptRef(new FEGaussianBlur(in, x, y));
     50 }
     51 
     52 float FEGaussianBlur::stdDeviationX() const
     53 {
     54     return m_x;
     55 }
     56 
     57 void FEGaussianBlur::setStdDeviationX(float x)
     58 {
     59     m_x = x;
     60 }
     61 
     62 float FEGaussianBlur::stdDeviationY() const
     63 {
     64     return m_y;
     65 }
     66 
     67 void FEGaussianBlur::setStdDeviationY(float y)
     68 {
     69     m_y = y;
     70 }
     71 
     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 
    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 
    138 void FEGaussianBlur::dump()
    139 {
    140 }
    141 
    142 } // namespace WebCore
    143 
    144 #endif // ENABLE(FILTERS)
    145