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