Bug 877728 - Convert some CSS rects passed to Java from gfx::Rect to CSSRect. r=BenWa
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 03 Jun 2013 09:52:44 -0400
changeset 133795 1fbdc5adccbecdd3d775882a146c4d373ad807fb
parent 133794 70cf9c347db65f7a5ddd154846ad2c295814eb1d
child 133796 f0fb17e872ea892f146df6e2b447c1c685e08a1f
push id24771
push userryanvm@gmail.com
push dateMon, 03 Jun 2013 19:56:31 +0000
treeherdermozilla-central@e8a328c3e5bb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBenWa
bugs877728
milestone24.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 877728 - Convert some CSS rects passed to Java from gfx::Rect to CSSRect. r=BenWa
dom/ipc/TabChild.cpp
gfx/2d/Rect.h
gfx/layers/FrameMetrics.h
gfx/layers/composite/AsyncCompositionManager.cpp
gfx/layers/composite/AsyncCompositionManager.h
gfx/layers/composite/ThebesLayerComposite.cpp
gfx/layers/ipc/AsyncPanZoomController.cpp
gfx/layers/ipc/AsyncPanZoomController.h
gfx/layers/ipc/Axis.cpp
gfx/layers/ipc/Axis.h
ipc/glue/IPCMessageUtils.h
layout/base/Units.h
layout/base/nsDisplayList.cpp
layout/ipc/RenderFrameParent.cpp
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJavaWrappers.cpp
widget/android/AndroidJavaWrappers.h
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -345,18 +345,19 @@ TabChild::Observe(nsISupports *aSubject,
 
         // Calculate a really simple resolution that we probably won't
         // be keeping, as well as putting the scroll offset back to
         // the top-left of the page.
         mLastMetrics.mZoom = gfxSize(1.0, 1.0);
         mLastMetrics.mViewport =
             gfx::Rect(0, 0,
                       kDefaultViewportSize.width, kDefaultViewportSize.height);
-        mLastMetrics.mCompositionBounds = nsIntRect(nsIntPoint(0, 0),
-                                                    mInnerSize);
+        // I don't know what units mInnerSize is in, hence FromUnknownRect
+        mLastMetrics.mCompositionBounds = LayerIntRect::FromUnknownRect(
+          gfx::IntRect(0, 0, mInnerSize.width, mInnerSize.height));
         mLastMetrics.mResolution =
           AsyncPanZoomController::CalculateResolution(mLastMetrics);
         mLastMetrics.mScrollOffset = CSSPoint(0, 0);
         utils->SetResolution(mLastMetrics.mResolution.width,
                              mLastMetrics.mResolution.height);
 
         HandlePossibleViewportChange();
       }
@@ -585,18 +586,20 @@ TabChild::HandlePossibleViewportChange()
   // respect to CSS pixels because of the CSS viewport size changing.
   int32_t oldScreenWidth = mLastMetrics.mCompositionBounds.width;
   if (!oldScreenWidth) {
     oldScreenWidth = mInnerSize.width;
   }
 
   FrameMetrics metrics(mLastMetrics);
   metrics.mViewport = gfx::Rect(0.0f, 0.0f, viewportW, viewportH);
-  metrics.mScrollableRect = gfx::Rect(0.0f, 0.0f, pageWidth, pageHeight);
-  metrics.mCompositionBounds = nsIntRect(0, 0, mInnerSize.width, mInnerSize.height);
+  metrics.mScrollableRect = CSSRect(0.0f, 0.0f, pageWidth, pageHeight);
+  // I don't know what units mInnerSize is in, hence FromUnknownRect
+  metrics.mCompositionBounds = LayerIntRect::FromUnknownRect(
+    gfx::IntRect(0, 0, mInnerSize.width, mInnerSize.height));
 
   // Changing the zoom when we're not doing a first paint will get ignored
   // by AsyncPanZoomController and causes a blurry flash.
   bool isFirstPaint;
   nsresult rv = utils->GetIsFirstPaint(&isFirstPaint);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   if (NS_FAILED(rv) || isFirstPaint) {
     gfxSize intrinsicScale =
@@ -1478,17 +1481,17 @@ TabChild::RecvUpdateFrame(const FrameMet
 
 bool
 TabChild::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
   {
     if (!mCx || !mTabChildGlobal) {
         return true;
     }
 
-    gfx::Rect cssCompositedRect =
+    CSSRect cssCompositedRect =
       AsyncPanZoomController::CalculateCompositedRectInCssPixels(aFrameMetrics);
     // The BrowserElementScrolling helper must know about these updated metrics
     // for other functions it performs, such as double tap handling.
     nsCString data;
     data += nsPrintfCString("{ \"x\" : %d", NS_lround(aFrameMetrics.mScrollOffset.x));
     data += nsPrintfCString(", \"y\" : %d", NS_lround(aFrameMetrics.mScrollOffset.y));
     data += nsPrintfCString(", \"viewport\" : ");
         data += nsPrintfCString("{ \"width\" : %f", aFrameMetrics.mViewport.width);
--- a/gfx/2d/Rect.h
+++ b/gfx/2d/Rect.h
@@ -36,16 +36,27 @@ struct IntRectTyped :
         Super(aPos, aSize) {}
     IntRectTyped(int32_t _x, int32_t _y, int32_t _width, int32_t _height) :
         Super(_x, _y, _width, _height) {}
 
     // Rounding isn't meaningful on an integer rectangle.
     void Round() {}
     void RoundIn() {}
     void RoundOut() {}
+
+    // XXX When all of the code is ported, the following functions to convert to and from
+    // unknown types should be removed.
+
+    static IntRectTyped<units> FromUnknownRect(const IntRectTyped<UnknownUnits>& rect) {
+        return IntRectTyped<units>(rect.x, rect.y, rect.width, rect.height);
+    }
+
+    IntRectTyped<UnknownUnits> ToUnknownRect() const {
+        return IntRectTyped<UnknownUnits>(this->x, this->y, this->width, this->height);
+    }
 };
 typedef IntRectTyped<UnknownUnits> IntRect;
 
 template<class units>
 struct RectTyped :
     public BaseRect<Float, RectTyped<units>, PointTyped<units>, SizeTyped<units>, Margin>,
     public units {
     typedef BaseRect<Float, RectTyped<units>, PointTyped<units>, SizeTyped<units>, Margin> Super;
@@ -70,15 +81,26 @@ struct RectTyped :
     bool ToIntRect(IntRectTyped<units> *aOut) const
     {
       *aOut = IntRectTyped<units>(int32_t(this->X()), int32_t(this->Y()),
                                   int32_t(this->Width()), int32_t(this->Height()));
       return RectTyped<units>(Float(aOut->x), Float(aOut->y), 
                               Float(aOut->width), Float(aOut->height))
              .IsEqualEdges(*this);
     }
+
+    // XXX When all of the code is ported, the following functions to convert to and from
+    // unknown types should be removed.
+
+    static RectTyped<units> FromUnknownRect(const RectTyped<UnknownUnits>& rect) {
+        return RectTyped<units>(rect.x, rect.y, rect.width, rect.height);
+    }
+
+    RectTyped<UnknownUnits> ToUnknownRect() const {
+        return RectTyped<UnknownUnits>(this->x, this->y, this->width, this->height);
+    }
 };
 typedef RectTyped<UnknownUnits> Rect;
 
 }
 }
 
 #endif /* MOZILLA_GFX_RECT_H_ */
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -115,17 +115,17 @@ public:
   // viewport dimensions to calculate the displayport, we'd run into situations
   // where we're prerendering the wrong regions and the content may be clipped,
   // or too much of it prerendered. If the displayport is the same as the
   // viewport, there is no need for this and we can just use the viewport
   // instead.
   //
   // This is only valid on the root layer. Nested iframes do not need this
   // metric as they do not have a displayport set. See bug 775452.
