Bug 915985 - Refactoring to introduce a ZoomConstraints class. r=botond a=1.3+
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 06 Jan 2014 13:26:44 -0500
changeset 175735 af1d3158671606298acccf60ec3605f02ebe6580
parent 175734 e3497406417d4c4975148dac1a3fccf7cf492c59
child 175736 7223b5a7a17102344c510bcded2b305b40fbb7e0
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond, 1
bugs915985
milestone28.0a2
Bug 915985 - Refactoring to introduce a ZoomConstraints class. r=botond a=1.3+
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
gfx/ipc/GfxMessageUtils.h
gfx/layers/FrameMetrics.h
gfx/layers/composite/APZCTreeManager.cpp
gfx/layers/composite/APZCTreeManager.h
gfx/layers/ipc/AsyncPanZoomController.cpp
gfx/layers/ipc/AsyncPanZoomController.h
gfx/layers/ipc/GeckoContentController.h
gfx/tests/gtest/TestAsyncPanZoomController.cpp
layout/ipc/RenderFrameParent.cpp
layout/ipc/RenderFrameParent.h
widget/windows/winrt/MetroWidget.cpp
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -19,16 +19,17 @@ include URIParams;
 
 
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
 using struct gfxMatrix from "gfxMatrix.h";
 using struct gfxSize from "gfxPoint.h";
 using CSSRect from "Units.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
 using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
+using struct mozilla::layers::ZoomConstraints from "FrameMetrics.h";
 using FrameMetrics::ViewID from "FrameMetrics.h";
 using mozilla::layout::ScrollingBehavior from "mozilla/layout/RenderFrameUtils.h";
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
 using nscolor from "nsColor.h";
 using class mozilla::WidgetCompositionEvent from "ipc/nsGUIEventIPC.h";
 using struct nsIMEUpdatePreference from "nsIWidget.h";
 using struct nsIntPoint from "nsPoint.h";
@@ -296,17 +297,17 @@ parent:
     ContentReceivedTouch(ScrollableLayerGuid aGuid, bool aPreventDefault);
 
     /**
      * Updates the zoom constraints for a scrollable frame in this tab.
      * The zoom controller code lives on the parent side and so this allows it to
      * have up-to-date zoom constraints.
      */
     UpdateZoomConstraints(uint32_t aPresShellId, ViewID aViewId, bool aIsRoot,
-                          bool aAllowZoom, CSSToScreenScale aMinZoom, CSSToScreenScale aMaxZoom);
+                          ZoomConstraints aConstraints);
 
     __delete__();
 
 child:
     /**
      * Notify the remote browser that it has been Show()n on this
      * side, with the given |visibleRect|.  This message is expected
      * to trigger creation of the remote browser's "widget".
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -513,22 +513,24 @@ TabChild::HandlePossibleViewportChange()
 
   nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
 
   nsViewportInfo viewportInfo = nsContentUtils::GetViewportInfo(document, mInnerSize);
   uint32_t presShellId;
   ViewID viewId;
   if (APZCCallbackHelper::GetScrollIdentifiers(document->GetDocumentElement(),
                                                &presShellId, &viewId)) {
+    ZoomConstraints constraints(
+      viewportInfo.IsZoomAllowed(),
+      viewportInfo.GetMinZoom(),
+      viewportInfo.GetMaxZoom());
     SendUpdateZoomConstraints(presShellId,
                               viewId,
                               /* isRoot = */ true,
-                              viewportInfo.IsZoomAllowed(),
-                              viewportInfo.GetMinZoom(),
-                              viewportInfo.GetMaxZoom());
+                              constraints);
   }
 
 
   float screenW = mInnerSize.width;
   float screenH = mInnerSize.height;
   CSSSize viewport(viewportInfo.GetSize());
 
   // We're not being displayed in any way; don't bother doing anything because
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1708,22 +1708,20 @@ TabParent::RecvZoomToRect(const uint32_t
   }
   return true;
 }
 
 bool
 TabParent::RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
                                      const ViewID& aViewId,
                                      const bool& aIsRoot,
