Bug 1251995 part 4 - Make nsContextBoxBlur use layout device pixels as unit to avoid repeatedly passing in the conversion factor. draft
authorXidorn Quan <quanxunzhen@gmail.com>
Tue, 01 Mar 2016 16:14:13 +0800
changeset 336080 95b5787ebb9cf16e825f3bfa219b094bee154060
parent 336079 eb78b0b108f328324250ee39876d09d9af730a35
child 336081 b10b011db974db1c5798e531e1e7931dddbc4fe3
push id11966
push userxquan@mozilla.com
push dateWed, 02 Mar 2016 10:09:40 +0000
bugs1251995
milestone47.0a1
Bug 1251995 part 4 - Make nsContextBoxBlur use layout device pixels as unit to avoid repeatedly passing in the conversion factor. MozReview-Commit-ID: 1N6THxOJpuk
layout/base/Units.h
layout/base/nsCSSRendering.cpp
layout/base/nsCSSRendering.h
layout/base/nsLayoutUtils.cpp
layout/generic/nsTextFrame.cpp
--- a/layout/base/Units.h
+++ b/layout/base/Units.h
@@ -335,16 +335,23 @@ struct LayoutDevicePixel {
   }
 
   static nsRect ToAppUnits(const LayoutDeviceRect& aRect, nscoord aAppUnitsPerDevPixel) {
     return nsRect(NSFloatPixelsToAppUnits(aRect.x, aAppUnitsPerDevPixel),
                   NSFloatPixelsToAppUnits(aRect.y, aAppUnitsPerDevPixel),
                   NSFloatPixelsToAppUnits(aRect.width, aAppUnitsPerDevPixel),
                   NSFloatPixelsToAppUnits(aRect.height, aAppUnitsPerDevPixel));
   }
