Bug 492627 - Remove Placeholder Continuations [Part IV: Switch float layout APIs to pass float directly, without placeholder] r=roc
authorfantasai <fantasai.cvs@inkedblade.net>
Mon, 31 Aug 2009 11:25:35 -0700
changeset 32107 9d788a1b2364
parent 32106 e9130436ada8
child 32108 28008648ca04
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 IV: Switch float layout APIs to pass float directly, without placeholder] r=roc
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
layout/generic/nsBlockReflowState.cpp
layout/generic/nsBlockReflowState.h
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsInlineFrame.cpp
layout/generic/nsLineBox.cpp
layout/generic/nsLineBox.h
layout/generic/nsLineLayout.cpp
layout/generic/nsLineLayout.h
layout/generic/nsTextFrameThebes.cpp
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -2264,17 +2264,17 @@ nsBlockFrame::MarkLineDirtyForInterrupt(
     PRInt32 n = aLine->GetChildCount();
     for (nsIFrame* f = aLine->mFirstChild; n > 0;
          f = f->GetNextSibling(), --n) {
       f->AddStateBits(NS_FRAME_IS_DIRTY);
     }
     // And mark all the floats whose reflows we might be skipping dirty too.
     if (aLine->HasFloats()) {
       for (nsFloatCache* fc = aLine->GetFirstFloat(); fc; fc = fc->Next()) {
-        fc->mPlaceholder->GetOutOfFlowFrame()->AddStateBits(NS_FRAME_IS_DIRTY);
+        fc->mFloat->AddStateBits(NS_FRAME_IS_DIRTY);
       }
     }
   } else {
     // Dirty all the descendant lines of block kids to handle float damage,
     // since our nsFloatManager will go away by the next time we're reflowing.
     // XXXbz Can we do something more like what PropagateFloatDamage does?
     // Would need to sort out the exact business with mBlockDelta for that....
     // This marks way too much dirty.  If we ever make this better, revisit
@@ -3880,19 +3880,21 @@ GetLastFloat(nsLineBox* aLine)
     fc = fc->Next();
   }
   return fc;
 }
 
 static PRBool
 CheckPlaceholderInLine(nsIFrame* aBlock, nsLineBox* aLine, nsFloatCache* aFC)
 {
-  if (!aFC)
+  if (!aFC || aFC->mFloat->GetPrevInFlow())
     return PR_TRUE;
-  for (nsIFrame* f = aFC->mPlaceholder; f; f = f->GetParent()) {
+  nsIFrame* ph = aBlock->PresContext()->FrameManager()->
+                   GetPlaceholderFrameFor(aFC->mFloat->GetFirstInFlow());
+  for (nsIFrame* f = ph; f; f = f->GetParent()) {
     if (f->GetParent() == aBlock)
       return aLine->Contains(f);
   }
   NS_ASSERTION(PR_FALSE, "aBlock is not an ancestor of aFrame!");
   return PR_TRUE;
 }
 
 nsresult
@@ -5468,71 +5470,70 @@ nsBlockFrame::AdjustFloatAvailableSpace(
   return nsRect(aState.BorderPadding().left,
                 aState.BorderPadding().top,
                 availWidth, availHeight);
 }
 
 nscoord
 nsBlockFrame::ComputeFloatWidth(nsBlockReflowState& aState,
                                 const nsRect&       aFloatAvailableSpace,
-                                nsPlaceholderFrame* aPlaceholder)
+                                nsIFrame*           aFloat)
 {
+  NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
+                  "aFloat must be an out-of-flow frame");
   // Reflow the float.
-  nsIFrame* floatFrame = aPlaceholder->GetOutOfFlowFrame();
-
   nsRect availSpace = AdjustFloatAvailableSpace(aState, aFloatAvailableSpace,
-                                                floatFrame);
-
-  nsHTMLReflowState floatRS(aState.mPresContext, aState.mReflowState,
-                            floatFrame, 
+                                                aFloat);
+
+  nsHTMLReflowState floatRS(aState.mPresContext, aState.mReflowState, aFloat, 
                             nsSize(availSpace.width, availSpace.height));
   return floatRS.ComputedWidth() + floatRS.mComputedBorderPadding.LeftRight() +
     floatRS.mComputedMargin.LeftRight();
 }
 
 nsresult
 nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
                           const nsRect&       aFloatAvailableSpace,
