Applying a filter on an SVG element, which is larger than 4096 pixels, causes this...
[WebKit-https.git] / Source / WebCore / platform / graphics / filters / FEColorMatrix.cpp
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  *
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  * along 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 #include "FEColorMatrix.h"
25
26 #include "Filter.h"
27 #include "GraphicsContext.h"
28 #include "TextStream.h"
29
30 #include <runtime/Uint8ClampedArray.h>
31 #include <wtf/MathExtras.h>
32
33 namespace WebCore {
34
35 FEColorMatrix::FEColorMatrix(Filter& filter, ColorMatrixType type, const Vector<float>& values)
36     : FilterEffect(filter)
37     , m_type(type)
38     , m_values(values)
39 {
40 }
41
42 Ref<FEColorMatrix> FEColorMatrix::create(Filter& filter, ColorMatrixType type, const Vector<float>& values)
43 {
44     return adoptRef(*new FEColorMatrix(filter, type, values));
45 }
46
47 ColorMatrixType FEColorMatrix::type() const
48 {
49     return m_type;
50 }
51
52 bool FEColorMatrix::setType(ColorMatrixType type)
53 {
54     if (m_type == type)
55         return false;
56     m_type = type;
57     return true;
58 }
59
60 const Vector<float>& FEColorMatrix::values() const
61 {
62     return m_values;
63 }
64
65 bool FEColorMatrix::setValues(const Vector<float> &values)
66 {
67     if (m_values == values)
68         return false;
69     m_values = values;
70     return true;
71 }
72
73 inline void matrix(float& red, float& green, float& blue, float& alpha, const Vector<float>& values)
74 {
75     float r = values[0] * red + values[1] * green + values[2] * blue + values[3] * alpha + values[4] * 255;
76     float g = values[5] * red + values[6] * green + values[7] * blue + values[8] * alpha + values[9] * 255;
77     float b = values[10] * red + values[11] * green + values[12] * blue + values[13] * alpha + values[14] * 255;
78     float a = values[15] * red + values[16] * green + values[17] * blue + values[18] * alpha + values[19] * 255;
79
80     red = r;
81     green = g;
82     blue = b;
83     alpha = a;
84 }
85
86 inline void saturateAndHueRotate(float& red, float& green, float& blue, const float* components)
87 {
88     float r = red * components[0] + green * components[1] + blue * components[2];
89     float g = red * components[3] + green * components[4] + blue * components[5];
90     float b = red * components[6] + green * components[7] + blue * components[8];
91
92     red = r;
93     green = g;
94     blue = b;
95 }
96
97 inline void luminance(float& red, float& green, float& blue, float& alpha)
98 {
99     alpha = 0.2125 * red + 0.7154 * green + 0.0721 * blue;
100     red = 0;
101     green = 0;
102     blue = 0;
103 }
104
105 template<ColorMatrixType filterType>
106 void effectType(Uint8ClampedArray* pixelArray, const Vector<float>& values)
107 {
108     unsigned pixelArrayLength = pixelArray->length();
109     float components[9];
110
111     if (filterType == FECOLORMATRIX_TYPE_SATURATE)
112         FEColorMatrix::calculateSaturateComponents(components, values[0]);
113     else if (filterType == FECOLORMATRIX_TYPE_HUEROTATE)
114         FEColorMatrix::calculateHueRotateComponents(components, values[0]);
115
116     for (unsigned pixelByteOffset = 0; pixelByteOffset < pixelArrayLength; pixelByteOffset += 4) {
117         float red = pixelArray->item(pixelByteOffset);
118         float green = pixelArray->item(pixelByteOffset + 1);
119         float blue = pixelArray->item(pixelByteOffset + 2);
120         float alpha = pixelArray->item(pixelByteOffset + 3);
121
122         switch (filterType) {
123             case FECOLORMATRIX_TYPE_MATRIX:
124                 matrix(red, green, blue, alpha, values);
125                 break;
126             case FECOLORMATRIX_TYPE_SATURATE:
127             case FECOLORMATRIX_TYPE_HUEROTATE:
128                 saturateAndHueRotate(red, green, blue, components);
129                 break;
130             case FECOLORMATRIX_TYPE_LUMINANCETOALPHA:
131                 luminance(red, green, blue, alpha);
132                 break;
133         }
134
135         pixelArray->set(pixelByteOffset, red);
136         pixelArray->set(pixelByteOffset + 1, green);
137         pixelArray->set(pixelByteOffset + 2, blue);
138         pixelArray->set(pixelByteOffset + 3, alpha);
139     }
140 }
141
142 void FEColorMatrix::platformApplySoftware()
143 {
144     FilterEffect* in = inputEffect(0);
145
146     ImageBuffer* resultImage = createImageBufferResult();
147     if (!resultImage)
148         return;
149
150     resultImage->context()->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
151
152     IntRect imageRect(IntPoint(), resultImage->logicalSize());
153     RefPtr<Uint8ClampedArray> pixelArray = resultImage->getUnmultipliedImageData(imageRect);
154
155     switch (m_type) {
156     case FECOLORMATRIX_TYPE_UNKNOWN:
157         break;
158     case FECOLORMATRIX_TYPE_MATRIX:
159         effectType<FECOLORMATRIX_TYPE_MATRIX>(pixelArray.get(), m_values);
160         break;
161     case FECOLORMATRIX_TYPE_SATURATE: 
162         effectType<FECOLORMATRIX_TYPE_SATURATE>(pixelArray.get(), m_values);
163         break;
164     case FECOLORMATRIX_TYPE_HUEROTATE:
165         effectType<FECOLORMATRIX_TYPE_HUEROTATE>(pixelArray.get(), m_values);
166         break;
167     case FECOLORMATRIX_TYPE_LUMINANCETOALPHA:
168         effectType<FECOLORMATRIX_TYPE_LUMINANCETOALPHA>(pixelArray.get(), m_values);
169         setIsAlphaImage(true);
170         break;
171     }
172
173     resultImage->putByteArray(Unmultiplied, pixelArray.get(), imageRect.size(), imageRect, IntPoint());
174 }
175
176 void FEColorMatrix::dump()
177 {
178 }
179
180 static TextStream& operator<<(TextStream& ts, const ColorMatrixType& type)
181 {
182     switch (type) {
183     case FECOLORMATRIX_TYPE_UNKNOWN:
184         ts << "UNKNOWN";
185         break;
186     case FECOLORMATRIX_TYPE_MATRIX:
187         ts << "MATRIX";
188         break;
189     case FECOLORMATRIX_TYPE_SATURATE:
190         ts << "SATURATE";
191         break;
192     case FECOLORMATRIX_TYPE_HUEROTATE:
193         ts << "HUEROTATE";
194         break;
195     case FECOLORMATRIX_TYPE_LUMINANCETOALPHA:
196         ts << "LUMINANCETOALPHA";
197         break;
198     }
199     return ts;
200 }
201
202 TextStream& FEColorMatrix::externalRepresentation(TextStream& ts, int indent) const
203 {
204     writeIndent(ts, indent);
205     ts << "[feColorMatrix";
206     FilterEffect::externalRepresentation(ts);
207     ts << " type=\"" << m_type << "\"";
208     if (!m_values.isEmpty()) {
209         ts << " values=\"";
210         Vector<float>::const_iterator ptr = m_values.begin();
211         const Vector<float>::const_iterator end = m_values.end();
212         while (ptr < end) {
213             ts << *ptr;
214             ++ptr;
215             if (ptr < end) 
216                 ts << " ";
217         }
218         ts << "\"";
219     }
220     ts << "]\n";
221     inputEffect(0)->externalRepresentation(ts, indent + 1);
222     return ts;
223 }
224
225 } // namespace WebCore