-                                     const bool& aAllowZoom,
-                                     const CSSToScreenScale& aMinZoom,
-                                     const CSSToScreenScale& aMaxZoom)
+                                     const ZoomConstraints& aConstraints)
 {
   if (RenderFrameParent* rfp = GetRenderFrame()) {
-    rfp->UpdateZoomConstraints(aPresShellId, aViewId, aIsRoot, aAllowZoom, aMinZoom, aMaxZoom);
+    rfp->UpdateZoomConstraints(aPresShellId, aViewId, aIsRoot, aConstraints);
   }
   return true;
 }
 
 bool
 TabParent::RecvContentReceivedTouch(const ScrollableLayerGuid& aGuid,
                                     const bool& aPreventDefault)
 {
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -163,19 +163,17 @@ public:
     virtual bool RecvGetDefaultScale(double* aValue);
     virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue);
     virtual bool RecvZoomToRect(const uint32_t& aPresShellId,
                                 const ViewID& aViewId,
                                 const CSSRect& aRect);
     virtual bool RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
                                            const ViewID& aViewId,
                                            const bool& aIsRoot,
-                                           const bool& aAllowZoom,
-                                           const CSSToScreenScale& aMinZoom,
-                                           const CSSToScreenScale& aMaxZoom);
+                                           const ZoomConstraints& aConstraints);
     virtual bool RecvContentReceivedTouch(const ScrollableLayerGuid& aGuid,
                                           const bool& aPreventDefault);
     virtual PContentDialogParent* AllocPContentDialogParent(const uint32_t& aType,
                                                             const nsCString& aName,
                                                             const nsCString& aFeatures,
                                                             const InfallibleTArray<int>& aIntParams,
                                                             const InfallibleTArray<nsString>& aStringParams);
     virtual bool DeallocPContentDialogParent(PContentDialogParent* aDialog)
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -680,11 +680,31 @@ struct ParamTraits<mozilla::layers::Scro
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mLayersId) &&
             ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
             ReadParam(aMsg, aIter, &aResult->mScrollId));
   }
 };
 
+template <>
+struct ParamTraits<mozilla::layers::ZoomConstraints>
+{
+  typedef mozilla::layers::ZoomConstraints paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mAllowZoom);
+    WriteParam(aMsg, aParam.mMinZoom);
+    WriteParam(aMsg, aParam.mMaxZoom);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return (ReadParam(aMsg, aIter, &aResult->mAllowZoom) &&
+            ReadParam(aMsg, aIter, &aResult->mMinZoom) &&
+            ReadParam(aMsg, aIter, &aResult->mMaxZoom));
+  }
+};
+
 } /* namespace IPC */
 
 #endif /* __GFXMESSAGEUTILS_H__ */
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -344,12 +344,51 @@ struct ScrollableLayerGuid {
   }
 
   bool operator!=(const ScrollableLayerGuid& other) const
   {
     return !(*this == other);
   }
 };
 
+struct ZoomConstraints {
+  bool mAllowZoom;
+  CSSToScreenScale mMinZoom;
+  CSSToScreenScale mMaxZoom;
+
+  ZoomConstraints()
+    : mAllowZoom(true)
+  {
+    MOZ_COUNT_CTOR(ZoomConstraints);
+  }
+
+  ZoomConstraints(bool aAllowZoom,
+                  const CSSToScreenScale& aMinZoom,
+                  const CSSToScreenScale& aMaxZoom)
+    : mAllowZoom(aAllowZoom)
+    , mMinZoom(aMinZoom)
+    , mMaxZoom(aMaxZoom)
+  {
+    MOZ_COUNT_CTOR(ZoomConstraints);
+  }
+
+  ~ZoomConstraints()
+  {
+    MOZ_COUNT_DTOR(ZoomConstraints);
+  }
+
+  bool operator==(const ZoomConstraints& other) const
+  {
+    return mAllowZoom == other.mAllowZoom
+        && mMinZoom == other.mMinZoom
+        && mMaxZoom == other.mMaxZoom;
+  }
+
+  bool operator!=(const ZoomConstraints& other) const
+  {
+    return !(*this == other);
+  }
+};
+
 }
 }
 
 #endif /* GFX_FRAMEMETRICS_H */