-                          nsPlaceholderFrame* aPlaceholder,
+                          nsIFrame*           aFloat,
                           nsMargin&           aFloatMargin,
                           nsReflowStatus&     aReflowStatus)
 {
+  NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
+                  "aFloat must be an out-of-flow frame");
   // Reflow the float.
-  nsIFrame* floatFrame = aPlaceholder->GetOutOfFlowFrame();
   aReflowStatus = NS_FRAME_COMPLETE;
 
 #ifdef NOISY_FLOAT
   printf("Reflow Float %p in parent %p, availSpace(%d,%d,%d,%d)\n",
-          aPlaceholder->GetOutOfFlowFrame(), this, 
+          aFloat, this, 
           aFloatAvailableSpace.x, aFloatAvailableSpace.y, 
           aFloatAvailableSpace.width, aFloatAvailableSpace.height
   );
 #endif
 
   nsRect availSpace = AdjustFloatAvailableSpace(aState, aFloatAvailableSpace,
-                                                floatFrame);
-
-  nsHTMLReflowState floatRS(aState.mPresContext, aState.mReflowState,
-                            floatFrame, 
+                                                aFloat);
+
+  nsHTMLReflowState floatRS(aState.mPresContext, aState.mReflowState, aFloat,
                             nsSize(availSpace.width, availSpace.height));
 
   // Setup a block reflow state to reflow the float.
   nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState);
 
   // Reflow the float
   PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
 
   nsIFrame* clearanceFrame = nsnull;
   nsresult rv;
   do {
     nsCollapsingMargin margin;
     PRBool mayNeedRetry = PR_FALSE;
     floatRS.mDiscoveredClearance = nsnull;
     // Only first in flow gets a top margin.
-    if (!floatFrame->GetPrevInFlow()) {
+    if (!aFloat->GetPrevInFlow()) {
       nsBlockReflowContext::ComputeCollapsedTopMargin(floatRS, &margin,
                                                       clearanceFrame, &mayNeedRetry);
 
       if (mayNeedRetry && !clearanceFrame) {
         floatRS.mDiscoveredClearance = &clearanceFrame;
         // We don't need to push the float manager state because the the block has its own
         // float manager that will be destroyed and recreated
       }
@@ -5549,17 +5550,17 @@ nsBlockFrame::ReflowFloat(nsBlockReflowS
   if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) &&
       (NS_UNCONSTRAINEDSIZE == availSpace.height))
     aReflowStatus = NS_FRAME_COMPLETE;
 
   if (aReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW) {
     aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
   }
 
-  if (floatFrame->GetType() == nsGkAtoms::letterFrame) {
+  if (aFloat->GetType() == nsGkAtoms::letterFrame) {
     // We never split floating first letters; an incomplete state for
     // such frames simply means that there is more content to be
     // reflowed on the line.
     if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus)) 
       aReflowStatus = NS_FRAME_COMPLETE;
   }
 
   if (NS_FAILED(rv)) {
@@ -5572,30 +5573,30 @@ nsBlockFrame::ReflowFloat(nsBlockReflowS
   const nsHTMLReflowMetrics& metrics = brc.GetMetrics();
 
   // Set the rect, make sure the view is properly sized and positioned,
   // and tell the frame we're done reflowing it
   // XXXldb This seems like the wrong place to be doing this -- shouldn't
   // we be doing this in nsBlockReflowState::FlowAndPlaceFloat after
   // we've positioned the float, and shouldn't we be doing the equivalent
   // of |::PlaceFrameView| here?
-  floatFrame->SetSize(nsSize(metrics.width, metrics.height));
-  if (floatFrame->HasView()) {
-    nsContainerFrame::SyncFrameViewAfterReflow(aState.mPresContext, floatFrame,
-                                               floatFrame->GetView(),
+  aFloat->SetSize(nsSize(metrics.width, metrics.height));
+  if (aFloat->HasView()) {
+    nsContainerFrame::SyncFrameViewAfterReflow(aState.mPresContext, aFloat,
+                                               aFloat->GetView(),
                                                &metrics.mOverflowArea,
                                                NS_FRAME_NO_MOVE_VIEW);
   }
   // Pass floatRS so the frame hierarchy can be used (redoFloatRS has the same hierarchy)  
-  floatFrame->DidReflow(aState.mPresContext, &floatRS,
+  aFloat->DidReflow(aState.mPresContext, &floatRS,
                         NS_FRAME_REFLOW_FINISHED);
 
 #ifdef NOISY_FLOAT
   printf("end ReflowFloat %p, sized to %d,%d\n",
-         floatFrame, metrics.width, metrics.height);
+         aFloat, metrics.width, metrics.height);
 #endif
 
   return NS_OK;
 }
 
 //////////////////////////////////////////////////////////////////////
 // Painting, event handling
 
@@ -6430,18 +6431,17 @@ nsBlockFrame::CheckFloats(nsBlockReflowS
 
   // Check that the float list is what we would have built
   nsAutoTArray<nsIFrame*, 8> lineFloats;
   for (line_iterator line = begin_lines(), line_end = end_lines();
        line != line_end; ++line) {
     if (line->HasFloats()) {
       nsFloatCache* fc = line->GetFirstFloat();
       while (fc) {
-        nsIFrame* floatFrame = fc->mPlaceholder->GetOutOfFlowFrame();
-        lineFloats.AppendElement(floatFrame);
+        lineFloats.AppendElement(fc->mFloat);
         fc = fc->Next();
       }
     }
     if (line->IsDirty()) {
       anyLineDirty = PR_TRUE;
     }
   }
   
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -538,22 +538,22 @@ protected:
 
   // Compute the available width for a float. 
   nsRect AdjustFloatAvailableSpace(nsBlockReflowState& aState,
                                    const nsRect&       aFloatAvailableSpace,
                                    nsIFrame*           aFloatFrame);
   // Computes the border-box width of the float
   nscoord ComputeFloatWidth(nsBlockReflowState& aState,
                             const nsRect&       aFloatAvailableSpace,
-                            nsPlaceholderFrame* aPlaceholder);
+                            nsIFrame*           aFloat);
   // An incomplete aReflowStatus indicates the float should be split
   // but only if the available height is constrained.
   nsresult ReflowFloat(nsBlockReflowState& aState,
                        const nsRect&       aFloatAvailableSpace,
-                       nsPlaceholderFrame* aPlaceholder,
+                       nsIFrame*           aFloat,
                        nsMargin&           aFloatMargin,
                        nsReflowStatus&     aReflowStatus);
 
   //----------------------------------------
   // Methods for pushing/pulling lines/frames
 
   virtual nsresult CreateContinuationFor(nsBlockReflowState& aState,
                                          nsLineBox*          aLine,
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -450,17 +450,17 @@ void
 nsBlockReflowState::RecoverFloats(nsLineList::iterator aLine,
                                   nscoord aDeltaY)
 {
   if (aLine->HasFloats()) {
     // Place the floats into the space-manager again. Also slide
     // them, just like the regular frames on the line.
     nsFloatCache* fc = aLine->GetFirstFloat();
     while (fc) {
-      nsIFrame* floatFrame = fc->mPlaceholder->GetOutOfFlowFrame();
+      nsIFrame* floatFrame = fc->mFloat;
       if (aDeltaY != 0) {
         nsPoint p = floatFrame->GetPosition();
         floatFrame->SetPosition(nsPoint(p.x, p.y + aDeltaY));
         nsContainerFrame::PositionFrameView(floatFrame);
         nsContainerFrame::PositionChildViews(floatFrame);
       }
 #ifdef DEBUG
       if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisyFloatManager) {
@@ -561,29 +561,31 @@ nsBlockReflowState::RecoverStateFrom(nsL
 // 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,
-                             nsPlaceholderFrame* aPlaceholder,
+                             nsIFrame*           aFloat,
                              nscoord             aAvailableWidth,
                              nsReflowStatus&     aReflowStatus)
 {
   NS_PRECONDITION(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
-  aPlaceholder->GetOutOfFlowFrame()->SetParent(mBlock);
+  aFloat->SetParent(mBlock);
 
   aReflowStatus = NS_FRAME_COMPLETE;
   // Allocate a nsFloatCache for the float
   nsFloatCache* fc = mFloatCacheFreeList.Alloc();
-  fc->mPlaceholder = aPlaceholder;
+  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,34 +598,34 @@ nsBlockReflowState::AddFloat(nsLineLayou
   // 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, aPlaceholder) <=
+       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();
-    placed = FlowAndPlaceFloat(fc, aReflowStatus, forceFit);
+    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, aPlaceholder->GetOutOfFlowFrame());
-      
+      aLineLayout.UpdateBand(availSpace, aFloat);
+
       // Record this float in the current-line list
       mCurrentLineFloats.Append(fc);
       // 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()) {
@@ -751,75 +753,72 @@ nsBlockReflowState::CanPlaceFloat(const 
     // Restore Y coordinate
     mY = saveY;
   }
 
   return result;
 }
 
 PRBool
-nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache*   aFloatCache,
+nsBlockReflowState::FlowAndPlaceFloat(nsIFrame*       aFloat,
                                       nsReflowStatus& aReflowStatus,
                                       PRBool          aForceFit)
 {
   aReflowStatus = NS_FRAME_COMPLETE;
   // Save away the Y coordinate before placing the float. We will
   // restore mY at the end after placing the float. This is
   // necessary because any adjustments to mY during the float
   // placement are for the float only, not for any non-floating
   // content.
   nscoord saveY = mY;
 
-  nsPlaceholderFrame* placeholder = aFloatCache->mPlaceholder;
-  nsIFrame*           floatFrame = placeholder->GetOutOfFlowFrame();
-
   // Grab the float's display information
-  const nsStyleDisplay* floatDisplay = floatFrame->GetStyleDisplay();
+  const nsStyleDisplay* floatDisplay = aFloat->GetStyleDisplay();
 
   // The float's old region, so we can propagate damage.
-  nsRect oldRegion = nsFloatManager::GetRegionFor(floatFrame);
+  nsRect oldRegion = nsFloatManager::GetRegionFor(aFloat);
 
   // Enforce CSS2 9.5.1 rule [2], i.e., make sure that a float isn't
   // ``above'' another float that preceded it in the flow.
   mY = NS_MAX(mFloatManager->GetLowestFloatTop() + BorderPadding().top, mY);
 
   // See if the float should clear any preceding floats...
   // XXX We need to mark this float somehow so that it gets reflowed
   // when floats are inserted before it.
   if (NS_STYLE_CLEAR_NONE != floatDisplay->mBreakType) {
     // XXXldb Does this handle vertical margins correctly?
     mY = ClearFloats(mY, floatDisplay->mBreakType);
   }
     // Get the band of available space
   nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(mY, aForceFit);
 
-  NS_ASSERTION(floatFrame->GetParent() == mBlock,
+  NS_ASSERTION(aFloat->GetParent() == mBlock,
                "Float frame has wrong parent");
 
   // Reflow the float
   nsMargin floatMargin; // computed margin
-  mBlock->ReflowFloat(*this, floatAvailableSpace.mRect, placeholder,
+  mBlock->ReflowFloat(*this, floatAvailableSpace.mRect, aFloat,
                       floatMargin, aReflowStatus);
-  if (placeholder->GetPrevInFlow())
+  if (aFloat->GetPrevInFlow())
     floatMargin.top = 0;
   if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus))
     floatMargin.bottom = 0;
 
 #ifdef DEBUG
   if (nsBlockFrame::gNoisyReflow) {
-    nsRect region = floatFrame->GetRect();
+    nsRect region = aFloat->GetRect();
     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     printf("flowed float: ");
-    nsFrame::ListTag(stdout, floatFrame);
+    nsFrame::ListTag(stdout, aFloat);
     printf(" (%d,%d,%d,%d)\n",
 	   region.x, region.y, region.width, region.height);
   }
 #endif
 
-  nsSize floatSize = floatFrame->GetSize() +
+  nsSize floatSize = aFloat->GetSize() +
                      nsSize(floatMargin.LeftRight(), floatMargin.TopBottom());
 
   // Find a place to place the float. The CSS2 spec doesn't want
   // floats overlapping each other or sticking out of the containing
   // block if possible (CSS2 spec section 9.5.1, see the rule list).
   NS_ASSERTION((NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) ||
 	       (NS_STYLE_FLOAT_RIGHT == floatDisplay->mFloats),
 	       "invalid float type");
@@ -844,20 +843,20 @@ nsBlockReflowState::FlowAndPlaceFloat(ns
     } else {
       // This quirk matches the one in nsBlockFrame::ReflowFloat
       // IE handles float tables in a very special way
 
       // see if the previous float is also a table and has "align"
       nsFloatCache* fc = mCurrentLineFloats.Head();
       nsIFrame* prevFrame = nsnull;
       while (fc) {
-        if (fc->mPlaceholder->GetOutOfFlowFrame() == floatFrame) {
+        if (fc->mFloat == aFloat) {
           break;
         }
-        prevFrame = fc->mPlaceholder->GetOutOfFlowFrame();
+        prevFrame = fc->mFloat;
         fc = fc->Next();
       }
       
       if(prevFrame) {
         //get the frame type
         if (nsGkAtoms::tableOuterFrame == prevFrame->GetType()) {
           //see if it has "align="
           // IE makes a difference between align and he float property
@@ -879,20 +878,20 @@ nsBlockReflowState::FlowAndPlaceFloat(ns
 
       // the table does not fit anymore in this line so advance to next band 
       mY += floatAvailableSpace.mRect.height;
       floatAvailableSpace = GetFloatAvailableSpace(mY, aForceFit);
       // reflow the float again now since we have more space
       // XXXldb We really don't need to Reflow in a loop, we just need
       // to ComputeSize in a loop (once ComputeSize depends on
       // availableWidth, which should make this work again).
-      mBlock->ReflowFloat(*this, floatAvailableSpace.mRect, placeholder,
+      mBlock->ReflowFloat(*this, floatAvailableSpace.mRect, aFloat,
                           floatMargin, aReflowStatus);
       // Get the floats bounding box and margin information
-      floatSize = floatFrame->GetSize() +
+      floatSize = aFloat->GetSize() +
                      nsSize(floatMargin.LeftRight(), floatMargin.TopBottom());
     }
   }
   // If the float is continued, it will get the same absolute x value as its prev-in-flow
 
   // We don't worry about the geometry of the prev in flow, let the continuation
   // place and size itself as required.
 
@@ -929,46 +928,46 @@ nsBlockReflowState::FlowAndPlaceFloat(ns
   // Calculate the actual origin of the float frame's border rect
   // relative to the parent block; floatX/Y must be converted from space-manager
   // coordinates to parent coordinates, and the margin must be added in
   // to get the border rect
   nsPoint origin(borderPadding.left + floatMargin.left + floatX,
                  borderPadding.top + floatMargin.top + floatY);
 
   // If float is relatively positioned, factor that in as well
-  origin += floatFrame->GetRelativeOffset(floatDisplay);
+  origin += aFloat->GetRelativeOffset(floatDisplay);
 
   // Position the float and make sure and views are properly
   // positioned. We need to explicitly position its child views as
   // well, since we're moving the float after flowing it.
-  floatFrame->SetPosition(origin);
-  nsContainerFrame::PositionFrameView(floatFrame);
-  nsContainerFrame::PositionChildViews(floatFrame);
+  aFloat->SetPosition(origin);
+  nsContainerFrame::PositionFrameView(aFloat);
+  nsContainerFrame::PositionChildViews(aFloat);
 
   // Update the float combined area state
-  nsRect combinedArea = floatFrame->GetOverflowRect() + origin;
+  nsRect combinedArea = aFloat->GetOverflowRect() + origin;
 
   // XXX Floats should really just get invalidated here if necessary
   mFloatCombinedArea.UnionRect(combinedArea, mFloatCombinedArea);
 
   // Place the float in the float manager
   // calculate region
-  nsRect region = nsFloatManager::CalculateRegionFor(floatFrame, floatMargin);
+  nsRect region = nsFloatManager::CalculateRegionFor(aFloat, floatMargin);
   // if the float split, then take up all of the vertical height
   if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) &&
       (NS_UNCONSTRAINEDSIZE != mContentArea.height)) {
     region.height = PR_MAX(region.height, mContentArea.height - floatY);
   }
   nsresult rv =
   // spacemanager translation is inset by the border+padding.
-  mFloatManager->AddFloat(floatFrame,
+  mFloatManager->AddFloat(aFloat,
                           region - nsPoint(borderPadding.left, borderPadding.top));
   NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "bad float placement");
   // store region
-  rv = nsFloatManager::StoreRegionFor(floatFrame, region);
+  rv = nsFloatManager::StoreRegionFor(aFloat, region);
   NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "float region storage failed");
 
   // If the float's dimensions have changed, note the damage in the
   // float manager.
   if (region != oldRegion) {
     // XXXwaterson conservative: we could probably get away with noting
     // less damage; e.g., if only height has changed, then only note the
     // area into which the float has grown or from which the float has
@@ -987,20 +986,20 @@ nsBlockReflowState::FlowAndPlaceFloat(ns
          region.x, region.y, region.width, region.height);
 #endif
 
   // Now restore mY
   mY = saveY;
 
 #ifdef DEBUG
   if (nsBlockFrame::gNoisyReflow) {
-    nsRect r = floatFrame->GetRect();
+    nsRect r = aFloat->GetRect();
     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     printf("placed float: ");
-    nsFrame::ListTag(stdout, floatFrame);
+    nsFrame::ListTag(stdout, aFloat);
     printf(" %d,%d,%d,%d\n", r.x, r.y, r.width, r.height);
   }
 #endif
 
   return PR_TRUE;
 }
 
 /**
@@ -1011,23 +1010,23 @@ nsBlockReflowState::PlaceBelowCurrentLin
 {
   nsFloatCache* fc = aList.Head();
   while (fc) {
     {
 #ifdef DEBUG
       if (nsBlockFrame::gNoisyReflow) {
         nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
         printf("placing bcl float: ");
-        nsFrame::ListTag(stdout, fc->mPlaceholder->GetOutOfFlowFrame());
+        nsFrame::ListTag(stdout, fc->mFloat);
         printf("\n");
       }
 #endif
       // Place the float
       nsReflowStatus reflowStatus;
-      PRBool placed = FlowAndPlaceFloat(fc, reflowStatus, aForceFit);
+      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)) {
--- a/layout/generic/nsBlockReflowState.h
+++ b/layout/generic/nsBlockReflowState.h
@@ -105,23 +105,23 @@ public:
                                     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.
    */
   PRBool AddFloat(nsLineLayout&       aLineLayout,
-                  nsPlaceholderFrame* aPlaceholderFrame,
+                  nsIFrame*           aFloat,
                   nscoord             aAvailableWidth,
                   nsReflowStatus&     aReflowStatus);
   PRBool CanPlaceFloat(const nsSize& aFloatSize, PRUint8 aFloats,
                        const nsFlowAreaRect& aFloatAvailableSpace,
                        PRBool aForceFit);
-  PRBool FlowAndPlaceFloat(nsFloatCache*   aFloatCache,
+  PRBool FlowAndPlaceFloat(nsIFrame*       aFloat,
                            nsReflowStatus& aReflowStatus,
                            PRBool          aForceFit);
   PRBool PlaceBelowCurrentLineFloats(nsFloatCacheFreeList& aFloats, PRBool aForceFit);
 
   // Returns the first coordinate >= aY that clears the
   // floats indicated by aBreakType and has enough width between floats
   // (or no floats remaining) to accomodate aReplacedBlock.
   nscoord ClearFloats(nscoord aY, PRUint8 aBreakType,
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -40,16 +40,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /* base class of all rendering objects */
 
 #include "nsCOMPtr.h"
 #include "nsFrame.h"
 #include "nsFrameList.h"
+#include "nsPlaceholderFrame.h"
 #include "nsLineLayout.h"
 #include "nsIContent.h"
 #include "nsContentUtils.h"
 #include "nsIAtom.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsStyleContext.h"
 #include "nsIView.h"
@@ -1477,17 +1478,18 @@ nsIFrame::BuildDisplayListForChild(nsDis
   PRBool isComposited = disp->mOpacity != 1.0f ||
     ((aChild->mState & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS) && 
      aChild->GetStyleDisplay()->HasTransform())
 #ifdef MOZ_SVG
     || nsSVGIntegrationUtils::UsingEffectsForFrame(aChild)
 #endif
     ;
   PRBool isPositioned = disp->IsPositioned();
-  if (isComposited || isPositioned || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
+  if (isComposited || isPositioned || disp->IsFloating() ||
+      (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
     // If you change this, also change IsPseudoStackingContextFromStyle()
     pseudoStackingContext = PR_TRUE;
   }
   
   nsRect overflowClip;
   PRBool applyOverflowClip =
     ApplyOverflowClipping(aBuilder, aChild, disp, &overflowClip);
   // Don't use overflowClip to restrict the dirty rect, since some of the
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -2068,17 +2068,17 @@ public:
 
   /**
    * Determines whether this frame is a pseudo stacking context, looking
    * only as style --- i.e., assuming that it's in-flow and not a replaced
    * element.
    */
   PRBool IsPseudoStackingContextFromStyle() {
     const nsStyleDisplay* disp = GetStyleDisplay();
-    return disp->mOpacity != 1.0f || disp->IsPositioned();
+    return disp->mOpacity != 1.0f || disp->IsPositioned() || disp->IsFloating();
   }
   
   virtual PRBool HonorPrintBackgroundSettings() { return PR_TRUE; }
 
   /**
    * Determine whether the frame is logically empty, which is roughly
    * whether the layout would be the same whether or not the frame is
    * present.  Placeholder frames should return true.  Block frames
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -35,16 +35,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /* rendering object for CSS display:inline objects */
 
 #include "nsCOMPtr.h"
 #include "nsInlineFrame.h"
 #include "nsBlockFrame.h"
+#include "nsPlaceholderFrame.h"
 #include "nsGkAtoms.h"
 #include "nsHTMLParts.h"
 #include "nsStyleContext.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIRenderingContext.h"
 #include "nsIFontMetrics.h"
 #include "nsAbsoluteContainingBlock.h"
--- a/layout/generic/nsLineBox.cpp
+++ b/layout/generic/nsLineBox.cpp
@@ -135,31 +135,27 @@ nsLineBox::Cleanup()
 
 #ifdef DEBUG
 static void
 ListFloats(FILE* out, PRInt32 aIndent, const nsFloatCacheList& aFloats)
 {
   nsFloatCache* fc = aFloats.Head();
   while (fc) {
     nsFrame::IndentBy(out, aIndent);
-    nsPlaceholderFrame* ph = fc->mPlaceholder;
-    if (ph) {
-      fprintf(out, "placeholder@%p ", static_cast<void*>(ph));
-      nsIFrame* frame = ph->GetOutOfFlowFrame();
-      if (frame) {
-        nsAutoString frameName;
-        frame->GetFrameName(frameName);
-        fputs(NS_LossyConvertUTF16toASCII(frameName).get(), out);
-      }
-
-      if (!frame) {
-        fputs("\n###!!! NULL out-of-flow frame", out);
-      }
-      fprintf(out, "\n");
+    nsIFrame* frame = fc->mFloat;
+    fprintf(out, "floatframe@%p ", static_cast<void*>(frame));
+    if (frame) {
+      nsAutoString frameName;
+      frame->GetFrameName(frameName);
+      fputs(NS_LossyConvertUTF16toASCII(frameName).get(), out);
     }
+    else {
+      fputs("\n###!!! NULL out-of-flow frame", out);
+    }
+    fprintf(out, "\n");
     fc = fc->Next();
   }
 }
 #endif
 
 #ifdef DEBUG
 const char *
 BreakTypeToString(PRUint8 aBreakType)
@@ -831,17 +827,17 @@ nsFloatCacheList::Append(nsFloatCacheFre
   aList.mTail = nsnull;
 }
 
 nsFloatCache*
 nsFloatCacheList::Find(nsIFrame* aOutOfFlowFrame)
 {
   nsFloatCache* fc = mHead;
   while (fc) {
-    if (fc->mPlaceholder->GetOutOfFlowFrame() == aOutOfFlowFrame) {
+    if (fc->mFloat == aOutOfFlowFrame) {
       break;
     }
     fc = fc->Next();
   }
   return fc;
 }
 
 nsFloatCache*
@@ -945,17 +941,17 @@ nsFloatCacheFreeList::Append(nsFloatCach
     NS_ASSERTION(!mHead, "Bogus!");
     mHead = mTail = aFloat;
   }
 }
 
 //----------------------------------------------------------------------
 
 nsFloatCache::nsFloatCache()
-  : mPlaceholder(nsnull),
+  : mFloat(nsnull),
     mNext(nsnull)
 {
   MOZ_COUNT_CTOR(nsFloatCache);
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsFloatCache::~nsFloatCache()
 {
--- a/layout/generic/nsLineBox.h
+++ b/layout/generic/nsLineBox.h
@@ -38,18 +38,18 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /* representation of one line within a block frame, a CSS line box */
 
 #ifndef nsLineBox_h___
 #define nsLineBox_h___
 
-#include "nsPlaceholderFrame.h"
 #include "nsILineIterator.h"
+#include "nsIFrame.h"
 
 class nsLineBox;
 class nsFloatCache;
 class nsFloatCacheList;
 class nsFloatCacheFreeList;
 
 // State cached after reflowing a float. This state is used during
 // incremental reflow when we avoid reflowing a float.
@@ -59,17 +59,17 @@ public:
 #ifdef NS_BUILD_REFCNT_LOGGING
   ~nsFloatCache();
 #else
   ~nsFloatCache() { }
 #endif
 
   nsFloatCache* Next() const { return mNext; }
 
-  nsPlaceholderFrame* mPlaceholder;     // nsPlaceholderFrame
+  nsIFrame* mFloat;                     // floating frame
 
 protected:
   nsFloatCache* mNext;
 
   friend class nsFloatCacheList;
   friend class nsFloatCacheFreeList;
 };
 
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -862,34 +862,33 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
   if (!frameType) {
     isEmpty = pfd->mFrame->IsEmpty();
   } else {
     if (nsGkAtoms::placeholderFrame == frameType) {
       isEmpty = PR_TRUE;
       pfd->SetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE, PR_TRUE);
       nsIFrame* outOfFlowFrame = nsLayoutUtils::GetFloatFromPlaceholder(aFrame);
       if (outOfFlowFrame) {
-        nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(aFrame);
         // Add mTrimmableWidth to the available width since if the line ends
         // here, the width of the inline content will be reduced by
         // mTrimmableWidth.
         nscoord availableWidth = psd->mRightEdge - (psd->mX - mTrimmableWidth);
         if (psd->mNoWrap) {
           // If we place floats after inline content where there's
           // no break opportunity, we don't know how much additional
           // width is required for the non-breaking content after the float,
           // so we can't know whether the float plus that content will fit
           // on the line. So for now, don't place floats after inline
           // content where there's no break opportunity. This is incorrect
           // but hopefully rare. Fixing it will require significant
           // restructuring of line layout.
           // We might as well allow zero-width floats to be placed, though.
           availableWidth = 0;
         }
-        placedFloat = AddFloat(placeholder, availableWidth, aReflowStatus);
+        placedFloat = AddFloat(outOfFlowFrame, availableWidth, aReflowStatus);
         NS_ASSERTION(!(outOfFlowFrame->GetType() == nsGkAtoms::letterFrame &&
                        GetFirstLetterStyleOK()),
                     "FirstLetterStyle set on line with floating first letter");
       }
     }
     else if (nsGkAtoms::textFrame == frameType) {
       // Note non-empty text-frames for inline frame compatibility hackery
       pfd->SetFlag(PFD_ISTEXTFRAME, PR_TRUE);
--- a/layout/generic/nsLineLayout.h
+++ b/layout/generic/nsLineLayout.h
@@ -204,20 +204,21 @@ public:
   void SetLineEndsInBR(PRBool aOn) 
   { 
     SetFlag(LL_LINEENDSINBR, aOn); 
   }
 
   //----------------------------------------
   // Inform the line-layout about the presence of a floating frame
   // XXX get rid of this: use get-frame-type?
-  PRBool AddFloat(nsPlaceholderFrame* aFrame,
-                  nscoord aAvailableWidth,
-                  nsReflowStatus& aReflowStatus) {
-    return mBlockRS->AddFloat(*this, aFrame, aAvailableWidth, aReflowStatus);
+  PRBool AddFloat(nsIFrame*       aFloat,
+                  nscoord         aAvailableWidth,
+                  nsReflowStatus& aReflowStatus)
+  {
+    return mBlockRS->AddFloat(*this, aFloat, aAvailableWidth, aReflowStatus);
   }
 
   void SetTrimmableWidth(nscoord aTrimmableWidth) {
     mTrimmableWidth = aTrimmableWidth;
   }
 
   //----------------------------------------
 
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -72,16 +72,17 @@
 #include "nsIDocument.h"
 #include "nsIDeviceContext.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCompatibility.h"
 #include "nsCSSColorUtils.h"
 #include "nsLayoutUtils.h"
 #include "nsDisplayList.h"
 #include "nsFrame.h"
+#include "nsPlaceholderFrame.h"
 #include "nsTextFrameUtils.h"
 #include "nsTextRunTransformations.h"
 #include "nsFrameManager.h"
 #include "nsTextFrameTextRunCache.h"
 #include "nsExpirationTracker.h"
 #include "nsTextFrame.h"
 #include "nsICaseConversion.h"
 #include "nsIUGenCategory.h"