Bug 1010584 - Part 1: Introduce RenderTargetPixel. r=mwoodrow
authorBenoit Girard <b56girard@gmail.com>
Wed, 30 Jul 2014 14:36:15 -0400
changeset 200700 4c1df9a780820453b8ba023512e4509fdf1ce289
parent 200699 4f9e0c8de078c89b591191aa8f134652c46c976f
child 200701 bf6096626941f8ca131c1aa9ef9edde83941708c
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmwoodrow
bugs1010584
milestone34.0a1
Bug 1010584 - Part 1: Introduce RenderTargetPixel. r=mwoodrow
gfx/layers/Compositor.cpp
gfx/layers/Compositor.h
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/composite/ContainerLayerComposite.cpp
gfx/layers/composite/ContainerLayerComposite.h
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/composite/LayerManagerComposite.h
gfx/layers/composite/ThebesLayerComposite.cpp
gfx/layers/composite/TiledContentHost.cpp
gfx/layers/d3d10/ContainerLayerD3D10.cpp
gfx/layers/d3d9/ContainerLayerD3D9.cpp
layout/base/Units.h
--- a/gfx/layers/Compositor.cpp
+++ b/gfx/layers/Compositor.cpp
@@ -99,40 +99,42 @@ Compositor::DrawDiagnostics(DiagnosticFl
   if (!ShouldDrawDiagnostics(aFlags)) {
     return;
   }
 
   DrawDiagnosticsInternal(aFlags, aVisibleRect, aClipRect, aTransform,
                           aFlashCounter);
 }
 
