Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / 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  * Copyright (C) 2013 Google Inc. All rights reserved.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24
25 #include "config.h"
26
27 #include "platform/graphics/filters/FEComposite.h"
28
29 #include "SkArithmeticMode.h"
30 #include "SkFlattenableBuffers.h"
31 #include "SkXfermodeImageFilter.h"
32
33 #include "platform/graphics/GraphicsContext.h"
34 #include "platform/graphics/cpu/arm/filters/FECompositeArithmeticNEON.h"
35 #include "platform/graphics/filters/SkiaImageFilterBuilder.h"
36 #include "platform/text/TextStream.h"
37 #include "third_party/skia/include/core/SkDevice.h"
38
39 #include "wtf/Uint8ClampedArray.h"
40
41 namespace WebCore {
42
43 FEComposite::FEComposite(Filter* filter, const CompositeOperationType& type, float k1, float k2, float k3, float k4)
44     : FilterEffect(filter)
45     , m_type(type)
46     , m_k1(k1)
47     , m_k2(k2)
48     , m_k3(k3)
49     , m_k4(k4)
50 {
51 }
52
53 PassRefPtr<FEComposite> FEComposite::create(Filter* filter, const CompositeOperationType& type, float k1, float k2, float k3, float k4)
54 {
55     return adoptRef(new FEComposite(filter, type, k1, k2, k3, k4));
56 }
57
58 CompositeOperationType FEComposite::operation() const
59 {
60     return m_type;
61 }
62
63 bool FEComposite::setOperation(CompositeOperationType type)
64 {
65     if (m_type == type)
66         return false;
67     m_type = type;
68     return true;
69 }
70
71 float FEComposite::k1() const
72 {
73     return m_k1;
74 }
75
76 bool FEComposite::setK1(float k1)
77 {
78     if (m_k1 == k1)
79         return false;
80     m_k1 = k1;
81     return true;
82 }
83
84 float FEComposite::k2() const
85 {
86     return m_k2;
87 }
88
89 bool FEComposite::setK2(float k2)
90 {
91     if (m_k2 == k2)
92         return false;
93     m_k2 = k2;
94     return true;
95 }
96
97 float FEComposite::k3() const
98 {
99     return m_k3;
100 }
101
102 bool FEComposite::setK3(float k3)
103 {
104     if (m_k3 == k3)
105         return false;
106     m_k3 = k3;
107     return true;
108 }
109
110 float FEComposite::k4() const
111 {
112     return m_k4;
113 }
114
115 bool FEComposite::setK4(float k4)
116 {
117     if (m_k4 == k4)
118         return false;
119     m_k4 = k4;
120     return true;
121 }
122
123 void FEComposite::correctFilterResultIfNeeded()
124 {
125     if (m_type != FECOMPOSITE_OPERATOR_ARITHMETIC)
126         return;
127
128     forceValidPreMultipliedPixels();
129 }
130
131 template <int b1, int b4>
132 static inline void computeArithmeticPixels(unsigned char* source, unsigned char* destination, int pixelArrayLength,
133                                     float k1, float k2, float k3, float k4)
134 {
135     float scaledK1;
136     float scaledK4;
137     if (b1)
138         scaledK1 = k1 / 255.0f;
139     if (b4)
140         scaledK4 = k4 * 255.0f;
141
142     while (--pixelArrayLength >= 0) {
143         unsigned char i1 = *source;
144         unsigned char i2 = *destination;
145         float result = k2 * i1 + k3 * i2;
146         if (b1)
147             result += scaledK1 * i1 * i2;
148         if (b4)
149             result += scaledK4;
150
151         if (result <= 0)
152             *destination = 0;
153         else if (result >= 255)
154             *destination = 255;
155         else
156             *destination = result;
157         ++source;
158         ++destination;
159     }
160 }
161
162 // computeArithmeticPixelsUnclamped is a faster version of computeArithmeticPixels for the common case where clamping
163 // is not necessary. This enables aggresive compiler optimizations such as auto-vectorization.
164 template <int b1, int b4>
165 static inline void computeArithmeticPixelsUnclamped(unsigned char* source, unsigned char* destination, int pixelArrayLength, float k1, float k2, float k3, float k4)
166 {
167     float scaledK1;
168     float scaledK4;
169     if (b1)
170         scaledK1 = k1 / 255.0f;
171     if (b4)
172         scaledK4 = k4 * 255.0f;
173
174     while (--pixelArrayLength >= 0) {
175         unsigned char i1 = *source;
176         unsigned char i2 = *destination;
177         float result = k2 * i1 + k3 * i2;
178         if (b1)
179             result += scaledK1 * i1 * i2;
180         if (b4)
181             result += scaledK4;
182
183         *destination = result;
184         ++source;
185         ++destination;
186     }
187 }
188
189 static inline void arithmeticSoftware(unsigned char* source, unsigned char* destination, int pixelArrayLength, float k1, float k2, float k3, float k4)
190 {
191     float upperLimit = std::max(0.0f, k1) + std::max(0.0f, k2) + std::max(0.0f, k3) + k4;
192     float lowerLimit = std::min(0.0f, k1) + std::min(0.0f, k2) + std::min(0.0f, k3) + k4;
193     if ((k4 >= 0.0f && k4 <= 1.0f) && (upperLimit >= 0.0f && upperLimit <= 1.0f) && (lowerLimit >= 0.0f && lowerLimit <= 1.0f)) {
194         if (k4) {
195             if (k1)
196                 computeArithmeticPixelsUnclamped<1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
197             else
198                 computeArithmeticPixelsUnclamped<0, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
199         } else {
200             if (k1)
201                 computeArithmeticPixelsUnclamped<1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
202             else
203                 computeArithmeticPixelsUnclamped<0, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
204         }
205         return;
206     }
207
208     if (k4) {
209         if (k1)
210             computeArithmeticPixels<1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
211         else
212             computeArithmeticPixels<0, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
213     } else {
214         if (k1)
215             computeArithmeticPixels<1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
216         else
217             computeArithmeticPixels<0, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
218     }
219 }
220
221 inline void FEComposite::platformArithmeticSoftware(Uint8ClampedArray* source, Uint8ClampedArray* destination,
222     float k1, float k2, float k3, float k4)
223 {
224     int length = source->length();
225     ASSERT(length == static_cast<int>(destination->length()));
226     // The selection here eventually should happen dynamically.
227 #if HAVE(ARM_NEON_INTRINSICS)
228     ASSERT(!(length & 0x3));
229     platformArithmeticNeon(source->data(), destination->data(), length, k1, k2, k3, k4);
230 #else
231     arithmeticSoftware(source->data(), destination->data(), length, k1, k2, k3, k4);
232 #endif
233 }
234
235 FloatRect FEComposite::determineAbsolutePaintRect(const FloatRect& originalRequestedRect)
236 {
237     FloatRect requestedRect = originalRequestedRect;
238     if (clipsToBounds())
239         requestedRect.intersect(maxEffectRect());
240
241     // We may be called multiple times if result is used more than once. Return
242     // quickly if nothing new is required.
243     if (absolutePaintRect().contains(enclosingIntRect(requestedRect)))
244         return requestedRect;
245
246     // No mapPaintRect required for FEComposite.
247     FloatRect input1Rect = inputEffect(1)->determineAbsolutePaintRect(requestedRect);
248     FloatRect affectedRect;
249     switch (m_type) {
250     case FECOMPOSITE_OPERATOR_IN:
251         // 'in' has output only in the intersection of both inputs.
252         affectedRect = intersection(input1Rect, inputEffect(0)->determineAbsolutePaintRect(input1Rect));
253         break;
254     case FECOMPOSITE_OPERATOR_ATOP:
255         // 'atop' has output only in the extents of the second input.
256         // Make sure first input knows where it needs to produce output.
257         inputEffect(0)->determineAbsolutePaintRect(input1Rect);
258         affectedRect = input1Rect;
259         break;
260     case FECOMPOSITE_OPERATOR_ARITHMETIC:
261         if (k4() > 0) {
262             // Make sure first input knows where it needs to produce output.
263             inputEffect(0)->determineAbsolutePaintRect(requestedRect);
264             // Arithmetic with non-zero k4 may influnce the complete filter primitive
265             // region. So we can't optimize the paint region here.
266             affectedRect = requestedRect;
267             break;
268         }
269         if (k2() <= 0) {
270             // Input 0 does not appear where input 1 is not present.
271             FloatRect input0Rect = inputEffect(0)->determineAbsolutePaintRect(input1Rect);
272             if (k3() > 0) {
273                 affectedRect = input1Rect;
274             } else {
275                 // Just k1 is positive. Use intersection.
276                 affectedRect = intersection(input1Rect, input0Rect);
277             }
278             break;
279         }
280         // else fall through to use union
281     default:
282         // Take the union of both input effects.
283         affectedRect = unionRect(input1Rect, inputEffect(0)->determineAbsolutePaintRect(requestedRect));
284         break;
285     }
286
287     affectedRect.intersect(requestedRect);
288     addAbsolutePaintRect(affectedRect);
289     return affectedRect;
290 }
291
292 void FEComposite::applySoftware()
293 {
294     FilterEffect* in = inputEffect(0);
295     FilterEffect* in2 = inputEffect(1);
296
297     if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) {
298         Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult();
299         if (!dstPixelArray)
300             return;
301
302         IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
303         RefPtr<Uint8ClampedArray> srcPixelArray = in->asPremultipliedImage(effectADrawingRect);
304
305         IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
306         in2->copyPremultipliedImage(dstPixelArray, effectBDrawingRect);
307
308         platformArithmeticSoftware(srcPixelArray.get(), dstPixelArray, m_k1, m_k2, m_k3, m_k4);
309         return;
310     }
311
312     ImageBuffer* resultImage = createImageBufferResult();
313     if (!resultImage)
314         return;
315     GraphicsContext* filterContext = resultImage->context();
316
317     ImageBuffer* imageBuffer = in->asImageBuffer();
318     ImageBuffer* imageBuffer2 = in2->asImageBuffer();
319     ASSERT(imageBuffer);
320     ASSERT(imageBuffer2);
321
322     switch (m_type) {
323     case FECOMPOSITE_OPERATOR_OVER:
324         filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()));
325         filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()));
326         break;
327     case FECOMPOSITE_OPERATOR_IN: {
328         // Applies only to the intersected region.
329         IntRect destinationRect = in->absolutePaintRect();
330         destinationRect.intersect(in2->absolutePaintRect());
331         destinationRect.intersect(absolutePaintRect());
332         if (destinationRect.isEmpty())
333             break;
334         IntPoint destinationPoint(destinationRect.x() - absolutePaintRect().x(), destinationRect.y() - absolutePaintRect().y());
335         FloatRect sourceRect(IntPoint(destinationRect.x() - in->absolutePaintRect().x(),
336                                     destinationRect.y() - in->absolutePaintRect().y()), destinationRect.size());
337         FloatRect source2Rect(IntPoint(destinationRect.x() - in2->absolutePaintRect().x(),
338                                      destinationRect.y() - in2->absolutePaintRect().y()), destinationRect.size());
339         filterContext->drawImageBuffer(imageBuffer2,
340             FloatRect(destinationPoint, imageBuffer2->size()), &source2Rect);
341         filterContext->drawImageBuffer(imageBuffer,
342             FloatRect(destinationPoint, imageBuffer->size()), &sourceRect, CompositeSourceIn);
343         break;
344     }
345     case FECOMPOSITE_OPERATOR_OUT:
346         filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()));
347         filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()), 0, CompositeDestinationOut);
348         break;
349     case FECOMPOSITE_OPERATOR_ATOP:
350         filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()));
351         filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), 0, CompositeSourceAtop);
352         break;
353     case FECOMPOSITE_OPERATOR_XOR:
354         filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()));
355         filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), 0, CompositeXOR);
356         break;
357     default:
358         break;
359     }
360 }
361
362 SkXfermode::Mode toXfermode(WebCore::CompositeOperationType mode)
363 {
364     switch (mode) {
365     case WebCore::FECOMPOSITE_OPERATOR_OVER:
366         return SkXfermode::kSrcOver_Mode;
367     case WebCore::FECOMPOSITE_OPERATOR_IN:
368         return SkXfermode::kSrcIn_Mode;
369     case WebCore::FECOMPOSITE_OPERATOR_OUT:
370         return SkXfermode::kSrcOut_Mode;
371     case WebCore::FECOMPOSITE_OPERATOR_ATOP:
372         return SkXfermode::kSrcATop_Mode;
373     case WebCore::FECOMPOSITE_OPERATOR_XOR:
374         return SkXfermode::kXor_Mode;
375     default:
376         ASSERT_NOT_REACHED();
377         return SkXfermode::kSrcOver_Mode;
378     }
379 }
380
381 PassRefPtr<SkImageFilter> FEComposite::createImageFilter(SkiaImageFilterBuilder* builder)
382 {
383     return createImageFilterInternal(builder, true);
384 }
385
386 PassRefPtr<SkImageFilter> FEComposite::createImageFilterWithoutValidation(SkiaImageFilterBuilder* builder)
387 {
388     return createImageFilterInternal(builder, false);
389 }
390
391 PassRefPtr<SkImageFilter> FEComposite::createImageFilterInternal(SkiaImageFilterBuilder* builder, bool requiresPMColorValidation)
392 {
393     RefPtr<SkImageFilter> foreground(builder->build(inputEffect(0), operatingColorSpace(), !mayProduceInvalidPreMultipliedPixels()));
394     RefPtr<SkImageFilter> background(builder->build(inputEffect(1), operatingColorSpace(), !mayProduceInvalidPreMultipliedPixels()));
395     SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset());
396     RefPtr<SkXfermode> mode;
397     if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC)
398         mode = adoptRef(SkArithmeticMode::Create(SkFloatToScalar(m_k1), SkFloatToScalar(m_k2), SkFloatToScalar(m_k3), SkFloatToScalar(m_k4), requiresPMColorValidation));
399     else
400         mode = adoptRef(SkXfermode::Create(toXfermode(m_type)));
401     return adoptRef(SkXfermodeImageFilter::Create(mode.get(), background.get(), foreground.get(), &cropRect));
402 }
403
404 static TextStream& operator<<(TextStream& ts, const CompositeOperationType& type)
405 {
406     switch (type) {
407     case FECOMPOSITE_OPERATOR_UNKNOWN:
408         ts << "UNKNOWN";
409         break;
410     case FECOMPOSITE_OPERATOR_OVER:
411         ts << "OVER";
412         break;
413     case FECOMPOSITE_OPERATOR_IN:
414         ts << "IN";
415         break;
416     case FECOMPOSITE_OPERATOR_OUT:
417         ts << "OUT";
418         break;
419     case FECOMPOSITE_OPERATOR_ATOP:
420         ts << "ATOP";
421         break;
422     case FECOMPOSITE_OPERATOR_XOR:
423         ts << "XOR";
424         break;
425     case FECOMPOSITE_OPERATOR_ARITHMETIC:
426         ts << "ARITHMETIC";
427         break;
428     }
429     return ts;
430 }
431
432 TextStream& FEComposite::externalRepresentation(TextStream& ts, int indent) const
433 {
434     writeIndent(ts, indent);
435     ts << "[feComposite";
436     FilterEffect::externalRepresentation(ts);
437     ts << " operation=\"" << m_type << "\"";
438     if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC)
439         ts << " k1=\"" << m_k1 << "\" k2=\"" << m_k2 << "\" k3=\"" << m_k3 << "\" k4=\"" << m_k4 << "\"";
440     ts << "]\n";
441     inputEffect(0)->externalRepresentation(ts, indent + 1);
442     inputEffect(1)->externalRepresentation(ts, indent + 1);
443     return ts;
444 }
445
446 } // namespace WebCore