paginate absolutely-positioned elements, b=154892 r+sr=roc a=roc
authorfantasai.cvs@inkedblade.net
Mon, 01 Oct 2007 22:57:45 -0700
changeset 6521 854d0d4791411c4733946d366a3824509451ed4f
parent 6520 9caa13c045ec8853af1fa112cd8a47df6e0a7ed8
child 6522 aeb35bcd5ca57c7c8cead1b42b16383dde4aadd1
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs154892
milestone1.9a9pre
paginate absolutely-positioned elements, b=154892 r+sr=roc a=roc
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsFrameManager.cpp
layout/base/nsLayoutUtils.cpp
layout/generic/nsAbsoluteContainingBlock.cpp
layout/generic/nsAbsoluteContainingBlock.h
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockReflowContext.cpp
layout/generic/nsBlockReflowContext.h
layout/generic/nsBlockReflowState.cpp
layout/generic/nsContainerFrame.cpp
layout/generic/nsContainerFrame.h
layout/generic/nsFrame.cpp
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsInlineFrame.cpp
layout/generic/nsPageContentFrame.cpp
layout/generic/nsSimplePageSequence.cpp
layout/generic/nsViewportFrame.cpp
layout/reftests/pagination/abspos-overflow-01-cols.ref.xhtml
layout/reftests/pagination/abspos-overflow-01-cols.xhtml
layout/reftests/pagination/abspos-overflow-01.ref.xhtml
layout/reftests/pagination/abspos-overflow-01.xhtml
layout/reftests/pagination/blank.html
layout/reftests/pagination/dynamic-abspos-overflow-01-cols.ref.xhtml
layout/reftests/pagination/dynamic-abspos-overflow-01-cols.xhtml
layout/reftests/pagination/reftest.list
layout/reftests/reftest.list
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1707,19 +1707,22 @@ nsAutoEnqueueBinding::~nsAutoEnqueueBind
 
 
 // Helper function that determines the child list name that aChildFrame
 // is contained in
 static nsIAtom*
 GetChildListNameFor(nsIFrame*       aChildFrame)
 {
   nsIAtom*      listName;
-  
+
+  if (aChildFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
+    listName = nsGkAtoms::overflowContainersList;
+  }
   // See if the frame is moved out of the flow
-  if (aChildFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
+  else if (aChildFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
     // Look at the style information to tell
     const nsStyleDisplay* disp = aChildFrame->GetStyleDisplay();
     
     if (NS_STYLE_POSITION_ABSOLUTE == disp->mPosition) {
       listName = nsGkAtoms::absoluteList;
     } else if (NS_STYLE_POSITION_FIXED == disp->mPosition) {
       listName = nsGkAtoms::fixedList;
 #ifdef MOZ_XUL
@@ -8097,29 +8100,33 @@ FindPreviousAnonymousSibling(nsIPresShel
     nsIFrame* prevSibling = aPresShell->GetPrimaryFrameFor(child);
     if (prevSibling) {
       // The frame may be a special frame (a split inline frame that
       // contains a block).  Get the last part of that split.
       if (IsFrameSpecial(prevSibling)) {
         prevSibling = GetLastSpecialSibling(prevSibling);
       }
 
-      // The frame may have a continuation. If so, we want the
-      // last continuation as our previous sibling.
-      prevSibling = prevSibling->GetLastContinuation();
-
       // If the frame is out-of-flow, GPFF() will have returned the
       // out-of-flow frame; we want the placeholder.
       if (prevSibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
         nsIFrame *placeholderFrame;
         aPresShell->GetPlaceholderFrameFor(prevSibling, &placeholderFrame);
         NS_ASSERTION(placeholderFrame, "no placeholder for out-of-flow frame");
         prevSibling = placeholderFrame;
       }
 
+      // The frame may have a continuation. If so, we want the
+      // last non-overflow-container continuation as our previous sibling.
+      prevSibling = prevSibling->GetLastContinuation();
+      while (prevSibling->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
+        prevSibling = prevSibling->GetPrevInFlow();
+        NS_ASSERTION(prevSibling, "first-in-flow can't be overflow container");
+      }
+
       // Found a previous sibling, we're done!
       return prevSibling;
     }
   }
 
   return nsnull;
 }
 
@@ -8282,37 +8289,39 @@ nsCSSFrameConstructor::FindPreviousSibli
 
     if (prevSibling) {
       // The frame may be a special frame (a split inline frame that
       // contains a block).  Get the last part of that split.
       if (IsFrameSpecial(prevSibling)) {
         prevSibling = GetLastSpecialSibling(prevSibling);
       }
 
-      // The frame may have a continuation. Get the last continuation
-      prevSibling = prevSibling->GetLastContinuation();
-
-      // XXXbz should the IsValidSibling check be after we get the
-      // placeholder for out-of-flows?
-      const nsStyleDisplay* display = prevSibling->GetStyleDisplay();
-  
-      if (aChild && !IsValidSibling(aContainerFrame, prevSibling, 
-                                    display->mDisplay, (nsIContent&)*aChild,
-                                    childDisplay))
-        continue;
-
       // If the frame is out-of-flow, GPFF() will have returned the
       // out-of-flow frame; we want the placeholder.
       if (prevSibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
         nsIFrame* placeholderFrame;
         mPresShell->GetPlaceholderFrameFor(prevSibling, &placeholderFrame);
         NS_ASSERTION(placeholderFrame, "no placeholder for out-of-flow frame");
         prevSibling = placeholderFrame;
       }
 
+      // The frame may have a continuation. if so get the last
+      // non-overflow-container continuation.
+      prevSibling = prevSibling->GetLastContinuation();
+      while (prevSibling->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
+        prevSibling = prevSibling->GetPrevInFlow();
+        NS_ASSERTION(prevSibling, "first-in-flow can't be overflow container");
+      }
+
+      const nsStyleDisplay* display = prevSibling->GetStyleDisplay();
+      if (aChild && !IsValidSibling(aContainerFrame, prevSibling,
+                                    display->mDisplay, (nsIContent&)*aChild,
+                                    childDisplay))
+        continue;
+
 #ifdef DEBUG
       nsIFrame* containerFrame = nsnull;
       containerFrame = mPresShell->GetPrimaryFrameFor(aContainer);
       NS_ASSERTION(prevSibling != containerFrame, "Previous Sibling is the Container's frame");
 #endif
       // Found a previous sibling, we're done!
       return prevSibling;
     }
@@ -9604,17 +9613,18 @@ UpdateViewsForTree(nsIFrame* aFrame, nsI
 
   // now do children of frame
   PRInt32 listIndex = 0;
   nsIAtom* childList = nsnull;
 
   do {
     nsIFrame* child = aFrame->GetFirstChild(childList);
     while (child) {
-      if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
+      if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
+          || (child->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
         // only do frames that are in flow
         if (nsGkAtoms::placeholderFrame == child->GetType()) { // placeholder
           // get out of flow frame and start over there
           nsIFrame* outOfFlowFrame =
             nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
 
           DoApplyRenderingChangeToTree(outOfFlowFrame, aViewManager,
                                        aFrameManager, aChange);
@@ -9776,18 +9786,21 @@ nsCSSFrameConstructor::StyleChangeReflow
 
   // If the frame is part of a split block-in-inline hierarchy, then
   // target the style-change reflow at the first ``normal'' ancestor
   // so we're sure that the style change will propagate to any
   // anonymously created siblings.
   if (IsFrameSpecial(aFrame))
     aFrame = GetIBContainingBlockFor(aFrame);
 
-  mPresShell->FrameNeedsReflow(aFrame, nsIPresShell::eStyleChange,
-                               NS_FRAME_IS_DIRTY);
+  do {
+    mPresShell->FrameNeedsReflow(aFrame, nsIPresShell::eStyleChange,
+                                 NS_FRAME_IS_DIRTY);
+    aFrame = aFrame->GetNextContinuation();
+  } while (aFrame);
 
   return NS_OK;
 }
 
 nsresult
 nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent,
                                             PRBool aAppend)
 {
@@ -10557,16 +10570,21 @@ nsCSSFrameConstructor::CreateContinuingF
     newFrame->SetPrevContinuation(aFrame);
   }
 
   // A continuation of generated content is also generated content
   if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) {
     newFrame->AddStateBits(NS_FRAME_GENERATED_CONTENT);
   }
 
+  // A continuation of an out-of-flow is also an out-of-flow
+  if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
+    newFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
+  }
+
   if (nextInFlow) {
     nextInFlow->SetPrevInFlow(newFrame);
     newFrame->SetNextInFlow(nextInFlow);
   } else if (nextContinuation) {
     nextContinuation->SetPrevContinuation(newFrame);
     newFrame->SetNextContinuation(nextContinuation);
   }
   return NS_OK;
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -843,17 +843,18 @@ VerifyStyleTree(nsPresContext* aPresCont
 
   PRInt32 listIndex = 0;
   nsIAtom* childList = nsnull;
   nsIFrame* child;
 
   do {
     child = aFrame->GetFirstChild(childList);
     while (child) {
-      if (NS_FRAME_OUT_OF_FLOW != (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
+      if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
+          || (child->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
         // only do frames that are in flow
         if (nsGkAtoms::placeholderFrame == child->GetType()) { 
           // placeholder: first recurse and verify the out of flow frame,
           // then verify the placeholder's context
           nsIFrame* outOfFlowFrame =
             nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
 
           // recurse to out of flow frame, letting the parent context get resolved
@@ -939,17 +940,18 @@ nsFrameManager::ReParentStyleContext(nsI
         nsIFrame* child;
           
         aFrame->SetStyleContext(newContext);
 
         do {
           child = aFrame->GetFirstChild(childList);
           while (child) {
             // only do frames that are in flow
-            if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
+            if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
+                 || (child->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
               if (nsGkAtoms::placeholderFrame == child->GetType()) {
                 // get out of flow frame and recurse there
                 nsIFrame* outOfFlowFrame =
                   nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
                 NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
 
                 NS_ASSERTION(outOfFlowFrame != providerChild,
                              "Out of flow provider?");
@@ -1312,18 +1314,19 @@ nsFrameManager::ReResolveStyleContext(ns
 
       // now do children
       PRInt32 listIndex = 0;
       nsIAtom* childList = nsnull;
 
       do {
         nsIFrame* child = aFrame->GetFirstChild(childList);
         while (child) {
-          if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
-            // only do frames that are in flow
+          if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
+              || (child->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
+            // only do frames that don't have placeholders
             if (nsGkAtoms::placeholderFrame == child->GetType()) { // placeholder
               // get out of flow frame and recur there
               nsIFrame* outOfFlowFrame =
                 nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
               NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
               NS_ASSERTION(outOfFlowFrame != resolvedChild,
                            "out-of-flow frame not a true descendant");
 
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1129,18 +1129,20 @@ nsLayoutUtils::FindNearestBlockAncestor(
   }
   return nsnull;
 }
 
 nsIFrame*
 nsLayoutUtils::GetParentOrPlaceholderFor(nsFrameManager* aFrameManager,
                                          nsIFrame* aFrame)
 {
-  if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
+  if ((aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
+      && !(aFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
     return aFrameManager->GetPlaceholderFrameFor(aFrame);
+  }
   return aFrame->GetParent();
 }
 
 nsIFrame*
 nsLayoutUtils::GetClosestCommonAncestorViaPlaceholders(nsIFrame* aFrame1,
                                                        nsIFrame* aFrame2,
                                                        nsIFrame* aKnownCommonAncestorHint)
 {
--- a/layout/generic/nsAbsoluteContainingBlock.cpp
+++ b/layout/generic/nsAbsoluteContainingBlock.cpp
@@ -118,55 +118,97 @@ nsAbsoluteContainingBlock::InsertFrames(
 }
 
 nsresult
 nsAbsoluteContainingBlock::RemoveFrame(nsIFrame*       aDelegatingFrame,
                                        nsIAtom*        aListName,
                                        nsIFrame*       aOldFrame)
 {
   NS_ASSERTION(GetChildListName() == aListName, "unexpected child list");
+  nsIFrame* nif = aOldFrame->GetNextInFlow();
+  if (nif) {
+    static_cast<nsContainerFrame*>(nif->GetParent())
+      ->DeleteNextInFlowChild(aOldFrame->PresContext(), nif);
+  }
 
   PRBool result = mAbsoluteFrames.DestroyFrame(aOldFrame);
   NS_ASSERTION(result, "didn't find frame to delete");
-  // Because positioned frames aren't part of a flow, there's no additional
-  // work to do, e.g. reflowing sibling frames. And because positioned frames
-  // have a view, we don't need to repaint
+
   return result ? NS_OK : NS_ERROR_FAILURE;
 }
 
 nsresult
-nsAbsoluteContainingBlock::Reflow(nsIFrame*                aDelegatingFrame,
-                                  nsPresContext*          aPresContext,
+nsAbsoluteContainingBlock::Reflow(nsContainerFrame*        aDelegatingFrame,
+                                  nsPresContext*           aPresContext,
                                   const nsHTMLReflowState& aReflowState,
+                                  nsReflowStatus&          aReflowStatus,
                                   nscoord                  aContainingBlockWidth,
                                   nscoord                  aContainingBlockHeight,
                                   PRBool                   aCBWidthChanged,
                                   PRBool                   aCBHeightChanged,
                                   nsRect*                  aChildBounds)
 {
   // Initialize OUT parameter
   if (aChildBounds)
     aChildBounds->SetRect(0, 0, 0, 0);
+  nsReflowStatus reflowStatus = NS_FRAME_COMPLETE;
 
   PRBool reflowAll = aReflowState.ShouldReflowAllKids();
 
   nsIFrame* kidFrame;
+  nsOverflowContinuationTracker tracker(aPresContext, aDelegatingFrame, PR_TRUE);
   for (kidFrame = mAbsoluteFrames.FirstChild(); kidFrame; kidFrame = kidFrame->GetNextSibling()) {
     if (reflowAll ||
         NS_SUBTREE_DIRTY(kidFrame) ||
         FrameDependsOnContainer(kidFrame, aCBWidthChanged, aCBHeightChanged)) {
       // Reflow the frame
-      nsReflowStatus  kidStatus;
-      ReflowAbsoluteFrame(aDelegatingFrame, aPresContext, aReflowState, aContainingBlockWidth,
-                          aContainingBlockHeight, kidFrame, kidStatus, aChildBounds);
-    } else if (aChildBounds) {
-      aChildBounds->UnionRect(*aChildBounds, kidFrame->GetOverflowRect() +
-                                             kidFrame->GetPosition());
+      nsReflowStatus  kidStatus = NS_FRAME_COMPLETE;
+      ReflowAbsoluteFrame(aDelegatingFrame, aPresContext, aReflowState,
+                          aContainingBlockWidth, aContainingBlockHeight,
+                          kidFrame, kidStatus, aChildBounds);
+      nsIFrame* nextFrame = kidFrame->GetNextInFlow();
+      if (!NS_FRAME_IS_FULLY_COMPLETE(kidStatus)) {
+        // Need a continuation
+        if (!nextFrame) {
+          nsresult rv = nsHTMLContainerFrame::CreateNextInFlow(aPresContext,
+                          aDelegatingFrame, kidFrame, nextFrame);
+          NS_ENSURE_SUCCESS(rv, rv);
+          kidFrame->SetNextSibling(nextFrame->GetNextSibling());
+          nextFrame->SetNextSibling(nsnull);
+        }
+        // Add it as an overflow container.
+        //XXXfr This is a hack to fix some of our printing dataloss.
+        // See bug 154892. Not sure how to do it "right" yet; probably want
+        // to keep continuations within an nsAbsoluteContainingBlock eventually.
+        tracker.Insert(nextFrame, kidStatus);
+        reflowStatus = NS_FRAME_MERGE_INCOMPLETE(reflowStatus, kidStatus);
+      }
+      else {
+        // Delete any continuations
+        if (nextFrame) {
+          tracker.Finish(kidFrame);
+          static_cast<nsContainerFrame*>(nextFrame->GetParent())
+            ->DeleteNextInFlowChild(aPresContext, nextFrame);
+        }
+      }
+    }
+    else {
+      tracker.Skip(kidFrame, reflowStatus);
+      if (aChildBounds) {
+        aChildBounds->UnionRect(*aChildBounds, kidFrame->GetOverflowRect() +
+                                               kidFrame->GetPosition());
+      }
     }
   }
+  // Abspos frames can't cause their parent to be incomplete,
+  // only overflow incomplete.
+  if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus))
+    NS_FRAME_SET_OVERFLOW_INCOMPLETE(reflowStatus);
+
+  aReflowStatus = NS_FRAME_MERGE_INCOMPLETE(reflowStatus, aReflowStatus);
   return NS_OK;
 }
 
 static inline PRBool IsFixedPaddingSize(nsStyleUnit aUnit) {
   return aUnit == eStyleUnit_Coord || aUnit == eStyleUnit_Chars;
 }
 static inline PRBool IsFixedMarginSize(nsStyleUnit aUnit) {
   return aUnit == eStyleUnit_Coord || aUnit == eStyleUnit_Chars;
@@ -366,16 +408,29 @@ nsAbsoluteContainingBlock::ReflowAbsolut
   nsHTMLReflowState kidReflowState(aPresContext, aReflowState, aKidFrame,
                                    nsSize(availWidth, NS_UNCONSTRAINEDSIZE),
                                    aContainingBlockWidth,
                                    aContainingBlockHeight);
 
   // Send the WillReflow() notification and position the frame
   aKidFrame->WillReflow(aPresContext);
 
+  PRBool constrainHeight = (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE)
+    && (nsGkAtoms::fixedList != GetChildListName())
+       // Don't split fixed frames
+    && (aDelegatingFrame->GetType() != nsGkAtoms::positionedInlineFrame)
+       //XXX we don't handle splitting frames for inline absolute containing blocks yet
+    && (aKidFrame->GetRect().y <= aReflowState.availableHeight);
+       // Don't split things below the fold. (Ideally we shouldn't *have*
+       // anything totally below the fold, but we can't position frames
+       // across next-in-flow breaks yet.
+  if (constrainHeight) {
+    kidReflowState.availableHeight = aReflowState.availableHeight - aKidFrame->GetRect().y;
+  }
+
   // Do the reflow
   rv = aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus);
 
   // If we're solving for 'left' or 'top', then compute it now that we know the
   // width/height
   if ((NS_AUTOOFFSET == kidReflowState.mComputedOffsets.left) ||
       (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.top)) {
     if (-1 == aContainingBlockWidth) {
--- a/layout/generic/nsAbsoluteContainingBlock.h
+++ b/layout/generic/nsAbsoluteContainingBlock.h
@@ -41,16 +41,17 @@
  */
 
 #ifndef nsAbsoluteContainingBlock_h___
 #define nsAbsoluteContainingBlock_h___
 
 #include "nsFrameList.h"
 #include "nsHTMLReflowState.h"
 #include "nsGkAtoms.h"
+#include "nsContainerFrame.h"
 
 class nsIAtom;
 class nsIFrame;
 class nsPresContext;
 
 /**
  * This class contains the logic for being an absolute containing block.  This
  * class is used within viewport frames (for frames representing content with
@@ -108,19 +109,20 @@ public:
   // 'auto' for an offset, or a percentage based width or height.
   // If aChildBounds is set, it returns (in the local coordinate space) the 
   // bounding rect of the absolutely positioned child elements taking into 
   // account their overflow area (if it is visible).
   // @param aForceReflow if this is false, reflow for some absolutely
   //        positioned frames may be skipped based on whether they use
   //        placeholders for positioning and on whether the containing block
   //        width or height changed.
-  nsresult Reflow(nsIFrame*                aDelegatingFrame,
+  nsresult Reflow(nsContainerFrame*        aDelegatingFrame,
                   nsPresContext*           aPresContext,
                   const nsHTMLReflowState& aReflowState,
+                  nsReflowStatus&          aReflowStatus,
                   nscoord                  aContainingBlockWidth,
                   nscoord                  aContainingBlockHeight,
                   PRBool                   aCBWidthChanged,
                   PRBool                   aCBHeightChanged,
                   nsRect*                  aChildBounds = nsnull);
 
 
   void DestroyFrames(nsIFrame* aDelegatingFrame);
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1129,16 +1129,17 @@ nsBlockFrame::Reflow(nsPresContext*     
     // containing block and the containing block height is the
     // viewport height, which can't change during incremental
     // reflow.
     PRBool cbHeightChanged =
       !(isRoot && NS_UNCONSTRAINEDSIZE == aReflowState.ComputedHeight()) &&
       aMetrics.height != oldSize.height;
 
     rv = mAbsoluteContainer.Reflow(this, aPresContext, aReflowState,
+                                   state.mReflowStatus,
                                    containingBlockSize.width,
                                    containingBlockSize.height,
                                    cbWidthChanged, cbHeightChanged,
                                    &childBounds);
 
     //XXXfr Why isn't this rv (and others in this file) checked/returned?
 
     // Factor the absolutely positioned child bounds into the overflow area
@@ -1273,17 +1274,17 @@ nsBlockFrame::ComputeFinalSize(const nsH
         computedHeightLeftOver -= prev->GetRect().height;
       }
       // We just subtracted our top-border padding, since it was included in the
       // first frame's height. Add it back to get the content height.
       computedHeightLeftOver += aReflowState.mComputedBorderPadding.top;
       // We may have stretched the frame beyond its computed height. Oh well.
       computedHeightLeftOver = PR_MAX(0, computedHeightLeftOver);
     }
-    NS_ASSERTION(!( (mState & NS_FRAME_IS_OVERFLOW_CONTAINER)
+    NS_ASSERTION(!( IS_TRUE_OVERFLOW_CONTAINER(this)
                     && computedHeightLeftOver ),
                  "overflow container must not have computedHeightLeftOver");
 
     aMetrics.height = borderPadding.top + computedHeightLeftOver + borderPadding.bottom;
     if (NS_FRAME_IS_NOT_COMPLETE(aState.mReflowStatus)
         && aMetrics.height < aReflowState.availableHeight) {
       // We ran out of height on this page but we're incomplete
       // Set status to complete except for overflow
@@ -1357,16 +1358,24 @@ nsBlockFrame::ComputeFinalSize(const nsH
       // Our min-height or max-height made our height change.  Don't carry out
       // our kids' bottom margins.
       aMetrics.mCarriedOutBottomMargin.Zero();
     }
     autoHeight += borderPadding.top + borderPadding.bottom;
     aMetrics.height = autoHeight;
   }
 
+  if (IS_TRUE_OVERFLOW_CONTAINER(this) &&
+      NS_FRAME_IS_NOT_COMPLETE(aState.mReflowStatus)) {
+    // Overflow containers can only be overflow complete.
+    // Note that auto height overflow containers have no normal children
+    NS_ASSERTION(aMetrics.height == 0, "overflow containers must be zero-height");
+    NS_FRAME_SET_OVERFLOW_INCOMPLETE(aState.mReflowStatus);
+  }
+
 #ifdef DEBUG_blocks
   if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
     ListTag(stdout);
     printf(": WARNING: desired:%d,%d\n", aMetrics.width, aMetrics.height);
   }
 #endif
 }
 
@@ -1970,17 +1979,20 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
     if (lineIter != this->begin_lines()) {
       lineIter--; // I have lines; step back from dummy iterator to last line.
       nsBlockInFlowLineIterator bifLineIter(this, lineIter, PR_FALSE);
 
       // Check for next-in-flow-chain's first line.
       // (First, see if there is such a line, and second, see if it's clean)
       if (!bifLineIter.Next() ||                
           !bifLineIter.GetLine()->IsDirty()) {
-        NS_FRAME_SET_INCOMPLETE(aState.mReflowStatus);
+        if (IS_TRUE_OVERFLOW_CONTAINER(aState.mNextInFlow))
+          NS_FRAME_SET_OVERFLOW_INCOMPLETE(aState.mReflowStatus);
+        else
+          NS_FRAME_SET_INCOMPLETE(aState.mReflowStatus);
         skipPull=PR_TRUE;
       }
     }
   }
   
   if (!skipPull && aState.mNextInFlow) {
     // Pull data from a next-in-flow if there's still room for more
     // content here.
@@ -2936,17 +2948,17 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
       aState.mSpaceManager->PushState(&spaceManagerState);
     } else if (!applyTopMargin) {
       blockHtmlRS.mDiscoveredClearance = aState.mReflowState.mDiscoveredClearance;
     }
     
     nsReflowStatus frameReflowStatus = NS_FRAME_COMPLETE;
     rv = brc.ReflowBlock(availSpace, applyTopMargin, aState.mPrevBottomMargin,
                          clearance, aState.IsAdjacentWithTop(), computedOffsets,
-                         aLine.get(), blockHtmlRS, frameReflowStatus);
+                         aLine.get(), blockHtmlRS, frameReflowStatus, aState);
 
     // If this was a second-pass reflow and the block's vertical position
     // changed, invalidates from the first pass might have happened in the
     // wrong places.  Invalidate the entire overflow rect at the new position.
     if (!mayNeedRetry && clearanceFrame &&
         frame->GetRect().y != passOriginalY) {
       Invalidate(frame->GetOverflowRect() + frame->GetPosition());
     }
@@ -5039,35 +5051,34 @@ nsBlockFrame::RemoveFrame(nsIAtom*  aLis
                        NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
   }
   return rv;
 }
 
 void
 nsBlockFrame::DoRemoveOutOfFlowFrame(nsIFrame* aFrame)
 {
-  // First remove aFrame's next in flow
-  nsIFrame* nextInFlow = aFrame->GetNextInFlow();
-  if (nextInFlow) {
-    nsBlockFrame::DoRemoveOutOfFlowFrame(nextInFlow);
-  }
-  // Now remove aFrame
-  const nsStyleDisplay* display = aFrame->GetStyleDisplay();
-
   // The containing block is always the parent of aFrame.
   nsBlockFrame* block = (nsBlockFrame*)aFrame->GetParent();
 
   // Remove aFrame from the appropriate list.
+  const nsStyleDisplay* display = aFrame->GetStyleDisplay();
   if (display->IsAbsolutelyPositioned()) {
+    // This also deletes the next-in-flows
     block->mAbsoluteContainer.RemoveFrame(block,
                                           nsGkAtoms::absoluteList,
                                           aFrame);
-    aFrame->Destroy();
   }
   else {
+    // First remove aFrame's next in flow
+    nsIFrame* nextInFlow = aFrame->GetNextInFlow();
+    if (nextInFlow) {
+      nsBlockFrame::DoRemoveOutOfFlowFrame(nextInFlow);
+    }
+    // Now remove aFrame
     // This also destroys the frame.
     block->RemoveFloat(aFrame);
   }
 }
 
 /**
  * This helps us iterate over the list of all normal + overflow lines
  */
@@ -5179,31 +5190,33 @@ static nsresult RemoveBlockChild(nsIFram
 // start by locating aDeletedFrame and then scanning from that point
 // on looking for continuations.
 nsresult
 nsBlockFrame::DoRemoveFrame(nsIFrame* aDeletedFrame, PRBool aDestroyFrames,
                             PRBool aRemoveOnlyFluidContinuations)
 {
   // Clear our line cursor, since our lines may change.
   ClearLineCursor();
-        
+
+  nsPresContext* presContext = PresContext();
+  if (NS_FRAME_IS_OVERFLOW_CONTAINER & aDeletedFrame->GetStateBits()) {
+    if (aDestroyFrames)
+      nsContainerFrame::DeleteNextInFlowChild(presContext, aDeletedFrame);
+    else
+      return nsContainerFrame::StealFrame(presContext, aDeletedFrame);
+  }
+
   if (aDeletedFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
     NS_ASSERTION(aDestroyFrames, "We can't not destroy out of flows");
     DoRemoveOutOfFlowFrame(aDeletedFrame);
     return NS_OK;
   }
   
-  nsPresContext* presContext = PresContext();
   nsIPresShell* presShell = presContext->PresShell();
 
-  if (NS_FRAME_IS_OVERFLOW_CONTAINER & aDeletedFrame->GetStateBits()) {
-    nsContainerFrame::DeleteNextInFlowChild(presContext, aDeletedFrame);
-    return NS_OK;
-  }
-
   PRBool isPlaceholder = nsGkAtoms::placeholderFrame == aDeletedFrame->GetType();
   if (isPlaceholder) {
     nsFrameList* overflowPlaceholders = GetOverflowPlaceholders();
     if (overflowPlaceholders && overflowPlaceholders->RemoveFrame(aDeletedFrame)) {
       nsIFrame* nif = aDeletedFrame->GetNextInFlow();
       if (aDestroyFrames) {
         aDeletedFrame->Destroy();
       } else {
@@ -5588,17 +5601,17 @@ nsBlockFrame::ReflowFloat(nsBlockReflowS
       }
     }
 
     nsMargin offsets; // Don't bother returning this to the caller; it's stored
                       // on a frame property anyawy
     rv = brc.ReflowBlock(availSpace, PR_TRUE, margin,
                          0, isAdjacentWithTop,
                          offsets, nsnull, floatRS,
-                         aReflowStatus);
+                         aReflowStatus, aState);
   } while (NS_SUCCEEDED(rv) && clearanceFrame);
 
   // An incomplete reflow status means we should split the float 
   // if the height is constrained (bug 145305). 
   if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) && (NS_UNCONSTRAINEDSIZE == availHeight))
     aReflowStatus = NS_FRAME_COMPLETE;
 
   //XXXfr Floats can't be overflow incomplete yet
@@ -5700,25 +5713,25 @@ nsBlockFrame::ReflowFloat(nsBlockReflowS
 }
 
 //////////////////////////////////////////////////////////////////////
 // Painting, event handling
 
 PRIntn
 nsBlockFrame::GetSkipSides() const
 {
-  if (mState & NS_FRAME_IS_OVERFLOW_CONTAINER)
+  if (IS_TRUE_OVERFLOW_CONTAINER(this))
     return (1 << NS_SIDE_TOP) | (1 << NS_SIDE_BOTTOM);
 
   PRIntn skip = 0;
   if (GetPrevInFlow()) {
     skip |= 1 << NS_SIDE_TOP;
   }
   nsIFrame* nif = GetNextInFlow();
-  if (nif && !(nif->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
+  if (nif && !IS_TRUE_OVERFLOW_CONTAINER(nif)) {
     skip |= 1 << NS_SIDE_BOTTOM;
   }
   return skip;
 }
 
 #ifdef DEBUG
 static void ComputeCombinedArea(nsLineList& aLines,
                                 nscoord aWidth, nscoord aHeight,
--- a/layout/generic/nsBlockReflowContext.cpp
+++ b/layout/generic/nsBlockReflowContext.cpp
@@ -245,17 +245,18 @@ nsresult
 nsBlockReflowContext::ReflowBlock(const nsRect&       aSpace,
                                   PRBool              aApplyTopMargin,
                                   nsCollapsingMargin& aPrevMargin,
                                   nscoord             aClearance,
                                   PRBool              aIsAdjacentWithTop,
                                   nsMargin&           aComputedOffsets,
                                   nsLineBox*          aLine,
                                   nsHTMLReflowState&  aFrameRS,
-                                  nsReflowStatus&     aFrameReflowStatus)
+                                  nsReflowStatus&     aFrameReflowStatus,
+                                  nsBlockReflowState& aState)
 {
   nsresult rv = NS_OK;
   mFrame = aFrameRS.frame;
   mSpace = aSpace;
 
   const nsStyleDisplay* display = mFrame->GetStyleDisplay();
 
   aComputedOffsets = aFrameRS.mComputedOffsets;
@@ -372,16 +373,17 @@ nsBlockReflowContext::ReflowBlock(const 
       nsIFrame* kidNextInFlow = mFrame->GetNextInFlow();
       if (nsnull != kidNextInFlow) {
         // Remove all of the childs next-in-flows. Make sure that we ask
         // the right parent to do the removal (it's possible that the
         // parent is not this because we are executing pullup code).
         // Floats will eventually be removed via nsBlockFrame::RemoveFloat
         // which detaches the placeholder from the float.
 /* XXX promote DeleteChildsNextInFlow to nsIFrame to elminate this cast */
+        aState.mOverflowTracker.Finish(mFrame);
         static_cast<nsHTMLContainerFrame*>(kidNextInFlow->GetParent())
           ->DeleteNextInFlowChild(mPresContext, kidNextInFlow);
       }
     }
   }
 
   return rv;
 }
--- a/layout/generic/nsBlockReflowContext.h
+++ b/layout/generic/nsBlockReflowContext.h
@@ -66,17 +66,18 @@ public:
   nsresult ReflowBlock(const nsRect&       aSpace,
                        PRBool              aApplyTopMargin,
                        nsCollapsingMargin& aPrevMargin,
                        nscoord             aClearance,
                        PRBool              aIsAdjacentWithTop,
                        nsMargin&           aComputedOffsets,
                        nsLineBox*          aLine,
                        nsHTMLReflowState&  aReflowState,
-                       nsReflowStatus&     aReflowStatus);
+                       nsReflowStatus&     aReflowStatus,
+                       nsBlockReflowState& aState);
 
   PRBool PlaceBlock(const nsHTMLReflowState& aReflowState,
                     PRBool                   aForceFit,
                     nsLineBox*               aLine,
                     const nsMargin&          aComputedOffsets,
                     nsCollapsingMargin&      aBottomMarginResult /* out */,
                     nsRect&                  aInFlowBounds,
                     nsRect&                  aCombinedRect,
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -67,21 +67,21 @@ nsBlockReflowState::nsBlockReflowState(c
                                        PRBool aBlockNeedsSpaceManager)
   : mBlock(aFrame),
     mPresContext(aPresContext),
     mReflowState(aReflowState),
     mPrevBottomMargin(),
     mLineNumber(0),
     mFlags(0),
     mFloatBreakType(NS_STYLE_CLEAR_NONE),
-    mOverflowTracker(aPresContext, aFrame)
+    mOverflowTracker(aPresContext, aFrame, PR_FALSE)
 {
   SetFlag(BRS_ISFIRSTINFLOW, aFrame->GetPrevInFlow() == nsnull);
   SetFlag(BRS_ISOVERFLOWCONTAINER,
-          !!(aFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER));
+          IS_TRUE_OVERFLOW_CONTAINER(aFrame));
 
   const nsMargin& borderPadding = BorderPadding();
 
   if (aTopMarginRoot || 0 != aReflowState.mComputedBorderPadding.top) {
     SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
   }
   if (aBottomMarginRoot || 0 != aReflowState.mComputedBorderPadding.bottom) {
     SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -712,22 +712,22 @@ nsContainerFrame::ReflowChild(nsIFrame* 
 
   // Reflow the child frame
   result = aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState,
                              aStatus);
 
   // If the reflow was successful and the child frame is complete, delete any
   // next-in-flows
   if (NS_SUCCEEDED(result) && NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
-    if (aTracker) aTracker->Finish(aKidFrame);
     nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow();
     if (nsnull != kidNextInFlow) {
       // Remove all of the childs next-in-flows. Make sure that we ask
       // the right parent to do the removal (it's possible that the
       // parent is not this because we are executing pullup code)
+      if (aTracker) aTracker->Finish(aKidFrame);
       static_cast<nsContainerFrame*>(kidNextInFlow->GetParent())
         ->DeleteNextInFlowChild(aPresContext, kidNextInFlow);
     }
   }
   return result;
 }
 
 
@@ -872,17 +872,17 @@ nsContainerFrame::ReflowOverflowContaine
         }
       }
     }
   }
 
   if (!overflowContainers)
     return NS_OK; // nothing to reflow
 
-  nsOverflowContinuationTracker tracker(aPresContext, this, PR_FALSE);
+  nsOverflowContinuationTracker tracker(aPresContext, this, PR_FALSE, PR_FALSE);
   for (nsIFrame* frame = overflowContainers->FirstChild(); frame;
        frame = frame->GetNextSibling()) {
     if (NS_SUBTREE_DIRTY(frame)) {
       // Get prev-in-flow
       nsIFrame* prevInFlow = frame->GetPrevInFlow();
       NS_ASSERTION(prevInFlow,
                    "overflow container frame must have a prev-in-flow");
       NS_ASSERTION(frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER,
@@ -891,30 +891,54 @@ nsContainerFrame::ReflowOverflowContaine
 
       // Initialize reflow params
       nsSize availSpace(prevRect.width, aReflowState.availableHeight);
       nsHTMLReflowMetrics desiredSize;
       nsHTMLReflowState frameState(aPresContext, aReflowState,
                                    frame, availSpace);
       nsReflowStatus frameStatus = NS_FRAME_COMPLETE;
 
+      // Cache old bounds
+      nsRect oldRect = frame->GetRect();
+      nsRect oldOverflow = frame->GetOverflowRect();
+
       // Reflow
       rv = ReflowChild(frame, aPresContext, desiredSize, frameState,
-                       prevRect.x, 0, aFlags, frameStatus);
+                       prevRect.x, 0, aFlags, frameStatus, &tracker);
       NS_ENSURE_SUCCESS(rv, rv);
       //XXXfr Do we need to override any shrinkwrap effects here?
       // e.g. desiredSize.width = prevRect.width;
       rv = FinishReflowChild(frame, aPresContext, &frameState, desiredSize,
                              prevRect.x, 0, aFlags);
       NS_ENSURE_SUCCESS(rv, rv);
 
+      // Invalidate if there was a position or size change
+      nsRect rect = frame->GetRect();
+      if (rect != oldRect) {
+        nsRect dirtyRect = oldOverflow;
+        dirtyRect.MoveBy(oldRect.x, oldRect.y);
+        Invalidate(dirtyRect);
+
+        dirtyRect = frame->GetOverflowRect();
+        dirtyRect.MoveBy(rect.x, rect.y);
+        Invalidate(dirtyRect);
+      }
+
       // Handle continuations
-      NS_ASSERTION(NS_FRAME_IS_COMPLETE(frameStatus),
-                   "overflow container frames can't be incomplete, only overflow-incomplete");
       if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus)) {
+        if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
+          // Abspos frames can't cause their parent to be incomplete,
+          // only overflow incomplete.
+          NS_FRAME_SET_OVERFLOW_INCOMPLETE(frameStatus);
+        }
+        else {
+          NS_ASSERTION(NS_FRAME_IS_COMPLETE(frameStatus),
+                       "overflow container frames can't be incomplete, only overflow-incomplete");
+        }
+
         // Acquire a next-in-flow, creating it if necessary
         nsIFrame* nif = frame->GetNextInFlow();
         if (!nif) {
           rv = nsHTMLContainerFrame::CreateNextInFlow(aPresContext, this,
                                                       frame, nif);
           NS_ENSURE_SUCCESS(rv, rv);
           NS_ASSERTION(frameStatus & NS_FRAME_REFLOW_NEXTINFLOW,
                        "Someone forgot a REFLOW_NEXTINFLOW flag");
@@ -1013,16 +1037,18 @@ nsContainerFrame::DeleteNextInFlowChild(
     }
     for (PRInt32 i = frames.Count() - 1; i >= 0; --i) {
       nsIFrame* delFrame = static_cast<nsIFrame*>(frames.ElementAt(i));
       static_cast<nsContainerFrame*>(delFrame->GetParent())
         ->DeleteNextInFlowChild(aPresContext, delFrame);
     }
   }
 
+  aNextInFlow->Invalidate(aNextInFlow->GetOverflowRect());
+
   // Disconnect the next-in-flow from the flow list
   nsSplittableFrame::BreakFromPrevFlow(aNextInFlow);
 
   // Take the next-in-flow out of the parent's child list
   nsresult rv = StealFrame(aPresContext, aNextInFlow);
   NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame failure");
 
   // Delete the next-in-flow frame and its descendants.
@@ -1223,22 +1249,24 @@ nsContainerFrame::MoveOverflowToChildLis
     mFrames.AppendFrames(nsnull, overflowFrames);
     result = PR_TRUE;
   }
   return result;
 }
 
 nsOverflowContinuationTracker::nsOverflowContinuationTracker(nsPresContext*    aPresContext,
                                                              nsContainerFrame* aFrame,
+                                                             PRBool            aWalkOOFFrames,
                                                              PRBool            aSkipOverflowContainerChildren)
   : mOverflowContList(nsnull),
     mPrevOverflowCont(nsnull),
     mSentry(nsnull),
     mParent(aFrame),
-    mSkipOverflowContainerChildren(aSkipOverflowContainerChildren)
+    mSkipOverflowContainerChildren(aSkipOverflowContainerChildren),
+    mWalkOOFFrames(aWalkOOFFrames)
 {
   NS_PRECONDITION(aFrame, "null frame pointer");
   nsContainerFrame* next = static_cast<nsContainerFrame*>
                              (aFrame->GetNextInFlow());
   if (next) {
     mOverflowContList =
       next->GetPropTableFrames(aPresContext,
                                nsGkAtoms::overflowContainersProperty);
@@ -1269,42 +1297,55 @@ nsOverflowContinuationTracker::SetUpList
   if (mOverflowContList) {
     nsIFrame* cur = mOverflowContList->FirstChild();
     if (mSkipOverflowContainerChildren) {
       while (cur && (cur->GetPrevInFlow()->GetStateBits()
                      & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
         mPrevOverflowCont = cur;
         cur = cur->GetNextSibling();
       }
+      while (cur && (mWalkOOFFrames == cur->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
+        mPrevOverflowCont = cur;
+        cur = cur->GetNextSibling();
+      }
     }
     if (cur) {
       mSentry = cur->GetPrevInFlow();
     }
   }
 }
 
 /**
  * Helper function to step forward through the overflow continuations list.
- * Sets mSentry and mPrevOverflowCont as appropriate.
- * May only be called when we have already set up an mOverflowContList;
- * mOverflowContList cannot be null.
+ * Sets mSentry and mPrevOverflowCont, skipping over OOF or non-OOF frames
+ * as appropriate. May only be called when we have already set up an
+ * mOverflowContList; mOverflowContList cannot be null.
  */
 void
 nsOverflowContinuationTracker::StepForward()
 {
   NS_PRECONDITION(mOverflowContList, "null list");
 
   // Step forward
   if (mPrevOverflowCont) {
     mPrevOverflowCont = mPrevOverflowCont->GetNextSibling();
   }
   else {
     mPrevOverflowCont = mOverflowContList->FirstChild();
   }
 
+  // Skip over oof or non-oof frames as appropriate
+  if (mSkipOverflowContainerChildren) {
+    nsIFrame* cur = mPrevOverflowCont->GetNextSibling();
+    while (cur && (mWalkOOFFrames == cur->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
+      mPrevOverflowCont = cur;
+      cur = cur->GetNextSibling();
+    }
+  }
+
   // Set up the sentry
   mSentry = (mPrevOverflowCont->GetNextSibling())
             ? mPrevOverflowCont->GetNextSibling()->GetPrevInFlow()
             : nsnull;
 }
 
 nsresult
 nsOverflowContinuationTracker::Insert(nsIFrame*       aOverflowCont,
@@ -1358,32 +1399,33 @@ nsOverflowContinuationTracker::Insert(ns
   return rv;
 }
 
 void
 nsOverflowContinuationTracker::Finish(nsIFrame* aChild)
 {
   NS_PRECONDITION(aChild, "null ptr");
   NS_PRECONDITION(aChild->GetNextInFlow(),
-                "supposed to call Next *before* deleting next-in-flow!");
+                "supposed to call Finish *before* deleting next-in-flow!");
   if (aChild == mSentry) {
     // Make sure we drop all references if this was the only frame
     // in the overflow containers list
     if (mOverflowContList->FirstChild() == aChild->GetNextInFlow()
         && !aChild->GetNextInFlow()->GetNextSibling()) {
       mOverflowContList = nsnull;
       mPrevOverflowCont = nsnull;
       mSentry = nsnull;
       mParent = static_cast<nsContainerFrame*>(aChild->GetParent());
     }
     else {
       // Don't move the mPrevOverflowCont, but shift the sentry
       // The intervening overflow continuation will be deleted by our caller
-      nsIFrame* sentryCont = aChild->GetNextInFlow()->GetNextSibling();
-      mSentry = (sentryCont) ? sentryCont->GetPrevInFlow() : nsnull;
+      nsIFrame* prevOverflowCont = mPrevOverflowCont;
+      StepForward();
+      mPrevOverflowCont = prevOverflowCont;
     }
   }
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // Debugging
 
 #ifdef NS_DEBUG
--- a/layout/generic/nsContainerFrame.h
+++ b/layout/generic/nsContainerFrame.h
@@ -408,16 +408,32 @@ protected:
   nsresult SetPropTableFrames(nsPresContext*  aPresContext,
                               nsFrameList*    aFrameList,
                               nsIAtom*        aPropID) const;
   // ==========================================================================
 
   nsFrameList mFrames;
 };
 
+// ==========================================================================
+/* The out-of-flow-related code below is for a hacky way of splitting
+ * absolutely-positioned frames. Basically what we do is split the frame
+ * in nsAbsoluteContainingBlock and pretend the continuation is an overflow
+ * container. This isn't an ideal solution, but it lets us print the content
+ * at least. See bug 154892.
+ */
+
+#define IS_TRUE_OVERFLOW_CONTAINER(frame)                      \
+  (  (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)  \
+  && !(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)           )
+//XXXfr This check isn't quite correct, because it doesn't handle cases
+//      where the out-of-flow has overflow.. but that's rare.
+//      We'll need to revisit the way abspos continuations are handled later
+//      for various reasons, this detail is one of them. See bug 154892
+
 /**
  * Helper class for tracking overflow container continuations during reflow.
  *
  * A frame is related to two sets of overflow containers: those that /are/
  * its own children, and those that are /continuations/ of its children.
  * This tracker walks through those continuations (the frame's NIF's children)
  * and their prev-in-flows (a subset of the frame's normal and overflow
  * container children) in parallel. It allows the reflower to synchronously
@@ -437,22 +453,27 @@ protected:
  *     continuation.
  */
 class nsOverflowContinuationTracker {
 public:
   /**
    * Initializes an nsOverflowContinuationTracker to help track overflow
    * continuations of aFrame's children. Typically invoked on 'this'.
    *
+   * aWalkOOFFrames determines whether the walker skips out-of-flow frames
+   * or skips non-out-of-flow frames.
+   *
    * Don't set aSkipOverflowContainerChildren to PR_FALSE unless you plan
    * to walk your own overflow container children. (Usually they are handled
-   * by calling ReflowOverflowContainerChildren.)
+   * by calling ReflowOverflowContainerChildren.) aWalkOOFFrames is ignored
+   * if aSkipOverflowContainerChildren is false.
    */
   nsOverflowContinuationTracker(nsPresContext*    aPresContext,
                                 nsContainerFrame* aFrame,
+                                PRBool            aWalkOOFFrames,
                                 PRBool            aSkipOverflowContainerChildren = PR_TRUE);
   /**
    * This function adds an overflow continuation to our running list and
    * sets its NS_FRAME_IS_OVERFLOW_CONTAINER flag.
    *
    * aReflowStatus should preferably be specific to the recently-reflowed
    * child and not influenced by any of its siblings' statuses. This
    * function sets the NS_FRAME_IS_DIRTY bit on aOverflowCont if it needs
@@ -466,18 +487,19 @@ public:
    *
    * The caller MUST NOT disconnect the frame from its parent's
    * child list if it is already an NS_FRAME_IS_OVERFLOW_CONTAINER.
    * (In this case we will disconnect and reconnect it ourselves.)
    */
   nsresult Insert(nsIFrame*       aOverflowCont,
                   nsReflowStatus& aReflowStatus);
   /**
-   * This function should be called for each child that is reflowed
-   * but no longer has an overflow continuation. It increments our
+   * This function must be called for each child that is reflowed
+   * but no longer has an overflow continuation. (It may be called for
+   * other children, but in that case has no effect.) It increments our
    * walker and makes sure we drop any dangling pointers to its
    * next-in-flow. This function MUST be called before stealing or
    * deleting aChild's next-in-flow.
    */
   void Finish(nsIFrame* aChild);
 
   /**
    * This function should be called for each child that isn't reflowed.
@@ -519,13 +541,15 @@ private:
   nsIFrame* mSentry;
   /* Parent of all frames in mOverflowContList. If our mOverflowContList
      is an excessOverflowContainersProperty, then this our frame (the frame
      that was passed in to our constructor). Otherwise this is that frame's
      next-in-flow, and our mOverflowContList is mParent's
      overflowContainersProperty */
   nsContainerFrame* mParent;
   /* Tells SetUpListWalker whether or not to walk us past any continuations
-     of overflow containers. */
+     of overflow containers. aWalkOOFFrames is ignored when this is false. */
   PRBool mSkipOverflowContainerChildren;
+  /* Tells us whether to pay attention to OOF frames or non-OOF frames */
+  PRBool mWalkOOFFrames;
 };
 
 #endif /* nsContainerFrame_h___ */
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -4953,16 +4953,20 @@ nsFrame::GetLineNumber(nsIFrame *aFrame,
   nsCOMPtr<nsILineIteratorNavigator> it; 
   nsresult result = NS_ERROR_FAILURE;
   while (NS_FAILED(result) && blockFrame)
   {
     thisBlock = blockFrame;
     if (thisBlock->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
       //if we are searching for a frame that is not in flow we will not find it. 
       //we must instead look for its placeholder
+      if (thisBlock->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
+        // abspos continuations don't have placeholders, get the fif
+        thisBlock = thisBlock->GetFirstInFlow();
+      }
       thisBlock = frameManager->GetPlaceholderFrameFor(thisBlock);
       if (!thisBlock)
         return -1;
     }  
     blockFrame = thisBlock->GetParent();
     result = NS_OK;
     if (blockFrame) {
       result = blockFrame->QueryInterface(NS_GET_IID(nsILineIteratorNavigator),getter_AddRefs(it));
@@ -5439,18 +5443,25 @@ nsFrame::DoGetParentStyleContextFrame(ns
     // If this frame is one of the blocks that split an inline, we must
     // return the "special" inline parent, i.e., the parent that this
     // frame would have if we didn't mangle the frame structure.
     return GetCorrectedParent(aPresContext, this, aProviderFrame);
   }
 
   // For out-of-flow frames, we must resolve underneath the
   // placeholder's parent.
+  nsIFrame* oofFrame = this;
+  if ((oofFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
+      && (oofFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
+    // Out of flows that are overflow containers do not
+    // have placeholders. Use their first-in-flow's placeholder.
+    oofFrame = oofFrame->GetFirstInFlow();
+  }
   nsIFrame *placeholder =
-    aPresContext->FrameManager()->GetPlaceholderFrameFor(this);
+    aPresContext->FrameManager()->GetPlaceholderFrameFor(oofFrame);
   if (!placeholder) {
     NS_NOTREACHED("no placeholder frame for out-of-flow frame");
     GetCorrectedParent(aPresContext, this, aProviderFrame);
     return NS_ERROR_FAILURE;
   }
   return static_cast<nsFrame*>(placeholder)->
     GetParentStyleContextFrame(aPresContext, aProviderFrame, aIsChild);
 }
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -517,16 +517,20 @@ nsHTMLReflowState::InitFrameType()
   // Section 9.7 of the CSS2 spec indicates that absolute position
   // takes precedence over float which takes precedence over display.
   // Make sure the frame was actually moved out of the flow, and don't
   // just assume what the style says
   // XXXldb nsRuleNode::ComputeDisplayData should take care of this, right?
   if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
     if (disp->IsAbsolutelyPositioned()) {
       frameType = NS_CSS_FRAME_TYPE_ABSOLUTE;
+      //XXXfr hack for making frames behave properly when in overflow container lists
+      //      see bug 154892; need to revisit later
+      if (frame->GetPrevInFlow())
+        frameType = NS_CSS_FRAME_TYPE_BLOCK;
     }
     else if (NS_STYLE_FLOAT_NONE != disp->mFloats) {
       frameType = NS_CSS_FRAME_TYPE_FLOATING;
     } else {
       NS_ASSERTION(disp->mDisplay == NS_STYLE_DISPLAY_POPUP,
                    "unknown out of flow frame type");
       frameType = NS_CSS_FRAME_TYPE_UNKNOWN;
     }
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -1126,16 +1126,16 @@ nsPositionedInlineFrame::Reflow(nsPresCo
       aDesiredSize.width - computedBorder.LeftRight();
     nscoord containingBlockHeight =
       aDesiredSize.height - computedBorder.TopBottom();
 
     // Factor the absolutely positioned child bounds into the overflow area
     // Don't include this frame's bounds, nor its inline descendants' bounds,
     // and don't store the overflow property.
     // That will all be done by nsLineLayout::RelativePositionFrames.
-    rv = mAbsoluteContainer.Reflow(this, aPresContext, aReflowState,
+    rv = mAbsoluteContainer.Reflow(this, aPresContext, aReflowState, aStatus,
                                    containingBlockWidth, containingBlockHeight,
                                    PR_TRUE, PR_TRUE, // XXX could be optimized
                                    &aDesiredSize.mOverflowArea);
   }
 
   return rv;
 }
--- a/layout/generic/nsPageContentFrame.cpp
+++ b/layout/generic/nsPageContentFrame.cpp
@@ -110,17 +110,16 @@ nsPageContentFrame::Reflow(nsPresContext
         SetOverflowFrames(aPresContext, nextFrame);
         // Root overflow containers will be normal children of
         // the pageContentFrame, but that's ok because there
         // aren't any other frames we need to isolate them from
         // during reflow.
       }
       if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
         nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
-        NS_FRAME_SET_INCOMPLETE(aStatus); // page frames can't have overflow
       }
     }
 
     // The document element's background should cover the entire canvas, so
     // take into account the combined area and any space taken up by
     // absolutely positioned elements
     nsMargin padding(0,0,0,0);
 
@@ -142,17 +141,17 @@ nsPageContentFrame::Reflow(nsPresContext
 
     // Place and size the child
     FinishReflowChild(frame, aPresContext, &kidReflowState, aDesiredSize, 0, 0, 0);
 
     NS_ASSERTION(aPresContext->IsDynamic() || !NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
                   !frame->GetNextInFlow(), "bad child flow list");
   }
   // Reflow our fixed frames 
-  mFixedContainer.Reflow(this, aPresContext, aReflowState,
+  mFixedContainer.Reflow(this, aPresContext, aReflowState, aStatus,
                          aReflowState.availableWidth,
                          aReflowState.availableHeight,
                          PR_TRUE, PR_TRUE); // XXX could be optimized
 
   // Return our desired size
   aDesiredSize.width = aReflowState.availableWidth;
   if (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
     aDesiredSize.height = aReflowState.availableHeight;
--- a/layout/generic/nsSimplePageSequence.cpp
+++ b/layout/generic/nsSimplePageSequence.cpp
@@ -302,17 +302,17 @@ nsSimplePageSequenceFrame::Reflow(nsPres
     y += kidSize.height;
 
     // Leave a slight gap between the pages
     y += deadSpaceGap;
 
     // Is the page complete?
     nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow();
 
-    if (NS_FRAME_IS_COMPLETE(status)) {
+    if (NS_FRAME_IS_FULLY_COMPLETE(status)) {
       NS_ASSERTION(nsnull == kidNextInFlow, "bad child flow list");
     } else if (nsnull == kidNextInFlow) {
       // The page isn't complete and it doesn't have a next-in-flow, so
       // create a continuing page
       nsIFrame* continuingPage;
       nsresult rv = CreateContinuingPageFrame(aPresContext, kidFrame,
                                               &continuingPage);
       if (NS_FAILED(rv)) {
--- a/layout/generic/nsViewportFrame.cpp
+++ b/layout/generic/nsViewportFrame.cpp
@@ -311,17 +311,17 @@ ViewportFrame::Reflow(nsPresContext*    
   nsIFrame* f;
   mFixedContainer.FirstChild(this, nsGkAtoms::fixedList, &f);
   NS_ASSERTION(!f || (offset.x == 0 && offset.y == 0),
                "We don't handle correct positioning of fixed frames with "
                "scrollbars in odd positions");
 #endif
 
   // Just reflow all the fixed-pos frames.
-  rv = mFixedContainer.Reflow(this, aPresContext, reflowState,
+  rv = mFixedContainer.Reflow(this, aPresContext, reflowState, aStatus,
                               reflowState.ComputedWidth(),
                               reflowState.ComputedHeight(),
                               PR_TRUE, PR_TRUE); // XXX could be optimized
 
   // If we were dirty then do a repaint
   if (GetStateBits() & NS_FRAME_IS_DIRTY) {
     nsRect damageRect(0, 0, aDesiredSize.width, aDesiredSize.height);
     Invalidate(damageRect, PR_FALSE);
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/abspos-overflow-01-cols.ref.xhtml
@@ -0,0 +1,73 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Multi-column Layout: AbsPos Pagination (Interlaced)</title>
+  <link rel="author" title="Elika J. Etemad" href="http://fantasai.inkedblade.net/contact"/>
+  <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#the-height-property"/>
+  <link rel="help" href="http://www.w3.org/TR/CSS21/syndata.html#length-units"/>
+  <style type="text/css">
+    html {
+      background: white;
+    }
+
+    .following {
+      margin: 0;
+      font-size: 10pt;
+      line-height: 10pt;
+      font-family: sans-serif;
+      text-align: center;
+      width: 100pt;
+    }
+    #colset {
+      width: 300pt;
+      height: 2in;
+      border: silver 2pt;
+      border-style: none solid;
+    }
+    #redline {
+      width: 303pt;
+      border-top: 4px solid lime;
+      margin-top: -1in;
+      position: relative;
+      z-index: -1;
+    }
+  </style>
+ </head>
+ <body>
+  <div id="colset">
+    <div>
+      <div class="ocontainer">
+        <div class="overflow o1"></div>
+      </div>
+      <div class="container">
+        <div class="overflow a1"></div>
+        <div class="overflow a2"></div>
+        <div class="overflow a3"></div>
+        <div class="overflow a4"></div>
+      </div>
+      <div class="container">
+        <div class="overflow b1"></div>
+        <div class="overflow b2"></div>
+        <div class="overflow b3"></div>
+        <div class="overflow b4">
+          <div class="overflow child1"></div>
+          <div class="overflow child2"></div>
+        </div>
+        <div class="overflow b5"></div>
+        <div class="overflow b6"></div>
+      </div>
+    </div>
+    <p class="following f1">
+      There must be a single green line and no red.
+    </p>
+    <div class="container">
+      <div class="overflow c1"></div>
+      <div class="overflow c2"></div>
+      <div class="overflow c3"></div>
+      <div class="overflow c4"></div>
+    </div>
+    <div class="following f2"></div>
+  </div>
+  <div id="redline"></div>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/abspos-overflow-01-cols.xhtml
@@ -0,0 +1,188 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Multi-column Layout: AbsPos Pagination (Interlaced)</title>
+  <link rel="author" title="Elika J. Etemad" href="http://fantasai.inkedblade.net/contact"/>
+  <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#the-height-property"/>
+  <link rel="help" href="http://www.w3.org/TR/CSS21/syndata.html#length-units"/>
+  <style type="text/css">
+    html {
+      background: white;
+    }
+
+    .container {
+      background: red;
+      height: 24pt;
+      position: relative;
+    }
+    .overflow {
+      width: 10pt;
+      border-bottom: lime 4px solid;
+      top: 0;
+    }
+    .following {
+      font-size: 10pt;
+      line-height: 10pt;
+      font-family: sans-serif;
+      text-align: center;
+      position: relative;
+      background: white;
+      width: 100pt;
+    }
+    #colset {
+      width: 300pt;
+      height: 2in;
+      -moz-column-count: 3;
+      -moz-column-gap: 0;
+      border: silver 2pt;
+      border-style: none solid;
+    }
+    #redline {
+      width: 303pt;
+      border-top: 4px solid red;
+      margin-top: -1in;
+      position: relative;
+      z-index: -1;
+    }
+
+    .ocontainer {
+      height: 0;
+    }
+    .o1 { /* 3rd col */
+      height: 5in;
+    }
+    .a1 { /* 1st col */
+      position: absolute;
+      height: 1in;
+      width: 33pt;
+    }
+    .a2 { /* 2nd col */
+      position: absolute;
+      height: 3in;
+      width: 25pt;
+      margin-left: 25pt;
+    }
+    .a3 { /* 3rd col */
+      position: absolute;
+      height: 5in;
+      margin-left: 10pt;
+    }
+    .a4 { /* 2nd col */
+      width: 25pt;
+      height: 3in;
+    }
+
+    .b1 { /* 3rd col */
+      position: absolute;
+      height: 336pt;
+      margin-left: 20pt;
+    }
+    .b2 { /* 2nd col */
+      position: absolute;
+      height: 192pt;
+      width: 25pt;
+      margin-left: 50pt;
+    }
+    .b3 { /* 3rd col */
+      position: absolute;
+      height: 336pt;
+      margin-left: 30pt;
+    }
+    .b4 { /* 1st col, but no border */
+      position: absolute;
+      height: 48pt;
+      border-bottom: none;
+    }
+    .b4 .child1 { /* 1st col */
+      position: absolute;
+      height: 100%;
+      width: 33pt;
+      margin-left: 33pt;
+    }
+    .b4 .child2 { /* 3rd col */
+      height: 336pt;
+      margin-left: 40pt;
+
+    }
+    .b5 { /* 1st col */
+      position: absolute;
+      height: 48pt;
+      width: 34pt;
+      margin-left: 66pt;
+    }
+    .b6 { /* 3rd col */
+      height: 336pt;
+      margin-left: 50pt;
+    }
+
+    .c1 { /* 3rd col */
+      position: absolute;
+      height: 3in;
+      margin-left: 60pt;
+    }
+    .c2 { /* 2nd col */
+      position: absolute;
+      height: 1in;
+      width: 25pt;
+      margin-left: 75pt;
+    }
+    .c3 { /* 3rd col */
+      position: absolute;
+      height: 3in;
+      margin-left: 70pt;
+    }
+    .c4 { /* 3rd col */
+      height: 3in;
+      width: 20pt;
+      margin-left: 80pt;
+    }
+
+    .f1 {
+      margin-top: -48pt;
+      height: 48pt;
+      margin-bottom: 96pt;
+    }
+    .f2 {
+      margin-top: -24pt;
+      height: 24pt;
+    }
+  </style>
+ </head>
+ <body>
+  <div id="colset">
+    <div>
+      <div class="ocontainer">
+        <div class="overflow o1"></div>
+      </div>
+      <div class="container">
+        <div class="overflow a1"></div>
+        <div class="overflow a2"></div>
+        <div class="overflow a3"></div>
+        <div class="overflow a4"></div>
+      </div>
+      <div class="container">
+        <div class="overflow b1"></div>
+        <div class="overflow b2"></div>
+        <div class="overflow b3"></div>
+        <div class="overflow b4">
+          <div class="overflow child1"></div>
+          <div class="overflow child2"></div>
+        </div>
+        <div class="overflow b5"></div>
+        <div class="overflow b6"></div>
+      </div>
+    </div>
+    <p class="following f1">
+      There must be a single green line and no red.
+    </p>
+    <div class="container">
+      <div class="overflow c1"></div>
+      <div class="overflow c2"></div>
+      <div class="overflow c3"></div>
+      <div class="overflow c4"></div>
+    </div>
+    <div class="following f2"></div>
+  </div>
+  <div id="redline"></div>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/abspos-overflow-01.ref.xhtml
@@ -0,0 +1,47 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-print">
+ <head>
+  <title>Multi-column Layout: AbsPos Pagination (Interlaced)</title>
+  <link rel="author" title="Elika J. Etemad" href="http://fantasai.inkedblade.net/contact"/>
+  <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#the-height-property"/>
+  <link rel="help" href="http://www.w3.org/TR/CSS21/syndata.html#length-units"/>
+  <style type="text/css">
+    /* If the reftest print size change, this needs to change too. */
+    html, body, p {
+      margin: 0;
+      padding: 0;
+    }
+
+    .box {
+      font-size: 10pt;
+      line-height: 10pt;
+      font-family: sans-serif;
+      text-align: center;
+      position: relative;
+      border-bottom: lime 4px solid;
+      margin-top: -4px;
+      height: 2in;
+    }
+    #pageset {
+      width: 100pt;
+      border: silver 2pt;
+      border-style: none solid;
+      height: 6in;
+    }
+
+    .n1 {
+      margin: 0;
+      height: 1in;
+    }
+  </style>
+ </head>
+ <body>
+  <div id="pageset">
+    <p class="box n1">
+      There must be 3 pages, a single green line on each page, and no red.
+    </p>
+    <p class="box"></p>
+    <p class="box"></p>
+  </div>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/abspos-overflow-01.xhtml
@@ -0,0 +1,201 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-print">
+ <head>
+  <title>Multi-column Layout: AbsPos Pagination (Interlaced)</title>
+  <link rel="author" title="Elika J. Etemad" href="http://fantasai.inkedblade.net/contact"/>
+  <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#the-height-property"/>
+  <link rel="help" href="http://www.w3.org/TR/CSS21/syndata.html#length-units"/>
+  <style type="text/css">
+    /* If the reftest print size change, this needs to change too. */
+    html, body {
+      margin: 0;
+      padding: 0;
+    }
+
+    .container {
+      background: red;
+      height: 24pt;
+      position: relative;
+    }
+    .overflow {
+      width: 10pt;
+      border-bottom: lime 4px solid;
+      top: 0;
+    }
+    .following {
+      font-size: 10pt;
+      line-height: 10pt;
+      font-family: sans-serif;
+      text-align: center;
+      position: relative;
+      background: white;
+      width: 100pt;
+    }
+    #pageset {
+      width: 100pt;
+      border: silver 2pt;
+      border-style: none solid;
+      height: 6in;
+    }
+    .redline {
+      float: left;
+      margin-right: -103pt;
+      width: 103pt;
+      border-bottom: 8px solid red;
+      position: relative;
+      z-index: -1;
+    }
+    .r1 {
+      height: 50%;
+    }
+    .r2 {
+      height: 150%;
+    }
+    .r3 {
+      height: 250%;
+    }
+
+    .ocontainer {
+      height: 0;
+    }
+    .o1 { /* 3rd page */
+      height: 5in;
+    }
+    .a1 { /* 1st page */
+      position: absolute;
+      height: 1in;
+      width: 33pt;
+    }
+    .a2 { /* 2nd page */
+      position: absolute;
+      height: 3in;
+      width: 25pt;
+      margin-left: 25pt;
+    }
+    .a3 { /* 3rd page */
+      position: absolute;
+      height: 5in;
+      margin-left: 10pt;
+    }
+    .a4 { /* 2nd page */
+      width: 25pt;
+      height: 3in;
+    }
+
+    .b1 { /* 3rd page */
+      position: absolute;
+      height: 336pt;
+      margin-left: 20pt;
+    }
+    .b2 { /* 2nd page */
+      position: absolute;
+      height: 192pt;
+      width: 25pt;
+      margin-left: 50pt;
+    }
+    .b3 { /* 3rd page */
+      position: absolute;
+      height: 336pt;
+      margin-left: 30pt;
+    }
+    .b4 { /* 1st col, but no border */
+      position: absolute;
+      height: 48pt;
+      border-bottom: none;
+    }
+    .b4 .child1 { /* 1st page */
+      position: absolute;
+      height: 100%;
+      width: 33pt;
+      margin-left: 33pt;
+    }
+    .b4 .child2 { /* 3rd page */
+      height: 336pt;
+      margin-left: 40pt;
+
+    }
+    .b5 { /* 1st page */
+      position: absolute;
+      height: 48pt;
+      width: 34pt;
+      margin-left: 66pt;
+    }
+    .b6 { /* 3rd page */
+      height: 336pt;
+      margin-left: 50pt;
+    }
+
+    .c1 { /* 3rd page */
+      position: absolute;
+      height: 3in;
+      margin-left: 60pt;
+    }
+    .c2 { /* 2nd page */
+      position: absolute;
+      height: 1in;
+      width: 25pt;
+      margin-left: 75pt;
+    }
+    .c3 { /* 3rd page */
+      position: absolute;
+      height: 3in;
+      margin-left: 70pt;
+    }
+    .c4 { /* 3rd page */
+      height: 3in;
+      width: 20pt;
+      margin-left: 80pt;
+    }
+
+    .f1 {
+      margin-top: -48pt;
+      height: 48pt;
+      margin-bottom: 96pt;
+    }
+    .f2 {
+      margin-top: -24pt;
+      height: 24pt;
+    }
+  </style>
+ </head>
+ <body>
+  <div class="redline r1"></div>
+  <div class="redline r2"></div>
+  <div class="redline r3"></div>
+
+  <div id="pageset">
+    <div>
+      <div class="ocontainer">
+        <div class="overflow o1"></div>
+      </div>
+      <div class="container">
+        <div class="overflow a1"></div>
+        <div class="overflow a2"></div>
+        <div class="overflow a3"></div>
+        <div class="overflow a4"></div>
+      </div>
+      <div class="container">
+        <div class="overflow b1"></div>
+        <div class="overflow b2"></div>
+        <div class="overflow b3"></div>
+        <div class="overflow b4">
+          <div class="overflow child1"></div>
+          <div class="overflow child2"></div>
+        </div>
+        <div class="overflow b5"></div>
+        <div class="overflow b6"></div>
+      </div>
+    </div>
+    <p class="following f1">
+      There must be 3 pages, a single green line on each page, and no red.
+    </p>
+    <div class="container">
+      <div class="overflow c1"></div>
+      <div class="overflow c2"></div>
+      <div class="overflow c3"></div>
+      <div class="overflow c4"></div>
+    </div>
+    <div class="following f2"></div>
+  </div>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/blank.html
@@ -0,0 +1,1 @@
+<!DOCTYPE html><html class="reftest-print"><style>html{font-size:12pt}</style>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/dynamic-abspos-overflow-01-cols.ref.xhtml
@@ -0,0 +1,79 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>Multi-column Layout: AbsPos Pagination (Interlaced Dynamic Height)</title>
+  <link rel="author" title="Elika J. Etemad" href="http://fantasai.inkedblade.net/contact"/>
+  <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#the-height-property"/>
+  <link rel="help" href="http://www.w3.org/TR/CSS21/syndata.html#length-units"/>
+  <style type="text/css">
+    html {
+      background: white;
+    }
+
+    #colset {
+      position: relative;
+      padding-top: 1px;
+      margin-top: -1px;
+      width: 300pt;
+      height: 2in;
+      border: silver 2pt;
+      border-style: none solid;
+    }
+
+    .centerline {
+      margin: 0 auto;
+      bottom: 0;
+      position: absolute;
+      width: 8px;
+      background: aqua;
+    }
+    #c1 {
+      height: 96pt;
+      right: 200pt;
+      left: 0;
+    }
+    #c2 {
+      height: 120pt;
+      right: 100pt;
+      left: 100pt;
+    }
+    #c3 {
+      height: 144pt;
+      right: 0;
+      left: 200pt;
+    }
+
+    #redline {
+      border-top: 8px solid lime;
+      margin-top: 1in;
+      position: relative;
+    }
+
+    #dynamo {
+      position: relative;
+      margin: -8px auto -8px;
+      width: 8px;
+      border-top: 8px solid orange;
+    }
+
+  </style>
+ </head>
+ <body>
+  <p>There must be a single green line with an orange square where
+    it intersects with the middle aqua line, and no red. The following
+    links must move the orange square to the intersection with the
+    indicated aqua line:</p>
+  <p>
+    <a href="">Left</a>
+    <a href="">Center</a>
+    <a href="">Right</a>
+  </p>
+  <div id="colset">
+    <div class="centerline" id="c1"></div>
+    <div class="centerline" id="c2"></div>
+    <div class="centerline" id="c3"></div>
+    <div id="redline"></div>
+    <div id="dynamo"></div>
+  </div>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/dynamic-abspos-overflow-01-cols.xhtml
@@ -0,0 +1,238 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
+ <head>
+  <title>Multi-column Layout: AbsPos Pagination (Interlaced Dynamic Height)</title>
+  <link rel="author" title="Elika J. Etemad" href="http://fantasai.inkedblade.net/contact"/>
+  <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#the-height-property"/>
+  <link rel="help" href="http://www.w3.org/TR/CSS21/syndata.html#length-units"/>
+  <style type="text/css">
+    html {
+      background: white;
+    }
+
+    .container {
+      background: red;
+      height: 24pt;
+      position: relative;
+    }
+    .overflow {
+      width: 10pt;
+      border-bottom: lime 8px solid;
+      top: 0;
+    }
+    .following {
+      position: relative;
+      background: white;
+      width: 100pt;
+    }
+    #colset {
+      width: 300pt;
+      height: 2in;
+      -moz-column-count: 3;
+      -moz-column-gap: 0;
+      border: silver 2pt;
+      border-style: none solid;
+    }
+    #redline {
+      width: 303pt;
+      border-top: 8px solid red;
+      margin-top: -1in;
+      position: relative;
+      z-index: -1;
+    }
+
+    .ocontainer {
+      height: 0;
+      position: relative;
+    }
+    .o1 { /* 3rd col */
+      height: 5in;
+    }
+    .a1 { /* 1st col */
+      position: absolute;
+      height: 1in;
+      width: 33pt;
+    }
+    .a2 { /* 2nd col */
+      position: absolute;
+      height: 3in;
+      width: 25pt;
+      margin-left: 25pt;
+    }
+    .a3 { /* 3rd col */
+      position: absolute;
+      height: 5in;
+      margin-left: 10pt;
+    }
+    .a4 { /* 2nd col */
+      width: 25pt;
+      height: 3in;
+    }
+
+    .b1 { /* 3rd col */
+      position: absolute;
+      height: 336pt;
+      margin-left: 20pt;
+    }
+    .b2 { /* 2nd col */
+      position: absolute;
+      height: 192pt;
+      width: 25pt;
+      margin-left: 50pt;
+    }
+    .b3 { /* 3rd col */
+      position: absolute;
+      height: 336pt;
+      margin-left: 30pt;
+    }
+    .b4 { /* 1st col, but no border */
+      position: absolute;
+      height: 48pt;
+      border-bottom: none;
+    }
+    .b4 .child1 { /* 1st col */
+      position: absolute;
+      height: 100%;
+      width: 33pt;
+      margin-left: 33pt;
+    }
+    .b4 .child2 { /* 3rd col */
+      height: 336pt;
+      margin-left: 40pt;
+
+    }
+    .b5 { /* 1st col */
+      position: absolute;
+      height: 48pt;
+      width: 34pt;
+      margin-left: 66pt;
+    }
+    .b6 { /* 3rd col */
+      height: 336pt;
+      margin-left: 50pt;
+    }
+
+    .c1 { /* 3rd col */
+      position: absolute;
+      height: 3in;
+      margin-left: 60pt;
+    }
+    .c2 { /* 2nd col */
+      position: absolute;
+      height: 1in;
+      width: 25pt;
+      margin-left: 75pt;
+    }
+    .c3 { /* 3rd col */
+      position: absolute;
+      height: 3in;
+      margin-left: 70pt;
+    }
+    .c4 { /* 3rd col */
+      height: 3in;
+      width: 20pt;
+      margin-left: 80pt;
+    }
+
+    .f1 {
+      margin-top: -48pt;
+      height: 48pt;
+      margin-bottom: 96pt;
+    }
+    .f2 {
+      margin-top: -24pt;
+      height: 24pt;
+    }
+
+    .centerline {
+      margin: 0 auto;
+      top: 0;
+      left: 0;
+      right: 0;
+      position: absolute;
+      width: 8px;
+      height: 6in;
+      background: aqua;
+    }
+
+    #dynamo {
+      background: transparent;
+      border-bottom: 8px solid orange;
+      z-index: 10;
+      height: 192pt;
+    }
+
+  </style>
+ </head>
+ <body onload="document.getElementById('dynamo').style.height = '48pt';
+               document.getElementById('dynamo').offsetHeight;
+               document.getElementById('dynamo').style.height = '336pt';
+               document.getElementById('dynamo').offsetHeight;
+               document.getElementById('dynamo').style.height = '48pt';
+               document.getElementById('dynamo').offsetHeight;
+               document.getElementById('dynamo').style.height = '192pt';
+               document.getElementById('dynamo').offsetHeight;
+               document.getElementById('dynamo').style.height = '1500pt';
+               document.getElementById('dynamo').offsetHeight;
+               document.getElementById('dynamo').style.height = '48pt';
+               document.getElementById('dynamo').offsetHeight;
+               document.getElementById('dynamo').style.height = '192pt';
+               document.getElementById('dynamo').offsetHeight;
+               document.getElementById('dynamo').style.height = '336pt';
+               document.getElementById('dynamo').offsetHeight;
+               document.getElementById('dynamo').style.height = '192pt';
+               document.getElementById('dynamo').offsetHeight;
+               document.getElementById('dynamo').style.height = '48pt';
+               document.getElementById('dynamo').offsetHeight;
+               document.getElementById('dynamo').style.height = '192pt';
+               document.documentElement.className = ''
+              ">
+  <p>There must be a single green line with an orange square where
+    it intersects with the middle aqua line, and no red. The following
+    links must move the orange square to the intersection with the
+    indicated aqua line:</p>
+  <p>
+    <a href="" onclick="document.getElementById('dynamo').style.height = '48pt'; return false;">Left</a>
+    <a href="" onclick="document.getElementById('dynamo').style.height = '192pt'; return false;">Center</a>
+    <a href="" onclick="document.getElementById('dynamo').style.height = '336pt'; return false;">Right</a>
+  </p>
+  <div id="colset">
+    <div>
+      <div class="ocontainer">
+        <div class="centerline"></div>
+        <div class="overflow o1"></div>
+      </div>
+      <div class="container">
+        <div class="overflow a1"></div>
+        <div class="overflow a2"></div>
+        <div class="overflow a3"></div>
+        <div class="overflow a4"></div>
+      </div>
+      <div class="ocontainer">
+        <div id="dynamo" class="centerline"></div>
+      </div>
+      <div class="container">
+        <div class="overflow b1"></div>
+        <div class="overflow b2"></div>
+        <div class="overflow b3"></div>
+        <div class="overflow b4">
+          <div class="overflow child1"></div>
+          <div class="overflow child2"></div>
+        </div>
+        <div class="overflow b5"></div>
+        <div class="overflow b6"></div>
+      </div>
+    </div>
+    <p class="following f1">
+    </p>
+    <div class="container">
+      <div class="overflow c1"></div>
+      <div class="overflow c2"></div>
+      <div class="overflow c3"></div>
+      <div class="overflow c4"></div>
+    </div>
+    <div class="following f2"></div>
+  </div>
+  <div id="redline"></div>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/pagination/reftest.list
@@ -0,0 +1,7 @@
+# Sanity check
+== blank.html blank.html
+
+# 
+== abspos-overflow-01.xhtml abspos-overflow-01.ref.xhtml
+== abspos-overflow-01-cols.xhtml abspos-overflow-01-cols.ref.xhtml
+# fails for no apparent reason on my system, uncomment if it passes on yours (my system is weird) == dynamic-abspos-overflow-01-cols.xhtml dynamic-abspos-overflow-01-cols.ref.xhtml
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -2,16 +2,17 @@
 # bugzilla and note the bug number as a comment on the line with the
 # failing test.
 
 # verify the tests work
 include reftest-sanity/reftest.list
 
 # printing
 include printing/reftest.list
+include pagination/reftest.list
 
 # bugs/
 include bugs/reftest.list
 
 # object/
 include object/reftest.list
 
 # pixel-rounding/