Bug 656130 - Part 1: Make sure that the absolute containing frame to be returned is actually marked as such in the frame tree; r=bzbarsky
authorEhsan Akhgari <ehsan@mozilla.com>
Wed, 11 May 2011 19:53:34 -0400
changeset 77842 731bbf32a6fdc2205648fc9122e8d50626ea2276
parent 77841 00f422b2cf36505e1ee8768e09997237be8294c0
child 77843 49b3a14730def03f863ff5d628dd501f4d7542ba
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersbzbarsky
bugs656130
milestone10.0a1
Bug 656130 - Part 1: Make sure that the absolute containing frame to be returned is actually marked as such in the frame tree; r=bzbarsky
layout/base/nsCSSFrameConstructor.cpp
layout/forms/nsFieldSetFrame.cpp
layout/forms/nsHTMLButtonControlFrame.cpp
layout/generic/crashtests/656130-1.html
layout/generic/crashtests/crashtests.list
layout/generic/nsColumnSetFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/reftests/abs-pos/continuation-positioned-inline-1.html
layout/reftests/abs-pos/continuation-positioned-inline-2.html
layout/reftests/abs-pos/continuation-positioned-inline-ref.html
layout/reftests/abs-pos/fieldset-1-ref.html
layout/reftests/abs-pos/fieldset-1.html
layout/reftests/abs-pos/reftest.list
layout/reftests/abs-pos/scrollframe-1-ref.html
layout/reftests/abs-pos/scrollframe-1.html
layout/reftests/abs-pos/scrollframe-2-ref.html
layout/reftests/abs-pos/scrollframe-2.html
layout/reftests/abs-pos/select-1-dynamic.html
layout/reftests/abs-pos/select-1-ref.html
layout/reftests/abs-pos/select-1.html
layout/reftests/abs-pos/select-2-ref.html
layout/reftests/abs-pos/select-2.html
layout/reftests/abs-pos/select-3-ref.html
layout/reftests/abs-pos/select-3.html
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1744,29 +1744,16 @@ nsCSSFrameConstructor::CreateGeneratedCo
     
 /****************************************************
  **  BEGIN TABLE SECTION
  ****************************************************/
 
 // The term pseudo frame is being used instead of anonymous frame, since anonymous
 // frame has been used elsewhere to refer to frames that have generated content
 
-static bool
-IsTableRelated(nsIAtom* aParentType)
-{
-  return
-    nsGkAtoms::tableOuterFrame    == aParentType ||
-    nsGkAtoms::tableRowGroupFrame == aParentType ||
-    nsGkAtoms::tableRowFrame      == aParentType ||
-    nsGkAtoms::tableCaptionFrame  == aParentType ||
-    nsGkAtoms::tableColGroupFrame == aParentType ||
-    nsGkAtoms::tableColFrame      == aParentType ||
-    IS_TABLE_CELL(aParentType);
-}
-
 // Return whether the given frame is a table pseudo-frame.  Note that
 // cell-content and table-outer frames have pseudo-types, but are always
 // created, even for non-anonymous cells and tables respectively.  So for those
 // we have to examine the cell or table frame to see whether it's a pseudo
 // frame.  In particular, a lone table caption will have an outer table as its
 // parent, but will also trigger construction of an empty inner table, which
 // will be the one we can examine to see whether the outer was a pseudo-frame.
 static bool
