Back out Bug 685767 for leaking.
authorKyle Huey <khuey@kylehuey.com>
Thu, 17 Nov 2011 13:01:11 -0500
changeset 80431 b62e6ee5ba9b3031b72faf30587bc7a195166467
parent 80380 87640c3cac6defe30491defccdd12a7aa3e79f79
child 80446 1695164143492a4890c4d63af48b70f3c25f2d1e
child 80552 677c4e284a9d614c08e7470f94db7bf63f9a127d
child 80598 796e27ab00cd8721b3669836db751c419a1a5631
child 81951 b92c1975156dcf27617f7badc7dbfcc5a41f8fa5
push id3447
push userjdrew@mozilla.com
push dateFri, 18 Nov 2011 09:08:13 +0000
treeherdermozilla-inbound@8531b4bf5cb9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs685767
milestone11.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Back out Bug 685767 for leaking.
gfx/2d/Blur.cpp
gfx/2d/Blur.h
gfx/2d/Makefile.in
gfx/thebes/gfxBlur.cpp
gfx/thebes/gfxBlur.h
deleted file mode 100644
--- a/gfx/2d/Blur.cpp
+++ /dev/null
@@ -1,526 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla gfx.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2011
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include <algorithm>
-#include <math.h>
-
-#include "CheckedInt.h"
-#include "mozilla/Util.h"
-
-#include "mozilla/gfx/Blur.h"
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-using namespace std;
-
-namespace mozilla {
-namespace gfx {
-
-/**
- * Box blur involves looking at one pixel, and setting its value to the average
- * of its neighbouring pixels.
- * @param aInput The input buffer.
- * @param aOutput The output buffer.
- * @param aLeftLobe The number of pixels to blend on the left.
- * @param aRightLobe The number of pixels to blend on the right.
- * @param aWidth The number of columns in the buffers.
- * @param aRows The number of rows in the buffers.
- * @param aSkipRect An area to skip blurring in.
- * XXX shouldn't we pass stride in separately here?
- */
-static void
-BoxBlurHorizontal(unsigned char* aInput,
-                  unsigned char* aOutput,
-                  int32_t aLeftLobe,
-                  int32_t aRightLobe,
-                  int32_t aWidth,
-                  int32_t aRows,
-                  const IntRect& aSkipRect)
-{
-    MOZ_ASSERT(aWidth > 0);
-
-    int32_t boxSize = aLeftLobe + aRightLobe + 1;
-    bool skipRectCoversWholeRow = 0 >= aSkipRect.x &&
-                                  aWidth <= aSkipRect.XMost();
-
-    for (int32_t y = 0; y < aRows; y++) {
-        // Check whether the skip rect intersects this row. If the skip
-        // rect covers the whole surface in this row, we can avoid
-        // this row entirely (and any others along the skip rect).
-        bool inSkipRectY = y >= aSkipRect.y &&
-                           y < aSkipRect.YMost();
-        if (inSkipRectY && skipRectCoversWholeRow) {
-            y = aSkipRect.YMost() - 1;
-            continue;
-        }
-
-        int32_t alphaSum = 0;
-        for (int32_t i = 0; i < boxSize; i++) {
-            int32_t pos = i - aLeftLobe;
-            // See assertion above; if aWidth is zero, then we would have no
-            // valid position to clamp to.
-            pos = max(pos, 0);
-            pos = min(pos, aWidth - 1);
-            alphaSum += aInput[aWidth * y + pos];
-        }
-        for (int32_t x = 0; x < aWidth; x++) {
-            // Check whether we are within the skip rect. If so, go
-            // to the next point outside the skip rect.
-            if (inSkipRectY && x >= aSkipRect.x &&
-                x < aSkipRect.XMost()) {
-                x = aSkipRect.XMost();
-                if (x >= aWidth)
-                    break;
-
-                // Recalculate the neighbouring alpha values for
-                // our new point on the surface.
-                alphaSum = 0;
-                for (int32_t i = 0; i < boxSize; i++) {
-                    int32_t pos = x + i - aLeftLobe;
-                    // See assertion above; if aWidth is zero, then we would have no
-                    // valid position to clamp to.
-                    pos = max(pos, 0);
-                    pos = min(pos, aWidth - 1);
-                    alphaSum += aInput[aWidth * y + pos];
-                }
-            }
-            int32_t tmp = x - aLeftLobe;
-            int32_t last = max(tmp, 0);
-            int32_t next = min(tmp + boxSize, aWidth - 1);
-
-            aOutput[aWidth * y + x] = alphaSum / boxSize;
-
-            alphaSum += aInput[aWidth * y + next] -
-                        aInput[aWidth * y + last];
-        }
-    }
-}
-
-/**
- * Identical to BoxBlurHorizontal, except it blurs top and bottom instead of
- * left and right.
- * XXX shouldn't we pass stride in separately here?
- */
-static void
-BoxBlurVertical(unsigned char* aInput,
-                unsigned char* aOutput,
-                int32_t aTopLobe,
-                int32_t aBottomLobe,
-                int32_t aWidth,
-                int32_t aRows,
-                const IntRect& aSkipRect)
-{
-    MOZ_ASSERT(aRows > 0);
-
-    int32_t boxSize = aTopLobe + aBottomLobe + 1;
-    bool skipRectCoversWholeColumn = 0 >= aSkipRect.y &&
-                                     aRows <= aSkipRect.YMost();
-
-    for (int32_t x = 0; x < aWidth; x++) {
-        bool inSkipRectX = x >= aSkipRect.x &&
-                           x < aSkipRect.XMost();
-        if (inSkipRectX && skipRectCoversWholeColumn) {
-            x = aSkipRect.XMost() - 1;
-            continue;
-        }
-
-        int32_t alphaSum = 0;
-        for (int32_t i = 0; i < boxSize; i++) {
-            int32_t pos = i - aTopLobe;
-            // See assertion above; if aRows is zero, then we would have no
-            // valid position to clamp to.
-            pos = max(pos, 0);
-            pos = min(pos, aRows - 1);
-            alphaSum += aInput[aWidth * pos + x];
-        }
-        for (int32_t y = 0; y < aRows; y++) {
-            if (inSkipRectX && y >= aSkipRect.y &&
-                y < aSkipRect.YMost()) {
-                y = aSkipRect.YMost();
-                if (y >= aRows)
-                    break;
-
-                alphaSum = 0;
-                for (int32_t i = 0; i < boxSize; i++) {
-                    int32_t pos = y + i - aTopLobe;
-                    // See assertion above; if aRows is zero, then we would have no
-                    // valid position to clamp to.
-                    pos = max(pos, 0);
-                    pos = min(pos, aRows - 1);
-                    alphaSum += aInput[aWidth * pos + x];
-                }
-            }
-            int32_t tmp = y - aTopLobe;
-            int32_t last = max(tmp, 0);
-            int32_t next = min(tmp + boxSize, aRows - 1);
-
-            aOutput[aWidth * y + x] = alphaSum/boxSize;
-
-            alphaSum += aInput[aWidth * next + x] -
-                        aInput[aWidth * last + x];
-        }
-    }
-}
-
-static void ComputeLobes(int32_t aRadius, int32_t aLobes[3][2])
-{
-    int32_t major, minor, final;
-
-    /* See http://www.w3.org/TR/SVG/filters.html#feGaussianBlur for
-     * some notes about approximating the Gaussian blur with box-blurs.
-     * The comments below are in the terminology of that page.
-     */
-    int32_t z = aRadius / 3;
-    switch (aRadius % 3) {
-    case 0:
-        // aRadius = z*3; choose d = 2*z + 1
-        major = minor = final = z;
-        break;
-    case 1:
-        // aRadius = z*3 + 1
-        // This is a tricky case since there is no value of d which will
-        // yield a radius of exactly aRadius. If d is odd, i.e. d=2*k + 1
-        // for some integer k, then the radius will be 3*k. If d is even,
-        // i.e. d=2*k, then the radius will be 3*k - 1.
-        // So we have to choose values that don't match the standard
-        // algorithm.
-        major = z + 1;
-        minor = final = z;
-        break;
-    case 2:
-        // aRadius = z*3 + 2; choose d = 2*z + 2
-        major = final = z + 1;
-        minor = z;
-        break;
-    default:
-        // Mathematical impossibility!
-        MOZ_ASSERT(false);
-        major = minor = final = 0;
-    }
-    MOZ_ASSERT(major + minor + final == aRadius);
-
-    aLobes[0][0] = major;
-    aLobes[0][1] = minor;
-    aLobes[1][0] = minor;
-    aLobes[1][1] = major;
-    aLobes[2][0] = final;
-    aLobes[2][1] = final;
-}
-
-static void
-SpreadHorizontal(unsigned char* aInput,
-                 unsigned char* aOutput,
-                 int32_t aRadius,
-                 int32_t aWidth,
-                 int32_t aRows,
-                 int32_t aStride,
-                 const IntRect& aSkipRect)
-{
-    if (aRadius == 0) {
-        memcpy(aOutput, aInput, aStride * aRows);
-        return;
-    }
-
-    bool skipRectCoversWholeRow = 0 >= aSkipRect.x &&
-                                    aWidth <= aSkipRect.XMost();
-    for (int32_t y = 0; y < aRows; y++) {
-        // Check whether the skip rect intersects this row. If the skip
-        // rect covers the whole surface in this row, we can avoid
-        // this row entirely (and any others along the skip rect).
-        bool inSkipRectY = y >= aSkipRect.y &&
-                             y < aSkipRect.YMost();
-        if (inSkipRectY && skipRectCoversWholeRow) {
-            y = aSkipRect.YMost() - 1;
-            continue;
-        }
-
-        for (int32_t x = 0; x < aWidth; x++) {
-            // Check whether we are within the skip rect. If so, go
-            // to the next point outside the skip rect.
-            if (inSkipRectY && x >= aSkipRect.x &&
-                x < aSkipRect.XMost()) {
-                x = aSkipRect.XMost();
-                if (x >= aWidth)
-                    break;
-            }
-
-            int32_t sMin = max(x - aRadius, 0);
-            int32_t sMax = min(x + aRadius, aWidth - 1);
-            int32_t v = 0;
-            for (int32_t s = sMin; s <= sMax; ++s) {
-                v = max<int32_t>(v, aInput[aStride * y + s]);
-            }
-            aOutput[aStride * y + x] = v;
-        }
-    }
-}
-
-static void
-SpreadVertical(unsigned char* aInput,
-               unsigned char* aOutput,
-               int32_t aRadius,
-               int32_t aWidth,
-               int32_t aRows,
-               int32_t aStride,
-               const IntRect& aSkipRect)
-{
-    if (aRadius == 0) {
-        memcpy(aOutput, aInput, aStride * aRows);
-        return;
-    }
-
-    bool skipRectCoversWholeColumn = 0 >= aSkipRect.y &&
-                                     aRows <= aSkipRect.YMost();
-    for (int32_t x = 0; x < aWidth; x++) {
-        bool inSkipRectX = x >= aSkipRect.x &&
-                           x < aSkipRect.XMost();
-        if (inSkipRectX && skipRectCoversWholeColumn) {
-            x = aSkipRect.XMost() - 1;
-            continue;
-        }
-
-        for (int32_t y = 0; y < aRows; y++) {
-            // Check whether we are within the skip rect. If so, go
-            // to the next point outside the skip rect.
-            if (inSkipRectX && y >= aSkipRect.y &&
-                y < aSkipRect.YMost()) {
-                y = aSkipRect.YMost();
-                if (y >= aRows)
-                    break;
-            }
-
-            int32_t sMin = max(y - aRadius, 0);
-            int32_t sMax = min(y + aRadius, aRows - 1);
-            int32_t v = 0;
-            for (int32_t s = sMin; s <= sMax; ++s) {
-                v = max<int32_t>(v, aInput[aStride * s + x]);
-            }
-            aOutput[aStride * y + x] = v;
-        }
-    }
-}
-
-static CheckedInt<int32_t>
-RoundUpToMultipleOf4(int32_t aVal)
-{
-  CheckedInt<int32_t> val(aVal);
-
-  val += 3;
-  val /= 4;
-  val *= 4;
-
-  return val;
-}
-
-AlphaBoxBlur::AlphaBoxBlur(const Rect& aRect,
-                           const IntSize& aSpreadRadius,
-                           const IntSize& aBlurRadius,
-                           const Rect* aDirtyRect,
-                           const Rect* aSkipRect)
- : mSpreadRadius(aSpreadRadius),
-   mBlurRadius(aBlurRadius),
-   mData(NULL)
-{
-  Rect rect(aRect);
-  rect.Inflate(Size(aBlurRadius + aSpreadRadius));
-  rect.RoundOut();
-
-  if (aDirtyRect) {
-    // If we get passed a dirty rect from layout, we can minimize the
-    // shadow size and make painting faster.
-    mHasDirtyRect = true;
-    mDirtyRect = *aDirtyRect;
-    Rect requiredBlurArea = mDirtyRect.Intersect(rect);
-    requiredBlurArea.Inflate(Size(aBlurRadius + aSpreadRadius));
-    rect = requiredBlurArea.Intersect(rect);
-  } else {
-    mHasDirtyRect = false;
-  }
-
-  if (rect.IsEmpty()) {
-    return;
-  }
-
-  if (aSkipRect) {
-    // If we get passed a skip rect, we can lower the amount of
-    // blurring/spreading we need to do. We convert it to IntRect to avoid
-    // expensive int<->float conversions if we were to use Rect instead.
-    Rect skipRect = *aSkipRect;
-    skipRect.RoundIn();
-    skipRect.Deflate(Size(aBlurRadius + aSpreadRadius));
-    mSkipRect = IntRect(skipRect.x, skipRect.y, skipRect.width, skipRect.height);
-
-    IntRect shadowIntRect(rect.x, rect.y, rect.width, rect.height);
-    mSkipRect.IntersectRect(mSkipRect, shadowIntRect);
-
-    if (mSkipRect.IsEqualInterior(shadowIntRect))
-      return;
-
-    mSkipRect -= shadowIntRect.TopLeft();
-  } else {
-    mSkipRect = IntRect(0, 0, 0, 0);
-  }
-
-  mRect = IntRect(rect.x, rect.y, rect.width, rect.height);
-
-  CheckedInt<int32_t> stride = RoundUpToMultipleOf4(mRect.width);
-  if (stride.valid()) {
-    mStride = stride.value();
-
-    CheckedInt<int32_t> size = CheckedInt<int32_t>(mStride) * mRect.height *
-                               sizeof(unsigned char);
-    if (size.valid()) {
-      mData = static_cast<unsigned char*>(malloc(size.value()));
-      memset(mData, 0, size.value());
-    }
-  }
-}
-
-AlphaBoxBlur::~AlphaBoxBlur()
-{
-  free(mData);
-}
-
-unsigned char*
-AlphaBoxBlur::GetData()
-{
-  return mData;
-}
-
-IntSize
-AlphaBoxBlur::GetSize()
-{
-  IntSize size(mRect.width, mRect.height);
-  return size;
-}
-
-int32_t
-AlphaBoxBlur::GetStride()
-{
-  return mStride;
-}
-
-IntRect
-AlphaBoxBlur::GetRect()
-{
-  return mRect;
-}
-
-Rect*
-AlphaBoxBlur::GetDirtyRect()
-{
-  if (mHasDirtyRect) {
-    return &mDirtyRect;
-  }
-
-  return NULL;
-}
-
-void
-AlphaBoxBlur::Blur()
-{
-  if (!mData) {
-    return;
-  }
-
-  // no need to do all this if not blurring or spreading
-  if (mBlurRadius != IntSize(0,0) || mSpreadRadius != IntSize(0,0)) {
-    int32_t stride = GetStride();
-
-    // No need to use CheckedInt here - we have validated it in the constructor.
-    size_t szB = stride * GetSize().height * sizeof(unsigned char);
-    unsigned char* tmpData = static_cast<unsigned char*>(malloc(szB));
-    if (!tmpData)
-      return; // OOM
-
-    memset(tmpData, 0, szB);
-
-    if (mSpreadRadius.width > 0 || mSpreadRadius.height > 0) {
-      SpreadHorizontal(mData, tmpData, mSpreadRadius.width, GetSize().width, GetSize().height, stride, mSkipRect);
-      SpreadVertical(tmpData, mData, mSpreadRadius.height, GetSize().width, GetSize().height, stride, mSkipRect);
-    }
-
-    if (mBlurRadius.width > 0) {
-      int32_t lobes[3][2];
-      ComputeLobes(mBlurRadius.width, lobes);
-      BoxBlurHorizontal(mData, tmpData, lobes[0][0], lobes[0][1], stride, GetSize().height, mSkipRect);
-      BoxBlurHorizontal(tmpData, mData, lobes[1][0], lobes[1][1], stride, GetSize().height, mSkipRect);
-      BoxBlurHorizontal(mData, tmpData, lobes[2][0], lobes[2][1], stride, GetSize().height, mSkipRect);
-    } else {
-      memcpy(tmpData, mData, stride * GetSize().height);
-    }
-
-    if (mBlurRadius.height > 0) {
-      int32_t lobes[3][2];
-      ComputeLobes(mBlurRadius.height, lobes);
-      BoxBlurVertical(tmpData, mData, lobes[0][0], lobes[0][1], stride, GetSize().height, mSkipRect);
-      BoxBlurVertical(mData, tmpData, lobes[1][0], lobes[1][1], stride, GetSize().height, mSkipRect);
-      BoxBlurVertical(tmpData, mData, lobes[2][0], lobes[2][1], stride, GetSize().height, mSkipRect);
-    } else {
-      memcpy(mData, tmpData, stride * GetSize().height);
-    }
-
-    free(tmpData);
-  }
-
-}
-
-/**
- * Compute the box blur size (which we're calling the blur radius) from
- * the standard deviation.
- *
- * Much of this, the 3 * sqrt(2 * pi) / 4, is the known value for
- * approximating a Gaussian using box blurs.  This yields quite a good
- * approximation for a Gaussian.  Then we multiply this by 1.5 since our
- * code wants the radius of the entire triple-box-blur kernel instead of
- * the diameter of an individual box blur.  For more details, see:
- *   http://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement
- *   https://bugzilla.mozilla.org/show_bug.cgi?id=590039#c19
- */
-static const Float GAUSSIAN_SCALE_FACTOR = (3 * sqrt(2 * M_PI) / 4) * 1.5;
-
-IntSize
-AlphaBoxBlur::CalculateBlurRadius(const Point& aStd)
-{
-    IntSize size(static_cast<int32_t>(floor(aStd.x * GAUSSIAN_SCALE_FACTOR + 0.5)),
-                 static_cast<int32_t>(floor(aStd.y * GAUSSIAN_SCALE_FACTOR + 0.5)));
-
-    return size;
-}
-
-}
-}
deleted file mode 100644
--- a/gfx/2d/Blur.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla gfx.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2011
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "mozilla/gfx/Rect.h"
-#include "mozilla/gfx/Point.h"
-
-namespace mozilla {
-namespace gfx {
-
-/**
- * Implementation of a triple box blur approximation of a Gaussian blur.
- *
- * A Gaussian blur is good for blurring because, when done independently
- * in the horizontal and vertical directions, it matches the result that
- * would be obtained using a different (rotated) set of axes.  A triple
- * box blur is a very close approximation of a Gaussian.
- *
- * Creates an 8-bit alpha channel context for callers to draw in,
- * spreads the contents of that context, and blurs the contents.
- *
- * A spread N makes each output pixel the maximum value of all source
- * pixels within a square of side length 2N+1 centered on the output pixel.
- *
- * A temporary surface is created in the Init function. The caller then draws
- * any desired content onto the context acquired through GetContext, and lastly
- * calls Paint to apply the blurred content as an alpha mask.
- */
-class AlphaBoxBlur
-{
-public:
-
-  /** Constructs a box blur and initializes the backing surface.
-   *
-   * @param aRect The coordinates of the surface to create in device units.
-   *
-   * @param aBlurRadius The blur radius in pixels.  This is the radius of the
-   *   entire (triple) kernel function.  Each individual box blur has radius
-   *   approximately 1/3 this value, or diameter approximately 2/3 this value.
-   *   This parameter should nearly always be computed using CalculateBlurRadius,
-   *   below.
-   *
-   * @param aDirtyRect A pointer to a dirty rect, measured in device units, if
-   *   available.  This will be used for optimizing the blur operation. It is
-   *   safe to pass NULL here.
-   *
-   * @param aSkipRect A pointer to a rect, measured in device units, that
-   *   represents an area where blurring is unnecessary and shouldn't be done for
-   *   speed reasons. It is safe to pass NULL here.
-   */
-  AlphaBoxBlur(const Rect& aRect,
-               const IntSize& aSpreadRadius,
-               const IntSize& aBlurRadius,
-               const Rect* aDirtyRect,
-               const Rect* aSkipRect);
-
-  ~AlphaBoxBlur();
-
-  /**
-   * Return the pointer to memory allocated by the constructor for the 8-bit
-   * alpha surface you need to be blurred. After you draw to this surface, call
-   * Blur(), below, to have its contents blurred.
-   */
-  unsigned char* GetData();
-
-  /**
-   * Return the size, in pixels, of the 8-bit alpha surface backed by the
-   * pointer returned by GetData().
-   */
-  IntSize GetSize();
-
-  /**
-   * Return the stride, in bytes, of the 8-bit alpha surface backed by the
-   * pointer returned by GetData().
-   */
-  int32_t GetStride();
-
-  /**
-   * Returns the device-space rectangle the 8-bit alpha surface covers.
-   */
-  IntRect GetRect();
-
-  /**
-   * Return a pointer to a dirty rect, as passed in to the constructor, or NULL
-   * if none was passed in.
-   */
-  Rect* GetDirtyRect();
-
-  /**
-   * Perform the blur in-place on the surface backed by the pointer returned by
-   * GetData().
-   */
-  void Blur();
-
-  /**
-   * Calculates a blur radius that, when used with box blur, approximates a
-   * Gaussian blur with the given standard deviation.  The result of this
-   * function should be used as the aBlurRadius parameter to AlphaBoxBlur's
-   * constructor, above.
-   */
-  static IntSize CalculateBlurRadius(const Point& aStandardDeviation);
-
-private:
-
-  /**
-   * A rect indicating the area where blurring is unnecessary, and the blur
-   * algorithm should skip over it.
-   */
-  IntRect mSkipRect;
-
-  /**
-   * The device-space rectangle the the backing 8-bit alpha surface covers.
-   */
-  IntRect mRect;
-
-  /**
-   * A copy of the dirty rect passed to the constructor. This will only be valid if
-   * mHasDirtyRect is true.
-   */
-  Rect mDirtyRect;
-
-  /**
-   * The spread radius, in pixels.
-   */
-  IntSize mSpreadRadius;
-
-  /**
-   * The blur radius, in pixels.
-   */
-  IntSize mBlurRadius;
-
-  /**
-   * A pointer to the backing 8-bit alpha surface.
-   */
-  unsigned char* mData;
-
-  /**
-   * The stride of the data contained in mData.
-   */
-  int32_t mStride;
-
-  /**
-   * Whether mDirtyRect contains valid data.
-   */
-  bool mHasDirtyRect;
-};
-
-}
-}
--- a/gfx/2d/Makefile.in
+++ b/gfx/2d/Makefile.in
@@ -51,30 +51,28 @@ EXPORTS_NAMESPACES = mozilla/gfx
 EXPORTS_mozilla/gfx	= \
         2D.h \
         BasePoint.h \
         BasePoint3D.h \
         BasePoint4D.h \
         BaseMargin.h \
         BaseRect.h \
         BaseSize.h \