--- a/gfx/layers/composite/APZCTreeManager.cpp
+++ b/gfx/layers/composite/APZCTreeManager.cpp
@@ -185,32 +185,30 @@ APZCTreeManager::UpdatePanZoomController
         } else {
           mRootApzc = apzc;
         }
 
         // Let this apzc be the parent of other controllers when we recurse downwards
         aParent = apzc;
 
         if (newApzc) {
-          bool allowZoom;
-          CSSToScreenScale minZoom, maxZoom;
           if (apzc->IsRootForLayersId()) {
             // If we just created a new apzc that is the root for its layers ID, then
             // we need to update its zoom constraints which might have arrived before this
             // was created
-            if (state->mController->GetRootZoomConstraints(&allowZoom, &minZoom, &maxZoom)) {
-              apzc->UpdateZoomConstraints(allowZoom, minZoom, maxZoom);
+            ZoomConstraints constraints;
+            if (state->mController->GetRootZoomConstraints(&constraints)) {
+              apzc->UpdateZoomConstraints(constraints);
             }
           } else {
             // For an apzc that is not the root for its layers ID, we give it the
             // same zoom constraints as its parent. This ensures that if e.g.
             // user-scalable=no was specified, none of the APZCs allow double-tap
             // to zoom.
-            apzc->GetParent()->GetZoomConstraints(&allowZoom, &minZoom, &maxZoom);
-            apzc->UpdateZoomConstraints(allowZoom, minZoom, maxZoom);
+            apzc->UpdateZoomConstraints(apzc->GetParent()->GetZoomConstraints());
           }
         }
       }
     }
 
     container->SetAsyncPanZoomController(apzc);
   }
 
@@ -570,42 +568,38 @@ APZCTreeManager::ContentReceivedTouch(co
   nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
   if (apzc) {
     apzc->ContentReceivedTouch(aPreventDefault);
   }
 }
 
 void
 APZCTreeManager::UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
-                                       bool aAllowZoom,
-                                       const CSSToScreenScale& aMinScale,
-                                       const CSSToScreenScale& aMaxScale)
+                                       const ZoomConstraints& aConstraints)
 {
   nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
   // For a given layers id, non-root APZCs inherit the zoom constraints
   // of their root.
   if (apzc && apzc->IsRootForLayersId()) {
     MonitorAutoLock lock(mTreeLock);
-    UpdateZoomConstraintsRecursively(apzc.get(), aAllowZoom, aMinScale, aMaxScale);
+    UpdateZoomConstraintsRecursively(apzc.get(), aConstraints);
   }
 }
 
 void
 APZCTreeManager::UpdateZoomConstraintsRecursively(AsyncPanZoomController* aApzc,
-                                                  bool aAllowZoom,
-                                                  const CSSToScreenScale& aMinScale,
-                                                  const CSSToScreenScale& aMaxScale)
+                                                  const ZoomConstraints& aConstraints)
 {
   mTreeLock.AssertCurrentThreadOwns();
 
-  aApzc->UpdateZoomConstraints(aAllowZoom, aMinScale, aMaxScale);
+  aApzc->UpdateZoomConstraints(aConstraints);
   for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
     // We can have subtrees with their own layers id - leave those alone.
     if (!child->IsRootForLayersId()) {
-      UpdateZoomConstraintsRecursively(child, aAllowZoom, aMinScale, aMaxScale);
+      UpdateZoomConstraintsRecursively(child, aConstraints);
     }
   }
 }
 
 void
 APZCTreeManager::CancelAnimation(const ScrollableLayerGuid &aGuid)
 {
   nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
--- a/gfx/layers/composite/APZCTreeManager.h
+++ b/gfx/layers/composite/APZCTreeManager.h
@@ -148,23 +148,19 @@ public:
    * that have come in. If |aPreventDefault| is true, any touch events in the
    * queue will be discarded.
    */
   void ContentReceivedTouch(const ScrollableLayerGuid& aGuid,
                             bool aPreventDefault);
 
   /**
    * Updates any zoom constraints contained in the <meta name="viewport"> tag.
-   * We try to obey everything it asks us elsewhere, but here we only handle
-   * minimum-scale, maximum-scale, and user-scalable.
    */
   void UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
-                             bool aAllowZoom,
-                             const CSSToScreenScale& aMinScale,
-                             const CSSToScreenScale& aMaxScale);
+                             const ZoomConstraints& aConstraints);
 
   /**
    * Cancels any currently running animation. Note that all this does is set the
    * state of the AsyncPanZoomController back to NOTHING, but it is the
    * animation's responsibility to check this before advancing.
    */
   void CancelAnimation(const ScrollableLayerGuid &aGuid);
 