-  nsIntRect mCompositionBounds;
+  LayerIntRect mCompositionBounds;
 
   // |mScrollableRect|, stored in device pixels. DECPRECATED, DO NOT USE.
   //
   // This is valid on any layer where |mScrollableRect| is, though it may be
   // more lazily maintained than |mScrollableRect|. That is, when
   // |mScrollableRect| is updated, this may lag. For this reason, it's better to
   // use |mScrollableRect| for any control logic.
   //
@@ -203,17 +203,17 @@ public:
   //   width = window.innerWidth, height = window.innerHeight }
   //
   // This is relative to the document. It is in the same coordinate space as
   // |mScrollOffset|, but a different coordinate space than |mViewport| and
   // |mDisplayPort|. Note also that this coordinate system is understood by
   // window.scrollTo().
   //
   // This is valid on any layer unless it has no content.
-  gfx::Rect mScrollableRect;
+  mozilla::CSSRect mScrollableRect;
 
   // ---------------------------------------------------------------------------
   // The following metrics are dimensionless.
   //
 
   // The resolution, along both axes, that the current frame has been painted
   // at.
   //
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -565,25 +565,25 @@ AsyncCompositionManager::TransformShadow
 
   return wantNextFrame;
 }
 
 void
 AsyncCompositionManager::SetFirstPaintViewport(const nsIntPoint& aOffset,
                                                float aZoom,
                                                const nsIntRect& aPageRect,
-                                               const gfx::Rect& aCssPageRect)
+                                               const CSSRect& aCssPageRect)
 {
 #ifdef MOZ_WIDGET_ANDROID
   AndroidBridge::Bridge()->SetFirstPaintViewport(aOffset, aZoom, aPageRect, aCssPageRect);
 #endif
 }
 
 void