@@ -3001,19 +2988,17 @@ nsCSSFrameConstructor::ConstructButtonFr
 #endif
   
   if (!isLeaf) { 
     // Process children
     nsFrameConstructorSaveState absoluteSaveState;
     nsFrameItems                childItems;
 
     if (aStyleDisplay->IsPositioned()) {
-      // The area frame becomes a container for child frames that are
-      // absolutely positioned
-      aState.PushAbsoluteContainingBlock(blockFrame, absoluteSaveState);
+      aState.PushAbsoluteContainingBlock(buttonFrame, absoluteSaveState);
     }
 
 #ifdef DEBUG
     // Make sure that anonymous child creation will have no effect in this case
     nsIAnonymousContentCreator* creator = do_QueryFrame(blockFrame);
     NS_ASSERTION(!creator, "Shouldn't be an anonymous content creator!");
 #endif
 
@@ -3226,25 +3211,18 @@ nsCSSFrameConstructor::InitializeSelectF
                    geometricParent, scrollFrame);
 
   if (aState.mFrameState && aState.mFrameManager) {
     // Restore frame state for the scroll frame
     aState.mFrameManager->RestoreFrameStateFor(scrollFrame, aState.mFrameState);
   }
 
   // Process children
-  nsFrameConstructorSaveState absoluteSaveState;
   nsFrameItems                childItems;
 
-  if (display->IsPositioned()) {
-    // The area frame becomes a container for child frames that are
-    // absolutely positioned
-    aState.PushAbsoluteContainingBlock(scrolledFrame, absoluteSaveState);
-  }
-
   ProcessChildren(aState, aContent, aStyleContext, scrolledFrame, PR_FALSE,
                   childItems, PR_FALSE, aPendingBinding);
 
   // Set the scrolled frame's initial child lists
   scrolledFrame->SetInitialChildList(kPrincipalList, childItems);
   return NS_OK;
 }
 
@@ -3285,21 +3263,17 @@ nsCSSFrameConstructor::ConstructFieldSet
     return rv;
   }
   
   // Process children
   nsFrameConstructorSaveState absoluteSaveState;
   nsFrameItems                childItems;
 
   if (aStyleDisplay->IsPositioned()) {
-    // The area frame becomes a container for child frames that are
-    // absolutely positioned
-    // XXXbz this is probably wrong, and once arbitrary frames can be absolute
-    // containing blocks we should fix this..
-    aState.PushAbsoluteContainingBlock(blockFrame, absoluteSaveState);
+    aState.PushAbsoluteContainingBlock(newFrame, absoluteSaveState);
   }
 
   ProcessChildren(aState, content, styleContext, blockFrame, PR_TRUE,
                   childItems, PR_TRUE, aItem.mPendingBinding);
 
   nsFrameItems fieldsetKids;
   fieldsetKids.AddChild(blockFrame);
 
