Bug 1143522 - Convert Layer::mClipRect to ParentLayerIntRect. r=botond
authorYing-Ruei Liang (KK) <thumbd03803@gmail.com>
Sat, 11 Apr 2015 22:03:00 -0400
changeset 268868 cd00518886c81e8355cf157c4e5835bc33fa3797
parent 268867 873428bfc72340793eb3ec541af3de0e2e1d0ae0
child 268869 85c946ddfe96c5420a17c4930f7a9278b1e0af66
push id4830
push userjlund@mozilla.com
push dateMon, 29 Jun 2015 20:18:48 +0000
treeherdermozilla-beta@4c2175bb0420 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1143522
milestone40.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1143522 - Convert Layer::mClipRect to ParentLayerIntRect. r=botond Change interface of getter/setter for mClipRect, also necessary modification for codes that use these resources. * * * Bundle mUseClipRect and mClipRect as Maybe<ParentLayerIntRect> mClipRect
gfx/2d/Rect.h
gfx/layers/LayerMetricsWrapper.h
gfx/layers/LayerTreeInvalidation.cpp
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/ReadbackProcessor.cpp
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/basic/BasicContainerLayer.cpp
gfx/layers/basic/BasicLayerManager.cpp
gfx/layers/composite/AsyncCompositionManager.cpp
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/composite/LayerManagerComposite.h
gfx/layers/ipc/LayerTransactionParent.cpp
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/ipc/ShadowLayers.cpp
gfx/tests/gtest/TestAsyncPanZoomController.cpp
layout/base/FrameLayerBuilder.cpp
layout/base/UnitTransforms.h
--- a/gfx/2d/Rect.h
+++ b/gfx/2d/Rect.h
@@ -94,16 +94,22 @@ struct IntRectTyped :
 
     bool Overflows() const {
       CheckedInt<int32_t> xMost = this->x;
       xMost += this->width;
       CheckedInt<int32_t> yMost = this->y;
       yMost += this->height;
       return !xMost.isValid() || !yMost.isValid();
     }
