2011-02-28 Renata Hodovan <reni@webkit.org>
[WebKit-https.git] / Source / WebCore / platform / graphics / filters / FEComposite.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  * 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
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
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
53 CompositeOperationType FEComposite::operation() const
54 {
55     return m_type;
56 }
57
58 bool FEComposite::setOperation(CompositeOperationType type)
59 {
60     if (m_type == type)
61         return false;
62     m_type = type;
63     return true;
64 }
65
66 float FEComposite::k1() const
67 {
68     return m_k1;
69 }
70
71 bool FEComposite::setK1(float k1)
72 {
73     if (m_k1 == k1)
74         return false;
75     m_k1 = k1;
76     return true;
77 }
78
79 float FEComposite::k2() const
80 {
81     return m_k2;
82 }
83
84 bool FEComposite::setK2(float k2)
85 {
86     if (m_k2 == k2)
87         return false;
88     m_k2 = k2;
89     return true;
90 }
91
92 float FEComposite::k3() const
93 {
94     return m_k3;
95 }
96
97 bool FEComposite::setK3(float k3)
98 {
99     if (m_k3 == k3)
100         return false;
101     m_k3 = k3;
102     return true;
103 }
104
105 float FEComposite::k4() const
106 {
107     return m_k4;
108 }
109
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>
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
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
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(maxEffectRect());
191         return;
192     default:
193         // Take the union of both input effects.
194         FilterEffect::determineAbsolutePaintRect();
195         return;
196     }
197 }
198
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
259 void FEComposite::dump()
260 {
261 }
262
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
291 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)