Use a struct containing a rectangle and a boolean for float available space rather than passing them around separately. (Bug 25888) r+sr=roc
authorL. David Baron <dbaron@dbaron.org>
Wed, 08 Apr 2009 13:52:37 -0700
changeset 27106 e5b1ab03542642f3de010c3eb31c3e4484f32e3c
parent 27105 f82ad9a10b7dffc6a56bc50fd403bd82dae6d517
child 27107 228855cf8aaeb7581947de3a3c0133003235dbd2
push idunknown
push userunknown
push dateunknown
bugs25888
milestone1.9.2a1pre
Use a struct containing a rectangle and a boolean for float available space rather than passing them around separately. (Bug 25888) r+sr=roc
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockReflowState.cpp
layout/generic/nsBlockReflowState.h
layout/generic/nsFloatManager.cpp
layout/generic/nsFloatManager.h
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1653,30 +1653,28 @@ nsBlockFrame::PropagateFloatDamage(nsBlo
       // if there's a float impacting this block, but the current float manager
       // makes it difficult to check that.  Therefore, we let the child block
       // decide what it needs to reflow.
       aLine->MarkDirty();
     } else {
       // Note that this check will become incorrect once bug 25888 is fixed
       // because we are only checking the top of the line
       PRBool wasImpactedByFloat = aLine->IsImpactedByFloat();
-      nsRect floatAvailableSpace;
-      PRBool isImpactedByFloat =
-        aState.GetFloatAvailableSpace(aLine->mBounds.y + aDeltaY, PR_FALSE,
-                                      floatAvailableSpace);
+      nsFlowAreaRect floatAvailableSpace =
+        aState.GetFloatAvailableSpace(aLine->mBounds.y + aDeltaY, PR_FALSE);
 
 #ifdef REALLY_NOISY_REFLOW
     printf("nsBlockFrame::PropagateFloatDamage %p was = %d, is=%d\n", 
-       this, wasImpactedByFloat, isImpactedByFloat);
+           this, wasImpactedByFloat, floatAvailableSpace.mHasFloats);
 #endif
 
       // Mark the line dirty if it was or is affected by a float
       // We actually only really need to reflow if the amount of impact
       // changes, but that's not straightforward to check
-      if (wasImpactedByFloat || isImpactedByFloat) {
+      if (wasImpactedByFloat || floatAvailableSpace.mHasFloats) {
         aLine->MarkDirty();
       }
     }
   }
 }
 
 static void PlaceFrameView(nsIFrame* aFrame);
 
@@ -2948,26 +2946,24 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
       } else {
         // Advance aState.mY to the top border-edge of the frame.
         aState.mY += topMargin;
       }
     }
     
     // Here aState.mY is the top border-edge of the block.
     // Compute the available space for the block
-    nsRect floatAvailableSpace;
-    PRBool isImpacted = aState.GetFloatAvailableSpace(floatAvailableSpace);
+    nsFlowAreaRect floatAvailableSpace = aState.GetFloatAvailableSpace();
 #ifdef REALLY_NOISY_REFLOW
     printf("setting line %p isImpacted to %s\n",
-           aLine.get(), isImpacted?"true":"false");
+           aLine.get(), floatAvailableSpace.mHasFloats?"true":"false");
 #endif
-    aLine->SetLineIsImpactedByFloat(isImpacted);
+    aLine->SetLineIsImpactedByFloat(floatAvailableSpace.mHasFloats);
     nsRect availSpace;