@@ -5518,73 +5492,61 @@ nsCSSFrameConstructor::GetFrameFor(nsICo
 
   return insertionFrame;
 }
 
 nsIFrame*
 nsCSSFrameConstructor::GetAbsoluteContainingBlock(nsIFrame* aFrame)
 {
   NS_PRECONDITION(nsnull != mRootElementFrame, "no root element frame");
-  
+
   // Starting with aFrame, look for a frame that is absolutely positioned or
   // relatively positioned
-  nsIFrame* containingBlock = nsnull;
-  for (nsIFrame* frame = aFrame; frame && !containingBlock;
-       frame = frame->GetParent()) {
+  for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
     if (frame->IsFrameOfType(nsIFrame::eMathML)) {
       // If it's mathml, bail out -- no absolute positioning out from inside
       // mathml frames.  Note that we don't make this part of the loop
       // condition because of the stuff at the end of this method...
       return nsnull;
     }
-    
-    // Is it positioned?
-    // If it's table-related then ignore it, because for the time
-    // being table-related frames are not containers for absolutely
-    // positioned child frames.
+
+    // If the frame is positioned, we will probably return it as the containing
+    // block (see the exceptions below).  Otherwise, we'll start looking at the
+    // parent frame, unless we're dealing with a scrollframe.
+    // Scrollframes are special since they're not positioned, but their
+    // scrolledframe might be.  So, we need to check this special case to return
+    // the correct containing block (the scrolledframe) in that case.
     const nsStyleDisplay* disp = frame->GetStyleDisplay();
-
-    if (disp->IsPositioned()) {
-      // For tables, return the outer frame table
-      if (frame->GetType() == nsGkAtoms::tableFrame) {
-        containingBlock = frame->GetParent();
-        break;
-      } else if (IsTableRelated(frame->GetType())) {
-        continue;
-      }
-
-      // Find the outermost wrapped block under this frame
-      for (nsIFrame* wrappedFrame = aFrame; wrappedFrame != frame->GetParent();
-           wrappedFrame = wrappedFrame->GetParent()) {
-        nsIAtom* frameType = wrappedFrame->GetType();
-        if (nsGkAtoms::blockFrame == frameType ||
-#ifdef MOZ_XUL
-            nsGkAtoms::XULLabelFrame == frameType ||
-#endif
-            (nsGkAtoms::inlineFrame == frameType && wrappedFrame->IsAbsoluteContainer())) {
-          containingBlock = wrappedFrame;
-        } else if (nsGkAtoms::fieldSetFrame == frameType) {
-          // If the positioned frame is a fieldset, use the area frame inside it.
-          // We don't use GetContentInsertionFrame for fieldsets yet.
-          containingBlock = GetFieldSetBlockFrame(wrappedFrame);
-        }
-      }
-
-      // We sometimes have a null containing block here because we
-      // haven't yet fixed bug 455338.  Once we fix that we shouldn't
-      // have to loop here.
-    }
-  }
-
-  // If we found an absolutely positioned containing block, then use the
-  // first-continuation.
-  if (containingBlock)
-    return AdjustAbsoluteContainingBlock(containingBlock);
-
-  // If we didn't find it, then use the document element containing block
+    if (!disp->IsPositioned()) {
+      continue;
+    }
+    nsIFrame* absPosCBCandidate = nsnull;
+    if (frame->GetType() == nsGkAtoms::scrollFrame) {
+      nsIScrollableFrame* scrollFrame = do_QueryFrame(frame);
+      absPosCBCandidate = scrollFrame->GetScrolledFrame();
+    } else {
+      // Only first continuations can be containing blocks.
+      absPosCBCandidate = frame->GetFirstContinuation();
+    }
+    // Is the frame really an absolute container?
+    if (!absPosCBCandidate || !absPosCBCandidate->IsAbsoluteContainer()) {
+      continue;
+    }
+
+    // For tables, return the outer table frame.
+    if (absPosCBCandidate->GetType() == nsGkAtoms::tableFrame) {
+      return absPosCBCandidate->GetParent();
+    }
+    // For outer table frames, we can just return absPosCBCandidate.
+    return absPosCBCandidate;
+  }
+
+  // It is possible for the search for the containing block to fail, because
+  // no absolute container can be found in the parent chain.  In those cases,
+  // we fall back to the document element's containing block.
   return mHasRootAbsPosContainingBlock ? mDocElementContainingBlock : nsnull;
 }
 
 nsIFrame*
 nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame)
 {
   // Starting with aFrame, look for a frame that is a float containing block.
   // IF we hit a mathml frame, bail out; we don't allow floating out of mathml
@@ -10663,17 +10625,17 @@ nsCSSFrameConstructor::ConstructBlock(ns
   // positioning must be computed with respect to the CSS dimensions
   // of the element, which are the dimensions of the outer block. But
   // we can't really do that because only blocks can have absolute
   // children. So use the block and try to compensate with hacks
   // in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
   nsFrameConstructorSaveState absoluteSaveState;
   if (aAbsPosContainer) {
     //    NS_ASSERTION(aRelPos, "should have made area frame for this");
-    aState.PushAbsoluteContainingBlock(blockFrame, absoluteSaveState);
+    aState.PushAbsoluteContainingBlock(*aNewFrame, absoluteSaveState);
   }
 
   // Process the child content
   nsFrameItems childItems;
   rv = ProcessChildren(aState, aContent, aStyleContext, blockFrame, PR_TRUE,
                        childItems, PR_TRUE, aPendingBinding);
 
   // Set the frame's initial child list
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -79,16 +79,17 @@ public:
                       nsLayoutUtils::IntrinsicWidthType);
   virtual nscoord GetMinWidth(nsRenderingContext* aRenderingContext);
   virtual nscoord GetPrefWidth(nsRenderingContext* aRenderingContext);
   virtual nsSize ComputeSize(nsRenderingContext *aRenderingContext,
                              nsSize aCBSize, nscoord aAvailableWidth,
                              nsSize aMargin, nsSize aBorder, nsSize aPadding,
                              bool aShrinkWrap);
   virtual nscoord GetBaseline() const;
+  virtual void DestroyFrom(nsIFrame* aDestructRoot);
 
   NS_IMETHOD Reflow(nsPresContext*           aPresContext,
                     nsHTMLReflowMetrics&     aDesiredSize,
                     const nsHTMLReflowState& aReflowState,
                     nsReflowStatus&          aStatus);
                                
   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
@@ -139,16 +140,23 @@ NS_IMPL_FRAMEARENA_HELPERS(nsFieldSetFra
 nsFieldSetFrame::nsFieldSetFrame(nsStyleContext* aContext)
   : nsHTMLContainerFrame(aContext)
 {
   mContentFrame = nsnull;
   mLegendFrame  = nsnull;
   mLegendSpace  = 0;
 }
 
+void
+nsFieldSetFrame::DestroyFrom(nsIFrame* aDestructRoot)
+{
+  DestroyAbsoluteFrames(aDestructRoot);
+  nsHTMLContainerFrame::DestroyFrom(aDestructRoot);
+}
+
 nsIAtom*
 nsFieldSetFrame::GetType() const
 {
   return nsGkAtoms::fieldSetFrame;
 }
 
 NS_IMETHODIMP
 nsFieldSetFrame::SetInitialChildList(ChildListID    aListID,
@@ -591,17 +599,17 @@ nsFieldSetFrame::Reflow(nsPresContext*  
       aDesiredSize.height = min;
   }
   aDesiredSize.width = contentRect.width + borderPadding.LeftRight();
   aDesiredSize.SetOverflowAreasToDesiredBounds();
   if (mLegendFrame)
     ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mLegendFrame);
   if (mContentFrame)
     ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mContentFrame);
-  FinishAndStoreOverflow(&aDesiredSize);
+  FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
 
   Invalidate(aDesiredSize.VisualOverflow());
 
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   return NS_OK;
 }
 
 PRIntn