+
+  static nsMargin ToAppUnits(const LayoutDeviceMargin& aMargin, nscoord aAppUnitsPerDevPixel) {
+    return nsMargin(NSFloatPixelsToAppUnits(aMargin.top, aAppUnitsPerDevPixel),
+                    NSFloatPixelsToAppUnits(aMargin.right, aAppUnitsPerDevPixel),
+                    NSFloatPixelsToAppUnits(aMargin.bottom, aAppUnitsPerDevPixel),
+                    NSFloatPixelsToAppUnits(aMargin.left, aAppUnitsPerDevPixel));
+  }
 };
 
 /*
  * The pixels that layout rasterizes and delivers to the graphics code.
  * These also are generally referred to as "device pixels" in layout code.
  * Conversion between CSS pixels and LayerPixels is affected by:
  * 1) the "display resolution" (see nsIPresShell::SetResolution)
  * 2) the "full zoom" (see nsPresContext::SetFullZoom)
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -1283,57 +1283,62 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
     if (hasBorderRadius) {
       ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
     }
   }
 
 
   // We don't show anything that intersects with the frame we're blurring on. So tell the
   // blurrer not to do unnecessary work there.
-  gfxRect skipGfxRect = ThebesRect(NSRectToRect(frameRect, twipsPerPixel));
-  skipGfxRect.Round();
-  bool useSkipGfxRect = true;
+  LayoutDeviceRect skipRect =
+    LayoutDevicePixel::FromAppUnits(frameRect, twipsPerPixel);
+  skipRect.Round();
+  bool useSkipRect = true;
   if (nativeTheme) {
     // Optimize non-leaf native-themed frames by skipping computing pixels
     // in the padding-box. We assume the padding-box is going to be painted
     // opaquely for non-leaf frames.
     // XXX this may not be a safe assumption; we should make this go away
     // by optimizing box-shadow drawing more for the cases where we don't have a skip-rect.
-    useSkipGfxRect = !aForFrame->IsLeaf();
+    useSkipRect = !aForFrame->IsLeaf();
     nsRect paddingRect =
       aForFrame->GetPaddingRect() - aForFrame->GetPosition() + aFrameArea.TopLeft();
-    skipGfxRect = nsLayoutUtils::RectToGfxRect(paddingRect, twipsPerPixel);
+    skipRect = LayoutDevicePixel::FromAppUnits(paddingRect, twipsPerPixel);
   } else if (hasBorderRadius) {
-    skipGfxRect.Deflate(gfxMargin(
+    skipRect.Deflate(LayoutDeviceMargin(
         std::max(borderRadii[C_TL].height, borderRadii[C_TR].height), 0,
         std::max(borderRadii[C_BL].height, borderRadii[C_BR].height), 0));
   }
 
   gfxContext* renderContext = aRenderingContext.ThebesContext();
+  LayoutDeviceRect dirtyRect =
+    LayoutDevicePixel::FromAppUnits(aDirtyRect, twipsPerPixel);
 
   for (uint32_t i = shadows->Length(); i > 0; --i) {
     nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
     if (shadowItem->mInset)
       continue;
 
-    nsRect shadowRect = frameRect;
-    shadowRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
+    nsRect shadowRectAppUnits = frameRect;
+    shadowRectAppUnits.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
     if (!nativeTheme) {
-      shadowRect.Inflate(shadowItem->mSpread, shadowItem->mSpread);
+      shadowRectAppUnits.Inflate(shadowItem->mSpread, shadowItem->mSpread);
     }
+    LayoutDeviceRect shadowRect =
+      LayoutDevicePixel::FromAppUnits(shadowRectAppUnits, twipsPerPixel);
 
     // shadowRect won't include the blur, so make an extra rect here that includes the blur
     // for use in the even-odd rule below.
-    nsRect shadowRectPlusBlur = shadowRect;
-    nscoord blurRadius = shadowItem->mRadius;
+    LayoutDeviceRect shadowRectPlusBlur = shadowRect;
+    Float blurRadius =
+      NSAppUnitsToFloatPixels(shadowItem->mRadius, twipsPerPixel);
     shadowRectPlusBlur.Inflate(
-      nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel));
-
-    Rect shadowGfxRectPlusBlur =
-      NSRectToRect(shadowRectPlusBlur, twipsPerPixel);
+      nsContextBoxBlur::GetBlurRadiusMargin(blurRadius));
+
+    Rect shadowGfxRectPlusBlur = shadowRectPlusBlur.ToUnknownRect();
     shadowGfxRectPlusBlur.RoundOut();
     MaybeSnapToDevicePixels(shadowGfxRectPlusBlur, aDrawTarget, true);
 
     // Set the shadow color; if not specified, use the foreground color
     nscolor shadowColor;
     if (shadowItem->mHasColor)
       shadowColor = shadowItem->mColor;
     else
@@ -1344,20 +1349,22 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
 
     if (nativeTheme) {
       nsContextBoxBlur blurringArea;
 
       // When getting the widget shape from the native theme, we're going
       // to draw the widget into the shadow surface to create a mask.
       // We need to ensure that there actually *is* a shadow surface
       // and that we're not going to draw directly into renderContext.
+      Float spread =
+        NSAppUnitsToFloatPixels(shadowItem->mSpread, twipsPerPixel);
       gfxContext* shadowContext =
-        blurringArea.Init(shadowRect, shadowItem->mSpread,
-                          blurRadius, twipsPerPixel, renderContext, aDirtyRect,
-                          useSkipGfxRect ? &skipGfxRect : nullptr,
+        blurringArea.Init(shadowRect, spread, blurRadius,
+                          renderContext, dirtyRect,
+                          useSkipRect ? &skipRect : nullptr,
                           nsContextBoxBlur::FORCE_MASK);
       if (!shadowContext)
         continue;
 
       MOZ_ASSERT(shadowContext == blurringArea.GetContext());
 
       renderContext->Save();
       renderContext->SetColor(gfxShadowColor);
@@ -1408,17 +1415,18 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
         } else {
           AppendRectToPath(builder, innerClipRect);
         }
         RefPtr<Path> path = builder->Finish();
         renderContext->Clip(path);
       }
 
       // Clip the shadow so that we only get the part that applies to aForFrame.
-      nsRect fragmentClip = shadowRectPlusBlur;
+      nsRect fragmentClip =
+        LayoutDevicePixel::ToAppUnits(shadowRectPlusBlur, twipsPerPixel);
       if (!skipSides.IsEmpty()) {
         if (skipSides.Left()) {
           nscoord xmost = fragmentClip.XMost();
           fragmentClip.x = aFrameArea.x;
           fragmentClip.width = xmost - fragmentClip.x;
         }
         if (skipSides.Right()) {
           nscoord xmost = fragmentClip.XMost();
@@ -1458,22 +1466,21 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
         borderSizes[NS_SIDE_BOTTOM] = spreadDistance;
 
         nsCSSBorderRenderer::ComputeOuterRadii(borderRadii, borderSizes,
             &clipRectRadii);
 
       }
       nsContextBoxBlur::BlurRectangle(renderContext,
                                       shadowRect,
-                                      twipsPerPixel,
                                       hasBorderRadius ? &clipRectRadii : nullptr,
                                       blurRadius,
                                       gfxShadowColor,
-                                      aDirtyRect,
-                                      skipGfxRect);
+                                      dirtyRect,
+                                      skipRect);
       renderContext->Restore();
     }
 
   }
 }
 
 void
 nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
@@ -1529,39 +1536,39 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
   for (uint32_t i = shadows->Length(); i > 0; --i) {
     nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
     if (!shadowItem->mInset)
       continue;
 
     // shadowPaintRect: the area to paint on the temp surface
     // shadowClipRect: the area on the temporary surface within shadowPaintRect
     //                 that we will NOT paint in
-    nscoord blurRadius = shadowItem->mRadius;
-    nsMargin blurMargin =
-      nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel);
-    nsRect shadowPaintRect = paddingRect;
+    Float blurRadius =
+      NSAppUnitsToFloatPixels(shadowItem->mRadius, twipsPerPixel);
+    LayoutDeviceMargin blurMargin =
+      nsContextBoxBlur::GetBlurRadiusMargin(blurRadius);
+    LayoutDeviceRect shadowPaintRect =
+      LayoutDevicePixel::FromAppUnits(paddingRect, twipsPerPixel);
     shadowPaintRect.Inflate(blurMargin);
 
-    Rect shadowPaintGfxRect = NSRectToRect(shadowPaintRect, twipsPerPixel);
-    shadowPaintGfxRect.RoundOut();
-
     // Round the spread radius to device pixels (by truncation).
     // This mostly matches what we do for borders, except that we don't round
     // up values between zero and one device pixels to one device pixel.
     // This way of rounding is symmetric around zero, which makes sense for
     // the spread radius.
     int32_t spreadDistance = shadowItem->mSpread / twipsPerPixel;
     nscoord spreadDistanceAppUnits = aPresContext->DevPixelsToAppUnits(spreadDistance);
 
-    nsRect shadowClipRect = paddingRect;
-    shadowClipRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
-    shadowClipRect.Deflate(spreadDistanceAppUnits, spreadDistanceAppUnits);
-
-    Rect shadowClipGfxRect = NSRectToRect(shadowClipRect, twipsPerPixel);
-    shadowClipGfxRect.Round();
+    nsRect shadowClipRectAppUnits = paddingRect;
+    shadowClipRectAppUnits.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
+    shadowClipRectAppUnits.Deflate(spreadDistanceAppUnits);
+
+    LayoutDeviceRect shadowClipRect =
+      LayoutDevicePixel::FromAppUnits(shadowClipRectAppUnits, twipsPerPixel);
+    shadowClipRect.Round();
 
     RectCornerRadii clipRectRadii;
     if (hasBorderRadius) {
       // Calculate the radii the inner clipping rect will have
       Float borderSizes[4] = {0, 0, 0, 0};
 
       // See PaintBoxShadowOuter and bug 514670
       if (innerRadii[C_TL].width > 0 || innerRadii[C_BL].width > 0) {
@@ -1581,21 +1588,20 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
       }
 
       nsCSSBorderRenderer::ComputeInnerRadii(innerRadii, borderSizes,
                                              &clipRectRadii);
     }
 
     // Set the "skip rect" to the area within the frame that we don't paint in,
     // including after blurring.
-    nsRect skipRect = shadowClipRect;
+    LayoutDeviceRect skipRect = shadowClipRect;
     skipRect.Deflate(blurMargin);
-    gfxRect skipGfxRect = nsLayoutUtils::RectToGfxRect(skipRect, twipsPerPixel);
     if (hasBorderRadius) {
-      skipGfxRect.Deflate(gfxMargin(
+      skipRect.Deflate(LayoutDeviceMargin(
           std::max(clipRectRadii[C_TL].height, clipRectRadii[C_TR].height), 0,
           std::max(clipRectRadii[C_BL].height, clipRectRadii[C_BR].height), 0));
     }
 
     // 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.
@@ -1622,26 +1628,24 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
       RefPtr<Path> roundedRect =
         MakePathForRoundedRect(*drawTarget, shadowGfxRect, innerRadii);
       renderContext->Clip(roundedRect);
     } else {
       renderContext->Clip(shadowGfxRect);
     }
 
     nsContextBoxBlur insetBoxBlur;
-    gfxRect destRect = nsLayoutUtils::RectToGfxRect(shadowPaintRect, twipsPerPixel);
-    Point shadowOffset(shadowItem->mXOffset / twipsPerPixel,
-                       shadowItem->mYOffset / twipsPerPixel);
-
-    insetBoxBlur.InsetBoxBlur(renderContext, ToRect(destRect),
-                              shadowClipGfxRect, shadowColor,
-                              blurRadius, spreadDistanceAppUnits,
-                              twipsPerPixel, hasBorderRadius,
-                              clipRectRadii, ToRect(skipGfxRect),
-                              shadowOffset);
+    LayoutDevicePoint shadowOffset = LayoutDevicePixel::FromAppUnits(
+      nsPoint(shadowItem->mXOffset, shadowItem->mYOffset), twipsPerPixel);
+
+    insetBoxBlur.InsetBoxBlur(renderContext, shadowPaintRect,
+                              shadowClipRect, shadowColor,
+                              blurRadius, spreadDistance,
+                              hasBorderRadius, clipRectRadii,
+                              skipRect, shadowOffset);
     renderContext->Restore();
   }
 }
 
 DrawResult
 nsCSSRendering::PaintBackground(nsPresContext* aPresContext,
                                 nsRenderingContext& aRenderingContext,
                                 nsIFrame* aForFrame,
@@ -5364,97 +5368,95 @@ nsImageRenderer::GetImage()
 
   nsCOMPtr<imgIContainer> image = mImageContainer;
   return image.forget();
 }
 
 #define MAX_BLUR_RADIUS 300
 #define MAX_SPREAD_RADIUS 50
 
-static inline gfxPoint ComputeBlurStdDev(nscoord aBlurRadius,
-                                         int32_t aAppUnitsPerDevPixel,
-                                         gfxFloat aScaleX,
-                                         gfxFloat aScaleY)
+static inline
+LayoutDevicePoint ComputeBlurStdDev(Float aBlurRadius,
+                                    Float aScaleX, Float aScaleY)
 {
   // http://dev.w3.org/csswg/css3-background/#box-shadow says that the
   // standard deviation of the blur should be half the given blur value.
-  gfxFloat blurStdDev = gfxFloat(aBlurRadius) / gfxFloat(aAppUnitsPerDevPixel);
-
-  return gfxPoint(std::min((blurStdDev * aScaleX),
-                           gfxFloat(MAX_BLUR_RADIUS)) / 2.0,
-                  std::min((blurStdDev * aScaleY),
-                           gfxFloat(MAX_BLUR_RADIUS)) / 2.0);
+  return LayoutDevicePoint(std::min((aBlurRadius * aScaleX),
+                                    Float(MAX_BLUR_RADIUS)) / 2.0,
+                           std::min((aBlurRadius * aScaleY),
+                                    Float(MAX_BLUR_RADIUS)) / 2.0);
 }
 
-static inline IntSize
-ComputeBlurRadius(nscoord aBlurRadius,
-                  int32_t aAppUnitsPerDevPixel,
-                  gfxFloat aScaleX = 1.0,
-                  gfxFloat aScaleY = 1.0)
+static inline LayoutDeviceIntSize
+ComputeBlurRadius(Float aBlurRadius,
+                  Float aScaleX = 1.0, Float aScaleY = 1.0)
 {
-  gfxPoint scaledBlurStdDev = ComputeBlurStdDev(aBlurRadius, aAppUnitsPerDevPixel,
-                                                aScaleX, aScaleY);
-  return
-    gfxAlphaBoxBlur::CalculateBlurRadius(scaledBlurStdDev);
+  LayoutDevicePoint scaledBlurStdDev =
+    ComputeBlurStdDev(aBlurRadius, aScaleX, aScaleY);
+  return LayoutDeviceIntSize::FromUnknownSize(
+    gfxAlphaBoxBlur::CalculateBlurRadius(
+      ThebesPoint(scaledBlurStdDev.ToUnknownPoint())));
 }
 
 // -----
 // nsContextBoxBlur
 // -----
 gfxContext*
-nsContextBoxBlur::Init(const nsRect& aRect, nscoord aSpreadRadius,
-                       nscoord aBlurRadius,
-                       int32_t aAppUnitsPerDevPixel,
+nsContextBoxBlur::Init(const LayoutDeviceRect& aRect,
+                       Float aSpreadRadius,
+                       Float aBlurRadius,
                        gfxContext* aDestinationCtx,
-                       const nsRect& aDirtyRect,
-                       const gfxRect* aSkipRect,
+                       const LayoutDeviceRect& aDirtyRect,
+                       const LayoutDeviceRect* aSkipRect,
                        uint32_t aFlags)
 {
   if (aRect.IsEmpty()) {
     mContext = nullptr;
     return nullptr;
   }
 
-  IntSize blurRadius;
-  IntSize spreadRadius;
-  GetBlurAndSpreadRadius(aDestinationCtx->GetDrawTarget(), aAppUnitsPerDevPixel,
+  LayoutDeviceIntSize blurRadius;
+  LayoutDeviceIntSize spreadRadius;
+  GetBlurAndSpreadRadius(aDestinationCtx->GetDrawTarget(),
                          aBlurRadius, aSpreadRadius,
                          blurRadius, spreadRadius);
 
   mDestinationCtx = aDestinationCtx;
 
   // If not blurring, draw directly onto the destination device
   if (blurRadius.width <= 0 && blurRadius.height <= 0 &&
       spreadRadius.width <= 0 && spreadRadius.height <= 0 &&
       !(aFlags & FORCE_MASK)) {
     mContext = aDestinationCtx;
     return mContext;
   }
 
   // Convert from app units to device pixels
-  gfxRect rect = nsLayoutUtils::RectToGfxRect(aRect, aAppUnitsPerDevPixel);
-
-  gfxRect dirtyRect =
-    nsLayoutUtils::RectToGfxRect(aDirtyRect, aAppUnitsPerDevPixel);
+  gfxRect rect = ThebesRect(aRect.ToUnknownRect());
+
+  gfxRect dirtyRect = ThebesRect(aDirtyRect.ToUnknownRect());
   dirtyRect.RoundOut();
 
   gfxMatrix transform = aDestinationCtx->CurrentMatrix();
   rect = transform.TransformBounds(rect);
 
   mPreTransformed = !transform.IsIdentity();
 
   // Create the temporary surface for blurring
   dirtyRect = transform.TransformBounds(dirtyRect);
   if (aSkipRect) {
-    gfxRect skipRect = transform.TransformBounds(*aSkipRect);
-    mContext = mAlphaBoxBlur.Init(rect, spreadRadius,
-                                  blurRadius, &dirtyRect, &skipRect);
+    gfxRect skipRect =
+      transform.TransformBounds(ThebesRect(aSkipRect->ToUnknownRect()));
+    mContext = mAlphaBoxBlur.Init(rect, spreadRadius.ToUnknownSize(),
+                                  blurRadius.ToUnknownSize(),
+                                  &dirtyRect, &skipRect);
   } else {
-    mContext = mAlphaBoxBlur.Init(rect, spreadRadius,
-                                  blurRadius, &dirtyRect, nullptr);
+    mContext = mAlphaBoxBlur.Init(rect, spreadRadius.ToUnknownSize(),
+                                  blurRadius.ToUnknownSize(),
+                                  &dirtyRect, nullptr);
   }
 
   if (mContext) {
     // we don't need to blur if skipRect is equal to rect
     // and mContext will be nullptr
     mContext->Multiply(transform);
   }
   return mContext;
@@ -5477,159 +5479,157 @@ nsContextBoxBlur::DoPaint()
 }
 
 gfxContext*
 nsContextBoxBlur::GetContext()
 {
   return mContext;
 }
 
-/* static */ nsMargin
-nsContextBoxBlur::GetBlurRadiusMargin(nscoord aBlurRadius,
-                                      int32_t aAppUnitsPerDevPixel)
+/* static */ LayoutDeviceMargin
+nsContextBoxBlur::GetBlurRadiusMargin(Float aBlurRadius)
 {
-  IntSize blurRadius = ComputeBlurRadius(aBlurRadius, aAppUnitsPerDevPixel);
-
-  nsMargin result;
-  result.top = result.bottom = blurRadius.height * aAppUnitsPerDevPixel;
-  result.left = result.right = blurRadius.width  * aAppUnitsPerDevPixel;
+  LayoutDeviceIntSize blurRadius = ComputeBlurRadius(aBlurRadius);
+
+  LayoutDeviceMargin result;
+  result.top = result.bottom = blurRadius.height;
+  result.left = result.right = blurRadius.width;
   return result;
 }
 
 /* static */ void
 nsContextBoxBlur::BlurRectangle(gfxContext* aDestinationCtx,
-                                const nsRect& aRect,
-                                int32_t aAppUnitsPerDevPixel,
+                                const LayoutDeviceRect& aRect,
                                 RectCornerRadii* aCornerRadii,
-                                nscoord aBlurRadius,
+                                Float aBlurRadius,
                                 const Color& aShadowColor,
-                                const nsRect& aDirtyRect,
-                                const gfxRect& aSkipRect)
+                                const LayoutDeviceRect& aDirtyRect,
+                                const LayoutDeviceRect& aSkipRect)
 {
   DrawTarget& aDestDrawTarget = *aDestinationCtx->GetDrawTarget();
 
   if (aRect.IsEmpty()) {
     return;
   }
 
-  Rect shadowGfxRect = NSRectToRect(aRect, aAppUnitsPerDevPixel);
+  Rect shadowGfxRect = aRect.ToUnknownRect();
 
   if (aBlurRadius <= 0) {
     ColorPattern color(ToDeviceColor(aShadowColor));
     if (aCornerRadii) {
       RefPtr<Path> roundedRect = MakePathForRoundedRect(aDestDrawTarget,
                                                         shadowGfxRect,
                                                         *aCornerRadii);
       aDestDrawTarget.Fill(roundedRect, color);
     } else {
       aDestDrawTarget.FillRect(shadowGfxRect, color);
     }
     return;
   }
 
-  gfxFloat scaleX = 1;
-  gfxFloat scaleY = 1;
+  Float scaleX = 1;
+  Float scaleY = 1;
 
   // Do blurs in device space when possible.
   // Chrome/Skia always does the blurs in device space
   // and will sometimes get incorrect results (e.g. rotated blurs)
   gfxMatrix transform = aDestinationCtx->CurrentMatrix();
   // XXX: we could probably handle negative scales but for now it's easier just to fallback
   if (!transform.HasNonAxisAlignedTransform() && transform._11 > 0.0 && transform._22 > 0.0) {
     scaleX = transform._11;
     scaleY = transform._22;
     aDestinationCtx->SetMatrix(gfxMatrix());
   } else {
     transform = gfxMatrix();
   }
 
-  gfxPoint blurStdDev = ComputeBlurStdDev(aBlurRadius, aAppUnitsPerDevPixel, scaleX, scaleY);
-
-  gfxRect dirtyRect =
-    nsLayoutUtils::RectToGfxRect(aDirtyRect, aAppUnitsPerDevPixel);
+  LayoutDevicePoint blurStdDev = ComputeBlurStdDev(aBlurRadius, scaleX, scaleY);
+
+  gfxRect dirtyRect = ThebesRect(aDirtyRect.ToUnknownRect());
   dirtyRect.RoundOut();
 
   gfxRect shadowThebesRect = transform.TransformBounds(ThebesRect(shadowGfxRect));
   dirtyRect = transform.TransformBounds(dirtyRect);
-  gfxRect skipRect = transform.TransformBounds(aSkipRect);
+  gfxRect skipRect =
+    transform.TransformBounds(ThebesRect(aSkipRect.ToUnknownRect()));
 
   if (aCornerRadii) {
     aCornerRadii->Scale(scaleX, scaleY);
   }
 
   gfxAlphaBoxBlur::BlurRectangle(aDestinationCtx,
                                  shadowThebesRect,
                                  aCornerRadii,
-                                 blurStdDev,
+                                 ThebesPoint(blurStdDev.ToUnknownPoint()),
                                  aShadowColor,
                                  dirtyRect,
                                  skipRect);
 }
 
 /* static */ void
 nsContextBoxBlur::GetBlurAndSpreadRadius(DrawTarget* aDestDrawTarget,
-                                         int32_t aAppUnitsPerDevPixel,
-                                         nscoord aBlurRadius,
-                                         nscoord aSpreadRadius,
-                                         IntSize& aOutBlurRadius,
-                                         IntSize& aOutSpreadRadius,
+                                         Float aBlurRadius,
+                                         Float aSpreadRadius,
+                                         LayoutDeviceIntSize& aOutBlurRadius,
+                                         LayoutDeviceIntSize& aOutSpreadRadius,
                                          bool aConstrainSpreadRadius)
 {
   // Do blurs in device space when possible.
   // Chrome/Skia always does the blurs in device space
   // and will sometimes get incorrect results (e.g. rotated blurs)
   Matrix transform = aDestDrawTarget->GetTransform();
   // XXX: we could probably handle negative scales but for now it's easier just to fallback
-  gfxFloat scaleX, scaleY;
+  Float scaleX, scaleY;
   if (transform.HasNonAxisAlignedTransform() || transform._11 <= 0.0 || transform._22 <= 0.0) {
     scaleX = 1;
     scaleY = 1;
   } else {
     scaleX = transform._11;
     scaleY = transform._22;
   }
 
   // compute a large or smaller blur radius
-  aOutBlurRadius = ComputeBlurRadius(aBlurRadius, aAppUnitsPerDevPixel, scaleX, scaleY);
-  aOutSpreadRadius =
-      IntSize(int32_t(aSpreadRadius * scaleX / aAppUnitsPerDevPixel),
-              int32_t(aSpreadRadius * scaleY / aAppUnitsPerDevPixel));
+  aOutBlurRadius = ComputeBlurRadius(aBlurRadius, scaleX, scaleY);
+  aOutSpreadRadius = LayoutDeviceIntSize(int32_t(aSpreadRadius * scaleX),
+                                         int32_t(aSpreadRadius * scaleY));
 
 
   if (aConstrainSpreadRadius) {
-    aOutSpreadRadius.width = std::min(aOutSpreadRadius.width, int32_t(MAX_SPREAD_RADIUS));
-    aOutSpreadRadius.height = std::min(aOutSpreadRadius.height, int32_t(MAX_SPREAD_RADIUS));
+    aOutSpreadRadius.width = std::min(aOutSpreadRadius.width,
+                                      int32_t(MAX_SPREAD_RADIUS));
+    aOutSpreadRadius.height = std::min(aOutSpreadRadius.height,
+                                       int32_t(MAX_SPREAD_RADIUS));
   }
 }
 
 /* static */ bool
 nsContextBoxBlur::InsetBoxBlur(gfxContext* aDestinationCtx,
-                               Rect aDestinationRect,
-                               Rect aShadowClipRect,
+                               LayoutDeviceRect aDestinationRect,
+                               LayoutDeviceRect aShadowClipRect,
                                Color& aShadowColor,
-                               nscoord aBlurRadiusAppUnits,
-                               nscoord aSpreadDistanceAppUnits,
-                               int32_t aAppUnitsPerDevPixel,
+                               Float aBlurRadius,
+                               Float aSpreadDistance,
                                bool aHasBorderRadius,
                                RectCornerRadii& aInnerClipRectRadii,
-                               Rect aSkipRect, Point aShadowOffset)
+                               LayoutDeviceRect aSkipRect,
+                               LayoutDevicePoint aShadowOffset)
 {
   if (aDestinationRect.IsEmpty()) {
     mContext = nullptr;
     return false;
   }
 
   gfxContextAutoSaveRestore autoRestore(aDestinationCtx);
 
-  IntSize blurRadius;
-  IntSize spreadRadius;
+  LayoutDeviceIntSize blurRadius;
+  LayoutDeviceIntSize spreadRadius;
   // Convert the blur and spread radius to device pixels
   bool constrainSpreadRadius = false;
-  GetBlurAndSpreadRadius(aDestinationCtx->GetDrawTarget(), aAppUnitsPerDevPixel,
-                         aBlurRadiusAppUnits, aSpreadDistanceAppUnits,
+  GetBlurAndSpreadRadius(aDestinationCtx->GetDrawTarget(),
+                         aBlurRadius, aSpreadDistance,
                          blurRadius, spreadRadius, constrainSpreadRadius);
 
   // The blur and spread radius are scaled already, so scale all
   // input data to the blur. This way, we don't have to scale the min
   // inset blur to the invert of the dest context, then rescale it back
   // when we draw to the destination surface.
   gfxSize scale = aDestinationCtx->CurrentMatrix().ScaleFactors(true);
   Matrix transform = ToMatrix(aDestinationCtx->CurrentMatrix());
@@ -5638,29 +5638,33 @@ nsContextBoxBlur::InsetBoxBlur(gfxContex
   if (!transform.HasNonAxisAlignedTransform() && transform._11 > 0.0 && transform._22 > 0.0) {
     // If we don't have a rotation, we're pre-transforming all the rects.
     aDestinationCtx->SetMatrix(gfxMatrix());
   } else {
     // Don't touch anything, we have a rotation.
     transform = Matrix();
   }
 
-  Rect transformedDestRect = transform.TransformBounds(aDestinationRect);
-  Rect transformedShadowClipRect = transform.TransformBounds(aShadowClipRect);
-  Rect transformedSkipRect = transform.TransformBounds(aSkipRect);
+  Rect transformedDestRect =
+    transform.TransformBounds(aDestinationRect.ToUnknownRect());
+  Rect transformedShadowClipRect =
+    transform.TransformBounds(aShadowClipRect.ToUnknownRect());
+  Rect transformedSkipRect =
+    transform.TransformBounds(aSkipRect.ToUnknownRect());
 
   transformedDestRect.Round();
   transformedShadowClipRect.Round();
   transformedSkipRect.RoundIn();
 
   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, spreadRadius,
+                             blurRadius.ToUnknownSize(),
+                             spreadRadius.ToUnknownSize(),
                              aShadowColor, aHasBorderRadius,
                              aInnerClipRectRadii, transformedSkipRect,
-                             aShadowOffset);
+                             aShadowOffset.ToUnknownPoint());
   return true;
 }
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -859,54 +859,53 @@ protected:
  * You must call Init() first to create a suitable temporary surface to draw
  * on.  You must then draw any desired content onto the given context, then
  * call DoPaint() to apply the blurred content as a single-color mask. You
  * can only call Init() once, so objects cannot be reused.
  *
  * This is very useful for creating drop shadows or silhouettes.
  */
 class nsContextBoxBlur {
+  typedef mozilla::LayoutDeviceMargin LayoutDeviceMargin;
+  typedef mozilla::LayoutDeviceRect LayoutDeviceRect;
+  typedef mozilla::LayoutDevicePoint LayoutDevicePoint;
+  typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize;
   typedef mozilla::gfx::Color Color;
+  typedef mozilla::gfx::Float Float;
   typedef mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::RectCornerRadii RectCornerRadii;
 
 public:
   enum {
     FORCE_MASK = 0x01
   };
   /**
    * Prepares a gfxContext to draw on. Do not call this twice; if you want
    * to get the gfxContext again use GetContext().
    *
    * @param aRect                The coordinates of the surface to create.
-   *                             All coordinates must be in app units.
    *                             This must not include the blur radius, pass
    *                             it as the second parameter and everything
    *                             is taken care of.
    *
-   * @param aBlurRadius          The blur radius in app units.
-   *
-   * @param aAppUnitsPerDevPixel The number of app units in a device pixel,
-   *                             for conversion.  Most of the time you'll
-   *                             pass this from the current PresContext if
-   *                             available.
+   * @param aBlurRadius          The blur radius in device pixels.
    *
    * @param aDestinationCtx      The graphics context to apply the blurred
    *                             mask to when you call DoPaint(). Make sure
    *                             it is not destroyed before you call
    *                             DoPaint(). To set the color of the
    *                             resulting blurred graphic mask, you must
    *                             set the color on this context before
    *                             calling Init().
    *
-   * @param aDirtyRect           The absolute dirty rect in app units. Used to
-   *                             optimize the temporary surface size and speed up blur.
+   * @param aDirtyRect           The absolute dirty rect. Used to optimize the
+   *                             temporary surface size and speed up blur.
    *
-   * @param aSkipRect            An area in device pixels (NOT app units!) to avoid
-   *                             blurring over, to prevent unnecessary work.
+   * @param aSkipRect            An area in device pixels to avoid blurring
+   *                             over, to prevent unnecessary work.
    *                             
    * @param aFlags               FORCE_MASK to ensure that the content drawn to the
    *                             returned gfxContext is used as a mask, and not
    *                             drawn directly to aDestinationCtx.
    *
    * @return            A blank 8-bit alpha-channel-only graphics context to
    *                    draw on, or null on error. Must not be freed. The
    *                    context has a device offset applied to it given by
@@ -915,20 +914,22 @@ public:
    *                    need to worry about translating any coordinates to
    *                    draw on this temporary surface.
    *
    * If aBlurRadius is 0, the returned context is aDestinationCtx and
    * DoPaint() does nothing, because no blurring is required. Therefore, you
    * should prepare the destination context as if you were going to draw
    * directly on it instead of any temporary surface created in this class.
    */
-  gfxContext* Init(const nsRect& aRect, nscoord aSpreadRadius,
-                   nscoord aBlurRadius,
-                   int32_t aAppUnitsPerDevPixel, gfxContext* aDestinationCtx,
-                   const nsRect& aDirtyRect, const gfxRect* aSkipRect,
+  gfxContext* Init(const LayoutDeviceRect& aRect,
+                   Float aSpreadRadius,
+                   Float aBlurRadius,
+                   gfxContext* aDestinationCtx,
+                   const LayoutDeviceRect& aDirtyRect,
+                   const LayoutDeviceRect* aSkipRect,
                    uint32_t aFlags = 0);
 
   /**
    * Does the actual blurring and mask applying. Users of this object *must*
    * have called Init() first, then have drawn whatever they want to be
    * blurred onto the internal gfxContext before calling this.
    */
   void DoPaint();
@@ -941,90 +942,78 @@ public:
   gfxContext* GetContext();
 
 
   /**
    * Get the margin associated with the given blur radius, i.e., the
    * additional area that might be painted as a result of it.  (The
    * margin for a spread radius is itself, on all sides.)
    */
-  static nsMargin GetBlurRadiusMargin(nscoord aBlurRadius,
-                                      int32_t aAppUnitsPerDevPixel);
+  static LayoutDeviceMargin GetBlurRadiusMargin(Float aBlurRadius);
 
   /**
    * Blurs a coloured rectangle onto aDestinationCtx. This is equivalent
    * to calling Init(), drawing a rectangle onto the returned surface
    * and then calling DoPaint, but may let us optimize better in the
    * backend.
    *
    * @param aDestinationCtx      The destination to blur to.
-   * @param aRect                The rectangle to blur in app units.
-   * @param aAppUnitsPerDevPixel The number of app units in a device pixel,
-   *                             for conversion.  Most of the time you'll
-   *                             pass this from the current PresContext if
-   *                             available.
+   * @param aRect                The rectangle to blur.
    * @param aCornerRadii         Corner radii for aRect, if it is a rounded
    *                             rectangle.
-   * @param aBlurRadius          The blur radius in app units.
+   * @param aBlurRadius          The blur radius in device pixels.
    * @param aShadowColor         The color to draw the blurred shadow.
-   * @param aDirtyRect           The absolute dirty rect in app units. Used to
-   *                             optimize the temporary surface size and speed up blur.
-   * @param aSkipRect            An area in device pixels (NOT app units!) to avoid
-   *                             blurring over, to prevent unnecessary work.
+   * @param aDirtyRect           The absolute dirty rect. Used to optimize the
+   *                             temporary surface size and speed up blur.
+   * @param aSkipRect            An area in device pixels to avoid blurring
+   *                             over, to prevent unnecessary work.
    */
   static void BlurRectangle(gfxContext* aDestinationCtx,
-                            const nsRect& aRect,
-                            int32_t aAppUnitsPerDevPixel,
+                            const LayoutDeviceRect& aRect,
                             RectCornerRadii* aCornerRadii,
-                            nscoord aBlurRadius,
+                            Float aBlurRadius,
                             const Color& aShadowColor,
-                            const nsRect& aDirtyRect,
-                            const gfxRect& aSkipRect);
+                            const LayoutDeviceRect& aDirtyRect,
+                            const LayoutDeviceRect& aSkipRect);
 
   /**
    * Draws a blurred inset box shadow shape onto the destination surface.
    * Like BlurRectangle, this is equivalent to calling Init(),
    * drawing a rectangle onto the returned surface
    * and then calling DoPaint, but may let us optimize better in the
    * backend.
    *
    * @param aDestinationCtx      The destination to blur to.
-   * @param aDestinationRect     The rectangle to blur in app units.
+   * @param aDestinationRect     The rectangle to blur
    * @param aShadowClipRect      The inside clip rect that creates the path.
    * @param aShadowColor         The color of the blur
-   * @param aBlurRadiusAppUnits  The blur radius in app units
-   * @param aSpreadRadiusAppUnits The spread radius in app units.
-   * @param aAppUnitsPerDevPixel The number of app units in a device pixel,
-   *                             for conversion.  Most of the time you'll
-   *                             pass this from the current PresContext if
-   *                             available.
+   * @param aBlurRadius          The blur radius in device pixels
+   * @param aSpreadRadius        The spread radius in device pixels
    * @param aHasBorderRadius     If this inset box blur has a border radius
    * @param aInnerClipRectRadii  The clip rect radii used for the inside rect's path.
    * @param aSkipRect            An area in device pixels (NOT app units!) to avoid
    *                             blurring over, to prevent unnecessary work.
    */
   bool InsetBoxBlur(gfxContext* aDestinationCtx,
-                    mozilla::gfx::Rect aDestinationRect,
-                    mozilla::gfx::Rect aShadowClipRect,
+                    LayoutDeviceRect aDestinationRect,
+                    LayoutDeviceRect aShadowClipRect,
                     mozilla::gfx::Color& aShadowColor,
-                    nscoord aBlurRadiusAppUnits,
-                    nscoord aSpreadRadiusAppUnits,
-                    int32_t aAppUnitsPerDevPixel,
+                    Float aBlurRadius,
+                    Float aSpreadRadius,
                     bool aHasBorderRadius,
                     RectCornerRadii& aInnerClipRectRadii,
-                    mozilla::gfx::Rect aSkipRect,
-                    mozilla::gfx::Point aShadowOffset);
+                    LayoutDeviceRect aSkipRect,
+                    LayoutDevicePoint aShadowOffset);
 
 protected:
   static void GetBlurAndSpreadRadius(DrawTarget* aDestDrawTarget,
-                                     int32_t aAppUnitsPerDevPixel,
-                                     nscoord aBlurRadius,
-                                     nscoord aSpreadRadius,
-                                     mozilla::gfx::IntSize& aOutBlurRadius,
-                                     mozilla::gfx::IntSize& aOutSpreadRadius,
+                                     Float aBlurRadius,
+                                     Float aSpreadRadius,
+                                     LayoutDeviceIntSize& aOutBlurRadius,
+                                     LayoutDeviceIntSize& aOutSpreadRadius,
                                      bool aConstrainSpreadRadius = true);
 
   gfxAlphaBoxBlur mAlphaBoxBlur;
   RefPtr<gfxContext> mContext;
   gfxContext* mDestinationCtx;
 
   /* This is true if the blur already has it's content transformed
    * by mDestinationCtx's transform */
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3784,17 +3784,19 @@ nsLayoutUtils::GetTextShadowRectsUnion(c
   const nsStyleText* textStyle = aFrame->StyleText();
   if (!textStyle->HasTextShadow())
     return aTextAndDecorationsRect;
 
   nsRect resultRect = aTextAndDecorationsRect;
   int32_t A2D = aFrame->PresContext()->AppUnitsPerDevPixel();
   for (uint32_t i = 0; i < textStyle->mTextShadow->Length(); ++i) {
     nsCSSShadowItem* shadow = textStyle->mTextShadow->ShadowAt(i);
-    nsMargin blur = nsContextBoxBlur::GetBlurRadiusMargin(shadow->mRadius, A2D);
+    nsMargin blur = LayoutDevicePixel::ToAppUnits(
+      nsContextBoxBlur::GetBlurRadiusMargin(
+        NSAppUnitsToFloatPixels(shadow->mRadius, A2D)), A2D);
     if ((aFlags & EXCLUDE_BLUR_SHADOWS) && blur != nsMargin(0, 0, 0, 0))
       continue;
 
     nsRect tmpRect(aTextAndDecorationsRect);
 
     tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset));
     tmpRect.Inflate(blur);
 
