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