+
+    // This is here only to keep IPDL-generated code happy. DO NOT USE.
+    bool operator==(const IntRectTyped<units>& aRect) const
+    {
+      return IntRectTyped<units>::IsEqualEdges(aRect);
+    }
 };
 typedef IntRectTyped<UnknownUnits> IntRect;
 
 template<class units>
 struct RectTyped :
     public BaseRect<Float, RectTyped<units>, PointTyped<units>, SizeTyped<units>, MarginTyped<units> >,
     public units {
     static_assert(IsPixel<units>::value,
--- a/gfx/layers/LayerMetricsWrapper.h
+++ b/gfx/layers/LayerMetricsWrapper.h
@@ -336,25 +336,27 @@ public:
     if (AtBottomLayer()) {
       return mLayer->GetVisibleRegion();
     }
     nsIntRegion region = mLayer->GetVisibleRegion();
     region.Transform(gfx::To3DMatrix(mLayer->GetTransform()));
     return region;
   }
 
-  const nsIntRect* GetClipRect() const
+  const Maybe<ParentLayerIntRect>& GetClipRect() const
   {
     MOZ_ASSERT(IsValid());
 
+    static const Maybe<ParentLayerIntRect> sNoClipRect = Nothing();
+
     if (AtBottomLayer()) {
       return mLayer->GetClipRect();
     }
 
-    return nullptr;
+    return sNoClipRect;
   }
 
   EventRegionsOverride GetEventRegionsOverride() const
   {
     MOZ_ASSERT(IsValid());
 
     if (mLayer->AsContainerLayer()) {
       return mLayer->AsContainerLayer()->GetEventRegionsOverride();
--- a/gfx/layers/LayerTreeInvalidation.cpp
+++ b/gfx/layers/LayerTreeInvalidation.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "LayerTreeInvalidation.h"
 #include <stdint.h>                     // for uint32_t
 #include "ImageContainer.h"             // for ImageContainer
 #include "ImageLayers.h"                // for ImageLayer, etc
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
+#include "Units.h"                      // for ParentLayerIntRect
 #include "gfxColor.h"                   // for gfxRGBA
 #include "GraphicsFilter.h"             // for GraphicsFilter
 #include "gfxRect.h"                    // for gfxRect
 #include "gfxUtils.h"                   // for gfxUtils
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr, nsAutoPtr, etc
@@ -135,17 +136,17 @@ struct LayerPropertiesBase : public Laye
 
   nsIntRegion ComputeChange(NotifySubDocInvalidationFunc aCallback,
                             bool& aGeometryChanged)
   {
     bool transformChanged = !mTransform.FuzzyEqual(mLayer->GetLocalTransform()) ||
                             mLayer->GetPostXScale() != mPostXScale ||
                             mLayer->GetPostYScale() != mPostYScale;
     Layer* otherMask = mLayer->GetMaskLayer();
-    const nsIntRect* otherClip = mLayer->GetClipRect();
+    const Maybe<ParentLayerIntRect>& otherClip = mLayer->GetClipRect();
     nsIntRegion result;
     if ((mMaskLayer ? mMaskLayer->mLayer : nullptr) != otherMask ||
         (mUseClipRect != !!otherClip) ||
         mLayer->GetLocalOpacity() != mOpacity ||
         transformChanged) 
     {
       aGeometryChanged = true;
       result = OldTransformedBounds();
@@ -161,17 +162,17 @@ struct LayerPropertiesBase : public Laye
       AddTransformedRegion(result, mMaskLayer->ComputeChange(aCallback, aGeometryChanged),
                            mTransform);
     }
 
     if (mUseClipRect && otherClip) {
       if (!mClipRect.IsEqualInterior(*otherClip)) {
         aGeometryChanged = true;
         nsIntRegion tmp; 
-        tmp.Xor(mClipRect, *otherClip); 
+        tmp.Xor(ParentLayerIntRect::ToUntyped(mClipRect), ParentLayerIntRect::ToUntyped(*otherClip)); 
         AddRegion(result, tmp);
       }
     }
 
     mLayer->ClearInvalidRect();
     return result;
   }
 
@@ -194,17 +195,17 @@ struct LayerPropertiesBase : public Laye
   nsRefPtr<Layer> mLayer;
   UniquePtr<LayerPropertiesBase> mMaskLayer;
   nsIntRegion mVisibleRegion;
   nsIntRegion mInvalidRegion;
   Matrix4x4 mTransform;
   float mPostXScale;
   float mPostYScale;
   float mOpacity;
-  nsIntRect mClipRect;
+  ParentLayerIntRect mClipRect;
   bool mUseClipRect;
 };
 
 struct ContainerLayerProperties : public LayerPropertiesBase
 {
   explicit ContainerLayerProperties(ContainerLayer* aLayer)
     : LayerPropertiesBase(aLayer)
     , mPreXScale(aLayer->GetPreXScale())
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -9,16 +9,17 @@
 #include <algorithm>                    // for max, min
 #include "apz/src/AsyncPanZoomController.h"
 #include "CompositableHost.h"           // for CompositableHost
 #include "ImageContainer.h"             // for ImageContainer, etc
 #include "ImageLayers.h"                // for ImageLayer
 #include "LayerSorter.h"                // for SortLayersBy3DZOrder
 #include "LayersLogging.h"              // for AppendToString
 #include "ReadbackLayer.h"              // for ReadbackLayer
+#include "UnitTransforms.h"             // for ViewAs
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "gfxPrefs.h"
 #include "gfxUtils.h"                   // for gfxUtils, etc
 #include "gfx2DGlue.h"
 #include "mozilla/DebugOnly.h"          // for DebugOnly
 #include "mozilla/Telemetry.h"          // for Accumulate
 #include "mozilla/dom/AnimationPlayer.h" // for ComputedTimingFunction
 #include "mozilla/gfx/2D.h"             // for DrawTarget
@@ -196,17 +197,16 @@ Layer::Layer(LayerManager* aManager, voi
   mImplData(aImplData),
   mMaskLayer(nullptr),
   mPostXScale(1.0f),
   mPostYScale(1.0f),
   mOpacity(1.0),
   mMixBlendMode(CompositionOp::OP_OVER),
   mForceIsolatedGroup(false),
   mContentFlags(0),
-  mUseClipRect(false),
   mUseTileSourceRect(false),
   mIsFixedPosition(false),
   mMargins(0, 0, 0, 0),
   mStickyPositionData(nullptr),
   mScrollbarTargetId(FrameMetrics::NULL_SCROLL_ID),
   mScrollbarDirection(ScrollDirection::NONE),
   mScrollbarThumbRatio(0.0f),
   mIsScrollbarContainer(false),
@@ -542,17 +542,17 @@ Layer::CanUseOpaqueSurface()
   // in the container.
   ContainerLayer* parent = GetParent();
   return parent && parent->GetFirstChild() == this &&
     parent->CanUseOpaqueSurface();
 }
 
 // NB: eventually these methods will be defined unconditionally, and
 // can be moved into Layers.h
-const nsIntRect*
+const Maybe<ParentLayerIntRect>&
 Layer::GetEffectiveClipRect()
 {
   if (LayerComposite* shadow = AsLayerComposite()) {
     return shadow->GetShadowClipRect();
   }
   return GetClipRect();
 }
 
@@ -668,17 +668,19 @@ Layer::CalculateScissorRect(const Render
   } else {
     currentClip = aCurrentScissorRect;
   }
 
   if (!GetEffectiveClipRect()) {
     return currentClip;
   }
 
-  const RenderTargetIntRect clipRect = RenderTargetPixel::FromUntyped(*GetEffectiveClipRect());
+  const RenderTargetIntRect clipRect =
+    ViewAs<RenderTargetPixel>(*GetEffectiveClipRect(),
+                              PixelCastJustification::RenderTargetIsParentLayerForRoot);
   if (clipRect.IsEmpty()) {
     // We might have a non-translation transform in the container so we can't
     // use the code path below.
     return RenderTargetIntRect(currentClip.TopLeft(), RenderTargetIntSize(0, 0));
   }
 
   RenderTargetIntRect scissor = clipRect;
   if (!container->UseIntermediateSurface()) {
@@ -689,17 +691,17 @@ Layer::CalculateScissorRect(const Render
                  "Non preserves axis aligned transform with clipped child should have forced intermediate surface");
     gfx::Rect r(scissor.x, scissor.y, scissor.width, scissor.height);
     gfxRect trScissor = gfx::ThebesRect(matrix.TransformBounds(r));
     trScissor.Round();
     nsIntRect tmp;
     if (!gfxUtils::GfxRectToIntRect(trScissor, &tmp)) {
       return RenderTargetIntRect(currentClip.TopLeft(), RenderTargetIntSize(0, 0));
     }
-    scissor = RenderTargetPixel::FromUntyped(tmp);
+    scissor = ViewAs<RenderTargetPixel>(tmp);
 
     // Find the nearest ancestor with an intermediate surface
     do {
       container = container->GetParent();
     } while (container && !container->UseIntermediateSurface());
   }
 
   if (container) {
@@ -879,17 +881,17 @@ Layer::GetVisibleRegionRelativeToRootLay
 
     // Translate the accumulated visible region of |this| by the offset of
     // |layer|.
     aResult.MoveBy(currentLayerOffset.x, currentLayerOffset.y);
 
     // If the parent layer clips its lower layers, clip the visible region
     // we're accumulating.
     if (layer->GetEffectiveClipRect()) {
-      aResult.AndWith(*layer->GetEffectiveClipRect());
+      aResult.AndWith(ParentLayerIntRect::ToUntyped(*layer->GetEffectiveClipRect()));
     }
 
     // Now we need to walk across the list of siblings for this parent layer,
     // checking to see if any of these layer trees obscure |this|. If so,
     // remove these areas from the visible region as well. This will pick up
     // chrome overlays like a tab modal prompt.
     Layer* sibling;
     for (sibling = layer->GetNextSibling(); sibling;
@@ -1094,17 +1096,17 @@ ContainerLayer::FillSpecificAttributes(S
                                     reinterpret_cast<uint64_t>(mHMDInfo.get()));
 }
 
 bool
 ContainerLayer::HasMultipleChildren()
 {
   uint32_t count = 0;
   for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
-    const nsIntRect *clipRect = child->GetEffectiveClipRect();
+    const Maybe<ParentLayerIntRect>& clipRect = child->GetEffectiveClipRect();
     if (clipRect && clipRect->IsEmpty())
       continue;
     if (child->GetVisibleRegion().IsEmpty())
       continue;
     ++count;
     if (count > 1)
       return true;
   }
@@ -1161,17 +1163,17 @@ ContainerLayer::DefaultComputeEffectiveT
       gfx::Matrix contTransform;
       if (!mEffectiveTransform.Is2D(&contTransform) ||
 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
         !contTransform.PreservesAxisAlignedRectangles()) {
 #else
         gfx::ThebesMatrix(contTransform).HasNonIntegerTranslation()) {
 #endif
         for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
-          const nsIntRect *clipRect = child->GetEffectiveClipRect();
+          const Maybe<ParentLayerIntRect>& clipRect = child->GetEffectiveClipRect();
           /* We can't (easily) forward our transform to children with a non-empty clip
            * rect since it would need to be adjusted for the transform. See
            * the calculations performed by CalculateScissorRect above.
            * Nor for a child with a mask layer.
            */
           if ((clipRect && !clipRect->IsEmpty() && !child->GetVisibleRegion().IsEmpty()) ||
               child->GetMaskLayer()) {
             useIntermediateSurface = true;
@@ -1560,18 +1562,18 @@ Layer::LogSelf(const char* aPrefix)
 void
 Layer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
 {
   aStream << aPrefix;
   aStream << nsPrintfCString("%s%s (0x%p)", mManager->Name(), Name(), this).get();
 
   layers::PrintInfo(aStream, AsLayerComposite());
 
-  if (mUseClipRect) {
-    AppendToString(aStream, mClipRect, " [clip=", "]");
+  if (mClipRect) {
+    AppendToString(aStream, *mClipRect, " [clip=", "]");
   }
   if (1.0 != mPostXScale || 1.0 != mPostYScale) {
     aStream << nsPrintfCString(" [postScale=%g, %g]", mPostXScale, mPostYScale).get();
   }
   if (!mTransform.IsIdentity()) {
     AppendToString(aStream, mTransform, " [transform=", "]");
   }
   if (!mLayerBounds.IsEmpty()) {
@@ -1645,18 +1647,20 @@ DumpTransform(layerscope::LayersPacket::
     aLayerMatrix->add_m(aMatrix._31), aLayerMatrix->add_m(aMatrix._32);
     aLayerMatrix->add_m(aMatrix._33), aLayerMatrix->add_m(aMatrix._34);
     aLayerMatrix->add_m(aMatrix._41), aLayerMatrix->add_m(aMatrix._42);
     aLayerMatrix->add_m(aMatrix._43), aLayerMatrix->add_m(aMatrix._44);
   }
 }
 
 // The static helper function sets the nsIntRect into the packet
+template <typename T, typename Sub, typename Point, typename SizeT, typename MarginT>
 static void
-DumpRect(layerscope::LayersPacket::Layer::Rect* aLayerRect, const nsIntRect& aRect)
+DumpRect(layerscope::LayersPacket::Layer::Rect* aLayerRect,
+         const BaseRect<T, Sub, Point, SizeT, MarginT>& aRect)
 {
   aLayerRect->set_x(aRect.x);
   aLayerRect->set_y(aRect.y);
   aLayerRect->set_w(aRect.width);
   aLayerRect->set_h(aRect.height);
 }
 
 // The static helper function sets the nsIntRegion into the packet
@@ -1677,29 +1681,29 @@ Layer::DumpPacket(layerscope::LayersPack
   LayersPacket::Layer* layer = aPacket->add_layer();
   // Basic information
   layer->set_type(LayersPacket::Layer::UnknownLayer);
   layer->set_ptr(reinterpret_cast<uint64_t>(this));
   layer->set_parentptr(reinterpret_cast<uint64_t>(aParent));
   // Shadow
   if (LayerComposite* lc = AsLayerComposite()) {
     LayersPacket::Layer::Shadow* s = layer->mutable_shadow();
-    if (const nsIntRect* clipRect = lc->GetShadowClipRect()) {
+    if (const Maybe<ParentLayerIntRect>& clipRect = lc->GetShadowClipRect()) {
       DumpRect(s->mutable_clip(), *clipRect);
     }
     if (!lc->GetShadowTransform().IsIdentity()) {
       DumpTransform(s->mutable_transform(), lc->GetShadowTransform());
     }
     if (!lc->GetShadowVisibleRegion().IsEmpty()) {
       DumpRegion(s->mutable_vregion(), lc->GetShadowVisibleRegion());
     }
   }
   // Clip
-  if (mUseClipRect) {
-    DumpRect(layer->mutable_clip(), mClipRect);
+  if (mClipRect) {
+    DumpRect(layer->mutable_clip(), *mClipRect);
   }
   // Transform
   if (!mTransform.IsIdentity()) {
     DumpTransform(layer->mutable_transform(), mTransform);
   }
   // Visible region
   if (!mVisibleRegion.IsEmpty()) {
     DumpRegion(layer->mutable_vregion(), mVisibleRegion);
@@ -2042,17 +2046,17 @@ LayerManager::IsLogEnabled()
 }
 
 void
 PrintInfo(std::stringstream& aStream, LayerComposite* aLayerComposite)
 {
   if (!aLayerComposite) {
     return;
   }
-  if (const nsIntRect* clipRect = aLayerComposite->GetShadowClipRect()) {
+  if (const Maybe<ParentLayerIntRect>& clipRect = aLayerComposite->GetShadowClipRect()) {
     AppendToString(aStream, *clipRect, " [shadow-clip=", "]");
   }
   if (!aLayerComposite->GetShadowTransform().IsIdentity()) {
     AppendToString(aStream, aLayerComposite->GetShadowTransform(), " [shadow-transform=", "]");
   }
   if (!aLayerComposite->GetShadowVisibleRegion().IsEmpty()) {
     AppendToString(aStream, aLayerComposite->GetShadowVisibleRegion(), " [shadow-visible=", "]");
   }
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -5,27 +5,28 @@
 
 #ifndef GFX_LAYERS_H
 #define GFX_LAYERS_H
 
 #include <stdint.h>                     // for uint32_t, uint64_t, uint8_t
 #include <stdio.h>                      // for FILE
 #include <sys/types.h>                  // for int32_t, int64_t
 #include "FrameMetrics.h"               // for FrameMetrics
-#include "Units.h"                      // for LayerMargin, LayerPoint
+#include "Units.h"                      // for LayerMargin, LayerPoint, ParentLayerIntRect
 #include "gfxContext.h"                 // for GraphicsOperator
 #include "gfxTypes.h"
 #include "gfxColor.h"                   // for gfxRGBA
 #include "GraphicsFilter.h"             // for GraphicsFilter
 #include "gfxPoint.h"                   // for gfxPoint
 #include "gfxRect.h"                    // for gfxRect
 #include "gfx2DGlue.h"
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2, etc
 #include "mozilla/DebugOnly.h"          // for DebugOnly
 #include "mozilla/EventForwards.h"      // for nsPaintEvent
+#include "mozilla/Maybe.h"              // for Maybe
 #include "mozilla/RefPtr.h"             // for TemporaryRef
 #include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc
 #include "mozilla/TimeStamp.h"          // for TimeStamp, TimeDuration
 #include "mozilla/gfx/BaseMargin.h"     // for BaseMargin
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 #include "mozilla/gfx/UserData.h"       // for UserData, etc
@@ -985,39 +986,38 @@ public:
    * Set a clip rect which will be applied to this layer as it is
    * composited to the destination. The coordinates are relative to
    * the parent layer (i.e. the contents of this layer
    * are transformed before this clip rect is applied).
    * For the root layer, the coordinates are relative to the widget,
    * in device pixels.
    * If aRect is null no clipping will be performed.
    */
-  void SetClipRect(const nsIntRect* aRect)
+  void SetClipRect(const Maybe<ParentLayerIntRect>& aRect)
   {
-    if (mUseClipRect) {
+    if (mClipRect) {
       if (!aRect) {
         MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ClipRect was %d,%d,%d,%d is <none>", this,
-                         mClipRect.x, mClipRect.y, mClipRect.width, mClipRect.height));
-        mUseClipRect = false;
+                         mClipRect->x, mClipRect->y, mClipRect->width, mClipRect->height));
+        mClipRect.reset();
         Mutated();
       } else {
-        if (!aRect->IsEqualEdges(mClipRect)) {
+        if (!aRect->IsEqualEdges(*mClipRect)) {
           MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ClipRect was %d,%d,%d,%d is %d,%d,%d,%d", this,
-                           mClipRect.x, mClipRect.y, mClipRect.width, mClipRect.height,
+                           mClipRect->x, mClipRect->y, mClipRect->width, mClipRect->height,
                            aRect->x, aRect->y, aRect->width, aRect->height));
-          mClipRect = *aRect;
+          mClipRect = aRect;
           Mutated();
         }
       }
     } else {
       if (aRect) {
         MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ClipRect was <none> is %d,%d,%d,%d", this,
                          aRect->x, aRect->y, aRect->width, aRect->height));
-        mUseClipRect = true;
-        mClipRect = *aRect;
+        mClipRect = aRect;
         Mutated();
       }
     }
   }
 
   /**
    * CONSTRUCTION PHASE ONLY
    * Set a layer to mask this layer.
@@ -1222,17 +1222,17 @@ public:
       mIsScrollbarContainer = true;
       Mutated();
     }
   }
 
   // These getters can be used anytime.
   float GetOpacity() { return mOpacity; }
   gfx::CompositionOp GetMixBlendMode() const { return mMixBlendMode; }
-  const nsIntRect* GetClipRect() { return mUseClipRect ? &mClipRect : nullptr; }
+  const Maybe<ParentLayerIntRect>& GetClipRect() const { return mClipRect; }
   uint32_t GetContentFlags() { return mContentFlags; }
   const nsIntRect& GetLayerBounds() const { return mLayerBounds; }
   const nsIntRegion& GetVisibleRegion() const { return mVisibleRegion; }
   const FrameMetrics& GetFrameMetrics(uint32_t aIndex) const;
   uint32_t GetFrameMetricsCount() const { return mFrameMetrics.Length(); }
   const nsTArray<FrameMetrics>& GetAllFrameMetrics() { return mFrameMetrics; }
   bool HasScrollableFrameMetrics() const;
   bool IsScrollInfoLayer() const;
@@ -1413,17 +1413,17 @@ public:
    * Dynamic cast to a ShadowableLayer.  Return null if this is not a
    * ShadowableLayer.  Can be used anytime.
    */
   virtual ShadowableLayer* AsShadowableLayer() { return nullptr; }
 
   // These getters can be used anytime.  They return the effective
   // values that should be used when drawing this layer to screen,
   // accounting for this layer possibly being a shadow.
-  const nsIntRect* GetEffectiveClipRect();
+  const Maybe<ParentLayerIntRect>& GetEffectiveClipRect();
   const nsIntRegion& GetEffectiveVisibleRegion();
 
   /**
    * Returns the product of the opacities of this layer and all ancestors up
    * to and excluding the nearest ancestor that has UseIntermediateSurface() set.
    */
   float GetEffectiveOpacity();
 
@@ -1695,22 +1695,21 @@ protected:
   gfx::Matrix4x4 mEffectiveTransform;
   AnimationArray mAnimations;
   // See mPendingTransform above.
   nsAutoPtr<AnimationArray> mPendingAnimations;
   InfallibleTArray<AnimData> mAnimationData;
   float mOpacity;
   gfx::CompositionOp mMixBlendMode;
   bool mForceIsolatedGroup;
-  nsIntRect mClipRect;
+  Maybe<ParentLayerIntRect> mClipRect;
   nsIntRect mTileSourceRect;
   nsIntRegion mInvalidRegion;
   nsTArray<nsRefPtr<AsyncPanZoomController> > mApzcs;
   uint32_t mContentFlags;
-  bool mUseClipRect;
   bool mUseTileSourceRect;
   bool mIsFixedPosition;
   LayerPoint mAnchor;
   LayerMargin mMargins;
   struct StickyPositionData {
     FrameMetrics::ViewID mScrollId;
     LayerRect mOuter;
     LayerRect mInner;
--- a/gfx/layers/ReadbackProcessor.cpp
+++ b/gfx/layers/ReadbackProcessor.cpp
@@ -2,16 +2,18 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ReadbackProcessor.h"
 #include <sys/types.h>                  // for int32_t
 #include "Layers.h"                     // for Layer, PaintedLayer, etc
 #include "ReadbackLayer.h"              // for ReadbackLayer, ReadbackSink
+#include "UnitTransforms.h"             // for ViewAs
+#include "Units.h"                      // for ParentLayerIntRect
 #include "gfxColor.h"                   // for gfxRGBA
 #include "gfxContext.h"                 // for gfxContext
 #include "gfxUtils.h"
 #include "gfxRect.h"                    // for gfxRect
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
 #include "nsAutoPtr.h"                  // for nsRefPtr, nsAutoPtr
@@ -71,18 +73,18 @@ FindBackgroundLayer(ReadbackLayer* aLaye
       return nullptr;
 
     if (l->GetEffectiveOpacity() != 1.0 ||
         l->GetMaskLayer() ||
         !(l->GetContentFlags() & Layer::CONTENT_OPAQUE))
       return nullptr;
 
     // cliprects are post-transform
-    const nsIntRect* clipRect = l->GetEffectiveClipRect();
-    if (clipRect && !clipRect->Contains(nsIntRect(transformOffset, aLayer->GetSize())))
+    const Maybe<ParentLayerIntRect>& clipRect = l->GetEffectiveClipRect();
+    if (clipRect && !clipRect->Contains(ViewAs<ParentLayerPixel>(nsIntRect(transformOffset, aLayer->GetSize()))))
       return nullptr;
 
     Layer::LayerType type = l->GetType();
     if (type != Layer::TYPE_COLOR && type != Layer::TYPE_PAINTED)
       return nullptr;
 
     *aOffset = backgroundOffset - transformOffset;
     return l;
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -24,16 +24,17 @@
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsThreadUtils.h"              // for NS_IsMainThread
 #include "mozilla/gfx/Logging.h"        // for gfx::TreeLog
 #include "UnitTransforms.h"             // for ViewAs
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "OverscrollHandoffState.h"     // for OverscrollHandoffState
 #include "LayersLogging.h"              // for Stringify
+#include "Units.h"                      // for ParentlayerPixel
 
 #define ENABLE_APZCTM_LOGGING 0
 // #define ENABLE_APZCTM_LOGGING 1
 
 #if ENABLE_APZCTM_LOGGING
 #  define APZCTM_LOG(...) printf_stderr("APZCTM: " __VA_ARGS__)
 #else
 #  define APZCTM_LOG(...)
@@ -197,17 +198,17 @@ APZCTreeManager::UpdateHitTestingTree(Co
 // Compute the clip region to be used for a layer with an APZC. This function
 // is only called for layers which actually have scrollable metrics and an APZC.
 static ParentLayerIntRegion
 ComputeClipRegion(GeckoContentController* aController,
                   const LayerMetricsWrapper& aLayer)
 {
   ParentLayerIntRegion clipRegion;
   if (aLayer.GetClipRect()) {
-    clipRegion = ViewAs<ParentLayerPixel>(*aLayer.GetClipRect());
+    clipRegion = *aLayer.GetClipRect();
   } else {
     // if there is no clip on this layer (which should only happen for the
     // root scrollable layer in a process, or for some of the LayerMetrics
     // expansions of a multi-metrics layer), fall back to using the comp
     // bounds which should be equivalent.
     clipRegion = RoundedToInt(aLayer.Metrics().mCompositionBounds);
   }
 
@@ -329,17 +330,17 @@ APZCTreeManager::PrepareNodeForLayer(con
     needsApzc = false;
   }
 
   nsRefPtr<HitTestingTreeNode> node = nullptr;
   if (!needsApzc) {
     node = RecycleOrCreateNode(aState, nullptr);
     AttachNodeToTree(node, aParent, aNextSibling);
     node->SetHitTestData(GetEventRegions(aLayer), aLayer.GetTransform(),
-        aLayer.GetClipRect() ? Some(ParentLayerIntRegion(ViewAs<ParentLayerPixel>(*aLayer.GetClipRect()))) : Nothing(),
+        aLayer.GetClipRect() ? Some(ParentLayerIntRegion(*aLayer.GetClipRect())) : Nothing(),
         GetEventRegionsOverride(aParent, aLayer));
     return node;
   }
 
   AsyncPanZoomController* apzc = nullptr;
   // If we get here, aLayer is a scrollable layer and somebody
   // has registered a GeckoContentController for it, so we need to ensure
   // it has an APZC instance to manage its scrolling.
--- a/gfx/layers/basic/BasicContainerLayer.cpp
+++ b/gfx/layers/basic/BasicContainerLayer.cpp
@@ -97,17 +97,17 @@ BasicContainerLayer::ChildrenPartitionVi
     if (!l->GetEffectiveTransform().CanDraw2D(&childTransform) ||
         ThebesMatrix(childTransform).HasNonIntegerTranslation() ||
         l->GetEffectiveOpacity() != 1.0)
       return false;
     nsIntRegion childRegion = l->GetEffectiveVisibleRegion();
     childRegion.MoveBy(int32_t(childTransform._31), int32_t(childTransform._32));
     childRegion.And(childRegion, rect);
     if (l->GetClipRect()) {
-      childRegion.And(childRegion, *l->GetClipRect() + offset);
+      childRegion.And(childRegion, ParentLayerIntRect::ToUntyped(*l->GetClipRect()) + offset);
     }
     nsIntRegion intersection;
     intersection.And(covered, childRegion);
     if (!intersection.IsEmpty())
       return false;
     covered.Or(covered, childRegion);
   }
 
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -319,19 +319,19 @@ MarkLayersHidden(Layer* aLayer, const ns
 
   // Allow aLayer or aLayer's descendants to cover underlying layers
   // only if it's opaque.
   if (aLayer->GetOpacity() != 1.0f) {
     newFlags &= ~ALLOW_OPAQUE;
   }
 
   {
-    const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
+    const Maybe<ParentLayerIntRect>& clipRect = aLayer->GetEffectiveClipRect();
     if (clipRect) {
-      nsIntRect cr = *clipRect;
+      nsIntRect cr = ParentLayerIntRect::ToUntyped(*clipRect);
       // clipRect is in the container's coordinate system. Get it into the
       // global coordinate system.
       if (aLayer->GetParent()) {
         Matrix tr;
         if (aLayer->GetParent()->GetEffectiveTransform().CanDraw2D(&tr)) {
           // Clip rect is applied after aLayer's transform, i.e., in the coordinate
           // system of aLayer's parent.
           TransformIntRect(cr, tr, ToInsideIntRect);
@@ -399,19 +399,19 @@ ApplyDoubleBuffering(Layer* aLayer, cons
 {
   BasicImplData* data = ToData(aLayer);
   if (data->IsHidden())
     return;
 
   nsIntRect newVisibleRect(aVisibleRect);
 
   {
-    const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
+    const Maybe<ParentLayerIntRect>& clipRect = aLayer->GetEffectiveClipRect();
     if (clipRect) {
-      nsIntRect cr = *clipRect;
+      nsIntRect cr = ParentLayerIntRect::ToUntyped(*clipRect);
       // clipRect is in the container's coordinate system. Get it into the
       // global coordinate system.
       if (aLayer->GetParent()) {
         Matrix tr;
         if (aLayer->GetParent()->GetEffectiveTransform().CanDraw2D(&tr)) {
           NS_ASSERTION(!ThebesMatrix(tr).HasNonIntegerTranslation(),
                        "Parent can only have an integer translation");
           cr += nsIntPoint(int32_t(tr._31), int32_t(tr._32));
@@ -860,17 +860,17 @@ BasicLayerManager::PaintLayer(gfxContext
   // Don't attempt to paint layers with a singular transform, cairo will
   // just throw an error.
   if (aLayer->GetEffectiveTransform().IsSingular()) {
     return;
   }
 
   RenderTraceScope trace("BasicLayerManager::PaintLayer", "707070");
 
-  const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
+  const Maybe<ParentLayerIntRect>& clipRect = aLayer->GetEffectiveClipRect();
   BasicContainerLayer* container =
     static_cast<BasicContainerLayer*>(aLayer->AsContainerLayer());
   bool needsGroup = container && container->UseIntermediateSurface();
   BasicImplData* data = ToData(aLayer);
   bool needsClipToVisibleRegion =
     data->GetClipToVisibleRegion() && !aLayer->AsPaintedLayer();
   NS_ASSERTION(needsGroup || !container ||
                container->GetOperator() == CompositionOp::OP_OVER,
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -135,22 +135,20 @@ GetBaseTransform2D(Layer* aLayer, Matrix
   return (aLayer->AsLayerComposite()->GetShadowTransformSetByAnimation() ?
           aLayer->GetLocalTransform() : aLayer->GetTransform()).Is2D(aTransform);
 }
 
 static void
 TransformClipRect(Layer* aLayer,
                   const Matrix4x4& aTransform)
 {
-  const nsIntRect* clipRect = aLayer->AsLayerComposite()->GetShadowClipRect();
+  const Maybe<ParentLayerIntRect>& clipRect = aLayer->AsLayerComposite()->GetShadowClipRect();
   if (clipRect) {
-    LayerIntRect transformed = TransformTo<LayerPixel>(
-        aTransform, LayerIntRect::FromUntyped(*clipRect));
-    nsIntRect shadowClip = LayerIntRect::ToUntyped(transformed);
-    aLayer->AsLayerComposite()->SetShadowClipRect(&shadowClip);
+    ParentLayerIntRect transformed = TransformTo<ParentLayerPixel>(aTransform, *clipRect);
+    aLayer->AsLayerComposite()->SetShadowClipRect(Some(transformed));
   }
 }
 
 /**
  * Set the given transform as the shadow transform on the layer, assuming
  * that the given transform already has the pre- and post-scales applied.
  * That is, this function cancels out the pre- and post-scales from aTransform
  * before setting it as the shadow transform on the layer, so that when
@@ -560,18 +558,18 @@ AdjustForClip(const Matrix4x4& asyncTran
   Matrix4x4 result = asyncTransform;
 
   // Container layers start at the origin, but they are clipped to where they
   // actually have content on the screen. The tree transform is meant to apply
   // to the clipped area. If the tree transform includes a scale component,
   // then applying it to container as-is will produce incorrect results. To
   // avoid this, translate the layer so that the clip rect starts at the origin,
   // apply the tree transform, and translate back.
-  if (const nsIntRect* shadowClipRect = aLayer->AsLayerComposite()->GetShadowClipRect()) {
-    if (shadowClipRect->TopLeft() != nsIntPoint()) {  // avoid a gratuitous change of basis
+  if (const Maybe<ParentLayerIntRect>& shadowClipRect = aLayer->AsLayerComposite()->GetShadowClipRect()) {
+    if (shadowClipRect->TopLeft() != ParentLayerIntPoint()) {  // avoid a gratuitous change of basis
       result.ChangeBasis(shadowClipRect->x, shadowClipRect->y, 0);
     }
   }
   return result;
 }
 
 bool
 AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
@@ -584,17 +582,17 @@ AsyncCompositionManager::ApplyAsyncConte
   }
 
   Matrix4x4 oldTransform = aLayer->GetTransform();
 
   Matrix4x4 combinedAsyncTransformWithoutOverscroll;
   Matrix4x4 combinedAsyncTransform;
   bool hasAsyncTransform = false;
   LayerMargin fixedLayerMargins(0, 0, 0, 0);
-  Maybe<nsIntRect> clipRect = ToMaybe(aLayer->AsLayerComposite()->GetShadowClipRect());
+  Maybe<ParentLayerIntRect> clipRect = aLayer->AsLayerComposite()->GetShadowClipRect();
 
   for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) {
     AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(i);
     if (!controller) {
       continue;
     }
 
     hasAsyncTransform = true;
@@ -634,25 +632,24 @@ AsyncCompositionManager::ApplyAsyncConte
       // layer, the clip rect needs to be adjusted for the async transforms of
       // the scroll frames other than the bottom-most one.
       // To make this adjustment, we start with the Layout-provided clip rect,
       // and at each level other than the bottom, transform it by the async
       // transform at that level, and then re-intersect it with the composition
       // bounds at that level.
       ParentLayerRect transformed = TransformTo<ParentLayerPixel>(
         (Matrix4x4(asyncTransformWithoutOverscroll) * overscrollTransform),
-        ParentLayerRect(ViewAs<ParentLayerPixel>(*clipRect)));
-      clipRect = Some(ParentLayerIntRect::ToUntyped(
-        RoundedOut(transformed.Intersect(metrics.mCompositionBounds))));
+        ParentLayerRect(*clipRect));
+      clipRect = Some(RoundedOut(transformed.Intersect(metrics.mCompositionBounds)));
     }
   }
 
   if (hasAsyncTransform) {
     if (clipRect) {
-      aLayer->AsLayerComposite()->SetShadowClipRect(clipRect.ptr());
+      aLayer->AsLayerComposite()->SetShadowClipRect(clipRect);
     }
     // Apply the APZ transform on top of GetLocalTransform() here (rather than
     // GetTransform()) in case the OMTA code in SampleAnimations already set a
     // shadow transform; in that case we want to apply ours on top of that one
     // rather than clobber it.
     SetShadowTransform(aLayer,
         aLayer->GetLocalTransform() * AdjustForClip(combinedAsyncTransform, aLayer));
 
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -16,16 +16,17 @@
 #include "GeckoProfiler.h"              // for profiler_set_frame_number, etc
 #include "ImageLayerComposite.h"        // for ImageLayerComposite
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
 #include "LayerScope.h"                 // for LayerScope Tool
 #include "protobuf/LayerScopePacket.pb.h" // for protobuf (LayerScope)
 #include "PaintedLayerComposite.h"      // for PaintedLayerComposite
 #include "TiledLayerBuffer.h"           // for TiledLayerComposer
 #include "Units.h"                      // for ScreenIntRect
+#include "UnitTransforms.h"             // for ViewAs
 #include "gfx2DGlue.h"                  // for ToMatrix4x4
 #include "gfxPrefs.h"                   // for gfxPrefs
 #ifdef XP_MACOSX
 #include "gfxPlatformMac.h"
 #endif
 #include "gfxRect.h"                    // for gfxRect
 #include "gfxUtils.h"                   // for frame color util
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
@@ -229,19 +230,19 @@ LayerManagerComposite::ApplyOcclusionCul
   // aOpaqueRegion.
   if (isTranslation &&
       !aLayer->GetMaskLayer() &&
       aLayer->GetLocalOpacity() == 1.0f) {
     if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) {
       localOpaque.Or(localOpaque, composite->GetFullyRenderedRegion());
     }
     localOpaque.MoveBy(transform2d._31, transform2d._32);
-    const nsIntRect* clip = aLayer->GetEffectiveClipRect();
+    const Maybe<ParentLayerIntRect>& clip = aLayer->GetEffectiveClipRect();
     if (clip) {
-      localOpaque.And(localOpaque, *clip);
+      localOpaque.And(localOpaque, ParentLayerIntRect::ToUntyped(*clip));
     }
     aOpaqueRegion.Or(aOpaqueRegion, localOpaque);
   }
 }
 
 bool
 LayerManagerComposite::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
@@ -689,30 +690,30 @@ LayerManagerComposite::Render()
   if (mTarget) {
     invalid = mTargetBounds;
   } else {
     invalid = mInvalidRegion;
     // Reset the invalid region now that we've begun compositing.
     mInvalidRegion.SetEmpty();
   }
 
-  nsIntRect clipRect;
+  ParentLayerIntRect clipRect;
   Rect bounds(mRenderBounds.x, mRenderBounds.y, mRenderBounds.width, mRenderBounds.height);
   Rect actualBounds;
 
   CompositorBench(mCompositor, bounds);
 
   if (mRoot->GetClipRect()) {
     clipRect = *mRoot->GetClipRect();
     Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
     mCompositor->BeginFrame(invalid, &rect, bounds, nullptr, &actualBounds);
   } else {
     gfx::Rect rect;
     mCompositor->BeginFrame(invalid, nullptr, bounds, &rect, &actualBounds);
-    clipRect = nsIntRect(rect.x, rect.y, rect.width, rect.height);
+    clipRect = ParentLayerIntRect(rect.x, rect.y, rect.width, rect.height);
   }
 
   if (actualBounds.IsEmpty()) {
     mCompositor->GetWidget()->PostRender(this);
     return;
   }
 
   // Allow widget to render a custom background.
@@ -724,30 +725,30 @@ LayerManagerComposite::Render()
   RefPtr<CompositingRenderTarget> previousTarget;
   if (haveLayerEffects) {
     previousTarget = PushGroupForLayerEffects();
   } else {
     mTwoPassTmpTarget = nullptr;
   }
 
   // Render our layers.
-  RootLayer()->Prepare(RenderTargetPixel::FromUntyped(clipRect));
-  RootLayer()->RenderLayer(clipRect);
+  RootLayer()->Prepare(ViewAs<RenderTargetPixel>(clipRect, PixelCastJustification::RenderTargetIsParentLayerForRoot));
+  RootLayer()->RenderLayer(ParentLayerIntRect::ToUntyped(clipRect));
 
   if (!mRegionToClear.IsEmpty()) {
     nsIntRegionRectIterator iter(mRegionToClear);
     const nsIntRect *r;
     while ((r = iter.Next())) {
       mCompositor->ClearRect(Rect(r->x, r->y, r->width, r->height));
     }
   }
 
   if (mTwoPassTmpTarget) {
     MOZ_ASSERT(haveLayerEffects);
-    PopGroupForLayerEffects(previousTarget, clipRect,
+    PopGroupForLayerEffects(previousTarget, ParentLayerIntRect::ToUntyped(clipRect),
                             grayscaleVal, invertVal, contrastVal);
   }
 
   // Allow widget to render a custom foreground.
   mCompositor->GetWidget()->DrawWindowOverlay(this, nsIntRect(actualBounds.x,
                                                               actualBounds.y,
                                                               actualBounds.width,
                                                               actualBounds.height));
@@ -1091,17 +1092,16 @@ LayerManagerComposite::CreateDrawTarget(
 #endif
   return LayerManager::CreateDrawTarget(aSize, aFormat);
 }
 
 LayerComposite::LayerComposite(LayerManagerComposite *aManager)
   : mCompositeManager(aManager)
   , mCompositor(aManager->GetCompositor())
   , mShadowOpacity(1.0)
-  , mUseShadowClipRect(false)
   , mShadowTransformSetByAnimation(false)
   , mDestroyed(false)
   , mLayerComposited(false)
 { }
 
 LayerComposite::~LayerComposite()
 {
 }
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -4,25 +4,27 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_LayerManagerComposite_H
 #define GFX_LayerManagerComposite_H
 
 #include <stdint.h>                     // for int32_t, uint32_t
 #include "GLDefs.h"                     // for GLenum
 #include "Layers.h"
+#include "Units.h"                      // for ParentLayerIntRect
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/RefPtr.h"             // for RefPtr, TemporaryRef
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/LayersTypes.h"  // for LayersBackend, etc
+#include "mozilla/Maybe.h"              // for Maybe
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "nsAString.h"
 #include "nsRefPtr.h"                   // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsRect.h"                     // for nsIntRect
@@ -398,22 +400,19 @@ public:
     mShadowVisibleRegion = aRegion;
   }
 
   void SetShadowOpacity(float aOpacity)
   {
     mShadowOpacity = aOpacity;
   }
 
-  void SetShadowClipRect(const nsIntRect* aRect)
+  void SetShadowClipRect(const Maybe<ParentLayerIntRect>& aRect)
   {
-    mUseShadowClipRect = aRect != nullptr;
-    if (aRect) {
-      mShadowClipRect = *aRect;
-    }
+    mShadowClipRect = aRect;
   }
 
   void SetShadowTransform(const gfx::Matrix4x4& aMatrix)
   {
     mShadowTransform = aMatrix;
   }
   void SetShadowTransformSetByAnimation(bool aSetByAnimation)
   {
@@ -427,38 +426,37 @@ public:
 
   void SetClearRect(const nsIntRect& aRect)
   {
     mClearRect = aRect;
   }
 
   // These getters can be used anytime.
   float GetShadowOpacity() { return mShadowOpacity; }
-  const nsIntRect* GetShadowClipRect() { return mUseShadowClipRect ? &mShadowClipRect : nullptr; }
+  const Maybe<ParentLayerIntRect>& GetShadowClipRect() { return mShadowClipRect; }
   const nsIntRegion& GetShadowVisibleRegion() { return mShadowVisibleRegion; }
   const gfx::Matrix4x4& GetShadowTransform() { return mShadowTransform; }
   bool GetShadowTransformSetByAnimation() { return mShadowTransformSetByAnimation; }
   bool HasLayerBeenComposited() { return mLayerComposited; }
   nsIntRect GetClearRect() { return mClearRect; }
 
   /**
    * Return the part of the visible region that has been fully rendered.
    * While progressive drawing is in progress this region will be
    * a subset of the shadow visible region.
    */
   nsIntRegion GetFullyRenderedRegion();
 
 protected:
   gfx::Matrix4x4 mShadowTransform;
   nsIntRegion mShadowVisibleRegion;
-  nsIntRect mShadowClipRect;
+  Maybe<ParentLayerIntRect> mShadowClipRect;
   LayerManagerComposite* mCompositeManager;
   RefPtr<Compositor> mCompositor;
   float mShadowOpacity;
-  bool mUseShadowClipRect;
   bool mShadowTransformSetByAnimation;
   bool mDestroyed;
   bool mLayerComposited;
   nsIntRect mClearRect;
 };
 
 
 } /* layers */
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -322,17 +322,17 @@ LayerTransactionParent::RecvUpdate(Infal
       const LayerAttributes& attrs = osla.attrs();
 
       const CommonLayerAttributes& common = attrs.common();
       layer->SetLayerBounds(common.layerBounds());
       layer->SetVisibleRegion(common.visibleRegion());
       layer->SetEventRegions(common.eventRegions());
       layer->SetContentFlags(common.contentFlags());
       layer->SetOpacity(common.opacity());
-      layer->SetClipRect(common.useClipRect() ? &common.clipRect() : nullptr);
+      layer->SetClipRect(common.useClipRect() ? Some(common.clipRect()) : Nothing());
       layer->SetBaseTransform(common.transform().value());
       layer->SetPostScale(common.postXScale(), common.postYScale());
       layer->SetIsFixedPosition(common.isFixedPosition());
       layer->SetFixedPositionAnchor(common.fixedPositionAnchor());
       layer->SetFixedPositionMargins(common.fixedPositionMargin());
       if (common.isStickyPosition()) {
         layer->SetStickyPositionData(common.stickyScrollContainerId(),
                                      common.stickyScrollRangeOuter(),
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -28,16 +28,17 @@ using class mozilla::TimeDuration from "
 using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
 using mozilla::ScreenRotation from "mozilla/WidgetUtils.h";
 using nsCSSProperty from "nsCSSProperty.h";
 using mozilla::dom::ScreenOrientation from "mozilla/dom/ScreenOrientation.h";
 using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 using mozilla::LayerMargin from "Units.h";
 using mozilla::LayerPoint from "Units.h";
 using mozilla::LayerRect from "Units.h";
+using mozilla::ParentLayerIntRect from "Units.h";
 using mozilla::layers::ScaleMode from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::EventRegions from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::EventRegionsOverride from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::DiagnosticTypes from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
 using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
 using struct mozilla::layers::FenceHandle from "mozilla/layers/FenceUtils.h";
 using struct mozilla::layers::FenceHandleFromChild from "mozilla/layers/FenceUtils.h";
@@ -199,17 +200,17 @@ struct CommonLayerAttributes {
   nsIntRegion visibleRegion;
   EventRegions eventRegions;
   TransformMatrix transform;
   float postXScale;
   float postYScale;
   uint32_t contentFlags;
   float opacity;
   bool useClipRect;
-  nsIntRect clipRect;
+  ParentLayerIntRect clipRect;
   bool isFixedPosition;
   LayerPoint fixedPositionAnchor;
   LayerMargin fixedPositionMargin;
   bool isStickyPosition;
   uint64_t stickyScrollContainerId;
   LayerRect stickyScrollRangeOuter;
   LayerRect stickyScrollRangeInner;
   uint64_t scrollbarTargetContainerId;
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -582,17 +582,17 @@ ShadowLayerForwarder::EndTransaction(Inf
     common.eventRegions() = mutant->GetEventRegions();
     common.postXScale() = mutant->GetPostXScale();
     common.postYScale() = mutant->GetPostYScale();
     common.transform() = mutant->GetBaseTransform();
     common.contentFlags() = mutant->GetContentFlags();
     common.opacity() = mutant->GetOpacity();
     common.useClipRect() = !!mutant->GetClipRect();
     common.clipRect() = (common.useClipRect() ?
-                         *mutant->GetClipRect() : nsIntRect());
+                         *mutant->GetClipRect() : ParentLayerIntRect());
     common.isFixedPosition() = mutant->GetIsFixedPosition();
     common.fixedPositionAnchor() = mutant->GetFixedPositionAnchor();
     common.fixedPositionMargin() = mutant->GetFixedPositionMargins();
     common.isStickyPosition() = mutant->GetIsStickyPosition();
     if (mutant->GetIsStickyPosition()) {
       common.stickyScrollContainerId() = mutant->GetStickyScrollContainerId();
       common.stickyScrollRangeOuter() = mutant->GetStickyScrollRangeOuter();
       common.stickyScrollRangeInner() = mutant->GetStickyScrollRangeInner();
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -14,16 +14,17 @@
 #include "mozilla/layers/LayerMetricsWrapper.h"
 #include "mozilla/layers/APZThreadUtils.h"
 #include "mozilla/UniquePtr.h"
 #include "apz/src/AsyncPanZoomController.h"
 #include "apz/src/HitTestingTreeNode.h"
 #include "base/task.h"
 #include "Layers.h"
 #include "TestLayers.h"
+#include "UnitTransforms.h"
 #include "gfxPrefs.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using ::testing::_;
 using ::testing::NiceMock;
 using ::testing::AtLeast;
@@ -1784,17 +1785,17 @@ protected:
     FrameMetrics metrics;
     metrics.SetScrollId(aScrollId);
     nsIntRect layerBound = aLayer->GetVisibleRegion().GetBounds();
     metrics.mCompositionBounds = ParentLayerRect(layerBound.x, layerBound.y,
                                                  layerBound.width, layerBound.height);
     metrics.SetScrollableRect(aScrollableRect);
     metrics.SetScrollOffset(CSSPoint(0, 0));
     aLayer->SetFrameMetrics(metrics);
-    aLayer->SetClipRect(&layerBound);
+    aLayer->SetClipRect(Some(ViewAs<ParentLayerPixel>(layerBound)));
     if (!aScrollableRect.IsEqualEdges(CSSRect(-1, -1, -1, -1))) {
       // The purpose of this is to roughly mimic what layout would do in the
       // case of a scrollable frame with the event regions and clip. This lets
       // us exercise the hit-testing code in APZCTreeManager
       EventRegions er = aLayer->GetEventRegions();
       nsIntRect scrollRect = LayerIntRect::ToUntyped(RoundedToInt(aScrollableRect * metrics.LayersPixelsPerCSSPixel()));
       er.mHitRegion = nsIntRegion(nsIntRect(layerBound.TopLeft(), scrollRect.Size()));
       aLayer->SetEventRegions(er);
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -2,45 +2,48 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/DebugOnly.h"
 
 #include "FrameLayerBuilder.h"
 
+#include "mozilla/LookAndFeel.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
 #include "mozilla/gfx/Matrix.h"
-#include "nsDisplayList.h"
-#include "nsPresContext.h"
-#include "nsLayoutUtils.h"
-#include "Layers.h"
-#include "BasicLayers.h"
-#include "gfxUtils.h"
-#include "nsRenderingContext.h"
-#include "MaskLayerImageCache.h"
-#include "nsIScrollableFrame.h"
-#include "nsPrintfCString.h"
-#include "LayerTreeInvalidation.h"
-#include "nsSVGIntegrationUtils.h"
-#include "ImageContainer.h"
 #include "ActiveLayerTracker.h"
+#include "BasicLayers.h"
+#include "ImageContainer.h"
+#include "LayerTreeInvalidation.h"
+#include "Layers.h"
+#include "MaskLayerImageCache.h"
+#include "UnitTransforms.h"
+#include "Units.h"
 #include "gfx2DGlue.h"
-#include "mozilla/LookAndFeel.h"
+#include "gfxUtils.h"
+#include "nsDisplayList.h"
 #include "nsDocShell.h"
+#include "nsIScrollableFrame.h"
 #include "nsImageFrame.h"
-#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
-
+#include "nsLayoutUtils.h"
+#include "nsPresContext.h"
+#include "nsPrintfCString.h"
+#include "nsRenderingContext.h"
+#include "nsSVGIntegrationUtils.h"
+
+#include "mozilla/Move.h"
+#include "mozilla/ReverseIterator.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/Tools.h"
+#include "mozilla/unused.h"
 #include "GeckoProfiler.h"
-#include "mozilla/gfx/Tools.h"
-#include "mozilla/gfx/2D.h"
+#include "LayersLogging.h"
 #include "gfxPrefs.h"
-#include "LayersLogging.h"
-#include "mozilla/unused.h"
-#include "mozilla/ReverseIterator.h"
-#include "mozilla/Move.h"
 
 #include <algorithm>
 
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 
@@ -2823,38 +2826,38 @@ void ContainerState::FinishPaintedLayerD
                  "Can't be a solid color as well as an image!");
     if (imageContainer) {
       nsRefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer(data->mLayer);
       imageLayer->SetContainer(imageContainer);
       data->mImage->ConfigureLayer(imageLayer, mParameters);
       imageLayer->SetPostScale(mParameters.mXScale,
                                mParameters.mYScale);
       if (data->mItemClip.HasClip()) {
-        nsIntRect clip = ScaleToNearestPixels(data->mItemClip.GetClipRect());
-        clip.MoveBy(mParameters.mOffset);
-        imageLayer->SetClipRect(&clip);
+        ParentLayerIntRect clip = ViewAs<ParentLayerPixel>(ScaleToNearestPixels(data->mItemClip.GetClipRect()));
+        clip.MoveBy(ViewAs<ParentLayerPixel>(mParameters.mOffset));
+        imageLayer->SetClipRect(Some(clip));
       } else {
-        imageLayer->SetClipRect(nullptr);
+        imageLayer->SetClipRect(Nothing());
       }
       layer = imageLayer;
       mLayerBuilder->StoreOptimizedLayerForFrame(data->mImage,
                                                  imageLayer);
       FLB_LOG_PAINTED_LAYER_DECISION(data, "  Selected image layer=%p\n", layer.get());
     } else {
       nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(data->mLayer);
       colorLayer->SetColor(data->mSolidColor);
 
       // Copy transform
       colorLayer->SetBaseTransform(data->mLayer->GetBaseTransform());
       colorLayer->SetPostScale(data->mLayer->GetPostXScale(), data->mLayer->GetPostYScale());
 
       nsIntRect visibleRect = data->mVisibleRegion.GetBounds();
       visibleRect.MoveBy(-GetTranslationForPaintedLayer(data->mLayer));
       colorLayer->SetBounds(visibleRect);
-      colorLayer->SetClipRect(nullptr);
+      colorLayer->SetClipRect(Nothing());
 
       layer = colorLayer;
       FLB_LOG_PAINTED_LAYER_DECISION(data, "  Selected color layer=%p\n", layer.get());
     }
 
     NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
                  "Layer already in list???");
     NS_ASSERTION(newLayerEntry->mLayer == data->mLayer,
@@ -2863,25 +2866,25 @@ void ContainerState::FinishPaintedLayerD
     newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex + 1];
     NS_ASSERTION(!newLayerEntry->mLayer, "Slot already occupied?");
     newLayerEntry->mLayer = layer;
     newLayerEntry->mAnimatedGeometryRoot = data->mAnimatedGeometryRoot;
     newLayerEntry->mFixedPosFrameForLayerData = data->mFixedPosFrameForLayerData;
 
     // Hide the PaintedLayer. We leave it in the layer tree so that we
     // can find and recycle it later.
-    nsIntRect emptyRect;
-    data->mLayer->SetClipRect(&emptyRect);
+    ParentLayerIntRect emptyRect;
+    data->mLayer->SetClipRect(Some(emptyRect));
     data->mLayer->SetVisibleRegion(nsIntRegion());
     data->mLayer->InvalidateRegion(data->mLayer->GetValidRegion().GetBounds());
     data->mLayer->SetEventRegions(EventRegions());
   } else {
     layer = data->mLayer;
     imageContainer = nullptr;
-    layer->SetClipRect(nullptr);
+    layer->SetClipRect(Nothing());
     FLB_LOG_PAINTED_LAYER_DECISION(data, "  Selected painted layer=%p\n", layer.get());
   }
 
   if (mLayerBuilder->IsBuildingRetainedLayers()) {
     newLayerEntry->mVisibleRegion = data->mVisibleRegion;
     newLayerEntry->mOpaqueRegion = data->mOpaqueRegion;
     newLayerEntry->mHideAllLayersBelow = data->mHideAllLayersBelow;
     newLayerEntry->mOpaqueForAnimatedGeometryRootParent = data->mOpaqueForAnimatedGeometryRootParent;
@@ -3503,25 +3506,25 @@ ContainerState::ProcessDisplayItems(nsDi
     if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
       nsDisplayLayerEventRegions* eventRegions =
         static_cast<nsDisplayLayerEventRegions*>(item);
       itemContent = eventRegions->GetHitRegionBounds(mBuilder, &snap);
     }
     nsIntRect itemDrawRect = ScaleToOutsidePixels(itemContent, snap);
     bool prerenderedTransform = itemType == nsDisplayItem::TYPE_TRANSFORM &&
         static_cast<nsDisplayTransform*>(item)->ShouldPrerender(mBuilder);
-    nsIntRect clipRect;
+    ParentLayerIntRect clipRect;
     const DisplayItemClip& itemClip = item->GetClip();
     if (itemClip.HasClip()) {
       itemContent.IntersectRect(itemContent, itemClip.GetClipRect());
-      clipRect = ScaleToNearestPixels(itemClip.GetClipRect());
+      clipRect = ViewAs<ParentLayerPixel>(ScaleToNearestPixels(itemClip.GetClipRect()));
       if (!prerenderedTransform) {
-        itemDrawRect.IntersectRect(itemDrawRect, clipRect);
+        itemDrawRect.IntersectRect(itemDrawRect, ParentLayerIntRect::ToUntyped(clipRect));
       }
-      clipRect.MoveBy(mParameters.mOffset);
+      clipRect.MoveBy(ViewAs<ParentLayerPixel>(mParameters.mOffset));
     }
 #ifdef DEBUG
     nsRect bounds = itemContent;
     bool dummy;
     if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
       bounds = item->GetBounds(mBuilder, &dummy);
       if (itemClip.HasClip()) {
         bounds.IntersectRect(bounds, itemClip.GetClipRect());
@@ -3609,28 +3612,34 @@ ContainerState::ProcessDisplayItems(nsDi
       // Ideally we'd only need the "else" case here and have
       // mPaintedLayerDataTree figure out the right clip from the animated
       // geometry root that we give it, but it can't easily figure about
       // overflow:hidden clips on ancestors just by looking at the frame.
       // So we'll do a little hand holding and pass the clip instead of the
       // visible rect for the two important cases.
       nscolor uniformColor = NS_RGBA(0,0,0,0);
       nscolor* uniformColorPtr = !mayDrawOutOfOrder ? &uniformColor : nullptr;
-      nsIntRect* clipPtr = itemClip.HasClip() ? &clipRect : nullptr;
+      nsIntRect clipRectUntyped;
+      nsIntRect* clipPtr = itemClip.HasClip() ? &clipRectUntyped : nullptr;
+      if (clipPtr) {
+	      clipRectUntyped = ParentLayerIntRect::ToUntyped(clipRect);
+      }
       if (animatedGeometryRoot == item->Frame() &&
           animatedGeometryRoot != mBuilder->RootReferenceFrame()) {
         // This is the case for scrollbar thumbs, for example. In that case the
         // clip we care about is the overflow:hidden clip on the scrollbar.
         const nsIFrame* clipAnimatedGeometryRoot =
           mPaintedLayerDataTree.GetParentAnimatedGeometryRoot(animatedGeometryRoot);
         mPaintedLayerDataTree.AddingOwnLayer(clipAnimatedGeometryRoot,
-                                             clipPtr, uniformColorPtr);
+					     clipPtr,
+					     uniformColorPtr);
       } else if (prerenderedTransform) {
         mPaintedLayerDataTree.AddingOwnLayer(animatedGeometryRoot,
-                                             clipPtr, uniformColorPtr);
+					     clipPtr,
+					     uniformColorPtr);
       } else {
         // Using itemVisibleRect here isn't perfect. itemVisibleRect can be
         // larger or smaller than the potential bounds of item's contents in
         // animatedGeometryRoot: It's too large if there's a clipped display
         // port somewhere among item's contents (see bug 1147673), and it can
         // be too small if the contents can move, because it only looks at the
         // contents' current bounds and doesn't anticipate any animations.
         // Time will tell whether this is good enough, or whether we need to do
@@ -3675,19 +3684,19 @@ ContainerState::ProcessDisplayItems(nsDi
       NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager");
       NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData),
                    "We shouldn't have a FrameLayerBuilder-managed layer here!");
       NS_ASSERTION(itemClip.HasClip() ||
                    itemClip.GetRoundedRectCount() == 0,
                    "If we have rounded rects, we must have a clip rect");
       // It has its own layer. Update that layer's clip and visible rects.
       if (itemClip.HasClip()) {
-        ownLayer->SetClipRect(&clipRect);
+        ownLayer->SetClipRect(Some(clipRect));
       } else {
-        ownLayer->SetClipRect(nullptr);
+        ownLayer->SetClipRect(Nothing());
       }
 
       // rounded rectangle clipping using mask layers
       // (must be done after visible rect is set on layer)
       if (itemClip.IsRectClippedByRoundedCorner(itemContent)) {
         SetupMaskLayer(ownLayer, itemClip, itemVisibleRect);
       }
 
@@ -4220,18 +4229,18 @@ ContainerState::SetupScrollingMetadata(N
   }
 
   nsAutoTArray<FrameMetrics,2> metricsArray;
   if (aEntry->mBaseFrameMetrics) {
     metricsArray.AppendElement(*aEntry->mBaseFrameMetrics);
   }
   uint32_t baseLength = metricsArray.Length();
 
-  nsIntRect tmpClipRect;
-  const nsIntRect* layerClip = aEntry->mLayer->GetClipRect();
+  ParentLayerIntRect tmpClipRect;
+  const ParentLayerIntRect* layerClip = aEntry->mLayer->GetClipRect().ptrOr(nullptr);
   nsIFrame* fParent;
   for (const nsIFrame* f = aEntry->mAnimatedGeometryRoot;
        f != mContainerAnimatedGeometryRoot;
        f = nsLayoutUtils::GetAnimatedGeometryRootForFrame(this->mBuilder,
            fParent, mContainerAnimatedGeometryRoot)) {
     fParent = nsLayoutUtils::GetCrossDocParentFrame(f);
     if (!fParent) {
       // This means mContainerAnimatedGeometryRoot was not an ancestor
@@ -4250,29 +4259,29 @@ ContainerState::SetupScrollingMetadata(N
     if (!scrollFrame) {
       continue;
     }
 
     nsRect clipRect(0, 0, -1, -1);
     scrollFrame->ComputeFrameMetrics(aEntry->mLayer, mContainerReferenceFrame,
                                      mParameters, &clipRect, &metricsArray);
     if (clipRect.width >= 0) {
-      nsIntRect pixClip = ScaleToNearestPixels(clipRect);
+      ParentLayerIntRect pixClip = ViewAs<ParentLayerPixel>(ScaleToNearestPixels(clipRect));
       if (layerClip) {
         tmpClipRect.IntersectRect(pixClip, *layerClip);
       } else {
         tmpClipRect = pixClip;
       }
       layerClip = &tmpClipRect;
       // XXX this could cause IPC churn due to cliprects being updated
       // twice during layer building --- for non-PaintedLayers that have
       // both CSS and scroll clipping.
     }
   }
-  aEntry->mLayer->SetClipRect(layerClip);
+  aEntry->mLayer->SetClipRect(ToMaybe(layerClip));
   // Watch out for FrameMetrics copies in profiles
   aEntry->mLayer->SetFrameMetrics(metricsArray);
 }
 
 void
 ContainerState::PostprocessRetainedLayers(nsIntRegion* aOpaqueRegionForContainer)
 {
   nsAutoTArray<OpaqueRegionEntry,4> opaqueRegions;
@@ -4293,19 +4302,19 @@ ContainerState::PostprocessRetainedLayer
     OpaqueRegionEntry* data = FindOpaqueRegionEntry(opaqueRegions,
         animatedGeometryRootForOpaqueness, e->mFixedPosFrameForLayerData);
 
     SetupScrollingMetadata(e);
 
     if (hideAll) {
       e->mVisibleRegion.SetEmpty();
     } else if (!e->mLayer->IsScrollbarContainer()) {
-      const nsIntRect* clipRect = e->mLayer->GetClipRect();
+      const Maybe<ParentLayerIntRect>& clipRect = e->mLayer->GetClipRect();
       if (clipRect && opaqueRegionForContainer >= 0 &&
-          opaqueRegions[opaqueRegionForContainer].mOpaqueRegion.Contains(*clipRect)) {
+          opaqueRegions[opaqueRegionForContainer].mOpaqueRegion.Contains(ParentLayerIntRect::ToUntyped(*clipRect))) {
         e->mVisibleRegion.SetEmpty();
       } else if (data) {
         e->mVisibleRegion.Sub(e->mVisibleRegion, data->mOpaqueRegion);
       }
     }
 
     SetOuterVisibleRegionForLayer(e->mLayer, e->mVisibleRegion,
       e->mLayerContentsVisibleRect.width >= 0 ? &e->mLayerContentsVisibleRect : nullptr);
@@ -4328,19 +4337,19 @@ ContainerState::PostprocessRetainedLayer
           opaqueRegionForContainer = opaqueRegions.Length();
         }
         data = opaqueRegions.AppendElement();
         data->mAnimatedGeometryRoot = animatedGeometryRootToCover;
         data->mFixedPosFrameForLayerData = e->mFixedPosFrameForLayerData;
       }
 
       nsIntRegion clippedOpaque = e->mOpaqueRegion;
-      const nsIntRect* clipRect = e->mLayer->GetClipRect();
+      const Maybe<ParentLayerIntRect>& clipRect = e->mLayer->GetClipRect();
       if (clipRect) {
-        clippedOpaque.AndWith(*clipRect);
+        clippedOpaque.AndWith(ParentLayerIntRect::ToUntyped(*clipRect));
       }
       data->mOpaqueRegion.Or(data->mOpaqueRegion, clippedOpaque);
       if (e->mHideAllLayersBelow) {
         hideAll = true;
       }
     }
 
     if (e->mLayer->GetType() == Layer::TYPE_READBACK) {
--- a/layout/base/UnitTransforms.h
+++ b/layout/base/UnitTransforms.h
@@ -17,16 +17,18 @@ namespace mozilla {
 // can be thought of as a cast).
 // To use these functions, you must provide a justification for each use!
 // Feel free to add more justifications to PixelCastJustification, along with
 // a comment that explains under what circumstances it is appropriate to use.
 
 enum class PixelCastJustification : uint8_t {
   // For the root layer, Screen Pixel = Parent Layer Pixel.
   ScreenIsParentLayerForRoot,
+  // For the root layer, Render Target Pixel = Parent Layer Pixel.
+  RenderTargetIsParentLayerForRoot,
   // For the root composition size we want to view it as layer pixels in any layer
   ParentLayerToLayerForRootComposition,
   // The Layer coordinate space for one layer is the ParentLayer coordinate
   // space for its children
   MovingDownToChildren,
   // The transform that is usually used to convert between two coordinate
   // systems is not available (for example, because the object that stores it
   // is being destroyed), so fall back to the identity.
@@ -49,16 +51,24 @@ gfx::IntSizeTyped<TargetUnits> ViewAs(co
 template <class TargetUnits, class SourceUnits>
 gfx::PointTyped<TargetUnits> ViewAs(const gfx::PointTyped<SourceUnits>& aPoint, PixelCastJustification) {
   return gfx::PointTyped<TargetUnits>(aPoint.x, aPoint.y);
 }
 template <class TargetUnits, class SourceUnits>
 gfx::IntPointTyped<TargetUnits> ViewAs(const gfx::IntPointTyped<SourceUnits>& aPoint, PixelCastJustification) {
   return gfx::IntPointTyped<TargetUnits>(aPoint.x, aPoint.y);
 }
+template <class TargetUnits, class SourceUnits>
+gfx::RectTyped<TargetUnits> ViewAs(const gfx::RectTyped<SourceUnits>& aRect, PixelCastJustification) {
+  return gfx::RectTyped<TargetUnits>(aRect.x, aRect.y, aRect.width, aRect.height);
+}
+template <class TargetUnits, class SourceUnits>
+gfx::IntRectTyped<TargetUnits> ViewAs(const gfx::IntRectTyped<SourceUnits>& aRect, PixelCastJustification) {
+  return gfx::IntRectTyped<TargetUnits>(aRect.x, aRect.y, aRect.width, aRect.height);
+}
 template <class NewTargetUnits, class OldTargetUnits, class SourceUnits>
 gfx::ScaleFactor<SourceUnits, NewTargetUnits> ViewTargetAs(
     const gfx::ScaleFactor<SourceUnits, OldTargetUnits>& aScaleFactor,
     PixelCastJustification) {
   return gfx::ScaleFactor<SourceUnits, NewTargetUnits>(aScaleFactor.scale);
 }
 
 // Convenience functions for casting untyped entities to typed entities.