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 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public License 19 * along with this library; see the file COPYING.LIB. If not, write to 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA. 22 */ 23 24#include "config.h" 25 26#if ENABLE(FILTERS) 27#include "FEBlend.h" 28#include "FEBlendNEON.h" 29 30#include "Filter.h" 31#include "FloatPoint.h" 32#include "GraphicsContext.h" 33#include "RenderTreeAsText.h" 34#include "TextStream.h" 35 36#include <wtf/Uint8ClampedArray.h> 37 38typedef unsigned char (*BlendType)(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB); 39 40namespace WebCore { 41 42FEBlend::FEBlend(Filter* filter, BlendModeType mode) 43 : FilterEffect(filter) 44 , m_mode(mode) 45{ 46} 47 48PassRefPtr<FEBlend> FEBlend::create(Filter* filter, BlendModeType mode) 49{ 50 return adoptRef(new FEBlend(filter, mode)); 51} 52 53BlendModeType FEBlend::blendMode() const 54{ 55 return m_mode; 56} 57 58bool FEBlend::setBlendMode(BlendModeType mode) 59{ 60 if (m_mode == mode) 61 return false; 62 m_mode = mode; 63 return true; 64} 65 66inline unsigned char feBlendNormal(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char) 67{ 68 return fastDivideBy255((255 - alphaA) * colorB + colorA * 255); 69} 70 71inline unsigned char feBlendMultiply(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) 72{ 73 return fastDivideBy255((255 - alphaA) * colorB + (255 - alphaB + colorB) * colorA); 74} 75 76inline unsigned char feBlendScreen(unsigned char colorA, unsigned char colorB, unsigned char, unsigned char) 77{ 78 return fastDivideBy255((colorB + colorA) * 255 - colorA * colorB); 79} 80 81inline unsigned char feBlendDarken(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) 82{ 83 return fastDivideBy255(std::min((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)); 84} 85 86inline unsigned char feBlendLighten(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) 87{ 88 return fastDivideBy255(std::max((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)); 89} 90 91inline unsigned char feBlendUnknown(unsigned char, unsigned char, unsigned char, unsigned char) 92{ 93 return 0; 94} 95 96template<BlendType BlendFunction> 97static void platformApply(unsigned char* sourcePixelA, unsigned char* sourcePixelB, 98 unsigned char* destinationPixel, unsigned pixelArrayLength) 99{ 100 unsigned len = pixelArrayLength / 4; 101 for (unsigned pixelOffset = 0; pixelOffset < len; pixelOffset++) { 102 unsigned char alphaA = sourcePixelA[3]; 103 unsigned char alphaB = sourcePixelB[3]; 104 destinationPixel[0] = BlendFunction(sourcePixelA[0], sourcePixelB[0], alphaA, alphaB); 105 destinationPixel[1] = BlendFunction(sourcePixelA[1], sourcePixelB[1], alphaA, alphaB); 106 destinationPixel[2] = BlendFunction(sourcePixelA[2], sourcePixelB[2], alphaA, alphaB); 107 destinationPixel[3] = 255 - fastDivideBy255((255 - alphaA) * (255 - alphaB)); 108 sourcePixelA += 4; 109 sourcePixelB += 4; 110 destinationPixel += 4; 111 } 112} 113 114void FEBlend::platformApplyGeneric(unsigned char* sourcePixelA, unsigned char* sourcePixelB, 115 unsigned char* destinationPixel, unsigned pixelArrayLength) 116{ 117 switch (m_mode) { 118 case FEBLEND_MODE_NORMAL: 119 platformApply<feBlendNormal>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength); 120 break; 121 case FEBLEND_MODE_MULTIPLY: 122 platformApply<feBlendMultiply>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength); 123 break; 124 case FEBLEND_MODE_SCREEN: 125 platformApply<feBlendScreen>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength); 126 break; 127 case FEBLEND_MODE_DARKEN: 128 platformApply<feBlendDarken>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength); 129 break; 130 case FEBLEND_MODE_LIGHTEN: 131 platformApply<feBlendLighten>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength); 132 break; 133 case FEBLEND_MODE_UNKNOWN: 134 platformApply<feBlendUnknown>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength); 135 break; 136 } 137} 138 139void FEBlend::platformApplySoftware() 140{ 141 FilterEffect* in = inputEffect(0); 142 FilterEffect* in2 = inputEffect(1); 143 144 ASSERT(m_mode > FEBLEND_MODE_UNKNOWN); 145 ASSERT(m_mode <= FEBLEND_MODE_LIGHTEN); 146 147 Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult(); 148 if (!dstPixelArray) 149 return; 150 151 IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); 152 RefPtr<Uint8ClampedArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect); 153 154 IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); 155 RefPtr<Uint8ClampedArray> srcPixelArrayB = in2->asPremultipliedImage(effectBDrawingRect); 156 157 unsigned pixelArrayLength = srcPixelArrayA->length(); 158 ASSERT(pixelArrayLength == srcPixelArrayB->length()); 159 160#if HAVE(ARM_NEON_INTRINSICS) 161 if (pixelArrayLength >= 8) 162 platformApplyNEON(srcPixelArrayA->data(), srcPixelArrayB->data(), dstPixelArray->data(), pixelArrayLength); 163 else { // If there is just one pixel we expand it to two. 164 ASSERT(pixelArrayLength > 0); 165 uint32_t sourceA[2] = {0, 0}; 166 uint32_t sourceBAndDest[2] = {0, 0}; 167 168 sourceA[0] = reinterpret_cast<uint32_t*>(srcPixelArrayA->data())[0]; 169 sourceBAndDest[0] = reinterpret_cast<uint32_t*>(srcPixelArrayB->data())[0]; 170 platformApplyNEON(reinterpret_cast<uint8_t*>(sourceA), reinterpret_cast<uint8_t*>(sourceBAndDest), reinterpret_cast<uint8_t*>(sourceBAndDest), 8); 171 reinterpret_cast<uint32_t*>(dstPixelArray->data())[0] = sourceBAndDest[0]; 172 } 173#else 174 platformApplyGeneric(srcPixelArrayA->data(), srcPixelArrayB->data(), dstPixelArray->data(), pixelArrayLength); 175#endif 176} 177 178void FEBlend::dump() 179{ 180} 181 182static TextStream& operator<<(TextStream& ts, const BlendModeType& type) 183{ 184 switch (type) { 185 case FEBLEND_MODE_UNKNOWN: 186 ts << "UNKNOWN"; 187 break; 188 case FEBLEND_MODE_NORMAL: 189 ts << "NORMAL"; 190 break; 191 case FEBLEND_MODE_MULTIPLY: 192 ts << "MULTIPLY"; 193 break; 194 case FEBLEND_MODE_SCREEN: 195 ts << "SCREEN"; 196 break; 197 case FEBLEND_MODE_DARKEN: 198 ts << "DARKEN"; 199 break; 200 case FEBLEND_MODE_LIGHTEN: 201 ts << "LIGHTEN"; 202 break; 203 } 204 return ts; 205} 206 207TextStream& FEBlend::externalRepresentation(TextStream& ts, int indent) const 208{ 209 writeIndent(ts, indent); 210 ts << "[feBlend"; 211 FilterEffect::externalRepresentation(ts); 212 ts << " mode=\"" << m_mode << "\"]\n"; 213 inputEffect(0)->externalRepresentation(ts, indent + 1); 214 inputEffect(1)->externalRepresentation(ts, indent + 1); 215 return ts; 216} 217 218} // namespace WebCore 219 220#endif // ENABLE(FILTERS) 221