-AsyncCompositionManager::SetPageRect(const gfx::Rect& aCssPageRect)
+AsyncCompositionManager::SetPageRect(const CSSRect& aCssPageRect)
 {
 #ifdef MOZ_WIDGET_ANDROID
   AndroidBridge::Bridge()->SetPageRect(aCssPageRect);
 #endif
 }
 
 void
 AsyncCompositionManager::SyncViewportInfo(const nsIntRect& aDisplayPort,
@@ -603,17 +603,17 @@ AsyncCompositionManager::SyncViewportInf
                                             aFixedLayerMargins,
                                             aOffset);
 #endif
 }
 
 void
 AsyncCompositionManager::SyncFrameMetrics(const gfx::Point& aScrollOffset,
                                           float aZoom,
-                                          const gfx::Rect& aCssPageRect,
+                                          const CSSRect& aCssPageRect,
                                           bool aLayersUpdated,
                                           const gfx::Rect& aDisplayPort,
                                           float aDisplayResolution,
                                           bool aIsFirstPaint,
                                           gfx::Margin& aFixedLayerMargins,
                                           gfx::Point& aOffset)
 {
 #ifdef MOZ_WIDGET_ANDROID
--- a/gfx/layers/composite/AsyncCompositionManager.h
+++ b/gfx/layers/composite/AsyncCompositionManager.h
@@ -116,28 +116,28 @@ private:
   // applied for |aLayer|.  *aWantNextFrame is set to true if the
   // controller wants another animation frame.
   bool ApplyAsyncContentTransformToTree(TimeStamp aCurrentFrame, Layer* aLayer,
                                         bool* aWantNextFrame);
 
   void SetFirstPaintViewport(const nsIntPoint& aOffset,
                              float aZoom,
                              const nsIntRect& aPageRect,
-                             const gfx::Rect& aCssPageRect);
-  void SetPageRect(const gfx::Rect& aCssPageRect);
+                             const CSSRect& aCssPageRect);
+  void SetPageRect(const CSSRect& aCssPageRect);
   void SyncViewportInfo(const nsIntRect& aDisplayPort,
                         float aDisplayResolution,
                         bool aLayersUpdated,
                         nsIntPoint& aScrollOffset,
                         float& aScaleX, float& aScaleY,
                         gfx::Margin& aFixedLayerMargins,
                         gfx::Point& aOffset);
   void SyncFrameMetrics(const gfx::Point& aScrollOffset,
                         float aZoom,
-                        const gfx::Rect& aCssPageRect,
+                        const CSSRect& aCssPageRect,
                         bool aLayersUpdated,
                         const gfx::Rect& aDisplayPort,
                         float aDisplayResolution,
                         bool aIsFirstPaint,
                         gfx::Margin& aFixedLayerMargins,
                         gfx::Point& aOffset);
 
   /**
--- a/gfx/layers/composite/ThebesLayerComposite.cpp
+++ b/gfx/layers/composite/ThebesLayerComposite.cpp
@@ -232,17 +232,20 @@ ThebesLayerComposite::GetCompositionBoun
   gfxRect compositionBounds;
   ContainerLayer* scrollableLayer = nullptr;
   for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) {
     const FrameMetrics& parentMetrics = parent->GetFrameMetrics();
     if (parentMetrics.IsScrollable())
       scrollableLayer = parent;
     if (!parentMetrics.mDisplayPort.IsEmpty() && scrollableLayer) {
       // Get the composition bounds, so as not to waste rendering time.
-      compositionBounds = gfxRect(parentMetrics.mCompositionBounds);
+      compositionBounds = gfxRect(parentMetrics.mCompositionBounds.x,
+                                  parentMetrics.mCompositionBounds.y,
+                                  parentMetrics.mCompositionBounds.width,
+                                  parentMetrics.mCompositionBounds.height);
 
       // Calculate the scale transform applied to the root layer to determine
       // the content resolution.
       Layer* rootLayer = Manager()->GetRoot();
       const gfx3DMatrix& rootTransform = rootLayer->GetTransform();
       float scaleX = rootTransform.GetXScale();
       float scaleY = rootTransform.GetYScale();
 
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -827,26 +827,24 @@ void AsyncPanZoomController::SetComposit
 void AsyncPanZoomController::ScrollBy(const gfx::Point& aOffset) {
   gfx::Point newOffset(mFrameMetrics.mScrollOffset.x + aOffset.x,
                        mFrameMetrics.mScrollOffset.y + aOffset.y);
   FrameMetrics metrics(mFrameMetrics);
   metrics.mScrollOffset = CSSPoint::FromUnknownPoint(newOffset);
   mFrameMetrics = metrics;
 }
 
-void AsyncPanZoomController::SetPageRect(const gfx::Rect& aCSSPageRect) {
+void AsyncPanZoomController::SetPageRect(const CSSRect& aCSSPageRect) {
   FrameMetrics metrics = mFrameMetrics;
-  gfx::Rect pageSize = aCSSPageRect;
   gfxFloat resolution = CalculateResolution(mFrameMetrics).width;
 
   // The page rect is the css page rect scaled by the current zoom.
-  pageSize.ScaleInverseRoundOut(resolution);
-
   // Round the page rect so we don't get any truncation, then get the nsIntRect
   // from this.
+  LayerIntRect pageSize = LayerRect::FromCSSRectRoundOut(aCSSPageRect, resolution);
   metrics.mContentRect = nsIntRect(pageSize.x, pageSize.y,
                                    pageSize.width, pageSize.height);
   metrics.mScrollableRect = aCSSPageRect;
 
   mFrameMetrics = metrics;
 }
 
 void AsyncPanZoomController::ScaleWithFocus(float aZoom,
@@ -913,20 +911,20 @@ const gfx::Rect AsyncPanZoomController::
   // If we don't get an estimated paint duration, we probably don't have any
   // data. In this case, we're dealing with either a stationary frame or a first
   // paint. In either of these cases, we can just assume it'll take 1 second to
   // paint. Getting this correct is not important anyways since it's only really
   // useful when accelerating, which can't be happening at this point.
   double estimatedPaintDuration =
     aEstimatedPaintDuration > EPSILON ? aEstimatedPaintDuration : 1.0;
 
-  gfxFloat resolution = CalculateResolution(aFrameMetrics).width;
-  nsIntRect compositionBounds = aFrameMetrics.mCompositionBounds;
-  compositionBounds.ScaleInverseRoundIn(resolution);
-  gfx::Rect scrollableRect = aFrameMetrics.mScrollableRect;
+  gfxSize resolution = CalculateResolution(aFrameMetrics);
+  CSSIntRect compositionBounds = LayerIntRect::ToCSSIntRectRoundIn(
+    aFrameMetrics.mCompositionBounds, resolution);
+  gfx::Rect scrollableRect = aFrameMetrics.mScrollableRect.ToUnknownRect();
 
   // Ensure the scrollableRect is at least as big as the compositionBounds
   // because the scrollableRect can be smaller if the content is not large
   // and the scrollableRect hasn't been updated yet.
   // We move the scrollableRect up because we don't know if we can move it
   // down. i.e. we know that scrollableRect can go back as far as zero.
   // but we don't know how much further ahead it can go.
   if (scrollableRect.width < compositionBounds.width) {
@@ -1005,26 +1003,23 @@ AsyncPanZoomController::CalculateIntrins
 AsyncPanZoomController::CalculateResolution(const FrameMetrics& aMetrics)
 {
   gfxSize intrinsicScale = CalculateIntrinsicScale(aMetrics);
   gfxSize userZoom = aMetrics.mZoom;
   return gfxSize(intrinsicScale.width * userZoom.width,
                  intrinsicScale.height * userZoom.height);
 }
 
-/*static*/ gfx::Rect
+/*static*/ CSSRect
 AsyncPanZoomController::CalculateCompositedRectInCssPixels(const FrameMetrics& aMetrics)
 {
   gfxSize resolution = CalculateResolution(aMetrics);
-  gfx::Rect rect(aMetrics.mCompositionBounds.x,
-                 aMetrics.mCompositionBounds.y,
-                 aMetrics.mCompositionBounds.width,
-                 aMetrics.mCompositionBounds.height);
-  rect.ScaleInverseRoundIn(resolution.width, resolution.height);
-  return rect;
+  CSSIntRect rect = LayerIntRect::ToCSSIntRectRoundIn(
+    aMetrics.mCompositionBounds, resolution);
+  return CSSRect(rect);
 }
 
 void AsyncPanZoomController::SetDPI(int aDPI) {
   mDPI = aDPI;
 }
 
 int AsyncPanZoomController::GetDPI() {
   return mDPI;
@@ -1300,20 +1295,20 @@ void AsyncPanZoomController::NotifyLayer
   }
 }
 
 const FrameMetrics& AsyncPanZoomController::GetFrameMetrics() {
   mMonitor.AssertCurrentThreadOwns();
   return mFrameMetrics;
 }
 
