Backed out changeset 25840ab0d453 (bug 1250037) for assertion in Windows 8 x64 debug bc6 in browser_UITour.js. r=backout
authorSebastian Hengst <archaeopteryx@coole-files.de>
Fri, 18 Nov 2016 00:30:41 +0100
changeset 368222 144ca2b74fd2c4f37fde99e293b2f4104e87b9e1
parent 368221 436011c88130cd63ec6e96b6ef5213bb5e98320e
child 368223 d607a23fc3dc64956e68b588e53772b9aef48f4f
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1250037
milestone53.0a1
backs out25840ab0d4538770e2316417db77b066b24beb90
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
Backed out changeset 25840ab0d453 (bug 1250037) for assertion in Windows 8 x64 debug bc6 in browser_UITour.js. r=backout
gfx/2d/Blur.cpp
gfx/2d/Blur.h
gfx/2d/PathHelpers.h
gfx/thebes/gfxBlur.cpp
gfx/thebes/gfxBlur.h
layout/base/nsCSSRendering.cpp
layout/reftests/box-shadow/reftest.list
layout/reftests/outline/reftest.list
--- a/gfx/2d/Blur.cpp
+++ b/gfx/2d/Blur.cpp
@@ -331,64 +331,52 @@ AlphaBoxBlur::RoundUpToMultipleOf4(int32
   return val;
 }
 
 AlphaBoxBlur::AlphaBoxBlur(const Rect& aRect,
                            const IntSize& aSpreadRadius,
                            const IntSize& aBlurRadius,
                            const Rect* aDirtyRect,
                            const Rect* aSkipRect)
-  : mSurfaceAllocationSize(0)
-{
-  Init(aRect, aSpreadRadius, aBlurRadius, aDirtyRect, aSkipRect);
-}
-
-AlphaBoxBlur::AlphaBoxBlur()
-  : mSurfaceAllocationSize(0)
+ : mSpreadRadius(aSpreadRadius),
+   mBlurRadius(aBlurRadius),
+   mSurfaceAllocationSize(0)
 {
-}
-
-void
-AlphaBoxBlur::Init(const Rect& aRect,
-                   const IntSize& aSpreadRadius,
-                   const IntSize& aBlurRadius,
-                   const Rect* aDirtyRect,
-                   const Rect* aSkipRect)
-{
-  mSpreadRadius = aSpreadRadius;
-  mBlurRadius = aBlurRadius;
-
   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;
   }
 
-  mRect = TruncatedToInt(rect);
+  mRect = IntRect(int32_t(rect.x), int32_t(rect.y),
+                  int32_t(rect.width), int32_t(rect.height));
   if (mRect.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 = RoundedIn(skipRect);
+    mSkipRect = IntRect(int32_t(skipRect.x), int32_t(skipRect.y),
+                        int32_t(skipRect.width), int32_t(skipRect.height));
+
     mSkipRect = mSkipRect.Intersect(mRect);
     if (mSkipRect.IsEqualInterior(mRect))
       return;
 
     mSkipRect -= mRect.TopLeft();
   } else {
     mSkipRect = IntRect(0, 0, 0, 0);
   }
@@ -405,17 +393,18 @@ AlphaBoxBlur::Init(const Rect& aRect,
     }
   }
 }
 
 AlphaBoxBlur::AlphaBoxBlur(const Rect& aRect,
                            int32_t aStride,
                            float aSigmaX,
                            float aSigmaY)