@@ -260,19 +256,17 @@ private:
   AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint);
   already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
   already_AddRefed<AsyncPanZoomController> RootAPZCForLayersId(AsyncPanZoomController* aApzc);
   already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent, ScreenPoint aPoint);
   nsEventStatus ProcessTouchEvent(const WidgetTouchEvent& touchEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetTouchEvent* aOutEvent);
   nsEventStatus ProcessMouseEvent(const WidgetMouseEvent& mouseEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetMouseEvent* aOutEvent);
   nsEventStatus ProcessEvent(const WidgetInputEvent& inputEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetInputEvent* aOutEvent);
   void UpdateZoomConstraintsRecursively(AsyncPanZoomController* aApzc,
-                                        bool aAllowZoom,
-                                        const CSSToScreenScale& aMinScale,
-                                        const CSSToScreenScale& aMaxScale);
+                                        const ZoomConstraints& aConstraints);
 
   /**
    * Recursive helper function to build the APZC tree. The tree of APZC instances has
    * the same shape as the layer tree, but excludes all the layers that are not scrollable.
    * Note that this means APZCs corresponding to layers at different depths in the tree
    * may end up becoming siblings. It also means that the "root" APZC may have siblings.
    * This function walks the layer tree backwards through siblings and constructs the APZC
    * tree also as a last-child-prev-sibling tree because that simplifies the hit detection
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -378,35 +378,33 @@ AsyncPanZoomController::AsyncPanZoomCont
   :  mLayersId(aLayersId),
      mPaintThrottler(GetFrameTime()),
      mGeckoContentController(aGeckoContentController),
      mRefPtrMonitor("RefPtrMonitor"),
      mMonitor("AsyncPanZoomController"),
      mTouchListenerTimeoutTask(nullptr),
      mX(MOZ_THIS_IN_INITIALIZER_LIST()),
      mY(MOZ_THIS_IN_INITIALIZER_LIST()),
-     mAllowZoom(true),
-     mMinZoom(MIN_ZOOM),
-     mMaxZoom(MAX_ZOOM),
+     mZoomConstraints(true, MIN_ZOOM, MAX_ZOOM),
      mLastSampleTime(GetFrameTime()),
      mState(NOTHING),
      mLastAsyncScrollTime(GetFrameTime()),
      mLastAsyncScrollOffset(0, 0),
      mCurrentAsyncScrollOffset(0, 0),
      mAsyncScrollTimeoutTask(nullptr),
      mHandlingTouchQueue(false),
      mTreeManager(aTreeManager)
 {
   MOZ_COUNT_CTOR(AsyncPanZoomController);
 
   if (aGestures == USE_GESTURE_DETECTOR) {
     mGestureEventListener = new GestureEventListener(this);
   }
   if (gAsyncZoomDisabled) {
-    mAllowZoom = false;
+    mZoomConstraints.mAllowZoom = false;
   }
 }
 
 AsyncPanZoomController::~AsyncPanZoomController() {
   MOZ_COUNT_DTOR(AsyncPanZoomController);
 }
 
 already_AddRefed<GeckoContentController>
@@ -679,17 +677,17 @@ nsEventStatus AsyncPanZoomController::On
 nsEventStatus AsyncPanZoomController::OnTouchCancel(const MultiTouchInput& aEvent) {
   APZC_LOG("%p got a touch-cancel in state %d\n", this, mState);
   SetState(NOTHING);
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEvent) {
   APZC_LOG("%p got a scale-begin in state %d\n", this, mState);
-  if (!mAllowZoom) {
+  if (!mZoomConstraints.mAllowZoom) {
     return nsEventStatus_eConsumeNoDefault;
   }
 
   SetState(PINCHING);
   mLastZoomFocus = aEvent.mFocusPoint - mFrameMetrics.mCompositionBounds.TopLeft();
 
   return nsEventStatus_eConsumeNoDefault;
 }
@@ -726,18 +724,18 @@ nsEventStatus AsyncPanZoomController::On
     }
     ScrollBy(focusChange);
 
     // When we zoom in with focus, we can zoom too much towards the boundaries
     // that we actually go over them. These are the needed displacements along
     // either axis such that we don't overscroll the boundaries when zooming.
     CSSPoint neededDisplacement;
 
-    CSSToScreenScale realMinZoom = mMinZoom;
-    CSSToScreenScale realMaxZoom = mMaxZoom;
+    CSSToScreenScale realMinZoom = mZoomConstraints.mMinZoom;
+    CSSToScreenScale realMaxZoom = mZoomConstraints.mMaxZoom;
     realMinZoom.scale = std::max(realMinZoom.scale,
                                  mFrameMetrics.mCompositionBounds.width / mFrameMetrics.mScrollableRect.width);
     realMinZoom.scale = std::max(realMinZoom.scale,
                                  mFrameMetrics.mCompositionBounds.height / mFrameMetrics.mScrollableRect.height);
     if (realMaxZoom < realMinZoom) {
       realMaxZoom = realMinZoom;
     }
 
@@ -842,19 +840,19 @@ nsEventStatus AsyncPanZoomController::On
     }
   }
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEvent) {
   APZC_LOG("%p got a single-tap-up in state %d\n", this, mState);
   nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
-  // If mAllowZoom is true we wait for a call to OnSingleTapConfirmed before
+  // If mZoomConstraints.mAllowZoom is true we wait for a call to OnSingleTapConfirmed before
   // sending event to content
-  if (controller && !mAllowZoom) {
+  if (controller && !mZoomConstraints.mAllowZoom) {
     int32_t modifiers = WidgetModifiersToDOMModifiers(aEvent.modifiers);
     CSSIntPoint geckoScreenPoint;
     if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
       controller->HandleSingleTap(geckoScreenPoint, modifiers);
       return nsEventStatus_eConsumeNoDefault;
     }
   }
   return nsEventStatus_eIgnore;
@@ -873,17 +871,17 @@ nsEventStatus AsyncPanZoomController::On
   }
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent) {
   APZC_LOG("%p got a double-tap in state %d\n", this, mState);
   nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
   if (controller) {
-    if (mAllowZoom) {
+    if (mZoomConstraints.mAllowZoom) {
       int32_t modifiers = WidgetModifiersToDOMModifiers(aEvent.modifiers);
       CSSIntPoint geckoScreenPoint;
       if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
         controller->HandleDoubleTap(geckoScreenPoint, modifiers);
       }
     }
 
     return nsEventStatus_eConsumeNoDefault;
@@ -1464,29 +1462,29 @@ void AsyncPanZoomController::ZoomToRect(
     CSSToScreenScale currentZoom = mFrameMetrics.mZoom;
     CSSToScreenScale 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.
-    CSSToScreenScale localMinZoom(std::max(mMinZoom.scale,
+    CSSToScreenScale localMinZoom(std::max(mZoomConstraints.mMinZoom.scale,
                                   std::max(compositionBounds.width / cssPageRect.width,
                                            compositionBounds.height / cssPageRect.height)));
-    CSSToScreenScale localMaxZoom = mMaxZoom;
+    CSSToScreenScale localMaxZoom = mZoomConstraints.mMaxZoom;
 
     if (!aRect.IsEmpty()) {
       // Intersect the zoom-to-rect to the CSS rect to make sure it fits.
       aRect = aRect.Intersect(cssPageRect);
       targetZoom = CSSToScreenScale(std::min(compositionBounds.width / aRect.width,
                                              compositionBounds.height / aRect.height));
     }
     // 1. If the rect is empty, request received from browserElementScrolling.js
-    // 2. currentZoom is equal to mMaxZoom and user still double-tapping it
+    // 2. currentZoom is equal to mZoomConstraints.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 (aRect.IsEmpty() ||
         (currentZoom == localMaxZoom && targetZoom >= localMaxZoom) ||
         (currentZoom == localMinZoom && targetZoom <= localMinZoom)) {
       CSSRect compositedRect = mFrameMetrics.CalculateCompositedRectInCssPixels();
       float y = scrollOffset.y;
       float newHeight =
@@ -1605,35 +1603,29 @@ bool AsyncPanZoomController::IsPanningSt
   return (aState == PANNING || aState == PANNING_LOCKED_X || aState == PANNING_LOCKED_Y);
 }
 
 void AsyncPanZoomController::TimeoutTouchListeners() {
   mTouchListenerTimeoutTask = nullptr;
   ContentReceivedTouch(false);
 }
 
-void AsyncPanZoomController::UpdateZoomConstraints(bool aAllowZoom,
-                                                   const CSSToScreenScale& aMinZoom,
-                                                   const CSSToScreenScale& aMaxZoom) {
+void AsyncPanZoomController::UpdateZoomConstraints(const ZoomConstraints& aConstraints) {
   if (gAsyncZoomDisabled) {
     return;
   }
-  mAllowZoom = aAllowZoom;
-  mMinZoom = (MIN_ZOOM > aMinZoom ? MIN_ZOOM : aMinZoom);
-  mMaxZoom = (MAX_ZOOM > aMaxZoom ? aMaxZoom : MAX_ZOOM);
+  mZoomConstraints.mAllowZoom = aConstraints.mAllowZoom;
+  mZoomConstraints.mMinZoom = (MIN_ZOOM > aConstraints.mMinZoom ? MIN_ZOOM : aConstraints.mMinZoom);
+  mZoomConstraints.mMaxZoom = (MAX_ZOOM > aConstraints.mMaxZoom ? aConstraints.mMaxZoom : MAX_ZOOM);
 }
 
-void
-AsyncPanZoomController::GetZoomConstraints(bool* aAllowZoom,
-                                           CSSToScreenScale* aMinZoom,
-                                           CSSToScreenScale* aMaxZoom)
+ZoomConstraints
+AsyncPanZoomController::GetZoomConstraints() const
 {
-  *aAllowZoom = mAllowZoom;
-  *aMinZoom = mMinZoom;
-  *aMaxZoom = mMaxZoom;
+  return mZoomConstraints;
 }
 
 
 void AsyncPanZoomController::PostDelayedTask(Task* aTask, int aDelayMs) {
   nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
   if (controller) {
     controller->PostDelayedTask(aTask, aDelayMs);
   }
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -116,30 +116,24 @@ public:
    * definitively whether or not content has preventDefaulted any touch events
    * that have come in. If |aPreventDefault| is true, any touch events in the
    * queue will be discarded.
    */
   void ContentReceivedTouch(bool aPreventDefault);
 
   /**
    * Updates any zoom constraints contained in the <meta name="viewport"> tag.
-   * We try to obey everything it asks us elsewhere, but here we only handle
-   * minimum-scale, maximum-scale, and user-scalable.
    */
