Bug 492627 - Remove Placeholder Continuations [Part V: Reimplement float splitting without placeholder continuations] r=roc
authorfantasai <fantasai.cvs@inkedblade.net>
Mon, 31 Aug 2009 11:25:36 -0700
changeset 32108 28008648ca049b3cfc661700e2b4bf2d586e864a
parent 32107 9d788a1b2364c35fbd60bd77fa68cdc2e73f54a6
child 32109 ccbef5922a0f8027fbc088c159a9e6af15045b76
push id8851
push userfantasai.cvs@inkedblade.net
push dateMon, 31 Aug 2009 19:40:38 +0000
treeherdermozilla-central@1b724a06a345 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs492627
milestone1.9.3a1pre
Bug 492627 - Remove Placeholder Continuations [Part V: Reimplement float splitting without placeholder continuations] r=roc
content/base/src/nsGkAtomList.h
layout/base/nsLayoutUtils.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
layout/generic/nsBlockReflowState.cpp
layout/generic/nsBlockReflowState.h
layout/generic/nsContainerFrame.cpp
layout/generic/nsContainerFrame.h
layout/generic/nsFrame.cpp
layout/generic/nsInlineFrame.cpp
layout/generic/nsLineBox.cpp
layout/generic/nsLineBox.h
layout/generic/nsLineLayout.h
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1640,16 +1640,17 @@ GK_ATOM(durationchange, "durationchange"
 GK_ATOM(volumechange, "volumechange")
 #endif
 
 // Frame property names
 GK_ATOM(boxMetricsProperty, "BoxMetricsProperty") // nsBoxLayoutMetrics*
 GK_ATOM(changeListProperty, "ChangeListProperty") // void*
 GK_ATOM(collapseOffsetProperty, "CollapseOffsetProperty")  // nsPoint*
 GK_ATOM(computedOffsetProperty, "ComputedOffsetProperty")  // nsPoint*
+GK_ATOM(floatContinuationProperty, "FloatContinuationProperty") // nsFrameList*
 GK_ATOM(floatRegionProperty, "FloatRegionProperty") // nsRect*
 GK_ATOM(generatedContent, "GeneratedContentProperty")  // nsCOMArray<nsIContent>*
 #ifdef MOZ_MATHML
 GK_ATOM(HTMLReflowMetricsProperty, "HTMLReflowMetricsProperty") // nsHTMLReflowMetrics*
 #endif
 GK_ATOM(IBSplitSpecialPrevSibling, "IBSplitSpecialPrevSibling")// nsIFrame*
 GK_ATOM(IBSplitSpecialSibling, "IBSplitSpecialSibling")    // nsIFrame*
 GK_ATOM(lineCursorProperty, "LineCursorProperty") // nsLineBox*
@@ -1658,17 +1659,16 @@ GK_ATOM(maxElementWidthProperty, "MaxEle
 GK_ATOM(outlineInnerRectProperty, "OutlineInnerRectProperty") // nsRect*
 GK_ATOM(outOfFlowDirtyRectProperty, "OutOfFlowDirtyRectProperty") // nsRect*
 GK_ATOM(overflowAreaProperty, "OverflowArea")              // nsRect*
 GK_ATOM(overflowProperty, "OverflowProperty")              // list of nsIFrame*
 GK_ATOM(overflowContainersProperty, "OverflowContainersProperty")             // nsFrameList*
 GK_ATOM(excessOverflowContainersProperty, "ExcessOverflowContainersProperty") // nsFrameList*
 GK_ATOM(overflowLinesProperty, "OverflowLinesProperty")    // list of nsLineBox*
 GK_ATOM(overflowOutOfFlowsProperty, "OverflowOutOfFlowsProperty")      // nsFrameList*
-GK_ATOM(overflowPlaceholdersProperty, "OverflowPlaceholdersProperty")  // nsFrameList*
 GK_ATOM(preEffectsBBoxProperty, "PreEffectsBBoxProperty") // nsRect*
 GK_ATOM(preTransformBBoxProperty, "PreTransformBBoxProperty") // nsRect*
 GK_ATOM(rowUnpaginatedHeightProperty, "RowUnpaginatedHeightProperty")  // nscoord*
 GK_ATOM(tabWidthProperty, "TabWidthProperty")              // nsTArray<TabSetting>* array of tab widths
 GK_ATOM(tableBCProperty, "TableBCProperty")                // table border collapsing info (e.g. damage area, table border widths)
 GK_ATOM(usedMarginProperty, "UsedMarginProperty") // nsMargin*
 GK_ATOM(usedPaddingProperty, "UsedPaddingProperty") // nsMargin*
 GK_ATOM(viewProperty, "ViewProperty")                      
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1569,17 +1569,17 @@ nsLayoutUtils::GetNonGeneratedAncestor(n
   return f;
 }
 
 nsIFrame*
 nsLayoutUtils::GetParentOrPlaceholderFor(nsFrameManager* aFrameManager,
                                          nsIFrame* aFrame)
 {
   if ((aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
-      && !(aFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
+      && !aFrame->GetPrevInFlow()) {
     return aFrameManager->GetPlaceholderFrameFor(aFrame);
   }
   return aFrame->GetParent();
 }
 
 nsIFrame*
 nsLayoutUtils::GetClosestCommonAncestorViaPlaceholders(nsIFrame* aFrame1,
                                                        nsIFrame* aFrame2,
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -931,21 +931,20 @@ nsBlockFrame::Reflow(nsPresContext*     
 #endif
     aStatus = NS_FRAME_COMPLETE;
     return NS_OK;
   }
 
   // Handle paginated overflow (see nsContainerFrame.h)
   // Note: We use a temporary reflow status, which we'll merge into the state's
   // reflow status down below.
-  nsRect overflowContainerBounds;
+  nsRect ocBounds;
   nsReflowStatus ocStatus = NS_FRAME_COMPLETE;
   if (GetPrevInFlow()) {
-    ReflowOverflowContainerChildren(aPresContext, aReflowState,
-                                    overflowContainerBounds, 0,
+    ReflowOverflowContainerChildren(aPresContext, aReflowState, ocBounds, 0,
                                     ocStatus);
   }
 
 
   PRBool marginRoot = BlockIsMarginRoot(this);
   nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
                            marginRoot, marginRoot, needFloatManager);
 
@@ -959,36 +958,43 @@ nsBlockFrame::Reflow(nsPresContext*     
   }
 
   nsresult rv = NS_OK;
 
   // ALWAYS drain overflow. We never want to leave the previnflow's
   // overflow lines hanging around; block reflow depends on the
   // overflow line lists being cleared out between reflow passes.
   DrainOverflowLines(state);
-  state.SetupOverflowPlaceholdersProperty();
- 
+  DrainFloatContinuations(state);
+
+  // Handle float continuations
+  nsRect fcBounds;
+  nsReflowStatus fcStatus = NS_FRAME_COMPLETE;
+  rv = ReflowFloatContinuations(state, fcBounds, fcStatus);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   // If we're not dirty (which means we'll mark everything dirty later)
   // and our width has changed, mark the lines dirty that we need to
   // mark dirty for a resize reflow.
   if (aReflowState.mFlags.mHResize)
     PrepareResizeReflow(state);
 
   mState &= ~NS_FRAME_FIRST_REFLOW;
 
   // Now reflow...
   rv = ReflowDirtyLines(state);
   NS_ASSERTION(NS_SUCCEEDED(rv), "reflow dirty lines failed");
   if (NS_FAILED(rv)) return rv;
 
   NS_MergeReflowStatusInto(&state.mReflowStatus, ocStatus);
-
-  // If the block is complete put continued floats at the beginning
-  // of the first overflow line.
-  NS_ASSERTION(state.mOverflowPlaceholders.IsEmpty(), "Where are these coming from? XXXfr");
+  NS_MergeReflowStatusInto(&state.mReflowStatus, fcStatus);
+
+  // Put continued floats at the end of mFloats
+  if (state.mFloatContinuations.NotEmpty())
+    mFloats.AppendFrames(nsnull, state.mFloatContinuations);
 
   if (!NS_FRAME_IS_FULLY_COMPLETE(state.mReflowStatus)) {
     if (GetOverflowLines()) {
       state.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
     }
 
 #ifdef DEBUG_kipp
     ListTag(stdout); printf(": block is not fully complete\n");
@@ -1037,18 +1043,19 @@ nsBlockFrame::Reflow(nsPresContext*     
     // Otherwise just leave the bullet where it is, up against our top padding.
   }
 
   // Compute our final size
   nscoord bottomEdgeOfChildren;
   ComputeFinalSize(aReflowState, state, aMetrics, &bottomEdgeOfChildren);
   ComputeCombinedArea(aReflowState, aMetrics, bottomEdgeOfChildren);
   // Factor overflow container child bounds into the overflow area
-  aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea,
-                                   overflowContainerBounds);
+  aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, ocBounds);
+  // Factor float continuation child bounds into the overflow area
+  aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, fcBounds);
 
   // Let the absolutely positioned container reflow any absolutely positioned
   // child frames that need to be reflowed, e.g., elements with a percentage
   // based width/height
   // We want to do this under either of two conditions:
   //  1. If we didn't do the incremental reflow above.
   //  2. If our size changed.
   // Even though it's the padding edge that's the containing block, we
@@ -3778,25 +3785,29 @@ nsBlockFrame::ReflowInlineFrame(nsBlockR
   }
   else if (NS_FRAME_IS_TRUNCATED(frameReflowStatus) &&
            nsGkAtoms::placeholderFrame == aFrame->GetType()) {
     // if the frame is a placeholder and was complete but truncated (and not at the top
     // of page), the entire line will be pushed to give it another chance to not truncate.
     *aLineReflowStatus = LINE_REFLOW_TRUNCATED;
   }
 
-  if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
+  if (!NS_FRAME_IS_FULLY_COMPLETE(frameReflowStatus)) {
     // Create a continuation for the incomplete frame. Note that the
     // frame may already have a continuation.
     nsIAtom* frameType = aFrame->GetType();
 
     PRBool madeContinuation;
-    if (nsGkAtoms::placeholderFrame == frameType)
-      NS_ASSERTION(0, "float splitting unimplemented"); //XXXfr SplitFloat(aState, aPlaceholder)
-    rv = CreateContinuationFor(aState, aLine, aFrame, madeContinuation);
+    if (nsGkAtoms::placeholderFrame == frameType) {
+      nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(aFrame);
+      rv = SplitFloat(aState, placeholder->GetOutOfFlowFrame(), frameReflowStatus);
+    }
+    else {
+      rv = CreateContinuationFor(aState, aLine, aFrame, madeContinuation);
+    }
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Remember that the line has wrapped
     if (!aLineLayout.GetLineEndsInBR()) {
       aLine->SetLineWrapped(PR_TRUE);
     }
     
     // If we just ended a first-letter frame or reflowed a placeholder then 
@@ -3843,37 +3854,43 @@ nsBlockFrame::CreateContinuationFor(nsBl
   }
 #ifdef DEBUG
   VerifyLines(PR_FALSE);
 #endif
   return rv;
 }
 
 nsresult
-nsBlockFrame::SplitPlaceholder(nsBlockReflowState& aState,
-                               nsIFrame*           aPlaceholder)
+nsBlockFrame::SplitFloat(nsBlockReflowState& aState,
+                         nsIFrame*           aFloat,
+                         nsReflowStatus      aFloatStatus)
 {
-  NS_PRECONDITION(0,"Unexpected call to SplitPlaceholder, replace with SplitFloat XXXfr");
   nsIFrame* nextInFlow;
-  nsresult rv = CreateNextInFlow(aState.mPresContext, this, aPlaceholder, nextInFlow);
+  nsresult rv = CreateNextInFlow(aState.mPresContext, this, aFloat, nextInFlow);
   NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aFloatStatus))
+    aFloat->GetNextInFlow()->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
+
+  // Float continuations can only trigger overflow
+  NS_FRAME_SET_OVERFLOW_INCOMPLETE(aFloatStatus);
+  // Make sure the containing block knows about the float's status
+  NS_MergeReflowStatusInto(&aState.mReflowStatus, aFloatStatus);
 
   if (!nextInFlow) {
     // Next in flow was not created because it already exists.
     return NS_OK;
   }
 
   // put the sibling list back to what it was before the continuation was created
-  nsIFrame *contFrame = aPlaceholder->GetNextSibling();
+  nsIFrame *contFrame = aFloat->GetNextSibling();
   nsIFrame *next = contFrame->GetNextSibling();
-  aPlaceholder->SetNextSibling(next);
+  aFloat->SetNextSibling(next);
   contFrame->SetNextSibling(nsnull);
 
-  // The new out of flow frame does not get put anywhere; the out-of-flows
-  // for placeholders in mOverflowPlaceholders are not kept in any child list
+  aState.AppendFloatContinuation(contFrame);
   return NS_OK;
 }
 
 static nsFloatCache*
 GetLastFloat(nsLineBox* aLine)
 {
   nsFloatCache* fc = aLine->GetFirstFloat();
   while (fc && fc->Next()) {
@@ -4341,19 +4358,16 @@ nsBlockFrame::DrainOverflowLines(nsBlock
     }
   }
 
   if (!overflowLines && !ourOverflowLines) {
     // nothing to do; always the case for non-constrained-height reflows
     return PR_FALSE;
   }
 
-  NS_ASSERTION(aState.mOverflowPlaceholders.IsEmpty(),
-               "Should have no overflow placeholders yet");
-
   // Now join the line lists into mLines
   if (overflowLines) {
     if (!overflowLines->empty()) {
       // Join the line lists
       if (! mLines.empty()) 
         {
           // Remember to recompute the margins on the first line. This will
           // also recompute the correct deltaY if necessary.
@@ -4378,16 +4392,75 @@ nsBlockFrame::DrainOverflowLines(nsBlock
       mLines.splice(mLines.end(), *ourOverflowLines);
     }
     delete ourOverflowLines;
   }
 
   return PR_TRUE;
 }
 
+// This function assumes our prev-in-flow has completed reflow and its
+// mFloats contains at most two frames that belong to the same flow chain,
+// the second one being a last-in-flow continuation intended for this block.
+void
+nsBlockFrame::DrainFloatContinuations(nsBlockReflowState& aState)
+{
+  // Cache any continuations of our own floats that we're still holding onto
+  // so they're out of the way. This should only happen if we're re-Reflow'd
+  // before our next-in-flow gets a chance to pull these continuations.
+  nsFrameList floatContinuations;
+  nsPresContext* presContext = PresContext();
+  for (nsIFrame* f = mFloats.FirstChild(); f; f = f->GetNextSibling()) {
+    nsIFrame* nif = f->GetNextInFlow();
+    if (!nif) continue;
+    if (nif->GetParent() == this) {
+      NS_ASSERTION(!nif->GetNextInFlow(),
+                   "Unexpected next-in-flow for float continuation");
+      StealFrame(presContext, nif);
+      floatContinuations.AppendFrame(nsnull, nif);
+    }
+  }
+  if (floatContinuations.NotEmpty()) {
+    aState.SetupFloatContinuationList();
+    aState.mFloatContinuations.AppendFrames(nsnull, floatContinuations);
+  }
+
+  // Walk our prev-in-flow's floats and prepend their continuations to our
+  // floats list. This pulls any continuations we need to take from our
+  // prev-in-flow and makes sure our continuations of its floats are in the
+  // proper order.
+  nsBlockFrame* prevBlock = static_cast<nsBlockFrame*>(GetPrevInFlow());
+  if (!prevBlock)
+    return;
+  for (nsIFrame* pf = prevBlock->mFloats.FirstChild(); pf; pf = pf->GetNextSibling()) {
+    nsIFrame* nif = pf->GetNextInFlow();
+    if (!nif)
+      continue;
+    nsContainerFrame* nifParent = static_cast<nsContainerFrame*>(nif->GetParent());
+    nifParent->StealFrame(presContext, nif);
+    if (nif->GetParent() != this) {
+      NS_ASSERTION(!nif->GetNextInFlow(),
+                   "Unexpected next-in-flow for float continuation");
+      ReparentFrame(nif, nifParent, this);
+    }
+    floatContinuations.AppendFrame(this, nif);
+  }
+  if (floatContinuations.NotEmpty())
+    mFloats.InsertFrames(nsnull, nsnull, floatContinuations);
+
+#ifdef DEBUG
+  for (nsIFrame* f = mFloats.FirstChild(); f ; f = f->GetNextSibling()) {
+    for (nsIFrame* c = f->GetFirstInFlow(); c ; c = c->GetNextInFlow()) {
+      NS_ASSERTION(c == f || c->GetParent() != this || !mFloats.ContainsFrame(c),
+                   "Two floats with same parent in same floats list, expect weird errors.");
+    }
+  }
+#endif
+}
+
 nsLineList*
 nsBlockFrame::GetOverflowLines() const
 {
   if (!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_LINES)) {
     return nsnull;
   }
   nsLineList* lines = static_cast<nsLineList*>
                                  (GetProperty(nsGkAtoms::overflowLinesProperty));
@@ -4473,28 +4546,16 @@ nsBlockFrame::SetOverflowOutOfFlows(cons
     RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS);
   } else {
     SetProperty(nsGkAtoms::overflowOutOfFlowsProperty,
                 aList.FirstChild(), nsnull);
     AddStateBits(NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS);
   }
 }
 
-nsFrameList*
-nsBlockFrame::GetOverflowPlaceholders() const
-{
-  if (!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS)) {
-    return nsnull;
-  }
-  nsFrameList* result = static_cast<nsFrameList*>
-                                   (GetProperty(nsGkAtoms::overflowPlaceholdersProperty));
-  NS_ASSERTION(result, "value should always be non-empty when state set");
-  return result;
-}
-
 //////////////////////////////////////////////////////////////////////
 // Frame list manipulation routines
 
 nsIFrame*
 nsBlockFrame::LastChild()
 {
   if (! mLines.empty()) {
     return mLines.back()->LastChild();
@@ -4767,21 +4828,18 @@ nsBlockFrame::RemoveFloat(nsIFrame* aFlo
 
   // Try our overflow list
   {
     nsAutoOOFFrameList oofs(this);
     if (oofs.mList.DestroyFrame(aFloat)) {
       return line_end;
     }
   }
-  
-  // If this is during reflow, it could be the out-of-flow frame for a
-  // placeholder in our block reflow state's mOverflowPlaceholders. But that's
-  // OK; it's not part of any child list, so we can just go ahead and delete it.
-  aFloat->Destroy();
+
+  NS_ERROR("Destroying float without removing from a child list.");
   return line_end;
 }
 
 static void MarkSameFloatManagerLinesDirty(nsBlockFrame* aBlock)
 {
   nsBlockFrame* blockWithFloatMgr = aBlock;
   while (!(blockWithFloatMgr->GetStateBits() & NS_BLOCK_FLOAT_MGR)) {
     nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(blockWithFloatMgr->GetParent());
@@ -4884,20 +4942,21 @@ nsBlockFrame::DoRemoveOutOfFlowFrame(nsI
   const nsStyleDisplay* display = aFrame->GetStyleDisplay();
   if (display->IsAbsolutelyPositioned()) {
     // This also deletes the next-in-flows
     block->mAbsoluteContainer.RemoveFrame(block,
                                           nsGkAtoms::absoluteList,
                                           aFrame);
   }
   else {
-    // First remove aFrame's next in flow
-    nsIFrame* nextInFlow = aFrame->GetNextInFlow();
-    if (nextInFlow) {
-      nsBlockFrame::DoRemoveOutOfFlowFrame(nextInFlow);
+    // First remove aFrame's next-in-flows
+    nsIFrame* nif = aFrame->GetNextInFlow();
+    if (nif) {
+      static_cast<nsContainerFrame*>(nif->GetParent())
+        ->DeleteNextInFlowChild(aFrame->PresContext(), nif, PR_FALSE);
     }
     // Now remove aFrame
     // This also destroys the frame.
     block->RemoveFloat(aFrame);
   }
 }
 
 /**
@@ -5089,44 +5148,32 @@ static nsresult RemoveBlockChild(nsIFram
 // on looking for continuations.
 nsresult
 nsBlockFrame::DoRemoveFrame(nsIFrame* aDeletedFrame, PRUint32 aFlags)
 {
   // Clear our line cursor, since our lines may change.
   ClearLineCursor();
 
   nsPresContext* presContext = PresContext();
-  if (NS_FRAME_IS_OVERFLOW_CONTAINER & aDeletedFrame->GetStateBits()) {
-    nsIFrame* nif = aDeletedFrame->GetNextInFlow();
-    if (nif)
-      static_cast<nsContainerFrame*>(nif->GetParent())
-        ->nsContainerFrame::DeleteNextInFlowChild(presContext, nif,
-            (aFlags & FRAMES_ARE_EMPTY) != 0);
-    nsresult rv = nsContainerFrame::StealFrame(presContext, aDeletedFrame);
-    NS_ENSURE_SUCCESS(rv, rv);
-    aDeletedFrame->Destroy();
+  if (aDeletedFrame->GetStateBits() &
+      (NS_FRAME_OUT_OF_FLOW | NS_FRAME_IS_OVERFLOW_CONTAINER)) {
+    if (!aDeletedFrame->GetPrevInFlow()) {
+      NS_ASSERTION(aDeletedFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
+                   "Expected out-of-flow frame");
+      DoRemoveOutOfFlowFrame(aDeletedFrame);
+    }
+    else {
+      nsContainerFrame::DeleteNextInFlowChild(presContext, aDeletedFrame,
+                                              (aFlags & FRAMES_ARE_EMPTY) != 0);
+    }
     return NS_OK;
   }
 
-  if (aDeletedFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
-    DoRemoveOutOfFlowFrame(aDeletedFrame);
-    return NS_OK;
-  }
-  
   nsIPresShell* presShell = presContext->PresShell();
 
-  PRBool isPlaceholder = nsGkAtoms::placeholderFrame == aDeletedFrame->GetType();
-  if (isPlaceholder) {
-    nsFrameList* overflowPlaceholders = GetOverflowPlaceholders();
-    if (overflowPlaceholders && overflowPlaceholders->RemoveFrame(aDeletedFrame)) {
-      NS_ASSERTION(!aDeletedFrame->GetNextContinuation(), "Placeholders can't have continuations.");
-      aDeletedFrame->Destroy();
-    }
-  }
-  
   // Find the line and the previous sibling that contains
   // deletedFrame; we also find the pointer to the line.
   nsLineList::iterator line_start = mLines.begin(),
                        line_end = mLines.end();
   nsLineList::iterator line = line_start;
   PRBool searchingOverflowList = PR_FALSE;
   nsIFrame* prevSibling = nsnull;
   // Make sure we look in the overflow lines even if the normal line
@@ -5330,16 +5377,29 @@ found_frame:;
 
 nsresult
 nsBlockFrame::StealFrame(nsPresContext* aPresContext,
                          nsIFrame*      aChild,
                          PRBool         aForceNormal)
 {
   NS_PRECONDITION(aPresContext && aChild, "null pointer");
 
+  if ((aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
+      aChild->GetStyleDisplay()->IsFloating()) {
+    PRBool removed = mFloats.RemoveFrame(aChild);
+    if (!removed) {
+      nsFrameList* list = GetPropTableFrames(aPresContext,
+                                          nsGkAtoms::floatContinuationProperty);
+      if (list) {
+        removed = list->RemoveFrame(aChild);
+      }
+    }
+    return (removed) ? NS_OK : NS_ERROR_UNEXPECTED;
+  }
+
   if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
       && !aForceNormal)
     return nsContainerFrame::StealFrame(aPresContext, aChild);
 
   // Find the line and the previous sibling that contains
   // aChild; we also find the pointer to the line.
   nsLineList::iterator line = mLines.begin(),
                        line_start = line,
@@ -5403,17 +5463,18 @@ nsBlockFrame::StealFrame(nsPresContext* 
 
 void
 nsBlockFrame::DeleteNextInFlowChild(nsPresContext* aPresContext,
                                     nsIFrame*      aNextInFlow,
                                     PRBool         aDeletingEmptyFrames)
 {
   NS_PRECONDITION(aNextInFlow->GetPrevInFlow(), "bad next-in-flow");
 
-  if (NS_FRAME_IS_OVERFLOW_CONTAINER & aNextInFlow->GetStateBits()) {
+  if (aNextInFlow->GetPrevInFlow() && (aNextInFlow->GetStateBits() &
+      (NS_FRAME_OUT_OF_FLOW | NS_FRAME_IS_OVERFLOW_CONTAINER))) {
     nsContainerFrame::DeleteNextInFlowChild(aPresContext,
         aNextInFlow, aDeletingEmptyFrames);
   }
   else {
     DoRemoveFrame(aNextInFlow,
         aDeletingEmptyFrames ? FRAMES_ARE_EMPTY : 0);
   }
 }
@@ -5460,17 +5521,16 @@ nsBlockFrame::AdjustFloatAvailableSpace(
       nsLayoutUtils::GetClosestFrameOfType(this, nsGkAtoms::columnSetFrame)) {
     // Tell the float it has unrestricted height, so it won't break.
     // If the float doesn't actually fit in the column it will fail to be
     // placed, and either move to the top of the next column or just
     // overflow.
     availHeight = NS_UNCONSTRAINEDSIZE;
   }
 #endif
-  availHeight = NS_UNCONSTRAINEDSIZE; //XXXfr Disable float splitting
 
   return nsRect(aState.BorderPadding().left,
                 aState.BorderPadding().top,
                 availWidth, availHeight);
 }
 
 nscoord
 nsBlockFrame::ComputeFloatWidth(nsBlockReflowState& aState,
@@ -5592,16 +5652,113 @@ nsBlockFrame::ReflowFloat(nsBlockReflowS
 #ifdef NOISY_FLOAT
   printf("end ReflowFloat %p, sized to %d,%d\n",
          aFloat, metrics.width, metrics.height);
 #endif
 
   return NS_OK;
 }
 
+nsresult
+nsBlockFrame::ReflowFloatContinuations(nsBlockReflowState& aState,
+                                       nsRect&             aBounds,
+                                       nsReflowStatus&     aStatus)
+{
+  nsresult rv = NS_OK;
+  for (nsIFrame* f = mFloats.FirstChild(); f && f->GetPrevInFlow();
+       f = f->GetNextSibling()) {
+    if (NS_SUBTREE_DIRTY(f) || aState.mReflowState.ShouldReflowAllKids()) {
+      // Cache old bounds
+      nsRect oldRect = f->GetRect();
+      nsRect oldOverflow = f->GetOverflowRect();
+
+      // Reflow
+      nsReflowStatus fStatus = NS_FRAME_COMPLETE;
+      aState.AddFloat(nsnull, f, aState.mContentArea.width, fStatus);
+      if (!NS_FRAME_IS_FULLY_COMPLETE(fStatus)) {
+        rv = SplitFloat(aState, f, fStatus);
+        NS_ENSURE_SUCCESS(rv, rv);
+        NS_FRAME_SET_OVERFLOW_INCOMPLETE(fStatus);
+      }
+      NS_MergeReflowStatusInto(&aStatus, fStatus);
+
+      // Invalidate if there was a position or size change
+      nsRect rect = f->GetRect();
+      if (rect != oldRect) {
+        nsRect dirtyRect = oldOverflow;
+        dirtyRect.MoveBy(oldRect.x, oldRect.y);
+        Invalidate(dirtyRect);
+
+        dirtyRect = f->GetOverflowRect();
+        dirtyRect.MoveBy(rect.x, rect.y);
+        Invalidate(dirtyRect);
+      }
+    }
+    else {
+      // Just reload the float region into the space manager
+      nsRect region = nsFloatManager::GetRegionFor(f);
+      aState.mFloatManager->AddFloat(f, region);
+      if (f->GetNextInFlow())
+        NS_MergeReflowStatusInto(&aStatus, NS_FRAME_OVERFLOW_INCOMPLETE);
+    }
+
+    ConsiderChildOverflow(aBounds, f);
+  }
+
+  return rv;
+}
+
+void
+nsBlockFrame::RecoverFloats(nsFloatManager& aFloatManager)
+{
+  // Recover our own floats
+  nsIFrame* stop = nsnull; // Stop before we reach float continuations that
+                           // belong to our next-in-flow
+  for (nsIFrame* f = mFloats.FirstChild(); f && f != stop; f = f->GetNextSibling()) {
+    nsRect region = nsFloatManager::GetRegionFor(f);
+    aFloatManager.AddFloat(f, region);
+    if (!stop && f->GetNextInFlow())
+      stop = f->GetNextInFlow();
+  }
+
+  // Recurse into our overflow container children
+  for (nsIFrame* oc = GetFirstChild(nsGkAtoms::overflowContainersList);
+       oc; oc = oc->GetNextSibling()) {
+    RecoverFloatsFor(oc, aFloatManager);
+  }
+
+  // Recurse into our normal children
+  for (nsBlockFrame::line_iterator line = begin_lines(); line != end_lines(); ++line) {
+    if (line->IsBlock()) {
+      RecoverFloatsFor(line->mFirstChild, aFloatManager);
+    }
+  }
+}
+
+void
+nsBlockFrame::RecoverFloatsFor(nsIFrame*       aFrame,
+                               nsFloatManager& aFloatManager)
+{
+  NS_PRECONDITION(aFrame, "null frame");
+  // Only blocks have floats
+  nsBlockFrame* block = nsLayoutUtils::GetAsBlock(aFrame);
+  // Don't recover any state inside a block that has its own space manager
+  // (we don't currently have any blocks like this, though, thanks to our
+  // use of extra frames for 'overflow')
+  if (block && !nsBlockFrame::BlockNeedsFloatManager(block)) {
+    // If the element is relatively positioned, then adjust x and y
+    // accordingly so that we consider relatively positioned frames
+    // at their original position.
+    nsPoint pos = block->GetPosition() - block->GetRelativeOffset();
+    aFloatManager.Translate(pos.x, pos.y);
+    block->RecoverFloats(aFloatManager);
+    aFloatManager.Translate(-pos.x, -pos.y);
+  }
+}
+
 //////////////////////////////////////////////////////////////////////
 // Painting, event handling
 
 PRIntn
 nsBlockFrame::GetSkipSides() const
 {
   if (IS_TRUE_OVERFLOW_CONTAINER(this))
     return (1 << NS_SIDE_TOP) | (1 << NS_SIDE_BOTTOM);
@@ -5811,16 +5968,20 @@ nsBlockFrame::BuildDisplayList(nsDisplay
     drawnLines = 0;
   }
 #endif
 
   DisplayBorderBackgroundOutline(aBuilder, aLists);
 
   if (GetPrevInFlow()) {
     DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
+    for (nsIFrame* f = mFloats.FirstChild(); f; f = f->GetNextSibling()) {
+      if (f->GetPrevInFlow())
+         BuildDisplayListForChild(aBuilder, f, aDirtyRect, aLists);
+    }
   }
 
   aBuilder->MarkFramesForDisplayList(this, mFloats, aDirtyRect);
   aBuilder->MarkFramesForDisplayList(this, mAbsoluteContainer.GetChildList(),
                                      aDirtyRect);
 
   // Don't use the line cursor if we might have a descendant placeholder ...
   // it might skip lines that contain placeholders but don't themselves
@@ -6444,16 +6605,18 @@ nsBlockFrame::CheckFloats(nsBlockReflowS
       anyLineDirty = PR_TRUE;
     }
   }
   
   nsAutoTArray<nsIFrame*, 8> storedFloats;
   PRBool equal = PR_TRUE;
   PRUint32 i = 0;
   for (nsIFrame* f = mFloats.FirstChild(); f; f = f->GetNextSibling()) {
+    if (f->GetPrevInFlow())
+      continue;
     storedFloats.AppendElement(f);
     if (i < lineFloats.Length() && lineFloats.ElementAt(i) != f) {
       equal = PR_FALSE;
     }
     ++i;
   }
 
   if ((!equal || lineFloats.Length() != storedFloats.Length()) && !anyLineDirty) {
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -87,24 +87,20 @@ class nsIntervalSet;
 #define NS_BLOCK_LIST_COUNT  (NS_CONTAINER_LIST_COUNT_INCL_OC + 4)
 
 /**
  * Some invariants:
  * -- The overflow out-of-flows list contains the out-of-
  * flow frames whose placeholders are in the overflow list.
  * -- A given piece of content has at most one placeholder
  * frame in a block's normal child list.
- * -- A given piece of content can have an unlimited number
- * of placeholder frames in the overflow-lines list.
- * -- A line containing a continuation placeholder contains
- * only continuation placeholders.
- * -- While a block is being reflowed, its overflowPlaceholdersList
- * frame property points to an nsFrameList in its
- * nsBlockReflowState. This list contains placeholders for
- * floats whose prev-in-flow is in the block's regular line
+ * -- While a block is being reflowed, it may have a floatContinuationProperty
+ * frame property that points to an nsFrameList in its
+ * nsBlockReflowState. This list contains continuations for
+ * floats whose prev-in-flow is in the block's regular float
  * list. The list is always empty/non-existent after the
  * block has been reflowed.
  * -- In all these frame lists, if there are two frames for
  * the same content appearing in the list, then the frames
  * appear with the prev-in-flow before the next-in-flow.
  * -- While reflowing a block, its overflow line list
  * will usually be empty but in some cases will have lines
  * (while we reflow the block at its shrink-wrap width).
@@ -118,22 +114,21 @@ class nsIntervalSet;
  * Something in the block has changed that requires Bidi resolution to be
  * performed on the block. This flag must be either set on all blocks in a 
  * continuation chain or none of them.
  */
 #define NS_BLOCK_NEEDS_BIDI_RESOLUTION      0x00100000 
 #define NS_BLOCK_HAS_LINE_CURSOR            0x01000000
 #define NS_BLOCK_HAS_OVERFLOW_LINES         0x02000000
 #define NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS  0x04000000
-#define NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS  0x08000000
 
 // Set on any block that has descendant frames in the normal
 // flow with 'clear' set to something other than 'none'
 // (including <BR CLEAR="..."> frames)
-#define NS_BLOCK_HAS_CLEAR_CHILDREN         0x10000000
+#define NS_BLOCK_HAS_CLEAR_CHILDREN         0x08000000
 
 #define nsBlockFrameSuper nsHTMLContainerFrame
 
 /*
  * Base class for block and inline frames.
  * The block frame has an additional named child list:
  * - "Absolute-list" which contains the absolutely positioned frames
  *
@@ -251,17 +246,17 @@ public:
                     nsReflowStatus&          aStatus);
 
   NS_IMETHOD AttributeChanged(PRInt32         aNameSpaceID,
                               nsIAtom*        aAttribute,
                               PRInt32         aModType);
 
   virtual nsresult StealFrame(nsPresContext* aPresContext,
                               nsIFrame*      aChild,
-                              PRBool         aForceNormal);
+                              PRBool         aForceNormal = PR_FALSE);
 
   virtual void DeleteNextInFlowChild(nsPresContext* aPresContext,
                                      nsIFrame*      aNextInFlow,
                                      PRBool         aDeletingEmptyFrames);
 
   /**
    * Determines whether the collapsed margin carried out of the last
    * line includes the margin-top of a line with clearance (in which
@@ -272,20 +267,16 @@ public:
   /** return the topmost block child based on y-index.
     * almost always the first or second line, if there is one.
     * accounts for lines that hold only compressed white space, etc.
     */
   nsIFrame* GetTopBlockChild(nsPresContext *aPresContext);
 
   static nsresult GetCurrentLine(nsBlockReflowState *aState, nsLineBox **aOutCurrentLine);
 
-  // Create a contination for aPlaceholder and its out of flow frame and
-  // add it to the list of overflow floats
-  nsresult SplitPlaceholder(nsBlockReflowState& aState, nsIFrame* aPlaceholder);
-
   static PRBool BlockIsMarginRoot(nsIFrame* aBlock);
   static PRBool BlockNeedsFloatManager(nsIFrame* aBlock);
 
   /**
    * Returns whether aFrame is a block frame that will wrap its contents
    * around floats intruding on it from the outside.  (aFrame need not
    * be a block frame, but if it's not, the result will be false.)
    */
@@ -303,16 +294,27 @@ public:
       { return marginLeft + borderBoxWidth + marginRight; }
   };
   static ReplacedElementWidthToClear
     WidthToClearPastFloats(nsBlockReflowState& aState,
                            const nsRect& aFloatAvailableSpace,
                            nsIFrame* aFrame);
 
   /**
+   * Creates a contination for aFloat and adds it to the list of overflow floats.
+   * Also updates aState.mReflowStatus to include the float's incompleteness.
+   * Must only be called while this block frame is in reflow.
+   * aFloatStatus must be the float's true, unmodified reflow status.
+   * 
+   */
+  nsresult SplitFloat(nsBlockReflowState& aState,
+                      nsIFrame*           aFloat,
+                      nsReflowStatus      aFloatStatus);
+
+  /**
    * Walks up the frame tree, starting with aCandidate, and returns the first
    * block frame that it encounters.
    */
   static nsBlockFrame* GetNearestAncestorBlock(nsIFrame* aCandidate);
   
 protected:
   nsBlockFrame(nsStyleContext* aContext)
     : nsHTMLContainerFrame(aContext)
@@ -426,24 +428,48 @@ public:
     FRAMES_ARE_EMPTY           = 0x04
   };
   nsresult DoRemoveFrame(nsIFrame* aDeletedFrame, PRUint32 aFlags);
 
   void ReparentFloats(nsIFrame* aFirstFrame,
                       nsBlockFrame* aOldParent, PRBool aFromOverflow,
                       PRBool aReparentSiblings);
 
+  /** Load all of aFrame's floats into the float manager iff aFrame is not a
+   *  block formatting context. Handles all necessary float manager translations;
+   *  assumes float manager is in aFrame's parent's coord system.
+   *  Safe to call on non-blocks (does nothing).
+   */
+  static void RecoverFloatsFor(nsIFrame*       aFrame,
+                               nsFloatManager& aFloatManager);
+
 protected:
 
   /** grab overflow lines from this block's prevInFlow, and make them
     * part of this block's mLines list.
     * @return PR_TRUE if any lines were drained.
     */
   PRBool DrainOverflowLines(nsBlockReflowState& aState);
 
+  /** grab float continuations from this block's prevInFlow, and splice
+    * them into this block's mFloats list.
+    */
+  void DrainFloatContinuations(nsBlockReflowState& aState);
+
+  /** Load all our floats into the float manager (without reflowing them).
+   *  Assumes float manager is in our own coordinate system.
+   */
+  void RecoverFloats(nsFloatManager& aFloatManager);
+
+  /** Reflow float continuations
+   */
+  nsresult ReflowFloatContinuations(nsBlockReflowState& aState,
+                                    nsRect&             aBounds,
+                                    nsReflowStatus&     aStatus);
+
   /**
     * Remove a float from our float list and also the float cache
     * for the line its placeholder is on.
     */
   line_iterator RemoveFloat(nsIFrame* aFloat);
 
   void CollectFloats(nsIFrame* aFrame, nsFrameList& aList, nsIFrame** aTail,
                      PRBool aFromOverflow, PRBool aCollectFromSiblings);
@@ -619,18 +645,16 @@ protected:
   virtual nsILineIterator* GetLineIterator();
 
 public:
   nsLineList* GetOverflowLines() const;
 protected:
   nsLineList* RemoveOverflowLines();
   nsresult SetOverflowLines(nsLineList* aOverflowLines);
 
-  nsFrameList* GetOverflowPlaceholders() const;
-
   /**
    * This class is useful for efficiently modifying the out of flow
    * overflow list. It gives the client direct writable access to
    * the frame list temporarily but ensures that property is only
    * written back if absolutely necessary.
    */
   struct nsAutoOOFFrameList {
     nsFrameList mList;
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -137,42 +137,30 @@ nsBlockReflowState::nsBlockReflowState(c
   mY = borderPadding.top;
 
   mPrevChild = nsnull;
   mCurrentLine = aFrame->end_lines();
 
   mMinLineHeight = aReflowState.CalcLineHeight();
 }
 
-void
-nsBlockReflowState::SetupOverflowPlaceholdersProperty()
-{
-  if (mReflowState.availableHeight != NS_UNCONSTRAINEDSIZE ||
-      !mOverflowPlaceholders.IsEmpty()) {
-    mBlock->SetProperty(nsGkAtoms::overflowPlaceholdersProperty,
-                        &mOverflowPlaceholders, nsnull);
-    mBlock->AddStateBits(NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS);
-  }
-}
-
 nsBlockReflowState::~nsBlockReflowState()
 {
-  NS_ASSERTION(mOverflowPlaceholders.IsEmpty(),
-               "Leaking overflow placeholder frames");
+  NS_ASSERTION(mFloatContinuations.IsEmpty(),
+               "Leaking float continuation frames");
 
   // Restore the coordinate system, unless the float manager is null,
   // which means it was just destroyed.
   if (mFloatManager) {
     const nsMargin& borderPadding = BorderPadding();
     mFloatManager->Translate(-borderPadding.left, -borderPadding.top);
   }
 
-  if (mBlock->GetStateBits() & NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS) {
-    mBlock->UnsetProperty(nsGkAtoms::overflowPlaceholdersProperty);
-    mBlock->RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS);
+  if (GetFlag(BRS_PROPTABLE_FLOATCLIST)) {
+    mBlock->UnsetProperty(nsGkAtoms::floatContinuationProperty);
   }
 }
 
 nsLineBox*
 nsBlockReflowState::NewLineBox(nsIFrame* aFrame,
                                PRInt32 aCount,
                                PRBool aIsBlock)
 {
@@ -433,16 +421,26 @@ nsBlockReflowState::ReconstructMarginAbo
       if (!GetFlag(BRS_ISTOPMARGINROOT)) {
         mPrevBottomMargin.Zero();
       }
       break;
     }
   }
 }
 
+void
+nsBlockReflowState::SetupFloatContinuationList()
+{
+  if (!GetFlag(BRS_PROPTABLE_FLOATCLIST)) {
+    mBlock->SetProperty(nsGkAtoms::floatContinuationProperty,
+                        &mFloatContinuations, nsnull);
+    SetFlag(BRS_PROPTABLE_FLOATCLIST, PR_TRUE);
+  }
+}
+
 /**
  * Restore information about floats into the float manager for an
  * incremental reflow, and simultaneously push the floats by
  * |aDeltaY|, which is the amount |aLine| was pushed relative to its
  * parent.  The recovery of state is one of the things that makes
  * incremental reflow O(N^2) and this state should really be kept
  * around, attached to the frame tree.
  */
@@ -475,48 +473,17 @@ nsBlockReflowState::RecoverFloats(nsLine
                aDeltaY, region.x, region.y, region.width, region.height);
       }
 #endif
       mFloatManager->AddFloat(floatFrame,
                               nsFloatManager::GetRegionFor(floatFrame));
       fc = fc->Next();
     }
   } else if (aLine->IsBlock()) {
-    nsBlockFrame *kid = nsLayoutUtils::GetAsBlock(aLine->mFirstChild);
-    // don't recover any state inside a block that has its own space
-    // manager (we don't currently have any blocks like this, though,
-    // thanks to our use of extra frames for 'overflow')
-    if (kid && !nsBlockFrame::BlockNeedsFloatManager(kid)) {
-      nscoord tx = kid->mRect.x, ty = kid->mRect.y;
-
-      // If the element is relatively positioned, then adjust x and y
-      // accordingly so that we consider relatively positioned frames
-      // at their original position.
-      if (NS_STYLE_POSITION_RELATIVE == kid->GetStyleDisplay()->mPosition) {
-        nsPoint *offsets = static_cast<nsPoint*>
-                                      (mPresContext->PropertyTable()->GetProperty(kid,
-                                       nsGkAtoms::computedOffsetProperty));
-
-        if (offsets) {
-          tx -= offsets->x;
-          ty -= offsets->y;
-        }
-      }
- 
-      mFloatManager->Translate(tx, ty);
-      for (nsBlockFrame::line_iterator line = kid->begin_lines(),
-                                   line_end = kid->end_lines();
-           line != line_end;
-           ++line)
-        // Pass 0, not the real DeltaY, since these floats aren't
-        // moving relative to their parent block, only relative to
-        // the float manager.
-        RecoverFloats(line, 0);
-      mFloatManager->Translate(-tx, -ty);
-    }
+    nsBlockFrame::RecoverFloatsFor(aLine->mFirstChild, *mFloatManager);
   }
 }
 
 /**
  * Everything done in this function is done O(N) times for each pass of
  * reflow so it is O(N*M) where M is the number of incremental reflow
  * passes.  That's bad.  Don't do stuff here.
  *
@@ -560,32 +527,29 @@ nsBlockReflowState::RecoverStateFrom(nsL
 // then the float is place immediately, otherwise the float
 // placement is deferred until the line has been reflowed.
 
 // XXXldb This behavior doesn't quite fit with CSS1 and CSS2 --
 // technically we're supposed let the current line flow around the
 // float as well unless it won't fit next to what we already have.
 // But nobody else implements it that way...
 PRBool
-nsBlockReflowState::AddFloat(nsLineLayout&       aLineLayout,
+nsBlockReflowState::AddFloat(nsLineLayout*       aLineLayout,
                              nsIFrame*           aFloat,
                              nscoord             aAvailableWidth,
                              nsReflowStatus&     aReflowStatus)
 {
-  NS_PRECONDITION(mBlock->end_lines() != mCurrentLine, "null ptr");
+  NS_PRECONDITION(!aLineLayout || mBlock->end_lines() != mCurrentLine, "null ptr");
   NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
                   "aFloat must be an out-of-flow frame");
 
   // Set the geometric parent of the float
   aFloat->SetParent(mBlock);
 
   aReflowStatus = NS_FRAME_COMPLETE;
-  // Allocate a nsFloatCache for the float
-  nsFloatCache* fc = mFloatCacheFreeList.Alloc();
-  fc->mFloat = aFloat;
 
   // Because we are in the middle of reflowing a placeholder frame
   // within a line (and possibly nested in an inline frame or two
   // that's a child of our block) we need to restore the space
   // manager's translation to the space that the block resides in
   // before placing the float.
   nscoord ox, oy;
   mFloatManager->GetTranslation(ox, oy);
@@ -596,64 +560,66 @@ nsBlockReflowState::AddFloat(nsLineLayou
   PRBool placed;
 
   // Now place the float immediately if possible. Otherwise stash it
   // away in mPendingFloats and place it later.
   // If one or more floats has already been pushed to the next line,
   // don't let this one go on the current line, since that would violate
   // float ordering.
   nsRect floatAvailableSpace = GetFloatAvailableSpace().mRect;
-  if (mBelowCurrentLineFloats.IsEmpty() &&
-      (aLineLayout.LineIsEmpty() ||
-       mBlock->ComputeFloatWidth(*this, floatAvailableSpace, aFloat) <=
-         aAvailableWidth)) {
+  if (!aLineLayout ||
+      (mBelowCurrentLineFloats.IsEmpty() &&
+       (aLineLayout->LineIsEmpty() ||
+        mBlock->ComputeFloatWidth(*this, floatAvailableSpace, aFloat)
+        <= aAvailableWidth))) {
     // And then place it
     // force it to fit if we're at the top of the block and we can't
     // break before this
-    PRBool forceFit = IsAdjacentWithTop() && !aLineLayout.LineIsBreakable();
+    PRBool forceFit = !aLineLayout ||
+                      (IsAdjacentWithTop() && !aLineLayout->LineIsBreakable());
     placed = FlowAndPlaceFloat(aFloat, aReflowStatus, forceFit);
     NS_ASSERTION(placed || !forceFit,
                  "If we asked for force-fit, it should have been placed");
     if (forceFit || (placed && !NS_FRAME_IS_TRUNCATED(aReflowStatus))) {
       // Pass on updated available space to the current inline reflow engine
       nsFlowAreaRect floatAvailSpace =
         GetFloatAvailableSpace(mY, forceFit);
       nsRect availSpace(nsPoint(floatAvailSpace.mRect.x + BorderPadding().left,
                                 mY),
                         floatAvailSpace.mRect.Size());
-      aLineLayout.UpdateBand(availSpace, aFloat);
-
-      // Record this float in the current-line list
-      mCurrentLineFloats.Append(fc);
+      if (aLineLayout) {
+        aLineLayout->UpdateBand(availSpace, aFloat);
+        // Record this float in the current-line list
+        mCurrentLineFloats.Append(mFloatCacheFreeList.Alloc(aFloat));
+      }
       // If we can't break here, hide the fact that it's truncated
       // XXX We can probably do this more cleanly
       aReflowStatus &= ~NS_FRAME_TRUNCATED;
     }
     else {
       if (IsAdjacentWithTop()) {
         // Pushing the line to the next page won't give us any more space;
         // therefore, we break.
-        NS_ASSERTION(aLineLayout.LineIsBreakable(),
+        NS_ASSERTION(aLineLayout->LineIsBreakable(),
                      "We can't get here unless forceFit is false");
         aReflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
       } else {
         // Make sure we propagate the truncated status; this signals the
         // block to push the line to the next page.
         aReflowStatus |= NS_FRAME_TRUNCATED;
       }
-      delete fc;
     }
   }
   else {
     // Always claim to be placed; we don't know whether we fit yet, so we
     // deal with this in PlaceBelowCurrentLineFloats
     placed = PR_TRUE;
     // This float will be placed after the line is done (it is a
     // below-current-line float).
-    mBelowCurrentLineFloats.Append(fc);
+    mBelowCurrentLineFloats.Append(mFloatCacheFreeList.Alloc(aFloat));
   }
 
   // Restore coordinate system
   mFloatManager->Translate(dx, dy);
 
   return placed;
 }
 
@@ -1024,18 +990,21 @@ nsBlockReflowState::PlaceBelowCurrentLin
       PRBool placed = FlowAndPlaceFloat(fc->mFloat, reflowStatus, aForceFit);
       NS_ASSERTION(placed || !aForceFit,
                    "If we're in force-fit mode, we should have placed the float");
 
       if (!placed || (NS_FRAME_IS_TRUNCATED(reflowStatus) && !aForceFit)) {
         // return before processing all of the floats, since the line will be pushed.
         return PR_FALSE;
       }
-      else if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus)) {
-        // Create a continuation for the incomplete float XXXfr
+      else if (!NS_FRAME_IS_FULLY_COMPLETE(reflowStatus)) {
+        // Create a continuation for the incomplete float
+        nsresult rv = mBlock->SplitFloat(*this, fc->mFloat, reflowStatus);
+        if (NS_FAILED(rv))
+          return PR_FALSE;
       } else {
         // XXX We could deal with truncated frames better by breaking before
         // the associated placeholder
         NS_WARN_IF_FALSE(!NS_FRAME_IS_TRUNCATED(reflowStatus),
                          "This situation currently leads to data not printing");
         // Float is complete.
       }
     }
--- a/layout/generic/nsBlockReflowState.h
+++ b/layout/generic/nsBlockReflowState.h
@@ -57,36 +57,31 @@
 // Set when mLineAdjacentToTop is valid
 #define BRS_HAVELINEADJACENTTOTOP 0x00000020
 // Set when the block has the equivalent of NS_BLOCK_FLOAT_MGR
 #define BRS_FLOAT_MGR             0x00000040
 // Set when nsLineLayout::LineIsEmpty was true at the end of reflowing
 // the current line
 #define BRS_LINE_LAYOUT_EMPTY     0x00000080
 #define BRS_ISOVERFLOWCONTAINER   0x00000100
-#define BRS_LASTFLAG              BRS_ISOVERFLOWCONTAINER
+// Our mFloatContinuations list is stored on the blocks' proptable
+#define BRS_PROPTABLE_FLOATCLIST  0x00000200
+#define BRS_LASTFLAG              BRS_PROPTABLE_FLOATCLIST
 
 class nsBlockReflowState {
 public:
   nsBlockReflowState(const nsHTMLReflowState& aReflowState,
                      nsPresContext* aPresContext,
                      nsBlockFrame* aFrame,
                      const nsHTMLReflowMetrics& aMetrics,
                      PRBool aTopMarginRoot, PRBool aBottomMarginRoot,
                      PRBool aBlockNeedsFloatManager);
 
   ~nsBlockReflowState();
 
-  // Set up a property on the block that points to our temporary mOverflowPlaceholders
-  // list, if that list is or could become non-empty during this reflow. Must be
-  // called after the block has done DrainOverflowLines because DrainOverflowLines
-  // can setup mOverflowPlaceholders even if the block is in unconstrained height
-  // reflow (it may have previously been reflowed with constrained height).
-  void SetupOverflowPlaceholdersProperty();
-
   /**
    * Get the available reflow space (the area not occupied by floats)
    * for the current y coordinate. The available space is relative to
    * our coordinate system, which is the content box, with (0, 0) in the
    * upper left.
    *
    * Returns whether there are floats present at the given vertical
    * coordinate and within the width of the content rect.
@@ -103,18 +98,20 @@ public:
   nsFlowAreaRect
     GetFloatAvailableSpaceForHeight(nscoord aY, nscoord aHeight,
                                     nsFloatManager::SavedState *aState) const;
 
   /*
    * The following functions all return PR_TRUE if they were able to
    * place the float, PR_FALSE if the float did not fit in available
    * space.
+   * aLineLayout is null when we are reflowing float continuations (because
+   * they are not associated with a line box).
    */
