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 79189 731bbf32a6fdc2205648fc9122e8d50626ea2276
parent 79188 00f422b2cf36505e1ee8768e09997237be8294c0
child 79190 49b3a14730def03f863ff5d628dd501f4d7542ba
push id434
push userclegnitto@mozilla.com
push dateWed, 21 Dec 2011 12:10:54 +0000
treeherdermozilla-beta@bddb6ed8dd47 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs656130
milestone10.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 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>