-        Blur.h \
         PathHelpers.h \
         Point.h \
         Matrix.h \
         Rect.h \
         Types.h \
 	$(NULL)
 
 CPPSRCS	= \
 	Factory.cpp \
         Matrix.cpp \
         DrawTargetCairo.cpp \
         SourceSurfaceCairo.cpp \
-        Blur.cpp \
         $(NULL)
 
 
 DEFINES += -DMOZ_GFX -DUSE_CAIRO
 
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS	+= \
 		SourceSurfaceSkia.cpp \
--- a/gfx/thebes/gfxBlur.cpp
+++ b/gfx/thebes/gfxBlur.cpp
@@ -32,99 +32,470 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxBlur.h"
 
-#include "mozilla/gfx/Blur.h"
+#include "nsMathUtils.h"
+#include "nsTArray.h"
 
-using namespace mozilla::gfx;
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
 
 gfxAlphaBoxBlur::gfxAlphaBoxBlur()
- : mBlur(nsnull)
 {
 }
 
 gfxAlphaBoxBlur::~gfxAlphaBoxBlur()
 {
 }
 
 gfxContext*
 gfxAlphaBoxBlur::Init(const gfxRect& aRect,
                       const gfxIntSize& aSpreadRadius,
                       const gfxIntSize& aBlurRadius,
                       const gfxRect* aDirtyRect,
                       const gfxRect* aSkipRect)
 {
-    Rect rect(aRect.x, aRect.y, aRect.width, aRect.height);
-    IntSize spreadRadius(aSpreadRadius.width, aSpreadRadius.height);
-    IntSize blurRadius(aBlurRadius.width, aBlurRadius.height);
-    nsAutoPtr<Rect> dirtyRect;
+    mSpreadRadius = aSpreadRadius;
+    mBlurRadius = aBlurRadius;
+
+    gfxRect rect(aRect);
+    rect.Inflate(aBlurRadius + aSpreadRadius);
+    rect.RoundOut();
+
     if (aDirtyRect) {
-      dirtyRect = new Rect(aDirtyRect->x, aDirtyRect->y, aDirtyRect->width, aDirtyRect->height);
-    }
-    nsAutoPtr<Rect> skipRect;
-    if (aSkipRect) {
-      skipRect = new Rect(aSkipRect->x, aSkipRect->y, aSkipRect->width, aSkipRect->height);
+        // If we get passed a dirty rect from layout, we can minimize the
+        // shadow size and make painting faster.
+        mHasDirtyRect = true;
+        mDirtyRect = *aDirtyRect;
+        gfxRect requiredBlurArea = mDirtyRect.Intersect(rect);
+        requiredBlurArea.Inflate(aBlurRadius + aSpreadRadius);
+        rect = requiredBlurArea.Intersect(rect);
+    } else {
+        mHasDirtyRect = false;
     }
 
-    mBlur = new AlphaBoxBlur(rect, spreadRadius, blurRadius, dirtyRect, skipRect);
+    // Check rect empty after accounting for aDirtyRect, since that may have
+    // make the rectangle empty. BoxBlurVertical and BoxBlurHorizontal require
+    // that we have a nonzero number of rows and columns.
+    if (rect.IsEmpty())
+        return nsnull;
 
-    unsigned char* data = mBlur->GetData();
-    if (!data)
-      return nsnull;
+    if (aSkipRect) {
+        // If we get passed a skip rect, we can lower the amount of
+        // blurring/spreading we need to do. We convert it to nsIntRect to avoid
+        // expensive int<->float conversions if we were to use gfxRect instead.
+        gfxRect skipRect = *aSkipRect;
+        skipRect.RoundIn();
+        skipRect.Deflate(aBlurRadius + aSpreadRadius);
+        gfxUtils::GfxRectToIntRect(skipRect, &mSkipRect);
+        nsIntRect shadowIntRect;
+        gfxUtils::GfxRectToIntRect(rect, &shadowIntRect);
+        mSkipRect.IntersectRect(mSkipRect, shadowIntRect);
+        if (mSkipRect.IsEqualInterior(shadowIntRect))
+          return nsnull;
 
-    IntSize size = mBlur->GetSize();
+        mSkipRect -= shadowIntRect.TopLeft();
+    } else {
+        mSkipRect = nsIntRect(0, 0, 0, 0);
+    }
+
     // Make an alpha-only surface to draw on. We will play with the data after
     // everything is drawn to create a blur effect.
-    mImageSurface = new gfxImageSurface(data, gfxIntSize(size.width, size.height),
-                                        mBlur->GetStride(),
+    mImageSurface = new gfxImageSurface(gfxIntSize(static_cast<PRInt32>(rect.Width()), static_cast<PRInt32>(rect.Height())),
                                         gfxASurface::ImageFormatA8);
-    if (mImageSurface->CairoStatus())
+    if (!mImageSurface || mImageSurface->CairoStatus())
         return nsnull;
 
-    IntRect irect = mBlur->GetRect();
-    gfxPoint topleft(irect.TopLeft().x, irect.TopLeft().y);
-
     // Use a device offset so callers don't need to worry about translating
     // coordinates, they can draw as if this was part of the destination context
     // at the coordinates of rect.
-    mImageSurface->SetDeviceOffset(-topleft);
+    mImageSurface->SetDeviceOffset(-rect.TopLeft());
 
     mContext = new gfxContext(mImageSurface);
 
     return mContext;
 }
 
+/**
+ * Box blur involves looking at one pixel, and setting its value to the average
+ * of its neighbouring pixels.
+ * @param aInput The input buffer.
+ * @param aOutput The output buffer.
+ * @param aLeftLobe The number of pixels to blend on the left.
+ * @param aRightLobe The number of pixels to blend on the right.
+ * @param aWidth The number of columns in the buffers.
+ * @param aRows The number of rows in the buffers.
+ * @param aSkipRect An area to skip blurring in.
+ * XXX shouldn't we pass stride in separately here?
+ */
+static void
+BoxBlurHorizontal(unsigned char* aInput,
+                  unsigned char* aOutput,
+                  PRInt32 aLeftLobe,
+                  PRInt32 aRightLobe,
+                  PRInt32 aWidth,
+                  PRInt32 aRows,
+                  const nsIntRect& aSkipRect)
+{
+    NS_ASSERTION(aWidth > 0, "Can't handle zero width here");
+
+    PRInt32 boxSize = aLeftLobe + aRightLobe + 1;
+    bool skipRectCoversWholeRow = 0 >= aSkipRect.x &&
+                                    aWidth <= aSkipRect.XMost();
+    if (boxSize == 1) {
+        memcpy(aOutput, aInput, aWidth*aRows);
+        return;
+    }
+    PRUint32 reciprocal = (PRUint64(1) << 32)/boxSize;
+
+    for (PRInt32 y = 0; y < aRows; y++) {
+        // Check whether the skip rect intersects this row. If the skip
+        // rect covers the whole surface in this row, we can avoid
+        // this row entirely (and any others along the skip rect).
+        bool inSkipRectY = y >= aSkipRect.y &&
+                             y < aSkipRect.YMost();
+        if (inSkipRectY && skipRectCoversWholeRow) {
+            y = aSkipRect.YMost() - 1;
+            continue;
+        }
+
+        PRUint32 alphaSum = 0;
+        for (PRInt32 i = 0; i < boxSize; i++) {
+            PRInt32 pos = i - aLeftLobe;
+            // See assertion above; if aWidth is zero, then we would have no
+            // valid position to clamp to.
+            pos = NS_MAX(pos, 0);
+            pos = NS_MIN(pos, aWidth - 1);
+            alphaSum += aInput[aWidth * y + pos];
+        }
+        for (PRInt32 x = 0; x < aWidth; x++) {
+            // Check whether we are within the skip rect. If so, go
+            // to the next point outside the skip rect.
+            if (inSkipRectY && x >= aSkipRect.x &&
+                x < aSkipRect.XMost()) {
+                x = aSkipRect.XMost();
+                if (x >= aWidth)
+                    break;
+
+                // Recalculate the neighbouring alpha values for
+                // our new point on the surface.
+                alphaSum = 0;
+                for (PRInt32 i = 0; i < boxSize; i++) {
+                    PRInt32 pos = x + i - aLeftLobe;
+                    // See assertion above; if aWidth is zero, then we would have no
+                    // valid position to clamp to.
+                    pos = NS_MAX(pos, 0);
+                    pos = NS_MIN(pos, aWidth - 1);
+                    alphaSum += aInput[aWidth * y + pos];
+                }
+            }
+            PRInt32 tmp = x - aLeftLobe;
+            PRInt32 last = NS_MAX(tmp, 0);
+            PRInt32 next = NS_MIN(tmp + boxSize, aWidth - 1);
+
+            aOutput[aWidth * y + x] = (PRUint64(alphaSum)*reciprocal) >> 32;
+
+            alphaSum += aInput[aWidth * y + next] -
+                        aInput[aWidth * y + last];
+        }
+    }
+}
+
+/**
+ * Identical to BoxBlurHorizontal, except it blurs top and bottom instead of
+ * left and right.
+ * XXX shouldn't we pass stride in separately here?
+ */
+static void
+BoxBlurVertical(unsigned char* aInput,
+                unsigned char* aOutput,
+                PRInt32 aTopLobe,
+                PRInt32 aBottomLobe,
+                PRInt32 aWidth,
+                PRInt32 aRows,
+                const nsIntRect& aSkipRect)
+{
+    NS_ASSERTION(aRows > 0, "Can't handle zero rows here");
+
+    PRInt32 boxSize = aTopLobe + aBottomLobe + 1;
+    bool skipRectCoversWholeColumn = 0 >= aSkipRect.y &&
+                                       aRows <= aSkipRect.YMost();
+    if (boxSize == 1) {
+        memcpy(aOutput, aInput, aWidth*aRows);
+        return;
+    }
+    PRUint32 reciprocal = (PRUint64(1) << 32)/boxSize;
+
+    for (PRInt32 x = 0; x < aWidth; x++) {
+        bool inSkipRectX = x >= aSkipRect.x &&
+                             x < aSkipRect.XMost();
+        if (inSkipRectX && skipRectCoversWholeColumn) {
+            x = aSkipRect.XMost() - 1;
+            continue;
+        }
+
+        PRUint32 alphaSum = 0;
+        for (PRInt32 i = 0; i < boxSize; i++) {
+            PRInt32 pos = i - aTopLobe;
+            // See assertion above; if aRows is zero, then we would have no
+            // valid position to clamp to.
+            pos = NS_MAX(pos, 0);
+            pos = NS_MIN(pos, aRows - 1);
+            alphaSum += aInput[aWidth * pos + x];
+        }
+        for (PRInt32 y = 0; y < aRows; y++) {
+            if (inSkipRectX && y >= aSkipRect.y &&
+                y < aSkipRect.YMost()) {
+                y = aSkipRect.YMost();
+                if (y >= aRows)
+                    break;
+
+                alphaSum = 0;
+                for (PRInt32 i = 0; i < boxSize; i++) {
+                    PRInt32 pos = y + i - aTopLobe;
+                    // See assertion above; if aRows is zero, then we would have no
+                    // valid position to clamp to.
+                    pos = NS_MAX(pos, 0);
+                    pos = NS_MIN(pos, aRows - 1);
+                    alphaSum += aInput[aWidth * pos + x];
+                }
+            }
+            PRInt32 tmp = y - aTopLobe;
+            PRInt32 last = NS_MAX(tmp, 0);
+            PRInt32 next = NS_MIN(tmp + boxSize, aRows - 1);
+
+            aOutput[aWidth * y + x] = (PRUint64(alphaSum)*reciprocal) >> 32;
+
+            alphaSum += aInput[aWidth * next + x] -
+                        aInput[aWidth * last + x];
+        }
+    }
+}
+
+static void ComputeLobes(PRInt32 aRadius, PRInt32 aLobes[3][2])
+{
+    PRInt32 major, minor, final;
+
+    /* See http://www.w3.org/TR/SVG/filters.html#feGaussianBlur for
+     * some notes about approximating the Gaussian blur with box-blurs.
+     * The comments below are in the terminology of that page.
+     */
+    PRInt32 z = aRadius/3;
+    switch (aRadius % 3) {
+    case 0:
+        // aRadius = z*3; choose d = 2*z + 1
+        major = minor = final = z;
+        break;
+    case 1:
+        // aRadius = z*3 + 1
+        // This is a tricky case since there is no value of d which will
+        // yield a radius of exactly aRadius. If d is odd, i.e. d=2*k + 1
+        // for some integer k, then the radius will be 3*k. If d is even,
+        // i.e. d=2*k, then the radius will be 3*k - 1.
+        // So we have to choose values that don't match the standard
+        // algorithm.
+        major = z + 1;
+        minor = final = z;
+        break;
+    case 2:
+        // aRadius = z*3 + 2; choose d = 2*z + 2
+        major = final = z + 1;
+        minor = z;
+        break;
+    default:
+        NS_ERROR("Mathematical impossibility.");
+        major = minor = final = 0;
+    }
+    NS_ASSERTION(major + minor + final == aRadius,
+                 "Lobes don't sum to the right length");
+
+    aLobes[0][0] = major;
+    aLobes[0][1] = minor;
+    aLobes[1][0] = minor;
+    aLobes[1][1] = major;
+    aLobes[2][0] = final;
+    aLobes[2][1] = final;
+}
+
+static void
+SpreadHorizontal(unsigned char* aInput,
+                 unsigned char* aOutput,
+                 PRInt32 aRadius,
+                 PRInt32 aWidth,
+                 PRInt32 aRows,
+                 PRInt32 aStride,
+                 const nsIntRect& aSkipRect)
+{
+    if (aRadius == 0) {
+        memcpy(aOutput, aInput, aStride*aRows);
+        return;
+    }
+
+    bool skipRectCoversWholeRow = 0 >= aSkipRect.x &&
+                                    aWidth <= aSkipRect.XMost();
+    for (PRInt32 y = 0; y < aRows; y++) {
+        // Check whether the skip rect intersects this row. If the skip
+        // rect covers the whole surface in this row, we can avoid
+        // this row entirely (and any others along the skip rect).
+        bool inSkipRectY = y >= aSkipRect.y &&
+                             y < aSkipRect.YMost();
+        if (inSkipRectY && skipRectCoversWholeRow) {
+            y = aSkipRect.YMost() - 1;
+            continue;
+        }
+
+        for (PRInt32 x = 0; x < aWidth; x++) {
+            // Check whether we are within the skip rect. If so, go
+            // to the next point outside the skip rect.
+            if (inSkipRectY && x >= aSkipRect.x &&
+                x < aSkipRect.XMost()) {
+                x = aSkipRect.XMost();
+                if (x >= aWidth)
+                    break;
+            }
+
+            PRInt32 sMin = NS_MAX(x - aRadius, 0);
+            PRInt32 sMax = NS_MIN(x + aRadius, aWidth - 1);
+            PRInt32 v = 0;
+            for (PRInt32 s = sMin; s <= sMax; ++s) {
+                v = NS_MAX<PRInt32>(v, aInput[aStride * y + s]);
+            }
+            aOutput[aStride * y + x] = v;
+        }
+    }
+}
+
+static void
+SpreadVertical(unsigned char* aInput,
+               unsigned char* aOutput,
+               PRInt32 aRadius,
+               PRInt32 aWidth,
+               PRInt32 aRows,
+               PRInt32 aStride,
+               const nsIntRect& aSkipRect)
+{
+    if (aRadius == 0) {
+        memcpy(aOutput, aInput, aStride*aRows);
+        return;
+    }
+
+    bool skipRectCoversWholeColumn = 0 >= aSkipRect.y &&
+                                       aRows <= aSkipRect.YMost();
+    for (PRInt32 x = 0; x < aWidth; x++) {
+        bool inSkipRectX = x >= aSkipRect.x &&
+                             x < aSkipRect.XMost();
+        if (inSkipRectX && skipRectCoversWholeColumn) {
+            x = aSkipRect.XMost() - 1;
+            continue;
+        }
+
+        for (PRInt32 y = 0; y < aRows; y++) {
+            // Check whether we are within the skip rect. If so, go
+            // to the next point outside the skip rect.
+            if (inSkipRectX && y >= aSkipRect.y &&
+                y < aSkipRect.YMost()) {
+                y = aSkipRect.YMost();
+                if (y >= aRows)
+                    break;
+            }
+
+            PRInt32 sMin = NS_MAX(y - aRadius, 0);
+            PRInt32 sMax = NS_MIN(y + aRadius, aRows - 1);
+            PRInt32 v = 0;
+            for (PRInt32 s = sMin; s <= sMax; ++s) {
+                v = NS_MAX<PRInt32>(v, aInput[aStride * s + x]);
+            }
+            aOutput[aStride * y + x] = v;
+        }
+    }
+}
+
 void
 gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset)
 {
     if (!mContext)
         return;
 
-    mBlur->Blur();
+    unsigned char* boxData = mImageSurface->Data();
+
+    // no need to do all this if not blurring or spreading
+    if (mBlurRadius != gfxIntSize(0,0) || mSpreadRadius != gfxIntSize(0,0)) {
+        nsTArray<unsigned char> tempAlphaDataBuf;
+        PRSize szB = mImageSurface->GetDataSize();
+        if (!tempAlphaDataBuf.SetLength(szB))
+           return; // OOM
+
+        unsigned char* tmpData = tempAlphaDataBuf.Elements();
+        // .SetLength above doesn't initialise the new elements since
+        // they are unsigned chars and so have no default constructor.
+        // So we have to initialise them by hand.
+        memset(tmpData, 0, szB);
+
+        PRInt32 stride = mImageSurface->Stride();
+        PRInt32 rows = mImageSurface->Height();
+        PRInt32 width = mImageSurface->Width();
 
-    Rect* dirtyrect = mBlur->GetDirtyRect();
+        if (mSpreadRadius.width > 0 || mSpreadRadius.height > 0) {
+            SpreadHorizontal(boxData, tmpData, mSpreadRadius.width, width, rows, stride, mSkipRect);
+            SpreadVertical(tmpData, boxData, mSpreadRadius.height, width, rows, stride, mSkipRect);
+        }
+
+        if (mBlurRadius.width > 0) {
+            PRInt32 lobes[3][2];
+            ComputeLobes(mBlurRadius.width, lobes);
+            BoxBlurHorizontal(boxData, tmpData, lobes[0][0], lobes[0][1], stride, rows, mSkipRect);
+            BoxBlurHorizontal(tmpData, boxData, lobes[1][0], lobes[1][1], stride, rows, mSkipRect);
+            BoxBlurHorizontal(boxData, tmpData, lobes[2][0], lobes[2][1], stride, rows, mSkipRect);
+        } else {
+            memcpy(tmpData, boxData, stride*rows);
+        }
+
+        if (mBlurRadius.height > 0) {
+            PRInt32 lobes[3][2];
+            ComputeLobes(mBlurRadius.height, lobes);
+            BoxBlurVertical(tmpData, boxData, lobes[0][0], lobes[0][1], stride, rows, mSkipRect);
+            BoxBlurVertical(boxData, tmpData, lobes[1][0], lobes[1][1], stride, rows, mSkipRect);
+            BoxBlurVertical(tmpData, boxData, lobes[2][0], lobes[2][1], stride, rows, mSkipRect);
+        } else {
+            memcpy(boxData, tmpData, stride*rows);
+        }
+    }
 
     // Avoid a semi-expensive clip operation if we can, otherwise
     // clip to the dirty rect
-    if (dirtyrect) {
+    if (mHasDirtyRect) {
         aDestinationCtx->Save();
         aDestinationCtx->NewPath();
-        gfxRect dirty(dirtyrect->x, dirtyrect->y, dirtyrect->width, dirtyrect->height);
-        aDestinationCtx->Rectangle(dirty);
+        aDestinationCtx->Rectangle(mDirtyRect);
         aDestinationCtx->Clip();
         aDestinationCtx->Mask(mImageSurface, offset);
         aDestinationCtx->Restore();
     } else {
         aDestinationCtx->Mask(mImageSurface, offset);
     }
 }
 
+/**
+ * Compute the box blur size (which we're calling the blur radius) from
+ * the standard deviation.
+ *
+ * Much of this, the 3 * sqrt(2 * pi) / 4, is the known value for
+ * approximating a Gaussian using box blurs.  This yields quite a good
+ * approximation for a Gaussian.  Then we multiply this by 1.5 since our
+ * code wants the radius of the entire triple-box-blur kernel instead of
+ * the diameter of an individual box blur.  For more details, see:
+ *   http://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement
+ *   https://bugzilla.mozilla.org/show_bug.cgi?id=590039#c19
+ */
+static const gfxFloat GAUSSIAN_SCALE_FACTOR = (3 * sqrt(2 * M_PI) / 4) * 1.5;
+
 gfxIntSize gfxAlphaBoxBlur::CalculateBlurRadius(const gfxPoint& aStd)
 {
-    Point std(aStd.x, aStd.y);
-    IntSize size = AlphaBoxBlur::CalculateBlurRadius(std);
-    return gfxIntSize(size.width, size.height);
+    return gfxIntSize(
+        static_cast<PRInt32>(floor(aStd.x * GAUSSIAN_SCALE_FACTOR + 0.5)),
+        static_cast<PRInt32>(floor(aStd.y * GAUSSIAN_SCALE_FACTOR + 0.5)));
 }
--- a/gfx/thebes/gfxBlur.h
+++ b/gfx/thebes/gfxBlur.h
@@ -37,22 +37,17 @@
 
 #ifndef GFX_BLUR_H
 #define GFX_BLUR_H
 
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 #include "gfxTypes.h"
 #include "gfxUtils.h"
-
-namespace mozilla {
-  namespace gfx {
-    class AlphaBoxBlur;
-  }
-}
+#include "nsRect.h"
 
 /**
  * Implementation of a triple box blur approximation of a Gaussian blur.
  *
  * A Gaussian blur is good for blurring because, when done independently
  * in the horizontal and vertical directions, it matches the result that
  * would be obtained using a different (rotated) set of axes.  A triple
  * box blur is a very close approximation of a Gaussian.
@@ -123,24 +118,41 @@ public:
      * a Gaussian blur with the given standard deviation.  The result of
      * this function should be used as the aBlurRadius parameter to Init,
      * above.
      */
     static gfxIntSize CalculateBlurRadius(const gfxPoint& aStandardDeviation);
 
 protected:
     /**
+     * The spread radius, in pixels.
+     */
+    gfxIntSize mSpreadRadius;
+    /**
+     * The blur radius, in pixels.
+     */
+    gfxIntSize mBlurRadius;
+
+    /**
      * The context of the temporary alpha surface.
      */
     nsRefPtr<gfxContext> mContext;
 
     /**
      * The temporary alpha surface.
      */
     nsRefPtr<gfxImageSurface> mImageSurface;
 
-     /**
-      * The object that actually does the blurring for us.
-      */
-    nsAutoPtr<mozilla::gfx::AlphaBoxBlur> mBlur;
+    /**
+     * A copy of the dirty rect passed to Init(). This will only be valid if
+     * mHasDirtyRect is TRUE.
+     */
+    gfxRect mDirtyRect;
+    /**
+     * A rect indicating the area where blurring is unnecessary, and the blur
+     * algorithm should skip over it.
+     */
+    nsIntRect mSkipRect;
+
+    bool mHasDirtyRect;
 };
 
 #endif /* GFX_BLUR_H */