Bug 732016 Allow override of the scroll port size used for clamping scroll positions. r=roc
authorTimothy Nikkel <tnikkel@gmail.com>
Thu, 19 Apr 2012 20:54:54 -0500
changeset 95332 492d12fa8b657824f4620e70d87bea908076a2ba
parent 95331 3a9db9c55f140cf04d28157bb8c5e6d49cf5509b
child 95333 83faa1da3db83f3abec690d67f09e711af98d0f9
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
bugs732016
milestone14.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 732016 Allow override of the scroll port size used for clamping scroll positions. r=roc
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 (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);