-  void UpdateZoomConstraints(bool aAllowZoom,
-                             const CSSToScreenScale& aMinScale,
-                             const CSSToScreenScale& aMaxScale);
+  void UpdateZoomConstraints(const ZoomConstraints& aConstraints);
 
   /**
    * Return the zoom constraints last set for this APZC (in the constructor
    * or in UpdateZoomConstraints()).
    */
-  void GetZoomConstraints(bool* aAllowZoom,
-                          CSSToScreenScale* aMinScale,
-                          CSSToScreenScale* aMaxScale);
+  ZoomConstraints GetZoomConstraints() const;
 
   /**
    * Schedules a runnable to run on the controller/UI thread at some time
    * in the future.
    */
   void PostDelayedTask(Task* aTask, int aDelayMs);
 
   // --------------------------------------------------------------------------
@@ -565,19 +559,17 @@ private:
   CancelableTask* mTouchListenerTimeoutTask;
 
   AxisX mX;
   AxisY mY;
 
   // Most up-to-date constraints on zooming. These should always be reasonable
   // values; for example, allowing a min zoom of 0.0 can cause very bad things
   // to happen.
-  bool mAllowZoom;
-  CSSToScreenScale mMinZoom;
-  CSSToScreenScale mMaxZoom;
+  ZoomConstraints mZoomConstraints;
 
   // The last time the compositor has sampled the content transform for this
   // frame.
   TimeStamp mLastSampleTime;
   // The last time a touch event came through on the UI thread.
   uint32_t mLastEventTime;
 
   // Stores the previous focus point if there is a pinch gesture happening. Used
