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) 2012 Nokia Corporation and/or its subsidiary(-ies)
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#include "platform/graphics/filters/FEBlend.h"
27
28#include "SkBitmapSource.h"
29#include "SkXfermodeImageFilter.h"
30#include "platform/graphics/GraphicsContext.h"
31#include "platform/graphics/cpu/arm/filters/FEBlendNEON.h"
32#include "platform/graphics/filters/SkiaImageFilterBuilder.h"
33#include "platform/graphics/skia/NativeImageSkia.h"
34#include "platform/graphics/skia/SkiaUtils.h"
35#include "platform/text/TextStream.h"
36#include "wtf/Uint8ClampedArray.h"
37
38typedef unsigned char (*BlendType)(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB);
39
40namespace blink {
41
42FEBlend::FEBlend(Filter* filter, WebBlendMode mode)
43    : FilterEffect(filter)
44    , m_mode(mode)
45{
46}
47
48PassRefPtr<FEBlend> FEBlend::create(Filter* filter, WebBlendMode mode)
49{
50    return adoptRef(new FEBlend(filter, mode));
51}
52
53WebBlendMode FEBlend::blendMode() const
54{
55    return m_mode;
56}
57
58bool FEBlend::setBlendMode(WebBlendMode mode)
59{
60    if (m_mode == mode)
61        return false;
62    m_mode = mode;
63    return true;
64}
65
66#if HAVE(ARM_NEON_INTRINSICS)
67bool FEBlend::applySoftwareNEON()
68{
69    if (m_mode != WebBlendModeNormal
70        && m_mode != WebBlendModeMultiply
71        && m_mode != WebBlendModeScreen
72        && m_mode != WebBlendModeDarken
73        && m_mode != WebBlendModeLighten)
74        return false;
75
76    Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult();
77    if (!dstPixelArray)
78        return true;
79
80    FilterEffect* in = inputEffect(0);
81    FilterEffect* in2 = inputEffect(1);
82
83    IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
84    RefPtr<Uint8ClampedArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect);
85
86    IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
87    RefPtr<Uint8ClampedArray> srcPixelArrayB = in2->asPremultipliedImage(effectBDrawingRect);
88
89    unsigned pixelArrayLength = srcPixelArrayA->length();
90    ASSERT(pixelArrayLength == srcPixelArrayB->length());
91
92    if (pixelArrayLength >= 8) {
93        platformApplyNEON(srcPixelArrayA->data(), srcPixelArrayB->data(), dstPixelArray->data(), pixelArrayLength);
94    } else {
95        // If there is just one pixel we expand it to two.
96        ASSERT(pixelArrayLength > 0);
97        uint32_t sourceA[2] = {0, 0};
98        uint32_t sourceBAndDest[2] = {0, 0};
99
100        sourceA[0] = reinterpret_cast<uint32_t*>(srcPixelArrayA->data())[0];
101        sourceBAndDest[0] = reinterpret_cast<uint32_t*>(srcPixelArrayB->data())[0];
102        platformApplyNEON(reinterpret_cast<uint8_t*>(sourceA), reinterpret_cast<uint8_t*>(sourceBAndDest), reinterpret_cast<uint8_t*>(sourceBAndDest), 8);
103        reinterpret_cast<uint32_t*>(dstPixelArray->data())[0] = sourceBAndDest[0];
104    }
105    return true;
106}
107#endif
108
109void FEBlend::applySoftware()
110{
111#if HAVE(ARM_NEON_INTRINSICS)
112    if (applySoftwareNEON())
113        return;
114#endif
115
116    FilterEffect* in = inputEffect(0);
117    FilterEffect* in2 = inputEffect(1);
118
119    ImageBuffer* resultImage = createImageBufferResult();
120    if (!resultImage)
121        return;
122    GraphicsContext* filterContext = resultImage->context();
123
124    ImageBuffer* imageBuffer = in->asImageBuffer();
125    ImageBuffer* imageBuffer2 = in2->asImageBuffer();
126    ASSERT(imageBuffer);
127    ASSERT(imageBuffer2);
128
129    filterContext->drawImageBuffer(imageBuffer2, drawingRegionOfInputImage(in2->absolutePaintRect()));
130    filterContext->drawImageBuffer(imageBuffer, drawingRegionOfInputImage(in->absolutePaintRect()), 0, CompositeSourceOver, m_mode);
131}
132
133PassRefPtr<SkImageFilter> FEBlend::createImageFilter(SkiaImageFilterBuilder* builder)
134{
135    RefPtr<SkImageFilter> foreground(builder->build(inputEffect(0), operatingColorSpace()));
136    RefPtr<SkImageFilter> background(builder->build(inputEffect(1), operatingColorSpace()));
137    RefPtr<SkXfermode> mode(adoptRef(SkXfermode::Create(WebCoreCompositeToSkiaComposite(CompositeSourceOver, m_mode))));
138    SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset());
139    return adoptRef(SkXfermodeImageFilter::Create(mode.get(), background.get(), foreground.get(), &cropRect));
140}
141
142TextStream& FEBlend::externalRepresentation(TextStream& ts, int indent) const
143{
144    writeIndent(ts, indent);
145    ts << "[feBlend";
146    FilterEffect::externalRepresentation(ts);
147    ts << " mode=\"" << (m_mode == WebBlendModeNormal ? "normal" : compositeOperatorName(CompositeSourceOver, m_mode)) << "\"]\n";
148    inputEffect(0)->externalRepresentation(ts, indent + 1);
149    inputEffect(1)->externalRepresentation(ts, indent + 1);
150    return ts;
151}
152
153} // namespace blink
154