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 #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/text/TextStream.h" 35 #include "wtf/Uint8ClampedArray.h" 36 37 typedef unsigned char (*BlendType)(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB); 38 39 namespace WebCore { 40 41 FEBlend::FEBlend(Filter* filter, BlendModeType mode) 42 : FilterEffect(filter) 43 , m_mode(mode) 44 { 45 } 46 47 PassRefPtr<FEBlend> FEBlend::create(Filter* filter, BlendModeType mode) 48 { 49 return adoptRef(new FEBlend(filter, mode)); 50 } 51 52 BlendModeType FEBlend::blendMode() const 53 { 54 return m_mode; 55 } 56 57 bool FEBlend::setBlendMode(BlendModeType mode) 58 { 59 if (m_mode == mode) 60 return false; 61 m_mode = mode; 62 return true; 63 } 64 65 static inline unsigned char fastDivideBy255(uint16_t value) 66 { 67 // This is an approximate algorithm for division by 255, but it gives accurate results for 16bit values. 68 uint16_t quotient = value >> 8; 69 uint16_t remainder = value - (quotient * 255) + 1; 70 return quotient + (remainder >> 8); 71 } 72 73 inline unsigned char feBlendNormal(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char) 74 { 75 return fastDivideBy255((255 - alphaA) * colorB + colorA * 255); 76 } 77 78 inline unsigned char feBlendMultiply(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) 79 { 80 return fastDivideBy255((255 - alphaA) * colorB + (255 - alphaB + colorB) * colorA); 81 } 82 83 inline unsigned char feBlendScreen(unsigned char colorA, unsigned char colorB, unsigned char, unsigned char) 84 { 85 return fastDivideBy255((colorB + colorA) * 255 - colorA * colorB); 86 } 87 88 inline unsigned char feBlendDarken(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) 89 { 90 return fastDivideBy255(std::min((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)); 91 } 92 93 inline unsigned char feBlendLighten(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) 94 { 95 return fastDivideBy255(std::max((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)); 96 } 97 98 inline unsigned char feBlendUnknown(unsigned char, unsigned char, unsigned char, unsigned char) 99 { 100 return 0; 101 } 102 103 template<BlendType BlendFunction> 104 static void platformApply(unsigned char* sourcePixelA, unsigned char* sourcePixelB, 105 unsigned char* destinationPixel, unsigned pixelArrayLength) 106 { 107 unsigned len = pixelArrayLength / 4; 108 for (unsigned pixelOffset = 0; pixelOffset < len; pixelOffset++) { 109 unsigned char alphaA = sourcePixelA[3]; 110 unsigned char alphaB = sourcePixelB[3]; 111 destinationPixel[0] = BlendFunction(sourcePixelA[0], sourcePixelB[0], alphaA, alphaB); 112 destinationPixel[1] = BlendFunction(sourcePixelA[1], sourcePixelB[1], alphaA, alphaB); 113 destinationPixel[2] = BlendFunction(sourcePixelA[2], sourcePixelB[2], alphaA, alphaB); 114 destinationPixel[3] = 255 - fastDivideBy255((255 - alphaA) * (255 - alphaB)); 115 sourcePixelA += 4; 116 sourcePixelB += 4; 117 destinationPixel += 4; 118 } 119 } 120 121 void FEBlend::platformApplyGeneric(unsigned char* sourcePixelA, unsigned char* sourcePixelB, 122 unsigned char* destinationPixel, unsigned pixelArrayLength) 123 { 124 switch (m_mode) { 125 case FEBLEND_MODE_NORMAL: 126 platformApply<feBlendNormal>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength); 127 break; 128 case FEBLEND_MODE_MULTIPLY: 129 platformApply<feBlendMultiply>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength); 130 break; 131 case FEBLEND_MODE_SCREEN: 132 platformApply<feBlendScreen>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength); 133 break; 134 case FEBLEND_MODE_DARKEN: 135 platformApply<feBlendDarken>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength); 136 break; 137 case FEBLEND_MODE_LIGHTEN: 138 platformApply<feBlendLighten>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength); 139 break; 140 case FEBLEND_MODE_UNKNOWN: 141 platformApply<feBlendUnknown>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength); 142 break; 143 } 144 } 145 146 void FEBlend::applySoftware() 147 { 148 FilterEffect* in = inputEffect(0); 149 FilterEffect* in2 = inputEffect(1); 150 151 ASSERT(m_mode > FEBLEND_MODE_UNKNOWN); 152 ASSERT(m_mode <= FEBLEND_MODE_LIGHTEN); 153 154 Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult(); 155 if (!dstPixelArray) 156 return; 157 158 IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); 159 RefPtr<Uint8ClampedArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect); 160 161 IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); 162 RefPtr<Uint8ClampedArray> srcPixelArrayB = in2->asPremultipliedImage(effectBDrawingRect); 163 164 unsigned pixelArrayLength = srcPixelArrayA->length(); 165 ASSERT(pixelArrayLength == srcPixelArrayB->length()); 166 167 #if HAVE(ARM_NEON_INTRINSICS) 168 if (pixelArrayLength >= 8) { 169 platformApplyNEON(srcPixelArrayA->data(), srcPixelArrayB->data(), dstPixelArray->data(), pixelArrayLength); 170 } 171 else { // If there is just one pixel we expand it to two. 172 ASSERT(pixelArrayLength > 0); 173 uint32_t sourceA[2] = {0, 0}; 174 uint32_t sourceBAndDest[2] = {0, 0}; 175 176 sourceA[0] = reinterpret_cast<uint32_t*>(srcPixelArrayA->data())[0]; 177 sourceBAndDest[0] = reinterpret_cast<uint32_t*>(srcPixelArrayB->data())[0]; 178 platformApplyNEON(reinterpret_cast<uint8_t*>(sourceA), reinterpret_cast<uint8_t*>(sourceBAndDest), reinterpret_cast<uint8_t*>(sourceBAndDest), 8); 179 reinterpret_cast<uint32_t*>(dstPixelArray->data())[0] = sourceBAndDest[0]; 180 } 181 #else 182 platformApplyGeneric(srcPixelArrayA->data(), srcPixelArrayB->data(), dstPixelArray->data(), pixelArrayLength); 183 #endif 184 } 185 186 static SkXfermode::Mode toSkiaMode(BlendModeType mode) 187 { 188 switch (mode) { 189 case FEBLEND_MODE_NORMAL: 190 return SkXfermode::kSrcOver_Mode; 191 case FEBLEND_MODE_MULTIPLY: 192 return SkXfermode::kMultiply_Mode; 193 case FEBLEND_MODE_SCREEN: 194 return SkXfermode::kScreen_Mode; 195 case FEBLEND_MODE_DARKEN: 196 return SkXfermode::kDarken_Mode; 197 case FEBLEND_MODE_LIGHTEN: 198 return SkXfermode::kLighten_Mode; 199 default: 200 return SkXfermode::kSrcOver_Mode; 201 } 202 } 203 204 PassRefPtr<SkImageFilter> FEBlend::createImageFilter(SkiaImageFilterBuilder* builder) 205 { 206 RefPtr<SkImageFilter> foreground(builder->build(inputEffect(0), operatingColorSpace())); 207 RefPtr<SkImageFilter> background(builder->build(inputEffect(1), operatingColorSpace())); 208 SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(toSkiaMode(m_mode))); 209 SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset()); 210 return adoptRef(SkXfermodeImageFilter::Create(mode, background.get(), foreground.get(), &cropRect)); 211 } 212 213 static TextStream& operator<<(TextStream& ts, const BlendModeType& type) 214 { 215 switch (type) { 216 case FEBLEND_MODE_UNKNOWN: 217 ts << "UNKNOWN"; 218 break; 219 case FEBLEND_MODE_NORMAL: 220 ts << "NORMAL"; 221 break; 222 case FEBLEND_MODE_MULTIPLY: 223 ts << "MULTIPLY"; 224 break; 225 case FEBLEND_MODE_SCREEN: 226 ts << "SCREEN"; 227 break; 228 case FEBLEND_MODE_DARKEN: 229 ts << "DARKEN"; 230 break; 231 case FEBLEND_MODE_LIGHTEN: 232 ts << "LIGHTEN"; 233 break; 234 } 235 return ts; 236 } 237 238 TextStream& FEBlend::externalRepresentation(TextStream& ts, int indent) const 239 { 240 writeIndent(ts, indent); 241 ts << "[feBlend"; 242 FilterEffect::externalRepresentation(ts); 243 ts << " mode=\"" << m_mode << "\"]\n"; 244 inputEffect(0)->externalRepresentation(ts, indent + 1); 245 inputEffect(1)->externalRepresentation(ts, indent + 1); 246 return ts; 247 } 248 249 } // namespace WebCore 250