-void AsyncPanZoomController::UpdateCompositionBounds(const nsIntRect& aCompositionBounds) {
+void AsyncPanZoomController::UpdateCompositionBounds(const LayerIntRect& aCompositionBounds) {
   MonitorAutoLock mon(mMonitor);
 
-  nsIntRect oldCompositionBounds = mFrameMetrics.mCompositionBounds;
+  LayerIntRect oldCompositionBounds = mFrameMetrics.mCompositionBounds;
   mFrameMetrics.mCompositionBounds = aCompositionBounds;
 
   // If the window had 0 dimensions before, or does now, we don't want to
   // repaint or update the zoom since we'll run into rendering issues and/or
   // divide-by-zero. This manifests itself as the screen flashing. If the page
   // has gone out of view, the buffer will be cleared elsewhere anyways.
   if (aCompositionBounds.width && aCompositionBounds.height &&
       oldCompositionBounds.width && oldCompositionBounds.height) {
@@ -1331,38 +1326,38 @@ void AsyncPanZoomController::CancelDefau
   }
 }
 
 void AsyncPanZoomController::DetectScrollableSubframe() {
   mDelayPanning = true;
 }
 
 void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) {
-  gfx::Rect zoomToRect(gfx::Rect(aRect.x, aRect.y, aRect.width, aRect.height));
+  CSSRect zoomToRect(aRect.x, aRect.y, aRect.width, aRect.height);
 
   SetState(ANIMATING_ZOOM);
 
   {
     MonitorAutoLock mon(mMonitor);
 
-    nsIntRect compositionBounds = mFrameMetrics.mCompositionBounds;
-    gfx::Rect cssPageRect = mFrameMetrics.mScrollableRect;
+    LayerIntRect compositionBounds = mFrameMetrics.mCompositionBounds;
+    CSSRect cssPageRect = mFrameMetrics.mScrollableRect;
     CSSPoint scrollOffset = mFrameMetrics.mScrollOffset;
     gfxSize resolution = CalculateResolution(mFrameMetrics);
     gfxSize currentZoom = mFrameMetrics.mZoom;
     float targetZoom;
     gfxFloat targetResolution;
 
     // The minimum zoom to prevent over-zoom-out.
     // If the zoom factor is lower than this (i.e. we are zoomed more into the page),
     // then the CSS content rect, in layers pixels, will be smaller than the
     // composition bounds. If this happens, we can't fill the target composited
     // area with this frame.
     float localMinZoom;
-    gfx::Rect compositedRect = CalculateCompositedRectInCssPixels(mFrameMetrics);
+    CSSRect compositedRect = CalculateCompositedRectInCssPixels(mFrameMetrics);
     localMinZoom =
       std::max(currentZoom.width / (cssPageRect.width / compositedRect.width),
                currentZoom.height / (cssPageRect.height / compositedRect.height));
     localMinZoom = std::max(localMinZoom, mMinZoom);
 
     if (!zoomToRect.IsEmpty()) {
       // Intersect the zoom-to-rect to the CSS rect to make sure it fits.
       zoomToRect = zoomToRect.Intersect(cssPageRect);
@@ -1373,59 +1368,57 @@ void AsyncPanZoomController::ZoomToRect(
     }
     // 1. If the rect is empty, request received from browserElementScrolling.js
     // 2. currentZoom is equal to mMaxZoom and user still double-tapping it
     // 3. currentZoom is equal to localMinZoom and user still double-tapping it
     // Treat these three cases as a request to zoom out as much as possible.
     if (zoomToRect.IsEmpty() ||
         (currentZoom.width == mMaxZoom && targetZoom >= mMaxZoom) ||
         (currentZoom.width == localMinZoom && targetZoom <= localMinZoom)) {
-      nsIntRect cssCompositionBounds = compositionBounds;
-      cssCompositionBounds.ScaleInverseRoundIn(resolution.width,
-                                               resolution.height);
+      CSSIntRect cssCompositionBounds = LayerIntRect::ToCSSIntRectRoundIn(
+        compositionBounds, resolution);
 
       float y = scrollOffset.y;
       float newHeight =
         cssCompositionBounds.height * cssPageRect.width / cssCompositionBounds.width;
       float dh = cssCompositionBounds.height - newHeight;
 
-      zoomToRect = gfx::Rect(0.0f,
-                             y + dh/2,
-                             cssPageRect.width,
-                             newHeight);
+      zoomToRect = CSSRect(0.0f,
+                           y + dh/2,
+                           cssPageRect.width,
+                           newHeight);
       zoomToRect = zoomToRect.Intersect(cssPageRect);
       targetResolution =
         std::min(compositionBounds.width / zoomToRect.width,
                  compositionBounds.height / zoomToRect.height);
       targetZoom = float(targetResolution / resolution.width) * currentZoom.width;
     }
 
     targetZoom = clamped(targetZoom, localMinZoom, mMaxZoom);
     mEndZoomToMetrics.mZoom = gfxSize(targetZoom, targetZoom);
 
     // Adjust the zoomToRect to a sensible position to prevent overscrolling.
     FrameMetrics metricsAfterZoom = mFrameMetrics;
     metricsAfterZoom.mZoom = mEndZoomToMetrics.mZoom;
-    gfx::Rect rectAfterZoom
+    CSSRect rectAfterZoom
       = CalculateCompositedRectInCssPixels(metricsAfterZoom);
 
     // If either of these conditions are met, the page will be
     // overscrolled after zoomed
     if (zoomToRect.y + rectAfterZoom.height > cssPageRect.height) {
       zoomToRect.y = cssPageRect.height - rectAfterZoom.height;
       zoomToRect.y = zoomToRect.y > 0 ? zoomToRect.y : 0;
     }
     if (zoomToRect.x + rectAfterZoom.width > cssPageRect.width) {
       zoomToRect.x = cssPageRect.width - rectAfterZoom.width;
       zoomToRect.x = zoomToRect.x > 0 ? zoomToRect.x : 0;
     }
 
     mStartZoomToMetrics = mFrameMetrics;
-    mEndZoomToMetrics.mScrollOffset = CSSPoint::FromUnknownPoint(
-      gfx::Point(zoomToRect.x, zoomToRect.y));
+    mEndZoomToMetrics.mScrollOffset = zoomToRect.TopLeft();
 
     mAnimationStartTime = TimeStamp::Now();
 
     ScheduleComposite();
   }
 }
 
 void AsyncPanZoomController::ContentReceivedTouch(bool aPreventDefault) {
@@ -1510,17 +1503,17 @@ void AsyncPanZoomController::SendAsyncSc
     return;
   }
 
   gfx::Rect contentRect;
   gfx::Size scrollableSize;
   {
     scrollableSize = gfx::Size(mFrameMetrics.mScrollableRect.width,
                                mFrameMetrics.mScrollableRect.height);
-    contentRect =
-      AsyncPanZoomController::CalculateCompositedRectInCssPixels(mFrameMetrics);
+    contentRect = AsyncPanZoomController::CalculateCompositedRectInCssPixels(mFrameMetrics)
+        .ToUnknownRect();
     contentRect.MoveTo(mCurrentAsyncScrollOffset);
   }
 
   mGeckoContentController->SendAsyncScrollDOMEvent(contentRect, scrollableSize);
 }
 }
 }
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -106,17 +106,17 @@ public:
 
   /**
    * Updates the composition bounds, i.e. the dimensions of the final size of
    * the frame this is tied to during composition onto, in device pixels. In
    * general, this will just be:
    * { x = 0, y = 0, width = surface.width, height = surface.height }, however
    * there is no hard requirement for this.
    */
-  void UpdateCompositionBounds(const nsIntRect& aCompositionBounds);
+  void UpdateCompositionBounds(const LayerIntRect& aCompositionBounds);
 
   /**
    * We are scrolling a subframe, so disable our machinery until we hit
    * a touch end or a new touch start. This prevents us from accidentally
    * panning both the subframe and the parent frame.
    *
    * XXX/bug 775452: We should eventually be supporting async scrollable
    * subframes.
@@ -197,17 +197,17 @@ public:
   // --------------------------------------------------------------------------
   // These methods can be called from any thread.
   //
 
   /**
    * Sets the CSS page rect, and calculates a new page rect based on the zoom
    * level of the current metrics and the passed in CSS page rect.
    */
-  void SetPageRect(const gfx::Rect& aCSSPageRect);
+  void SetPageRect(const CSSRect& aCSSPageRect);
 
   /**
    * Sets the DPI of the device for use within panning and zooming logic. It is
    * a platform responsibility to set this on initialization of this class and
    * whenever it changes.
    */
   void SetDPI(int aDPI);
 
@@ -238,17 +238,17 @@ public:
   /**
    * Return the resolution that content should be rendered at given
    * the configuration in aFrameMetrics: viewport dimensions, zoom
    * factor, etc.  (The mResolution member of aFrameMetrics is
    * ignored.)
    */
   static gfxSize CalculateResolution(const FrameMetrics& aMetrics);
 
-  static gfx::Rect CalculateCompositedRectInCssPixels(const FrameMetrics& aMetrics);
+  static CSSRect CalculateCompositedRectInCssPixels(const FrameMetrics& aMetrics);
 
   /**
    * Send an mozbrowserasyncscroll event.
    * *** The monitor must be held while calling this.
    */
   void SendAsyncScrollEvent();
 
   /**
--- a/gfx/layers/ipc/Axis.cpp
+++ b/gfx/layers/ipc/Axis.cpp
@@ -293,82 +293,79 @@ float Axis::GetPageEnd() {
 
 float Axis::GetOrigin() {
   CSSPoint origin = mAsyncPanZoomController->GetFrameMetrics().mScrollOffset;
   return GetPointOffset(origin);
 }
 
 float Axis::GetCompositionLength() {
   const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
-  gfx::Rect cssCompositedRect =
+  CSSRect cssCompositedRect =
     AsyncPanZoomController::CalculateCompositedRectInCssPixels(metrics);
   return GetRectLength(cssCompositedRect);
 }
 
 float Axis::GetPageStart() {
-  gfx::Rect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect;
+  CSSRect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect;
   return GetRectOffset(pageRect);
 }
 
 float Axis::GetPageLength() {
-  gfx::Rect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect;
+  CSSRect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect;
   return GetRectLength(pageRect);
 }
 
 bool Axis::ScaleWillOverscrollBothSides(float aScale) {
   const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
 
-  gfx::Rect cssContentRect = metrics.mScrollableRect;
+  CSSRect cssContentRect = metrics.mScrollableRect;
 
   float currentScale = metrics.mZoom.width;
-  nsIntRect compositionBounds = metrics.mCompositionBounds;
-  gfx::Rect scaledCompositionBounds =
-    gfx::Rect(compositionBounds.x, compositionBounds.y,
-              compositionBounds.width, compositionBounds.height);
-  scaledCompositionBounds.ScaleInverseRoundIn(currentScale * aScale);
+  CSSIntRect cssCompositionBounds = LayerIntRect::ToCSSIntRectRoundIn(
+    metrics.mCompositionBounds, currentScale * aScale);
 
-  return GetRectLength(cssContentRect) < GetRectLength(scaledCompositionBounds);
+  return GetRectLength(cssContentRect) < GetRectLength(CSSRect(cssCompositionBounds));
 }
 
 AxisX::AxisX(AsyncPanZoomController* aAsyncPanZoomController)
   : Axis(aAsyncPanZoomController)
 {
 
 }
 
 float AxisX::GetPointOffset(const CSSPoint& aPoint)
 {
   return aPoint.x;
 }
 
-float AxisX::GetRectLength(const gfx::Rect& aRect)
+float AxisX::GetRectLength(const CSSRect& aRect)
 {
   return aRect.width;
 }
 
-float AxisX::GetRectOffset(const gfx::Rect& aRect)
+float AxisX::GetRectOffset(const CSSRect& aRect)
 {
   return aRect.x;
 }
 
 AxisY::AxisY(AsyncPanZoomController* aAsyncPanZoomController)
   : Axis(aAsyncPanZoomController)
 {
 
 }
 
 float AxisY::GetPointOffset(const CSSPoint& aPoint)
 {
   return aPoint.y;
 }
 
-float AxisY::GetRectLength(const gfx::Rect& aRect)
+float AxisY::GetRectLength(const CSSRect& aRect)
 {
   return aRect.height;
 }
 
-float AxisY::GetRectOffset(const gfx::Rect& aRect)
+float AxisY::GetRectOffset(const CSSRect& aRect)
 {
   return aRect.y;
 }
 
 }
 }
--- a/gfx/layers/ipc/Axis.h
+++ b/gfx/layers/ipc/Axis.h
@@ -167,18 +167,18 @@ public:
   float GetOrigin();
   float GetCompositionLength();
   float GetPageStart();
   float GetPageLength();
   float GetCompositionEnd();
   float GetPageEnd();
 
   virtual float GetPointOffset(const CSSPoint& aPoint) = 0;
-  virtual float GetRectLength(const gfx::Rect& aRect) = 0;
-  virtual float GetRectOffset(const gfx::Rect& aRect) = 0;
+  virtual float GetRectLength(const CSSRect& aRect) = 0;
+  virtual float GetRectOffset(const CSSRect& aRect) = 0;
 
 protected:
   int32_t mPos;
   int32_t mStartPos;
   float mVelocity;
   // Acceleration is represented by an int, which is the power we raise a
   // constant to and then multiply the velocity by whenever it is sampled. We do
   // this only when we detect that the user wants to do a fast fling; that is,
@@ -188,24 +188,24 @@ protected:
   AsyncPanZoomController* mAsyncPanZoomController;
   nsTArray<float> mVelocityQueue;
 };
 
 class AxisX : public Axis {
 public:
   AxisX(AsyncPanZoomController* mAsyncPanZoomController);
   virtual float GetPointOffset(const CSSPoint& aPoint);
-  virtual float GetRectLength(const gfx::Rect& aRect);
-  virtual float GetRectOffset(const gfx::Rect& aRect);
+  virtual float GetRectLength(const CSSRect& aRect);
+  virtual float GetRectOffset(const CSSRect& aRect);
 };
 
 class AxisY : public Axis {
 public:
   AxisY(AsyncPanZoomController* mAsyncPanZoomController);
   virtual float GetPointOffset(const CSSPoint& aPoint);
-  virtual float GetRectLength(const gfx::Rect& aRect);
-  virtual float GetRectOffset(const gfx::Rect& aRect);
+  virtual float GetRectLength(const CSSRect& aRect);
+  virtual float GetRectOffset(const CSSRect& aRect);
 };
 
 }
 }
 
 #endif
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -819,20 +819,42 @@ struct ParamTraits<mozilla::gfx::Size>
 
   static bool Read(const Message* msg, void** iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->width) &&
             ReadParam(msg, iter, &result->height));
   }
 };
 
-template<>
-struct ParamTraits<mozilla::gfx::Rect>
+template<class T>
+struct ParamTraits< mozilla::gfx::RectTyped<T> >
 {
-  typedef mozilla::gfx::Rect paramType;
+  typedef mozilla::gfx::RectTyped<T> paramType;
+
+  static void Write(Message* msg, const paramType& param)
+  {
+    WriteParam(msg, param.x);
+    WriteParam(msg, param.y);
+    WriteParam(msg, param.width);
+    WriteParam(msg, param.height);
+  }
+
+  static bool Read(const Message* msg, void** iter, paramType* result)
+  {
+    return (ReadParam(msg, iter, &result->x) &&
+            ReadParam(msg, iter, &result->y) &&
+            ReadParam(msg, iter, &result->width) &&
+            ReadParam(msg, iter, &result->height));
+  }
+};
+
+template<class T>
+struct ParamTraits< mozilla::gfx::IntRectTyped<T> >
+{
+  typedef mozilla::gfx::IntRectTyped<T> paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.x);
     WriteParam(msg, param.y);
     WriteParam(msg, param.width);
     WriteParam(msg, param.height);
   }
--- a/layout/base/Units.h
+++ b/layout/base/Units.h
@@ -17,15 +17,47 @@ struct CSSPixel {
     return gfx::PointTyped<CSSPixel>(NSAppUnitsToFloatPixels(pt.x, float(nsDeviceContext::AppUnitsPerCSSPixel())),
                                      NSAppUnitsToFloatPixels(pt.y, float(nsDeviceContext::AppUnitsPerCSSPixel())));
   }
 
   static nsPoint ToAppUnits(const gfx::PointTyped<CSSPixel> &pt) {
     return nsPoint(NSFloatPixelsToAppUnits(pt.x, float(nsDeviceContext::AppUnitsPerCSSPixel())),
                    NSFloatPixelsToAppUnits(pt.y, float(nsDeviceContext::AppUnitsPerCSSPixel())));
   }
+
+  static gfx::RectTyped<CSSPixel> FromAppUnits(const nsRect &rect) {
+    return gfx::RectTyped<CSSPixel>(NSAppUnitsToFloatPixels(rect.x, float(nsDeviceContext::AppUnitsPerCSSPixel())),
+                                    NSAppUnitsToFloatPixels(rect.y, float(nsDeviceContext::AppUnitsPerCSSPixel())),
+                                    NSAppUnitsToFloatPixels(rect.width, float(nsDeviceContext::AppUnitsPerCSSPixel())),
+                                    NSAppUnitsToFloatPixels(rect.height, float(nsDeviceContext::AppUnitsPerCSSPixel())));
+  }
 };
 
 typedef gfx::PointTyped<CSSPixel> CSSPoint;
+typedef gfx::RectTyped<CSSPixel> CSSRect;
+typedef gfx::IntRectTyped<CSSPixel> CSSIntRect;
+
+struct LayerPixel {
+  static gfx::IntRectTyped<LayerPixel> FromCSSRectRoundOut(const CSSRect& rect, gfxFloat resolution) {
+    gfx::RectTyped<LayerPixel> scaled(rect.x, rect.y, rect.width, rect.height);
+    scaled.ScaleInverseRoundOut(resolution);
+    return gfx::IntRectTyped<LayerPixel>(scaled.x, scaled.y, scaled.width, scaled.height);
+  }
+
+  static CSSIntRect ToCSSIntRectRoundIn(const gfx::IntRectTyped<LayerPixel>& rect, gfxFloat resolution) {
+    gfx::IntRectTyped<CSSPixel> ret(rect.x, rect.y, rect.width, rect.height);
+    ret.ScaleInverseRoundIn(resolution, resolution);
+    return ret;
+  }
+
+  static CSSIntRect ToCSSIntRectRoundIn(const gfx::IntRectTyped<LayerPixel>& rect, gfxSize resolution) {
+    gfx::IntRectTyped<CSSPixel> ret(rect.x, rect.y, rect.width, rect.height);
+    ret.ScaleInverseRoundIn(resolution.width, resolution.height);
+    return ret;
+  }
+};
+
+typedef gfx::RectTyped<LayerPixel> LayerRect;
+typedef gfx::IntRectTyped<LayerPixel> LayerIntRect;
 
 };
 
 #endif
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -650,33 +650,25 @@ static void RecordFrameMetrics(nsIFrame*
   nsIScrollableFrame* scrollableFrame = nullptr;
   if (aScrollFrame)
     scrollableFrame = aScrollFrame->GetScrollTargetFrame();
 
   if (scrollableFrame) {
     nsRect contentBounds = scrollableFrame->GetScrollRange();
     contentBounds.width += scrollableFrame->GetScrollPortRect().width;
     contentBounds.height += scrollableFrame->GetScrollPortRect().height;
-    metrics.mScrollableRect =
-      mozilla::gfx::Rect(nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.x),
-                         nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.y),
-                         nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.width),
-                         nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.height));
+    metrics.mScrollableRect = CSSRect::FromAppUnits(contentBounds);
     metrics.mContentRect = contentBounds.ScaleToNearestPixels(
       aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
     nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
     metrics.mScrollOffset = CSSPoint::FromAppUnits(scrollPosition);
   }
   else {
     nsRect contentBounds = aForFrame->GetRect();
-    metrics.mScrollableRect =
-      mozilla::gfx::Rect(nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.x),
-                         nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.y),
-                         nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.width),
-                         nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.height));
+    metrics.mScrollableRect = CSSRect::FromAppUnits(contentBounds);
     metrics.mContentRect = contentBounds.ScaleToNearestPixels(
       aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
   }
 
   metrics.mScrollId = aScrollId;
 
   nsIPresShell* presShell = presContext->GetPresShell();
   if (TabChild *tc = GetTabChildFrom(presShell)) {
@@ -685,17 +677,21 @@ static void RecordFrameMetrics(nsIFrame*
   metrics.mResolution = gfxSize(presShell->GetXResolution(), presShell->GetYResolution());
 
   metrics.mDevPixelsPerCSSPixel =
     (float)nsPresContext::AppUnitsPerCSSPixel() / auPerDevPixel;
 
   metrics.mMayHaveTouchListeners = aMayHaveTouchListeners;
 
   if (nsIWidget* widget = aForFrame->GetNearestWidget()) {
-    widget->GetBounds(metrics.mCompositionBounds);
+    nsIntRect bounds;
+    widget->GetBounds(bounds);
+    // I don't know what units bounds are in, hence FromUnknownRect
+    metrics.mCompositionBounds = LayerIntRect::FromUnknownRect(
+      mozilla::gfx::IntRect(bounds.x, bounds.y, bounds.width, bounds.height));
   }
 
   metrics.mPresShellId = presShell->GetPresShellId();
 
   aRoot->SetFrameMetrics(metrics);
 }
 
 nsDisplayListBuilder::~nsDisplayListBuilder() {
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -787,18 +787,19 @@ RenderFrameParent::NotifyInputEvent(cons
     mPanZoomController->ReceiveInputEvent(aEvent, aOutEvent);
   }
 }
 
 void
 RenderFrameParent::NotifyDimensionsChanged(int width, int height)
 {
   if (mPanZoomController) {
+    // I don't know what units width/height are in, hence FromUnknownRect
     mPanZoomController->UpdateCompositionBounds(
-      nsIntRect(0, 0, width, height));
+      LayerIntRect::FromUnknownRect(gfx::IntRect(0, 0, width, height)));
   }
 }
 
 void
 RenderFrameParent::ActorDestroy(ActorDestroyReason why)
 {
   if (mLayersId != 0) {
     CompositorParent::DeallocateLayerTreeId(mLayersId);
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -2107,27 +2107,27 @@ AndroidBridge::IsTablet()
     bool ret = env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsTablet);
     if (jniFrame.CheckForException())
         return false;
 
     return ret;
 }
 
 void
-AndroidBridge::SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const gfx::Rect& aCssPageRect)
+AndroidBridge::SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const CSSRect& aCssPageRect)
 {
     AndroidGeckoLayerClient *client = mLayerClient;
     if (!client)
         return;
 
     client->SetFirstPaintViewport(aOffset, aZoom, aPageRect, aCssPageRect);
 }
 
 void
-AndroidBridge::SetPageRect(const gfx::Rect& aCssPageRect)
+AndroidBridge::SetPageRect(const CSSRect& aCssPageRect)
 {
     AndroidGeckoLayerClient *client = mLayerClient;
     if (!client)
         return;
 
     client->SetPageRect(aCssPageRect);
 }
 
@@ -2140,17 +2140,17 @@ AndroidBridge::SyncViewportInfo(const ns
     if (!client)
         return;
 
     client->SyncViewportInfo(aDisplayPort, aDisplayResolution, aLayersUpdated,
                              aScrollOffset, aScaleX, aScaleY, aFixedLayerMargins,
                              aOffset);
 }
 
-void AndroidBridge::SyncFrameMetrics(const gfx::Point& aScrollOffset, float aZoom, const gfx::Rect& aCssPageRect,
+void AndroidBridge::SyncFrameMetrics(const gfx::Point& aScrollOffset, float aZoom, const CSSRect& aCssPageRect,
                                      bool aLayersUpdated, const gfx::Rect& aDisplayPort, float aDisplayResolution,
                                      bool aIsFirstPaint, gfx::Margin& aFixedLayerMargins, gfx::Point& aOffset)
 {
     AndroidGeckoLayerClient *client = mLayerClient;
     if (!client)
         return;
 
     client->SyncFrameMetrics(aScrollOffset, aZoom, aCssPageRect,
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -366,22 +366,22 @@ public:
     already_AddRefed<nsIMobileMessageCallback> DequeueSmsRequest(uint32_t aRequestId);
 
     bool IsTablet();
 
     void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo);
     void EnableNetworkNotifications();
     void DisableNetworkNotifications();
 
-    void SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const gfx::Rect& aCssPageRect);
-    void SetPageRect(const gfx::Rect& aCssPageRect);
+    void SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const CSSRect& aCssPageRect);
+    void SetPageRect(const CSSRect& aCssPageRect);
     void SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated,
                           nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY,
                           gfx::Margin& aFixedLayerMargins, gfx::Point& aOffset);
-    void SyncFrameMetrics(const gfx::Point& aScrollOffset, float aZoom, const gfx::Rect& aCssPageRect,
+    void SyncFrameMetrics(const gfx::Point& aScrollOffset, float aZoom, const CSSRect& aCssPageRect,
                           bool aLayersUpdated, const gfx::Rect& aDisplayPort, float aDisplayResolution,
                           bool aIsFirstPaint, gfx::Margin& aFixedLayerMargins, gfx::Point& aOffset);
 
     void AddPluginView(jobject view, const gfxRect& rect, bool isFullScreen);
     void RemovePluginView(jobject view, bool isFullScreen);
 
     // These methods don't use a ScreenOrientation because it's an
     // enum and that would require including the header which requires
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -858,31 +858,31 @@ AndroidViewTransform::Init(jobject jobj)
 void
 AndroidProgressiveUpdateData::Init(jobject jobj)
 {
     NS_ABORT_IF_FALSE(wrapped_obj == nullptr, "Init called on non-null wrapped_obj!");
     wrapped_obj = jobj;
 }
 
 void
-AndroidGeckoLayerClient::SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const gfx::Rect& aCssPageRect)
+AndroidGeckoLayerClient::SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const CSSRect& aCssPageRect)
 {
     NS_ASSERTION(!isNull(), "SetFirstPaintViewport called on null layer client!");
     JNIEnv *env = GetJNIForThread();    // this is called on the compositor thread
     if (!env)
         return;
 
     AutoLocalJNIFrame jniFrame(env, 0);
     return env->CallVoidMethod(wrapped_obj, jSetFirstPaintViewport, (float)aOffset.x, (float)aOffset.y, aZoom,
                                (float)aPageRect.x, (float)aPageRect.y, (float)aPageRect.XMost(), (float)aPageRect.YMost(),
                                aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
 }
 
 void
-AndroidGeckoLayerClient::SetPageRect(const gfx::Rect& aCssPageRect)
+AndroidGeckoLayerClient::SetPageRect(const CSSRect& aCssPageRect)
 {
     NS_ASSERTION(!isNull(), "SetPageRect called on null layer client!");
     JNIEnv *env = GetJNIForThread();    // this is called on the compositor thread
     if (!env)
         return;
 
     AutoLocalJNIFrame jniFrame(env, 0);
     return env->CallVoidMethod(wrapped_obj, jSetPageRect,
@@ -917,17 +917,17 @@ AndroidGeckoLayerClient::SyncViewportInf
     aScaleX = aScaleY = viewTransform.GetScale(env);
     viewTransform.GetFixedLayerMargins(env, aFixedLayerMargins);
 
     aOffset.x = viewTransform.GetOffsetX(env);
     aOffset.y = viewTransform.GetOffsetY(env);
 }
 
 void
-AndroidGeckoLayerClient::SyncFrameMetrics(const gfx::Point& aScrollOffset, float aZoom, const gfx::Rect& aCssPageRect,
+AndroidGeckoLayerClient::SyncFrameMetrics(const gfx::Point& aScrollOffset, float aZoom, const CSSRect& aCssPageRect,
                                           bool aLayersUpdated, const gfx::Rect& aDisplayPort, float aDisplayResolution,
                                           bool aIsFirstPaint, gfx::Margin& aFixedLayerMargins, gfx::Point& aOffset)
 {
     NS_ASSERTION(!isNull(), "SyncFrameMetrics called on null layer client!");
     JNIEnv *env = GetJNIForThread();    // this is called on the compositor thread
     if (!env)
         return;
 
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -13,16 +13,17 @@
 #include "nsGeoPosition.h"
 #include "nsPoint.h"
 #include "nsRect.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/dom/Touch.h"
 #include "InputData.h"
+#include "Units.h"
 
 //#define FORCE_ALOG 1
 
 #ifndef ALOG
 #if defined(DEBUG) || defined(FORCE_ALOG)
 #define ALOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gecko" , ## args)
 #else
 #define ALOG(args...) ((void)0)
@@ -263,22 +264,22 @@ class AndroidGeckoLayerClient : public W
 public:
     static void InitGeckoLayerClientClass(JNIEnv *jEnv);
 
     void Init(jobject jobj);
 
     AndroidGeckoLayerClient() {}
     AndroidGeckoLayerClient(jobject jobj) { Init(jobj); }
 
-    void SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const gfx::Rect& aCssPageRect);
-    void SetPageRect(const gfx::Rect& aCssPageRect);
+    void SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const CSSRect& aCssPageRect);
+    void SetPageRect(const CSSRect& aCssPageRect);
     void SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated,
                           nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY,
                           gfx::Margin& aFixedLayerMargins, gfx::Point& aOffset);
-    void SyncFrameMetrics(const gfx::Point& aScrollOffset, float aZoom, const gfx::Rect& aCssPageRect,
+    void SyncFrameMetrics(const gfx::Point& aScrollOffset, float aZoom, const CSSRect& aCssPageRect,
                           bool aLayersUpdated, const gfx::Rect& aDisplayPort, float aDisplayResolution,
                           bool aIsFirstPaint, gfx::Margin& aFixedLayerMargins, gfx::Point& aOffset);
     bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const gfx::Rect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, gfx::Rect& aViewport, float& aScaleX, float& aScaleY);
     bool CreateFrame(AutoLocalJNIFrame *jniFrame, AndroidLayerRendererFrame& aFrame);
     bool ActivateProgram(AutoLocalJNIFrame *jniFrame);
     bool DeactivateProgram(AutoLocalJNIFrame *jniFrame);
     void GetDisplayPort(AutoLocalJNIFrame *jniFrame, bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort);
     void ContentDocumentChanged(AutoLocalJNIFrame *jniFrame);