-gfx::Rect
-Compositor::ClipRectInLayersCoordinates(gfx::Rect aClip) const {
-  gfx::Rect result;
-  aClip = aClip + GetCurrentRenderTarget()->GetOrigin();
-  gfx::IntSize destSize = GetWidgetSize();
+RenderTargetRect
+Compositor::ClipRectInLayersCoordinates(RenderTargetIntRect aClip) const {
+  RenderTargetRect result;
+  aClip = aClip + RenderTargetIntPoint(GetCurrentRenderTarget()->GetOrigin().x,
+                                       GetCurrentRenderTarget()->GetOrigin().y);
+  RenderTargetIntSize destSize = RenderTargetIntSize(GetWidgetSize().width,
+                                                     GetWidgetSize().height);
 
   switch (mScreenRotation) {
     case ROTATION_0:
-      result = aClip;
+      result = RenderTargetRect(aClip.x, aClip.y, aClip.width, aClip.height);
       break;
     case ROTATION_90:
-      result = gfx::Rect(aClip.y,
-                         destSize.width - aClip.x - aClip.width,
-                         aClip.height, aClip.width);
+      result = RenderTargetRect(aClip.y,
+                                destSize.width - aClip.x - aClip.width,
+                                aClip.height, aClip.width);
       break;
     case ROTATION_270:
-      result = gfx::Rect(destSize.height - aClip.y - aClip.height,
-                         aClip.x,
-                         aClip.height, aClip.width);
+      result = RenderTargetRect(destSize.height - aClip.y - aClip.height,
+                                aClip.x,
+                                aClip.height, aClip.width);
       break;
     case ROTATION_180:
-      result = gfx::Rect(destSize.width - aClip.x - aClip.width,
-                         destSize.height - aClip.y - aClip.height,
-                         aClip.width, aClip.height);
+      result = RenderTargetRect(destSize.width - aClip.x - aClip.width,
+                                destSize.height - aClip.y - aClip.height,
+                                aClip.width, aClip.height);
       break;
       // ScreenRotation has a sentinel value, need to catch it in the switch
       // statement otherwise the build fails (-WError)
     default: {}
   }
   return result;
 }
 
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -493,17 +493,17 @@ public:
 
   // On b2g the clip rect is in the coordinate space of the physical screen
   // independently of its rotation, while the coordinate space of the layers,
   // on the other hand, depends on the screen orientation.
   // This only applies to b2g as with other platforms, orientation is handled
   // at the OS level rather than in Gecko.
   // In addition, the clip rect needs to be offset by the rendering origin.
   // This becomes important if intermediate surfaces are used.
-  gfx::Rect ClipRectInLayersCoordinates(gfx::Rect aClip) const;
+  RenderTargetRect ClipRectInLayersCoordinates(RenderTargetIntRect aClip) const;
 
 protected:
   void DrawDiagnosticsInternal(DiagnosticFlags aFlags,
                                const gfx::Rect& aVisibleRect,
                                const gfx::Rect& aClipRect,
                                const gfx::Matrix4x4& transform,
                                uint32_t aFlashCounter);
 
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -596,69 +596,76 @@ bool
 Layer::MayResample()
 {
   Matrix transform2d;
   return !GetEffectiveTransform().Is2D(&transform2d) ||
          ThebesMatrix(transform2d).HasNonIntegerTranslation() ||
          AncestorLayerMayChangeTransform(this);
 }
 
-nsIntRect
-Layer::CalculateScissorRect(const nsIntRect& aCurrentScissorRect,
+RenderTargetIntRect
+Layer::CalculateScissorRect(const RenderTargetIntRect& aCurrentScissorRect,
                             const gfx::Matrix* aWorldTransform)
 {
   ContainerLayer* container = GetParent();
   NS_ASSERTION(container, "This can't be called on the root!");
 
   // Establish initial clip rect: it's either the one passed in, or
   // if the parent has an intermediate surface, it's the extents of that surface.
-  nsIntRect currentClip;
+  RenderTargetIntRect currentClip;
   if (container->UseIntermediateSurface()) {
     currentClip.SizeTo(container->GetIntermediateSurfaceRect().Size());
   } else {
     currentClip = aCurrentScissorRect;
   }
 
-  const nsIntRect *clipRect = GetEffectiveClipRect();
-  if (!clipRect)
+  if (!GetEffectiveClipRect()) {
     return currentClip;
+  }
 
-  if (clipRect->IsEmpty()) {
+  const RenderTargetIntRect clipRect = RenderTargetPixel::FromUntyped(*GetEffectiveClipRect());
+  if (clipRect.IsEmpty()) {
     // We might have a non-translation transform in the container so we can't
     // use the code path below.
-    return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
+    return RenderTargetIntRect(currentClip.TopLeft(), RenderTargetIntSize(0, 0));
   }
 
-  nsIntRect scissor = *clipRect;
+  RenderTargetIntRect scissor = clipRect;
   if (!container->UseIntermediateSurface()) {
     gfx::Matrix matrix;
     DebugOnly<bool> is2D = container->GetEffectiveTransform().Is2D(&matrix);
     // See DefaultComputeEffectiveTransforms below
     NS_ASSERTION(is2D && matrix.PreservesAxisAlignedRectangles(),
                  "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();
-    if (!gfxUtils::GfxRectToIntRect(trScissor, &scissor)) {
-      return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
+    nsIntRect tmp;
+    if (!gfxUtils::GfxRectToIntRect(trScissor, &tmp)) {
+      return RenderTargetIntRect(currentClip.TopLeft(), RenderTargetIntSize(0, 0));
     }
+    scissor = RenderTargetPixel::FromUntyped(tmp);
 
     // Find the nearest ancestor with an intermediate surface
     do {
       container = container->GetParent();
     } while (container && !container->UseIntermediateSurface());
   }
+
   if (container) {
     scissor.MoveBy(-container->GetIntermediateSurfaceRect().TopLeft());
   } else if (aWorldTransform) {
     gfx::Rect r(scissor.x, scissor.y, scissor.width, scissor.height);
     gfx::Rect trScissor = aWorldTransform->TransformBounds(r);
     trScissor.Round();
-    if (!gfxUtils::GfxRectToIntRect(ThebesRect(trScissor), &scissor))
-      return nsIntRect(currentClip.TopLeft(), nsIntSize(0, 0));
+    nsIntRect tmp;
+    if (!gfxUtils::GfxRectToIntRect(ThebesRect(trScissor), &tmp)) {
+      return RenderTargetIntRect(currentClip.TopLeft(), RenderTargetIntSize(0, 0));
+    }
+    scissor = RenderTargetPixel::FromUntyped(tmp);
   }
   return currentClip.Intersect(scissor);
 }
 
 const Matrix4x4
 Layer::GetTransform() const
 {
   Matrix4x4 transform = mTransform;
@@ -751,16 +758,26 @@ Layer::ComputeEffectiveTransformForMaskL
 #ifdef DEBUG
     bool maskIs2D = mMaskLayer->GetTransform().CanDraw2D();
     NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
 #endif
     mMaskLayer->mEffectiveTransform = mMaskLayer->GetTransform() * mMaskLayer->mEffectiveTransform;
   }
 }
 
+RenderTargetRect
+Layer::TransformRectToRenderTarget(const LayerIntRect& aRect)
+{
+  LayerRect rect(aRect);
+  RenderTargetRect quad = RenderTargetRect::FromUnknown(
+    GetEffectiveTransform().TransformBounds(
+      LayerPixel::ToUnknown(rect)));
+  return quad;
+}
+
 ContainerLayer::ContainerLayer(LayerManager* aManager, void* aImplData)
   : Layer(aManager, aImplData),
     mFirstChild(nullptr),
     mLastChild(nullptr),
     mPreXScale(1.0f),
     mPreYScale(1.0f),
     mInheritedXScale(1.0f),
     mInheritedYScale(1.0f),
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1383,18 +1383,18 @@ public:
    * Returns a rectangle relative to the intermediate surface belonging to the
    * nearest ancestor that has an intermediate surface, or relative to the root
    * viewport if no ancestor has an intermediate surface, corresponding to the
    * clip rect for this layer intersected with aCurrentScissorRect.
    * If no ancestor has an intermediate surface, the clip rect is transformed
    * by aWorldTransform before being combined with aCurrentScissorRect, if
    * aWorldTransform is non-null.
    */
-  nsIntRect CalculateScissorRect(const nsIntRect& aCurrentScissorRect,
-                                 const gfx::Matrix* aWorldTransform);
+  RenderTargetIntRect CalculateScissorRect(const RenderTargetIntRect& aCurrentScissorRect,
+                                           const gfx::Matrix* aWorldTransform);
 
   virtual const char* Name() const =0;
   virtual LayerType GetType() const =0;
 
   /**
    * Only the implementation should call this. This is per-implementation
    * private data. Normally, all layers with a given layer manager
    * use the same type of ImplData.
@@ -1481,32 +1481,33 @@ public:
 
 #ifdef DEBUG
   void SetDebugColorIndex(uint32_t aIndex) { mDebugColorIndex = aIndex; }
   uint32_t GetDebugColorIndex() { return mDebugColorIndex; }
 #endif
 
   virtual LayerRenderState GetRenderState() { return LayerRenderState(); }
 
-
   void Mutated()
   {
     mManager->Mutated(this);
   }
 
   virtual int32_t GetMaxLayerSize() { return Manager()->GetMaxTextureSize(); }
 
   /**
    * Returns true if this layer's effective transform is not just
    * a translation by integers, or if this layer or some ancestor layer
    * is marked as having a transform that may change without a full layer
    * transaction.
    */
   bool MayResample();
 
+  RenderTargetRect TransformRectToRenderTarget(const LayerIntRect& aRect);
+
 protected:
   Layer(LayerManager* aManager, void* aImplData);
 
   // Protected destructor, to discourage deletion outside of Release():
   virtual ~Layer();
 
   /**
    * We can snap layer transforms for two reasons:
@@ -1808,22 +1809,25 @@ public:
    * on this layer.
    * Returns true if this will use an intermediate surface. This is largely
    * backend-dependent, but it affects the operation of GetEffectiveOpacity().
    */
   bool UseIntermediateSurface() { return mUseIntermediateSurface; }
 
   /**
    * Returns the rectangle covered by the intermediate surface,
-   * in this layer's coordinate system
+   * in this layer's coordinate system.
+   *
+   * NOTE: Since this layer has an intermediate surface it follows
+   *       that LayerPixel == RenderTargetPixel
    */
-  nsIntRect GetIntermediateSurfaceRect()
+  RenderTargetIntRect GetIntermediateSurfaceRect()
   {
     NS_ASSERTION(mUseIntermediateSurface, "Must have intermediate surface");
-    return mVisibleRegion.GetBounds();
+    return RenderTargetPixel::FromUntyped(mVisibleRegion.GetBounds());
   }
 
   /**
    * Returns true if this container has more than one non-empty child
    */
   bool HasMultipleChildren();
 
   /**
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -112,17 +112,17 @@ static gfx::Point GetScrollData(Layer* a
   if (aLayer->GetLocalTransform().Is2D(&matrix)) {
     return matrix.GetTranslation();
   }
 
   gfx::Point origin;
   return origin;
 }
 
-static void DrawLayerInfo(const nsIntRect& aClipRect,
+static void DrawLayerInfo(const RenderTargetIntRect& aClipRect,
                           LayerManagerComposite* aManager,
                           Layer* aLayer)
 {
 
   if (aLayer->GetType() == Layer::LayerType::TYPE_CONTAINER) {
     // XXX - should figure out a way to render this, but for now this
     // is hard to do, since it will often get superimposed over the first
     // child of the layer, which is bad.
@@ -149,17 +149,17 @@ static LayerVelocityUserData* GetVelocit
   if (!aLayer->HasUserData(key)) {
     LayerVelocityUserData* newData = new LayerVelocityUserData();
     aLayer->SetUserData(key, newData);
   }
 
   return static_cast<LayerVelocityUserData*>(aLayer->GetUserData(key));
 }
 
-static void DrawVelGraph(const nsIntRect& aClipRect,
+static void DrawVelGraph(const RenderTargetIntRect& aClipRect,
                          LayerManagerComposite* aManager,
                          Layer* aLayer) {
   Compositor* compositor = aManager->GetCompositor();
   gfx::Rect clipRect(aClipRect.x, aClipRect.y,
                      aClipRect.width, aClipRect.height);
 
   TimeStamp now = TimeStamp::Now();
   LayerVelocityUserData* velocityData = GetVelocityData(aLayer);
@@ -276,36 +276,36 @@ static void PrintUniformityInfo(Layer* a
 
   printf_stderr("UniformityInfo Layer_Move %llu %p %f, %f\n",
     TimeStamp::Now(), aLayer, layerScroll.x, layerScroll.y);
 }
 
 /* all of the per-layer prepared data we need to maintain */
 struct PreparedLayer
 {
-  PreparedLayer(LayerComposite *aLayer, nsIntRect aClipRect, bool aRestoreVisibleRegion, nsIntRegion &aVisibleRegion) :
+  PreparedLayer(LayerComposite *aLayer, RenderTargetIntRect aClipRect, bool aRestoreVisibleRegion, nsIntRegion &aVisibleRegion) :
     mLayer(aLayer), mClipRect(aClipRect), mRestoreVisibleRegion(aRestoreVisibleRegion), mSavedVisibleRegion(aVisibleRegion) {}
   LayerComposite* mLayer;
-  nsIntRect mClipRect;
+  RenderTargetIntRect mClipRect;
   bool mRestoreVisibleRegion;
   nsIntRegion mSavedVisibleRegion;
 };
 
 /* all of the prepared data that we need in RenderLayer() */
 struct PreparedData
 {
   RefPtr<CompositingRenderTarget> mTmpTarget;
   nsAutoTArray<PreparedLayer, 12> mLayers;
 };
 
 // ContainerPrepare is shared between RefLayer and ContainerLayer
 template<class ContainerT> void
 ContainerPrepare(ContainerT* aContainer,
                  LayerManagerComposite* aManager,
-                 const nsIntRect& aClipRect)
+                 const RenderTargetIntRect& aClipRect)
 {
   aContainer->mPrepared = MakeUnique<PreparedData>();
 
   /**
    * Determine which layers to draw.
    */
   nsAutoTArray<Layer*, 12> children;
   aContainer->SortChildrenBy3DZOrder(children);
@@ -313,17 +313,17 @@ ContainerPrepare(ContainerT* aContainer,
   for (uint32_t i = 0; i < children.Length(); i++) {
     LayerComposite* layerToRender = static_cast<LayerComposite*>(children.ElementAt(i)->ImplData());
 
     if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty() &&
         !layerToRender->GetLayer()->AsContainerLayer()) {
       continue;
     }
 
-    nsIntRect clipRect = layerToRender->GetLayer()->
+    RenderTargetIntRect clipRect = layerToRender->GetLayer()->
         CalculateScissorRect(aClipRect, &aManager->GetWorldTransform());
     if (clipRect.IsEmpty()) {
       continue;
     }
 
     CULLING_LOG("Preparing sublayer %p\n", layerToRender->GetLayer());
 
     nsIntRegion savedVisibleRegion;
@@ -370,26 +370,26 @@ ContainerPrepare(ContainerT* aContainer,
   // DefaultComputeSupportsComponentAlphaChildren can mutate aContainer so call it unconditionally
   aContainer->DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded);
   if (aContainer->UseIntermediateSurface()) {
     MOZ_PERFORMANCE_WARNING("gfx", "[%p] Container layer requires intermediate surface\n", aContainer);
     if (!surfaceCopyNeeded) {
       // If we don't need a copy we can render to the intermediate now to avoid
       // unecessary render target switching. This brings a big perf boost on mobile gpus.
       RefPtr<CompositingRenderTarget> surface = CreateTemporaryTarget(aContainer, aManager);
-      RenderIntermediate(aContainer, aManager, aClipRect, surface);
+      RenderIntermediate(aContainer, aManager, RenderTargetPixel::ToUntyped(aClipRect), surface);
       aContainer->mPrepared->mTmpTarget = surface;
     }
   }
 }
 
 template<class ContainerT> void
 RenderLayers(ContainerT* aContainer,
 	     LayerManagerComposite* aManager,
-	     const nsIntRect& aClipRect)
+	     const RenderTargetIntRect& aClipRect)
 {
   Compositor* compositor = aManager->GetCompositor();
 
   float opacity = aContainer->GetEffectiveOpacity();
 
   // If this is a scrollable container layer, and it's overscrolled, the layer's
   // contents are transformed in a way that would leave blank regions in the
   // composited area. If the layer has a background color, fill these areas
@@ -402,40 +402,42 @@ RenderLayers(ContainerT* aContainer,
       gfxRGBA color = aContainer->GetBackgroundColor();
       // If the background is completely transparent, there's no point in
       // drawing anything for it. Hopefully the layers behind, if any, will
       // provide suitable content for the overscroll effect.
       if (color.a != 0.0) {
         EffectChain effectChain(aContainer);
         effectChain.mPrimaryEffect = new EffectSolidColor(ToColor(color));
         gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
-        Compositor* compositor = aManager->GetCompositor();
-        compositor->DrawQuad(compositor->ClipRectInLayersCoordinates(clipRect),
-            clipRect, effectChain, opacity, Matrix4x4());
+        compositor->DrawQuad(
+          RenderTargetPixel::ToUnknown(
+            compositor->ClipRectInLayersCoordinates(aClipRect)),
+          clipRect, effectChain, opacity, Matrix4x4());
       }
     }
   }
 
   for (size_t i = 0u; i < aContainer->mPrepared->mLayers.Length(); i++) {
     PreparedLayer& preparedData = aContainer->mPrepared->mLayers[i];
     LayerComposite* layerToRender = preparedData.mLayer;
-    nsIntRect clipRect = preparedData.mClipRect;
+    const RenderTargetIntRect& clipRect = preparedData.mClipRect;
+
     if (layerToRender->HasLayerBeenComposited()) {
       // Composer2D will compose this layer so skip GPU composition
       // this time & reset composition flag for next composition phase
       layerToRender->SetLayerComposited(false);
       nsIntRect clearRect = layerToRender->GetClearRect();
       if (!clearRect.IsEmpty()) {
         // Clear layer's visible rect on FrameBuffer with transparent pixels
         gfx::Rect fbRect(clearRect.x, clearRect.y, clearRect.width, clearRect.height);
         compositor->ClearRect(fbRect);
         layerToRender->SetClearRect(nsIntRect(0, 0, 0, 0));
       }
     } else {
-      layerToRender->RenderLayer(clipRect);
+      layerToRender->RenderLayer(RenderTargetPixel::ToUntyped(clipRect));
     }
 
     if (preparedData.mRestoreVisibleRegion) {
       // Restore the region in case it's not covered by opaque content next time
       layerToRender->SetShadowVisibleRegion(preparedData.mSavedVisibleRegion);
     }
 
     if (gfxPrefs::LayersScrollGraph()) {
@@ -503,34 +505,35 @@ RenderIntermediate(ContainerT* aContaine
   RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();
 
   if (!surface) {
     return;
   }
 
   compositor->SetRenderTarget(surface);
   // pre-render all of the layers into our temporary
-  RenderLayers(aContainer, aManager, aClipRect);
+  RenderLayers(aContainer, aManager, RenderTargetPixel::FromUntyped(aClipRect));
   // Unbind the current surface and rebind the previous one.
   compositor->SetRenderTarget(previousTarget);
 }
 
 template<class ContainerT> void
 ContainerRender(ContainerT* aContainer,
                  LayerManagerComposite* aManager,
                  const nsIntRect& aClipRect)
 {
   MOZ_ASSERT(aContainer->mPrepared);
   if (aContainer->UseIntermediateSurface()) {
     RefPtr<CompositingRenderTarget> surface;
 
     if (!aContainer->mPrepared->mTmpTarget) {
       // we needed to copy the background so we waited until now to render the intermediate
       surface = CreateTemporaryTargetAndCopyFromBackground(aContainer, aManager);
-      RenderIntermediate(aContainer, aManager, aClipRect, surface);
+      RenderIntermediate(aContainer, aManager,
+                         aClipRect, surface);
     } else {
       surface = aContainer->mPrepared->mTmpTarget;
     }
 
     float opacity = aContainer->GetEffectiveOpacity();
 
     nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();
 #ifdef MOZ_DUMP_PAINTING
@@ -554,17 +557,17 @@ ContainerRender(ContainerT* aContainer,
     aContainer->AddBlendModeEffect(effectChain);
     effectChain.mPrimaryEffect = new EffectRenderTarget(surface);
 
     gfx::Rect rect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height);
     gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
     aManager->GetCompositor()->DrawQuad(rect, clipRect, effectChain, opacity,
                                         aContainer->GetEffectiveTransform());
   } else {
-    RenderLayers(aContainer, aManager, aClipRect);
+    RenderLayers(aContainer, aManager, RenderTargetPixel::FromUntyped(aClipRect));
   }
   aContainer->mPrepared = nullptr;
 
   if (aContainer->GetFrameMetrics().IsScrollable()) {
     const FrameMetrics& frame = aContainer->GetFrameMetrics();
     LayerRect layerBounds = frame.mCompositionBounds * ParentLayerToLayerScale(1.0);
     gfx::Rect rect(layerBounds.x, layerBounds.y, layerBounds.width, layerBounds.height);
     gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
@@ -623,17 +626,17 @@ ContainerLayerComposite::GetFirstChildCo
 
 void
 ContainerLayerComposite::RenderLayer(const nsIntRect& aClipRect)
 {
   ContainerRender(this, mCompositeManager, aClipRect);
 }
 
 void
-ContainerLayerComposite::Prepare(const nsIntRect& aClipRect)
+ContainerLayerComposite::Prepare(const RenderTargetIntRect& aClipRect)
 {
   ContainerPrepare(this, mCompositeManager, aClipRect);
 }
 
 void
 ContainerLayerComposite::CleanupResources()
 {
   for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
@@ -672,17 +675,17 @@ RefLayerComposite::GetFirstChildComposit
 
 void
 RefLayerComposite::RenderLayer(const nsIntRect& aClipRect)
 {
   ContainerRender(this, mCompositeManager, aClipRect);
 }
 
 void
-RefLayerComposite::Prepare(const nsIntRect& aClipRect)
+RefLayerComposite::Prepare(const RenderTargetIntRect& aClipRect)
 {
   ContainerPrepare(this, mCompositeManager, aClipRect);
 }
 
 
 void
 RefLayerComposite::CleanupResources()
 {
--- a/gfx/layers/composite/ContainerLayerComposite.h
+++ b/gfx/layers/composite/ContainerLayerComposite.h
@@ -22,57 +22,57 @@ class CompositingRenderTarget;
 struct PreparedData;
 
 class ContainerLayerComposite : public ContainerLayer,
                                 public LayerComposite
 {
   template<class ContainerT>
   friend void ContainerPrepare(ContainerT* aContainer,
                                LayerManagerComposite* aManager,
-                               const nsIntRect& aClipRect);
+                               const RenderTargetIntRect& aClipRect);
   template<class ContainerT>
   friend void ContainerRender(ContainerT* aContainer,
                               LayerManagerComposite* aManager,
-                              const nsIntRect& aClipRect);
+                              const RenderTargetIntRect& aClipRect);
   template<class ContainerT>
   friend void RenderLayers(ContainerT* aContainer,
                            LayerManagerComposite* aManager,
-                           const nsIntRect& aClipRect);
+                           const RenderTargetIntRect& aClipRect);
   template<class ContainerT>
   friend void RenderIntermediate(ContainerT* aContainer,
                    LayerManagerComposite* aManager,
                    const nsIntRect& aClipRect,
                    RefPtr<CompositingRenderTarget> surface);
   template<class ContainerT>
   friend RefPtr<CompositingRenderTarget>
   CreateTemporaryTargetAndCopyFromBackground(ContainerT* aContainer,
                                              LayerManagerComposite* aManager,
-                                             const nsIntRect& aClipRect);
+                                             const RenderTargetIntRect& aClipRect);
   template<class ContainerT>
   friend RefPtr<CompositingRenderTarget>
   CreateTemporaryTarget(ContainerT* aContainer,
                         LayerManagerComposite* aManager,
-                        const nsIntRect& aClipRect);
+                        const RenderTargetIntRect& aClipRect);
 
 public:
   explicit ContainerLayerComposite(LayerManagerComposite *aManager);
 
 protected:
   ~ContainerLayerComposite();
 
 public:
   // LayerComposite Implementation
   virtual Layer* GetLayer() MOZ_OVERRIDE { return this; }
 
   virtual void Destroy() MOZ_OVERRIDE;
 
   LayerComposite* GetFirstChildComposite();
 
   virtual void RenderLayer(const nsIntRect& aClipRect) MOZ_OVERRIDE;
-  virtual void Prepare(const nsIntRect& aClipRect) MOZ_OVERRIDE;
+  virtual void Prepare(const RenderTargetIntRect& aClipRect) MOZ_OVERRIDE;
 
   virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) MOZ_OVERRIDE
   {
     DefaultComputeEffectiveTransforms(aTransformToSurface);
   }
 
   virtual void CleanupResources() MOZ_OVERRIDE;
 
@@ -86,17 +86,17 @@ public:
 };
 
 class RefLayerComposite : public RefLayer,
                           public LayerComposite
 {
   template<class ContainerT>
   friend void ContainerPrepare(ContainerT* aContainer,
                                LayerManagerComposite* aManager,
-                               const nsIntRect& aClipRect);
+                               const RenderTargetIntRect& aClipRect);
   template<class ContainerT>
   friend void ContainerRender(ContainerT* aContainer,
                               LayerManagerComposite* aManager,
                               const nsIntRect& aClipRect);
   template<class ContainerT>
   friend void RenderLayers(ContainerT* aContainer,
                            LayerManagerComposite* aManager,
                            const nsIntRect& aClipRect);
@@ -126,17 +126,17 @@ public:
   /** LayerOGL implementation */
   Layer* GetLayer() MOZ_OVERRIDE { return this; }
 
   void Destroy() MOZ_OVERRIDE;
 
   LayerComposite* GetFirstChildComposite();
 
   virtual void RenderLayer(const nsIntRect& aClipRect) MOZ_OVERRIDE;
-  virtual void Prepare(const nsIntRect& aClipRect) MOZ_OVERRIDE;
+  virtual void Prepare(const RenderTargetIntRect& aClipRect) MOZ_OVERRIDE;
 
   virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) MOZ_OVERRIDE
   {
     DefaultComputeEffectiveTransforms(aTransformToSurface);
   }
 
   virtual void CleanupResources() MOZ_OVERRIDE;
 
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -560,17 +560,17 @@ LayerManagerComposite::Render()
   RefPtr<CompositingRenderTarget> previousTarget;
   if (gfxPrefs::Invert() || gfxPrefs::Grayscale()) {
     previousTarget = PushGroup();
   } else {
     mTwoPassTmpTarget = nullptr;
   }
 
   // Render our layers.
-  RootLayer()->Prepare(clipRect);
+  RootLayer()->Prepare(RenderTargetPixel::FromUntyped(clipRect));
   RootLayer()->RenderLayer(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));
     }
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -331,18 +331,19 @@ public:
 
   virtual Layer* GetLayer() = 0;
 
   /**
    * Perform a first pass over the layer tree to prepare intermediate surfaces.
    * This allows us on to avoid framebuffer switches in the middle of our render
    * which is inefficient. This must be called before RenderLayer.
    */
