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/graphics/skia/SkiaUtils.h" 35 #include "platform/text/TextStream.h" 36 #include "wtf/Uint8ClampedArray.h" 37 38 typedef unsigned char (*BlendType)(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB); 39 40 namespace blink { 41 42 FEBlend::FEBlend(Filter* filter, WebBlendMode mode) 43 : FilterEffect(filter) 44 , m_mode(mode) 45 { 46 } 47 48 PassRefPtr<FEBlend> FEBlend::create(Filter* filter, WebBlendMode mode) 49 { 50 return adoptRef(new FEBlend(filter, mode)); 51 } 52 53 WebBlendMode FEBlend::blendMode() const 54 { 55 return m_mode; 56 } 57 58 bool 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) 67 bool 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 109 void 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 133 PassRefPtr<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 142 TextStream& 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