Home | History | Annotate | Download | only in filters
      1 /*
      2  * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005 Rob Buis <buis (at) kde.org>
      4  * Copyright (C) 2005 Eric Seidel <eric (at) webkit.org>
      5  * Copyright (C) 2009 Dirk Schulze <krit (at) 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 
     27 #include "core/platform/graphics/cpu/arm/filters/FEBlendNEON.h"
     28 #include "core/platform/graphics/filters/FEBlend.h"
     29 
     30 #include "core/platform/graphics/GraphicsContext.h"
     31 #include "core/platform/graphics/filters/Filter.h"
     32 #include "core/platform/text/TextStream.h"
     33 #include "core/rendering/RenderTreeAsText.h"
     34 
     35 #include "wtf/Uint8ClampedArray.h"
     36 
     37 #include "SkBitmapSource.h"
     38 #include "SkXfermodeImageFilter.h"
     39 #include "core/platform/graphics/filters/SkiaImageFilterBuilder.h"
     40 #include "core/platform/graphics/skia/NativeImageSkia.h"
     41 
     42 typedef unsigned char (*BlendType)(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB);
     43 
     44 namespace WebCore {
     45 
     46 FEBlend::FEBlend(Filter* filter, BlendModeType mode)
     47     : FilterEffect(filter)
     48     , m_mode(mode)
     49 {
     50 }
     51 
     52 PassRefPtr<FEBlend> FEBlend::create(Filter* filter, BlendModeType mode)
     53 {
     54     return adoptRef(new FEBlend(filter, mode));
     55 }
     56 
     57 BlendModeType FEBlend::blendMode() const
     58 {
     59     return m_mode;
     60 }
     61 
     62 bool FEBlend::setBlendMode(BlendModeType mode)
     63 {
     64     if (m_mode == mode)
     65         return false;
     66     m_mode = mode;
     67     return true;
     68 }
     69 
     70 static inline unsigned char fastDivideBy255(uint16_t value)
     71 {
     72     // This is an approximate algorithm for division by 255, but it gives accurate results for 16bit values.
     73     uint16_t quotient = value >> 8;
     74     uint16_t remainder = value - (quotient * 255) + 1;
     75     return quotient + (remainder >> 8);
     76 }
     77 
     78 inline unsigned char feBlendNormal(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char)
     79 {
     80     return fastDivideBy255((255 - alphaA) * colorB + colorA * 255);
     81 }
     82 
     83 inline unsigned char feBlendMultiply(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
     84 {
     85     return fastDivideBy255((255 - alphaA) * colorB + (255 - alphaB + colorB) * colorA);
     86 }
     87 
     88 inline unsigned char feBlendScreen(unsigned char colorA, unsigned char colorB, unsigned char, unsigned char)
     89 {
     90     return fastDivideBy255((colorB + colorA) * 255 - colorA * colorB);
     91 }
     92 
     93 inline unsigned char feBlendDarken(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
     94 {
     95     return fastDivideBy255(std::min((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255));
     96 }
     97 
     98 inline unsigned char feBlendLighten(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
     99 {
    100     return fastDivideBy255(std::max((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255));
    101 }
    102 
    103 inline unsigned char feBlendUnknown(unsigned char, unsigned char, unsigned char, unsigned char)
    104 {
    105     return 0;
    106 }
    107 
    108 template<BlendType BlendFunction>
    109 static void platformApply(unsigned char* sourcePixelA, unsigned char* sourcePixelB,
    110                           unsigned char* destinationPixel, unsigned pixelArrayLength)
    111 {
    112     unsigned len = pixelArrayLength / 4;
    113     for (unsigned pixelOffset = 0; pixelOffset < len; pixelOffset++) {
    114         unsigned char alphaA = sourcePixelA[3];
    115         unsigned char alphaB = sourcePixelB[3];
    116         destinationPixel[0] = BlendFunction(sourcePixelA[0], sourcePixelB[0], alphaA, alphaB);
    117         destinationPixel[1] = BlendFunction(sourcePixelA[1], sourcePixelB[1], alphaA, alphaB);
    118         destinationPixel[2] = BlendFunction(sourcePixelA[2], sourcePixelB[2], alphaA, alphaB);
    119         destinationPixel[3] = 255 - fastDivideBy255((255 - alphaA) * (255 - alphaB));
    120         sourcePixelA += 4;
    121         sourcePixelB += 4;
    122         destinationPixel += 4;
    123     }
    124 }
    125 
    126 void FEBlend::platformApplyGeneric(unsigned char* sourcePixelA, unsigned char* sourcePixelB,
    127                                    unsigned char* destinationPixel, unsigned pixelArrayLength)
    128 {
    129     switch (m_mode) {
    130     case FEBLEND_MODE_NORMAL:
    131         platformApply<feBlendNormal>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength);
    132         break;
    133     case FEBLEND_MODE_MULTIPLY:
    134         platformApply<feBlendMultiply>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength);
    135         break;
    136     case FEBLEND_MODE_SCREEN:
    137         platformApply<feBlendScreen>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength);
    138         break;
    139     case FEBLEND_MODE_DARKEN:
    140         platformApply<feBlendDarken>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength);
    141         break;
    142     case FEBLEND_MODE_LIGHTEN:
    143         platformApply<feBlendLighten>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength);
    144         break;
    145     case FEBLEND_MODE_UNKNOWN:
    146         platformApply<feBlendUnknown>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength);
    147         break;
    148     }
    149 }
    150 
    151 void FEBlend::applySoftware()
    152 {
    153     FilterEffect* in = inputEffect(0);
    154     FilterEffect* in2 = inputEffect(1);
    155 
    156     ASSERT(m_mode > FEBLEND_MODE_UNKNOWN);
    157     ASSERT(m_mode <= FEBLEND_MODE_LIGHTEN);
    158 
    159     Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult();
    160     if (!dstPixelArray)
    161         return;
    162 
    163     IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
    164     RefPtr<Uint8ClampedArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect);
    165 
    166     IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
    167     RefPtr<Uint8ClampedArray> srcPixelArrayB = in2->asPremultipliedImage(effectBDrawingRect);
    168 
    169     unsigned pixelArrayLength = srcPixelArrayA->length();
    170     ASSERT(pixelArrayLength == srcPixelArrayB->length());
    171 
    172 #if HAVE(ARM_NEON_INTRINSICS)
    173     if (pixelArrayLength >= 8)
    174         platformApplyNEON(srcPixelArrayA->data(), srcPixelArrayB->data(), dstPixelArray->data(), pixelArrayLength);
    175     else { // If there is just one pixel we expand it to two.
    176         ASSERT(pixelArrayLength > 0);
    177         uint32_t sourceA[2] = {0, 0};
    178         uint32_t sourceBAndDest[2] = {0, 0};
    179 
    180         sourceA[0] = reinterpret_cast<uint32_t*>(srcPixelArrayA->data())[0];
    181         sourceBAndDest[0] = reinterpret_cast<uint32_t*>(srcPixelArrayB->data())[0];
    182         platformApplyNEON(reinterpret_cast<uint8_t*>(sourceA), reinterpret_cast<uint8_t*>(sourceBAndDest), reinterpret_cast<uint8_t*>(sourceBAndDest), 8);
    183         reinterpret_cast<uint32_t*>(dstPixelArray->data())[0] = sourceBAndDest[0];
    184     }
    185 #else
    186     platformApplyGeneric(srcPixelArrayA->data(), srcPixelArrayB->data(), dstPixelArray->data(), pixelArrayLength);
    187 #endif
    188 }
    189 
    190 static SkXfermode::Mode toSkiaMode(BlendModeType mode)
    191 {
    192     switch (mode) {
    193     case FEBLEND_MODE_NORMAL:
    194         return SkXfermode::kSrcOver_Mode;
    195     case FEBLEND_MODE_MULTIPLY:
    196         return SkXfermode::kMultiply_Mode;
    197     case FEBLEND_MODE_SCREEN:
    198         return SkXfermode::kScreen_Mode;
    199     case FEBLEND_MODE_DARKEN:
    200         return SkXfermode::kDarken_Mode;
    201     case FEBLEND_MODE_LIGHTEN:
    202         return SkXfermode::kLighten_Mode;
    203     default:
    204         return SkXfermode::kSrcOver_Mode;
    205     }
    206 }
    207 
    208 bool FEBlend::applySkia()
    209 {
    210     // For now, only use the skia implementation for accelerated rendering.
    211     if (filter()->renderingMode() != Accelerated)
    212         return false;
    213 
    214     FilterEffect* in = inputEffect(0);
    215     FilterEffect* in2 = inputEffect(1);
    216 
    217     if (!in || !in2)
    218         return false;
    219 
    220     ImageBuffer* resultImage = createImageBufferResult();
    221     if (!resultImage)
    222         return false;
    223 
    224     RefPtr<Image> foreground = in->asImageBuffer()->copyImage(DontCopyBackingStore);
    225     RefPtr<Image> background = in2->asImageBuffer()->copyImage(DontCopyBackingStore);
    226 
    227     RefPtr<NativeImageSkia> foregroundNativeImage = foreground->nativeImageForCurrentFrame();
    228     RefPtr<NativeImageSkia> backgroundNativeImage = background->nativeImageForCurrentFrame();
    229 
    230     if (!foregroundNativeImage || !backgroundNativeImage)
    231         return false;
    232 
    233     SkBitmap foregroundBitmap = foregroundNativeImage->bitmap();
    234     SkBitmap backgroundBitmap = backgroundNativeImage->bitmap();
    235 
    236     SkAutoTUnref<SkImageFilter> backgroundSource(new SkBitmapSource(backgroundBitmap));
    237     SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(toSkiaMode(m_mode)));
    238     SkAutoTUnref<SkImageFilter> blend(new SkXfermodeImageFilter(mode, backgroundSource));
    239     SkPaint paint;
    240     paint.setImageFilter(blend);
    241     resultImage->context()->drawBitmap(foregroundBitmap, 0, 0, &paint);
    242     return true;
    243 }
    244 
    245 PassRefPtr<SkImageFilter> FEBlend::createImageFilter(SkiaImageFilterBuilder* builder)
    246 {
    247     RefPtr<SkImageFilter> foreground(builder->build(inputEffect(0), operatingColorSpace()));
    248     RefPtr<SkImageFilter> background(builder->build(inputEffect(1), operatingColorSpace()));
    249     SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(toSkiaMode(m_mode)));
    250     return adoptRef(new SkXfermodeImageFilter(mode, background.get(), foreground.get()));
    251 }
    252 
    253 static TextStream& operator<<(TextStream& ts, const BlendModeType& type)
    254 {
    255     switch (type) {
    256     case FEBLEND_MODE_UNKNOWN:
    257         ts << "UNKNOWN";
    258         break;
    259     case FEBLEND_MODE_NORMAL:
    260         ts << "NORMAL";
    261         break;
    262     case FEBLEND_MODE_MULTIPLY:
    263         ts << "MULTIPLY";
    264         break;
    265     case FEBLEND_MODE_SCREEN:
    266         ts << "SCREEN";
    267         break;
    268     case FEBLEND_MODE_DARKEN:
    269         ts << "DARKEN";
    270         break;
    271     case FEBLEND_MODE_LIGHTEN:
    272         ts << "LIGHTEN";
    273         break;
    274     }
    275     return ts;
    276 }
    277 
    278 TextStream& FEBlend::externalRepresentation(TextStream& ts, int indent) const
    279 {
    280     writeIndent(ts, indent);
    281     ts << "[feBlend";
    282     FilterEffect::externalRepresentation(ts);
    283     ts << " mode=\"" << m_mode << "\"]\n";
    284     inputEffect(0)->externalRepresentation(ts, indent + 1);
    285     inputEffect(1)->externalRepresentation(ts, indent + 1);
    286     return ts;
    287 }
    288 
    289 } // namespace WebCore
    290