--- a/layout/forms/nsHTMLButtonControlFrame.cpp
+++ b/layout/forms/nsHTMLButtonControlFrame.cpp
@@ -83,16 +83,17 @@ nsHTMLButtonControlFrame::nsHTMLButtonCo
 nsHTMLButtonControlFrame::~nsHTMLButtonControlFrame()
 {
 }
 
 void
 nsHTMLButtonControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), PR_FALSE);
+  DestroyAbsoluteFrames(aDestructRoot);
   nsHTMLContainerFrame::DestroyFrom(aDestructRoot);
 }
 
 NS_IMETHODIMP
 nsHTMLButtonControlFrame::Init(
               nsIContent*      aContent,
               nsIFrame*        aParent,
               nsIFrame*        aPrevInFlow)
@@ -276,17 +277,17 @@ nsHTMLButtonControlFrame::Reflow(nsPresC
                                       aReflowState.mComputedMinHeight,
                                       aReflowState.mComputedMaxHeight);
 
   aDesiredSize.ascent +=
     aReflowState.mComputedBorderPadding.top + focusPadding.top;
 
   aDesiredSize.SetOverflowAreasToDesiredBounds();
   ConsiderChildOverflow(aDesiredSize.mOverflowAreas, firstKid);
-  FinishAndStoreOverflow(&aDesiredSize);
+  FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
 
   aStatus = NS_FRAME_COMPLETE;
 
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   return NS_OK;
 }
 
 void
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/656130-1.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<head>
+<script>
+
+function boom()
+{
+  var b = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
+  b.style.position = "absolute";
+  document.getElementById("a").appendChild(b);
+}
+
+</script>
+</head>
+
+<body onload="boom();"><div id="a" style="display: -moz-inline-stack; position: relative">x</div></body>
+</html>
+
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -356,16 +356,17 @@ load 604843.html
 load 605340.html
 load 621841-1.html
 load 645072-1.html
 load 645072-2.html
 load 646561-1.html
 load 646983-1.html
 load 647332-1.html
 load 650499-1.html
