c44f09d558274b3ba946974e7ef25a41eb085250
[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 <wtf/text/TextStream.h>
29
30 #include <runtime/Uint8ClampedArray.h>
31 #include <wtf/MathExtras.h>
32
33 #if USE(ACCELERATE)
34 #include <Accelerate/Accelerate.h>
35 #endif
36
37 #define PRINT_FILTER_PERFORMANCE 0
38
39 namespace WebCore {
40
41 FEColorMatrix::FEColorMatrix(Filter& filter, ColorMatrixType type, const Vector<float>& values)
42     : FilterEffect(filter)
43     , m_type(type)
44     , m_values(values)
45 {
46 }
47
48 Ref<FEColorMatrix> FEColorMatrix::create(Filter& filter, ColorMatrixType type, const Vector<float>& values)
49 {
50     return adoptRef(*new FEColorMatrix(filter, type, values));
51 }
52
53 bool FEColorMatrix::setType(ColorMatrixType type)
54 {
55     if (m_type == type)
56         return false;
57     m_type = type;
58     return true;
59 }
60
61 bool FEColorMatrix::setValues(const Vector<float> &values)
62 {
63     if (m_values == values)
64         return false;
65     m_values = values;
66     return true;
67 }
68
69 inline void matrix(float& red, float& green, float& blue, float& alpha, const Vector<float>& values)
70 {
71     float r = red;
72     float g = green;
73     float b = blue;
74     float a = alpha;
75
76     red     = values[ 0] * r + values[ 1] * g + values[ 2] * b + values[ 3] * a + values[ 4] * 255;
77     green   = values[ 5] * r + values[ 6] * g + values [7] * b + values[ 8] * a + values[ 9] * 255;
78     blue    = values[10] * r + values[11] * g + values[12] * b + values[13] * a + values[14] * 255;
79     alpha   = values[15] * r + values[16] * g + values[17] * b + values[18] * a + values[19] * 255;
80 }
81
82 inline void saturateAndHueRotate(float& red, float& green, float& blue, const float* components)
83 {
84     float r = red;
85     float g = green;
86     float b = blue;
87
88     red     = r * components[0] + g * components[1] + b * components[2];
89     green   = r * components[3] + g * components[4] + b * components[5];
90     blue    = r * components[6] + g * components[7] + b * components[8];
91 }
92
93 inline void luminance(float& red, float& green, float& blue, float& alpha)
94 {
95     alpha = 0.2125 * red + 0.7154 * green + 0.0721 * blue;
96     red = 0;
97     green = 0;
98     blue = 0;
99 }
100
101 #if USE(ACCELERATE)
102 template<ColorMatrixType filterType>
103 bool effectApplyAccelerated(Uint8ClampedArray* pixelArray, const Vector<float>& values, float components[9], IntSize bufferSize)
104 {
105     ASSERT(pixelArray->length() == bufferSize.area().unsafeGet() * 4);
106     
107     if (filterType == FECOLORMATRIX_TYPE_MATRIX) {
108         // vImageMatrixMultiply_ARGB8888 takes a 4x4 matrix, if any value in the last column of the FEColorMatrix 5x4 matrix
109         // is not zero, fall back to non-vImage code.
110         if (values[4] != 0 || values[9] != 0 || values[14] != 0 || values[19] != 0)
111             return false;
112     }
113
114     const int32_t divisor = 256;
115     uint8_t* data = pixelArray->data();
116
117     vImage_Buffer src;
118     src.width = bufferSize.width();
119     src.height = bufferSize.height();
120     src.rowBytes = bufferSize.width() * 4;
121     src.data = data;
122     
123     vImage_Buffer dest;
124     dest.width = bufferSize.width();
125     dest.height = bufferSize.height();
126     dest.rowBytes = bufferSize.width() * 4;
127     dest.data = data;
128
129     switch (filterType) {
130     case FECOLORMATRIX_TYPE_MATRIX: {
131         const int16_t matrix[4 * 4] = {
132             static_cast<int16_t>(roundf(values[ 0] * divisor)),
133             static_cast<int16_t>(roundf(values[ 5] * divisor)),
134             static_cast<int16_t>(roundf(values[10] * divisor)),
135             static_cast<int16_t>(roundf(values[15] * divisor)),
136
137             static_cast<int16_t>(roundf(values[ 1] * divisor)),
138             static_cast<int16_t>(roundf(values[ 6] * divisor)),
139             static_cast<int16_t>(roundf(values[11] * divisor)),
140             static_cast<int16_t>(roundf(values[16] * divisor)),
141
142             static_cast<int16_t>(roundf(values[ 2] * divisor)),
143             static_cast<int16_t>(roundf(values[ 7] * divisor)),
144             static_cast<int16_t>(roundf(values[12] * divisor)),
145             static_cast<int16_t>(roundf(values[17] * divisor)),
146
147             static_cast<int16_t>(roundf(values[ 3] * divisor)),
148             static_cast<int16_t>(roundf(values[ 8] * divisor)),
149             static_cast<int16_t>(roundf(values[13] * divisor)),
150             static_cast<int16_t>(roundf(values[18] * divisor)),
151         };
152         vImageMatrixMultiply_ARGB8888(&src, &dest, matrix, divisor, nullptr, nullptr, kvImageNoFlags);
153         break;
154     }
155
156     case FECOLORMATRIX_TYPE_SATURATE:
157     case FECOLORMATRIX_TYPE_HUEROTATE: {
158         const int16_t matrix[4 * 4] = {
159             static_cast<int16_t>(roundf(components[0] * divisor)),
160             static_cast<int16_t>(roundf(components[3] * divisor)),
161             static_cast<int16_t>(roundf(components[6] * divisor)),
162             0,
163
164             static_cast<int16_t>(roundf(components[1] * divisor)),
165             static_cast<int16_t>(roundf(components[4] * divisor)),
166             static_cast<int16_t>(roundf(components[7] * divisor)),
167             0,
168
169             static_cast<int16_t>(roundf(components[2] * divisor)),
170             static_cast<int16_t>(roundf(components[5] * divisor)),
171             static_cast<int16_t>(roundf(components[8] * divisor)),
172             0,
173
174             0,
175             0,
176             0,
177             divisor,
178         };
179         vImageMatrixMultiply_ARGB8888(&src, &dest, matrix, divisor, nullptr, nullptr, kvImageNoFlags);
180         break;
181     }
182     case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: {
183         const int16_t matrix[4 * 4] = {
184             0,
185             0,
186             0,
187             static_cast<int16_t>(roundf(0.2125 * divisor)),
188
189             0,
190             0,
191             0,
192             static_cast<int16_t>(roundf(0.7154 * divisor)),
193
194             0,
195             0,
196             0,
197             static_cast<int16_t>(roundf(0.0721 * divisor)),
198
199             0,
200             0,
201             0,
202             0,
203         };
204         vImageMatrixMultiply_ARGB8888(&src, &dest, matrix, divisor, nullptr, nullptr, kvImageNoFlags);
205         break;
206     }
207     }
208     
209     return true;
210 }
211 #endif
212
213 template<ColorMatrixType filterType>
214 void effectType(Uint8ClampedArray* pixelArray, const Vector<float>& values, IntSize bufferSize)
215 {
216     float components[9];
217
218     if (filterType == FECOLORMATRIX_TYPE_SATURATE)
219         FEColorMatrix::calculateSaturateComponents(components, values[0]);
220     else if (filterType == FECOLORMATRIX_TYPE_HUEROTATE)
221         FEColorMatrix::calculateHueRotateComponents(components, values[0]);
222
223     unsigned pixelArrayLength = pixelArray->length();
224
225 #if USE(ACCELERATE)
226     if (effectApplyAccelerated<filterType>(pixelArray, values, components, bufferSize))
227         return;
228 #else
229     UNUSED_PARAM(bufferSize);
230 #endif
231
232     switch (filterType) {
233     case FECOLORMATRIX_TYPE_MATRIX:
234         for (unsigned pixelByteOffset = 0; pixelByteOffset < pixelArrayLength; pixelByteOffset += 4) {
235             float red = pixelArray->item(pixelByteOffset);
236             float green = pixelArray->item(pixelByteOffset + 1);
237             float blue = pixelArray->item(pixelByteOffset + 2);
238             float alpha = pixelArray->item(pixelByteOffset + 3);
239             matrix(red, green, blue, alpha, values);
240             pixelArray->set(pixelByteOffset, red);
241             pixelArray->set(pixelByteOffset + 1, green);
242             pixelArray->set(pixelByteOffset + 2, blue);
243             pixelArray->set(pixelByteOffset + 3, alpha);
244         }
245         break;
246
247     case FECOLORMATRIX_TYPE_SATURATE:
248     case FECOLORMATRIX_TYPE_HUEROTATE:
249         for (unsigned pixelByteOffset = 0; pixelByteOffset < pixelArrayLength; pixelByteOffset += 4) {
250             float red = pixelArray->item(pixelByteOffset);
251             float green = pixelArray->item(pixelByteOffset + 1);
252             float blue = pixelArray->item(pixelByteOffset + 2);
253             float alpha = pixelArray->item(pixelByteOffset + 3);
254             saturateAndHueRotate(red, green, blue, components);
255             pixelArray->set(pixelByteOffset, red);
256             pixelArray->set(pixelByteOffset + 1, green);
257             pixelArray->set(pixelByteOffset + 2, blue);
258             pixelArray->set(pixelByteOffset + 3, alpha);
259         }
260         break;
261
262     case FECOLORMATRIX_TYPE_LUMINANCETOALPHA:
263         for (unsigned pixelByteOffset = 0; pixelByteOffset < pixelArrayLength; pixelByteOffset += 4) {
264             float red = pixelArray->item(pixelByteOffset);
265             float green = pixelArray->item(pixelByteOffset + 1);
266             float blue = pixelArray->item(pixelByteOffset + 2);
267             float alpha = pixelArray->item(pixelByteOffset + 3);
268             luminance(red, green, blue, alpha);
269             pixelArray->set(pixelByteOffset, red);
270             pixelArray->set(pixelByteOffset + 1, green);
271             pixelArray->set(pixelByteOffset + 2, blue);
272             pixelArray->set(pixelByteOffset + 3, alpha);
273         }
274         break;
275     }
276 }
277
278 void FEColorMatrix::platformApplySoftware()
279 {
280     FilterEffect* in = inputEffect(0);
281
282     ImageBuffer* resultImage = createImageBufferResult();
283     if (!resultImage)
284         return;
285
286 #if PRINT_FILTER_PERFORMANCE
287     MonotonicTime startTime = MonotonicTime::now();
288 #endif
289
290     ImageBuffer* inBuffer = in->asImageBuffer();
291     if (inBuffer)
292         resultImage->context().drawImageBuffer(*inBuffer, drawingRegionOfInputImage(in->absolutePaintRect()));
293
294     IntRect imageRect(IntPoint(), resultImage->logicalSize());
295     IntSize pixelArrayDimensions;
296     RefPtr<Uint8ClampedArray> pixelArray = resultImage->getUnmultipliedImageData(imageRect, &pixelArrayDimensions);
297     Vector<float> values = normalizedFloats(m_values);
298
299     switch (m_type) {
300     case FECOLORMATRIX_TYPE_UNKNOWN:
301         break;
302     case FECOLORMATRIX_TYPE_MATRIX:
303         effectType<FECOLORMATRIX_TYPE_MATRIX>(pixelArray.get(), values, pixelArrayDimensions);
304         break;
305     case FECOLORMATRIX_TYPE_SATURATE: 
306         effectType<FECOLORMATRIX_TYPE_SATURATE>(pixelArray.get(), values, pixelArrayDimensions);
307         break;
308     case FECOLORMATRIX_TYPE_HUEROTATE:
309         effectType<FECOLORMATRIX_TYPE_HUEROTATE>(pixelArray.get(), values, pixelArrayDimensions);
310         break;
311     case FECOLORMATRIX_TYPE_LUMINANCETOALPHA:
312         effectType<FECOLORMATRIX_TYPE_LUMINANCETOALPHA>(pixelArray.get(), values, pixelArrayDimensions);
313         setIsAlphaImage(true);
314         break;
315     }
316
317     resultImage->putByteArray(Unmultiplied, pixelArray.get(), imageRect.size(), imageRect, IntPoint());
318
319 #if PRINT_FILTER_PERFORMANCE
320     MonotonicTime endTime = MonotonicTime::now();
321     Seconds duration = endTime - startTime;
322     unsigned pixelCount = imageRect.width() * imageRect.height();
323     
324     static double totalMegapixels;
325     totalMegapixels += (double)pixelCount / 1048576.0;
326     
327     static Seconds totalTime;
328     totalTime += duration;
329     
330     WTFLogAlways("FEColorMatrix::platformApplySoftware (%dx%d) took %.4fms (ave %.4fms/mp)", imageRect.width(), imageRect.height(), duration.milliseconds(), totalTime.milliseconds() / totalMegapixels);
331 #endif
332 }
333
334 static TextStream& operator<<(TextStream& ts, const ColorMatrixType& type)
335 {
336     switch (type) {
337     case FECOLORMATRIX_TYPE_UNKNOWN:
338         ts << "UNKNOWN";
339         break;
340     case FECOLORMATRIX_TYPE_MATRIX:
341         ts << "MATRIX";
342         break;
343     case FECOLORMATRIX_TYPE_SATURATE:
344         ts << "SATURATE";
345         break;
346     case FECOLORMATRIX_TYPE_HUEROTATE:
347         ts << "HUEROTATE";
348         break;
349     case FECOLORMATRIX_TYPE_LUMINANCETOALPHA:
350         ts << "LUMINANCETOALPHA";
351         break;
352     }
353     return ts;
354 }
355
356 TextStream& FEColorMatrix::externalRepresentation(TextStream& ts, int indent) const
357 {
358     writeIndent(ts, indent);
359     ts << "[feColorMatrix";
360     FilterEffect::externalRepresentation(ts);
361     ts << " type=\"" << m_type << "\"";
362     if (!m_values.isEmpty()) {
363         ts << " values=\"";
364         Vector<float>::const_iterator ptr = m_values.begin();
365         const Vector<float>::const_iterator end = m_values.end();
366         while (ptr < end) {
367             ts << *ptr;
368             ++ptr;
369             if (ptr < end) 
370                 ts << " ";
371         }
372         ts << "\"";
373     }
374     ts << "]\n";
375     inputEffect(0)->externalRepresentation(ts, indent + 1);
376     return ts;
377 }
378
379 } // namespace WebCore