--- a/gfx/layers/ipc/GeckoContentController.h
+++ b/gfx/layers/ipc/GeckoContentController.h
@@ -71,19 +71,17 @@ public:
    */
   virtual void PostDelayedTask(Task* aTask, int aDelayMs) = 0;
 
   /**
    * Retrieves the last known zoom constraints for the root scrollable layer
    * for this layers tree. This function should return false if there are no
    * last known zoom constraints.
    */
-  virtual bool GetRootZoomConstraints(bool* aOutAllowZoom,
-                                      CSSToScreenScale* aOutMinZoom,
-                                      CSSToScreenScale* aOutMaxZoom)
+  virtual bool GetRootZoomConstraints(ZoomConstraints* aOutConstraints)
   {
     return false;
   }
 
   /**
    * General tranformation notices for consumers. These fire any time
    * the apzc is modifying the view, including panning, zooming, and
    * fling.
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -479,17 +479,17 @@ TEST(AsyncPanZoomController, OverScrollP
 TEST(AsyncPanZoomController, ShortPress) {
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
     0, mcc, tm, AsyncPanZoomController::USE_GESTURE_DETECTOR);
 
   apzc->SetFrameMetrics(TestFrameMetrics());
   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
-  apzc->UpdateZoomConstraints(false, CSSToScreenScale(1.0), CSSToScreenScale(1.0));
+  apzc->UpdateZoomConstraints(ZoomConstraints(false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
 
   EXPECT_CALL(*mcc, HandleSingleTap(CSSIntPoint(10, 10), 0)).Times(1);
 
   int time = 0;
   nsEventStatus status = ApzcTap(apzc, 10, 10, time, 100);
   EXPECT_EQ(nsEventStatus_eIgnore, status);
 
   apzc->Destroy();
@@ -498,17 +498,17 @@ TEST(AsyncPanZoomController, ShortPress)
 TEST(AsyncPanZoomController, MediumPress) {
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
     0, mcc, tm, AsyncPanZoomController::USE_GESTURE_DETECTOR);
 
   apzc->SetFrameMetrics(TestFrameMetrics());
   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
-  apzc->UpdateZoomConstraints(false, CSSToScreenScale(1.0), CSSToScreenScale(1.0));
+  apzc->UpdateZoomConstraints(ZoomConstraints(false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
 
   EXPECT_CALL(*mcc, HandleSingleTap(CSSIntPoint(10, 10), 0)).Times(1);
 
   int time = 0;
   nsEventStatus status = ApzcTap(apzc, 10, 10, time, 400);
   EXPECT_EQ(nsEventStatus_eIgnore, status);
 
   apzc->Destroy();
@@ -517,17 +517,17 @@ TEST(AsyncPanZoomController, MediumPress
 TEST(AsyncPanZoomController, LongPress) {
   nsRefPtr<MockContentControllerDelayed> mcc = new MockContentControllerDelayed();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
     0, mcc, tm, AsyncPanZoomController::USE_GESTURE_DETECTOR);
 
   apzc->SetFrameMetrics(TestFrameMetrics());
   apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
-  apzc->UpdateZoomConstraints(false, CSSToScreenScale(1.0), CSSToScreenScale(1.0));
+  apzc->UpdateZoomConstraints(ZoomConstraints(false, CSSToScreenScale(1.0), CSSToScreenScale(1.0)));
 
   int time = 0;
 
   nsEventStatus status = ApzcDown(apzc, 10, 10, time);
   EXPECT_EQ(nsEventStatus_eConsumeNoDefault, status);
 
   Task* t = mcc->GetDelayedTask();
 
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -495,17 +495,16 @@ GetFrom(nsFrameLoader* aFrameLoader)
 }
 
 class RemoteContentController : public GeckoContentController {
 public:
   RemoteContentController(RenderFrameParent* aRenderFrame)
     : mUILoop(MessageLoop::current())
     , mRenderFrame(aRenderFrame)
     , mHaveZoomConstraints(false)
-    , mAllowZoom(true)
   { }
 
   virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) MOZ_OVERRIDE
   {
     // We always need to post requests into the "UI thread" otherwise the
     // requests may get processed out of order.
     mUILoop->PostTask(
       FROM_HERE,
@@ -606,34 +605,26 @@ public:
     }
   }
 
   virtual void PostDelayedTask(Task* aTask, int aDelayMs) MOZ_OVERRIDE
   {
     MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs);
   }
 
-  void SaveZoomConstraints(bool aAllowZoom,
-                           const CSSToScreenScale& aMinZoom,
-                           const CSSToScreenScale& aMaxZoom)
+  void SaveZoomConstraints(const ZoomConstraints& aConstraints)
   {
     mHaveZoomConstraints = true;
-    mAllowZoom = aAllowZoom;
-    mMinZoom = aMinZoom;
-    mMaxZoom = aMaxZoom;
+    mZoomConstraints = aConstraints;
   }
 
-  virtual bool GetRootZoomConstraints(bool* aOutAllowZoom,
-                                      CSSToScreenScale* aOutMinZoom,
-                                      CSSToScreenScale* aOutMaxZoom)
+  virtual bool GetRootZoomConstraints(ZoomConstraints* aOutConstraints)
   {
-    if (mHaveZoomConstraints) {
-      *aOutAllowZoom = mAllowZoom;
-      *aOutMinZoom = mMinZoom;
-      *aOutMaxZoom = mMaxZoom;
+    if (mHaveZoomConstraints && aOutConstraints) {
+      *aOutConstraints = mZoomConstraints;
     }
     return mHaveZoomConstraints;
   }
 
   virtual void NotifyTransformBegin(const ScrollableLayerGuid& aGuid)
   {
     if (MessageLoop::current() != mUILoop) {
       mUILoop->PostTask(
@@ -671,19 +662,17 @@ private:
       browser->UpdateFrame(aFrameMetrics);
     }
   }
 
   MessageLoop* mUILoop;
   RenderFrameParent* mRenderFrame;
 
   bool mHaveZoomConstraints;
-  bool mAllowZoom;
-  CSSToScreenScale mMinZoom;
-  CSSToScreenScale mMaxZoom;
+  ZoomConstraints mZoomConstraints;
 };
 
 RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader,
                                      ScrollingBehavior aScrollingBehavior,
                                      TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                      uint64_t* aId)
   : mLayersId(0)
   , mFrameLoader(aFrameLoader)
@@ -1086,26 +1075,24 @@ RenderFrameParent::ContentReceivedTouch(
     GetApzcTreeManager()->ContentReceivedTouch(aGuid, aPreventDefault);
   }
 }
 
 void
 RenderFrameParent::UpdateZoomConstraints(uint32_t aPresShellId,
                                          ViewID aViewId,
                                          bool aIsRoot,
-                                         bool aAllowZoom,
-                                         const CSSToScreenScale& aMinZoom,
-                                         const CSSToScreenScale& aMaxZoom)
+                                         const ZoomConstraints& aConstraints)
 {
   if (mContentController && aIsRoot) {
-    mContentController->SaveZoomConstraints(aAllowZoom, aMinZoom, aMaxZoom);
+    mContentController->SaveZoomConstraints(aConstraints);
   }
   if (GetApzcTreeManager()) {
     GetApzcTreeManager()->UpdateZoomConstraints(ScrollableLayerGuid(mLayersId, aPresShellId, aViewId),
-                                                aAllowZoom, aMinZoom, aMaxZoom);
+                                                aConstraints);
   }
 }
 
 bool
 RenderFrameParent::HitTest(const nsRect& aRect)
 {
   return mTouchRegion.Contains(aRect);
 }
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -44,16 +44,17 @@ class RenderFrameParent : public PRender
   typedef mozilla::layers::ContainerLayer ContainerLayer;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::TargetConfig TargetConfig;
   typedef mozilla::layers::LayerTransactionParent LayerTransactionParent;
   typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
   typedef mozilla::layers::TextureFactoryIdentifier TextureFactoryIdentifier;
   typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
+  typedef mozilla::layers::ZoomConstraints ZoomConstraints;
   typedef FrameMetrics::ViewID ViewID;
 
 public:
   typedef std::map<ViewID, nsRefPtr<nsContentView> > ViewMap;
 
   /**
    * Select the desired scrolling behavior.  If ASYNC_PAN_ZOOM is
    * chosen, then RenderFrameParent will watch input events and use
@@ -112,19 +113,17 @@ public:
   void ZoomToRect(uint32_t aPresShellId, ViewID aViewId, const CSSRect& aRect);
 
   void ContentReceivedTouch(const ScrollableLayerGuid& aGuid,
                             bool aPreventDefault);
 
   void UpdateZoomConstraints(uint32_t aPresShellId,
                              ViewID aViewId,
                              bool aIsRoot,
-                             bool aAllowZoom,
-                             const CSSToScreenScale& aMinZoom,
-                             const CSSToScreenScale& aMaxZoom);
+                             const ZoomConstraints& aConstraints);
 
   bool HitTest(const nsRect& aRect);
 
 protected:
   void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
   virtual bool RecvNotifyCompositorTransaction() MOZ_OVERRIDE;
 
--- a/widget/windows/winrt/MetroWidget.cpp
+++ b/widget/windows/winrt/MetroWidget.cpp
@@ -1610,12 +1610,13 @@ MetroWidget::Observe(nsISupports *subjec
 
     int reScan = swscanf(data, L"%d,%llu",
       &presShellId, &viewId);
     if (reScan != 2) {
       NS_WARNING("Malformed apzc-disable-zoom message");
     }
 
     ScrollableLayerGuid guid = ScrollableLayerGuid(mRootLayerTreeId, presShellId, viewId);
-    APZController::sAPZC->UpdateZoomConstraints(guid, false, CSSToScreenScale(1.0f), CSSToScreenScale(1.0f));
+    APZController::sAPZC->UpdateZoomConstraints(guid,
+      ZoomConstraints(false, CSSToScreenScale(1.0f), CSSToScreenScale(1.0f)));
   }
   return NS_OK;
 }