Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "gfxBlur.h"
7 #include "gfxContext.h"
8 #include "gfxImageSurface.h"
9 #include "gfxPlatform.h"
11 #include "mozilla/gfx/Blur.h"
12 #include "mozilla/gfx/2D.h"
14 using namespace mozilla::gfx;
16 gfxAlphaBoxBlur::gfxAlphaBoxBlur()
17 : mBlur(nullptr)
18 {
19 }
21 gfxAlphaBoxBlur::~gfxAlphaBoxBlur()
22 {
23 mContext = nullptr;
24 delete mBlur;
25 }
27 gfxContext*
28 gfxAlphaBoxBlur::Init(const gfxRect& aRect,
29 const gfxIntSize& aSpreadRadius,
30 const gfxIntSize& aBlurRadius,
31 const gfxRect* aDirtyRect,
32 const gfxRect* aSkipRect)
33 {
34 mozilla::gfx::Rect rect(Float(aRect.x), Float(aRect.y),
35 Float(aRect.width), Float(aRect.height));
36 IntSize spreadRadius(aSpreadRadius.width, aSpreadRadius.height);
37 IntSize blurRadius(aBlurRadius.width, aBlurRadius.height);
38 nsAutoPtr<mozilla::gfx::Rect> dirtyRect;
39 if (aDirtyRect) {
40 dirtyRect = new mozilla::gfx::Rect(Float(aDirtyRect->x),
41 Float(aDirtyRect->y),
42 Float(aDirtyRect->width),
43 Float(aDirtyRect->height));
44 }
45 nsAutoPtr<mozilla::gfx::Rect> skipRect;
46 if (aSkipRect) {
47 skipRect = new mozilla::gfx::Rect(Float(aSkipRect->x),
48 Float(aSkipRect->y),
49 Float(aSkipRect->width),
50 Float(aSkipRect->height));
51 }
53 mBlur = new AlphaBoxBlur(rect, spreadRadius, blurRadius, dirtyRect, skipRect);
54 size_t blurDataSize = mBlur->GetSurfaceAllocationSize();
55 if (blurDataSize == 0)
56 return nullptr;
58 IntSize size = mBlur->GetSize();
60 // Make an alpha-only surface to draw on. We will play with the data after
61 // everything is drawn to create a blur effect.
62 mData = new (std::nothrow) unsigned char[blurDataSize];
63 if (!mData) {
64 return nullptr;
65 }
66 memset(mData, 0, blurDataSize);
68 mozilla::RefPtr<DrawTarget> dt =
69 gfxPlatform::GetPlatform()->CreateDrawTargetForData(mData, size,
70 mBlur->GetStride(),
71 SurfaceFormat::A8);
72 if (!dt) {
73 nsRefPtr<gfxImageSurface> image =
74 new gfxImageSurface(mData,
75 gfxIntSize(size.width, size.height),
76 mBlur->GetStride(),
77 gfxImageFormat::A8);
78 dt = Factory::CreateDrawTargetForCairoSurface(image->CairoSurface(), size);
79 if (!dt) {
80 return nullptr;
81 }
82 }
84 IntRect irect = mBlur->GetRect();
85 gfxPoint topleft(irect.TopLeft().x, irect.TopLeft().y);
87 mContext = new gfxContext(dt);
88 mContext->Translate(-topleft);
90 return mContext;
91 }
93 void
94 gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx)
95 {
96 if (!mContext)
97 return;
99 mBlur->Blur(mData);
101 mozilla::gfx::Rect* dirtyRect = mBlur->GetDirtyRect();
103 DrawTarget *dest = aDestinationCtx->GetDrawTarget();
104 if (!dest) {
105 NS_WARNING("Blurring not supported for Thebes contexts!");
106 return;
107 }
109 mozilla::RefPtr<SourceSurface> mask
110 = dest->CreateSourceSurfaceFromData(mData,
111 mBlur->GetSize(),
112 mBlur->GetStride(),
113 SurfaceFormat::A8);
114 if (!mask) {
115 NS_ERROR("Failed to create mask!");
116 return;
117 }
119 nsRefPtr<gfxPattern> thebesPat = aDestinationCtx->GetPattern();
120 Pattern* pat = thebesPat->GetPattern(dest, nullptr);
122 Matrix oldTransform = dest->GetTransform();
123 Matrix newTransform = oldTransform;
124 newTransform.Translate(mBlur->GetRect().x, mBlur->GetRect().y);
126 // Avoid a semi-expensive clip operation if we can, otherwise
127 // clip to the dirty rect
128 if (dirtyRect) {
129 dest->PushClipRect(*dirtyRect);
130 }
132 dest->SetTransform(newTransform);
133 dest->MaskSurface(*pat, mask, Point(0, 0));
134 dest->SetTransform(oldTransform);
136 if (dirtyRect) {
137 dest->PopClip();
138 }
139 }
141 gfxIntSize gfxAlphaBoxBlur::CalculateBlurRadius(const gfxPoint& aStd)
142 {
143 mozilla::gfx::Point std(Float(aStd.x), Float(aStd.y));
144 IntSize size = AlphaBoxBlur::CalculateBlurRadius(std);
145 return gfxIntSize(size.width, size.height);
146 }
148 /* static */ void
149 gfxAlphaBoxBlur::BlurRectangle(gfxContext *aDestinationCtx,
150 const gfxRect& aRect,
151 gfxCornerSizes* aCornerRadii,
152 const gfxPoint& aBlurStdDev,
153 const gfxRGBA& aShadowColor,
154 const gfxRect& aDirtyRect,
155 const gfxRect& aSkipRect)
156 {
157 gfxIntSize blurRadius = CalculateBlurRadius(aBlurStdDev);
159 // Create the temporary surface for blurring
160 gfxAlphaBoxBlur blur;
161 gfxContext *dest = blur.Init(aRect, gfxIntSize(), blurRadius, &aDirtyRect, &aSkipRect);
163 if (!dest) {
164 return;
165 }
167 gfxRect shadowGfxRect = aRect;
168 shadowGfxRect.Round();
170 dest->NewPath();
171 if (aCornerRadii) {
172 dest->RoundedRectangle(shadowGfxRect, *aCornerRadii);
173 } else {
174 dest->Rectangle(shadowGfxRect);
175 }
176 dest->Fill();
178 aDestinationCtx->SetColor(aShadowColor);
179 blur.Paint(aDestinationCtx);
180 }