-  : mRect(TruncatedToInt(aRect)),
+  : mRect(int32_t(aRect.x), int32_t(aRect.y),
+          int32_t(aRect.width), int32_t(aRect.height)),
     mSpreadRadius(),
     mBlurRadius(CalculateBlurRadius(Point(aSigmaX, aSigmaY))),
     mStride(aStride),
     mSurfaceAllocationSize(0)
 {
   IntRect intRect;
   if (aRect.ToIntRect(&intRect)) {
     size_t minDataSize = BufferSizeFromStrideAndHeight(intRect.width, intRect.height);
--- a/gfx/2d/Blur.h
+++ b/gfx/2d/Blur.h
@@ -64,24 +64,16 @@ public:
                const Rect* aDirtyRect,
                const Rect* aSkipRect);
 
   AlphaBoxBlur(const Rect& aRect,
                int32_t aStride,
                float aSigmaX,
                float aSigmaY);
 
-  AlphaBoxBlur();
-
-  void Init(const Rect& aRect,
-            const IntSize& aSpreadRadius,
-            const IntSize& aBlurRadius,
-            const Rect* aDirtyRect,
-            const Rect* aSkipRect);
-
   ~AlphaBoxBlur();
 
   /**
    * Return the size, in pixels, of the 8-bit alpha surface we'd use.
    */
   IntSize GetSize();
 
   /**
--- a/gfx/2d/PathHelpers.h
+++ b/gfx/2d/PathHelpers.h
@@ -219,25 +219,16 @@ struct RectCornerRadii {
 
   bool operator==(const RectCornerRadii& aOther) const {
     for (size_t i = 0; i < RectCorner::Count; i++) {
       if (radii[i] != aOther.radii[i]) return false;
     }
     return true;
   }
 
-  bool AreRadiiSame() const {
-    for (size_t i = 1; i < RectCorner::Count; i++) {
-      if (radii[i] != radii[0]) {
-        return false;
-      }
-    }
-    return true;
-  }
-
   void Scale(Float aXScale, Float aYScale) {
     for (int i = 0; i < RectCorner::Count; i++) {
       radii[i].Scale(aXScale, aYScale);
     }
   }
 
   const Size TopLeft() const { return radii[RectCorner::TopLeft]; }
   Size& TopLeft() { return radii[RectCorner::TopLeft]; }
--- a/gfx/thebes/gfxBlur.cpp
+++ b/gfx/thebes/gfxBlur.cpp
@@ -6,88 +6,91 @@
 #include "gfxBlur.h"
 
 #include "gfx2DGlue.h"
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Blur.h"
 #include "mozilla/gfx/PathHelpers.h"
-#include "mozilla/Maybe.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/UniquePtrExtensions.h"
 #include "nsExpirationTracker.h"
 #include "nsClassHashtable.h"
 #include "gfxUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 gfxAlphaBoxBlur::gfxAlphaBoxBlur()
-  : mData(nullptr)
 {
 }
 
 gfxAlphaBoxBlur::~gfxAlphaBoxBlur()
 {
-  if (mData) {
-    free(mData);
-  }
+  mContext = nullptr;
 }
 
-already_AddRefed<gfxContext>
+gfxContext*
 gfxAlphaBoxBlur::Init(const gfxRect& aRect,
                       const IntSize& aSpreadRadius,
                       const IntSize& aBlurRadius,
                       const gfxRect* aDirtyRect,
                       const gfxRect* aSkipRect)
 {
-  Maybe<Rect> dirtyRect = aDirtyRect ? Some(ToRect(*aDirtyRect)) : Nothing();
-  Maybe<Rect> skipRect = aSkipRect ? Some(ToRect(*aSkipRect)) : Nothing();
-  RefPtr<DrawTarget> dt =
-    InitDrawTarget(ToRect(aRect), aSpreadRadius, aBlurRadius,
-                   dirtyRect.ptrOr(nullptr), skipRect.ptrOr(nullptr));
-  if (!dt) {
-    return nullptr;
-  }
+    mozilla::gfx::Rect rect(Float(aRect.x), Float(aRect.y),
+                            Float(aRect.width), Float(aRect.height));
+    IntSize spreadRadius(aSpreadRadius.width, aSpreadRadius.height);
+    IntSize blurRadius(aBlurRadius.width, aBlurRadius.height);
+    UniquePtr<Rect> dirtyRect;
+    if (aDirtyRect) {
+      dirtyRect = MakeUnique<Rect>(Float(aDirtyRect->x),
+                                   Float(aDirtyRect->y),
+                                   Float(aDirtyRect->width),
+                                   Float(aDirtyRect->height));
+    }
+    UniquePtr<Rect> skipRect;
+    if (aSkipRect) {
+      skipRect = MakeUnique<Rect>(Float(aSkipRect->x),
+                                  Float(aSkipRect->y),
+                                  Float(aSkipRect->width),
+                                  Float(aSkipRect->height));
+    }
 
-  RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
-  MOZ_ASSERT(context); // already checked for target above
-  context->SetMatrix(gfxMatrix::Translation(-mBlur.GetRect().TopLeft()));
-  return context.forget();
-}
+    mBlur = MakeUnique<AlphaBoxBlur>(rect, spreadRadius, blurRadius, dirtyRect.get(), skipRect.get());
+    size_t blurDataSize = mBlur->GetSurfaceAllocationSize();
+    if (blurDataSize == 0)
+        return nullptr;
 
-already_AddRefed<DrawTarget>
-gfxAlphaBoxBlur::InitDrawTarget(const Rect& aRect,
-                                const IntSize& aSpreadRadius,
-                                const IntSize& aBlurRadius,
-                                const Rect* aDirtyRect,
-                                const Rect* aSkipRect)
-{
-  mBlur.Init(aRect, aSpreadRadius, aBlurRadius, aDirtyRect, aSkipRect);
-  size_t blurDataSize = mBlur.GetSurfaceAllocationSize();
-  if (blurDataSize == 0) {
-    return nullptr;
-  }
+    IntSize size = mBlur->GetSize();
+
+    // Make an alpha-only surface to draw on. We will play with the data after
+    // everything is drawn to create a blur effect.
+    mData = MakeUniqueFallible<unsigned char[]>(blurDataSize);
+    if (!mData) {
+        return nullptr;
+    }
+    memset(mData.get(), 0, blurDataSize);
 
-  // Make an alpha-only surface to draw on. We will play with the data after
-  // everything is drawn to create a blur effect.
-  mData = static_cast<uint8_t*>(calloc(1, blurDataSize));
-  if (!mData) {
-    return nullptr;
-  }
+    RefPtr<DrawTarget> dt =
+        gfxPlatform::CreateDrawTargetForData(mData.get(), size,
+                                             mBlur->GetStride(),
+                                             SurfaceFormat::A8);
+    if (!dt || !dt->IsValid()) {
+        return nullptr;
+    }
 
-  RefPtr<DrawTarget> dt =
-    gfxPlatform::CreateDrawTargetForData(mData,
-                                         mBlur.GetSize(),
-                                         mBlur.GetStride(),
-                                         SurfaceFormat::A8);
-  if (!dt || !dt->IsValid()) {
-    return nullptr;
-  }
-  dt->SetTransform(Matrix::Translation(-mBlur.GetRect().TopLeft()));
-  return dt.forget();
+    IntRect irect = mBlur->GetRect();
+    gfxPoint topleft(irect.TopLeft().x, irect.TopLeft().y);
+
+    mContext = gfxContext::CreateOrNull(dt);
+    MOZ_ASSERT(mContext); // already checked for target above
+    mContext->SetMatrix(gfxMatrix::Translation(-topleft));
+
+    return mContext;
 }
 
 void
 DrawBlur(gfxContext* aDestinationCtx,
          SourceSurface* aBlur,
          const IntPoint& aTopLeft,
          const Rect* aDirtyRect)
 {
@@ -113,39 +116,39 @@ DrawBlur(gfxContext* aDestinationCtx,
     if (aDirtyRect) {
         dest->PopClip();
     }
 }
 
 already_AddRefed<SourceSurface>
 gfxAlphaBoxBlur::DoBlur(DrawTarget* aDT, IntPoint* aTopLeft)
 {
-    mBlur.Blur(mData);
+    mBlur->Blur(mData.get());
 
-    *aTopLeft = mBlur.GetRect().TopLeft();
+    *aTopLeft = mBlur->GetRect().TopLeft();
 
-    return aDT->CreateSourceSurfaceFromData(mData,
-                                            mBlur.GetSize(),
-                                            mBlur.GetStride(),
+    return aDT->CreateSourceSurfaceFromData(mData.get(),
+                                            mBlur->GetSize(),
+                                            mBlur->GetStride(),
                                             SurfaceFormat::A8);
 }
 
 void
 gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx)
 {
-    if (!mData)
+    if (!mContext)
         return;
 
     DrawTarget *dest = aDestinationCtx->GetDrawTarget();
     if (!dest) {
       NS_WARNING("Blurring not supported for Thebes contexts!");
       return;
     }
 
-    Rect* dirtyRect = mBlur.GetDirtyRect();
+    Rect* dirtyRect = mBlur->GetDirtyRect();
 
     IntPoint topLeft;
     RefPtr<SourceSurface> mask = DoBlur(dest, &topLeft);
     if (!mask) {
       NS_ERROR("Failed to create mask!");
       return;
     }
 
@@ -167,48 +170,51 @@ struct BlurCacheKey : public PLDHashEntr
   IntSize mMinSize;
   IntSize mBlurRadius;
   Color mShadowColor;
   BackendType mBackend;
   RectCornerRadii mCornerRadii;
   bool mIsInset;
 
   // Only used for inset blurs
+  bool mHasBorderRadius;
   IntSize mInnerMinSize;
 
-  BlurCacheKey(const IntSize& aMinSize, const IntSize& aBlurRadius,
-               const RectCornerRadii* aCornerRadii, const Color& aShadowColor,
+  BlurCacheKey(IntSize aMinSize, IntSize aBlurRadius,
+               RectCornerRadii* aCornerRadii, const Color& aShadowColor,
                BackendType aBackendType)
     : BlurCacheKey(aMinSize, IntSize(0, 0),
                    aBlurRadius, aCornerRadii,
                    aShadowColor, false,
-                   aBackendType)
+                   false, aBackendType)
   {}
 
   explicit BlurCacheKey(const BlurCacheKey* aOther)
     : mMinSize(aOther->mMinSize)
     , mBlurRadius(aOther->mBlurRadius)
     , mShadowColor(aOther->mShadowColor)
     , mBackend(aOther->mBackend)
     , mCornerRadii(aOther->mCornerRadii)
     , mIsInset(aOther->mIsInset)
+    , mHasBorderRadius(aOther->mHasBorderRadius)
     , mInnerMinSize(aOther->mInnerMinSize)
   { }
 
-  explicit BlurCacheKey(const IntSize& aOuterMinSize, const IntSize& aInnerMinSize,
-                        const IntSize& aBlurRadius,
+  explicit BlurCacheKey(IntSize aOuterMinSize, IntSize aInnerMinSize,
+                        IntSize aBlurRadius,
                         const RectCornerRadii* aCornerRadii,
                         const Color& aShadowColor, bool aIsInset,
-                        BackendType aBackendType)
+                        bool aHasBorderRadius, BackendType aBackendType)
     : mMinSize(aOuterMinSize)
     , mBlurRadius(aBlurRadius)
     , mShadowColor(aShadowColor)
     , mBackend(aBackendType)
     , mCornerRadii(aCornerRadii ? *aCornerRadii : RectCornerRadii())
     , mIsInset(aIsInset)
+    , mHasBorderRadius(aHasBorderRadius)
     , mInnerMinSize(aInnerMinSize)
   { }
 
   static PLDHashNumber
   HashKey(const KeyTypePointer aKey)
   {
     PLDHashNumber hash = 0;
     hash = AddToHash(hash, aKey->mMinSize.width, aKey->mMinSize.height);
@@ -226,31 +232,33 @@ struct BlurCacheKey : public PLDHashEntr
     for (int i = 0; i < 4; i++) {
       hash = AddToHash(hash, aKey->mCornerRadii[i].width, aKey->mCornerRadii[i].height);
     }
 
     hash = AddToHash(hash, (uint32_t)aKey->mBackend);
 
     if (aKey->mIsInset) {
       hash = AddToHash(hash, aKey->mInnerMinSize.width, aKey->mInnerMinSize.height);
+      hash = AddToHash(hash, HashBytes(&aKey->mHasBorderRadius, sizeof(bool)));
     }
     return hash;
   }
 
   bool
   KeyEquals(KeyTypePointer aKey) const
   {
     if (aKey->mMinSize == mMinSize &&
         aKey->mBlurRadius == mBlurRadius &&
         aKey->mCornerRadii == mCornerRadii &&
         aKey->mShadowColor == mShadowColor &&
         aKey->mBackend == mBackend) {
 
       if (mIsInset) {
-        return (mInnerMinSize == aKey->mInnerMinSize);
+        return (mHasBorderRadius == aKey->mHasBorderRadius) &&
+                (mInnerMinSize == aKey->mInnerMinSize);
       }
 
       return true;
      }
 
      return false;
   }
 
@@ -261,35 +269,35 @@ struct BlurCacheKey : public PLDHashEntr
   }
 };
 
 /**
  * This class is what is cached. It need to be allocated in an object separated
  * to the cache entry to be able to be tracked by the nsExpirationTracker.
  * */
 struct BlurCacheData {
-  BlurCacheData(SourceSurface* aBlur, const IntMargin& aBlurMargin, const BlurCacheKey& aKey)
+  BlurCacheData(SourceSurface* aBlur, IntMargin aExtendDestBy, const BlurCacheKey& aKey)
     : mBlur(aBlur)
-    , mBlurMargin(aBlurMargin)
+    , mExtendDest(aExtendDestBy)
     , mKey(aKey)
   {}
 
   BlurCacheData(const BlurCacheData& aOther)
     : mBlur(aOther.mBlur)
-    , mBlurMargin(aOther.mBlurMargin)
+    , mExtendDest(aOther.mExtendDest)
     , mKey(aOther.mKey)
   { }
 
   nsExpirationState *GetExpirationState() {
     return &mExpirationState;
   }
 
   nsExpirationState mExpirationState;
   RefPtr<SourceSurface> mBlur;
-  IntMargin mBlurMargin;
+  IntMargin mExtendDest;
   BlurCacheKey mKey;
 };
 
 /**
  * This class implements a cache with no maximum size, that retains the
  * SourceSurfaces used to draw the blurs.
  *
  * An entry stays in the cache as long as it is used often.
@@ -303,45 +311,46 @@ class BlurCache final : public nsExpirat
     }
 
     virtual void NotifyExpired(BlurCacheData* aObject)
     {
       RemoveObject(aObject);
       mHashEntries.Remove(aObject->mKey);
     }
 
-    BlurCacheData* Lookup(const IntSize& aMinSize,
+    BlurCacheData* Lookup(const IntSize aMinSize,
                           const IntSize& aBlurRadius,
-                          const RectCornerRadii* aCornerRadii,
+                          RectCornerRadii* aCornerRadii,
                           const Color& aShadowColor,
                           BackendType aBackendType)
     {
       BlurCacheData* blur =
         mHashEntries.Get(BlurCacheKey(aMinSize, aBlurRadius,
                                       aCornerRadii, aShadowColor,
                                       aBackendType));
       if (blur) {
         MarkUsed(blur);
       }
 
       return blur;
     }
 
-    BlurCacheData* LookupInsetBoxShadow(const IntSize& aOuterMinSize,
-                                        const IntSize& aInnerMinSize,
+    BlurCacheData* LookupInsetBoxShadow(const IntSize aOuterMinSize,
+                                        const IntSize aInnerMinSize,
                                         const IntSize& aBlurRadius,
                                         const RectCornerRadii* aCornerRadii,
                                         const Color& aShadowColor,
+                                        const bool& aHasBorderRadius,
                                         BackendType aBackendType)
     {
       bool insetBoxShadow = true;
       BlurCacheKey key(aOuterMinSize, aInnerMinSize,
                        aBlurRadius, aCornerRadii,
                        aShadowColor, insetBoxShadow,
-                       aBackendType);
+                       aHasBorderRadius, aBackendType);
       BlurCacheData* blur = mHashEntries.Get(key);
       if (blur) {
         MarkUsed(blur);
       }
 
       return blur;
     }
 
@@ -369,197 +378,196 @@ class BlurCache final : public nsExpirat
      * https://bugzilla.mozilla.org/show_bug.cgi?id=761393#c47
      */
     nsClassHashtable<BlurCacheKey, BlurCacheData> mHashEntries;
 };
 
 static BlurCache* gBlurCache = nullptr;
 
 static IntSize