+load 656130-1.html
 load 660416.html
 load text-overflow-form-elements.html
 load text-overflow-iframe.html
 load text-overflow-bug666751-1.html
 load text-overflow-bug666751-2.html
 asserts(2) load text-overflow-bug670564.xhtml # asserts(2) for bug 436470
 load text-overflow-bug671796.xhtml
 load 667025.html
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -69,16 +69,17 @@ public:
   NS_IMETHOD  AppendFrames(ChildListID     aListID,
                            nsFrameList&    aFrameList);
   NS_IMETHOD  InsertFrames(ChildListID     aListID,
                            nsIFrame*       aPrevFrame,
                            nsFrameList&    aFrameList);
   NS_IMETHOD  RemoveFrame(ChildListID     aListID,
                           nsIFrame*       aOldFrame);
 
+  virtual void DestroyFrom(nsIFrame* aDestructRoot);
   virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext);  
   virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext);
 
   virtual nsIFrame* GetContentInsertionFrame() {
     nsIFrame* frame = GetFirstPrincipalChild();
 
     // if no children return nsnull
     if (!frame)
@@ -197,16 +198,23 @@ NS_NewColumnSetFrame(nsIPresShell* aPres
 NS_IMPL_FRAMEARENA_HELPERS(nsColumnSetFrame)
 
 nsColumnSetFrame::nsColumnSetFrame(nsStyleContext* aContext)
   : nsHTMLContainerFrame(aContext), mLastBalanceHeight(NS_INTRINSICSIZE),
     mLastFrameStatus(NS_FRAME_COMPLETE)
 {
 }
 
+void
+nsColumnSetFrame::DestroyFrom(nsIFrame* aDestructRoot)
+{
+  DestroyAbsoluteFrames(aDestructRoot);
+  nsHTMLContainerFrame::DestroyFrom(aDestructRoot);
+}
+
 nsIAtom*
 nsColumnSetFrame::GetType() const
 {
   return nsGkAtoms::columnSetFrame;
 }
 
 static void
 PaintColumnRule(nsIFrame* aFrame, nsRenderingContext* aCtx,
@@ -1064,17 +1072,17 @@ nsColumnSetFrame::Reflow(nsPresContext* 
       aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE) {
     // In this situation, we might be lying about our reflow status, because
     // our last kid (the one that got interrupted) was incomplete.  Fix that.
     aStatus = NS_FRAME_COMPLETE;
   }
   
   CheckInvalidateSizeChange(aDesiredSize);
 
-  FinishAndStoreOverflow(&aDesiredSize);
+  FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
   aDesiredSize.mCarriedOutBottomMargin = carriedOutBottomMargin;
 
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
 
   NS_ASSERTION(NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
                aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE,
                "Column set should be complete if the available height is unconstrained");
 
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -116,16 +116,17 @@ nsHTMLScrollFrame::AppendAnonymousConten
 {
   mInner.AppendAnonymousContentTo(aElements, aFilter);
 }
 
 void
 nsHTMLScrollFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   mInner.Destroy();
+  DestroyAbsoluteFrames(aDestructRoot);
   nsHTMLContainerFrame::DestroyFrom(aDestructRoot);
 }
 
 NS_IMETHODIMP
 nsHTMLScrollFrame::SetInitialChildList(ChildListID  aListID,
                                        nsFrameList& aChildList)
 {
   nsresult rv = nsHTMLContainerFrame::SetInitialChildList(aListID, aChildList);
@@ -922,17 +923,17 @@ nsHTMLScrollFrame::Reflow(nsPresContext*
     state.mComputedBorder.LeftRight();
   aDesiredSize.height = state.mInsideBorderSize.height +
     state.mComputedBorder.TopBottom();
 
   aDesiredSize.SetOverflowAreasToDesiredBounds();
 
   CheckInvalidateSizeChange(aDesiredSize);
 
-  FinishAndStoreOverflow(&aDesiredSize);
+  FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
 
   if (!InInitialReflow() && !mInner.mHadNonInitialReflow) {
     mInner.mHadNonInitialReflow = PR_TRUE;
   }
 
   if (mInner.mIsRoot && !oldScrolledAreaBounds.IsEqualEdges(newScrolledAreaBounds)) {
     mInner.PostScrolledAreaEvent();
   }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/continuation-positioned-inline-1.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <span style="position: relative; top: 100px">foo<br>
+      <span id="ins-point"><span style="position: absolute; top: 0">abs</span>bar</span></span>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/continuation-positioned-inline-2.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+  <body onload="loaded()">
+    <span style="position: relative; top: 100px">foo<br>
+      <span id="ins-point">bar</span></span>
+    <script>
+      function loaded() {
+        var insPoint = document.getElementById("ins-point");
+        var span = document.createElement("span");
+        span.style.position = "absolute";
+        span.style.top = 0;
+        span.appendChild(document.createTextNode("abs"));
+        insPoint.insertBefore(span, insPoint.firstChild);
+      }
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/continuation-positioned-inline-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <span style="position: relative; top: 100px"><span style="position: absolute; top: 0; left: 0">abs</span>foo<br>
+      <span id="ins-point">bar</span></span>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/fieldset-1-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+      * { border: 0; margin: 0; padding: 0; }
+    </style>
+  </head>
+  <body>
+    <span style="position: absolute; top: 50px; left: 50px">test</span>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/fieldset-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+      * { border: 0; margin: 0; padding: 0; }
+    </style>
+  </head>
+  <body>
+    <fieldset style="position: relative; top: 25px; left: 20px; width: 100px;">
+      <legend>
+        <span style="position: absolute; top: 25px; left: 30px">test</span>
+      </legend>
+    </fieldset>
+  </body>
+</html>
--- a/layout/reftests/abs-pos/reftest.list
+++ b/layout/reftests/abs-pos/reftest.list
@@ -1,5 +1,14 @@
 == font-size-wrap.html font-size-wrap-ref.html
 == abs-pos-auto-margin-1.html abs-pos-auto-margin-1-ref.html
 == auto-offset-inline-block-1.html auto-offset-inline-block-1-ref.html
+== fieldset-1.html fieldset-1-ref.html
 == table-1.html table-1-ref.html
 == table-2.html table-2-ref.html
+== continuation-positioned-inline-1.html continuation-positioned-inline-ref.html
+== continuation-positioned-inline-2.html continuation-positioned-inline-ref.html
+== scrollframe-1.html scrollframe-1-ref.html
+== scrollframe-2.html scrollframe-2-ref.html
+== select-1.html select-1-ref.html
+== select-1-dynamic.html select-1-ref.html
+== select-2.html select-2-ref.html
+== select-3.html select-3-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/scrollframe-1-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+  <body onload="loaded()">
+    <div style="position: relative; top: 100px; overflow: scroll; width: 100px; height: 100px;">
+      <div style="height: 200px"></div></div>
+    <script>
+      function loaded() {
+        var insPoint = document.querySelector("div");
+        insPoint.scrollTop = 50;
+      }
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/scrollframe-1.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+  <body onload="loaded()">
+    <div style="position: relative; top: 100px; overflow: scroll; width: 100px; height: 100px;">
+      <div style="height: 200px">foo</div></div>
+    <script>
+      function loaded() {
+        var insPoint = document.querySelector("div");
+        insPoint.scrollTop = 50;
+        var div = document.createElement("div");
+        div.style.position = "absolute";
+        div.style.top = 0;
+        div.appendChild(document.createTextNode("abs"));
+        insPoint.insertBefore(div, insPoint.firstChild);
+      }
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/scrollframe-2-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+  <body onload="loaded()">
+    <div style="position: relative; top: 100px; overflow: scroll; width: 100px; height: 100px;">
+      <div style="height: 200px"></div></div>
+    <div style="position: absolute; top: 100px;" id="abs">abs</div>
+    <script>
+      function loaded() {
+        var insPoint = document.querySelector("div");
+        insPoint.scrollTop = 50;
+        var abs = document.getElementById("abs");
+        abs.style.top = insPoint.offsetTop + "px";
+      }
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/scrollframe-2.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+  <body onload="loaded()">
+    <div style="position: relative; top: 100px; overflow: scroll; width: 100px; height: 100px;">
+      <div style="height: 200px">foo</div></div>
+    <script>
+      function loaded() {
+        var insPoint = document.querySelector("div");
+        insPoint.scrollTop = 50;
+        var div = document.createElement("div");
+        div.style.position = "absolute";
+        div.style.top = '50px';
+        div.appendChild(document.createTextNode("abs"));
+        insPoint.insertBefore(div, insPoint.firstChild);
+      }
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/select-1-dynamic.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+  <select style="position: relative" size=4>
+    <option>bar</option>
+  </select>
+  <select style="position: relative">
+    <option>bar</option>
+  </select>
+  <script>
+    function injectAbsPosKid(s) {
+      var option = document.createElement("option");
+      option.appendChild(document.createTextNode("foo"));
+      option.style.position = "absolute";
+      option.style.top = "100px";
+      s.insertBefore(option, s.firstChild);
+
+      var div = document.createElement("div");
+      div.appendChild(document.createTextNode("bar"));
+      div.style.position = "absolute";
+      div.style.top = "200px";
+      s.appendChild(div);
+    }
+    onload = function() {
+      var s1 = document.querySelectorAll("select")[0];
+      var s2 = document.querySelectorAll("select")[1];
+      injectAbsPosKid(s1);
+      injectAbsPosKid(s2);
+      s2.selectedIndex = 0;
+    };
+  </script>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/select-1-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <select size=4>
+    <option>foo</option>
+    <option>bar</option>
+  </select>
+  <select>
+    <option>foo</option>
+    <option>bar</option>
+  </select>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/select-1.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+  <select style="position: relative" size=4>
+    <option style="position: absolute; top:100px;">foo</option>
+    <option>bar</option>
+    <div style="position: absolute; top: 200px;">baz</div>
+  </select>
+  <select style="position: relative">
+    <option style="position: absolute; top:100px;">foo</option>
+    <option>bar</option>
+    <div style="position: absolute; top: 200px;">baz</div>
+  </select>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/select-2-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <body style="margin: 0; padding: 0;">
+    <div style="position: absolute; top: 100px; left: 100px;">
+      <select size=4>
+        <option>foo</option>
+        <option>bar</option>
+      </select>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/select-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <body style="margin: 0; padding: 0;">
+    <div style="position: relative">
+      <select size=4 style="position: absolute; top: 100px; left: 100px;">
+        <option>foo</option>
+        <option>bar</option>
+      </select>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/select-3-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+  <body style="margin: 0; padding: 0;">
+    <select style="position: fixed; top: 100px; left: 100px;">
+      <option>foo</option>
+      <option>bar</option>
+    </select>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/select-3.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <body style="margin: 0; padding: 0;">
+    <div style="position: relative;">
+      <select style="position: absolute; top: 100px; left: 100px;">
+        <option>foo</option>
+        <option>bar</option>
+      </select>
+    </div>
+  </body>
+</html>