-  PRBool AddFloat(nsLineLayout&       aLineLayout,
+  PRBool AddFloat(nsLineLayout*       aLineLayout,
                   nsIFrame*           aFloat,
                   nscoord             aAvailableWidth,
                   nsReflowStatus&     aReflowStatus);
   PRBool CanPlaceFloat(const nsSize& aFloatSize, PRUint8 aFloats,
                        const nsFlowAreaRect& aFloatAvailableSpace,
                        PRBool aForceFit);
   PRBool FlowAndPlaceFloat(nsIFrame*       aFloat,
                            nsReflowStatus& aReflowStatus,
@@ -224,23 +221,28 @@ public:
 
   // The content area to reflow child frames within. The x/y
   // coordinates are known to be mBorderPadding.left and
   // mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
   // if the container reflowing this frame has given the frame an
   // unconstrained area.
   nsSize mContentArea;
 
-  // Placeholders for continuation out-of-flow frames that need to
-  // move to our next in flow are placed here during reflow. At the end of reflow
-  // they move to the end of the overflow lines.
-  // Their out-of-flows are not in any child list during reflow, but are added
-  // to the overflow-out-of-flow list when the placeholders are appended to
-  // the overflow lines.
-  nsFrameList mOverflowPlaceholders;
+  // Continuation out-of-flow float frames that need to move to our
+  // next in flow are placed here during reflow. At the end of reflow
+  // they move to the end of the mFloats list.
+  nsFrameList mFloatContinuations;
+  // This method makes sure float continuations are accessible to
+  // StealFrame. Call it before adding any frames to mFloatContinuations.
+  void SetupFloatContinuationList();
+  // Use this method to append to mFloatContinuations.
+  void AppendFloatContinuation(nsIFrame* aFloatCont) {
+    SetupFloatContinuationList();
+    mFloatContinuations.AppendFrame(mBlock, aFloatCont);
+  }
 
   // Track child overflow continuations.
   nsOverflowContinuationTracker mOverflowTracker;
 
   //----------------------------------------
 
   // This state is "running" state updated by the reflow of each line
   // in the block. This same state is "recovered" when a line is not
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -1061,16 +1061,18 @@ nsContainerFrame::ReflowOverflowContaine
       }
       NS_MergeReflowStatusInto(&aStatus, frameStatus);
       // At this point it would be nice to assert !frame->GetOverflowRect().IsEmpty(),
       // but we have some unsplittable frames that, when taller than
       // availableHeight will push zero-height content into a next-in-flow.
     }
     else {
       tracker.Skip(frame, aStatus);
+      if (aReflowState.mFloatManager)
+        nsBlockFrame::RecoverFloatsFor(frame, *aReflowState.mFloatManager);
     }
     ConsiderChildOverflow(aOverflowRect, frame);
   }
 
   return NS_OK;
 }
 
 void
