Home | History | Annotate | Download | only in filters
      1 /*
      2  * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005 Rob Buis <buis (at) kde.org>
      4  * Copyright (C) 2005 Eric Seidel <eric (at) webkit.org>
      5  * Copyright (C) 2009 Dirk Schulze <krit (at) webkit.org>
      6  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
      7  *
      8  * This library is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU Library General Public
     10  * License as published by the Free Software Foundation; either
     11  * version 2 of the License, or (at your option) any later version.
     12  *
     13  * This library is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16  * Library General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU Library General Public License
     19  * along with this library; see the file COPYING.LIB.  If not, write to
     20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     21  * Boston, MA 02110-1301, USA.
     22  */
     23 
     24 #include "config.h"
     25 
     26 #if ENABLE(FILTERS)
     27 #include "FEMorphology.h"
     28 
     29 #include "Filter.h"
     30 #include "RenderTreeAsText.h"
     31 #include "TextStream.h"
     32 
     33 #include <wtf/ByteArray.h>
     34 #include <wtf/Vector.h>
     35 
     36 using std::min;
     37 using std::max;
     38 
     39 namespace WebCore {
     40 
     41 FEMorphology::FEMorphology(Filter* filter, MorphologyOperatorType type, float radiusX, float radiusY)
     42     : FilterEffect(filter)
     43     , m_type(type)
     44     , m_radiusX(radiusX)
     45     , m_radiusY(radiusY)
     46 {
     47 }
     48 
     49 PassRefPtr<FEMorphology> FEMorphology::create(Filter* filter, MorphologyOperatorType type, float radiusX, float radiusY)
     50 {
     51     return adoptRef(new FEMorphology(filter, type, radiusX, radiusY));
     52 }
     53 
     54 MorphologyOperatorType FEMorphology::morphologyOperator() const
     55 {
     56     return m_type;
     57 }
     58 
     59 bool FEMorphology::setMorphologyOperator(MorphologyOperatorType type)
     60 {
     61     if (m_type == type)
     62         return false;
     63     m_type = type;
     64     return true;
     65 }
     66 
     67 float FEMorphology::radiusX() const
     68 {
     69     return m_radiusX;
     70 }
     71 
     72 bool FEMorphology::setRadiusX(float radiusX)
     73 {
     74     if (m_radiusX == radiusX)
     75         return false;
     76     m_radiusX = radiusX;
     77     return true;
     78 }
     79 
     80 float FEMorphology::radiusY() const
     81 {
     82     return m_radiusY;
     83 }
     84 
     85 void FEMorphology::determineAbsolutePaintRect()
     86 {
     87     FloatRect paintRect = inputEffect(0)->absolutePaintRect();
     88     Filter* filter = this->filter();
     89     paintRect.inflateX(filter->applyHorizontalScale(m_radiusX));
     90     paintRect.inflateY(filter->applyVerticalScale(m_radiusY));
     91     paintRect.intersect(maxEffectRect());
     92     setAbsolutePaintRect(enclosingIntRect(paintRect));
     93 }
     94 
     95 bool FEMorphology::setRadiusY(float radiusY)
     96 {
     97     if (m_radiusY == radiusY)
     98         return false;
     99     m_radiusY = radiusY;
    100     return true;
    101 }
    102 
    103 void FEMorphology::apply()
    104 {
    105     if (hasResult())
    106         return;
    107     FilterEffect* in = inputEffect(0);
    108     in->apply();
    109     if (!in->hasResult())
    110         return;
    111 
    112     ByteArray* dstPixelArray = createPremultipliedImageResult();
    113     if (!dstPixelArray)
    114         return;
    115 
    116     setIsAlphaImage(in->isAlphaImage());
    117     if (m_radiusX <= 0 || m_radiusY <= 0)
    118         return;
    119 
    120     Filter* filter = this->filter();
    121     int radiusX = static_cast<int>(floorf(filter->applyHorizontalScale(m_radiusX)));
    122     int radiusY = static_cast<int>(floorf(filter->applyVerticalScale(m_radiusY)));
    123 
    124     IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
    125     RefPtr<ByteArray> srcPixelArray = in->asPremultipliedImage(effectDrawingRect);
    126 
    127     int effectWidth = effectDrawingRect.width() * 4;
    128 
    129     // Limit the radius size to effect dimensions
    130     radiusX = min(effectDrawingRect.width() - 1, radiusX);
    131     radiusY = min(effectDrawingRect.height() - 1, radiusY);
    132 
    133     Vector<unsigned char> extrema;
    134     for (int y = 0; y < effectDrawingRect.height(); ++y) {
    135         int startY = max(0, y - radiusY);
    136         int endY = min(effectDrawingRect.height() - 1, y + radiusY);
    137         for (unsigned channel = 0; channel < 4; ++channel) {
    138             // Fill the kernel
    139             extrema.clear();
    140             for (int j = 0; j <= radiusX; ++j) {
    141                 unsigned char columnExtrema = srcPixelArray->get(startY * effectWidth + 4 * j + channel);
    142                 for (int i = startY; i <= endY; ++i) {
    143                     unsigned char pixel = srcPixelArray->get(i * effectWidth + 4 * j + channel);
    144                     if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) ||
    145                         (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema))
    146                         columnExtrema = pixel;
    147                 }
    148                 extrema.append(columnExtrema);
    149             }
    150 
    151             // Kernel is filled, get extrema of next column
    152             for (int x = 0; x < effectDrawingRect.width(); ++x) {
    153                 unsigned endX = min(x + radiusX, effectDrawingRect.width() - 1);
    154                 unsigned char columnExtrema = srcPixelArray->get(startY * effectWidth + endX * 4 + channel);
    155                 for (int i = startY; i <= endY; ++i) {
    156                     unsigned char pixel = srcPixelArray->get(i * effectWidth + endX * 4 + channel);
    157                     if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) ||
    158                         (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema))
    159                         columnExtrema = pixel;
    160                 }
    161                 if (x - radiusX >= 0)
    162                     extrema.remove(0);
    163                 if (x + radiusX <= effectDrawingRect.width())
    164                     extrema.append(columnExtrema);
    165                 unsigned char entireExtrema = extrema[0];
    166                 for (unsigned kernelIndex = 0; kernelIndex < extrema.size(); ++kernelIndex) {
    167                     if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && extrema[kernelIndex] <= entireExtrema) ||
    168                         (m_type == FEMORPHOLOGY_OPERATOR_DILATE && extrema[kernelIndex] >= entireExtrema))
    169                         entireExtrema = extrema[kernelIndex];
    170                 }
    171                 dstPixelArray->set(y * effectWidth + 4 * x + channel, entireExtrema);
    172             }
    173         }
    174     }
    175 }
    176 
    177 void FEMorphology::dump()
    178 {
    179 }
    180 
    181 static TextStream& operator<<(TextStream& ts, const MorphologyOperatorType& type)
    182 {
    183     switch (type) {
    184     case FEMORPHOLOGY_OPERATOR_UNKNOWN:
    185         ts << "UNKNOWN";
    186         break;
    187     case FEMORPHOLOGY_OPERATOR_ERODE:
    188         ts << "ERODE";
    189         break;
    190     case FEMORPHOLOGY_OPERATOR_DILATE:
    191         ts << "DILATE";
    192         break;
    193     }
    194     return ts;
    195 }
    196 
    197 TextStream& FEMorphology::externalRepresentation(TextStream& ts, int indent) const
    198 {
    199     writeIndent(ts, indent);
    200     ts << "[feMorphology";
    201     FilterEffect::externalRepresentation(ts);
    202     ts << " operator=\"" << morphologyOperator() << "\" "
    203        << "radius=\"" << radiusX() << ", " << radiusY() << "\"]\n";
    204     inputEffect(0)->externalRepresentation(ts, indent + 1);
    205     return ts;
    206 }
    207 
    208 } // namespace WebCore
    209 
    210 #endif // ENABLE(FILTERS)
    211