-ComputeMinSizeForShadowShape(const RectCornerRadii* aCornerRadii,
-                             const IntSize& aBlurRadius,
-                             IntMargin& aOutSlice,
+ComputeMinSizeForShadowShape(RectCornerRadii* aCornerRadii,
+                             IntSize aBlurRadius,
+                             IntMargin& aSlice,
                              const IntSize& aRectSize)
 {
-  Size cornerSize(0, 0);
+  float cornerWidth = 0;
+  float cornerHeight = 0;
   if (aCornerRadii) {
-    const RectCornerRadii& corners = *aCornerRadii;
-    for (size_t i = 0; i < RectCorner::Count; i++) {
-      cornerSize.width = std::max(cornerSize.width, corners[i].width);
-      cornerSize.height = std::max(cornerSize.height, corners[i].height);
+    RectCornerRadii corners = *aCornerRadii;
+    for (size_t i = 0; i < 4; i++) {
+      cornerWidth = std::max(cornerWidth, corners[i].width);
+      cornerHeight = std::max(cornerHeight, corners[i].height);
     }
   }
 
-  IntSize margin = IntSize::Ceil(cornerSize) + aBlurRadius;
-  aOutSlice = IntMargin(margin.height, margin.width,
-                        margin.height, margin.width);
+  aSlice = IntMargin(ceil(cornerHeight) + aBlurRadius.height,
+                     ceil(cornerWidth) + aBlurRadius.width,
+                     ceil(cornerHeight) + aBlurRadius.height,
+                     ceil(cornerWidth) + aBlurRadius.width);
 
-  IntSize minSize(aOutSlice.LeftRight() + 1,
-                  aOutSlice.TopBottom() + 1);
+  IntSize minSize(aSlice.LeftRight() + 1,
+                      aSlice.TopBottom() + 1);
 
   // If aRectSize is smaller than minSize, the border-image approach won't
   // work; there's no way to squeeze parts of the min box-shadow source
   // image such that the result looks correct. So we need to adjust minSize
   // in such a way that we can later draw it without stretching in the affected
   // dimension. We also need to adjust "slice" to ensure that we're not trying
   // to slice away more than we have.
   if (aRectSize.width < minSize.width) {
     minSize.width = aRectSize.width;
-    aOutSlice.left = 0;
-    aOutSlice.right = 0;
+    aSlice.left = 0;
+    aSlice.right = 0;
   }
   if (aRectSize.height < minSize.height) {
     minSize.height = aRectSize.height;
-    aOutSlice.top = 0;
-    aOutSlice.bottom = 0;
+    aSlice.top = 0;
+    aSlice.bottom = 0;
   }
 
-  MOZ_ASSERT(aOutSlice.LeftRight() <= minSize.width);
-  MOZ_ASSERT(aOutSlice.TopBottom() <= minSize.height);
+  MOZ_ASSERT(aSlice.LeftRight() <= minSize.width);
+  MOZ_ASSERT(aSlice.TopBottom() <= minSize.height);
   return minSize;
 }
 
 void
-CacheBlur(DrawTarget* aDT,
+CacheBlur(DrawTarget& aDT,
           const IntSize& aMinSize,
           const IntSize& aBlurRadius,
-          const RectCornerRadii* aCornerRadii,
+          RectCornerRadii* aCornerRadii,
           const Color& aShadowColor,
-          const IntMargin& aBlurMargin,
+          IntMargin aExtendDest,
           SourceSurface* aBoxShadow)
 {
-  BlurCacheKey key(aMinSize, aBlurRadius, aCornerRadii, aShadowColor, aDT->GetBackendType());
-  BlurCacheData* data = new BlurCacheData(aBoxShadow, aBlurMargin, key);
+  BlurCacheKey key(aMinSize, aBlurRadius, aCornerRadii, aShadowColor, aDT.GetBackendType());
+  BlurCacheData* data = new BlurCacheData(aBoxShadow, aExtendDest, key);
   if (!gBlurCache->RegisterEntry(data)) {
     delete data;
   }
 }
 
 // Blurs a small surface and creates the mask.
 static already_AddRefed<SourceSurface>
-CreateBlurMask(DrawTarget* aDestDrawTarget,
-               const IntSize& aMinSize,
-               const RectCornerRadii* aCornerRadii,
-               const IntSize& aBlurRadius,
-               bool aMirrorCorners,
-               IntMargin& aOutBlurMargin)
+CreateBlurMask(const IntSize& aMinSize,
+               RectCornerRadii* aCornerRadii,
+               IntSize aBlurRadius,
+               IntMargin& aExtendDestBy,
+               IntMargin& aSliceBorder,
+               DrawTarget& aDestDrawTarget)
 {
   gfxAlphaBoxBlur blur;
-  Rect minRect(Point(0, 0), Size(aMinSize));
-  Rect blurRect(minRect);
-  // If mirroring corners, we only need to draw the top-left quadrant.
-  // Use ceil to preserve the remaining 1x1 middle area for minimized box
-  // shadows.
-  if (aMirrorCorners) {
-    blurRect.SizeTo(ceil(blurRect.width * 0.5f), ceil(blurRect.height * 0.5f));
-  }
-  IntSize zeroSpread(0, 0);
-  RefPtr<DrawTarget> blurDT =
-    blur.InitDrawTarget(blurRect, zeroSpread, aBlurRadius);
-  if (!blurDT) {
+  IntRect minRect(IntPoint(), aMinSize);
+
+  gfxContext* blurCtx = blur.Init(ThebesRect(Rect(minRect)), IntSize(),
+                                  aBlurRadius, nullptr, nullptr);
+
+  if (!blurCtx) {
     return nullptr;
   }
 
+  DrawTarget* blurDT = blurCtx->GetDrawTarget();
   ColorPattern black(Color(0.f, 0.f, 0.f, 1.f));
 
   if (aCornerRadii) {
     RefPtr<Path> roundedRect =
-      MakePathForRoundedRect(*blurDT, minRect, *aCornerRadii);
+      MakePathForRoundedRect(*blurDT, Rect(minRect), *aCornerRadii);
     blurDT->Fill(roundedRect, black);
   } else {
-    blurDT->FillRect(minRect, black);
+    blurDT->FillRect(Rect(minRect), black);
   }
 
   IntPoint topLeft;
-  RefPtr<SourceSurface> result = blur.DoBlur(aDestDrawTarget, &topLeft);
+  RefPtr<SourceSurface> result = blur.DoBlur(&aDestDrawTarget, &topLeft);
   if (!result) {
     return nullptr;
   }
 
-  // Since blurRect is at (0, 0), we can find the inflated margin by
-  // negating the new rect origin, which would have been negative if
-  // the rect was inflated.
-  aOutBlurMargin = IntMargin(-topLeft.y, -topLeft.x, -topLeft.y, -topLeft.x);
+  IntRect expandedMinRect(topLeft, result->GetSize());
+  aExtendDestBy = expandedMinRect - minRect;
+  aSliceBorder += aExtendDestBy;
+
+  MOZ_ASSERT(aSliceBorder.LeftRight() <= expandedMinRect.width);
+  MOZ_ASSERT(aSliceBorder.TopBottom() <= expandedMinRect.height);
 
   return result.forget();
 }
 
 static already_AddRefed<SourceSurface>
-CreateBoxShadow(DrawTarget* aDestDT, SourceSurface* aBlurMask, const Color& aShadowColor)
+CreateBoxShadow(DrawTarget& aDestDT, SourceSurface* aBlurMask, const Color& aShadowColor)
 {
   IntSize blurredSize = aBlurMask->GetSize();
   RefPtr<DrawTarget> boxShadowDT =
-    Factory::CreateDrawTarget(aDestDT->GetBackendType(), blurredSize, SurfaceFormat::B8G8R8A8);
+    Factory::CreateDrawTarget(aDestDT.GetBackendType(), blurredSize, SurfaceFormat::B8G8R8A8);
 
   if (!boxShadowDT) {
     return nullptr;
   }
 
   ColorPattern shadowColor(ToDeviceColor(aShadowColor));
   boxShadowDT->MaskSurface(shadowColor, aBlurMask, Point(0, 0));
   return boxShadowDT->Snapshot();
 }
 
 static already_AddRefed<SourceSurface>
 GetBlur(gfxContext* aDestinationCtx,
         const IntSize& aRectSize,
         const IntSize& aBlurRadius,
-        const RectCornerRadii* aCornerRadii,
+        RectCornerRadii* aCornerRadii,
         const Color& aShadowColor,
-        bool aMirrorCorners,
-        IntMargin& aOutBlurMargin,
-        IntMargin& aOutSlice,
-        IntSize& aOutMinSize)
+        IntMargin& aExtendDestBy,
+        IntMargin& aSlice)
 {
   if (!gBlurCache) {
     gBlurCache = new BlurCache();
   }
 
   IntSize minSize =
-    ComputeMinSizeForShadowShape(aCornerRadii, aBlurRadius, aOutSlice, aRectSize);
+    ComputeMinSizeForShadowShape(aCornerRadii, aBlurRadius, aSlice, aRectSize);
 
   // We can get seams using the min size rect when drawing to the destination rect
   // if we have a non-pixel aligned destination transformation. In those cases,
   // fallback to just rendering the destination rect.
   Matrix destMatrix = ToMatrix(aDestinationCtx->CurrentMatrix());
   bool useDestRect = !destMatrix.IsRectilinear() || destMatrix.HasNonIntegerTranslation();
   if (useDestRect) {
     minSize = aRectSize;
   }
-  aOutMinSize = minSize;
 
-  DrawTarget* destDT = aDestinationCtx->GetDrawTarget();
+  DrawTarget& destDT = *aDestinationCtx->GetDrawTarget();
 
-  if (!useDestRect) {
-    BlurCacheData* cached = gBlurCache->Lookup(minSize, aBlurRadius,
-                                               aCornerRadii, aShadowColor,
-                                               destDT->GetBackendType());
-    if (cached) {
-      // See CreateBlurMask() for these values
-      aOutBlurMargin = cached->mBlurMargin;
-      RefPtr<SourceSurface> blur = cached->mBlur;
-      return blur.forget();
-    }
+  BlurCacheData* cached = gBlurCache->Lookup(minSize, aBlurRadius,
+                                             aCornerRadii, aShadowColor,
+                                             destDT.GetBackendType());
+  if (cached && !useDestRect) {
+    // See CreateBlurMask() for these values
+    aExtendDestBy = cached->mExtendDest;
+    aSlice = aSlice + aExtendDestBy;
+    RefPtr<SourceSurface> blur = cached->mBlur;
+    return blur.forget();
   }
 
   RefPtr<SourceSurface> blurMask =
-    CreateBlurMask(destDT, minSize, aCornerRadii, aBlurRadius,
-                   aMirrorCorners, aOutBlurMargin);
+    CreateBlurMask(minSize, aCornerRadii, aBlurRadius, aExtendDestBy, aSlice,
+                   destDT);
+
   if (!blurMask) {
     return nullptr;
   }
 
   RefPtr<SourceSurface> boxShadow = CreateBoxShadow(destDT, blurMask, aShadowColor);
   if (!boxShadow) {
     return nullptr;
   }
 
-  if (!useDestRect) {
+  if (useDestRect) {
+    // Since we're just going to paint the actual rect to the destination
+    aSlice.SizeTo(0, 0, 0, 0);
+  } else {
     CacheBlur(destDT, minSize, aBlurRadius, aCornerRadii, aShadowColor,
-              aOutBlurMargin, boxShadow);
+              aExtendDestBy, boxShadow);
   }
   return boxShadow.forget();
 }
 
 void
 gfxAlphaBoxBlur::ShutdownBlurCache()
 {
   delete gBlurCache;
@@ -567,66 +575,59 @@ gfxAlphaBoxBlur::ShutdownBlurCache()
 }
 
 static Rect
 RectWithEdgesTRBL(Float aTop, Float aRight, Float aBottom, Float aLeft)
 {
   return Rect(aLeft, aTop, aRight - aLeft, aBottom - aTop);
 }
 
-static bool
-ShouldStretchSurface(DrawTarget* aDT, SourceSurface* aSurface)
-{
-  // Use stretching if possible, since it leads to less seams when the
-  // destination is transformed. However, don't do this if we're using cairo,
-  // because if cairo is using pixman it won't render anything for large
-  // stretch factors because pixman's internal fixed point precision is not
-  // high enough to handle those scale factors.
-  // Calling FillRect on a D2D backend with a repeating pattern is much slower
-  // than DrawSurface, so special case the D2D backend here.
-  return (!aDT->GetTransform().IsRectilinear() &&
-          aDT->GetBackendType() != BackendType::CAIRO) ||
-         (aDT->GetBackendType() == BackendType::DIRECT2D1_1);
-}
-
 static void
-RepeatOrStretchSurface(DrawTarget* aDT, SourceSurface* aSurface,
-                       const Rect& aDest, const Rect& aSrc, const Rect& aSkipRect)
+RepeatOrStretchSurface(DrawTarget& aDT, SourceSurface* aSurface,
+                       const Rect& aDest, const Rect& aSrc, Rect& aSkipRect)
 {
   if (aSkipRect.Contains(aDest)) {
     return;
   }
 
-  if (ShouldStretchSurface(aDT, aSurface)) {
-    aDT->DrawSurface(aSurface, aDest, aSrc);
+  if ((!aDT.GetTransform().IsRectilinear() &&
+       aDT.GetBackendType() != BackendType::CAIRO) ||
+      (aDT.GetBackendType() == BackendType::DIRECT2D1_1)) {
+    // Use stretching if possible, since it leads to less seams when the
+    // destination is transformed. However, don't do this if we're using cairo,
+    // because if cairo is using pixman it won't render anything for large
+    // stretch factors because pixman's internal fixed point precision is not
+    // high enough to handle those scale factors.
+    // Calling FillRect on a D2D backend with a repeating pattern is much slower
+    // than DrawSurface, so special case the D2D backend here.
+    aDT.DrawSurface(aSurface, aDest, aSrc);
     return;
   }
 
   SurfacePattern pattern(aSurface, ExtendMode::REPEAT,
                          Matrix::Translation(aDest.TopLeft() - aSrc.TopLeft()),
                          SamplingFilter::GOOD, RoundedToInt(aSrc));
-  aDT->FillRect(aDest, pattern);
+  aDT.FillRect(aDest, pattern);
 }
 
 static void
-DrawCorner(DrawTarget* aDT, SourceSurface* aSurface,
-           const Rect& aDest, const Rect& aSrc, const Rect& aSkipRect)
+DrawCorner(DrawTarget& aDT, SourceSurface* aSurface,
+           const Rect& aDest, const Rect& aSrc, Rect& aSkipRect)
 {
   if (aSkipRect.Contains(aDest)) {
     return;
   }
 
-  aDT->DrawSurface(aSurface, aDest, aSrc);
+  aDT.DrawSurface(aSurface, aDest, aSrc);
 }
 
 static void
-DrawMinBoxShadow(DrawTarget* aDestDrawTarget, SourceSurface* aSourceBlur,
-                 const Rect& aDstOuter, const Rect& aDstInner,
-                 const Rect& aSrcOuter, const Rect& aSrcInner,
-                 const Rect& aSkipRect)
+DrawBoxShadows(DrawTarget& aDestDrawTarget, SourceSurface* aSourceBlur,
+               Rect aDstOuter, Rect aDstInner, Rect aSrcOuter, Rect aSrcInner,
+               Rect aSkipRect)
 {
   // Corners: top left, top right, bottom left, bottom right
   DrawCorner(aDestDrawTarget, aSourceBlur,
              RectWithEdgesTRBL(aDstOuter.Y(), aDstInner.X(),
                                aDstInner.Y(), aDstOuter.X()),
              RectWithEdgesTRBL(aSrcOuter.Y(), aSrcInner.X(),
                                aSrcInner.Y(), aSrcOuter.X()),
                                aSkipRect);
@@ -675,205 +676,74 @@ DrawMinBoxShadow(DrawTarget* aDestDrawTa
   RepeatOrStretchSurface(aDestDrawTarget, aSourceBlur,
                          RectWithEdgesTRBL(aDstInner.YMost(), aDstInner.XMost(),
                                            aDstOuter.YMost(), aDstInner.X()),
                          RectWithEdgesTRBL(aSrcInner.YMost(), aSrcInner.XMost(),
                                            aSrcOuter.YMost(), aSrcInner.X()),
                          aSkipRect);
 }
 
-static void
-DrawMirroredRect(DrawTarget* aDT,
-                 SourceSurface* aSurface,
-                 const Rect& aDest, const Point& aSrc,
-                 Float aScaleX, Float aScaleY)
-{
-  SurfacePattern pattern(aSurface, ExtendMode::CLAMP,
-                         Matrix::Scaling(aScaleX, aScaleY)
-                           .PreTranslate(-aSrc)
-                           .PostTranslate(
-                             aScaleX < 0 ? aDest.XMost() : aDest.x,
-                             aScaleY < 0 ? aDest.YMost() : aDest.y));
-  aDT->FillRect(aDest, pattern);
-}
-
-static void
-DrawMirroredBoxShadow(DrawTarget* aDT,
-                      SourceSurface* aSurface,
-                      const Rect& aDestRect)
-{
-  Rect topLeft(aDestRect.x, aDestRect.y,
-               ceil(aDestRect.x + aDestRect.width / 2) - aDestRect.x,
-               ceil(aDestRect.y + aDestRect.height / 2) - aDestRect.y);
-  Rect bottomRight(topLeft.BottomRight(), aDestRect.Size() - topLeft.Size());
-  Rect topRight(bottomRight.x, topLeft.y, bottomRight.width, topLeft.height);
-  Rect bottomLeft(topLeft.x, bottomRight.y, topLeft.width, bottomRight.height);
-  DrawMirroredRect(aDT, aSurface, topLeft, Point(), 1, 1);
-  DrawMirroredRect(aDT, aSurface, topRight, Point(), -1, 1);
-  DrawMirroredRect(aDT, aSurface, bottomLeft, Point(), 1, -1);
-  DrawMirroredRect(aDT, aSurface, bottomRight, Point(), -1, -1);
-}
-
-static void
-DrawMirroredCorner(DrawTarget* aDT, SourceSurface* aSurface,
-                   const Rect& aDest, const Point& aSrc,
-                   const Rect& aSkipRect, Float aScaleX, Float aScaleY)
-{
-  if (aSkipRect.Contains(aDest)) {
-    return;
-  }
-
-  DrawMirroredRect(aDT, aSurface, aDest, aSrc, aScaleX, aScaleY);
-}
-
-static void
-RepeatOrStretchMirroredSurface(DrawTarget* aDT, SourceSurface* aSurface,
-                               const Rect& aDest, const Rect& aSrc,
-                               const Rect& aSkipRect, Float aScaleX, Float aScaleY)
-{
-  if (aSkipRect.Contains(aDest)) {
-    return;
-  }
-
-  if (ShouldStretchSurface(aDT, aSurface)) {
-    aScaleX *= aDest.width / aSrc.width;
-    aScaleY *= aDest.height / aSrc.height;
-    DrawMirroredRect(aDT, aSurface, aDest, aSrc.TopLeft(), aScaleX, aScaleY);
-    return;
-  }
-
-  SurfacePattern pattern(aSurface, ExtendMode::REPEAT,
-                         Matrix::Scaling(aScaleX, aScaleY)
-                           .PreTranslate(-aSrc.TopLeft())
-                           .PostTranslate(
-                             aScaleX < 0 ? aDest.XMost() : aDest.x,
-                             aScaleY < 0 ? aDest.YMost() : aDest.y),
-                         SamplingFilter::GOOD, RoundedToInt(aSrc));
-  aDT->FillRect(aDest, pattern);
-}
-
-static void
-DrawMirroredMinBoxShadow(DrawTarget* aDestDrawTarget, SourceSurface* aSourceBlur,
-                         const Rect& aDstOuter, const Rect& aDstInner,
-                         const Rect& aSrcOuter, const Rect& aSrcInner,
-                         const Rect& aSkipRect)
-{
-  // Corners: top left, top right, bottom left, bottom right
-  DrawMirroredCorner(aDestDrawTarget, aSourceBlur,
-                     RectWithEdgesTRBL(aDstOuter.Y(), aDstInner.X(),
-                                       aDstInner.Y(), aDstOuter.X()),
-                     aSrcOuter.TopLeft(), aSkipRect, 1, 1);
-  DrawMirroredCorner(aDestDrawTarget, aSourceBlur,
-                     RectWithEdgesTRBL(aDstOuter.Y(), aDstOuter.XMost(),
-                                       aDstInner.Y(), aDstInner.XMost()),
-                     aSrcOuter.TopLeft(), aSkipRect, -1, 1);
-  DrawMirroredCorner(aDestDrawTarget, aSourceBlur,
-                     RectWithEdgesTRBL(aDstInner.YMost(), aDstInner.X(),
-                                       aDstOuter.YMost(), aDstOuter.X()),
-                     aSrcOuter.TopLeft(), aSkipRect, 1, -1);
-  DrawMirroredCorner(aDestDrawTarget, aSourceBlur,
-                     RectWithEdgesTRBL(aDstInner.YMost(), aDstOuter.XMost(),
-                                       aDstOuter.YMost(), aDstInner.XMost()),
-                     aSrcOuter.TopLeft(), aSkipRect, -1, -1);
-
-  // Edges: top, left, right, bottom
-  RepeatOrStretchMirroredSurface(aDestDrawTarget, aSourceBlur,
-                         RectWithEdgesTRBL(aDstOuter.Y(), aDstInner.XMost(),
-                                           aDstInner.Y(), aDstInner.X()),
-                         RectWithEdgesTRBL(aSrcOuter.Y(), aSrcInner.XMost(),
-                                           aSrcInner.Y(), aSrcInner.X()),
-                         aSkipRect, 1, 1);
-  RepeatOrStretchMirroredSurface(aDestDrawTarget, aSourceBlur,
-                         RectWithEdgesTRBL(aDstInner.Y(), aDstInner.X(),
-                                           aDstInner.YMost(), aDstOuter.X()),
-                         RectWithEdgesTRBL(aSrcInner.Y(), aSrcInner.X(),
-                                           aSrcInner.YMost(), aSrcOuter.X()),
-                         aSkipRect, 1, 1);
-  RepeatOrStretchMirroredSurface(aDestDrawTarget, aSourceBlur,
-                         RectWithEdgesTRBL(aDstInner.Y(), aDstOuter.XMost(),
-                                           aDstInner.YMost(), aDstInner.XMost()),
-                         RectWithEdgesTRBL(aSrcInner.Y(), aSrcInner.X(),
-                                           aSrcInner.YMost(), aSrcOuter.X()),
-                         aSkipRect, -1, 1);
-  RepeatOrStretchMirroredSurface(aDestDrawTarget, aSourceBlur,
-                         RectWithEdgesTRBL(aDstInner.YMost(), aDstInner.XMost(),
-                                           aDstOuter.YMost(), aDstInner.X()),
-                         RectWithEdgesTRBL(aSrcOuter.Y(), aSrcInner.XMost(),
-                                           aSrcInner.Y(), aSrcInner.X()),
-                         aSkipRect, 1, -1);
-}
-
 /***
  * We draw a blurred a rectangle by only blurring a smaller rectangle and
  * splitting the rectangle into 9 parts.
  * First, a small minimum source rect is calculated and used to create a blur
  * mask since the actual blurring itself is expensive. Next, we use the mask
  * with the given shadow color to create a minimally-sized box shadow of the
  * right color. Finally, we cut out the 9 parts from the box-shadow source and
  * paint each part in the right place, stretching the non-corner parts to fill
  * the space between the corners.
  */
 
 /* static */ void
 gfxAlphaBoxBlur::BlurRectangle(gfxContext* aDestinationCtx,
                                const gfxRect& aRect,
-                               const RectCornerRadii* aCornerRadii,
+                               RectCornerRadii* aCornerRadii,
                                const gfxPoint& aBlurStdDev,
                                const Color& aShadowColor,
                                const gfxRect& aDirtyRect,
                                const gfxRect& aSkipRect)
 {
   IntSize blurRadius = CalculateBlurRadius(aBlurStdDev);
-  bool mirrorCorners = !aCornerRadii || aCornerRadii->AreRadiiSame();
 
   IntRect rect = RoundedToInt(ToRect(aRect));
-  IntMargin blurMargin;
+  IntMargin extendDestBy;
   IntMargin slice;
-  IntSize minSize;
+
   RefPtr<SourceSurface> boxShadow = GetBlur(aDestinationCtx,
                                             rect.Size(), blurRadius,
-                                            aCornerRadii, aShadowColor, mirrorCorners,
-                                            blurMargin, slice, minSize);
+                                            aCornerRadii, aShadowColor,
+                                            extendDestBy, slice);
   if (!boxShadow) {
     return;
   }
 
-  DrawTarget* destDrawTarget = aDestinationCtx->GetDrawTarget();
-  destDrawTarget->PushClipRect(ToRect(aDirtyRect));
+  DrawTarget& destDrawTarget = *aDestinationCtx->GetDrawTarget();
+  destDrawTarget.PushClipRect(ToRect(aDirtyRect));
 
   // Copy the right parts from boxShadow into destDrawTarget. The middle parts
   // will be stretched, border-image style.
 
-  Rect srcOuter(Point(blurMargin.left, blurMargin.top), Size(minSize));
-  Rect srcInner(srcOuter);
-  srcOuter.Inflate(Margin(blurMargin));
+  Rect srcOuter(Point(), Size(boxShadow->GetSize()));
+  Rect srcInner = srcOuter;
   srcInner.Deflate(Margin(slice));
 
+  rect.Inflate(extendDestBy);
   Rect dstOuter(rect);
   Rect dstInner(rect);
-  dstOuter.Inflate(Margin(blurMargin));
   dstInner.Deflate(Margin(slice));
 
   Rect skipRect = ToRect(aSkipRect);
 
-  if (minSize == rect.Size()) {
+  if (srcInner.IsEqualInterior(srcOuter)) {
+    MOZ_ASSERT(dstInner.IsEqualInterior(dstOuter));
     // The target rect is smaller than the minimal size so just draw the surface
-    if (mirrorCorners) {
-      DrawMirroredBoxShadow(destDrawTarget, boxShadow, dstOuter);
-    } else {
-      destDrawTarget->DrawSurface(boxShadow, dstOuter, srcOuter);
-    }
+    destDrawTarget.DrawSurface(boxShadow, dstInner, srcInner);
   } else {
-    if (mirrorCorners) {
-      DrawMirroredMinBoxShadow(destDrawTarget, boxShadow, dstOuter, dstInner,
-                               srcOuter, srcInner, skipRect);
-    } else {
-      DrawMinBoxShadow(destDrawTarget, boxShadow, dstOuter, dstInner,
-                       srcOuter, srcInner, skipRect);
-    }
+    DrawBoxShadows(destDrawTarget, boxShadow, dstOuter, dstInner,
+                   srcOuter, srcInner, skipRect);
 
     // Middle part
     RepeatOrStretchSurface(destDrawTarget, boxShadow,
                            RectWithEdgesTRBL(dstInner.Y(), dstInner.XMost(),
                                              dstInner.YMost(), dstInner.X()),
                            RectWithEdgesTRBL(srcInner.Y(), srcInner.XMost(),
                                              srcInner.YMost(), srcInner.X()),
                            skipRect);
@@ -891,23 +761,23 @@ gfxAlphaBoxBlur::BlurRectangle(gfxContex
   // we have a way to say "Please anti-alias the clip, but don't antialias the
   // destination rect of the DrawSurface call".
   // On OS X there is an additional problem with turning off AA: CoreGraphics
   // will not just fill the pixels that have their pixel center inside the
   // filled shape. Instead, it will fill all the pixels which are partially
   // covered by the shape. So for pixels on the edge between two adjacent parts,
   // all those pixels will be painted to by both parts, which looks very bad.
 
-  destDrawTarget->PopClip();
+  destDrawTarget.PopClip();
 }
 
 static already_AddRefed<Path>
 GetBoxShadowInsetPath(DrawTarget* aDrawTarget,
                       const Rect aOuterRect, const Rect aInnerRect,
-                      const RectCornerRadii* aInnerClipRadii)
+                      const bool aHasBorderRadius, const RectCornerRadii& aInnerClipRadii)
 {
   /***
    * We create an inset path by having two rects.
    *
    *  -----------------------
    *  |  ________________   |
    *  | |                |  |
    *  | |                |  |
@@ -916,143 +786,147 @@ GetBoxShadowInsetPath(DrawTarget* aDrawT
    *
    * The outer rect and the inside rect. The path
    * creates a frame around the content where we draw the inset shadow.
    */
   RefPtr<PathBuilder> builder =
     aDrawTarget->CreatePathBuilder(FillRule::FILL_EVEN_ODD);
   AppendRectToPath(builder, aOuterRect, true);
 
-  if (aInnerClipRadii) {
-    AppendRoundedRectToPath(builder, aInnerRect, *aInnerClipRadii, false);
+  if (aHasBorderRadius) {
+    AppendRoundedRectToPath(builder, aInnerRect, aInnerClipRadii, false);
   } else {
     AppendRectToPath(builder, aInnerRect, false);
   }
   return builder->Finish();
 }
 
 static void
 FillDestinationPath(gfxContext* aDestinationCtx,
-                    const Rect& aDestinationRect,
-                    const Rect& aShadowClipRect,
+                    const Rect aDestinationRect,
+                    const Rect aShadowClipRect,
                     const Color& aShadowColor,
-                    const RectCornerRadii* aInnerClipRadii = nullptr)
+                    const bool aHasBorderRadius,
+                    const RectCornerRadii& aInnerClipRadii)
 {
   // When there is no blur radius, fill the path onto the destination
   // surface.
   aDestinationCtx->SetColor(aShadowColor);
   DrawTarget* destDrawTarget = aDestinationCtx->GetDrawTarget();
   RefPtr<Path> shadowPath = GetBoxShadowInsetPath(destDrawTarget, aDestinationRect,
-                                                  aShadowClipRect, aInnerClipRadii);
+                                                  aShadowClipRect, aHasBorderRadius,
+                                                  aInnerClipRadii);
 
   aDestinationCtx->SetPath(shadowPath);
   aDestinationCtx->Fill();
 }
 
 static void
-CacheInsetBlur(const IntSize& aMinOuterSize,
-               const IntSize& aMinInnerSize,
+CacheInsetBlur(const IntSize aMinOuterSize,
+               const IntSize aMinInnerSize,
                const IntSize& aBlurRadius,
                const RectCornerRadii* aCornerRadii,
                const Color& aShadowColor,
+               const bool& aHasBorderRadius,
                BackendType aBackendType,
                SourceSurface* aBoxShadow)
 {
   bool isInsetBlur = true;
   BlurCacheKey key(aMinOuterSize, aMinInnerSize,
                    aBlurRadius, aCornerRadii,
                    aShadowColor, isInsetBlur,
-                   aBackendType);
-  IntMargin blurMargin(0, 0, 0, 0);
-  BlurCacheData* data = new BlurCacheData(aBoxShadow, blurMargin, key);
+                   aHasBorderRadius, aBackendType);
+  IntMargin extendDestBy(0, 0, 0, 0);
+  BlurCacheData* data = new BlurCacheData(aBoxShadow, extendDestBy, key);
   if (!gBlurCache->RegisterEntry(data)) {
     delete data;
   }
 }
 
-already_AddRefed<SourceSurface>
-gfxAlphaBoxBlur::GetInsetBlur(const Rect& aOuterRect,
-                              const Rect& aWhitespaceRect,
-                              bool aIsDestRect,
-                              const Color& aShadowColor,
-                              const IntSize& aBlurRadius,
-                              const RectCornerRadii* aInnerClipRadii,
-                              DrawTarget* aDestDrawTarget,
-                              bool aMirrorCorners)
+already_AddRefed<mozilla::gfx::SourceSurface>
+gfxAlphaBoxBlur::GetInsetBlur(const mozilla::gfx::Rect aOuterRect,
+                              const mozilla::gfx::Rect aWhitespaceRect,
+                              const bool aIsDestRect,
+                              const mozilla::gfx::Color& aShadowColor,
+                              const mozilla::gfx::IntSize& aBlurRadius,
+                              const bool aHasBorderRadius,
+                              const RectCornerRadii& aInnerClipRadii,
+                              DrawTarget* aDestDrawTarget)
 {
   if (!gBlurCache) {
     gBlurCache = new BlurCache();
   }
 
-  IntSize outerSize = IntSize::Truncate(aOuterRect.Size());
-  IntSize whitespaceSize = IntSize::Truncate(aWhitespaceRect.Size());
-  if (!aIsDestRect) {
-    BlurCacheData* cached =
+  IntSize outerSize((int)aOuterRect.width, (int)aOuterRect.height);
+  IntSize whitespaceSize((int)aWhitespaceRect.width, (int)aWhitespaceRect.height);
+  BlurCacheData* cached =
       gBlurCache->LookupInsetBoxShadow(outerSize, whitespaceSize,
-                                       aBlurRadius, aInnerClipRadii,
-                                       aShadowColor, aDestDrawTarget->GetBackendType());
-    if (cached) {
-      // So we don't forget the actual cached blur
-      RefPtr<SourceSurface> cachedBlur = cached->mBlur;
-      return cachedBlur.forget();
-    }
+                                       aBlurRadius, &aInnerClipRadii,
+                                       aShadowColor, aHasBorderRadius,
+                                       aDestDrawTarget->GetBackendType());
+
+  if (cached && !aIsDestRect) {
+    // So we don't forget the actual cached blur
+    RefPtr<SourceSurface> cachedBlur = cached->mBlur;
+    return cachedBlur.forget();
   }
 
   // If we can do a min rect, the whitespace rect will be expanded in Init to
   // aOuterRect.
   Rect blurRect = aIsDestRect ? aOuterRect : aWhitespaceRect;
-  // If mirroring corners, we only need to draw the top-left quadrant.
-  // Use ceil to preserve the remaining 1x1 middle area for minimized box
-  // shadows.
-  if (aMirrorCorners) {
-    blurRect.SizeTo(ceil(blurRect.width * 0.5f), ceil(blurRect.height * 0.5f));
-  }
   IntSize zeroSpread(0, 0);
-  RefPtr<DrawTarget> minDrawTarget =
-    InitDrawTarget(blurRect, zeroSpread, aBlurRadius);
-  if (!minDrawTarget) {
+  gfxContext* minGfxContext = Init(ThebesRect(blurRect),
+                                   zeroSpread, aBlurRadius,
+                                   nullptr, nullptr);
+  if (!minGfxContext) {
     return nullptr;
   }
 
-  // This is really annoying. When we create the AlphaBoxBlur, the DrawTarget
+  // This is really annoying. When we create the AlphaBoxBlur, the gfxContext
   // has a translation applied to it that is the topLeft point. This is actually
   // the rect we gave it plus the blur radius. The rects we give this for the outer
   // and whitespace rects are based at (0, 0). We could either translate those rects
   // when we don't have a destination rect or ignore the translation when using
   // the dest rect. The dest rects layout gives us expect this translation.
   if (!aIsDestRect) {
-    minDrawTarget->SetTransform(Matrix());
+    minGfxContext->SetMatrix(gfxMatrix());
   }
 
+  DrawTarget* minDrawTarget = minGfxContext->GetDrawTarget();
+
   // Fill in the path between the inside white space / outer rects
   // NOT the inner frame
   RefPtr<Path> maskPath =
     GetBoxShadowInsetPath(minDrawTarget, aOuterRect,
-                          aWhitespaceRect, aInnerClipRadii);
+                          aWhitespaceRect, aHasBorderRadius,
+                          aInnerClipRadii);
 
-  ColorPattern black(Color(0.f, 0.f, 0.f, 1.f));
-  minDrawTarget->Fill(maskPath, black);
+  Color black(0.f, 0.f, 0.f, 1.f);
+  minGfxContext->SetColor(black);
+  minGfxContext->SetPath(maskPath);
+  minGfxContext->Fill();
 
   // Create the A8 mask
   IntPoint topLeft;
   RefPtr<SourceSurface> minMask = DoBlur(minDrawTarget, &topLeft);
   if (!minMask) {
     return nullptr;
   }
 
   // Fill in with the color we actually wanted
-  RefPtr<SourceSurface> minInsetBlur = CreateBoxShadow(aDestDrawTarget, minMask, aShadowColor);
+  RefPtr<SourceSurface> minInsetBlur = CreateBoxShadow(*aDestDrawTarget, minMask, aShadowColor);
   if (!minInsetBlur) {
     return nullptr;
   }
 
   if (!aIsDestRect) {
     CacheInsetBlur(outerSize, whitespaceSize,
-                   aBlurRadius, aInnerClipRadii,
-                   aShadowColor, aDestDrawTarget->GetBackendType(),
+                   aBlurRadius, &aInnerClipRadii,
+                   aShadowColor, aHasBorderRadius,
+                   aDestDrawTarget->GetBackendType(),
                    minInsetBlur);
   }
 
   return minInsetBlur.forget();
 }
 
 /***
  * We create our minimal rect with 2 rects.
@@ -1072,45 +946,46 @@ gfxAlphaBoxBlur::GetInsetBlur(const Rect
  * |          |             |       |
  * |      (2) |    (1)      |  (2)  |
  * |       B  |     W       |   B   |
  * |          |             |       |
  * |          |             |       |
  * |          |                     |
  * |________________________________|
  */
-static void GetBlurMargins(const RectCornerRadii* aInnerClipRadii,
-                           const IntSize& aBlurRadius,
+static void GetBlurMargins(const bool aHasBorderRadius,
+                           const RectCornerRadii& aInnerClipRadii,
+                           const IntSize aBlurRadius,
                            Margin& aOutBlurMargin,
                            Margin& aOutInnerMargin)
 {
-  Size cornerSize(0, 0);
-  if (aInnerClipRadii) {
-    const RectCornerRadii& corners = *aInnerClipRadii;
-    for (size_t i = 0; i < RectCorner::Count; i++) {
-      cornerSize.width = std::max(cornerSize.width, corners[i].width);
-      cornerSize.height = std::max(cornerSize.height, corners[i].height);
+  float cornerWidth = 0;
+  float cornerHeight = 0;
+  if (aHasBorderRadius) {
+    for (size_t i = 0; i < 4; i++) {
+      cornerWidth = std::max(cornerWidth, aInnerClipRadii[i].width);
+      cornerHeight = std::max(cornerHeight, aInnerClipRadii[i].height);
     }
   }
 
   // Only the inside whitespace size cares about the border radius size.
   // Outer sizes only care about blur.
-  IntSize margin = IntSize::Ceil(cornerSize) + aBlurRadius;
+  int width = cornerWidth + aBlurRadius.width;
+  int height = cornerHeight + aBlurRadius.height;
 
-  aOutInnerMargin.SizeTo(margin.height, margin.width,
-                         margin.height, margin.width);
+  aOutInnerMargin.SizeTo(height, width, height, width);
   aOutBlurMargin.SizeTo(aBlurRadius.height, aBlurRadius.width,
                         aBlurRadius.height, aBlurRadius.width);
 }
 
 static bool
-GetInsetBoxShadowRects(const Margin& aBlurMargin,
-                       const Margin& aInnerMargin,
-                       const Rect& aShadowClipRect,
-                       const Rect& aDestinationRect,
+GetInsetBoxShadowRects(const Margin aBlurMargin,
+                       const Margin aInnerMargin,
+                       const Rect aShadowClipRect,
+                       const Rect aDestinationRect,
                        Rect& aOutWhitespaceRect,
                        Rect& aOutOuterRect)
 {
   // We always copy (2 * blur radius) + corner radius worth of data to the destination rect
   // This covers the blend of the path + the actual blur
   // Need +1 so that we copy the edges correctly as we'll copy
   // over the min box shadow corners then the +1 for the edges between
   // Note, the (x,y) coordinates are from the blur margin
@@ -1135,85 +1010,79 @@ GetInsetBoxShadowRects(const Margin& aBl
     aOutOuterRect.Inflate(aBlurMargin);
   }
 
   return useDestRect;
 }
 
 void
 gfxAlphaBoxBlur::BlurInsetBox(gfxContext* aDestinationCtx,
-                              const Rect& aDestinationRect,
-                              const Rect& aShadowClipRect,
-                              const IntSize& aBlurRadius,
+                              const Rect aDestinationRect,
+                              const Rect aShadowClipRect,
+                              const IntSize aBlurRadius,
+                              const IntSize aSpreadRadius,
                               const Color& aShadowColor,
-                              const RectCornerRadii* aInnerClipRadii,
-                              const Rect& aSkipRect,
-                              const Point& aShadowOffset)
+                              bool aHasBorderRadius,
+                              const RectCornerRadii& aInnerClipRadii,
+                              const Rect aSkipRect,
+                              const Point aShadowOffset)
 {
   if ((aBlurRadius.width == 0 && aBlurRadius.height == 0)
       || aShadowClipRect.IsEmpty()) {
     FillDestinationPath(aDestinationCtx, aDestinationRect, aShadowClipRect,
-        aShadowColor, aInnerClipRadii);
+        aShadowColor, aHasBorderRadius, aInnerClipRadii);
     return;
   }
 
   DrawTarget* destDrawTarget = aDestinationCtx->GetDrawTarget();
 
   Margin innerMargin;
   Margin blurMargin;
-  GetBlurMargins(aInnerClipRadii, aBlurRadius, blurMargin, innerMargin);
+  GetBlurMargins(aHasBorderRadius, aInnerClipRadii, aBlurRadius,
+                 blurMargin, innerMargin);
 
   Rect whitespaceRect;
   Rect outerRect;
-  bool useDestRect =
-    GetInsetBoxShadowRects(blurMargin, innerMargin, aShadowClipRect,
-                           aDestinationRect, whitespaceRect, outerRect);
+  bool useDestRect = GetInsetBoxShadowRects(blurMargin, innerMargin, aShadowClipRect,
+                                            aDestinationRect, whitespaceRect, outerRect);
 
-  bool mirrorCorners = !aInnerClipRadii || aInnerClipRadii->AreRadiiSame();
-  RefPtr<SourceSurface> minBlur =
-    GetInsetBlur(outerRect, whitespaceRect, useDestRect, aShadowColor,
-                 aBlurRadius, aInnerClipRadii, destDrawTarget, mirrorCorners);
+  RefPtr<SourceSurface> minBlur = GetInsetBlur(outerRect, whitespaceRect, useDestRect, aShadowColor,
+                                               aBlurRadius, aHasBorderRadius, aInnerClipRadii,
+                                               destDrawTarget);
   if (!minBlur) {
     return;
   }
 
   if (useDestRect) {
+    IntSize blurSize = minBlur->GetSize();
+    Rect srcBlur(0, 0, blurSize.width, blurSize.height);
     Rect destBlur = aDestinationRect;
+
+    // The blur itself expands the rect by the blur margin, so we
+    // have to mimic that here.
     destBlur.Inflate(blurMargin);
-    if (mirrorCorners) {
-      DrawMirroredBoxShadow(destDrawTarget, minBlur.get(), destBlur);
-    } else {
-      Rect srcBlur(Point(0, 0), Size(minBlur->GetSize()));
-      MOZ_ASSERT(srcBlur.Size() == destBlur.Size());
-      destDrawTarget->DrawSurface(minBlur, destBlur, srcBlur);
-    }
+    MOZ_ASSERT(srcBlur.Size() == destBlur.Size());
+    destDrawTarget->DrawSurface(minBlur, destBlur, srcBlur);
   } else {
     Rect srcOuter(outerRect);
     Rect srcInner(srcOuter);
     srcInner.Deflate(blurMargin);   // The outer color fill
     srcInner.Deflate(innerMargin);  // The inner whitespace
 
     // The shadow clip rect already takes into account the spread radius
     Rect outerFillRect(aShadowClipRect);
     outerFillRect.Inflate(blurMargin);
-    FillDestinationPath(aDestinationCtx, aDestinationRect, outerFillRect, aShadowColor);
+    FillDestinationPath(aDestinationCtx, aDestinationRect, outerFillRect, aShadowColor, false, RectCornerRadii());
 
     // Inflate once for the frame around the whitespace
     Rect destRect(aShadowClipRect);
     destRect.Inflate(blurMargin);
 
     // Deflate for the blurred in white space
     Rect destInnerRect(aShadowClipRect);
     destInnerRect.Deflate(innerMargin);
 
-    if (mirrorCorners) {
-      DrawMirroredMinBoxShadow(destDrawTarget, minBlur,
-                               destRect, destInnerRect,
-                               srcOuter, srcInner,
-                               aSkipRect);
-    } else {
-      DrawMinBoxShadow(destDrawTarget, minBlur,
-                       destRect, destInnerRect,
-                       srcOuter, srcInner,
-                       aSkipRect);
-    }
+    DrawBoxShadows(*destDrawTarget, minBlur,
+                   destRect, destInnerRect,
+                   srcOuter, srcInner,
+                   aSkipRect);
   }
 }
--- a/gfx/thebes/gfxBlur.h
+++ b/gfx/thebes/gfxBlur.h
@@ -5,23 +5,24 @@
 
 #ifndef GFX_BLUR_H
 #define GFX_BLUR_H
 
 #include "gfxTypes.h"
 #include "nsSize.h"
 #include "gfxPoint.h"
 #include "mozilla/RefPtr.h"
-#include "mozilla/gfx/Blur.h"
+#include "mozilla/UniquePtr.h"
 
 class gfxContext;
 struct gfxRect;
 
 namespace mozilla {
   namespace gfx {
+    class AlphaBoxBlur;
     struct Color;
     struct RectCornerRadii;
     class SourceSurface;
     class DrawTarget;
   } // namespace gfx
 } // namespace mozilla
 
 /**
@@ -67,29 +68,31 @@ public:
      * @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 nullptr 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 nullptr here.
      */
-    already_AddRefed<gfxContext>
-    Init(const gfxRect& aRect,
-         const mozilla::gfx::IntSize& aSpreadRadius,
-         const mozilla::gfx::IntSize& aBlurRadius,
-         const gfxRect* aDirtyRect,
-         const gfxRect* aSkipRect);
+    gfxContext* Init(const gfxRect& aRect,
+                     const mozilla::gfx::IntSize& aSpreadRadius,
+                     const mozilla::gfx::IntSize& aBlurRadius,
+                     const gfxRect* aDirtyRect,
+                     const gfxRect* aSkipRect);
 
-    already_AddRefed<DrawTarget>
-    InitDrawTarget(const mozilla::gfx::Rect& aRect,
-                   const mozilla::gfx::IntSize& aSpreadRadius,
-                   const mozilla::gfx::IntSize& aBlurRadius,
-                   const mozilla::gfx::Rect* aDirtyRect = nullptr,
-                   const mozilla::gfx::Rect* aSkipRect = nullptr);
+    /**
+     * Returns the context that should be drawn to supply the alpha mask to be
+     * blurred. If the returned surface is null, then there was an error in
+     * its creation.
+     */
+    gfxContext* GetContext()
+    {
+        return mContext;
+    }
 
     already_AddRefed<mozilla::gfx::SourceSurface>
     DoBlur(DrawTarget* aDT, mozilla::gfx::IntPoint* aTopLeft);
 
     /**
      * Does the actual blurring/spreading and mask applying. Users of this
      * object must have drawn whatever they want to be blurred onto the internal
      * gfxContext returned by GetContext before calling this.
@@ -121,17 +124,17 @@ public:
      * @param aShadowColor         The color to draw the blurred shadow.
      * @param aDirtyRect           An area in device pixels that is dirty and needs
      *                             to be redrawn.
      * @param aSkipRect            An area in device pixels to avoid blurring over,
      *                             to prevent unnecessary work.
      */
     static void BlurRectangle(gfxContext *aDestinationCtx,
                               const gfxRect& aRect,
-                              const RectCornerRadii* aCornerRadii,
+                              RectCornerRadii* aCornerRadii,
                               const gfxPoint& aBlurStdDev,
                               const Color& aShadowColor,
                               const gfxRect& aDirtyRect,
                               const gfxRect& aSkipRect);
 
     static void ShutdownBlurCache();
 
     /***
@@ -139,44 +142,53 @@ public:
      * This is equivalent to calling Init(), drawing the inset path,
      * and calling paint. Do not call Init() if using this method.
      *
      * @param aDestinationCtx     The destination to blur to.
      * @param aDestinationRect    The destination rect in device pixels
      * @param aShadowClipRect     The destiniation inner rect of the
      *                            inset path in device pixels.
      * @param aBlurRadius         The standard deviation of the blur.
+     * @param aSpreadRadius       The spread radius in device pixels.
      * @param aShadowColor        The color of the blur.
+     * @param aHasBorderRadius    If this element also has a border radius
      * @param aInnerClipRadii     Corner radii for the inside rect if it is a rounded rect.
-     * @param aSkipRect           An area in device pixels we don't have to paint in.
+     * @param aSKipRect           An area in device pixels we don't have to paint in.
      */
     void BlurInsetBox(gfxContext* aDestinationCtx,
-                      const mozilla::gfx::Rect& aDestinationRect,
-                      const mozilla::gfx::Rect& aShadowClipRect,
-                      const mozilla::gfx::IntSize& aBlurRadius,
+                      const mozilla::gfx::Rect aDestinationRect,
+                      const mozilla::gfx::Rect aShadowClipRect,
+                      const mozilla::gfx::IntSize aBlurRadius,
+                      const mozilla::gfx::IntSize aSpreadRadius,
                       const mozilla::gfx::Color& aShadowColor,
-                      const RectCornerRadii* aInnerClipRadii,
-                      const mozilla::gfx::Rect& aSkipRect,
-                      const mozilla::gfx::Point& aShadowOffset);
+                      const bool aHasBorderRadius,
+                      const RectCornerRadii& aInnerClipRadii,
+                      const mozilla::gfx::Rect aSkipRect,
+                      const mozilla::gfx::Point aShadowOffset);
 
 protected:
     already_AddRefed<mozilla::gfx::SourceSurface>
-    GetInsetBlur(const mozilla::gfx::Rect& aOuterRect,
-                 const mozilla::gfx::Rect& aWhitespaceRect,
-                 bool aIsDestRect,
+    GetInsetBlur(const mozilla::gfx::Rect aOuterRect,
+                 const mozilla::gfx::Rect aWhitespaceRect,
+                 const bool aIsDestRect,
                  const mozilla::gfx::Color& aShadowColor,
                  const mozilla::gfx::IntSize& aBlurRadius,
-                 const RectCornerRadii* aInnerClipRadii,
-                 DrawTarget* aDestDrawTarget,
-                 bool aMirrorCorners);
+                 const bool aHasBorderRadius,
+                 const RectCornerRadii& aInnerClipRadii,
+                 DrawTarget* aDestDrawTarget);
+
+    /**
+     * The context of the temporary alpha surface.
+     */
+    RefPtr<gfxContext> mContext;
 
     /**
      * The temporary alpha surface.
      */
-    uint8_t* mData;
+    mozilla::UniquePtr<unsigned char[]> mData;
 
      /**
       * The object that actually does the blurring for us.
       */
-    mozilla::gfx::AlphaBoxBlur mBlur;
+    mozilla::UniquePtr<mozilla::gfx::AlphaBoxBlur> mBlur;
 };
 
 #endif /* GFX_BLUR_H */
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -1627,16 +1627,17 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
     }
 
     // When there's a blur radius, gfxAlphaBoxBlur leaves the skiprect area
     // unchanged. And by construction the gfxSkipRect is not touched by the
     // rendered shadow (even after blurring), so those pixels must be completely
     // transparent in the shadow, so drawing them changes nothing.
     gfxContext* renderContext = aRenderingContext.ThebesContext();
     DrawTarget* drawTarget = renderContext->GetDrawTarget();
+    nsContextBoxBlur blurringArea;
 
     // Clip the context to the area of the frame's padding rect, so no part of the
     // shadow is painted outside. Also cut out anything beyond where the inset shadow
     // will be.
     Rect shadowGfxRect = NSRectToRect(paddingRect, twipsPerPixel);
     shadowGfxRect.Round();
 
     // Set the shadow color; if not specified, use the foreground color
@@ -6117,13 +6118,14 @@ nsContextBoxBlur::InsetBoxBlur(gfxContex
 
   for (size_t i = 0; i < 4; i++) {
     aInnerClipRectRadii[i].width = std::floor(scale.width * aInnerClipRectRadii[i].width);
     aInnerClipRectRadii[i].height = std::floor(scale.height * aInnerClipRectRadii[i].height);
   }
 
   mAlphaBoxBlur.BlurInsetBox(aDestinationCtx, transformedDestRect,
                              transformedShadowClipRect,
-                             blurRadius, aShadowColor,
-                             aHasBorderRadius ? &aInnerClipRectRadii : nullptr,
-                             transformedSkipRect, aShadowOffset);
+                             blurRadius, spreadRadius,
+                             aShadowColor, aHasBorderRadius,
+                             aInnerClipRectRadii, transformedSkipRect,
+                             aShadowOffset);
   return true;
 }
--- a/layout/reftests/box-shadow/reftest.list
+++ b/layout/reftests/box-shadow/reftest.list
@@ -13,22 +13,22 @@ fails-if(Android) == boxshadow-button.ht
 fails-if(Android) == boxshadow-fileupload.html boxshadow-fileupload-ref.html
 == boxshadow-inner-basic.html boxshadow-inner-basic-ref.svg
 random-if(layersGPUAccelerated) == boxshadow-mixed.html boxshadow-mixed-ref.html
 random-if(d2d) == boxshadow-rounded-spread.html boxshadow-rounded-spread-ref.html
 fuzzy-if(skiaContent,1,50) HTTP(..) == boxshadow-dynamic.xul boxshadow-dynamic-ref.xul
 random-if(d2d) == boxshadow-onecorner.html boxshadow-onecorner-ref.html
 random-if(d2d) == boxshadow-twocorners.html boxshadow-twocorners-ref.html
 random-if(d2d) == boxshadow-threecorners.html boxshadow-threecorners-ref.html
-fuzzy(2,440) == boxshadow-skiprect.html boxshadow-skiprect-ref.html
+== boxshadow-skiprect.html boxshadow-skiprect-ref.html
 == boxshadow-opacity.html boxshadow-opacity-ref.html
 == boxshadow-color-rounding.html boxshadow-color-rounding-ref.html
 == boxshadow-color-rounding-middle.html boxshadow-color-rounding-middle-ref.html
 fuzzy-if(OSX==1010,1,24) fuzzy-if(d2d,16,568) == boxshadow-large-border-radius.html boxshadow-large-border-radius-ref.html # Bug 1209649
-fuzzy(3,500) fuzzy-if(d2d,3,1080) == boxshadow-border-radius-int.html boxshadow-border-radius-int-ref.html
+fuzzy-if(d2d,2,1080) == boxshadow-border-radius-int.html boxshadow-border-radius-int-ref.html
 == boxshadow-inset-neg-spread.html about:blank
 == boxshadow-inset-neg-spread2.html boxshadow-inset-neg-spread2-ref.html
 fuzzy(26,3610) == boxshadow-rotated.html boxshadow-rotated-ref.html # Bug 1211264
 == boxshadow-inset-large-border-radius.html boxshadow-inset-large-border-radius-ref.html
 
 # fuzzy due to blur going inside, but as long as it's essentially black instead of a light gray its ok.
 fuzzy(12,9445) == boxshadow-inset-large-offset.html boxshadow-inset-large-offset-ref.html
 
--- a/layout/reftests/outline/reftest.list
+++ b/layout/reftests/outline/reftest.list
@@ -1,9 +1,9 @@
-fuzzy(2,18) == outline-and-box-shadow.html outline-and-box-shadow-ref.html
+== outline-and-box-shadow.html outline-and-box-shadow-ref.html
 == outline-and-3d-transform-1a.html outline-and-3d-transform-1-ref.html
 == outline-and-3d-transform-1b.html outline-and-3d-transform-1-ref.html
 fuzzy-if(gtkWidget,136,120) fuzzy-if(Android,255,356) fuzzy-if(d2d,16,96) fuzzy-if(cocoaWidget,255,120) fuzzy-if(winWidget,255,216) == outline-and-3d-transform-2.html outline-and-3d-transform-2-ref.html
 == outline-overflow-block-abspos.html outline-overflow-block-ref.html
 == outline-overflow-block-float.html outline-overflow-block-ref.html
 == outline-overflow-inlineblock-abspos.html outline-overflow-inlineblock-ref.html
 == outline-overflow-inlineblock-float.html outline-overflow-inlineblock-ref.html
 pref(layout.css.outline-style-auto.enabled,true) skip-if(!gtkWidget&&!winWidget&&!cocoaWidget) == outline-auto-001.html outline-auto-001-ref.html # only works on platforms that supports NS_THEME_FOCUS_OUTLINE