Bug 584703. Compute XUL listbox contents overlow area correctly. r=enndeakin
authorRobert O'Callahan <robert@ocallahan.org>
Mon, 06 Sep 2010 15:23:44 +1200
changeset 52060 40f76b916195940b6ed9b41b190be1ba538c4b5b
parent 52059 d4e3befbd494043852e11f13c3584b5b4d352edc
child 52061 e560e0fe90d17de4333d04d1b3eb213b81a63a1d
push idunknown
push userunknown
push dateunknown
reviewersenndeakin
bugs584703
milestone2.0b6pre
Bug 584703. Compute XUL listbox contents overlow area correctly. r=enndeakin
layout/xul/base/src/nsListBoxBodyFrame.cpp
layout/xul/base/src/nsListBoxBodyFrame.h
toolkit/content/tests/widgets/test_hiddenpaging.xul
--- a/layout/xul/base/src/nsListBoxBodyFrame.cpp
+++ b/layout/xul/base/src/nsListBoxBodyFrame.cpp
@@ -285,16 +285,34 @@ nsListBoxBodyFrame::MarkIntrinsicWidthsD
 NS_IMETHODIMP
 nsListBoxBodyFrame::DoLayout(nsBoxLayoutState& aBoxLayoutState)
 {
   if (mScrolling)
     aBoxLayoutState.SetPaintingDisabled(PR_TRUE);
 
   nsresult rv = nsBoxFrame::DoLayout(aBoxLayoutState);
 
+  // determine the real height for the scrollable area from the total number
+  // of rows, since non-visible rows don't yet have frames
+  nsSize size = GetSize();
+  nsRect overflowRect = nsRect(nsPoint(0, 0), size);
+  if (mLayoutManager) {
+    nsIFrame* childFrame = mFrames.FirstChild();
+    while (childFrame) {
+      ConsiderChildOverflow(overflowRect, childFrame);
+      childFrame = childFrame->GetNextSibling();
+    }
+
+    nsSize prefSize = mLayoutManager->GetPrefSize(this, aBoxLayoutState);
+    if (prefSize.height > overflowRect.height) {
+      overflowRect.height = prefSize.height;
+    }
+  }
+  FinishAndStoreOverflow(&overflowRect, GetSize());
+
   if (mScrolling)
     aBoxLayoutState.SetPaintingDisabled(PR_FALSE);
 
   // if we are scrolled and the row height changed
   // make sure we are scrolled to a correct index.
   if (mAdjustScroll)
      PostReflowCallback();
 
--- a/layout/xul/base/src/nsListBoxBodyFrame.h
+++ b/layout/xul/base/src/nsListBoxBodyFrame.h
@@ -151,16 +151,18 @@ public:
   {
     NS_ENSURE_TRUE(!mBoxObject, PR_FALSE);
     mBoxObject = aBoxObject;
     return PR_TRUE;
   }
 
   virtual PRBool SupportsOrdinalsInChildren();
 
+  virtual PRBool ComputesOwnOverflowArea() { return PR_TRUE; }
+
 protected:
   class nsPositionChangedEvent;
   friend class nsPositionChangedEvent;
 
   class nsPositionChangedEvent : public nsRunnable
   {
   public:
     nsPositionChangedEvent(nsListBoxBodyFrame* aFrame,
--- a/toolkit/content/tests/widgets/test_hiddenpaging.xul
+++ b/toolkit/content/tests/widgets/test_hiddenpaging.xul
@@ -99,16 +99,18 @@ function testListbox()
   var listbox = document.getElementById(id);
 
   // Check that a scrollbar is visible by comparing the width of the listitem
   // with the width of the listbox. This is a simple way to do this without
   // checking the anonymous content.
   ok(listbox.firstChild.getBoundingClientRect().width < listbox.getBoundingClientRect().width - 10,
      id + ": Scrollbar visible");
 
+  var rowHeight = listbox.firstChild.getBoundingClientRect().height;
+
   listbox.selectedIndex = 0;
   sendKey("PAGE_DOWN", id);
   is(listbox.selectedItem.id, id + "_item8", id + ": Page down should go to the item one visible page away");
   is(listbox.getIndexOfFirstVisibleRow(), 7, id + ": Page down should have scrolled down a visible page");
   sendKey("PAGE_DOWN", id);
   is(listbox.selectedItem.id, id + "_item13", id + ": Second page down should go to the item two visible pages away");
   is(listbox.getIndexOfFirstVisibleRow(), 9, id + ": Second page down should not scroll beyond the end");
   sendKey("PAGE_DOWN", id);
@@ -119,16 +121,37 @@ function testListbox()
   // the listScrollbox seems to go haywire when scrolling up with hidden listitems
   todo_is(listbox.getIndexOfFirstVisibleRow(), 3, id + ": Page up should scroll up a visible page");
   sendKey("PAGE_UP", id);
   is(listbox.selectedItem.id, id + "_item2", id + ": Second page up should go to the item two visible pages away");
   is(listbox.getIndexOfFirstVisibleRow(), 0, id + ": Second page up should not scroll beyond the start");
   sendKey("PAGE_UP", id);
   is(listbox.selectedItem.id, id + "_item1", id + ": Third page up should return to the first visible item");
   is(listbox.getIndexOfFirstVisibleRow(), 0, id + ": Third page up should not have scrolled at all");
+
+  var scrollHeight = document.getAnonymousNodes(listbox)[1].lastChild.scrollHeight;
+  is(scrollHeight, rowHeight * 15, id + ": scrollHeight when rows set");
+
+  listbox.minHeight = 50;
+  scrollHeight = document.getAnonymousNodes(listbox)[1].lastChild.scrollHeight;
+  is(scrollHeight, rowHeight * 15, id + ": scrollHeight when rows and minimium height set");
+
+  listbox.removeAttribute("rows");
+
+  var availHeight = document.getAnonymousNodes(listbox)[1].lastChild.getBoundingClientRect().height;
+  // The listbox layout adds this extra height in GetPrefSize. Not sure what it's for though.
+  var e = (rowHeight * 15 - availHeight) % rowHeight;
+  var extraHeight = (e == 0) ? 0 : rowHeight - e;
+
+  scrollHeight = document.getAnonymousNodes(listbox)[1].lastChild.scrollHeight;
+  is(scrollHeight, rowHeight * 15 + extraHeight, id + ": scrollHeight when minimium height set");
+
+  listbox.removeAttribute("minheight");
+  scrollHeight = document.getAnonymousNodes(listbox)[1].lastChild.scrollHeight;
+  is(scrollHeight, rowHeight * 15 + extraHeight, id + ": scrollHeight");
 }
 
 window.onload = function runTests() {
   testRichlistbox();
   testListbox();
   SimpleTest.finish();
 };
   ]]></script>