Bug 732016 Allow override of the scroll port size used for clamping scroll positions. r=roc a=lsblakk
authorTimothy Nikkel <tnikkel@gmail.com>
Tue, 24 Apr 2012 13:52:35 -0500
changeset 95548 e08b460bcb6090cd5b6b8d982bf6d30245c249e8
parent 95547 00d9852452e5b3250242eeb7152d9d25a91c9794
child 95549 a38075d6e6d0d504ea0a5826334616d48bd4a27a
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, lsblakk
bugs732016
milestone14.0a2
Bug 732016 Allow override of the scroll port size used for clamping scroll positions. r=roc a=lsblakk
dom/base/nsDOMWindowUtils.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2312,8 +2312,31 @@ nsDOMWindowUtils::GetPlugins(JSContext* 
 
   JSObject* jsPlugins = nsnull;
   rv = nsTArrayToJSArray(cx, plugins, &jsPlugins);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aPlugins = OBJECT_TO_JSVAL(jsPlugins);
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsDOMWindowUtils::SetScrollPositionClampingScrollPortSize(float aWidth, float aHeight)
+{
+  if (!IsUniversalXPConnectCapable()) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+  if (!(aWidth >= 0.0 && aHeight >= 0.0)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  nsIPresShell* presShell = GetPresShell();
+  if (!presShell) {
+    return NS_ERROR_FAILURE;
+  }
+
+  presShell->SetScrollPositionClampingScrollPortSize(
+    nsPresContext::CSSPixelsToAppUnits(aWidth),
+    nsPresContext::CSSPixelsToAppUnits(aHeight));
+
+  return NS_OK;
+}
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -65,17 +65,17 @@ interface nsIDOMEvent;
 interface nsITransferable;
 interface nsIQueryContentEventResult;
 interface nsIDOMWindow;
 interface nsIDOMBlob;
 interface nsIDOMFile;
 interface nsIFile;
 interface nsIDOMTouch;
 
-[scriptable, uuid(c7f303a1-4f7b-4d38-a192-c3f0e25dadb1)]
+[scriptable, uuid(66a68858-df38-40e1-a792-fda04ebcc084)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -1105,9 +1105,17 @@ interface nsIDOMWindowUtils : nsISupport
    *
    * Cannot be accessed from unprivileged context (not content-accessible).
    * Will throw a DOM security error if called without UniversalXPConnect
    * privileges.
    *
    */
   [implicit_jscontext]
   readonly attribute jsval plugins;
+
+  /**
+   * Set the scrollport size for the purposes of clamping scroll positions for
+   * the root scroll frame of this document to be (aWidth,aHeight) in CSS pixels.
+   *
+   * The caller of this method must have UniversalXPConnect privileges.
+   */
+  void setScrollPositionClampingScrollPortSize(in float aWidth, in float aHeight);
 };
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -1260,16 +1260,25 @@ public:
    */
   static void InitializeStatics();
   static void ReleaseStatics();
 
   // If a frame in the subtree rooted at aFrame is capturing the mouse then
   // clears that capture.
   static void ClearMouseCapture(nsIFrame* aFrame);
 
+  void SetScrollPositionClampingScrollPortSize(nscoord aWidth, nscoord aHeight);
+  bool IsScrollPositionClampingScrollPortSizeSet() {
+    return mScrollPositionClampingScrollPortSizeSet;
+  }
+  nsSize GetScrollPositionClampingScrollPortSize() {
+    NS_ASSERTION(mScrollPositionClampingScrollPortSizeSet, "asking for scroll port when its not set?");
+    return mScrollPositionClampingScrollPortSize;
+  }
+
 protected:
   friend class nsRefreshDriver;
 
   // IMPORTANT: The ownership implicit in the following member variables
   // has been explicitly checked.  If you add any members to this class,
   // please make the ownership explicit (pinkerton, scc).
 
   // these are the same Document and PresContext owned by the DocViewer.
@@ -1310,16 +1319,18 @@ protected:
 
   bool                      mReflowScheduled; // If true, we have a reflow
                                               // scheduled. Guaranteed to be
                                               // false if mReflowContinueTimer
                                               // is non-null.
 
   bool                      mSuppressInterruptibleReflows;
 
+  bool                      mScrollPositionClampingScrollPortSizeSet;
+
   // A list of weak frames. This is a pointer to the last item in the list.
   nsWeakFrame*              mWeakFrames;
 
   // Most recent canvas background color.
   nscolor                   mCanvasBackgroundColor;
 
   // Flags controlling how our document is rendered.  These persist
   // between paints and so are tied with retained layer pixels.
@@ -1328,16 +1339,18 @@ protected:
   // re-use old pixels.
   PRUint32                  mRenderFlags;
 
   // Used to force allocation and rendering of proportionally more or
   // less pixels in the given dimension.
   float                     mXResolution;
   float                     mYResolution;
 
+  nsSize                    mScrollPositionClampingScrollPortSize;
+
   static nsIContent* gKeyDownTarget;
 };
 
 /**
  * Create a new empty presentation shell. Upon success, call Init
  * before attempting to use the shell.
  */
 nsresult
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -826,16 +826,18 @@ PresShell::PresShell()
 #ifdef DEBUG
   mPresArenaAllocCount = 0;
 #endif
   mRenderFlags = 0;
   mXResolution = 1.0;
   mYResolution = 1.0;
   mViewportOverridden = false;
 
+  mScrollPositionClampingScrollPortSizeSet = false;
+
   static bool addedSynthMouseMove = false;
   if (!addedSynthMouseMove) {
     Preferences::AddBoolVarCache(&sSynthMouseMove,
                                  "layout.reflow.synthMouseMove", true);
     addedSynthMouseMove = true;
   }
 }
 