-    aState.ComputeBlockAvailSpace(frame, display,
-                                  isImpacted, floatAvailableSpace,
+    aState.ComputeBlockAvailSpace(frame, display, floatAvailableSpace,
                                   replacedBlock != nsnull, availSpace);
     
     // Now put the Y coordinate back to the top of the top-margin +
     // clearance, and flow the block.
     aState.mY -= topMargin;
     availSpace.y -= topMargin;
     if (NS_UNCONSTRAINEDSIZE != availSpace.height) {
       availSpace.height += topMargin;
@@ -3038,17 +3034,17 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
       
       // Try to place the child block.
       // Don't force the block to fit if we have positive clearance, because
       // pushing it to the next page would give it more room.
       // Don't force the block to fit if it's impacted by a float. If it is,
       // then pushing it to the next page would give it more room. Note that
       // isImpacted doesn't include impact from the block's own floats.
       PRBool forceFit = aState.IsAdjacentWithTop() && clearance <= 0 &&
-        !isImpacted;
+        !floatAvailableSpace.mHasFloats;
       nsCollapsingMargin collapsedBottomMargin;
       nsRect combinedArea(0,0,0,0);
       *aKeepReflowGoing = brc.PlaceBlock(blockHtmlRS, forceFit, aLine.get(),
                                          collapsedBottomMargin,
                                          aLine->mBounds, combinedArea, frameReflowStatus);
       if (aLine->SetCarriedOutBottomMargin(collapsedBottomMargin)) {
         line_iterator nextLine = aLine;
         ++nextLine;
@@ -3346,43 +3342,42 @@ nsBlockFrame::DoReflowInlineFrames(nsBlo
   aLine->FreeFloats(aState.mFloatCacheFreeList);
   aState.mFloatCombinedArea.SetRect(0, 0, 0, 0);
 
   // Setup initial coordinate system for reflowing the inline frames
   // into. Apply a previous block frame's bottom margin first.
   if (ShouldApplyTopMargin(aState, aLine)) {
     aState.mY += aState.mPrevBottomMargin.get();
   }
-  nsRect floatAvailableSpace;
-  PRBool impactedByFloats = aState.GetFloatAvailableSpace(floatAvailableSpace);
-  aLine->SetLineIsImpactedByFloat(impactedByFloats);
+  nsFlowAreaRect floatAvailableSpace = aState.GetFloatAvailableSpace();
+  aLine->SetLineIsImpactedByFloat(floatAvailableSpace.mHasFloats);
 #ifdef REALLY_NOISY_REFLOW
   printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n",
-         this, impactedByFloats);
+         this, floatAvailableSpace.mHasFloats);
 #endif
 
   const nsMargin& borderPadding = aState.BorderPadding();
-  nscoord x = floatAvailableSpace.x + borderPadding.left;
-  nscoord availWidth = floatAvailableSpace.width;
+  nscoord x = floatAvailableSpace.mRect.x + borderPadding.left;
+  nscoord availWidth = floatAvailableSpace.mRect.width;
   nscoord availHeight;
   if (aState.GetFlag(BRS_UNCONSTRAINEDHEIGHT)) {
     availHeight = NS_UNCONSTRAINEDSIZE;
   }
   else {
     /* XXX get the height right! */
-    availHeight = floatAvailableSpace.height;
+    availHeight = floatAvailableSpace.mRect.height;
   }
 
   // Make sure to enable resize optimization before we call BeginLineReflow
   // because it might get disabled there
   aLine->EnableResizeReflowOptimization();
 
   aLineLayout.BeginLineReflow(x, aState.mY,
                               availWidth, availHeight,
-                              impactedByFloats,
+                              floatAvailableSpace.mHasFloats,
                               PR_FALSE /*XXX isTopOfPage*/);
 
   aState.SetFlag(BRS_LINE_LAYOUT_EMPTY, PR_FALSE);
 
   // XXX Unfortunately we need to know this before reflowing the first
   // inline frame in the line. FIX ME.
   if ((0 == aLineLayout.GetLineNumber()) &&
       (NS_BLOCK_HAS_FIRST_LETTER_CHILD & mState) &&
@@ -3395,17 +3390,17 @@ nsBlockFrame::DoReflowInlineFrames(nsBlo
   LineReflowStatus lineReflowStatus = LINE_REFLOW_OK;
   PRInt32 i;
   nsIFrame* frame = aLine->mFirstChild;
 
   // Determine whether this is a line of placeholders for out-of-flow
   // continuations
   PRBool isContinuingPlaceholders = PR_FALSE;
 
-  if (impactedByFloats) {
+  if (floatAvailableSpace.mHasFloats) {
     // There is a soft break opportunity at the start of the line, because
     // we can always move this line down below float(s).
     if (aLineLayout.NotifyOptionalBreakPosition(frame->GetContent(), 0, PR_TRUE, eNormalBreak)) {
       lineReflowStatus = LINE_REFLOW_REDO_NEXT_BAND;
     }
   }
 
   // need to repeatedly call GetChildCount here, because the child
@@ -3500,24 +3495,24 @@ nsBlockFrame::DoReflowInlineFrames(nsBlo
 
   if (LINE_REFLOW_REDO_NEXT_BAND == lineReflowStatus) {
     // This happens only when we have a line that is impacted by
     // floats and the first element in the line doesn't fit with
     // the floats.
     //
     // What we do is to advance past the first float we find and
     // then reflow the line all over again.
-    NS_ASSERTION(NS_UNCONSTRAINEDSIZE != floatAvailableSpace.height,
+    NS_ASSERTION(NS_UNCONSTRAINEDSIZE != floatAvailableSpace.mRect.height,
                  "unconstrained height on totally empty line");
 
     // See the analogous code for blocks in nsBlockReflowState::ClearFloats.
-    if (floatAvailableSpace.height > 0) {
-      NS_ASSERTION(impactedByFloats,
+    if (floatAvailableSpace.mRect.height > 0) {
+      NS_ASSERTION(floatAvailableSpace.mHasFloats,
                    "redo line on totally empty line with non-empty band...");
-      aState.mY += floatAvailableSpace.height;
+      aState.mY += floatAvailableSpace.mRect.height;
     } else {
       NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableHeight,
                    "We shouldn't be running out of height here");
       if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableHeight) {
         // just move it down a bit to try to get out of this mess
         aState.mY += 1;
       } else {
         // There's nowhere to retry placing the line. Just treat it as if
@@ -6659,20 +6654,20 @@ nsBlockFrame::ReflowBullet(nsBlockReflow
   mBullet->WillReflow(aState.mPresContext);
   mBullet->Reflow(aState.mPresContext, aMetrics, reflowState, status);
 
   // Get the float available space using our saved state from before we
   // started reflowing the block, so that we ignore any floats inside
   // the block.
   // FIXME: aLineTop isn't actually set correctly by some callers, since
   // they reposition the line.
-  nsRect floatAvailSpace;
-  aState.GetFloatAvailableSpaceWithState(aLineTop, PR_FALSE,
-                                         &aState.mFloatManagerStateBefore,
-                                         floatAvailSpace);
+  nsRect floatAvailSpace =
+    aState.GetFloatAvailableSpaceWithState(aLineTop, PR_FALSE,
+                                           &aState.mFloatManagerStateBefore)
+          .mRect;
   // FIXME (bug 25888): need to check the entire region that the first
   // line overlaps, not just the top pixel.
 
   // Place the bullet now.  We want to place the bullet relative to the
   // border-box of the associated block (using the right/left margin of
   // the bullet frame as separation).  However, if a line box would be
   // displaced by floats that are *outside* the associated block, we
   // want to displace it by the same amount.  That is, we act as though
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -240,23 +240,23 @@ nsBlockReflowState::ComputeReplacedBlock
 }
 
 // Compute the amount of available space for reflowing a block frame
 // at the current Y coordinate. This method assumes that
 // GetAvailableSpace has already been called.
 void
 nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
                                            const nsStyleDisplay* aDisplay,
-                                           PRBool aBandHasFloats,
-                                           const nsRect& aFloatAvailableSpace,
+                                           const nsFlowAreaRect& aFloatAvailableSpace,
                                            PRBool aBlockAvoidsFloats,
                                            nsRect& aResult)
 {
 #ifdef REALLY_NOISY_REFLOW
-  printf("CBAS frame=%p has floats %d\n", aFrame, aBandHasFloats);
+  printf("CBAS frame=%p has floats %d\n",
+         aFrame, aFloatAvailableSpace.mHasFloats);
 #endif
   aResult.y = mY;
   aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
     ? NS_UNCONSTRAINEDSIZE
     : PR_MAX(0, mReflowState.availableHeight - mY);
   // mY might be greater than mBottomEdge if the block's top margin pushes
   // it off the page/column. Negative available height can confuse other code
   // and is nonsense in principle.
@@ -274,34 +274,34 @@ nsBlockReflowState::ComputeBlockAvailSpa
   // true but nsBlockFrame::BlockCanIntersectFloats is false,
   // nsBlockFrame::WidthToClearPastFloats would need to use the
   // shrink-wrap formula, max(MIN_WIDTH, min(avail width, PREF_WIDTH))
   // rather than just using MIN_WIDTH.
   NS_ASSERTION(nsBlockFrame::BlockCanIntersectFloats(aFrame) == 
                  !aBlockAvoidsFloats,
                "unexpected replaced width");
   if (!aBlockAvoidsFloats) {
-    if (aBandHasFloats) {
+    if (aFloatAvailableSpace.mHasFloats) {
       // Use the float-edge property to determine how the child block
       // will interact with the float.
       const nsStyleBorder* borderStyle = aFrame->GetStyleBorder();
       switch (borderStyle->mFloatEdge) {
         default:
         case NS_STYLE_FLOAT_EDGE_CONTENT:  // content and only content does runaround of floats
           // The child block will flow around the float. Therefore
           // give it all of the available space.
           aResult.x = borderPadding.left;
           aResult.width = mContentArea.width;
           break;
         case NS_STYLE_FLOAT_EDGE_MARGIN:
           {
             // The child block's margins should be placed adjacent to,
             // but not overlap the float.
-            aResult.x = aFloatAvailableSpace.x + borderPadding.left;
-            aResult.width = aFloatAvailableSpace.width;
+            aResult.x = aFloatAvailableSpace.mRect.x + borderPadding.left;
+            aResult.width = aFloatAvailableSpace.mRect.width;
           }
           break;
       }
     }
     else {
       // Since there are no floats present the float-edge property
       // doesn't matter therefore give the block element all of the
       // available space since it will flow around the float itself.
@@ -310,65 +310,64 @@ nsBlockReflowState::ComputeBlockAvailSpa
     }
   }
   else {
     nsBlockFrame::ReplacedElementWidthToClear replacedWidthStruct;
     nsBlockFrame::ReplacedElementWidthToClear *replacedWidth = nsnull;
     if (aFrame->GetType() == nsGkAtoms::tableOuterFrame) {
       replacedWidth = &replacedWidthStruct;
       replacedWidthStruct =
-        nsBlockFrame::WidthToClearPastFloats(*this, aFloatAvailableSpace,
+        nsBlockFrame::WidthToClearPastFloats(*this, aFloatAvailableSpace.mRect,
                                              aFrame);
     }
 
     nscoord leftOffset, rightOffset;
-    ComputeReplacedBlockOffsetsForFloats(aFrame, aFloatAvailableSpace,
+    ComputeReplacedBlockOffsetsForFloats(aFrame, aFloatAvailableSpace.mRect,
                                          leftOffset, rightOffset,
                                          replacedWidth);
     aResult.x = borderPadding.left + leftOffset;
     aResult.width = mContentArea.width - leftOffset - rightOffset;
   }
 
 #ifdef REALLY_NOISY_REFLOW
   printf("  CBAS: result %d %d %d %d\n", aResult.x, aResult.y, aResult.width, aResult.height);
 #endif
 }
 
-PRBool
+nsFlowAreaRect
 nsBlockReflowState::GetFloatAvailableSpaceWithState(
                       nscoord aY, PRBool aRelaxHeightConstraint,
-                      nsFloatManager::SavedState *aState,
-                      nsRect& aResult) const
+                      nsFloatManager::SavedState *aState) const
 {
 #ifdef DEBUG
   // Verify that the caller setup the coordinate system properly
   nscoord wx, wy;
   mFloatManager->GetTranslation(wx, wy);
   NS_ASSERTION((wx == mFloatManagerX) && (wy == mFloatManagerY),
                "bad coord system");
 #endif
 
-  PRBool hasFloats;
-  aResult = 
+  nsFlowAreaRect result =
     mFloatManager->GetBand(aY - BorderPadding().top, 
                            aRelaxHeightConstraint ? nscoord_MAX
                                                   : mContentArea.height,
-                           mContentArea.width, aState, &hasFloats);
+                           mContentArea.width, aState);
   // Keep the width >= 0 for compatibility with nsSpaceManager.
-  if (aResult.width < 0)
-    aResult.width = 0;
+  if (result.mRect.width < 0)
+    result.mRect.width = 0;
 
 #ifdef DEBUG
   if (nsBlockFrame::gNoisyReflow) {
     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     printf("GetAvailableSpace: band=%d,%d,%d,%d hasfloats=%d\n",
-           aResult.x, aResult.y, aResult.width, aResult.height, hasFloats);
+           result.mRect.x, result.mRect.y, result.mRect.width,
+           result.mRect.height, result.mHasFloats);
   }
 #endif
-  return hasFloats;
+  return result;
 }
 
 /*
  * Reconstruct the vertical margin before the line |aLine| in order to
  * do an incremental reflow that begins with |aLine| without reflowing
  * the line before it.  |aLine| may point to the fencepost at the end of
  * the line list, and it is used this way since we (for now, anyway)
  * always need to recover margins at the end of a block.
@@ -575,36 +574,36 @@ 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(floatAvailableSpace);
+  nsRect floatAvailableSpace = GetFloatAvailableSpace().mRect;
   if (mBelowCurrentLineFloats.IsEmpty() &&
       (aLineLayout.LineIsEmpty() ||
        mBlock->ComputeFloatWidth(*this, floatAvailableSpace, aPlaceholder) <=
          aAvailableWidth)) {
     // And then place it
     PRBool isLeftFloat;
     // 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, &isLeftFloat, 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
-      nsRect floatAvailSpace;
-      GetFloatAvailableSpace(mY, forceFit, floatAvailSpace);
-      nsRect availSpace(nsPoint(floatAvailSpace.x + BorderPadding().left, mY),
-                        floatAvailSpace.Size());
+      nsFlowAreaRect floatAvailSpace =
+        GetFloatAvailableSpace(mY, forceFit);
+      nsRect availSpace(nsPoint(floatAvailSpace.mRect.x + BorderPadding().left,
+                                mY),
+                        floatAvailSpace.mRect.Size());
       aLineLayout.UpdateBand(availSpace, isLeftFloat,
                              aPlaceholder->GetOutOfFlowFrame());
       
       // 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;
@@ -648,58 +647,59 @@ nsBlockReflowState::AddFloat(nsLineLayou
   // Restore coordinate system
   mFloatManager->Translate(dx, dy);
 
   return placed;
 }
 
 PRBool
 nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize, PRUint8 aFloats,
-                                  const nsRect& aFloatAvailableSpace,
-                                  PRBool aBandHasFloats, PRBool aForceFit)
+                                  const nsFlowAreaRect& aFloatAvailableSpace,
+                                  PRBool aForceFit)
 {
   // If the current Y coordinate is not impacted by any floats
   // then by definition the float fits.
   PRBool result = PR_TRUE;
-  if (aBandHasFloats) {
+  if (aFloatAvailableSpace.mHasFloats) {
     // XXX We should allow overflow by up to half a pixel here (bug 21193).
-    if (aFloatAvailableSpace.width < aFloatSize.width) {
+    if (aFloatAvailableSpace.mRect.width < aFloatSize.width) {
       // The available width is too narrow (and its been impacted by a
       // prior float)
       result = PR_FALSE;
     }
   }
 
   if (!result)
     return result;
 
   // At this point we know that there is enough horizontal space for
   // the float (somewhere). Lets see if there is enough vertical
   // space.
-  if (NSCoordGreaterThan(aFloatSize.height, aFloatAvailableSpace.height)) {
+  if (NSCoordGreaterThan(aFloatSize.height,
+                         aFloatAvailableSpace.mRect.height)) {
     // The available height is too short. However, its possible that
     // there is enough open space below which is not impacted by a
     // float.
     //
     // Compute the X coordinate for the float based on its float
     // type, assuming its placed on the current line. This is
     // where the float will be placed horizontally if it can go
     // here.
     nscoord xa;
     if (NS_STYLE_FLOAT_LEFT == aFloats) {
-      xa = aFloatAvailableSpace.x;
+      xa = aFloatAvailableSpace.mRect.x;
     }
     else {
-      xa = aFloatAvailableSpace.XMost() - aFloatSize.width;
+      xa = aFloatAvailableSpace.mRect.XMost() - aFloatSize.width;
 
       // In case the float is too big, don't go past the left edge
       // XXXldb This seems wrong, but we might want to fix bug 6976
       // first.
-      if (xa < aFloatAvailableSpace.x) {
-        xa = aFloatAvailableSpace.x;
+      if (xa < aFloatAvailableSpace.mRect.x) {
+        xa = aFloatAvailableSpace.mRect.x;
       }
     }
     nscoord xb = xa + aFloatSize.width;
 
     // Calculate the top and bottom y coordinates, again assuming
     // that the float is placed on the current line.
     const nsMargin& borderPadding = BorderPadding();
     nscoord ya = mY - borderPadding.top;
@@ -709,40 +709,39 @@ nsBlockReflowState::CanPlaceFloat(const 
       // containing block is the content edge of the block box, this
       // means the margin edge of the float can't be higher than the
       // content edge of the block that contains it.)
       ya = 0;
     }
     nscoord yb = ya + aFloatSize.height;
 
     nscoord saveY = mY;
-    nsRect floatAvailableSpace(aFloatAvailableSpace);
+    nsFlowAreaRect floatAvailableSpace(aFloatAvailableSpace);
     for (;;) {
       // Get the available space at the new Y coordinate
-      if (floatAvailableSpace.height <= 0) {
+      if (floatAvailableSpace.mRect.height <= 0) {
         // there is no more available space. We lose.
         result = PR_FALSE;
         break;
       }
 
-      mY += floatAvailableSpace.height;
-      PRBool bandHasFloats =
-        GetFloatAvailableSpace(mY, aForceFit, floatAvailableSpace);
+      mY += floatAvailableSpace.mRect.height;
+      floatAvailableSpace = GetFloatAvailableSpace(mY, aForceFit);
 
-      if (bandHasFloats) {
-        if (xa < floatAvailableSpace.x ||
-            xb > floatAvailableSpace.XMost()) {
+      if (floatAvailableSpace.mHasFloats) {
+        if (xa < floatAvailableSpace.mRect.x ||
+            xb > floatAvailableSpace.mRect.XMost()) {
           // The float can't go here.
           result = PR_FALSE;
           break;
         }
       }
 
       // See if there is now enough height for the float.
-      if (yb <= mY + floatAvailableSpace.height) {
+      if (yb <= mY + floatAvailableSpace.mRect.height) {
         // Winner. The bottom Y coordinate of the float is in
         // this band.
         break;
       }
     }
 
     // Restore Y coordinate
     mY = saveY;
@@ -781,26 +780,24 @@ nsBlockReflowState::FlowAndPlaceFloat(ns
   // 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
-  nsRect floatAvailableSpace;
-  PRBool bandHasFloats =
-    GetFloatAvailableSpace(mY, aForceFit, floatAvailableSpace);
+  nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(mY, aForceFit);
 
   NS_ASSERTION(floatFrame->GetParent() == mBlock,
                "Float frame has wrong parent");
 
   // Reflow the float
   nsMargin floatMargin;
-  mBlock->ReflowFloat(*this, floatAvailableSpace, placeholder,
+  mBlock->ReflowFloat(*this, floatAvailableSpace.mRect, placeholder,
                       floatMargin, aReflowStatus);
 
 #ifdef DEBUG
   if (nsBlockFrame::gNoisyReflow) {
     nsRect region = floatFrame->GetRect();
     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     printf("flowed float: ");
     nsFrame::ListTag(stdout, floatFrame);
@@ -818,30 +815,29 @@ nsBlockReflowState::FlowAndPlaceFloat(ns
   NS_ASSERTION((NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) ||
 	       (NS_STYLE_FLOAT_RIGHT == floatDisplay->mFloats),
 	       "invalid float type");
 
   // Can the float fit here?
   PRBool keepFloatOnSameLine = PR_FALSE;
 
   while (!CanPlaceFloat(floatSize, floatDisplay->mFloats, floatAvailableSpace,
-                        bandHasFloats, aForceFit)) {
-    if (floatAvailableSpace.height <= 0) {
+                        aForceFit)) {
+    if (floatAvailableSpace.mRect.height <= 0) {
       // No space, nowhere to put anything.
       mY = saveY;
       return PR_FALSE;
     }
 
     // Nope. try to advance to the next band.
     if (NS_STYLE_DISPLAY_TABLE != floatDisplay->mDisplay ||
           eCompatibility_NavQuirks != mPresContext->CompatibilityMode() ) {
 
-      mY += floatAvailableSpace.height;
-      bandHasFloats =
-        GetFloatAvailableSpace(mY, aForceFit, floatAvailableSpace);
+      mY += floatAvailableSpace.mRect.height;
+      floatAvailableSpace = GetFloatAvailableSpace(mY, aForceFit);
     } 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) {
@@ -869,24 +865,23 @@ nsBlockReflowState::FlowAndPlaceFloat(ns
               // since we cannot evangelize the world
               break;
             }
           }
         }
       }
 
       // the table does not fit anymore in this line so advance to next band 
-      mY += floatAvailableSpace.height;
-      bandHasFloats =
-        GetFloatAvailableSpace(mY, aForceFit, floatAvailableSpace);
+      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, placeholder,
+      mBlock->ReflowFloat(*this, floatAvailableSpace.mRect, placeholder,
                           floatMargin, aReflowStatus);
       // Get the floats bounding box and margin information
       floatSize = floatFrame->GetSize() +
                      nsSize(floatMargin.LeftRight(), floatMargin.TopBottom());
     }
   }
   // If the float is continued, it will get the same absolute x value as its prev-in-flow
 
@@ -896,28 +891,28 @@ nsBlockReflowState::FlowAndPlaceFloat(ns
   // Assign an x and y coordinate to the float. Note that the x,y
   // coordinates are computed <b>relative to the translation in the
   // spacemanager</b> which means that the impacted region will be
   // <b>inside</b> the border/padding area.
   PRBool isLeftFloat;
   nscoord floatX, floatY;
   if (NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) {
     isLeftFloat = PR_TRUE;
-    floatX = floatAvailableSpace.x;
+    floatX = floatAvailableSpace.mRect.x;
   }
   else {
     isLeftFloat = PR_FALSE;
     if (!keepFloatOnSameLine) {
-      floatX = floatAvailableSpace.XMost() - floatSize.width;
+      floatX = floatAvailableSpace.mRect.XMost() - floatSize.width;
     } 
     else {
       // this is the IE quirk (see few lines above)
       // the table is kept in the same line: don't let it overlap the
       // previous float 
-      floatX = floatAvailableSpace.x;
+      floatX = floatAvailableSpace.mRect.x;
     }
   }
   *aIsLeftFloat = isLeftFloat;
   const nsMargin& borderPadding = BorderPadding();
   floatY = mY - borderPadding.top;
   if (floatY < 0) {
     // CSS2 spec, 9.5.1 rule [4]: "A floating box's outer top may not
     // be higher than the top of its containing block."  (Since the
@@ -1101,35 +1096,35 @@ nsBlockReflowState::ClearFloats(nscoord 
   nscoord newY = aY;
 
   if (aBreakType != NS_STYLE_CLEAR_NONE) {
     newY = bp.top + mFloatManager->ClearFloats(newY - bp.top, aBreakType);
   }
 
   if (aReplacedBlock) {
     for (;;) {
-      nsRect floatAvailableSpace;
-      PRBool bandHasFloats =
-        GetFloatAvailableSpace(newY, PR_FALSE, floatAvailableSpace);
+      nsFlowAreaRect floatAvailableSpace = 
+        GetFloatAvailableSpace(newY, PR_FALSE);
       nsBlockFrame::ReplacedElementWidthToClear replacedWidth =
-        nsBlockFrame::WidthToClearPastFloats(*this, floatAvailableSpace,
+        nsBlockFrame::WidthToClearPastFloats(*this, floatAvailableSpace.mRect,
                                              aReplacedBlock);
-      if (!bandHasFloats ||
-          PR_MAX(floatAvailableSpace.x, replacedWidth.marginLeft) +
+      if (!floatAvailableSpace.mHasFloats ||
+          PR_MAX(floatAvailableSpace.mRect.x, replacedWidth.marginLeft) +
             replacedWidth.borderBoxWidth +
             PR_MAX(mContentArea.width -
-                     PR_MIN(mContentArea.width, floatAvailableSpace.XMost()),
+                     PR_MIN(mContentArea.width,
+                            floatAvailableSpace.mRect.XMost()),
                    replacedWidth.marginRight) <=
           mContentArea.width) {
         break;
       }
       // See the analogous code for inlines in nsBlockFrame::DoReflowInlineFrames
-      if (floatAvailableSpace.height > 0) {
+      if (floatAvailableSpace.mRect.height > 0) {
         // See if there's room in the next band.
-        newY += floatAvailableSpace.height;
+        newY += floatAvailableSpace.mRect.height;
       } else {
         if (mReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
           // Stop trying to clear here; we'll just get pushed to the
           // next column or page and try again there.
           break;
         }
         NS_NOTREACHED("avail space rect with zero height!");
         newY += 1;
--- a/layout/generic/nsBlockReflowState.h
+++ b/layout/generic/nsBlockReflowState.h
@@ -86,44 +86,43 @@ public:
    * 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.
    */
-  PRBool GetFloatAvailableSpace(nsRect& aResult) const
-    { return GetFloatAvailableSpace(mY, PR_FALSE, aResult); }
-  PRBool GetFloatAvailableSpace(nscoord aY, PRBool aRelaxHeightConstraint,
-                                nsRect& aResult) const
+  nsFlowAreaRect GetFloatAvailableSpace() const
+    { return GetFloatAvailableSpace(mY, PR_FALSE); }
+  nsFlowAreaRect GetFloatAvailableSpace(nscoord aY,
+                                        PRBool aRelaxHeightConstraint) const
     { return GetFloatAvailableSpaceWithState(aY, aRelaxHeightConstraint,
-                                             nsnull, aResult); }
-  PRBool GetFloatAvailableSpaceWithState(nscoord aY,
-                                         PRBool aRelaxHeightConstraint,
-                                         nsFloatManager::SavedState *aState,
-                                         nsRect& aResult) const;
+                                             nsnull); }
+  nsFlowAreaRect
+    GetFloatAvailableSpaceWithState(nscoord aY, PRBool aRelaxHeightConstraint,
+                                    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 InitFloat(nsLineLayout&       aLineLayout,
                    nsPlaceholderFrame* aPlaceholderFrame,
                    nscoord             aAvailableWidth,
                    nsReflowStatus&     aReflowStatus);
   PRBool AddFloat(nsLineLayout&       aLineLayout,
                   nsPlaceholderFrame* aPlaceholderFrame,
                   PRBool              aInitialReflow,
                   nscoord             aAvailableWidth,
                   nsReflowStatus&     aReflowStatus);
   PRBool CanPlaceFloat(const nsSize& aFloatSize, PRUint8 aFloats,
-                       const nsRect& aFloatAvailableSpace,
-                       PRBool aBandHasFloats, PRBool aForceFit);
+                       const nsFlowAreaRect& aFloatAvailableSpace,
+                       PRBool aForceFit);
   PRBool FlowAndPlaceFloat(nsFloatCache*   aFloatCache,
                            PRBool*         aIsLeftFloat,
                            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
@@ -167,18 +166,17 @@ public:
                                             nscoord& aLeftResult,
                                             nscoord& aRightResult,
                                        nsBlockFrame::ReplacedElementWidthToClear
                                                       *aReplacedWidth = nsnull);
 
   // Caller must have called GetAvailableSpace for the current mY
   void ComputeBlockAvailSpace(nsIFrame* aFrame,
                               const nsStyleDisplay* aDisplay,
-                              PRBool aBandHasFloats,
-                              const nsRect& aFloatAvailableSpace,
+                              const nsFlowAreaRect& aFloatAvailableSpace,
                               PRBool aBlockAvoidsFloats,
                               nsRect& aResult);
 
 protected:
   void RecoverFloats(nsLineList::iterator aLine, nscoord aDeltaY);
 
 public:
   void RecoverStateFrom(nsLineList::iterator aLine, nscoord aDeltaY);
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -130,22 +130,21 @@ void nsFloatManager::Shutdown()
     if (floatManager)
       nsMemory::Free(floatManager);
   }
 
   // Disable further caching.
   sCachedFloatManagerCount = -1;
 }
 
-nsRect
+nsFlowAreaRect
 nsFloatManager::GetBand(nscoord aYOffset,
                         nscoord aMaxHeight,
                         nscoord aContentAreaWidth,
-                        SavedState* aState,
-                        PRBool* aHasFloats) const
+                        SavedState* aState) const
 {
   NS_ASSERTION(aMaxHeight >= 0, "unexpected max height");
   NS_ASSERTION(aContentAreaWidth >= 0, "unexpected content area width");
 
   nscoord top = aYOffset + mY;
   if (top < nscoord_MIN) {
     NS_WARNING("bad value");
     top = nscoord_MIN;
@@ -162,18 +161,17 @@ nsFloatManager::GetBand(nscoord aYOffset
     floatCount = mFloats.Length();
   }
 
   // If there are no floats at all, or we're below the last one, return
   // quickly.
   if (floatCount == 0 ||
       (mFloats[floatCount-1].mLeftYMost <= top &&
        mFloats[floatCount-1].mRightYMost <= top)) {
-    *aHasFloats = PR_FALSE;
-    return nsRect(0, aYOffset, aContentAreaWidth, aMaxHeight);
+    return nsFlowAreaRect(0, aYOffset, aContentAreaWidth, aMaxHeight, PR_FALSE);
   }
 
   nscoord bottom;
   if (aMaxHeight == nscoord_MAX) {
     bottom = nscoord_MAX;
   } else {
     bottom = top + aMaxHeight;
     if (bottom < top || bottom > nscoord_MAX) {
@@ -236,19 +234,18 @@ nsFloatManager::GetBand(nscoord aYOffset
           right = leftEdge;
           // See above.
           haveFloats = PR_TRUE;
         }
       }
     }
   }
 
-  *aHasFloats = haveFloats;
   nscoord height = (bottom == nscoord_MAX) ? nscoord_MAX : (bottom - top);
-  return nsRect(left - mX, top - mY, right - left, height);
+  return nsFlowAreaRect(left - mX, top - mY, right - left, height, haveFloats);
 }
 
 nsresult
 nsFloatManager::AddFloat(nsIFrame* aFloatFrame, const nsRect& aMarginRect)
 {
   NS_ASSERTION(aMarginRect.width >= 0, "negative width!");
   NS_ASSERTION(aMarginRect.height >= 0, "negative height!");
 
--- a/layout/generic/nsFloatManager.h
+++ b/layout/generic/nsFloatManager.h
@@ -47,16 +47,32 @@
 #include "nsRect.h"
 #include "nsTArray.h"
 
 class nsIPresShell;
 class nsIFrame;
 struct nsHTMLReflowState;
 class nsPresContext;
 
+/**
+ * The available space for content not occupied by floats is divided
+ * into a (vertical) sequence of rectangles.  However, we need to know
+ * not only the rectangle, but also whether it was reduced (from the
+ * content rectangle) by floats that actually intruded into the content
+ * rectangle.
+ */
+struct nsFlowAreaRect {
+  nsRect mRect;
+  PRPackedBool mHasFloats;
+
+  nsFlowAreaRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight,
+                 PRBool aHasFloats)
+    : mRect(aX, aY, aWidth, aHeight), mHasFloats(aHasFloats) {}
+};
+
 #define NS_FLOAT_MANAGER_CACHE_SIZE 4
 
 class nsFloatManager {
 public:
   nsFloatManager(nsIPresShell* aPresShell);
   ~nsFloatManager();
 
   void* operator new(size_t aSize) CPP_THROW_NEW;
@@ -102,28 +118,28 @@ public:
    * @param aY [in] vertical coordinate for top of available space
    *           desired
    * @param aMaxHeight [in] maximum height of available space desired
    * @param aContentAreaWidth [in] the width of the content area (whose left
    *                          edge must be zero in the current translation)
    * @param aState [in] If null, use the current state, otherwise, do
    *                    computation based only on floats present in the given
    *                    saved state.
-   * @param aHasFloats [out] whether there are floats at the sides of
-   *                    the return value including those that do not
-   *                    reduce the line box width at all (because they
-   *                    are entirely in the margins)
-   * @return the resulting rectangle for line boxes.  It will not go
-   *         left of 0, nor right of aContentAreaWidth, but will be
-   *         narrower when floats are present.
+   * @return An nsFlowAreaRect whose:
+   *           mRect is the resulting rectangle for line boxes.  It will not go
+   *             left of 0, nor right of aContentAreaWidth, but will be
+   *             narrower when floats are present.
+   *          mBandHasFloats is whether there are floats at the sides of the
+   *            return value including those that do not reduce the line box
+   *            width at all (because they are entirely in the margins)
    *
    * aY and aAvailSpace are positioned relative to the current translation
    */
-  nsRect GetBand(nscoord aY, nscoord aMaxHeight, nscoord aContentAreaWidth,
-                 SavedState* aState, PRBool* aHasFloats) const;
+  nsFlowAreaRect GetBand(nscoord aY, nscoord aMaxHeight,
+                         nscoord aContentAreaWidth, SavedState* aState) const;
 
   /**
    * Add a float that comes after all floats previously added.  Its top
    * must be even with or below the top of all previous floats.
    *
    * aMarginRect is relative to the current translation.  The caller
    * must ensure aMarginRect.height >= 0 and aMarginRect.width >= 0.
    */