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.
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.
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.
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.
27 #include "platform/graphics/filters/FEComposite.h"
29 #include "SkArithmeticMode.h"
30 #include "SkFlattenableBuffers.h"
31 #include "SkXfermodeImageFilter.h"
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"
39 #include "wtf/Uint8ClampedArray.h"
43 FEComposite::FEComposite(Filter* filter, const CompositeOperationType& type, float k1, float k2, float k3, float k4)
44 : FilterEffect(filter)
53 PassRefPtr<FEComposite> FEComposite::create(Filter* filter, const CompositeOperationType& type, float k1, float k2, float k3, float k4)
55 return adoptRef(new FEComposite(filter, type, k1, k2, k3, k4));
58 CompositeOperationType FEComposite::operation() const
63 bool FEComposite::setOperation(CompositeOperationType type)
71 float FEComposite::k1() const
76 bool FEComposite::setK1(float k1)
84 float FEComposite::k2() const
89 bool FEComposite::setK2(float k2)
97 float FEComposite::k3() const
102 bool FEComposite::setK3(float k3)
110 float FEComposite::k4() const
115 bool FEComposite::setK4(float k4)
123 void FEComposite::correctFilterResultIfNeeded()
125 if (m_type != FECOMPOSITE_OPERATOR_ARITHMETIC)
128 forceValidPreMultipliedPixels();
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)
138 scaledK1 = k1 / 255.0f;
140 scaledK4 = k4 * 255.0f;
142 while (--pixelArrayLength >= 0) {
143 unsigned char i1 = *source;
144 unsigned char i2 = *destination;
145 float result = k2 * i1 + k3 * i2;
147 result += scaledK1 * i1 * i2;
153 else if (result >= 255)
156 *destination = result;
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)
170 scaledK1 = k1 / 255.0f;
172 scaledK4 = k4 * 255.0f;
174 while (--pixelArrayLength >= 0) {
175 unsigned char i1 = *source;
176 unsigned char i2 = *destination;
177 float result = k2 * i1 + k3 * i2;
179 result += scaledK1 * i1 * i2;
183 *destination = result;
189 static inline void arithmeticSoftware(unsigned char* source, unsigned char* destination, int pixelArrayLength, float k1, float k2, float k3, float k4)
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)) {
196 computeArithmeticPixelsUnclamped<1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
198 computeArithmeticPixelsUnclamped<0, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
201 computeArithmeticPixelsUnclamped<1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
203 computeArithmeticPixelsUnclamped<0, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
210 computeArithmeticPixels<1, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
212 computeArithmeticPixels<0, 1>(source, destination, pixelArrayLength, k1, k2, k3, k4);
215 computeArithmeticPixels<1, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
217 computeArithmeticPixels<0, 0>(source, destination, pixelArrayLength, k1, k2, k3, k4);
221 inline void FEComposite::platformArithmeticSoftware(Uint8ClampedArray* source, Uint8ClampedArray* destination,
222 float k1, float k2, float k3, float k4)
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);
231 arithmeticSoftware(source->data(), destination->data(), length, k1, k2, k3, k4);
235 FloatRect FEComposite::determineAbsolutePaintRect(const FloatRect& originalRequestedRect)
237 FloatRect requestedRect = originalRequestedRect;
239 requestedRect.intersect(maxEffectRect());
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;
246 // No mapPaintRect required for FEComposite.
247 FloatRect input1Rect = inputEffect(1)->determineAbsolutePaintRect(requestedRect);
248 FloatRect affectedRect;
250 case FECOMPOSITE_OPERATOR_IN:
251 // 'in' has output only in the intersection of both inputs.
252 affectedRect = intersection(input1Rect, inputEffect(0)->determineAbsolutePaintRect(input1Rect));
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;
260 case FECOMPOSITE_OPERATOR_ARITHMETIC:
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;
270 // Input 0 does not appear where input 1 is not present.
271 FloatRect input0Rect = inputEffect(0)->determineAbsolutePaintRect(input1Rect);
273 affectedRect = input1Rect;
275 // Just k1 is positive. Use intersection.
276 affectedRect = intersection(input1Rect, input0Rect);
280 // else fall through to use union
282 // Take the union of both input effects.
283 affectedRect = unionRect(input1Rect, inputEffect(0)->determineAbsolutePaintRect(requestedRect));
287 affectedRect.intersect(requestedRect);
288 addAbsolutePaintRect(affectedRect);
292 void FEComposite::applySoftware()
294 FilterEffect* in = inputEffect(0);
295 FilterEffect* in2 = inputEffect(1);
297 if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) {
298 Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult();
302 IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
303 RefPtr<Uint8ClampedArray> srcPixelArray = in->asPremultipliedImage(effectADrawingRect);
305 IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
306 in2->copyPremultipliedImage(dstPixelArray, effectBDrawingRect);
308 platformArithmeticSoftware(srcPixelArray.get(), dstPixelArray, m_k1, m_k2, m_k3, m_k4);
312 ImageBuffer* resultImage = createImageBufferResult();
315 GraphicsContext* filterContext = resultImage->context();
317 ImageBuffer* imageBuffer = in->asImageBuffer();
318 ImageBuffer* imageBuffer2 = in2->asImageBuffer();
320 ASSERT(imageBuffer2);
323 case FECOMPOSITE_OPERATOR_OVER:
324 filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()));
325 filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()));
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())
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);
345 case FECOMPOSITE_OPERATOR_OUT:
346 filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()));
347 filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()), 0, CompositeDestinationOut);
349 case FECOMPOSITE_OPERATOR_ATOP:
350 filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()));
351 filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), 0, CompositeSourceAtop);
353 case FECOMPOSITE_OPERATOR_XOR:
354 filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()));
355 filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), 0, CompositeXOR);
362 SkXfermode::Mode toXfermode(WebCore::CompositeOperationType 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;
376 ASSERT_NOT_REACHED();
377 return SkXfermode::kSrcOver_Mode;
381 PassRefPtr<SkImageFilter> FEComposite::createImageFilter(SkiaImageFilterBuilder* builder)
383 return createImageFilterInternal(builder, true);
386 PassRefPtr<SkImageFilter> FEComposite::createImageFilterWithoutValidation(SkiaImageFilterBuilder* builder)
388 return createImageFilterInternal(builder, false);
391 PassRefPtr<SkImageFilter> FEComposite::createImageFilterInternal(SkiaImageFilterBuilder* builder, bool requiresPMColorValidation)
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));
400 mode = adoptRef(SkXfermode::Create(toXfermode(m_type)));
401 return adoptRef(SkXfermodeImageFilter::Create(mode.get(), background.get(), foreground.get(), &cropRect));
404 static TextStream& operator<<(TextStream& ts, const CompositeOperationType& type)
407 case FECOMPOSITE_OPERATOR_UNKNOWN:
410 case FECOMPOSITE_OPERATOR_OVER:
413 case FECOMPOSITE_OPERATOR_IN:
416 case FECOMPOSITE_OPERATOR_OUT:
419 case FECOMPOSITE_OPERATOR_ATOP:
422 case FECOMPOSITE_OPERATOR_XOR:
425 case FECOMPOSITE_OPERATOR_ARITHMETIC:
432 TextStream& FEComposite::externalRepresentation(TextStream& ts, int indent) const
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 << "\"";
441 inputEffect(0)->externalRepresentation(ts, indent + 1);
442 inputEffect(1)->externalRepresentation(ts, indent + 1);
446 } // namespace WebCore