--- a/layout/generic/nsContainerFrame.h
+++ b/layout/generic/nsContainerFrame.h
@@ -447,17 +447,18 @@ protected:
  * 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)           )
+  && !( (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&      \
+        frame->GetStyleDisplay()->IsAbsolutelyPositioned()  )  )
 //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/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -5874,19 +5874,19 @@ nsFrame::DoGetParentStyleContextFrame(ns
     // 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
+  if ((oofFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
+      GetPrevInFlow()) {
+    // Out of flows that are continuations do not
     // have placeholders. Use their first-in-flow's placeholder.
     oofFrame = oofFrame->GetFirstInFlow();
   }
   nsIFrame *placeholder =
     aPresContext->FrameManager()->GetPlaceholderFrameFor(oofFrame);
   if (!placeholder) {
     NS_NOTREACHED("no placeholder frame for out-of-flow frame");
     GetCorrectedParent(aPresContext, this, aProviderFrame);
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -709,20 +709,22 @@ nsInlineFrame::ReflowInlineFrame(nsPresC
             NS_FRAME_SET_INCOMPLETE(aStatus);
             break;
           }
           nextInFlow = (nsInlineFrame*) nextInFlow->GetNextInFlow();
         }
       }
     }
   }
-  else if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
+  else if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
     if (nsGkAtoms::placeholderFrame == aFrame->GetType()) {
       nsBlockReflowState* blockRS = lineLayout->mBlockRS;
-      NS_ASSERTION(0, "float splitting unimplemented"); // SplitFloat XXXfr
+      nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(aFrame);
+      rv = blockRS->mBlock->SplitFloat(*blockRS, placeholder->GetOutOfFlowFrame(),
+                                       aStatus);
       // Allow the parent to continue reflowing
       aStatus = NS_FRAME_COMPLETE;
     }
     else {
       nsIFrame* newFrame;
       rv = CreateNextInFlow(aPresContext, this, aFrame, newFrame);
       if (NS_FAILED(rv)) {
         return rv;
--- a/layout/generic/nsLineBox.cpp
+++ b/layout/generic/nsLineBox.cpp
@@ -904,31 +904,34 @@ nsFloatCacheFreeList::Remove(nsFloatCach
 void
 nsFloatCacheFreeList::DeleteAll()
 {
   nsFloatCacheList::DeleteAll();
   mTail = nsnull;
 }
 
 nsFloatCache*
-nsFloatCacheFreeList::Alloc()
+nsFloatCacheFreeList::Alloc(nsIFrame* aFloat)
 {
+  NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
+                  "This is a float cache, why isn't the frame out-of-flow?");
   nsFloatCache* fc = mHead;
   if (mHead) {
     if (mHead == mTail) {
       mHead = mTail = nsnull;
     }
     else {
       mHead = fc->mNext;
     }
     fc->mNext = nsnull;
   }
   else {
     fc = new nsFloatCache();
   }
+  fc->mFloat = aFloat;
   return fc;
 }
 
 void
 nsFloatCacheFreeList::Append(nsFloatCache* aFloat)
 {
   NS_ASSERTION(!aFloat->mNext, "Bogus!");
   aFloat->mNext = nsnull;
--- a/layout/generic/nsLineBox.h
+++ b/layout/generic/nsLineBox.h
@@ -157,18 +157,18 @@ public:
   // free-list.  aList must not be empty.
   void Append(nsFloatCacheList& aList);
 
   void Append(nsFloatCache* aFloatCache);
 
   void Remove(nsFloatCache* aElement);
 
   // Remove an nsFloatCache object from this list and return it, or create
-  // a new one if this one is empty;
-  nsFloatCache* Alloc();
+  // a new one if this one is empty; Set its mFloat to aFloat.
+  nsFloatCache* Alloc(nsIFrame* aFloat);
   
 protected:
   nsFloatCache* mTail;
 
   friend class nsFloatCacheList;
 };
 
 //----------------------------------------------------------------------
--- a/layout/generic/nsLineLayout.h
+++ b/layout/generic/nsLineLayout.h
@@ -208,17 +208,17 @@ public:
 
   //----------------------------------------
   // Inform the line-layout about the presence of a floating frame
   // XXX get rid of this: use get-frame-type?
   PRBool AddFloat(nsIFrame*       aFloat,
                   nscoord         aAvailableWidth,
                   nsReflowStatus& aReflowStatus)
   {
-    return mBlockRS->AddFloat(*this, aFloat, aAvailableWidth, aReflowStatus);
+    return mBlockRS->AddFloat(this, aFloat, aAvailableWidth, aReflowStatus);
   }
 
   void SetTrimmableWidth(nscoord aTrimmableWidth) {
     mTrimmableWidth = aTrimmableWidth;
   }
 
   //----------------------------------------