@@ -5822,34 +5824,35 @@ nsLayoutUtils::PaintTextShadow(const nsI
                                const nsRect& aDirtyRect,
                                const nscolor& aForegroundColor,
                                TextShadowCallback aCallback,
                                void* aCallbackData)
 {
   const nsStyleText* textStyle = aFrame->StyleText();
   if (!textStyle->HasTextShadow())
     return;
+  const auto A2D = aFrame->PresContext()->AppUnitsPerDevPixel();
 
   // Text shadow happens with the last value being painted at the back,
   // ie. it is painted first.
   gfxContext* aDestCtx = aContext->ThebesContext();
   for (uint32_t i = textStyle->mTextShadow->Length(); i > 0; --i) {
     nsCSSShadowItem* shadowDetails = textStyle->mTextShadow->ShadowAt(i - 1);
     nsPoint shadowOffset(shadowDetails->mXOffset,
                          shadowDetails->mYOffset);
     nscoord blurRadius = std::max(shadowDetails->mRadius, 0);
 
     nsRect shadowRect(aTextRect);
     shadowRect.MoveBy(shadowOffset);
 
-    nsPresContext* presCtx = aFrame->PresContext();
     nsContextBoxBlur contextBoxBlur;
-    gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, 0, blurRadius,
-                                                    presCtx->AppUnitsPerDevPixel(),
-                                                    aDestCtx, aDirtyRect, nullptr);
+    gfxContext* shadowContext = contextBoxBlur.Init(
+      LayoutDevicePixel::FromAppUnits(shadowRect, A2D),
+      0, NSAppUnitsToFloatPixels(blurRadius, A2D), aDestCtx,
+      LayoutDevicePixel::FromAppUnits(aDirtyRect, A2D), nullptr);
     if (!shadowContext)
       continue;
 
     nscolor shadowColor;
     if (shadowDetails->mHasColor)
       shadowColor = shadowDetails->mColor;
     else
       shadowColor = aForegroundColor;
@@ -8008,18 +8011,19 @@ nsLayoutUtils::GetBoxShadowRectForFrame(
     nsCSSShadowItem* shadow = boxShadows->ShadowAt(i);
 
     // inset shadows are never painted outside the frame
     if (shadow->mInset)
       continue;
 
     tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset));
     tmpRect.Inflate(shadow->mSpread);
