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 "FEComposite.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
36 namespace WebCore {
37
FEComposite(Filter * filter,const CompositeOperationType & type,float k1,float k2,float k3,float k4)38 FEComposite::FEComposite(Filter* filter, const CompositeOperationType& type, float k1, float k2, float k3, float k4)
39 : FilterEffect(filter)
40 , m_type(type)
41 , m_k1(k1)
42 , m_k2(k2)
43 , m_k3(k3)
44 , m_k4(k4)
45 {
46 }
47
create(Filter * filter,const CompositeOperationType & type,float k1,float k2,float k3,float k4)48 PassRefPtr<FEComposite> FEComposite::create(Filter* filter, const CompositeOperationType& type, float k1, float k2, float k3, float k4)
49 {
50 return adoptRef(new FEComposite(filter, type, k1, k2, k3, k4));
51 }
52
operation() const53 CompositeOperationType FEComposite::operation() const
54 {
55 return m_type;
56 }
57
setOperation(CompositeOperationType type)58 bool FEComposite::setOperation(CompositeOperationType type)
59 {
60 if (m_type == type)
61 return false;
62 m_type = type;
63 return true;
64 }
65
k1() const66 float FEComposite::k1() const
67 {
68 return m_k1;
69 }
70
setK1(float k1)71 bool FEComposite::setK1(float k1)
72 {
73 if (m_k1 == k1)
74 return false;
75 m_k1 = k1;
76 return true;
77 }
78
k2() const79 float FEComposite::k2() const
80 {
81 return m_k2;
82 }
83
setK2(float k2)84 bool FEComposite::setK2(float k2)
85 {
86 if (m_k2 == k2)
87 return false;
88 m_k2 = k2;
89 return true;
90 }
91
k3() const92 float FEComposite::k3() const
93 {
94 return m_k3;
95 }
96
setK3(float k3)97 bool FEComposite::setK3(float k3)
98 {
99 if (m_k3 == k3)
100 return false;
101 m_k3 = k3;
102 return true;
103 }
104
k4() const105 float FEComposite::k4() const
106 {
107 return m_k4;
108 }
109
setK4(float k4)110 bool FEComposite::setK4(float k4)
111 {
112 if (m_k4 == k4)
113 return false;
114 m_k4 = k4;
115 return true;
116 }
117
118 template <int b1, int b2, int b3, int b4>
computeArithmeticPixels(unsigned char * source,unsigned char * destination,int pixelArrayLength,float k1,float k2,float k3,float k4)119 inline void computeArithmeticPixels(unsigned char* source, unsigned char* destination, int pixelArrayLength,
120 float k1, float k2, float k3, float k4)
121 {
122 float scaledK4;
123 float scaledK1;
124 if (b1)
125 scaledK1 = k1 / 255.f;
126 if (b4)
127 scaledK4 = k4 * 255.f;
128
129 while (--pixelArrayLength >= 0) {
130 unsigned char i1 = *source;
131 unsigned char i2 = *destination;
132 float result = 0;
133 if (b1)
134 result += scaledK1 * i1 * i2;
135 if (b2)
136 result += k2 * i1;
137 if (b3)
138 result += k3 * i2;
139 if (b4)
140 result += scaledK4;
141
142 if (result <= 0)
143 *destination = 0;
144 else if (result >= 255)
145 *destination = 255;
146 else
147 *destination = result;
148 ++source;
149 ++destination;
150 }
151 }
152
arithmetic(ByteArray * srcPixelArrayA,ByteArray * srcPixelArrayB,float k1,float k2,float k3,float k4)153 inline void arithmetic(ByteArray* srcPixelArrayA, ByteArray* srcPixelArrayB,
154 float k1, float k2, float k3, float k4)
155 {
156 int pixelArrayLength = srcPixelArrayA->length();
157 ASSERT(pixelArrayLength == static_cast<int>(srcPixelArrayB->length()));
158 unsigned char* source = srcPixelArrayA->data();
159 unsigned char* destination = srcPixelArrayB->data();
160
161 if (!k4) {
162 if (!k1) {
163 computeArithmeticPixels<0, 1, 1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
164 return;
165 }
166
167 computeArithmeticPixels<1, 1, 1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
168 return;
169 }
170
171 if (!k1) {
172 computeArithmeticPixels<0, 1, 1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
173 return;
174 }
175 computeArithmeticPixels<1, 1, 1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
176 }
177
determineAbsolutePaintRect()178 void FEComposite::determineAbsolutePaintRect()
179 {
180 switch (m_type) {
181 case FECOMPOSITE_OPERATOR_IN:
182 case FECOMPOSITE_OPERATOR_ATOP:
183 // For In and Atop the first effect just influences the result of
184 // the second effect. So just use the absolute paint rect of the second effect here.
185 setAbsolutePaintRect(inputEffect(1)->absolutePaintRect());
186 return;
187 case FECOMPOSITE_OPERATOR_ARITHMETIC:
188 // Arithmetic may influnce the compele filter primitive region. So we can't
189 // optimize the paint region here.
190 setAbsolutePaintRect(enclosingIntRect(maxEffectRect()));
191 return;
192 default:
193 // Take the union of both input effects.
194 FilterEffect::determineAbsolutePaintRect();
195 return;
196 }
197 }
198
apply()199 void FEComposite::apply()
200 {
201 if (hasResult())
202 return;
203 FilterEffect* in = inputEffect(0);
204 FilterEffect* in2 = inputEffect(1);
205 in->apply();
206 in2->apply();
207 if (!in->hasResult() || !in2->hasResult())
208 return;
209
210 if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) {
211 ByteArray* dstPixelArray = createPremultipliedImageResult();
212 if (!dstPixelArray)
213 return;
214
215 IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
216 RefPtr<ByteArray> srcPixelArray = in->asPremultipliedImage(effectADrawingRect);
217
218 IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
219 in2->copyPremultipliedImage(dstPixelArray, effectBDrawingRect);
220
221 arithmetic(srcPixelArray.get(), dstPixelArray, m_k1, m_k2, m_k3, m_k4);
222 return;
223 }
224
225 ImageBuffer* resultImage = createImageBufferResult();
226 if (!resultImage)
227 return;
228 GraphicsContext* filterContext = resultImage->context();
229
230 FloatRect srcRect = FloatRect(0, 0, -1, -1);
231 switch (m_type) {
232 case FECOMPOSITE_OPERATOR_OVER:
233 filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
234 filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
235 break;
236 case FECOMPOSITE_OPERATOR_IN:
237 filterContext->save();
238 filterContext->clipToImageBuffer(in2->asImageBuffer(), drawingRegionOfInputImage(in2->absolutePaintRect()));
239 filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
240 filterContext->restore();
241 break;
242 case FECOMPOSITE_OPERATOR_OUT:
243 filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()));
244 filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()), srcRect, CompositeDestinationOut);
245 break;
246 case FECOMPOSITE_OPERATOR_ATOP:
247 filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
248 filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeSourceAtop);
249 break;
250 case FECOMPOSITE_OPERATOR_XOR:
251 filterContext->drawImageBuffer(in2->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()));
252 filterContext->drawImageBuffer(in->asImageBuffer(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeXOR);
253 break;
254 default:
255 break;
256 }
257 }
258
dump()259 void FEComposite::dump()
260 {
261 }
262
operator <<(TextStream & ts,const CompositeOperationType & type)263 static TextStream& operator<<(TextStream& ts, const CompositeOperationType& type)
264 {
265 switch (type) {
266 case FECOMPOSITE_OPERATOR_UNKNOWN:
267 ts << "UNKNOWN";
268 break;
269 case FECOMPOSITE_OPERATOR_OVER:
270 ts << "OVER";
271 break;
272 case FECOMPOSITE_OPERATOR_IN:
273 ts << "IN";
274 break;
275 case FECOMPOSITE_OPERATOR_OUT:
276 ts << "OUT";
277 break;
278 case FECOMPOSITE_OPERATOR_ATOP:
279 ts << "ATOP";
280 break;
281 case FECOMPOSITE_OPERATOR_XOR:
282 ts << "XOR";
283 break;
284 case FECOMPOSITE_OPERATOR_ARITHMETIC:
285 ts << "ARITHMETIC";
286 break;
287 }
288 return ts;
289 }
290
externalRepresentation(TextStream & ts,int indent) const291 TextStream& FEComposite::externalRepresentation(TextStream& ts, int indent) const
292 {
293 writeIndent(ts, indent);
294 ts << "[feComposite";
295 FilterEffect::externalRepresentation(ts);
296 ts << " operation=\"" << m_type << "\"";
297 if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC)
298 ts << " k1=\"" << m_k1 << "\" k2=\"" << m_k2 << "\" k3=\"" << m_k3 << "\" k4=\"" << m_k4 << "\"";
299 ts << "]\n";
300 inputEffect(0)->externalRepresentation(ts, indent + 1);
301 inputEffect(1)->externalRepresentation(ts, indent + 1);
302 return ts;
303 }
304
305 } // namespace WebCore
306
307 #endif // ENABLE(FILTERS)
308