-  virtual void Prepare(const nsIntRect& aClipRect) {}
+  virtual void Prepare(const RenderTargetIntRect& aClipRect) {}
 
+  // TODO: This should also take RenderTargetIntRect like Prepare.
   virtual void RenderLayer(const nsIntRect& aClipRect) = 0;
 
   virtual bool SetCompositableHost(CompositableHost*)
   {
     // We must handle this gracefully, see bug 967824
     NS_WARNING("called SetCompositableHost for a layer type not accepting a compositable");
     return false;
   }
--- a/gfx/layers/composite/ThebesLayerComposite.cpp
+++ b/gfx/layers/composite/ThebesLayerComposite.cpp
@@ -112,33 +112,32 @@ ThebesLayerComposite::RenderLayer(const 
   }
   PROFILER_LABEL("ThebesLayerComposite", "RenderLayer",
     js::ProfileEntry::Category::GRAPHICS);
 
   MOZ_ASSERT(mBuffer->GetCompositor() == mCompositeManager->GetCompositor() &&
              mBuffer->GetLayer() == this,
              "buffer is corrupted");
 
+  const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();
   gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
 
 #ifdef MOZ_DUMP_PAINTING
   if (gfxUtils::sDumpPainting) {
     RefPtr<gfx::DataSourceSurface> surf = mBuffer->GetAsSurface();
     if (surf) {
       WriteSnapshotToDumpFile(this, surf);
     }
   }
 #endif
 
   EffectChain effectChain(this);
   LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
   AddBlendModeEffect(effectChain);
 
