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