Bug 375304. Fix absolute positioning where the abs-pos container is scrollable and has a height constrained by min-height etc. Patch by Eli Friedman, r+sr=roc
authorroc+@cs.cmu.edu
Sat, 01 Dec 2007 02:38:09 -0800
changeset 8518 7ee55d6fd44e71970969bacc694bcf737ef1d696
parent 8517 c9aa8cf5984e48e96e36b06c8816892c58014950
child 8519 5e1ba80ae89a4d645f1ca01dc40f36c47c97f59a
push idunknown
push userunknown
push dateunknown
bugs375304
milestone1.9b2pre
Bug 375304. Fix absolute positioning where the abs-pos container is scrollable and has a height constrained by min-height etc. Patch by Eli Friedman, r+sr=roc
layout/generic/nsBlockFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsHTMLReflowState.cpp
layout/reftests/percent-overflow-sizing/greenbox.html
layout/reftests/percent-overflow-sizing/greenboxhbar.html
layout/reftests/percent-overflow-sizing/hScrollAbsHeight.html
layout/reftests/percent-overflow-sizing/hScrollAbsHeightD.html
layout/reftests/percent-overflow-sizing/hScrollAbsHeightQuirks.html
layout/reftests/percent-overflow-sizing/hScrollAbsHeightQuirksD.html
layout/reftests/percent-overflow-sizing/hScrollAbsMinHeightD.html
layout/reftests/percent-overflow-sizing/hScrollAbsMinHeightQuirksD.html
layout/reftests/percent-overflow-sizing/hScrollSimpleHeight.html
layout/reftests/percent-overflow-sizing/hScrollSimpleHeightD.html
layout/reftests/percent-overflow-sizing/hScrollSimpleHeightQuirks-1.html
layout/reftests/percent-overflow-sizing/hScrollSimpleHeightQuirks-1D.html
layout/reftests/percent-overflow-sizing/hScrollSimpleHeightQuirks-2.html
layout/reftests/percent-overflow-sizing/hScrollSimpleHeightQuirks-2D.html
layout/reftests/percent-overflow-sizing/hScrollSimpleHeightQuirks-3.html
layout/reftests/percent-overflow-sizing/hScrollSimpleHeightQuirks-3D.html
layout/reftests/percent-overflow-sizing/hScrollSimpleMinHeightD.html
layout/reftests/percent-overflow-sizing/hScrollSimpleMinHeightQuirks-1D.html
layout/reftests/percent-overflow-sizing/hScrollSimpleMinHeightQuirks-3D.html
layout/reftests/percent-overflow-sizing/reftest.list
layout/reftests/percent-overflow-sizing/simpleAbsHeight.html
layout/reftests/percent-overflow-sizing/simpleAbsHeightD.html
layout/reftests/percent-overflow-sizing/simpleAbsMinHeightD.html
layout/reftests/percent-overflow-sizing/simpleHeight100.html
layout/reftests/percent-overflow-sizing/simpleHeight100D.html
layout/reftests/percent-overflow-sizing/simpleMinHeight100D.html
layout/reftests/reftest.list
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -779,22 +779,18 @@ nsBlockFrame::ComputeTightBounds(gfxCont
 
 static nsSize
 CalculateContainingBlockSizeForAbsolutes(const nsHTMLReflowState& aReflowState,
                                          nsSize aFrameSize)
 {
   // The issue here is that for a 'height' of 'auto' the reflow state
   // code won't know how to calculate the containing block height
   // because it's calculated bottom up. So we use our own computed
-  // size as the dimensions. We don't really want to do this for the
-  // initial containing block
+  // size as the dimensions.
   nsIFrame* frame = aReflowState.frame;
-  if (nsLayoutUtils::IsInitialContainingBlock(frame)) {
-    return nsSize(-1, -1);
-  }
 
   nsSize cbSize(aFrameSize);
     // Containing block is relative to the padding edge
   const nsMargin& border = aReflowState.mStyleBorder->GetBorder();
   cbSize.width -= border.left + border.right;
   cbSize.height -= border.top + border.bottom;
 
   if (frame->GetParent()->GetContent() == frame->GetContent()) {
@@ -820,23 +816,19 @@ CalculateContainingBlockSizeForAbsolutes
       // padding-edge. We need better APIs for getting the various boxes from a frame.
       nsIScrollableFrame* scrollFrame;
       CallQueryInterface(aLastRS->frame, &scrollFrame);
       nsMargin scrollbars(0,0,0,0);
       if (scrollFrame) {
         nsBoxLayoutState dummyState(aLastRS->frame->PresContext(),
                                     aLastRS->rendContext);
         scrollbars = scrollFrame->GetDesiredScrollbarSizes(&dummyState);
-        // XXX We should account for the horizontal scrollbar too --- but currently
-        // nsGfxScrollFrame assumes nothing depends on the presence (or absence) of
-        // a horizontal scrollbar, so accounting for it would create incremental
-        // reflow bugs.
-        //if (!lastButOneRS->mFlags.mAssumingHScrollbar) {
+        if (!lastButOneRS->mFlags.mAssumingHScrollbar) {
           scrollbars.top = scrollbars.bottom = 0;
-        //}
+        }
         if (!lastButOneRS->mFlags.mAssumingVScrollbar) {
           scrollbars.left = scrollbars.right = 0;
         }
       }
       // We found a reflow state for the outermost wrapping frame, so use
       // its computed metrics if available
       if (aLastRS->ComputedWidth() != NS_UNCONSTRAINEDSIZE) {
         cbSize.width = PR_MAX(0,
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -415,16 +415,29 @@ nsHTMLScrollFrame::ReflowScrolledFrame(c
                                        PRBool aFirstPass)
 {
   // these could be NS_UNCONSTRAINEDSIZE ... PR_MIN arithmetic should
   // be OK
   nscoord paddingLR = aState.mReflowState.mComputedPadding.LeftRight();
 
   nscoord availWidth = aState.mReflowState.ComputedWidth() + paddingLR;
 
+  nscoord computedHeight = aState.mReflowState.ComputedHeight();
+  nscoord computedMinHeight = aState.mReflowState.mComputedMinHeight;
+  nscoord computedMaxHeight = aState.mReflowState.mComputedMaxHeight;
+  if (aAssumeHScroll) {
+    nsSize hScrollbarPrefSize = 
+      mInner.mHScrollbarBox->GetPrefSize(const_cast<nsBoxLayoutState&>(aState.mBoxState));
+    if (computedHeight != NS_UNCONSTRAINEDSIZE)
+      computedHeight = PR_MAX(0, computedHeight - hScrollbarPrefSize.height);
+    computedMinHeight = PR_MAX(0, computedMinHeight - hScrollbarPrefSize.height);
+    if (computedMaxHeight != NS_UNCONSTRAINEDSIZE)
+      computedMaxHeight = PR_MAX(0, computedMaxHeight - hScrollbarPrefSize.height);
+  }
+  
   if (aAssumeVScroll) {
     nsSize vScrollbarPrefSize = 
       mInner.mVScrollbarBox->GetPrefSize(const_cast<nsBoxLayoutState&>(aState.mBoxState));
     availWidth = PR_MAX(0, availWidth - vScrollbarPrefSize.width);
   }
 
   // We're forcing the padding on our scrolled frame, so let it know what that
   // padding is.
@@ -438,16 +451,19 @@ nsHTMLScrollFrame::ReflowScrolledFrame(c
   nsHTMLReflowState kidReflowState(presContext, aState.mReflowState,
                                    mInner.mScrolledFrame,
                                    nsSize(availWidth, NS_UNCONSTRAINEDSIZE),
                                    -1, -1, PR_FALSE);
   kidReflowState.Init(presContext, -1, -1, nsnull,
                       &aState.mReflowState.mComputedPadding);
   kidReflowState.mFlags.mAssumingHScrollbar = aAssumeHScroll;
   kidReflowState.mFlags.mAssumingVScrollbar = aAssumeVScroll;
+  kidReflowState.SetComputedHeight(computedHeight);
+  kidReflowState.mComputedMinHeight = computedMinHeight;
+  kidReflowState.mComputedMaxHeight = computedMaxHeight;
 
   nsReflowStatus status;
   nsresult rv = ReflowChild(mInner.mScrolledFrame, presContext, *aMetrics,
                             kidReflowState, 0, 0,
                             NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_MOVE_VIEW, status);
   // Don't resize or position the view because we're going to resize
   // it to the correct size anyway in PlaceScrollArea. Allowing it to
   // resize here would size it to the natural height of the frame,
@@ -521,23 +537,24 @@ nsHTMLScrollFrame::InInitialReflow() con
   // assumption, because our initial reflow is no longer synchronous).
   return !mInner.mIsRoot && (GetStateBits() & NS_FRAME_FIRST_REFLOW);
 }
 
 nsresult
 nsHTMLScrollFrame::ReflowContents(ScrollReflowState* aState,
                                   const nsHTMLReflowMetrics& aDesiredSize)
 {
-  PRBool currentlyUsingVScrollbar = GuessVScrollbarNeeded(*aState);
+  PRBool lastUsedVScrollbar = GuessVScrollbarNeeded(*aState);
+  PRBool lastUsedHScrollbar = mInner.mHasHorizontalScrollbar; // XXX is this good enough?
   nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mFlags);
-  nsresult rv = ReflowScrolledFrame(*aState, PR_FALSE, currentlyUsingVScrollbar,
+  nsresult rv = ReflowScrolledFrame(*aState, lastUsedHScrollbar, lastUsedVScrollbar,
                                     &kidDesiredSize, PR_TRUE);
-  if (NS_FAILED(rv))
-    return rv;
-  PRBool didUseScrollbar = currentlyUsingVScrollbar;
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PRBool relativeHeight = (mInner.mScrolledFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT) != 0;
 
   // There's an important special case ... if the child appears to fit
   // in the inside-border rect (but overflows the scrollport), we
   // should try laying it out without a vertical scrollbar. It will
   // usually fit because making the available-width wider will not
   // normally make the child taller. (The only situation I can think
   // of is when you have a line containing %-width inline replaced
   // elements whose percentages sum to more than 100%, so increasing
@@ -545,75 +562,88 @@ nsHTMLScrollFrame::ReflowContents(Scroll
   // before.) If we don't treat this case specially, then we will
   // decide that showing scrollbars is OK because the content
   // overflows when we're showing scrollbars and we won't try to
   // remove the vertical scrollbar.
 
   // Detecting when we enter this special case is important for when
   // people design layouts that exactly fit the container "most of the
   // time".
-  if (currentlyUsingVScrollbar &&
+
+  // XXX Is this check really sufficient to catch all the incremental cases
+  // where the ideal case doesn't have a scrollbar?
+  if ((lastUsedVScrollbar || (lastUsedHScrollbar && relativeHeight)) &&
       aState->mStyles.mVertical != NS_STYLE_OVERFLOW_SCROLL &&
       aState->mStyles.mHorizontal != NS_STYLE_OVERFLOW_SCROLL) {
     nsSize insideBorderSize =
       ComputeInsideBorderSize(aState,
                               nsSize(kidDesiredSize.width, kidDesiredSize.height));
     nsRect scrolledRect = mInner.GetScrolledRect(insideBorderSize);
     if (nsRect(nsPoint(0, 0), insideBorderSize).Contains(scrolledRect)) {
       // Let's pretend we had no vertical scrollbar coming in here
-      currentlyUsingVScrollbar = PR_FALSE;
-      rv = ReflowScrolledFrame(*aState, PR_FALSE, currentlyUsingVScrollbar,
+      rv = ReflowScrolledFrame(*aState, PR_FALSE, PR_FALSE,
                                &kidDesiredSize, PR_FALSE);
-      if (NS_FAILED(rv))
-        return rv;
-      didUseScrollbar = PR_FALSE;
+      NS_ENSURE_SUCCESS(rv, rv);
+      lastUsedVScrollbar = PR_FALSE;
+      lastUsedHScrollbar = PR_FALSE;
     }
   }
 
   // First try a layout without a horizontal scrollbar, then with.
-  if (TryLayout(aState, kidDesiredSize, didUseScrollbar, PR_FALSE, PR_FALSE))
-    return NS_OK;
-  // XXX Adding a horizontal scrollbar could cause absolute children positioned
-  // relative to the bottom padding-edge to need to be reflowed. But we don't,
-  // because that would be slow.
-  if (TryLayout(aState, kidDesiredSize, didUseScrollbar, PR_TRUE, PR_FALSE))
-    return NS_OK;
+  if (!relativeHeight) {
+    if (TryLayout(aState, kidDesiredSize, lastUsedVScrollbar, PR_FALSE, PR_FALSE))
+      return NS_OK;
+
+    if (TryLayout(aState, kidDesiredSize, lastUsedVScrollbar, PR_TRUE, PR_FALSE))
+      return NS_OK;
+  } else {
+    if (TryLayout(aState, kidDesiredSize, lastUsedVScrollbar, lastUsedHScrollbar, PR_FALSE))
+      return NS_OK;
+  }
 
   PRBool canHaveVerticalScrollbar =
     aState->mStyles.mVertical != NS_STYLE_OVERFLOW_HIDDEN;
+  PRBool canHaveHorizontalScrollbar =
+    aState->mStyles.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN;
+
   // That didn't work. Try the other setting for the vertical scrollbar.
   // But don't try to show a scrollbar if we know there can't be one.
-  if (currentlyUsingVScrollbar || canHaveVerticalScrollbar) {
-    nsHTMLReflowMetrics kidRetrySize(aDesiredSize.mFlags);
-    rv = ReflowScrolledFrame(*aState, PR_FALSE, !currentlyUsingVScrollbar,
-                             &kidRetrySize, PR_FALSE);
-    if (NS_FAILED(rv))
-      return rv;
-    didUseScrollbar = !currentlyUsingVScrollbar;
-    // XXX Adding a horizontal scrollbar could cause absolute children positioned
-    // relative to the bottom padding-edge to need to be reflowed. But we don't,
-    // because that would be slow.
-    if (TryLayout(aState, kidRetrySize, didUseScrollbar, PR_FALSE, PR_FALSE))
-      return NS_OK;
-    if (TryLayout(aState, kidRetrySize, didUseScrollbar, PR_TRUE, PR_FALSE))
-      return NS_OK;
-
-    NS_WARNING("Strange content ... we can't find logically consistent scrollbar settings");
-  } else {
-    NS_WARNING("Strange content ... we can't find logically consistent scrollbar settings");
+  if (lastUsedVScrollbar || canHaveVerticalScrollbar) {
+    rv = ReflowScrolledFrame(*aState, PR_FALSE, !lastUsedVScrollbar,
+                             &kidDesiredSize, PR_FALSE);
+    NS_ENSURE_SUCCESS(rv, rv);
+    lastUsedHScrollbar = PR_FALSE;
+    lastUsedVScrollbar = !lastUsedVScrollbar;
+    if (!relativeHeight) {
+      if (TryLayout(aState, kidDesiredSize, lastUsedVScrollbar, PR_FALSE, PR_FALSE))
+        return NS_OK;
+      if (TryLayout(aState, kidDesiredSize, lastUsedVScrollbar, PR_TRUE, PR_FALSE))
+        return NS_OK;
+    } else {
+      if (TryLayout(aState, kidDesiredSize, lastUsedVScrollbar, lastUsedHScrollbar, PR_FALSE))
+        return NS_OK;
+    }
   }
 
-  // Fall back to no scrollbars --- even if NS_STYLE_OVERFLOW_SCROLL is
-  // in effect. They might not fit anyway.
-  if (didUseScrollbar) {
-    rv = ReflowScrolledFrame(*aState, PR_FALSE, PR_FALSE, &kidDesiredSize, PR_FALSE);
-    if (NS_FAILED(rv))
-      return rv;
+  if ((lastUsedHScrollbar || canHaveHorizontalScrollbar) && relativeHeight) {
+    rv = ReflowScrolledFrame(*aState, PR_TRUE, PR_FALSE,
+                             &kidDesiredSize, PR_FALSE);
+    lastUsedHScrollbar = PR_TRUE;
+    lastUsedVScrollbar = PR_FALSE;
+    NS_ENSURE_SUCCESS(rv, rv);
+    if (TryLayout(aState, kidDesiredSize, lastUsedVScrollbar, lastUsedHScrollbar, PR_FALSE))
+      return NS_OK;
   }
-  TryLayout(aState, kidDesiredSize, PR_FALSE, PR_FALSE, PR_TRUE);
+
+  rv = ReflowScrolledFrame(*aState, PR_TRUE, PR_TRUE,
+                           &kidDesiredSize, PR_FALSE);
+  lastUsedHScrollbar = PR_TRUE;
+  lastUsedVScrollbar = PR_TRUE;
+  NS_ENSURE_SUCCESS(rv, rv);
+  TryLayout(aState, kidDesiredSize, lastUsedVScrollbar, lastUsedHScrollbar, PR_TRUE);
   return NS_OK;
 }
 
 void
 nsHTMLScrollFrame::PlaceScrollArea(const ScrollReflowState& aState)
 {
   nsIView* scrollView = mInner.mScrollableView->View();
   nsIViewManager* vm = scrollView->GetViewManager();
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -357,26 +357,17 @@ void nsHTMLReflowState::InitCBReflowStat
  * this function as well
  */
 static PRBool
 IsQuirkContainingBlockHeight(const nsHTMLReflowState* rs) 
 {
   nsIAtom* frameType = rs->frame->GetType();
   if (nsGkAtoms::blockFrame == frameType ||
       nsGkAtoms::areaFrame == frameType ||
-      nsGkAtoms::scrollFrame == frameType) {  
-
-    if (nsGkAtoms::areaFrame == frameType) {
-      // Skip over scrolled-content area frames
-      if (rs->frame->GetStyleContext()->GetPseudoType() ==
-          nsCSSAnonBoxes::scrolledContent) {
-        return PR_FALSE;
-      }
-    }
-    
+      nsGkAtoms::scrollFrame == frameType) {
     // Note: This next condition could change due to a style change,
     // but that would cause a style reflow anyway, which means we're ok.
     if (NS_AUTOHEIGHT == rs->ComputedHeight()) {
       if (!rs->frame->GetStyleDisplay()->IsAbsolutelyPositioned()) {
         return PR_FALSE;
       }
     }
   }
@@ -419,17 +410,17 @@ nsHTMLReflowState::InitResizeFlags(nsPre
                         mComputedHeight + mComputedBorderPadding.TopBottom();
   }
 
   const PRBool dependsOnCBHeight =
     mStylePosition->mHeight.GetUnit() == eStyleUnit_Percent ||
     mStylePosition->mMinHeight.GetUnit() == eStyleUnit_Percent ||
     mStylePosition->mMaxHeight.GetUnit() == eStyleUnit_Percent ||
     mStylePosition->mOffset.GetTopUnit() == eStyleUnit_Percent ||
-    mStylePosition->mOffset.GetBottomUnit() == eStyleUnit_Percent ||
+    mStylePosition->mOffset.GetBottomUnit() != eStyleUnit_Auto ||
     frame->IsBoxFrame() ||
     frame->GetIntrinsicSize().height.GetUnit() == eStyleUnit_Percent;
 
   // If we're the child of a table cell that performs special height
   // reflows and we could be the child that requires them, always set
   // the vertical resize in case this is the first pass before the
   // special height reflow.
   if (!mFlags.mVResize && mCBReflowState &&
@@ -1412,24 +1403,16 @@ CalcQuirkContainingBlockHeight(const nsH
   const nsHTMLReflowState* rs = aCBReflowState;
   for (; rs; rs = (nsHTMLReflowState *)(rs->parentReflowState)) { 
     nsIAtom* frameType = rs->frame->GetType();
     // if the ancestor is auto height then skip it and continue up if it 
     // is the first block/area frame and possibly the body/html
     if (nsGkAtoms::blockFrame == frameType ||
         nsGkAtoms::areaFrame == frameType ||
         nsGkAtoms::scrollFrame == frameType) {
-      
-      if (nsGkAtoms::areaFrame == frameType) {
-        // Skip over scrolled-content area frames
-        if (rs->frame->GetStyleContext()->GetPseudoType() ==
-            nsCSSAnonBoxes::scrolledContent) {
-          continue;
-        }
-      }
 
       secondAncestorRS = firstAncestorRS;
       firstAncestorRS = (nsHTMLReflowState*)rs;
 
       // If the current frame we're looking at is positioned, we don't want to
       // go any further (see bug 221784).  The behavior we want here is: 1) If
       // not auto-height, use this as the percentage base.  2) If auto-height,
       // keep looking, unless the frame is positioned.
@@ -1437,22 +1420,17 @@ CalcQuirkContainingBlockHeight(const nsH
         if (rs->frame->GetStyleDisplay()->IsAbsolutelyPositioned()) {
           break;
         } else {
           continue;
         }
       }
     }
     else if (nsGkAtoms::canvasFrame == frameType) {
-      // Use scroll frames' computed height if we have one, this will
-      // allow us to get viewport height for native scrollbars.
-      nsHTMLReflowState* scrollState = (nsHTMLReflowState *)rs->parentReflowState;
-      if (nsGkAtoms::scrollFrame == scrollState->frame->GetType()) {
-        rs = scrollState;
-      }
+      // Always continue on to the height calculation
     }
     else if (nsGkAtoms::pageContentFrame == frameType) {
       nsIFrame* prevInFlow = rs->frame->GetPrevInFlow();
       // only use the page content frame for a height basis if it is the first in flow
       if (prevInFlow) 
         break;
     }
     else {
@@ -1663,34 +1641,24 @@ nsHTMLReflowState::InitConstraints(nsPre
     nsFrame::ListTag(stdout, frame); printf(": cb=");
     nsFrame::ListTag(stdout, cbrs->frame); printf(" size=%d,%d\n", aContainingBlockWidth, aContainingBlockHeight);
 #endif
 
     // See if the containing block height is based on the size of its
     // content
     nsIAtom* fType;
     if (NS_AUTOHEIGHT == aContainingBlockHeight) {
-      // See if the containing block is (1) a scrolled frame, i.e. its
-      // parent is a scroll frame. The presence of the intervening
-      // frame (that the scroll frame scrolls) needs to be hidden from
-      // the containingBlockHeight calcuation, or (2) a cell frame which needs
+      // See if the containing block is a cell frame which needs
       // to use the mComputedHeight of the cell instead of what the cell block passed in.
+      // XXX It seems like this could lead to bugs with min-height and friends
       if (cbrs->parentReflowState) {
-        nsIFrame* f = cbrs->parentReflowState->frame;
-        fType = f->GetType();
-        if (nsGkAtoms::scrollFrame == fType) {
-          // Use the scroll frame's computed height instead
-          aContainingBlockHeight = cbrs->parentReflowState->mComputedHeight;
-        }
-        else {
-          fType = cbrs->frame->GetType();
-          if (IS_TABLE_CELL(fType)) {
-            // use the cell's computed height 
-            aContainingBlockHeight = cbrs->mComputedHeight;
-          }
+        fType = cbrs->frame->GetType();
+        if (IS_TABLE_CELL(fType)) {
+          // use the cell's computed height 
+          aContainingBlockHeight = cbrs->mComputedHeight;
         }
       }
     }
 
     InitOffsets(aContainingBlockWidth, aBorder, aPadding);
 
     nsStyleUnit heightUnit = mStylePosition->mHeight.GetUnit();
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/greenbox.html
@@ -0,0 +1,1 @@
+<div style="height:200px;width:200px; background:green">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/greenboxhbar.html
@@ -0,0 +1,2 @@
+<div style="overflow:auto; background:green; height:200px; width:200px">
+<div style="width:300px; height:1px">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollAbsHeight.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<div style="overflow:auto; width:200px; position:absolute; height:200px;">
+<div style="position:absolute; width:300px; height:100%; background:green">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollAbsHeightD.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<body onload="document.getElementById('a').style.height='100%';">
+<div style="overflow:auto; width:200px; position:absolute; height:200px;">
+<div id=a style="position:absolute; width:300px; background:green">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollAbsHeightQuirks.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<div style="overflow:auto; width:200px; position:absolute; height:200px;">
+<div style="position:absolute; width:300px; height:100%; background:green">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollAbsHeightQuirksD.html
@@ -0,0 +1,5 @@
+<body onload="document.getElementById('a').style.height='100%';">
+<div style="overflow:auto; width:200px; position:absolute; height:200px;">
+<div id=a style="position:absolute; width:300px; background:green">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollAbsMinHeightD.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<body onload="document.getElementById('a').style.minHeight='100%';">
+<div style="overflow:auto; width:200px; position:absolute; height:200px;">
+<div id=a style="position:absolute; width:300px; background:green">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollAbsMinHeightQuirksD.html
@@ -0,0 +1,5 @@
+<body onload="document.getElementById('a').style.minHeight='100%';">
+<div style="overflow:auto; width:200px; position:absolute; height:200px;">
+<div id=a style="position:absolute; width:300px; background:green">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollSimpleHeight.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<div style="overflow:auto; width:200px; height:200px;">
+<div style="width:300px; height:100%; background:green">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollSimpleHeightD.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<body onload="document.getElementById('a').style.height='100%';">
+<div style="overflow:auto; width:200px; height:200px;">
+<div id=a style="width:300px; background:green">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollSimpleHeightQuirks-1.html
@@ -0,0 +1,4 @@
+<div style="overflow:auto; width:200px; height:200px;">
+<div style="width:300px; height:100%; background:green">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollSimpleHeightQuirks-1D.html
@@ -0,0 +1,5 @@
+<body onload="document.getElementById('a').style.height='100%';">
+<div style="overflow:auto; width:200px; height:200px;">
+<div id=a style="width:300px; background:green">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollSimpleHeightQuirks-2.html
@@ -0,0 +1,6 @@
+<div style="overflow:auto; width:200px; height:200px;">
+<div>
+<div style="width:300px; height:100%; background:green">
+</div>
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollSimpleHeightQuirks-2D.html
@@ -0,0 +1,7 @@
+<body onload="document.getElementById('a').style.height='100%';">
+<div style="overflow:auto; width:200px; height:200px;">
+<div>
+<div id=a style="width:300px; background:green">
+</div>
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollSimpleHeightQuirks-3.html
@@ -0,0 +1,8 @@
+<div style="width:200px; height:200px; overflow:auto">
+<div>
+<table cellspacing=0 cellpadding=0 border=0 height="100%"><tr><td>
+<div style="width:300px; height:100%; background:green"><div style="height:1px"><!--Workaround for unrelated table bug--></div>
+</div>
+</table>
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollSimpleHeightQuirks-3D.html
@@ -0,0 +1,9 @@
+<body onload="document.getElementById('a').style.height='100%';">
+<div style="width:200px; height:200px; overflow:auto">
+<div>
+<table id=a cellspacing=0 cellpadding=0 border=0 height="100%"><tr><td>
+<div style="width:300px; background:green; height:100%"><div style="height:1px"><!--Workaround for unrelated table bug--></div>
+</div>
+</table>
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollSimpleMinHeightD.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<body onload="document.getElementById('a').style.minHeight='100%';">
+<div style="overflow:auto; width:200px; height:200px;">
+<div id=a style="width:300px; background:green">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollSimpleMinHeightQuirks-1D.html
@@ -0,0 +1,5 @@
+<body onload="document.getElementById('a').style.minHeight='100%';">
+<div style="overflow:auto; width:200px; height:200px;">
+<div id=a style="width:300px; background:green">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/hScrollSimpleMinHeightQuirks-3D.html
@@ -0,0 +1,9 @@
+<body onload="document.getElementById('a').style.minHeight='100%';">
+<div style="width:200px; height:200px; overflow:auto">
+<div>
+<table id=a cellspacing=0 cellpadding=0 border=0 height="100%"><tr><td>
+<div style="width:300px; background:green; height:100%"><div style="height:1px"><!--Workaround for unrelated table bug--></div>
+</div>
+</table>
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/reftest.list
@@ -0,0 +1,23 @@
+== simpleHeight100.html greenbox.html
+== simpleAbsHeight.html greenbox.html
+== hScrollSimpleHeight.html greenboxhbar.html
+== hScrollSimpleHeightQuirks-1.html greenboxhbar.html
+== hScrollSimpleHeightQuirks-2.html greenboxhbar.html
+== hScrollSimpleHeightQuirks-3.html greenboxhbar.html
+== hScrollAbsHeight.html greenboxhbar.html
+== hScrollAbsHeightQuirks.html greenboxhbar.html
+== simpleHeight100D.html greenbox.html
+== simpleAbsHeightD.html greenbox.html
+== hScrollSimpleHeightD.html greenboxhbar.html
+== hScrollSimpleHeightQuirks-1D.html greenboxhbar.html
+== hScrollSimpleHeightQuirks-2D.html greenboxhbar.html
+== hScrollSimpleHeightQuirks-3D.html greenboxhbar.html
+== hScrollAbsHeightD.html greenboxhbar.html
+== hScrollAbsHeightQuirksD.html greenboxhbar.html
+== simpleMinHeight100D.html greenbox.html
+== simpleAbsMinHeightD.html greenbox.html
+== hScrollSimpleMinHeightD.html greenboxhbar.html
+== hScrollSimpleMinHeightQuirks-1D.html greenboxhbar.html
+== hScrollSimpleMinHeightQuirks-3D.html greenboxhbar.html
+== hScrollAbsMinHeightD.html greenboxhbar.html
+== hScrollAbsMinHeightQuirksD.html greenboxhbar.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/simpleAbsHeight.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<div style="overflow:auto; height:200px; width:200px; position:relative">
+<div style="background: green; height:100%; width:100%; position:absolute">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/simpleAbsHeightD.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<body onload="document.getElementById('a').style.height='100%';">
+<div style="overflow:auto; height:200px; width:200px; position:relative">
+<div id=a style="background: green; width:100%; position:absolute">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/simpleAbsMinHeightD.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<body onload="document.getElementById('a').style.minHeight='100%'">
+<div style="overflow:auto; height:200px; width:200px; position:relative">
+<div id=a style="background: green; min-width:100%; position:absolute">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/simpleHeight100.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<div style="overflow:auto; height:200px; width:200px">
+<div style="background: green; height:100%">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/simpleHeight100D.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<body onload="document.getElementById('a').style.height='100%';">
+<div style="overflow:auto; height:200px; width:200px">
+<div id=a style="background: green;">
+</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/percent-overflow-sizing/simpleMinHeight100D.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<body onload="document.getElementById('a').style.minHeight='100%';">
+<div style="overflow:auto; height:200px; width:200px">
+<div id=a style="background: green;">
+</div>
+</div>
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -75,8 +75,12 @@ include columns/reftest.list
 # image-region/
 include image-region/reftest.list
 
 # block-inside-inline splits
 include ib-split/reftest.list
 
 # line-breaking
 include line-breaking/reftest.list
+
+# percent-overflow-sizing
+include percent-overflow-sizing/reftest.list
+