-  const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();
-
   mBuffer->SetPaintWillResample(MayResample());
 
   mBuffer->Composite(effectChain,
                      GetEffectiveOpacity(),
                      GetEffectiveTransform(),
                      GetEffectFilter(),
                      clipRect,
                      &visibleRegion);
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -419,20 +419,21 @@ TiledContentHost::RenderTile(const TileH
 {
   if (aTile.IsPlaceholderTile()) {
     // This shouldn't ever happen, but let's fail semi-gracefully. No need
     // to warn, the texture update would have already caught this.
     return;
   }
 
   nsIntRect screenBounds = aScreenRegion.GetBounds();
-  Rect quad(screenBounds.x, screenBounds.y, screenBounds.width, screenBounds.height);
-  quad = aTransform.TransformBounds(quad);
+  Rect layerQuad(screenBounds.x, screenBounds.y, screenBounds.width, screenBounds.height);
+  RenderTargetRect quad = RenderTargetRect::FromUnknown(aTransform.TransformBounds(layerQuad));
 
-  if (!quad.Intersects(mCompositor->ClipRectInLayersCoordinates(aClipRect))) {
+  if (!quad.Intersects(mCompositor->ClipRectInLayersCoordinates(
+        RenderTargetIntRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height)))) {
     return;
   }
 
   if (aBackgroundColor) {
     aEffectChain.mPrimaryEffect = new EffectSolidColor(ToColor(*aBackgroundColor));
     nsIntRegionRectIterator it(aScreenRegion);
     for (const nsIntRect* rect = it.Next(); rect != nullptr; rect = it.Next()) {
       Rect graphicsRect(rect->x, rect->y, rect->width, rect->height);
--- a/gfx/layers/d3d10/ContainerLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ContainerLayerD3D10.cpp
@@ -151,19 +151,19 @@ ContainerLayerD3D10::RenderLayer()
    * Render this container's contents.
    */
   for (uint32_t i = 0; i < children.Length(); i++) {
     LayerD3D10* layerToRender = static_cast<LayerD3D10*>(children.ElementAt(i)->ImplData());
 
     if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty()) {
       continue;
     }
-    
+
     nsIntRect scissorRect =
-        layerToRender->GetLayer()->CalculateScissorRect(oldScissor, nullptr);
+        RenderTargetPixel::ToUntyped(layerToRender->GetLayer()->CalculateScissorRect(RenderTargetPixel::FromUntyped(oldScissor), nullptr));
     if (scissorRect.IsEmpty()) {
       continue;
     }
 
     D3D10_RECT d3drect;
     d3drect.left = scissorRect.x;
     d3drect.top = scissorRect.y;
     d3drect.right = scissorRect.x + scissorRect.width;
--- a/gfx/layers/d3d9/ContainerLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ContainerLayerD3D9.cpp
@@ -154,19 +154,19 @@ ContainerLayerD3D9::RenderLayer()
    * Render this container's contents.
    */
   for (uint32_t i = 0; i < children.Length(); i++) {
     LayerD3D9* layerToRender = static_cast<LayerD3D9*>(children.ElementAt(i)->ImplData());
 
     if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty()) {
       continue;
     }
-    
+
     nsIntRect scissorRect =
-      layerToRender->GetLayer()->CalculateScissorRect(oldScissor, nullptr);
+      RenderTargetPixel::ToUntyped(layerToRender->GetLayer()->CalculateScissorRect(RenderTargetPixel::FromUntyped(oldScissor), nullptr));
     if (scissorRect.IsEmpty()) {
       continue;
     }
 
     RECT d3drect;
     d3drect.left = scissorRect.x;
     d3drect.top = scissorRect.y;
     d3drect.right = scissorRect.x + scissorRect.width;
--- a/layout/base/Units.h
+++ b/layout/base/Units.h
@@ -16,24 +16,27 @@
 #include "mozilla/AppUnits.h"
 #include "mozilla/TypeTraits.h"
 
 namespace mozilla {
 
 template <typename T>
 struct IsPixel : FalseType {};
 
+// See struct decleration for a description of each unit type
 struct CSSPixel;
 struct LayoutDevicePixel;
 struct LayerPixel;
+struct RenderTargetPixel;
 struct ScreenPixel;
 
 template<> struct IsPixel<CSSPixel>          : TrueType {};
 template<> struct IsPixel<LayoutDevicePixel> : TrueType {};
 template<> struct IsPixel<LayerPixel>        : TrueType {};
+template<> struct IsPixel<RenderTargetPixel> : TrueType {};
 template<> struct IsPixel<ScreenPixel>       : TrueType {};
 
 typedef gfx::CoordTyped<CSSPixel> CSSCoord;
 typedef gfx::IntCoordTyped<CSSPixel> CSSIntCoord;
 typedef gfx::PointTyped<CSSPixel> CSSPoint;
 typedef gfx::IntPointTyped<CSSPixel> CSSIntPoint;
 typedef gfx::SizeTyped<CSSPixel> CSSSize;
 typedef gfx::IntSizeTyped<CSSPixel> CSSIntSize;
@@ -61,36 +64,47 @@ typedef gfx::SizeTyped<LayerPixel> Layer
 typedef gfx::IntSizeTyped<LayerPixel> LayerIntSize;
 typedef gfx::RectTyped<LayerPixel> LayerRect;
 typedef gfx::IntRectTyped<LayerPixel> LayerIntRect;
 typedef gfx::MarginTyped<LayerPixel> LayerMargin;
 typedef gfx::IntMarginTyped<LayerPixel> LayerIntMargin;
 
 typedef gfx::CoordTyped<ScreenPixel> ScreenCoord;
 typedef gfx::IntCoordTyped<ScreenPixel> ScreenIntCoord;
+typedef gfx::PointTyped<RenderTargetPixel> RenderTargetPoint;
+typedef gfx::IntPointTyped<RenderTargetPixel> RenderTargetIntPoint;
+typedef gfx::SizeTyped<RenderTargetPixel> RenderTargetSize;
+typedef gfx::IntSizeTyped<RenderTargetPixel> RenderTargetIntSize;
+typedef gfx::RectTyped<RenderTargetPixel> RenderTargetRect;
+typedef gfx::IntRectTyped<RenderTargetPixel> RenderTargetIntRect;
+typedef gfx::MarginTyped<RenderTargetPixel> RenderTargetMargin;
+typedef gfx::IntMarginTyped<RenderTargetPixel> RenderTargetIntMargin;
+
 typedef gfx::PointTyped<ScreenPixel> ScreenPoint;
 typedef gfx::IntPointTyped<ScreenPixel> ScreenIntPoint;
 typedef gfx::SizeTyped<ScreenPixel> ScreenSize;
 typedef gfx::IntSizeTyped<ScreenPixel> ScreenIntSize;
 typedef gfx::RectTyped<ScreenPixel> ScreenRect;
 typedef gfx::IntRectTyped<ScreenPixel> ScreenIntRect;
 typedef gfx::MarginTyped<ScreenPixel> ScreenMargin;
 typedef gfx::IntMarginTyped<ScreenPixel> ScreenIntMargin;
 
 typedef gfx::ScaleFactor<CSSPixel, LayoutDevicePixel> CSSToLayoutDeviceScale;
+typedef gfx::ScaleFactor<CSSPixel, LayerPixel> CSSToLayerScale;
+typedef gfx::ScaleFactor<CSSPixel, ScreenPixel> CSSToScreenScale;
 typedef gfx::ScaleFactor<LayoutDevicePixel, CSSPixel> LayoutDeviceToCSSScale;
-typedef gfx::ScaleFactor<CSSPixel, LayerPixel> CSSToLayerScale;
+typedef gfx::ScaleFactor<LayoutDevicePixel, LayerPixel> LayoutDeviceToLayerScale;
+typedef gfx::ScaleFactor<LayoutDevicePixel, ScreenPixel> LayoutDeviceToScreenScale;
 typedef gfx::ScaleFactor<LayerPixel, CSSPixel> LayerToCSSScale;
-typedef gfx::ScaleFactor<CSSPixel, ScreenPixel> CSSToScreenScale;
+typedef gfx::ScaleFactor<LayerPixel, LayoutDevicePixel> LayerToLayoutDeviceScale;
+typedef gfx::ScaleFactor<LayerPixel, RenderTargetPixel> LayerToRenderTargetScale;
+typedef gfx::ScaleFactor<LayerPixel, ScreenPixel> LayerToScreenScale;
+typedef gfx::ScaleFactor<RenderTargetPixel, ScreenPixel> RenderTargetToScreenScale;
 typedef gfx::ScaleFactor<ScreenPixel, CSSPixel> ScreenToCSSScale;
-typedef gfx::ScaleFactor<LayoutDevicePixel, LayerPixel> LayoutDeviceToLayerScale;
-typedef gfx::ScaleFactor<LayerPixel, LayoutDevicePixel> LayerToLayoutDeviceScale;
-typedef gfx::ScaleFactor<LayoutDevicePixel, ScreenPixel> LayoutDeviceToScreenScale;
 typedef gfx::ScaleFactor<ScreenPixel, LayoutDevicePixel> ScreenToLayoutDeviceScale;
-typedef gfx::ScaleFactor<LayerPixel, ScreenPixel> LayerToScreenScale;
 typedef gfx::ScaleFactor<ScreenPixel, LayerPixel> ScreenToLayerScale;
 
 /*
  * The pixels that content authors use to specify sizes in.
  */
 struct CSSPixel {
 
   // Conversions from app units
@@ -210,16 +224,65 @@ struct LayoutDevicePixel {
  * 1) the "display resolution" (see nsIPresShell::SetResolution)
  * 2) the "full zoom" (see nsPresContext::SetFullZoom)
  * 3) the "widget scale" (see nsIWidget::GetDefaultScale)
  */
 struct LayerPixel {
   static nsIntRect ToUntyped(const LayerIntRect& aRect) {
     return nsIntRect(aRect.x, aRect.y, aRect.width, aRect.height);
   }
+
+  static gfx::IntRect ToUnknown(const LayerIntRect& aRect) {
+    return gfx::IntRect(aRect.x, aRect.y, aRect.width, aRect.height);
+  }
+
+  static gfx::Rect ToUnknown(const LayerRect& aRect) {
+    return gfx::Rect(aRect.x, aRect.y, aRect.width, aRect.height);
+  }
+
+  static LayerIntRect FromUntyped(const nsIntRect& aRect) {
+    return LayerIntRect(aRect.x, aRect.y, aRect.width, aRect.height);
+  }
+
+  static LayerIntPoint FromUntyped(const nsIntPoint& aPoint) {
+    return LayerIntPoint(aPoint.x, aPoint.y);
+  }
+};
+
+/*
+ * Layers are always composited to a render target. This unit
+ * represents one pixel in the render target. Note that for the
+ * root render target RenderTargetPixel == ScreenPixel. Also
+ * any ContainerLayer providing an intermediate surface will
+ * have RenderTargetPixel == LayerPixel.
+ */
+struct RenderTargetPixel {
+  static nsIntPoint ToUntyped(const RenderTargetIntPoint& aPoint) {
+    return nsIntPoint(aPoint.x, aPoint.y);
+  }
+
+  static nsIntRect ToUntyped(const RenderTargetIntRect& aRect) {
+    return nsIntRect(aRect.x, aRect.y, aRect.width, aRect.height);
+  }
+
+  static gfx::IntRect ToUnknown(const RenderTargetIntRect& aRect) {
+    return gfx::IntRect(aRect.x, aRect.y, aRect.width, aRect.height);
+  }
+
+  static gfx::Rect ToUnknown(const RenderTargetRect& aRect) {
+    return gfx::Rect(aRect.x, aRect.y, aRect.width, aRect.height);
+  }
+
+  static RenderTargetRect FromUnknown(const gfx::Rect& aRect) {
+    return RenderTargetRect(aRect.x, aRect.y, aRect.width, aRect.height);
+  }
+
+  static RenderTargetIntRect FromUntyped(const nsIntRect& aRect) {
+    return RenderTargetIntRect(aRect.x, aRect.y, aRect.width, aRect.height);
+  }
 };
 
 /*
  * The pixels that are displayed on the screen.
  * On non-OMTC platforms this should be equivalent to LayerPixel units.
  * On OMTC platforms these may diverge from LayerPixel units temporarily,
  * while an asynchronous zoom is happening, but should eventually converge
  * back to LayerPixel units. Some variables (such as those representing