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