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(SVG) && ENABLE(FILTERS) 26 #include "SVGFEMorphology.h" 27 28 #include "CanvasPixelArray.h" 29 #include "Filter.h" 30 #include "ImageData.h" 31 #include "SVGRenderTreeAsText.h" 32 33 #include <wtf/Vector.h> 34 35 using std::min; 36 using std::max; 37 38 namespace WebCore { 39 40 FEMorphology::FEMorphology(FilterEffect* in, MorphologyOperatorType type, float radiusX, float radiusY) 41 : FilterEffect() 42 , m_in(in) 43 , m_type(type) 44 , m_radiusX(radiusX) 45 , m_radiusY(radiusY) 46 { 47 } 48 49 PassRefPtr<FEMorphology> FEMorphology::create(FilterEffect* in, MorphologyOperatorType type, float radiusX, float radiusY) 50 { 51 return adoptRef(new FEMorphology(in, type, radiusX, radiusY)); 52 } 53 54 MorphologyOperatorType FEMorphology::morphologyOperator() const 55 { 56 return m_type; 57 } 58 59 void FEMorphology::setMorphologyOperator(MorphologyOperatorType type) 60 { 61 m_type = type; 62 } 63 64 float FEMorphology::radiusX() const 65 { 66 return m_radiusX; 67 } 68 69 void FEMorphology::setRadiusX(float radiusX) 70 { 71 m_radiusX = radiusX; 72 } 73 74 float FEMorphology::radiusY() const 75 { 76 return m_radiusY; 77 } 78 79 void FEMorphology::setRadiusY(float radiusY) 80 { 81 m_radiusY = radiusY; 82 } 83 84 void FEMorphology::apply(Filter* filter) 85 { 86 m_in->apply(filter); 87 if (!m_in->resultImage()) 88 return; 89 90 if (!getEffectContext()) 91 return; 92 93 setIsAlphaImage(m_in->isAlphaImage()); 94 95 if (!m_radiusX || !m_radiusY) 96 return; 97 98 IntRect imageRect(IntPoint(), resultImage()->size()); 99 IntRect effectDrawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); 100 RefPtr<CanvasPixelArray> srcPixelArray(m_in->resultImage()->getPremultipliedImageData(effectDrawingRect)->data()); 101 RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); 102 103 int radiusX = static_cast<int>(m_radiusX * filter->filterResolution().width()); 104 int radiusY = static_cast<int>(m_radiusY * filter->filterResolution().height()); 105 int effectWidth = effectDrawingRect.width() * 4; 106 107 // Limit the radius size to effect width 108 radiusX = min(effectDrawingRect.width() - 1, radiusX); 109 110 Vector<unsigned char> extrema; 111 for (int y = 0; y < effectDrawingRect.height(); ++y) { 112 int startY = max(0, y - radiusY); 113 int endY = min(effectDrawingRect.height() - 1, y + radiusY); 114 for (unsigned channel = 0; channel < 4; ++channel) { 115 // Fill the kernel 116 extrema.clear(); 117 for (int j = 0; j <= radiusX; ++j) { 118 unsigned char columnExtrema = srcPixelArray->get(startY * effectWidth + 4 * j + channel); 119 for (int i = startY; i <= endY; ++i) { 120 unsigned char pixel = srcPixelArray->get(i * effectWidth + 4 * j + channel); 121 if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) || 122 (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema)) 123 columnExtrema = pixel; 124 } 125 extrema.append(columnExtrema); 126 } 127 128 // Kernel is filled, get extrema of next column 129 for (int x = 0; x < effectDrawingRect.width(); ++x) { 130 unsigned endX = min(x + radiusX, effectDrawingRect.width() - 1); 131 unsigned char columnExtrema = srcPixelArray->get(startY * effectWidth + endX * 4 + channel); 132 for (int i = startY; i <= endY; ++i) { 133 unsigned char pixel = srcPixelArray->get(i * effectWidth + endX * 4 + channel); 134 if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) || 135 (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema)) 136 columnExtrema = pixel; 137 } 138 if (x - radiusX >= 0) 139 extrema.remove(0); 140 if (x + radiusX <= effectDrawingRect.width()) 141 extrema.append(columnExtrema); 142 unsigned char entireExtrema = extrema[0]; 143 for (unsigned kernelIndex = 0; kernelIndex < extrema.size(); ++kernelIndex) { 144 if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && extrema[kernelIndex] <= entireExtrema) || 145 (m_type == FEMORPHOLOGY_OPERATOR_DILATE && extrema[kernelIndex] >= entireExtrema)) 146 entireExtrema = extrema[kernelIndex]; 147 } 148 imageData->data()->set(y * effectWidth + 4 * x + channel, entireExtrema); 149 } 150 } 151 } 152 resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint()); 153 } 154 155 void FEMorphology::dump() 156 { 157 } 158 159 static TextStream& operator<<(TextStream& ts, MorphologyOperatorType t) 160 { 161 switch (t) 162 { 163 case FEMORPHOLOGY_OPERATOR_UNKNOWN: 164 ts << "UNKNOWN"; break; 165 case FEMORPHOLOGY_OPERATOR_ERODE: 166 ts << "ERODE"; break; 167 case FEMORPHOLOGY_OPERATOR_DILATE: 168 ts << "DILATE"; break; 169 } 170 return ts; 171 } 172 173 TextStream& FEMorphology::externalRepresentation(TextStream& ts) const 174 { 175 ts << "[type=MORPHOLOGY] "; 176 FilterEffect::externalRepresentation(ts); 177 ts << " [operator type=" << morphologyOperator() << "]" 178 << " [radius x=" << radiusX() << " y=" << radiusY() << "]"; 179 return ts; 180 } 181 182 } // namespace WebCore 183 184 #endif // ENABLE(SVG) && ENABLE(FILTERS) 185