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 * 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 "FEComponentTransfer.h"
28
29 #include "Filter.h"
30 #include "GraphicsContext.h"
31 #include "RenderTreeAsText.h"
32 #include "TextStream.h"
33
34 #include <wtf/ByteArray.h>
35 #include <wtf/MathExtras.h>
36
37 namespace WebCore {
38
39 typedef void (*TransferType)(unsigned char*, const ComponentTransferFunction&);
40
FEComponentTransfer(Filter * filter,const ComponentTransferFunction & redFunc,const ComponentTransferFunction & greenFunc,const ComponentTransferFunction & blueFunc,const ComponentTransferFunction & alphaFunc)41 FEComponentTransfer::FEComponentTransfer(Filter* filter, const ComponentTransferFunction& redFunc, const ComponentTransferFunction& greenFunc,
42 const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc)
43 : FilterEffect(filter)
44 , m_redFunc(redFunc)
45 , m_greenFunc(greenFunc)
46 , m_blueFunc(blueFunc)
47 , m_alphaFunc(alphaFunc)
48 {
49 }
50
create(Filter * filter,const ComponentTransferFunction & redFunc,const ComponentTransferFunction & greenFunc,const ComponentTransferFunction & blueFunc,const ComponentTransferFunction & alphaFunc)51 PassRefPtr<FEComponentTransfer> FEComponentTransfer::create(Filter* filter, const ComponentTransferFunction& redFunc,
52 const ComponentTransferFunction& greenFunc, const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc)
53 {
54 return adoptRef(new FEComponentTransfer(filter, redFunc, greenFunc, blueFunc, alphaFunc));
55 }
56
redFunction() const57 ComponentTransferFunction FEComponentTransfer::redFunction() const
58 {
59 return m_redFunc;
60 }
61
setRedFunction(const ComponentTransferFunction & func)62 void FEComponentTransfer::setRedFunction(const ComponentTransferFunction& func)
63 {
64 m_redFunc = func;
65 }
66
greenFunction() const67 ComponentTransferFunction FEComponentTransfer::greenFunction() const
68 {
69 return m_greenFunc;
70 }
71
setGreenFunction(const ComponentTransferFunction & func)72 void FEComponentTransfer::setGreenFunction(const ComponentTransferFunction& func)
73 {
74 m_greenFunc = func;
75 }
76
blueFunction() const77 ComponentTransferFunction FEComponentTransfer::blueFunction() const
78 {
79 return m_blueFunc;
80 }
81
setBlueFunction(const ComponentTransferFunction & func)82 void FEComponentTransfer::setBlueFunction(const ComponentTransferFunction& func)
83 {
84 m_blueFunc = func;
85 }
86
alphaFunction() const87 ComponentTransferFunction FEComponentTransfer::alphaFunction() const
88 {
89 return m_alphaFunc;
90 }
91
setAlphaFunction(const ComponentTransferFunction & func)92 void FEComponentTransfer::setAlphaFunction(const ComponentTransferFunction& func)
93 {
94 m_alphaFunc = func;
95 }
96
identity(unsigned char *,const ComponentTransferFunction &)97 static void identity(unsigned char*, const ComponentTransferFunction&)
98 {
99 }
100
table(unsigned char * values,const ComponentTransferFunction & transferFunction)101 static void table(unsigned char* values, const ComponentTransferFunction& transferFunction)
102 {
103 const Vector<float>& tableValues = transferFunction.tableValues;
104 unsigned n = tableValues.size();
105 if (n < 1)
106 return;
107 for (unsigned i = 0; i < 256; ++i) {
108 double c = i / 255.0;
109 unsigned k = static_cast<unsigned>(c * (n - 1));
110 double v1 = tableValues[k];
111 double v2 = tableValues[std::min((k + 1), (n - 1))];
112 double val = 255.0 * (v1 + (c * (n - 1) - k) * (v2 - v1));
113 val = std::max(0.0, std::min(255.0, val));
114 values[i] = static_cast<unsigned char>(val);
115 }
116 }
117
discrete(unsigned char * values,const ComponentTransferFunction & transferFunction)118 static void discrete(unsigned char* values, const ComponentTransferFunction& transferFunction)
119 {
120 const Vector<float>& tableValues = transferFunction.tableValues;
121 unsigned n = tableValues.size();
122 if (n < 1)
123 return;
124 for (unsigned i = 0; i < 256; ++i) {
125 unsigned k = static_cast<unsigned>((i * n) / 255.0);
126 k = std::min(k, n - 1);
127 double val = 255 * tableValues[k];
128 val = std::max(0.0, std::min(255.0, val));
129 values[i] = static_cast<unsigned char>(val);
130 }
131 }
132
linear(unsigned char * values,const ComponentTransferFunction & transferFunction)133 static void linear(unsigned char* values, const ComponentTransferFunction& transferFunction)
134 {
135 for (unsigned i = 0; i < 256; ++i) {
136 double val = transferFunction.slope * i + 255 * transferFunction.intercept;
137 val = std::max(0.0, std::min(255.0, val));
138 values[i] = static_cast<unsigned char>(val);
139 }
140 }
141
gamma(unsigned char * values,const ComponentTransferFunction & transferFunction)142 static void gamma(unsigned char* values, const ComponentTransferFunction& transferFunction)
143 {
144 for (unsigned i = 0; i < 256; ++i) {
145 double exponent = transferFunction.exponent; // RCVT doesn't like passing a double and a float to pow, so promote this to double
146 double val = 255.0 * (transferFunction.amplitude * pow((i / 255.0), exponent) + transferFunction.offset);
147 val = std::max(0.0, std::min(255.0, val));
148 values[i] = static_cast<unsigned char>(val);
149 }
150 }
151
apply()152 void FEComponentTransfer::apply()
153 {
154 if (hasResult())
155 return;
156 FilterEffect* in = inputEffect(0);
157 in->apply();
158 if (!in->hasResult())
159 return;
160
161 ByteArray* pixelArray = createUnmultipliedImageResult();
162 if (!pixelArray)
163 return;
164
165 unsigned char rValues[256], gValues[256], bValues[256], aValues[256];
166 for (unsigned i = 0; i < 256; ++i)
167 rValues[i] = gValues[i] = bValues[i] = aValues[i] = i;
168 unsigned char* tables[] = { rValues, gValues, bValues, aValues };
169 ComponentTransferFunction transferFunction[] = {m_redFunc, m_greenFunc, m_blueFunc, m_alphaFunc};
170 TransferType callEffect[] = {identity, identity, table, discrete, linear, gamma};
171
172 for (unsigned channel = 0; channel < 4; channel++)
173 (*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]);
174
175 IntRect drawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
176 in->copyUnmultipliedImage(pixelArray, drawingRect);
177
178 unsigned pixelArrayLength = pixelArray->length();
179 for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) {
180 for (unsigned channel = 0; channel < 4; ++channel) {
181 unsigned char c = pixelArray->get(pixelOffset + channel);
182 pixelArray->set(pixelOffset + channel, tables[channel][c]);
183 }
184 }
185 }
186
dump()187 void FEComponentTransfer::dump()
188 {
189 }
190
operator <<(TextStream & ts,const ComponentTransferType & type)191 static TextStream& operator<<(TextStream& ts, const ComponentTransferType& type)
192 {
193 switch (type) {
194 case FECOMPONENTTRANSFER_TYPE_UNKNOWN:
195 ts << "UNKNOWN";
196 break;
197 case FECOMPONENTTRANSFER_TYPE_IDENTITY:
198 ts << "IDENTITY";
199 break;
200 case FECOMPONENTTRANSFER_TYPE_TABLE:
201 ts << "TABLE";
202 break;
203 case FECOMPONENTTRANSFER_TYPE_DISCRETE:
204 ts << "DISCRETE";
205 break;
206 case FECOMPONENTTRANSFER_TYPE_LINEAR:
207 ts << "LINEAR";
208 break;
209 case FECOMPONENTTRANSFER_TYPE_GAMMA:
210 ts << "GAMMA";
211 break;
212 }
213 return ts;
214 }
215
operator <<(TextStream & ts,const ComponentTransferFunction & function)216 static TextStream& operator<<(TextStream& ts, const ComponentTransferFunction& function)
217 {
218 ts << "type=\"" << function.type
219 << "\" slope=\"" << function.slope
220 << "\" intercept=\"" << function.intercept
221 << "\" amplitude=\"" << function.amplitude
222 << "\" exponent=\"" << function.exponent
223 << "\" offset=\"" << function.offset << "\"";
224 return ts;
225 }
226
externalRepresentation(TextStream & ts,int indent) const227 TextStream& FEComponentTransfer::externalRepresentation(TextStream& ts, int indent) const
228 {
229 writeIndent(ts, indent);
230 ts << "[feComponentTransfer";
231 FilterEffect::externalRepresentation(ts);
232 ts << " \n";
233 writeIndent(ts, indent + 2);
234 ts << "{red: " << m_redFunc << "}\n";
235 writeIndent(ts, indent + 2);
236 ts << "{green: " << m_greenFunc << "}\n";
237 writeIndent(ts, indent + 2);
238 ts << "{blue: " << m_blueFunc << "}\n";
239 writeIndent(ts, indent + 2);
240 ts << "{alpha: " << m_alphaFunc << "}]\n";
241 inputEffect(0)->externalRepresentation(ts, indent + 1);
242 return ts;
243 }
244
245 } // namespace WebCore
246
247 #endif // ENABLE(FILTERS)
248