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 323259 144ca2b74fd2c4f37fde99e293b2f4104e87b9e1
parent 323258 436011c88130cd63ec6e96b6ef5213bb5e98320e
child 323260 d607a23fc3dc64956e68b588e53772b9aef48f4f
push id21
push usermaklebus@msu.edu
push dateThu, 01 Dec 2016 06:22:08 +0000
reviewersbackout
bugs1250037
milestone53.0a1
backs out25840ab0d4538770e2316417db77b066b24beb90
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