1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
4  * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
5  * Copyright (C) 2009 Dirk Schulze <krit@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 
FEMorphology(Filter * filter,MorphologyOperatorType type,float radiusX,float radiusY)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 
create(Filter * filter,MorphologyOperatorType type,float radiusX,float radiusY)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 
morphologyOperator() const54 MorphologyOperatorType FEMorphology::morphologyOperator() const
55 {
56     return m_type;
57 }
58 
setMorphologyOperator(MorphologyOperatorType type)59 bool FEMorphology::setMorphologyOperator(MorphologyOperatorType type)
60 {
61     if (m_type == type)
62         return false;
63     m_type = type;
64     return true;
65 }
66 
radiusX() const67 float FEMorphology::radiusX() const
68 {
69     return m_radiusX;
70 }
71 
setRadiusX(float radiusX)72 bool FEMorphology::setRadiusX(float radiusX)
73 {
74     if (m_radiusX == radiusX)
75         return false;
76     m_radiusX = radiusX;
77     return true;
78 }
79 
radiusY() const80 float FEMorphology::radiusY() const
81 {
82     return m_radiusY;
83 }
84 
determineAbsolutePaintRect()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 
setRadiusY(float radiusY)95 bool FEMorphology::setRadiusY(float radiusY)
96 {
97     if (m_radiusY == radiusY)
98         return false;
99     m_radiusY = radiusY;
100     return true;
101 }
102 
apply()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 
dump()177 void FEMorphology::dump()
178 {
179 }
180 
operator <<(TextStream & ts,const MorphologyOperatorType & type)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 
externalRepresentation(TextStream & ts,int indent) const197 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