-    tmpRect.Inflate(
-      nsContextBoxBlur::GetBlurRadiusMargin(shadow->mRadius, A2D));
+    tmpRect.Inflate(LayoutDevicePixel::ToAppUnits(
+      nsContextBoxBlur::GetBlurRadiusMargin(
+        NSAppUnitsToFloatPixels(shadow->mRadius, A2D)), A2D));
     shadows.UnionRect(shadows, tmpRect);
   }
   return shadows;
 }
 
 /* static */ void
 nsLayoutUtils::UpdateImageVisibilityForFrame(nsIFrame* aImageFrame)
 {
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -5857,18 +5857,20 @@ nsTextFrame::PaintOneShadow(gfxTextRun::
                             gfxContext* aCtx, const nscolor& aForegroundColor,
                             const nsCharClipDisplayItem::ClipEdges& aClipEdges,
                             nscoord aLeftSideOffset, gfxRect& aBoundingBox,
                             uint32_t aBlurFlags)
 {
   PROFILER_LABEL("nsTextFrame", "PaintOneShadow",
     js::ProfileEntry::Category::GRAPHICS);
 
+  const auto app = PresContext()->AppUnitsPerDevPixel();
   gfxPoint shadowOffset(aShadowDetails->mXOffset, aShadowDetails->mYOffset);
-  nscoord blurRadius = std::max(aShadowDetails->mRadius, 0);
+  Float blurRadius =
+    NSAppUnitsToFloatPixels(std::max(aShadowDetails->mRadius, 0), app);
 
   // This rect is the box which is equivalent to where the shadow will be painted.
   // The origin of aBoundingBox is the text baseline left, so we must translate it by
   // that much in order to make the origin the top-left corner of the text bounding box.
   // Note that aLeftSideOffset is line-left, so actually means top offset in
   // vertical writing modes.
   gfxRect shadowGfxRect;
   WritingMode wm = GetWritingMode();
@@ -5888,20 +5890,19 @@ nsTextFrame::PaintOneShadow(gfxTextRun::
   shadowGfxRect += shadowOffset;
 
   nsRect shadowRect(NSToCoordRound(shadowGfxRect.X()),
                     NSToCoordRound(shadowGfxRect.Y()),
                     NSToCoordRound(shadowGfxRect.Width()),
                     NSToCoordRound(shadowGfxRect.Height()));
 
   nsContextBoxBlur contextBoxBlur;
-  gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, 0, blurRadius,
-                                                  PresContext()->AppUnitsPerDevPixel(),
-                                                  aCtx, aDirtyRect, nullptr,
-                                                  aBlurFlags);
+  gfxContext* shadowContext = contextBoxBlur.Init(
+    LayoutDevicePixel::FromAppUnits(shadowRect, app), 0, blurRadius, aCtx,
+    LayoutDevicePixel::FromAppUnits(aDirtyRect, app), nullptr, aBlurFlags);
   if (!shadowContext)
     return;
 
   nscolor shadowColor;
   const nscolor* decorationOverrideColor;
   if (aShadowDetails->mHasColor) {
     shadowColor = aShadowDetails->mColor;
     decorationOverrideColor = &shadowColor;