gfx/thebes/gfxBlur.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial