Bug 980493 - Transition FrameMetrics::mScrollOffset to use a getter/setter. r=kats
authorBotond Ballo <botond@mozilla.com>
Thu, 13 Mar 2014 02:34:34 -0400
changeset 191535 509090e51f4c17dd12526b4c35a88cd7c82ec481
parent 191534 dd53db747a5e17ecf8e41951ec1771651893fbab
child 191536 27737607943da6fa3855e4f66f6262da341e441b
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs980493
milestone30.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 980493 - Transition FrameMetrics::mScrollOffset to use a getter/setter. r=kats
dom/ipc/TabChild.cpp
gfx/layers/FrameMetrics.h
gfx/layers/LayersLogging.cpp
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/client/ClientTiledThebesLayer.cpp
gfx/layers/client/SimpleTiledContentClient.cpp
gfx/layers/client/TiledContentClient.cpp
gfx/layers/composite/AsyncCompositionManager.cpp
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/ipc/AsyncPanZoomController.cpp
gfx/layers/ipc/Axis.cpp
gfx/tests/gtest/TestAsyncPanZoomController.cpp
layout/base/nsDisplayList.cpp
layout/ipc/RenderFrameParent.cpp
widget/android/AndroidBridge.cpp
widget/xpwidgets/APZCCallbackHelper.cpp
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -325,17 +325,17 @@ TabChild::InitializeRootMetrics()
   mLastRootMetrics.mDevPixelsPerCSSPixel = mWidget->GetDefaultScale();
   // We use ScreenToLayerScale(1) below in order to turn the
   // async zoom amount into the gecko zoom amount.
   mLastRootMetrics.mCumulativeResolution =
     mLastRootMetrics.mZoom / mLastRootMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
   // This is the root layer, so the cumulative resolution is the same
   // as the resolution.
   mLastRootMetrics.mResolution = mLastRootMetrics.mCumulativeResolution / LayoutDeviceToParentLayerScale(1);
-  mLastRootMetrics.mScrollOffset = CSSPoint(0, 0);
+  mLastRootMetrics.SetScrollOffset(CSSPoint(0, 0));
 }
 
 bool
 TabChild::HasValidInnerSize()
 {
   return (mInnerSize.width != 0) && (mInnerSize.height != 0);
 }
 
@@ -1521,18 +1521,18 @@ TabChild::ProcessUpdateFrame(const Frame
     FrameMetrics newMetrics = aFrameMetrics;
     APZCCallbackHelper::UpdateRootFrame(utils, newMetrics);
 
     CSSRect cssCompositedRect = CSSRect(newMetrics.CalculateCompositedRectInCssPixels());
     // The BrowserElementScrolling helper must know about these updated metrics
     // for other functions it performs, such as double tap handling.
     // Note, %f must not be used because it is locale specific!
     nsCString data;
-    data.AppendPrintf("{ \"x\" : %d", NS_lround(newMetrics.mScrollOffset.x));
-    data.AppendPrintf(", \"y\" : %d", NS_lround(newMetrics.mScrollOffset.y));
+    data.AppendPrintf("{ \"x\" : %d", NS_lround(newMetrics.GetScrollOffset().x));
+    data.AppendPrintf(", \"y\" : %d", NS_lround(newMetrics.GetScrollOffset().y));
     data.AppendLiteral(", \"viewport\" : ");
         data.AppendLiteral("{ \"width\" : ");
         data.AppendFloat(newMetrics.mViewport.width);
         data.AppendLiteral(", \"height\" : ");
         data.AppendFloat(newMetrics.mViewport.height);
         data.AppendLiteral(" }");
     data.AppendLiteral(", \"cssPageRect\" : ");
         data.AppendLiteral("{ \"x\" : ");
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -66,51 +66,51 @@ public:
   static const ViewID START_SCROLL_ID = 2;  // This is the ID that scrolling subframes
                                         // will begin at.
 
   FrameMetrics()
     : mCompositionBounds(0, 0, 0, 0)
     , mDisplayPort(0, 0, 0, 0)
     , mCriticalDisplayPort(0, 0, 0, 0)
     , mViewport(0, 0, 0, 0)
-    , mScrollOffset(0, 0)
     , mScrollId(NULL_SCROLL_ID)
     , mScrollableRect(0, 0, 0, 0)
     , mResolution(1)
     , mCumulativeResolution(1)
     , mZoom(1)
     , mTransformScale(1)
     , mDevPixelsPerCSSPixel(1)
     , mPresShellId(-1)
     , mMayHaveTouchListeners(false)
     , mIsRoot(false)
     , mHasScrollgrab(false)
+    , mScrollOffset(0, 0)
     , mUpdateScrollOffset(false)
     , mScrollGeneration(0)
   {}
 
   // Default copy ctor and operator= are fine
 
   bool operator==(const FrameMetrics& aOther) const
   {
     // mContentDescription is not compared on purpose as it's only used
     // for debugging.
     return mCompositionBounds.IsEqualEdges(aOther.mCompositionBounds) &&
            mDisplayPort.IsEqualEdges(aOther.mDisplayPort) &&
            mCriticalDisplayPort.IsEqualEdges(aOther.mCriticalDisplayPort) &&
            mViewport.IsEqualEdges(aOther.mViewport) &&
-           mScrollOffset == aOther.mScrollOffset &&
            mScrollId == aOther.mScrollId &&
            mScrollableRect.IsEqualEdges(aOther.mScrollableRect) &&
            mResolution == aOther.mResolution &&
            mCumulativeResolution == aOther.mCumulativeResolution &&
            mDevPixelsPerCSSPixel == aOther.mDevPixelsPerCSSPixel &&
            mMayHaveTouchListeners == aOther.mMayHaveTouchListeners &&
            mPresShellId == aOther.mPresShellId &&
            mIsRoot == aOther.mIsRoot &&
+           mScrollOffset == aOther.mScrollOffset &&
            mHasScrollgrab == aOther.mHasScrollgrab &&
            mUpdateScrollOffset == aOther.mUpdateScrollOffset;
   }
   bool operator!=(const FrameMetrics& aOther) const
   {
     return !operator==(aOther);
   }
 
@@ -134,17 +134,17 @@ public:
 
   CSSToLayerScale LayersPixelsPerCSSPixel() const
   {
     return mCumulativeResolution * mDevPixelsPerCSSPixel;
   }
 
   LayerPoint GetScrollOffsetInLayerPixels() const
   {
-    return mScrollOffset * LayersPixelsPerCSSPixel();
+    return GetScrollOffset() * LayersPixelsPerCSSPixel();
   }
 
   LayoutDeviceToParentLayerScale GetParentResolution() const
   {
     return mCumulativeResolution / mResolution;
   }
 
   // Ensure the scrollableRect is at least as big as the compositionBounds
@@ -189,16 +189,21 @@ public:
     return mZoom * mTransformScale;
   }
 
   CSSIntRect CalculateCompositedRectInCssPixels() const
   {
     return gfx::RoundedIn(mCompositionBounds / GetZoomToParent());
   }
 
+  void ScrollBy(const CSSPoint& aPoint)
+  {
+    mScrollOffset += aPoint;
+  }
+
   // ---------------------------------------------------------------------------
   // The following metrics are all in widget space/device pixels.
   //
 
   // This is the area within the widget that we're compositing to. It is relative
   // to the layer tree origin.
   //
   // This is useful because, on mobile, the viewport and composition dimensions
@@ -253,33 +258,16 @@ public:
   // method layout uses to scroll content.
   //
   // This is mainly useful on the root layer, however nested iframes can have
   // their own viewport, which will just be the size of the window of the
   // iframe. For layers that don't correspond to a document, this metric is
   // meaningless and invalid.
   CSSRect mViewport;
 
-  // The position of the top-left of the CSS viewport, relative to the document
-  // (or the document relative to the viewport, if that helps understand it).
-  //
-  // Thus it is relative to the document. It is in the same coordinate space as
-  // |mScrollableRect|, but a different coordinate space than |mViewport| and
-  // |mDisplayPort|.
-  //
-  // It is required that the rect:
-  // { x = mScrollOffset.x, y = mScrollOffset.y,
-  //   width = mCompositionBounds.x / mResolution.scale,
-  //   height = mCompositionBounds.y / mResolution.scale }
-  // Be within |mScrollableRect|.
-  //
-  // This is valid for any layer, but is always relative to this frame and
-  // not any parents, regardless of parent transforms.
-  CSSPoint mScrollOffset;
-
   // A unique ID assigned to each scrollable frame.
   ViewID mScrollId;
 
   // The scrollable bounds of a frame. This is determined by reflow.
   // Ordinarily the x and y will be 0 and the width and height will be the
   // size of the element being scrolled. However for RTL pages or elements
   // the x value may be negative.
   //
@@ -335,16 +323,26 @@ public:
 
   // Whether or not this is the root scroll frame for the root content document.
   bool mIsRoot;
 
   // Whether or not this frame is for an element marked 'scrollgrab'.
   bool mHasScrollgrab;
 
 public:
+  void SetScrollOffset(const CSSPoint& aScrollOffset)
+  {
+    mScrollOffset = aScrollOffset;
+  }
+
+  const CSSPoint& GetScrollOffset() const
+  {
+    return mScrollOffset;
+  }
+
   void SetScrollOffsetUpdated(uint32_t aScrollGeneration)
   {
     mUpdateScrollOffset = true;
     mScrollGeneration = aScrollGeneration;
   }
 
   bool GetScrollOffsetUpdated() const
   {
@@ -365,16 +363,33 @@ public:
   {
     mContentDescription = aContentDescription;
   }
 
 private:
   // New fields from now on should be made private and old fields should
   // be refactored to be private.
 
+  // The position of the top-left of the CSS viewport, relative to the document
+  // (or the document relative to the viewport, if that helps understand it).
+  //
+  // Thus it is relative to the document. It is in the same coordinate space as
+  // |mScrollableRect|, but a different coordinate space than |mViewport| and
+  // |mDisplayPort|.
+  //
+  // It is required that the rect:
+  // { x = mScrollOffset.x, y = mScrollOffset.y,
+  //   width = mCompositionBounds.x / mResolution.scale,
+  //   height = mCompositionBounds.y / mResolution.scale }
+  // Be within |mScrollableRect|.
+  //
+  // This is valid for any layer, but is always relative to this frame and
+  // not any parents, regardless of parent transforms.
+  CSSPoint mScrollOffset;
+
   // Whether mScrollOffset was updated by something other than the APZ code, and
   // if the APZC receiving this metrics should update its local copy.
   bool mUpdateScrollOffset;
   // The scroll generation counter used to acknowledge the scroll offset update.
   uint32_t mScrollGeneration;
 
   // A description of the content element corresponding to this frame.
   // This is empty unless the apz.printtree pref is turned on.
--- a/gfx/layers/LayersLogging.cpp
+++ b/gfx/layers/LayersLogging.cpp
@@ -113,17 +113,17 @@ AppendToString(nsACString& s, const nsIn
 }
 
 nsACString&
 AppendToString(nsACString& s, const FrameMetrics& m,
                const char* pfx, const char* sfx)
 {
   s += pfx;
   AppendToString(s, m.mViewport, "{ viewport=");
-  AppendToString(s, m.mScrollOffset, " viewportScroll=");
+  AppendToString(s, m.GetScrollOffset(), " viewportScroll=");
   AppendToString(s, m.mDisplayPort, " displayport=");
   AppendToString(s, m.mScrollableRect, " scrollableRect=");
   AppendToString(s, m.mScrollId, " scrollId=", " }");
   return s += sfx;
 }
 
 nsACString&
 AppendToString(nsACString& s, const IntSize& size,
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -544,17 +544,17 @@ ClientLayerManager::ProgressiveUpdateCal
     const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
 
     // This is derived from the code in
     // gfx/layers/ipc/CompositorParent.cpp::TransformShadowTree.
     CSSToLayerScale paintScale = metrics.LayersPixelsPerCSSPixel();
     const CSSRect& metricsDisplayPort =
       (aDrawingCritical && !metrics.mCriticalDisplayPort.IsEmpty()) ?
         metrics.mCriticalDisplayPort : metrics.mDisplayPort;
-    LayerRect displayPort = (metricsDisplayPort + metrics.mScrollOffset) * paintScale;
+    LayerRect displayPort = (metricsDisplayPort + metrics.GetScrollOffset()) * paintScale;
 
     return AndroidBridge::Bridge()->ProgressiveUpdateCallback(
       aHasPendingNewThebesContent, displayPort, paintScale.scale, aDrawingCritical,
       aCompositionBounds, aZoom);
   }
 #endif
 
   return false;
--- a/gfx/layers/client/ClientTiledThebesLayer.cpp
+++ b/gfx/layers/client/ClientTiledThebesLayer.cpp
@@ -124,17 +124,17 @@ ClientTiledThebesLayer::BeginPaint()
 
   // Calculate the scroll offset since the last transaction, and the
   // composition bounds.
   mPaintData.mCompositionBounds.SetEmpty();
   mPaintData.mScrollOffset.MoveTo(0, 0);
   Layer* primaryScrollable = ClientManager()->GetPrimaryScrollableLayer();
   if (primaryScrollable) {
     const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
-    mPaintData.mScrollOffset = metrics.mScrollOffset * metrics.mZoom;
+    mPaintData.mScrollOffset = metrics.GetScrollOffset() * metrics.mZoom;
     mPaintData.mCompositionBounds =
       ApplyParentLayerToLayoutTransform(mPaintData.mTransformParentLayerToLayout,
                                         ParentLayerRect(metrics.mCompositionBounds));
   }
 }
 
 void
 ClientTiledThebesLayer::EndPaint(bool aFinish)
--- a/gfx/layers/client/SimpleTiledContentClient.cpp
+++ b/gfx/layers/client/SimpleTiledContentClient.cpp
@@ -336,17 +336,17 @@ SimpleClientTiledThebesLayer::BeginPaint
 
   // Calculate the scroll offset since the last transaction, and the
   // composition bounds.
   mPaintData.mCompositionBounds.SetEmpty();
   mPaintData.mScrollOffset.MoveTo(0, 0);
   Layer* primaryScrollable = ClientManager()->GetPrimaryScrollableLayer();
   if (primaryScrollable) {
     const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
-    mPaintData.mScrollOffset = metrics.mScrollOffset * metrics.mZoom;
+    mPaintData.mScrollOffset = metrics.GetScrollOffset() * metrics.mZoom;
     mPaintData.mCompositionBounds =
       ApplyParentLayerToLayoutTransform(mPaintData.mTransformParentLayerToLayout,
                                         ParentLayerRect(metrics.mCompositionBounds));
   }
 }
 
 void
 SimpleClientTiledThebesLayer::EndPaint(bool aFinish)
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -181,18 +181,18 @@ SharedFrameMetricsHelper::UpdateFromComp
   if (!FuzzyEquals(compositorMetrics.mZoom.scale, contentMetrics.mZoom.scale)) {
     return true;
   }
 
   // Never abort drawing if we can't be sure we've sent a more recent
   // display-port. If we abort updating when we shouldn't, we can end up
   // with blank regions on the screen and we open up the risk of entering
   // an endless updating cycle.
-  if (fabsf(contentMetrics.mScrollOffset.x - compositorMetrics.mScrollOffset.x) <= 2 &&
-      fabsf(contentMetrics.mScrollOffset.y - compositorMetrics.mScrollOffset.y) <= 2 &&
+  if (fabsf(contentMetrics.GetScrollOffset().x - compositorMetrics.GetScrollOffset().x) <= 2 &&
+      fabsf(contentMetrics.GetScrollOffset().y - compositorMetrics.GetScrollOffset().y) <= 2 &&
       fabsf(contentMetrics.mDisplayPort.x - compositorMetrics.mDisplayPort.x) <= 2 &&
       fabsf(contentMetrics.mDisplayPort.y - compositorMetrics.mDisplayPort.y) <= 2 &&
       fabsf(contentMetrics.mDisplayPort.width - compositorMetrics.mDisplayPort.width) <= 2 &&
       fabsf(contentMetrics.mDisplayPort.height - compositorMetrics.mDisplayPort.height)) {
     return false;
   }
 
   // When not a low precision pass and the page is in danger of checker boarding
@@ -236,17 +236,17 @@ SharedFrameMetricsHelper::FindFallbackCo
   aZoom = contentMetrics->GetZoomToParent();  // TODO(botond): double-check this
   return;
 }
 
 bool
 SharedFrameMetricsHelper::AboutToCheckerboard(const FrameMetrics& aContentMetrics,
                                               const FrameMetrics& aCompositorMetrics)
 {
-  return !aContentMetrics.mDisplayPort.Contains(CSSRect(aCompositorMetrics.CalculateCompositedRectInCssPixels()) - aCompositorMetrics.mScrollOffset);
+  return !aContentMetrics.mDisplayPort.Contains(CSSRect(aCompositorMetrics.CalculateCompositedRectInCssPixels()) - aCompositorMetrics.GetScrollOffset());
 }
 
 ClientTiledLayerBuffer::ClientTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer,
                                              CompositableClient* aCompositableClient,
                                              ClientLayerManager* aManager,
                                              SharedFrameMetricsHelper* aHelper)
   : mThebesLayer(aThebesLayer)
   , mCompositableClient(aCompositableClient)
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -657,17 +657,17 @@ AsyncCompositionManager::TransformScroll
   gfx3DMatrix currentTransform;
   To3DMatrix(aLayer->GetTransform(), currentTransform);
   Matrix4x4 oldTransform = aLayer->GetTransform();
 
   gfx3DMatrix treeTransform;
 
   CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel();
 
-  LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.mScrollOffset * geckoZoom);
+  LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.GetScrollOffset() * geckoZoom);
 
   if (mIsFirstPaint) {
     mContentRect = metrics.mScrollableRect;
     SetFirstPaintViewport(scrollOffsetLayerPixels,
                           geckoZoom,
                           mContentRect);
     mIsFirstPaint = false;
   } else if (!metrics.mScrollableRect.IsEqualEdges(mContentRect)) {
@@ -689,17 +689,17 @@ AsyncCompositionManager::TransformScroll
   ScreenPoint offset(0, 0);
 
   // Ideally we would initialize userZoom to AsyncPanZoomController::CalculateResolution(metrics)
   // but this causes a reftest-ipc test to fail (see bug 883646 comment 27). The reason for this
   // appears to be that metrics.mZoom is poorly initialized in some scenarios. In these scenarios,
   // however, we can assume there is no async zooming in progress and so the following statement
   // works fine.
   CSSToScreenScale userZoom(metrics.mDevPixelsPerCSSPixel * metrics.mCumulativeResolution * LayerToScreenScale(1));
-  ScreenPoint userScroll = metrics.mScrollOffset * userZoom;
+  ScreenPoint userScroll = metrics.GetScrollOffset() * userZoom;
   SyncViewportInfo(displayPort, geckoZoom, mLayersUpdated,
                    userScroll, userZoom, fixedLayerMargins,
                    offset);
   mLayersUpdated = false;
 
   // Apply the render offset
   mLayerManager->GetCompositor()->SetScreenRenderOffset(offset);
 
@@ -708,17 +708,17 @@ AsyncCompositionManager::TransformScroll
   // determine the scroll offset used by Gecko from the frame metrics of the
   // primary scrollable layer. We compare this to the user zoom and scroll
   // offset in the view transform we obtained from Java in order to compute the
   // transformation we need to apply.
   LayerToScreenScale zoomAdjust = userZoom / geckoZoom;
 
   LayerPoint geckoScroll(0, 0);
   if (metrics.IsScrollable()) {
-    geckoScroll = metrics.mScrollOffset * geckoZoom;
+    geckoScroll = metrics.GetScrollOffset() * geckoZoom;
   }
 
   LayerPoint translation = (userScroll / zoomAdjust) - geckoScroll;
   treeTransform = gfx3DMatrix(ViewTransform(-translation,
                                             userZoom
                                           / metrics.mDevPixelsPerCSSPixel
                                           / metrics.GetParentResolution()));
 
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -681,18 +681,18 @@ LayerManagerComposite::ComputeRenderInte
     // AsyncCompositionManager::TransformScrollableLayer
     const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
     gfx3DMatrix transform;
     gfx::To3DMatrix(primaryScrollable->GetEffectiveTransform(), transform);
     transform.ScalePost(metrics.mResolution.scale, metrics.mResolution.scale, 1);
 
     // Clip the screen rect to the document bounds
     gfxRect documentBounds =
-      transform.TransformBounds(gfxRect(metrics.mScrollableRect.x - metrics.mScrollOffset.x,
-                                        metrics.mScrollableRect.y - metrics.mScrollOffset.y,
+      transform.TransformBounds(gfxRect(metrics.mScrollableRect.x - metrics.GetScrollOffset().x,
+                                        metrics.mScrollableRect.y - metrics.GetScrollOffset().y,
                                         metrics.mScrollableRect.width,
                                         metrics.mScrollableRect.height));
     documentBounds.RoundOut();
     screenRect = screenRect.Intersect(nsIntRect(documentBounds.x, documentBounds.y,
                                                 documentBounds.width, documentBounds.height));
 
     // If the screen rect is empty, the user has scrolled entirely into
     // over-scroll and so we can be considered to have full integrity.
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -1281,20 +1281,20 @@ bool FlingAnimation::Sample(FrameMetrics
   ScreenPoint velocity(mApzc.mX.GetVelocity(), mApzc.mY.GetVelocity());
 
   ScreenPoint offset = velocity * aDelta.ToMilliseconds();
 
   // Inversely scale the offset by the resolution (when you're zoomed further in,
   // the same swipe should move you a shorter distance).
   CSSPoint cssOffset = offset / aFrameMetrics.mZoom;
   CSSPoint overscroll;
-  aFrameMetrics.mScrollOffset += CSSPoint(
+  aFrameMetrics.ScrollBy(CSSPoint(
     mApzc.mX.AdjustDisplacement(cssOffset.x, overscroll.x),
     mApzc.mY.AdjustDisplacement(cssOffset.y, overscroll.y)
-  );
+  ));
 
   // If the fling has caused us to reach the end of our scroll range, hand
   // off the fling to the next APZC in the overscroll handoff chain.
   if (!IsZero(overscroll)) {
     // We may have reached the end of the scroll range along one axis but
     // not the other. In such a case we only want to hand off the relevant
     // component of the fling.
     if (FuzzyEqualsMultiplicative(overscroll.x, 0.0f)) {
@@ -1346,27 +1346,27 @@ void AsyncPanZoomController::SetComposit
   mCompositorParent = aCompositorParent;
 }
 
 void AsyncPanZoomController::SetCrossProcessCompositorParent(PCompositorParent* aCrossProcessCompositorParent) {
   mCrossProcessCompositorParent = aCrossProcessCompositorParent;
 }
 
 void AsyncPanZoomController::ScrollBy(const CSSPoint& aOffset) {
-  mFrameMetrics.mScrollOffset += aOffset;
+  mFrameMetrics.ScrollBy(aOffset);
 }
 
 void AsyncPanZoomController::ScaleWithFocus(float aScale,
                                             const CSSPoint& aFocus) {
   mFrameMetrics.mZoom.scale *= aScale;
   // We want to adjust the scroll offset such that the CSS point represented by aFocus remains
   // at the same position on the screen before and after the change in zoom. The below code
   // accomplishes this; see https://bugzilla.mozilla.org/show_bug.cgi?id=923431#c6 for an
   // in-depth explanation of how.
-  mFrameMetrics.mScrollOffset = (mFrameMetrics.mScrollOffset + aFocus) - (aFocus / aScale);
+  mFrameMetrics.SetScrollOffset((mFrameMetrics.GetScrollOffset() + aFocus) - (aFocus / aScale));
 }
 
 /**
  * Enlarges the displayport along both axes based on the velocity.
  */
 static CSSSize
 CalculateDisplayPortSize(const CSSRect& aCompositionBounds,
                          const CSSPoint& aVelocity)
@@ -1410,17 +1410,17 @@ RedistributeDisplayPortExcess(CSSSize& a
 /* static */
 const CSSRect AsyncPanZoomController::CalculatePendingDisplayPort(
   const FrameMetrics& aFrameMetrics,
   const ScreenPoint& aVelocity,
   double aEstimatedPaintDuration)
 {
   CSSRect compositionBounds(aFrameMetrics.CalculateCompositedRectInCssPixels());
   CSSPoint velocity = aVelocity / aFrameMetrics.mZoom;
-  CSSPoint scrollOffset = aFrameMetrics.mScrollOffset;
+  CSSPoint scrollOffset = aFrameMetrics.GetScrollOffset();
   CSSRect scrollableRect = aFrameMetrics.GetExpandedScrollableRect();
 
   // Calculate the displayport size based on how fast we're moving along each axis.
   CSSSize displayPortSize = CalculateDisplayPortSize(compositionBounds, velocity);
 
   if (gEnlargeDisplayPortWhenClipped) {
     RedistributeDisplayPortExcess(displayPortSize, compositionBounds, scrollableRect);
   }
@@ -1467,28 +1467,28 @@ void AsyncPanZoomController::RequestCont
   aFrameMetrics.mDisplayPort =
     CalculatePendingDisplayPort(aFrameMetrics,
                                 GetVelocityVector(),
                                 mPaintThrottler.AverageDuration().ToSeconds());
 
   // If we're trying to paint what we already think is painted, discard this
   // request since it's a pointless paint.
   CSSRect oldDisplayPort = mLastPaintRequestMetrics.mDisplayPort
-                         + mLastPaintRequestMetrics.mScrollOffset;
+                         + mLastPaintRequestMetrics.GetScrollOffset();
   CSSRect newDisplayPort = aFrameMetrics.mDisplayPort
-                         + aFrameMetrics.mScrollOffset;
+                         + aFrameMetrics.GetScrollOffset();
 
   if (fabsf(oldDisplayPort.x - newDisplayPort.x) < EPSILON &&
       fabsf(oldDisplayPort.y - newDisplayPort.y) < EPSILON &&
       fabsf(oldDisplayPort.width - newDisplayPort.width) < EPSILON &&
       fabsf(oldDisplayPort.height - newDisplayPort.height) < EPSILON &&
-      fabsf(mLastPaintRequestMetrics.mScrollOffset.x -
-            aFrameMetrics.mScrollOffset.x) < EPSILON &&
-      fabsf(mLastPaintRequestMetrics.mScrollOffset.y -
-            aFrameMetrics.mScrollOffset.y) < EPSILON &&
+      fabsf(mLastPaintRequestMetrics.GetScrollOffset().x -
+            aFrameMetrics.GetScrollOffset().x) < EPSILON &&
+      fabsf(mLastPaintRequestMetrics.GetScrollOffset().y -
+            aFrameMetrics.GetScrollOffset().y) < EPSILON &&
       aFrameMetrics.mZoom == mLastPaintRequestMetrics.mZoom &&
       fabsf(aFrameMetrics.mViewport.width - mLastPaintRequestMetrics.mViewport.width) < EPSILON &&
       fabsf(aFrameMetrics.mViewport.height - mLastPaintRequestMetrics.mViewport.height) < EPSILON) {
     return;
   }
 
   SendAsyncScrollEvent();
   mPaintThrottler.PostTask(
@@ -1504,17 +1504,17 @@ void AsyncPanZoomController::RequestCont
 
 void
 AsyncPanZoomController::DispatchRepaintRequest(const FrameMetrics& aFrameMetrics) {
   nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
   if (controller) {
     APZC_LOG_FM(aFrameMetrics, "%p requesting content repaint", this);
 
     LogRendertraceRect(GetGuid(), "requested displayport", "yellow",
-        aFrameMetrics.mDisplayPort + aFrameMetrics.mScrollOffset);
+        aFrameMetrics.mDisplayPort + aFrameMetrics.GetScrollOffset());
 
     controller->RequestContentRepaint(aFrameMetrics);
     mLastDispatchedPaintMetrics = aFrameMetrics;
   }
 }
 
 void
 AsyncPanZoomController::FireAsyncScrollOnTimeout()
@@ -1528,34 +1528,34 @@ AsyncPanZoomController::FireAsyncScrollO
 
 bool ZoomAnimation::Sample(FrameMetrics& aFrameMetrics,
                            const TimeDuration& aDelta) {
   mDuration += aDelta;
   double animPosition = mDuration / ZOOM_TO_DURATION;
 
   if (animPosition >= 1.0) {
     aFrameMetrics.mZoom = mEndZoom;
-    aFrameMetrics.mScrollOffset = mEndOffset;
+    aFrameMetrics.SetScrollOffset(mEndOffset);
     return false;
   }
 
   // Sample the zoom at the current time point.  The sampled zoom
   // will affect the final computed resolution.
   double sampledPosition = gComputedTimingFunction->GetValue(animPosition);
 
   // We scale the scrollOffset linearly with sampledPosition, so the zoom
   // needs to scale inversely to match.
   aFrameMetrics.mZoom = CSSToScreenScale(1 /
     (sampledPosition / mEndZoom.scale +
     (1 - sampledPosition) / mStartZoom.scale));
 
-  aFrameMetrics.mScrollOffset = CSSPoint::FromUnknownPoint(gfx::Point(
+  aFrameMetrics.SetScrollOffset(CSSPoint::FromUnknownPoint(gfx::Point(
     mEndOffset.x * sampledPosition + mStartOffset.x * (1 - sampledPosition),
     mEndOffset.y * sampledPosition + mStartOffset.y * (1 - sampledPosition)
-  ));
+  )));
 
   return true;
 }
 
 bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime)
 {
   if (mAnimation) {
     if (mAnimation->Sample(mFrameMetrics, aSampleTime - mLastSampleTime)) {
@@ -1586,24 +1586,24 @@ bool AsyncPanZoomController::SampleConte
   // responsibility to schedule a composite.
   bool requestAnimationFrame = false;
 
   {
     ReentrantMonitorAutoEnter lock(mMonitor);
 
     requestAnimationFrame = UpdateAnimation(aSampleTime);
 
-    aScrollOffset = mFrameMetrics.mScrollOffset * mFrameMetrics.mZoom;
+    aScrollOffset = mFrameMetrics.GetScrollOffset() * mFrameMetrics.mZoom;
     *aNewTransform = GetCurrentAsyncTransform();
 
     LogRendertraceRect(GetGuid(), "viewport", "red",
-      CSSRect(mFrameMetrics.mScrollOffset,
+      CSSRect(mFrameMetrics.GetScrollOffset(),
               ParentLayerSize(mFrameMetrics.mCompositionBounds.Size()) / mFrameMetrics.GetZoomToParent()));
 
-    mCurrentAsyncScrollOffset = mFrameMetrics.mScrollOffset;
+    mCurrentAsyncScrollOffset = mFrameMetrics.GetScrollOffset();
   }
 
   // Execute tasks queued up by mAnimation's Sample() (called by
   // UpdateAnimation()) for execution after mMonitor has been released.
   if (mAnimation) {
     mAnimation->ExecuteDeferredTasks();
   }
 
@@ -1637,20 +1637,20 @@ bool AsyncPanZoomController::SampleConte
   return requestAnimationFrame;
 }
 
 ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() {
   ReentrantMonitorAutoEnter lock(mMonitor);
 
   CSSPoint lastPaintScrollOffset;
   if (mLastContentPaintMetrics.IsScrollable()) {
-    lastPaintScrollOffset = mLastContentPaintMetrics.mScrollOffset;
+    lastPaintScrollOffset = mLastContentPaintMetrics.GetScrollOffset();
   }
 
-  CSSPoint currentScrollOffset = mFrameMetrics.mScrollOffset +
+  CSSPoint currentScrollOffset = mFrameMetrics.GetScrollOffset() +
     mTestAsyncScrollOffset;
 
   // If checkerboarding has been disallowed, clamp the scroll position to stay
   // within rendered content.
   if (!gAllowCheckerboarding &&
       !mLastContentPaintMetrics.mDisplayPort.IsEmpty()) {
     CSSRect compositedRect(mLastContentPaintMetrics.CalculateCompositedRectInCssPixels());
     CSSPoint maxScrollOffset = lastPaintScrollOffset +
@@ -1679,17 +1679,17 @@ gfx3DMatrix AsyncPanZoomController::GetN
   ReentrantMonitorAutoEnter lock(mMonitor);
   return gfx3DMatrix::ScalingMatrix(mLastContentPaintMetrics.mResolution.scale,
                                     mLastContentPaintMetrics.mResolution.scale,
                                     1.0f);
 }
 
 gfx3DMatrix AsyncPanZoomController::GetTransformToLastDispatchedPaint() {
   ReentrantMonitorAutoEnter lock(mMonitor);
-  LayerPoint scrollChange = (mLastContentPaintMetrics.mScrollOffset - mLastDispatchedPaintMetrics.mScrollOffset)
+  LayerPoint scrollChange = (mLastContentPaintMetrics.GetScrollOffset() - mLastDispatchedPaintMetrics.GetScrollOffset())
                           * mLastContentPaintMetrics.LayersPixelsPerCSSPixel();
   float zoomChange = mLastContentPaintMetrics.mZoom.scale / mLastDispatchedPaintMetrics.mZoom.scale;
   return gfx3DMatrix::Translation(scrollChange.x, scrollChange.y, 0) *
          gfx3DMatrix::ScalingMatrix(zoomChange, zoomChange, 1);
 }
 
 void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint) {
   ReentrantMonitorAutoEnter lock(mMonitor);
@@ -1698,17 +1698,17 @@ void AsyncPanZoomController::NotifyLayer
   UpdateTransformScale();
 
   bool isDefault = mFrameMetrics.IsDefault();
   mFrameMetrics.mMayHaveTouchListeners = aLayerMetrics.mMayHaveTouchListeners;
   APZC_LOG_FM(aLayerMetrics, "%p got a NotifyLayersUpdated with aIsFirstPaint=%d", this, aIsFirstPaint);
 
   LogRendertraceRect(GetGuid(), "page", "brown", aLayerMetrics.mScrollableRect);
   LogRendertraceRect(GetGuid(), "painted displayport", "green",
-    aLayerMetrics.mDisplayPort + aLayerMetrics.mScrollOffset);
+    aLayerMetrics.mDisplayPort + aLayerMetrics.GetScrollOffset());
 
   mPaintThrottler.TaskComplete(GetFrameTime());
   bool needContentRepaint = false;
   if (aLayerMetrics.mCompositionBounds.width == mFrameMetrics.mCompositionBounds.width &&
       aLayerMetrics.mCompositionBounds.height == mFrameMetrics.mCompositionBounds.height) {
     // Remote content has sync'd up to the composition geometry
     // change, so we can accept the viewport it's calculated.
     if (mFrameMetrics.mViewport.width != aLayerMetrics.mViewport.width ||
@@ -1755,17 +1755,17 @@ void AsyncPanZoomController::NotifyLayer
 
     // If the layers update was not triggered by our own repaint request, then
     // we want to take the new scroll offset.
     if (aLayerMetrics.GetScrollOffsetUpdated()) {
       APZC_LOG("%p updating scroll offset from (%f, %f) to (%f, %f)\n", this,
         mFrameMetrics.mScrollOffset.x, mFrameMetrics.mScrollOffset.y,
         aLayerMetrics.mScrollOffset.x, aLayerMetrics.mScrollOffset.y);
 
-      mFrameMetrics.mScrollOffset = aLayerMetrics.mScrollOffset;
+      mFrameMetrics.SetScrollOffset(aLayerMetrics.GetScrollOffset());
 
       // Because of the scroll offset update, any inflight paint requests are
       // going to be ignored by layout, and so mLastDispatchedPaintMetrics
       // becomes incorrect for the purposes of calculating the LD transform. To
       // correct this we need to update mLastDispatchedPaintMetrics to be the
       // last thing we know was painted by Gecko.
       mLastDispatchedPaintMetrics = aLayerMetrics;
     }
@@ -1802,17 +1802,17 @@ void AsyncPanZoomController::ZoomToRect(
 
   SetState(ANIMATING_ZOOM);
 
   {
     ReentrantMonitorAutoEnter lock(mMonitor);
 
     ParentLayerIntRect compositionBounds = mFrameMetrics.mCompositionBounds;
     CSSRect cssPageRect = mFrameMetrics.mScrollableRect;
-    CSSPoint scrollOffset = mFrameMetrics.mScrollOffset;
+    CSSPoint scrollOffset = mFrameMetrics.GetScrollOffset();
     CSSToParentLayerScale currentZoom = mFrameMetrics.GetZoomToParent();
     CSSToParentLayerScale targetZoom;
 
     // 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.
@@ -1862,26 +1862,26 @@ void AsyncPanZoomController::ZoomToRect(
       aRect.y = cssPageRect.height - rectAfterZoom.height;
       aRect.y = aRect.y > 0 ? aRect.y : 0;
     }
     if (aRect.x + rectAfterZoom.width > cssPageRect.width) {
       aRect.x = cssPageRect.width - rectAfterZoom.width;
       aRect.x = aRect.x > 0 ? aRect.x : 0;
     }
 
-    endZoomToMetrics.mScrollOffset = aRect.TopLeft();
+    endZoomToMetrics.SetScrollOffset(aRect.TopLeft());
     endZoomToMetrics.mDisplayPort =
       CalculatePendingDisplayPort(endZoomToMetrics,
                                   ScreenPoint(0,0),
                                   0);
 
     StartAnimation(new ZoomAnimation(
-        mFrameMetrics.mScrollOffset,
+        mFrameMetrics.GetScrollOffset(),
         mFrameMetrics.mZoom,
-        endZoomToMetrics.mScrollOffset,
+        endZoomToMetrics.GetScrollOffset(),
         endZoomToMetrics.mZoom));
 
     // Schedule a repaint now, so the new displayport will be painted before the
     // animation finishes.
     RequestContentRepaint(endZoomToMetrics);
   }
 }
 
--- a/gfx/layers/ipc/Axis.cpp
+++ b/gfx/layers/ipc/Axis.cpp
@@ -262,17 +262,17 @@ float Axis::GetCompositionEnd() {
   return GetOrigin() + GetCompositionLength();
 }
 
 float Axis::GetPageEnd() {
   return GetPageStart() + GetPageLength();
 }
 
 float Axis::GetOrigin() {
-  CSSPoint origin = mAsyncPanZoomController->GetFrameMetrics().mScrollOffset;
+  CSSPoint origin = mAsyncPanZoomController->GetFrameMetrics().GetScrollOffset();
   return GetPointOffset(origin);
 }
 
 float Axis::GetCompositionLength() {
   const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
   CSSRect cssCompositedRect = CSSRect(metrics.CalculateCompositedRectInCssPixels());
   return GetRectLength(cssCompositedRect);
 }
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -344,60 +344,60 @@ TEST(AsyncPanZoomController, Constructor
 TEST(AsyncPanZoomController, Pinch) {
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
 
   FrameMetrics fm;
   fm.mViewport = CSSRect(0, 0, 980, 480);
   fm.mCompositionBounds = ParentLayerIntRect(200, 200, 100, 200);
   fm.mScrollableRect = CSSRect(0, 0, 980, 1000);
-  fm.mScrollOffset = CSSPoint(300, 300);
+  fm.SetScrollOffset(CSSPoint(300, 300));
   fm.mZoom = CSSToScreenScale(2.0);
   apzc->SetFrameMetrics(fm);
   apzc->UpdateZoomConstraints(ZoomConstraints(true, true, CSSToScreenScale(0.25), CSSToScreenScale(4.0)));
   // the visible area of the document in CSS pixels is x=300 y=300 w=50 h=100
 
   EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
 
   ApzcPinch(apzc, 250, 300, 1.25);
 
   // the visible area of the document in CSS pixels is now x=305 y=310 w=40 h=80
   fm = apzc->GetFrameMetrics();
   EXPECT_EQ(fm.mZoom.scale, 2.5f);
-  EXPECT_EQ(fm.mScrollOffset.x, 305);
-  EXPECT_EQ(fm.mScrollOffset.y, 310);
+  EXPECT_EQ(fm.GetScrollOffset().x, 305);
+  EXPECT_EQ(fm.GetScrollOffset().y, 310);
 
   // part 2 of the test, move to the top-right corner of the page and pinch and
   // make sure we stay in the correct spot
   fm.mZoom = CSSToScreenScale(2.0);
-  fm.mScrollOffset = CSSPoint(930, 5);
+  fm.SetScrollOffset(CSSPoint(930, 5));
   apzc->SetFrameMetrics(fm);
   // the visible area of the document in CSS pixels is x=930 y=5 w=50 h=100
 
   ApzcPinch(apzc, 250, 300, 0.5);
 
   // the visible area of the document in CSS pixels is now x=880 y=0 w=100 h=200
   fm = apzc->GetFrameMetrics();
   EXPECT_EQ(fm.mZoom.scale, 1.0f);
-  EXPECT_EQ(fm.mScrollOffset.x, 880);
-  EXPECT_EQ(fm.mScrollOffset.y, 0);
+  EXPECT_EQ(fm.GetScrollOffset().x, 880);
+  EXPECT_EQ(fm.GetScrollOffset().y, 0);
 
   apzc->Destroy();
 }
 
 TEST(AsyncPanZoomController, PinchWithTouchActionNone) {
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
 
   FrameMetrics fm;
   fm.mViewport = CSSRect(0, 0, 980, 480);
   fm.mCompositionBounds = ParentLayerIntRect(200, 200, 100, 200);
   fm.mScrollableRect = CSSRect(0, 0, 980, 1000);
-  fm.mScrollOffset = CSSPoint(300, 300);
+  fm.SetScrollOffset(CSSPoint(300, 300));
   fm.mZoom = CSSToScreenScale(2.0);
   apzc->SetFrameMetrics(fm);
   // the visible area of the document in CSS pixels is x=300 y=300 w=50 h=100
 
   // Apzc's OnScaleEnd method calls once SendAsyncScrollDOMEvent and RequestContentRepaint methods,
   // therefore we're setting these specific values.
   EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtMost(1));
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(AtMost(1));
@@ -409,45 +409,45 @@ TEST(AsyncPanZoomController, PinchWithTo
 
   apzc->SetAllowedTouchBehavior(values);
   ApzcPinch(apzc, 250, 300, 1.25);
 
   // The frame metrics should stay the same since touch-action:none makes
   // apzc ignore pinch gestures.
   fm = apzc->GetFrameMetrics();
   EXPECT_EQ(fm.mZoom.scale, 2.0f);
-  EXPECT_EQ(fm.mScrollOffset.x, 300);
-  EXPECT_EQ(fm.mScrollOffset.y, 300);
+  EXPECT_EQ(fm.GetScrollOffset().x, 300);
+  EXPECT_EQ(fm.GetScrollOffset().y, 300);
 }
 
 TEST(AsyncPanZoomController, Overzoom) {
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
 
   FrameMetrics fm;
   fm.mViewport = CSSRect(0, 0, 100, 100);
   fm.mCompositionBounds = ParentLayerIntRect(0, 0, 100, 100);
   fm.mScrollableRect = CSSRect(0, 0, 125, 150);
-  fm.mScrollOffset = CSSPoint(10, 0);
+  fm.SetScrollOffset(CSSPoint(10, 0));
   fm.mZoom = CSSToScreenScale(1.0);
   apzc->SetFrameMetrics(fm);
   apzc->UpdateZoomConstraints(ZoomConstraints(true, true, CSSToScreenScale(0.25), CSSToScreenScale(4.0)));
   // the visible area of the document in CSS pixels is x=10 y=0 w=100 h=100
 
   EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
 
   ApzcPinch(apzc, 50, 50, 0.5);
 
   fm = apzc->GetFrameMetrics();
   EXPECT_EQ(fm.mZoom.scale, 0.8f);
   // bug 936721 - PGO builds introduce rounding error so
   // use a fuzzy match instead
-  EXPECT_LT(abs(fm.mScrollOffset.x), 1e-5);
-  EXPECT_LT(abs(fm.mScrollOffset.y), 1e-5);
+  EXPECT_LT(abs(fm.GetScrollOffset().x), 1e-5);
+  EXPECT_LT(abs(fm.GetScrollOffset().y), 1e-5);
 }
 
 TEST(AsyncPanZoomController, SimpleTransform) {
   TimeStamp testStartTime = TimeStamp::Now();
   // RefCounted class can't live in the stack
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
   apzc->SetFrameMetrics(TestFrameMetrics());
@@ -500,17 +500,17 @@ TEST(AsyncPanZoomController, ComplexTran
   nsTArray<nsRefPtr<Layer> > layers;
   nsRefPtr<LayerManager> lm;
   nsRefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers);
 
   FrameMetrics metrics;
   metrics.mCompositionBounds = ParentLayerIntRect(0, 0, 24, 24);
   metrics.mDisplayPort = CSSRect(-1, -1, 6, 6);
   metrics.mViewport = CSSRect(0, 0, 4, 4);
-  metrics.mScrollOffset = CSSPoint(10, 10);
+  metrics.SetScrollOffset(CSSPoint(10, 10));
   metrics.mScrollableRect = CSSRect(0, 0, 50, 50);
   metrics.mCumulativeResolution = LayoutDeviceToLayerScale(2);
   metrics.mResolution = ParentLayerToLayerScale(2);
   metrics.mZoom = CSSToScreenScale(6);
   metrics.mDevPixelsPerCSSPixel = CSSToLayoutDeviceScale(3);
   metrics.mScrollId = FrameMetrics::START_SCROLL_ID;
 
   FrameMetrics childMetrics = metrics;
@@ -534,23 +534,23 @@ TEST(AsyncPanZoomController, ComplexTran
 
   childApzc->SetFrameMetrics(childMetrics);
   childApzc->NotifyLayersUpdated(childMetrics, true);
   childApzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
   EXPECT_EQ(ViewTransform(LayerPoint(), ParentLayerToScreenScale(2)), viewTransformOut);
   EXPECT_EQ(ScreenPoint(60, 60), pointOut);
 
   // do an async scroll by 5 pixels and check the transform
-  metrics.mScrollOffset += CSSPoint(5, 0);
+  metrics.ScrollBy(CSSPoint(5, 0));
   apzc->SetFrameMetrics(metrics);
   apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
   EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), ParentLayerToScreenScale(2)), viewTransformOut);
   EXPECT_EQ(ScreenPoint(90, 60), pointOut);
 
-  childMetrics.mScrollOffset += CSSPoint(5, 0);
+  childMetrics.ScrollBy(CSSPoint(5, 0));
   childApzc->SetFrameMetrics(childMetrics);
   childApzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
   EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), ParentLayerToScreenScale(2)), viewTransformOut);
   EXPECT_EQ(ScreenPoint(90, 60), pointOut);
 
   // do an async zoom of 1.5x and check the transform
   metrics.mZoom.scale *= 1.5f;
   apzc->SetFrameMetrics(metrics);
@@ -927,17 +927,17 @@ SetScrollableFrameMetrics(Layer* aLayer,
 {
   ContainerLayer* container = aLayer->AsContainerLayer();
   FrameMetrics metrics;
   metrics.mScrollId = aScrollId;
   nsIntRect layerBound = aLayer->GetVisibleRegion().GetBounds();
   metrics.mCompositionBounds = ParentLayerIntRect(layerBound.x, layerBound.y,
                                                   layerBound.width, layerBound.height);
   metrics.mScrollableRect = aScrollableRect;
-  metrics.mScrollOffset = CSSPoint(0, 0);
+  metrics.SetScrollOffset(CSSPoint(0, 0));
   container->SetFrameMetrics(metrics);
 }
 
 static already_AddRefed<AsyncPanZoomController>
 GetTargetAPZC(APZCTreeManager* manager, const ScreenPoint& aPoint,
               gfx3DMatrix& aTransformToApzcOut, gfx3DMatrix& aTransformToGeckoOut)
 {
   nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(aPoint);
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -677,17 +677,17 @@ static void RecordFrameMetrics(nsIFrame*
     }
     if (scrollableFrame->GetScrollbarStyles().mHorizontal == NS_STYLE_OVERFLOW_HIDDEN) {
       contentBounds.x = scrollPosition.x;
       contentBounds.width = 0;
     }
     contentBounds.width += scrollableFrame->GetScrollPortRect().width;
     contentBounds.height += scrollableFrame->GetScrollPortRect().height;
     metrics.mScrollableRect = CSSRect::FromAppUnits(contentBounds);
-    metrics.mScrollOffset = CSSPoint::FromAppUnits(scrollPosition);
+    metrics.SetScrollOffset(CSSPoint::FromAppUnits(scrollPosition));
 
     // If the frame was scrolled since the last layers update, and by
     // something other than the APZ code, we want to tell the APZ to update
     // its scroll offset.
     nsIAtom* originOfLastScroll = scrollableFrame->OriginOfLastScroll();
     if (originOfLastScroll && originOfLastScroll != nsGkAtoms::apz) {
       metrics.SetScrollOffsetUpdated(scrollableFrame->CurrentScrollGeneration());
     }
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -417,18 +417,18 @@ BuildViewMap(ViewMap& oldContentViews, V
       aAccConfigXScale *= config.mXScale;
       aAccConfigYScale *= config.mYScale;
     } else {
       // View doesn't exist, so generate one. We start the view scroll offset at
       // the same position as the framemetric's scroll offset from the layer.
       // The default scale is 1, so no need to propagate scale down.
       ViewConfig config;
       config.mScrollOffset = nsPoint(
-        NSIntPixelsToAppUnits(metrics.mScrollOffset.x, auPerCSSPixel) * aXScale,
-        NSIntPixelsToAppUnits(metrics.mScrollOffset.y, auPerCSSPixel) * aYScale);
+        NSIntPixelsToAppUnits(metrics.GetScrollOffset().x, auPerCSSPixel) * aXScale,
+        NSIntPixelsToAppUnits(metrics.GetScrollOffset().y, auPerCSSPixel) * aYScale);
       view = new nsContentView(aFrameLoader, scrollId, metrics.mIsRoot, config);
       view->mParentScaleX = aAccConfigXScale;
       view->mParentScaleY = aAccConfigYScale;
     }
 
     // I don't know what units mViewportSize is in, hence use ToUnknownRect
     // here to mark the current frontier in type info propagation
     gfx::Rect viewport = metrics.mViewport.ToUnknownRect();
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -1876,17 +1876,17 @@ AndroidBridge::SetNativePanZoomControlle
 }
 
 void
 AndroidBridge::RequestContentRepaint(const mozilla::layers::FrameMetrics& aFrameMetrics)
 {
     ALOG_BRIDGE("AndroidBridge::RequestContentRepaint");
 
     CSSToScreenScale resolution = aFrameMetrics.mZoom;
-    ScreenRect dp = (aFrameMetrics.mDisplayPort + aFrameMetrics.mScrollOffset) * resolution;
+    ScreenRect dp = (aFrameMetrics.mDisplayPort + aFrameMetrics.GetScrollOffset()) * resolution;
 
     mNativePanZoomController->RequestContentRepaintWrapper(dp.x, dp.y, dp.width, dp.height, resolution.scale);
 }
 
 void
 AndroidBridge::AcknowledgeScrollUpdate(const mozilla::layers::FrameMetrics::ViewID& aScrollId,
                                        const uint32_t& aScrollGeneration)
 {
--- a/widget/xpwidgets/APZCCallbackHelper.cpp
+++ b/widget/xpwidgets/APZCCallbackHelper.cpp
@@ -63,17 +63,17 @@ static CSSRect ExpandDisplayPortToTileBo
 
 static void
 MaybeAlignAndClampDisplayPort(mozilla::layers::FrameMetrics& aFrameMetrics,
                               const CSSPoint& aActualScrollOffset)
 {
   // Correct the display-port by the difference between the requested scroll
   // offset and the resulting scroll offset after setting the requested value.
   CSSRect& displayPort = aFrameMetrics.mDisplayPort;
-  displayPort += aFrameMetrics.mScrollOffset - aActualScrollOffset;
+  displayPort += aFrameMetrics.GetScrollOffset() - aActualScrollOffset;
 
   // Expand the display port to the next tile boundaries, if tiled thebes layers
   // are enabled.
   if (gfxPrefs::LayersTilesEnabled()) {
     // We don't use LayersPixelsPerCSSPixel() here as mCumulativeResolution on
     // this FrameMetrics may be incorrect (and is about to be reset by mZoom).
     displayPort =
       ExpandDisplayPortToTileBoundaries(displayPort + aActualScrollOffset,
@@ -157,34 +157,34 @@ APZCCallbackHelper::UpdateRootFrame(nsID
     // scroll range would be 900. Therefore this calculation depends on the zoom applied
     // to the content relative to the container.
     CSSSize scrollPort = CSSSize(aMetrics.CalculateCompositedRectInCssPixels().Size());
     aUtils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height);
 
     // Scroll the window to the desired spot
     nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.mScrollId);
     bool scrollUpdated = false;
-    CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.mScrollOffset, scrollUpdated);
+    CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.GetScrollOffset(), scrollUpdated);
 
     if (!scrollUpdated) {
       // For whatever reason we couldn't update the scroll offset on the scroll frame,
       // which means the data APZ used for its displayport calculation is stale. Fall
       // back to a sane default behaviour. Note that we don't tile-align the recentered
       // displayport because tile-alignment depends on the scroll position, and the
       // scroll position here is out of our control. See bug 966507 comment 21 for a
       // more detailed explanation.
       RecenterDisplayPort(aMetrics);
     }
 
     // Correct the display port due to the difference between mScrollOffset and the
     // actual scroll offset, possibly align it to tile boundaries (if tiled layers are
     // enabled), and clamp it to the scrollable rect.
     MaybeAlignAndClampDisplayPort(aMetrics, actualScrollOffset);
 
-    aMetrics.mScrollOffset = actualScrollOffset;
+    aMetrics.SetScrollOffset(actualScrollOffset);
 
     // The mZoom variable on the frame metrics stores the CSS-to-screen scale for this
     // frame. This scale includes all of the (cumulative) resolutions set on the presShells
     // from the root down to this frame. However, when setting the resolution, we only
     // want the piece of the resolution that corresponds to this presShell, rather than
     // all of the cumulative stuff, so we need to divide out the parent resolutions.
     // Finally, we multiply by a ScreenToLayerScale of 1.0f because the goal here is to
     // take the async zoom calculated by the APZC and tell gecko about it (turning it into
@@ -227,32 +227,32 @@ APZCCallbackHelper::UpdateSubFrame(nsICo
         return;
     }
 
     // We currently do not support zooming arbitrary subframes. They can only
     // be scrolled, so here we only have to set the scroll position and displayport.
 
     nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.mScrollId);
     bool scrollUpdated = false;
-    CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.mScrollOffset, scrollUpdated);
+    CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.GetScrollOffset(), scrollUpdated);
 
     nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent);
     if (element) {
         if (!scrollUpdated) {
             RecenterDisplayPort(aMetrics);
         }
         MaybeAlignAndClampDisplayPort(aMetrics, actualScrollOffset);
         utils->SetDisplayPortForElement(aMetrics.mDisplayPort.x,
                                         aMetrics.mDisplayPort.y,
                                         aMetrics.mDisplayPort.width,
                                         aMetrics.mDisplayPort.height,
                                         element, 0);
     }
 
-    aMetrics.mScrollOffset = actualScrollOffset;
+    aMetrics.SetScrollOffset(actualScrollOffset);
 }
 
 already_AddRefed<nsIDOMWindowUtils>
 APZCCallbackHelper::GetDOMWindowUtils(const nsIDocument* aDoc)
 {
     nsCOMPtr<nsIDOMWindowUtils> utils;
     nsCOMPtr<nsIDOMWindow> window = aDoc->GetDefaultView();
     if (window) {
@@ -333,17 +333,17 @@ DestroyCSSPoint(void* aObject, nsIAtom* 
 
 void
 APZCCallbackHelper::UpdateCallbackTransform(const FrameMetrics& aApzcMetrics, const FrameMetrics& aActualMetrics)
 {
     nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aApzcMetrics.mScrollId);
     if (!content) {
         return;
     }
-    CSSPoint scrollDelta = aApzcMetrics.mScrollOffset - aActualMetrics.mScrollOffset;
+    CSSPoint scrollDelta = aApzcMetrics.GetScrollOffset() - aActualMetrics.GetScrollOffset();
     content->SetProperty(nsGkAtoms::apzCallbackTransform, new CSSPoint(scrollDelta), DestroyCSSPoint);
 }
 
 CSSPoint
 APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput, const ScrollableLayerGuid& aGuid)
 {
     // XXX: technically we need to walk all the way up the layer tree from the layer
     // represented by |aGuid.mScrollId| up to the root of the layer tree and apply