1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/thebes/gfxBlur.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,180 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "gfxBlur.h" 1.10 +#include "gfxContext.h" 1.11 +#include "gfxImageSurface.h" 1.12 +#include "gfxPlatform.h" 1.13 + 1.14 +#include "mozilla/gfx/Blur.h" 1.15 +#include "mozilla/gfx/2D.h" 1.16 + 1.17 +using namespace mozilla::gfx; 1.18 + 1.19 +gfxAlphaBoxBlur::gfxAlphaBoxBlur() 1.20 + : mBlur(nullptr) 1.21 +{ 1.22 +} 1.23 + 1.24 +gfxAlphaBoxBlur::~gfxAlphaBoxBlur() 1.25 +{ 1.26 + mContext = nullptr; 1.27 + delete mBlur; 1.28 +} 1.29 + 1.30 +gfxContext* 1.31 +gfxAlphaBoxBlur::Init(const gfxRect& aRect, 1.32 + const gfxIntSize& aSpreadRadius, 1.33 + const gfxIntSize& aBlurRadius, 1.34 + const gfxRect* aDirtyRect, 1.35 + const gfxRect* aSkipRect) 1.36 +{ 1.37 + mozilla::gfx::Rect rect(Float(aRect.x), Float(aRect.y), 1.38 + Float(aRect.width), Float(aRect.height)); 1.39 + IntSize spreadRadius(aSpreadRadius.width, aSpreadRadius.height); 1.40 + IntSize blurRadius(aBlurRadius.width, aBlurRadius.height); 1.41 + nsAutoPtr<mozilla::gfx::Rect> dirtyRect; 1.42 + if (aDirtyRect) { 1.43 + dirtyRect = new mozilla::gfx::Rect(Float(aDirtyRect->x), 1.44 + Float(aDirtyRect->y), 1.45 + Float(aDirtyRect->width), 1.46 + Float(aDirtyRect->height)); 1.47 + } 1.48 + nsAutoPtr<mozilla::gfx::Rect> skipRect; 1.49 + if (aSkipRect) { 1.50 + skipRect = new mozilla::gfx::Rect(Float(aSkipRect->x), 1.51 + Float(aSkipRect->y), 1.52 + Float(aSkipRect->width), 1.53 + Float(aSkipRect->height)); 1.54 + } 1.55 + 1.56 + mBlur = new AlphaBoxBlur(rect, spreadRadius, blurRadius, dirtyRect, skipRect); 1.57 + size_t blurDataSize = mBlur->GetSurfaceAllocationSize(); 1.58 + if (blurDataSize == 0) 1.59 + return nullptr; 1.60 + 1.61 + IntSize size = mBlur->GetSize(); 1.62 + 1.63 + // Make an alpha-only surface to draw on. We will play with the data after 1.64 + // everything is drawn to create a blur effect. 1.65 + mData = new (std::nothrow) unsigned char[blurDataSize]; 1.66 + if (!mData) { 1.67 + return nullptr; 1.68 + } 1.69 + memset(mData, 0, blurDataSize); 1.70 + 1.71 + mozilla::RefPtr<DrawTarget> dt = 1.72 + gfxPlatform::GetPlatform()->CreateDrawTargetForData(mData, size, 1.73 + mBlur->GetStride(), 1.74 + SurfaceFormat::A8); 1.75 + if (!dt) { 1.76 + nsRefPtr<gfxImageSurface> image = 1.77 + new gfxImageSurface(mData, 1.78 + gfxIntSize(size.width, size.height), 1.79 + mBlur->GetStride(), 1.80 + gfxImageFormat::A8); 1.81 + dt = Factory::CreateDrawTargetForCairoSurface(image->CairoSurface(), size); 1.82 + if (!dt) { 1.83 + return nullptr; 1.84 + } 1.85 + } 1.86 + 1.87 + IntRect irect = mBlur->GetRect(); 1.88 + gfxPoint topleft(irect.TopLeft().x, irect.TopLeft().y); 1.89 + 1.90 + mContext = new gfxContext(dt); 1.91 + mContext->Translate(-topleft); 1.92 + 1.93 + return mContext; 1.94 +} 1.95 + 1.96 +void 1.97 +gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx) 1.98 +{ 1.99 + if (!mContext) 1.100 + return; 1.101 + 1.102 + mBlur->Blur(mData); 1.103 + 1.104 + mozilla::gfx::Rect* dirtyRect = mBlur->GetDirtyRect(); 1.105 + 1.106 + DrawTarget *dest = aDestinationCtx->GetDrawTarget(); 1.107 + if (!dest) { 1.108 + NS_WARNING("Blurring not supported for Thebes contexts!"); 1.109 + return; 1.110 + } 1.111 + 1.112 + mozilla::RefPtr<SourceSurface> mask 1.113 + = dest->CreateSourceSurfaceFromData(mData, 1.114 + mBlur->GetSize(), 1.115 + mBlur->GetStride(), 1.116 + SurfaceFormat::A8); 1.117 + if (!mask) { 1.118 + NS_ERROR("Failed to create mask!"); 1.119 + return; 1.120 + } 1.121 + 1.122 + nsRefPtr<gfxPattern> thebesPat = aDestinationCtx->GetPattern(); 1.123 + Pattern* pat = thebesPat->GetPattern(dest, nullptr); 1.124 + 1.125 + Matrix oldTransform = dest->GetTransform(); 1.126 + Matrix newTransform = oldTransform; 1.127 + newTransform.Translate(mBlur->GetRect().x, mBlur->GetRect().y); 1.128 + 1.129 + // Avoid a semi-expensive clip operation if we can, otherwise 1.130 + // clip to the dirty rect 1.131 + if (dirtyRect) { 1.132 + dest->PushClipRect(*dirtyRect); 1.133 + } 1.134 + 1.135 + dest->SetTransform(newTransform); 1.136 + dest->MaskSurface(*pat, mask, Point(0, 0)); 1.137 + dest->SetTransform(oldTransform); 1.138 + 1.139 + if (dirtyRect) { 1.140 + dest->PopClip(); 1.141 + } 1.142 +} 1.143 + 1.144 +gfxIntSize gfxAlphaBoxBlur::CalculateBlurRadius(const gfxPoint& aStd) 1.145 +{ 1.146 + mozilla::gfx::Point std(Float(aStd.x), Float(aStd.y)); 1.147 + IntSize size = AlphaBoxBlur::CalculateBlurRadius(std); 1.148 + return gfxIntSize(size.width, size.height); 1.149 +} 1.150 + 1.151 +/* static */ void 1.152 +gfxAlphaBoxBlur::BlurRectangle(gfxContext *aDestinationCtx, 1.153 + const gfxRect& aRect, 1.154 + gfxCornerSizes* aCornerRadii, 1.155 + const gfxPoint& aBlurStdDev, 1.156 + const gfxRGBA& aShadowColor, 1.157 + const gfxRect& aDirtyRect, 1.158 + const gfxRect& aSkipRect) 1.159 +{ 1.160 + gfxIntSize blurRadius = CalculateBlurRadius(aBlurStdDev); 1.161 + 1.162 + // Create the temporary surface for blurring 1.163 + gfxAlphaBoxBlur blur; 1.164 + gfxContext *dest = blur.Init(aRect, gfxIntSize(), blurRadius, &aDirtyRect, &aSkipRect); 1.165 + 1.166 + if (!dest) { 1.167 + return; 1.168 + } 1.169 + 1.170 + gfxRect shadowGfxRect = aRect; 1.171 + shadowGfxRect.Round(); 1.172 + 1.173 + dest->NewPath(); 1.174 + if (aCornerRadii) { 1.175 + dest->RoundedRectangle(shadowGfxRect, *aCornerRadii); 1.176 + } else { 1.177 + dest->Rectangle(shadowGfxRect); 1.178 + } 1.179 + dest->Fill(); 1.180 + 1.181 + aDestinationCtx->SetColor(aShadowColor); 1.182 + blur.Paint(aDestinationCtx); 1.183 +}