From 71c39670d639e0eb6388c4c659ad6f64b688746d Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Thu, 5 Aug 2010 21:59:18 -0700 Subject: [PATCH] Make nsBlockReflowState::FlowAndPlaceFloat reflow the float after computing its vertical position, so we know how much height is actually available. (Bug 563584, patch 4) r=roc Test coverage for this is in the future patch "Add reftests for bug 563584.". --- layout/generic/nsBlockFrame.cpp | 12 ++-- layout/generic/nsBlockFrame.h | 4 +- layout/generic/nsBlockReflowState.cpp | 88 +++++++++++++++++---------- 3 files changed, 63 insertions(+), 41 deletions(-) diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index b533b997c68..5efb0cfa789 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -5576,7 +5576,7 @@ nsBlockFrame::ComputeFloatWidth(nsBlockReflowState& aState, nsresult nsBlockFrame::ReflowFloat(nsBlockReflowState& aState, - const nsRect& aFloatAvailableSpace, + const nsRect& aAdjustedAvailableSpace, nsIFrame* aFloat, nsMargin& aFloatMargin, nsReflowStatus& aReflowStatus) @@ -5594,11 +5594,9 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState, ); #endif - nsRect availSpace = AdjustFloatAvailableSpace(aState, aFloatAvailableSpace, - aFloat); - nsHTMLReflowState floatRS(aState.mPresContext, aState.mReflowState, aFloat, - nsSize(availSpace.width, availSpace.height)); + nsSize(aAdjustedAvailableSpace.width, + aAdjustedAvailableSpace.height)); // Setup a block reflow state to reflow the float. nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState); @@ -5624,7 +5622,7 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState, } } - rv = brc.ReflowBlock(availSpace, PR_TRUE, margin, + rv = brc.ReflowBlock(aAdjustedAvailableSpace, PR_TRUE, margin, 0, isAdjacentWithTop, nsnull, floatRS, aReflowStatus, aState); @@ -5633,7 +5631,7 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState, // An incomplete reflow status means we should split the float // if the height is constrained (bug 145305). if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) && - (NS_UNCONSTRAINEDSIZE == availSpace.height)) + (NS_UNCONSTRAINEDSIZE == aAdjustedAvailableSpace.height)) aReflowStatus = NS_FRAME_COMPLETE; if (aReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW) { diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h index 97cbfa77c34..149f1fde0bc 100644 --- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -582,8 +582,10 @@ protected: nsIFrame* aFloat); // An incomplete aReflowStatus indicates the float should be split // but only if the available height is constrained. + // aAdjustedAvailableSpace is the result of calling + // nsBlockFrame::AdjustFloatAvailableSpace. nsresult ReflowFloat(nsBlockReflowState& aState, - const nsRect& aFloatAvailableSpace, + const nsRect& aAdjustedAvailableSpace, nsIFrame* aFloat, nsMargin& aFloatMargin, nsReflowStatus& aReflowStatus); diff --git a/layout/generic/nsBlockReflowState.cpp b/layout/generic/nsBlockReflowState.cpp index 6fbb64afcc0..350616d38fd 100644 --- a/layout/generic/nsBlockReflowState.cpp +++ b/layout/generic/nsBlockReflowState.cpp @@ -636,6 +636,30 @@ nsBlockReflowState::CanPlaceFloat(nscoord aFloatWidth, aFloatAvailableSpace.mRect.width >= aFloatWidth; } +static nscoord +FloatMarginWidth(const nsHTMLReflowState& aCBReflowState, + nscoord aFloatAvailableWidth, + nsIFrame *aFloat, + const nsCSSOffsetState& aFloatOffsetState) +{ + return aFloat->ComputeSize( + aCBReflowState.rendContext, + nsSize(aCBReflowState.ComputedWidth(), + aCBReflowState.ComputedHeight()), + aFloatAvailableWidth, + nsSize(aFloatOffsetState.mComputedMargin.LeftRight(), + aFloatOffsetState.mComputedMargin.TopBottom()), + nsSize(aFloatOffsetState.mComputedBorderPadding.LeftRight() - + aFloatOffsetState.mComputedPadding.LeftRight(), + aFloatOffsetState.mComputedBorderPadding.TopBottom() - + aFloatOffsetState.mComputedPadding.TopBottom()), + nsSize(aFloatOffsetState.mComputedPadding.LeftRight(), + aFloatOffsetState.mComputedPadding.TopBottom()), + PR_TRUE).width + + aFloatOffsetState.mComputedMargin.LeftRight() + + aFloatOffsetState.mComputedBorderPadding.LeftRight(); +} + PRBool nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat, nsReflowStatus& aReflowStatus) @@ -667,32 +691,18 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat, } // Get the band of available space nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(mY); + nsRect adjustedAvailableSpace = mBlock->AdjustFloatAvailableSpace(*this, + floatAvailableSpace.mRect, aFloat); NS_ASSERTION(aFloat->GetParent() == mBlock, "Float frame has wrong parent"); - // Reflow the float - nsMargin floatMargin; // computed margin - mBlock->ReflowFloat(*this, floatAvailableSpace.mRect, aFloat, - floatMargin, aReflowStatus); - if (aFloat->GetPrevInFlow()) - floatMargin.top = 0; - if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus)) - floatMargin.bottom = 0; + nsCSSOffsetState offsets(aFloat, mReflowState.rendContext, + mReflowState.ComputedWidth()); -#ifdef DEBUG - if (nsBlockFrame::gNoisyReflow) { - nsRect region = aFloat->GetRect(); - nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent); - printf("flowed float: "); - nsFrame::ListTag(stdout, aFloat); - printf(" (%d,%d,%d,%d)\n", - region.x, region.y, region.width, region.height); - } -#endif - - nsSize floatSize = aFloat->GetSize() + - nsSize(floatMargin.LeftRight(), floatMargin.TopBottom()); + nscoord floatMarginWidth = FloatMarginWidth(mReflowState, + adjustedAvailableSpace.width, + aFloat, offsets); // Find a place to place the float. The CSS2 spec doesn't want // floats overlapping each other or sticking out of the containing @@ -711,7 +721,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat, return PR_FALSE; } - if (CanPlaceFloat(floatSize.width, floatAvailableSpace)) { + if (CanPlaceFloat(floatMarginWidth, floatAvailableSpace)) { // We found an appropriate place. break; } @@ -721,9 +731,12 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat, eCompatibility_NavQuirks != mPresContext->CompatibilityMode() ) { mY += floatAvailableSpace.mRect.height; + if (adjustedAvailableSpace.height != NS_UNCONSTRAINEDSIZE) { + adjustedAvailableSpace.height -= floatAvailableSpace.mRect.height; + } floatAvailableSpace = GetFloatAvailableSpace(mY); } else { - // This quirk matches the one in nsBlockFrame::ReflowFloat + // This quirk matches the one in nsBlockFrame::AdjustFloatAvailableSpace // IE handles float tables in a very special way // see if the previous float is also a table and has "align" @@ -760,18 +773,17 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat, // the table does not fit anymore in this line so advance to next band mY += floatAvailableSpace.mRect.height; + // To match nsBlockFrame::AdjustFloatAvailableSpace, we have to + // get a new width for the new band. floatAvailableSpace = GetFloatAvailableSpace(mY); - // 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, aFloat, - floatMargin, aReflowStatus); - // Get the floats bounding box and margin information - floatSize = aFloat->GetSize() + - nsSize(floatMargin.LeftRight(), floatMargin.TopBottom()); + adjustedAvailableSpace = mBlock->AdjustFloatAvailableSpace(*this, + floatAvailableSpace.mRect, aFloat); + floatMarginWidth = FloatMarginWidth(mReflowState, + adjustedAvailableSpace.width, + aFloat, offsets); } } + // 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 @@ -787,7 +799,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat, } else { if (!keepFloatOnSameLine) { - floatX = floatAvailableSpace.mRect.XMost() - floatSize.width; + floatX = floatAvailableSpace.mRect.XMost() - floatMarginWidth; } else { // this is the IE quirk (see few lines above) @@ -807,6 +819,16 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat, floatY = 0; } + // Reflow the float after computing its vertical position so it knows + // where to break. + nsMargin floatMargin; // computed margin + mBlock->ReflowFloat(*this, adjustedAvailableSpace, aFloat, + floatMargin, aReflowStatus); + if (aFloat->GetPrevInFlow()) + floatMargin.top = 0; + if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus)) + floatMargin.bottom = 0; + // 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