@@ -9142,8 +9144,15 @@ PresShell::SizeOfTextRuns(nsMallocSizeOf
   nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, nsnull,
                                          /* clear = */true);
 
   // collect the total memory in use for textruns
   return nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, aMallocSizeOf,
                                                 /* clear = */false);
 }
 
+void
+nsIPresShell::SetScrollPositionClampingScrollPortSize(nscoord aWidth, nscoord aHeight)
+{
+  mScrollPositionClampingScrollPortSizeSet = true;
+  mScrollPositionClampingScrollPortSize.width = aWidth;
+  mScrollPositionClampingScrollPortSize.height = aHeight;
+}
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1640,17 +1640,17 @@ Clamp(nscoord aLower, nscoord aVal, nsco
   if (aVal > aUpper)
     return aUpper;
   return aVal;
 }
 
 nsPoint
 nsGfxScrollFrameInner::ClampScrollPosition(const nsPoint& aPt) const
 {
-  nsRect range = GetScrollRange();
+  nsRect range = GetScrollRangeForClamping();
   return nsPoint(Clamp(range.x, aPt.x, range.XMost()),
                  Clamp(range.y, aPt.y, range.YMost()));
 }
 
 /*
  * Callback function from timer used in nsGfxScrollFrameInner::ScrollTo
  */
 void
