15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2005 Eric Seidel <eric@webkit.org> 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2010 Igalia, S.L. 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) Research In Motion Limited 2010. All rights reserved. 853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) * Copyright (C) 2013 Google Inc. All rights reserved. 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is free software; you can redistribute it and/or 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modify it under the terms of the GNU Library General Public 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * License as published by the Free Software Foundation; either 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * version 2 of the License, or (at your option) any later version. 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is distributed in the hope that it will be useful, 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * but WITHOUT ANY WARRANTY; without even the implied warranty of 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Library General Public License for more details. 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * You should have received a copy of the GNU Library General Public License 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * along with this library; see the file COPYING.LIB. If not, write to 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Boston, MA 02110-1301, USA. 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h" 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 28a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/graphics/filters/FEGaussianBlur.h" 295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 30a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/graphics/GraphicsContext.h" 31a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/graphics/cpu/arm/filters/FEGaussianBlurNEON.h" 32a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/graphics/filters/ParallelJobs.h" 33a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/graphics/filters/SkiaImageFilterBuilder.h" 341e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/text/TextStream.h" 357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/MathExtras.h" 367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/Uint8ClampedArray.h" 375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "SkBlurImageFilter.h" 3953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) 405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static inline float gaussianKernelFactor() 415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 42d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) return 3 / 4.f * sqrtf(twoPiFloat); 435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdochstatic const int gMaxKernelSize = 1000; 465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 47c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink { 485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FEGaussianBlur::FEGaussianBlur(Filter* filter, float x, float y) 505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : FilterEffect(filter) 515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_stdX(x) 525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_stdY(y) 535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)PassRefPtr<FEGaussianBlur> FEGaussianBlur::create(Filter* filter, float x, float y) 575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return adoptRef(new FEGaussianBlur(filter, x, y)); 595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float FEGaussianBlur::stdDeviationX() const 625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return m_stdX; 645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void FEGaussianBlur::setStdDeviationX(float x) 675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_stdX = x; 695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float FEGaussianBlur::stdDeviationY() const 725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return m_stdY; 745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void FEGaussianBlur::setStdDeviationY(float y) 775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_stdY = y; 795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8107a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben MurdochIntSize FEGaussianBlur::calculateUnscaledKernelSize(const FloatPoint& std) 825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 8307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch ASSERT(std.x() >= 0 && std.y() >= 0); 845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch IntSize kernelSize; 8607a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch // Limit the kernel size to 1000. A bigger radius won't make a big difference for the result image but 8707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch // inflates the absolute paint rect to much. This is compatible with Firefox' behavior. 8807a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch if (std.x()) { 897242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci int size = std::max<unsigned>(2, static_cast<unsigned>(floorf(std.x() * gaussianKernelFactor() + 0.5f))); 907242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci kernelSize.setWidth(std::min(size, gMaxKernelSize)); 915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch if (std.y()) { 947242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci int size = std::max<unsigned>(2, static_cast<unsigned>(floorf(std.y() * gaussianKernelFactor() + 0.5f))); 957242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci kernelSize.setHeight(std::min(size, gMaxKernelSize)); 965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9807a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch return kernelSize; 995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 10107a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben MurdochIntSize FEGaussianBlur::calculateKernelSize(Filter* filter, const FloatPoint& std) 1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 10307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch FloatPoint stdError(filter->applyHorizontalScale(std.x()), filter->applyVerticalScale(std.y())); 10402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 10507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch return calculateUnscaledKernelSize(stdError); 1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 108e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)FloatRect FEGaussianBlur::mapRect(const FloatRect& rect, bool) 109e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles){ 110e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles) FloatRect result = rect; 11107a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch IntSize kernelSize = calculateKernelSize(filter(), FloatPoint(m_stdX, m_stdY)); 112e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles) 113e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles) // We take the half kernel size and multiply it with three, because we run box blur three times. 11407a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch result.inflateX(3 * kernelSize.width() * 0.5f); 11507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch result.inflateY(3 * kernelSize.height() * 0.5f); 116e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles) return result; 117e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)} 118e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles) 11909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)FloatRect FEGaussianBlur::determineAbsolutePaintRect(const FloatRect& originalRequestedRect) 12009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){ 12109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) FloatRect requestedRect = originalRequestedRect; 12209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) if (clipsToBounds()) 12309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) requestedRect.intersect(maxEffectRect()); 12409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) 12509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) FilterEffect* input = inputEffect(0); 12609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) FloatRect inputRect = input->determineAbsolutePaintRect(mapRect(requestedRect, false)); 12709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) FloatRect outputRect = mapRect(inputRect, true); 12809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) outputRect.intersect(requestedRect); 12909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) addAbsolutePaintRect(outputRect); 13009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) 13109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) // Blur needs space for both input and output pixels in the paint area. 13209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) // Input is also clipped to subregion. 13309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) if (clipsToBounds()) 13409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) inputRect.intersect(maxEffectRect()); 13509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) addAbsolutePaintRect(inputRect); 13609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) return outputRect; 13709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)} 13809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) 13953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)void FEGaussianBlur::applySoftware() 1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 14153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) ImageBuffer* resultImage = createImageBufferResult(); 14253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) if (!resultImage) 14307a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch return; 14453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) 14553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) FilterEffect* in = inputEffect(0); 14653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) 14753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) IntRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); 14853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) 14953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) setIsAlphaImage(in->isAlphaImage()); 15053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) 15153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) float stdX = filter()->applyHorizontalScale(m_stdX); 15253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) float stdY = filter()->applyVerticalScale(m_stdY); 15353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) 15453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore); 15553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) 15653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) SkPaint paint; 15753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) GraphicsContext* dstContext = resultImage->context(); 15810f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch paint.setImageFilter(SkBlurImageFilter::Create(stdX, stdY))->unref(); 15953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) 16007a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch SkRect bounds = SkRect::MakeWH(absolutePaintRect().width(), absolutePaintRect().height()); 16107a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch dstContext->saveLayer(&bounds, &paint); 16253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) paint.setColor(0xFFFFFFFF); 1635267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) dstContext->drawImage(image.get(), drawingRegion.location(), CompositeCopy); 16453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) dstContext->restoreLayer(); 16553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)} 16653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) 1673c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben MurdochPassRefPtr<SkImageFilter> FEGaussianBlur::createImageFilter(SkiaImageFilterBuilder* builder) 1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1693c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch RefPtr<SkImageFilter> input(builder->build(inputEffect(0), operatingColorSpace())); 170591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch float stdX = filter()->applyHorizontalScale(m_stdX); 171591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch float stdY = filter()->applyVerticalScale(m_stdY); 1721e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) SkImageFilter::CropRect rect = getCropRect(builder->cropOffset()); 17310f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch return adoptRef(SkBlurImageFilter::Create(SkFloatToScalar(stdX), SkFloatToScalar(stdY), input.get(), &rect)); 1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TextStream& FEGaussianBlur::externalRepresentation(TextStream& ts, int indent) const 1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) writeIndent(ts, indent); 1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ts << "[feGaussianBlur"; 1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) FilterEffect::externalRepresentation(ts); 1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ts << " stdDeviation=\"" << m_stdX << ", " << m_stdY << "\"]\n"; 1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) inputEffect(0)->externalRepresentation(ts, indent + 1); 1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return ts; 1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 186c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)} // namespace blink 187