@@ -1966,17 +1966,17 @@ nsGfxScrollFrameInner::RestrictToDevPixe
                                            bool aShouldClamp) const
 {
   nsPresContext* presContext = mOuter->PresContext();
   nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
   // Convert to device pixels so we scroll to an integer offset of device
   // pixels. But we also need to make sure that our position remains
   // inside the allowed region.
   if (aShouldClamp) {
-    nsRect scrollRange = GetScrollRange();
+    nsRect scrollRange = GetScrollRangeForClamping();
     *aPtDevPx = nsIntPoint(ClampInt(scrollRange.x, aPt.x, scrollRange.XMost(), appUnitsPerDevPixel),
                            ClampInt(scrollRange.y, aPt.y, scrollRange.YMost(), appUnitsPerDevPixel));
   } else {
     *aPtDevPx = nsIntPoint(NSAppUnitsToIntPixels(aPt.x, appUnitsPerDevPixel),
                            NSAppUnitsToIntPixels(aPt.y, appUnitsPerDevPixel));
   }
   return nsPoint(NSIntPixelsToAppUnits(aPtDevPx->x, appUnitsPerDevPixel),
                  NSIntPixelsToAppUnits(aPtDevPx->y, appUnitsPerDevPixel));
@@ -2322,31 +2322,48 @@ static nscoord
 AlignToDevPixelRoundingToZero(nscoord aVal, PRInt32 aAppUnitsPerDevPixel)
 {
   return (aVal/aAppUnitsPerDevPixel)*aAppUnitsPerDevPixel;
 }
 
 nsRect
 nsGfxScrollFrameInner::GetScrollRange() const
 {
+  return GetScrollRange(mScrollPort.width, mScrollPort.height);
+}
+
+nsRect
+nsGfxScrollFrameInner::GetScrollRange(nscoord aWidth, nscoord aHeight) const
+{
   nsRect range = GetScrolledRect();
-  range.width -= mScrollPort.width;
-  range.height -= mScrollPort.height;
+  range.width -= aWidth;
+  range.height -= aHeight;
 
   nsPresContext* presContext = mOuter->PresContext();
   PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
   range.width =
     AlignToDevPixelRoundingToZero(range.XMost(), appUnitsPerDevPixel) - range.x;
   range.height =
     AlignToDevPixelRoundingToZero(range.YMost(), appUnitsPerDevPixel) - range.y;
   range.x = AlignToDevPixelRoundingToZero(range.x, appUnitsPerDevPixel);
   range.y = AlignToDevPixelRoundingToZero(range.y, appUnitsPerDevPixel);
   return range;
 }
 
+nsRect
+nsGfxScrollFrameInner::GetScrollRangeForClamping() const
+{
+  nsIPresShell* presShell = mOuter->PresContext()->PresShell();
+  if (mIsRoot && presShell->IsScrollPositionClampingScrollPortSizeSet()) {
+    nsSize size = presShell->GetScrollPositionClampingScrollPortSize();
+    return GetScrollRange(size.width, size.height);
+  }
+  return GetScrollRange();
+}
+
 static void
 AdjustForWholeDelta(PRInt32 aDelta, nscoord* aCoord)
 {
   if (aDelta < 0) {
     *aCoord = nscoord_MIN;
   } else if (aDelta > 0) {
     *aCoord = nscoord_MAX;
   }
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -173,17 +173,22 @@ public:
     nsPoint pt;
     pt.x = IsLTR() ?
       mScrollPort.x - mScrolledFrame->GetPosition().x :
       mScrollPort.XMost() - mScrolledFrame->GetRect().XMost();
     pt.y = mScrollPort.y - mScrolledFrame->GetPosition().y;
     return pt;
   }
   nsRect GetScrollRange() const;
+  // Get the scroll range assuming the scrollport has size (aWidth, aHeight).
+  nsRect GetScrollRange(nscoord aWidth, nscoord aHeight) const;
+protected:
+  nsRect GetScrollRangeForClamping() const;
 
+public:
   nsPoint RestrictToDevPixels(const nsPoint& aPt, nsIntPoint* aPtDevPx, bool aShouldClamp) const;
   nsPoint ClampScrollPosition(const nsPoint& aPt) const;
   static void AsyncScrollCallback(nsITimer *aTimer, void* anInstance);
   void ScrollTo(nsPoint aScrollPosition, nsIScrollableFrame::ScrollMode aMode) {
     ScrollToWithOrigin(aScrollPosition, aMode, nsGkAtoms::other);
   };
   void ScrollToImpl(nsPoint aScrollPosition);
   void ScrollVisual(nsPoint aOldScrolledFramePosition);