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.".
This commit is contained in:
L. David Baron 2010-08-05 21:59:18 -07:00
Родитель 4011b9b81d
Коммит 71c39670d6
3 изменённых файлов: 63 добавлений и 41 удалений

Просмотреть файл

@ -5576,7 +5576,7 @@ nsBlockFrame::ComputeFloatWidth(nsBlockReflowState& aState,
nsresult nsresult
nsBlockFrame::ReflowFloat(nsBlockReflowState& aState, nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace, const nsRect& aAdjustedAvailableSpace,
nsIFrame* aFloat, nsIFrame* aFloat,
nsMargin& aFloatMargin, nsMargin& aFloatMargin,
nsReflowStatus& aReflowStatus) nsReflowStatus& aReflowStatus)
@ -5594,11 +5594,9 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
); );
#endif #endif
nsRect availSpace = AdjustFloatAvailableSpace(aState, aFloatAvailableSpace,
aFloat);
nsHTMLReflowState floatRS(aState.mPresContext, aState.mReflowState, 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. // Setup a block reflow state to reflow the float.
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState); 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, 0, isAdjacentWithTop,
nsnull, floatRS, nsnull, floatRS,
aReflowStatus, aState); aReflowStatus, aState);
@ -5633,7 +5631,7 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
// An incomplete reflow status means we should split the float // An incomplete reflow status means we should split the float
// if the height is constrained (bug 145305). // if the height is constrained (bug 145305).
if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) && if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) &&
(NS_UNCONSTRAINEDSIZE == availSpace.height)) (NS_UNCONSTRAINEDSIZE == aAdjustedAvailableSpace.height))
aReflowStatus = NS_FRAME_COMPLETE; aReflowStatus = NS_FRAME_COMPLETE;
if (aReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW) { if (aReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW) {

Просмотреть файл

@ -582,8 +582,10 @@ protected:
nsIFrame* aFloat); nsIFrame* aFloat);
// An incomplete aReflowStatus indicates the float should be split // An incomplete aReflowStatus indicates the float should be split
// but only if the available height is constrained. // but only if the available height is constrained.
// aAdjustedAvailableSpace is the result of calling
// nsBlockFrame::AdjustFloatAvailableSpace.
nsresult ReflowFloat(nsBlockReflowState& aState, nsresult ReflowFloat(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace, const nsRect& aAdjustedAvailableSpace,
nsIFrame* aFloat, nsIFrame* aFloat,
nsMargin& aFloatMargin, nsMargin& aFloatMargin,
nsReflowStatus& aReflowStatus); nsReflowStatus& aReflowStatus);

Просмотреть файл

@ -636,6 +636,30 @@ nsBlockReflowState::CanPlaceFloat(nscoord aFloatWidth,
aFloatAvailableSpace.mRect.width >= 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 PRBool
nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat, nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat,
nsReflowStatus& aReflowStatus) nsReflowStatus& aReflowStatus)
@ -667,32 +691,18 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat,
} }
// Get the band of available space // Get the band of available space
nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(mY); nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(mY);
nsRect adjustedAvailableSpace = mBlock->AdjustFloatAvailableSpace(*this,
floatAvailableSpace.mRect, aFloat);
NS_ASSERTION(aFloat->GetParent() == mBlock, NS_ASSERTION(aFloat->GetParent() == mBlock,
"Float frame has wrong parent"); "Float frame has wrong parent");
// Reflow the float nsCSSOffsetState offsets(aFloat, mReflowState.rendContext,
nsMargin floatMargin; // computed margin mReflowState.ComputedWidth());
mBlock->ReflowFloat(*this, floatAvailableSpace.mRect, aFloat,
floatMargin, aReflowStatus);
if (aFloat->GetPrevInFlow())
floatMargin.top = 0;
if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus))
floatMargin.bottom = 0;
#ifdef DEBUG nscoord floatMarginWidth = FloatMarginWidth(mReflowState,
if (nsBlockFrame::gNoisyReflow) { adjustedAvailableSpace.width,
nsRect region = aFloat->GetRect(); aFloat, offsets);
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());
// Find a place to place the float. The CSS2 spec doesn't want // Find a place to place the float. The CSS2 spec doesn't want
// floats overlapping each other or sticking out of the containing // floats overlapping each other or sticking out of the containing
@ -711,7 +721,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat,
return PR_FALSE; return PR_FALSE;
} }
if (CanPlaceFloat(floatSize.width, floatAvailableSpace)) { if (CanPlaceFloat(floatMarginWidth, floatAvailableSpace)) {
// We found an appropriate place. // We found an appropriate place.
break; break;
} }
@ -721,9 +731,12 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat,
eCompatibility_NavQuirks != mPresContext->CompatibilityMode() ) { eCompatibility_NavQuirks != mPresContext->CompatibilityMode() ) {
mY += floatAvailableSpace.mRect.height; mY += floatAvailableSpace.mRect.height;
if (adjustedAvailableSpace.height != NS_UNCONSTRAINEDSIZE) {
adjustedAvailableSpace.height -= floatAvailableSpace.mRect.height;
}
floatAvailableSpace = GetFloatAvailableSpace(mY); floatAvailableSpace = GetFloatAvailableSpace(mY);
} else { } 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 // IE handles float tables in a very special way
// see if the previous float is also a table and has "align" // 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 // the table does not fit anymore in this line so advance to next band
mY += floatAvailableSpace.mRect.height; mY += floatAvailableSpace.mRect.height;
// To match nsBlockFrame::AdjustFloatAvailableSpace, we have to
// get a new width for the new band.
floatAvailableSpace = GetFloatAvailableSpace(mY); floatAvailableSpace = GetFloatAvailableSpace(mY);
// reflow the float again now since we have more space adjustedAvailableSpace = mBlock->AdjustFloatAvailableSpace(*this,
// XXXldb We really don't need to Reflow in a loop, we just need floatAvailableSpace.mRect, aFloat);
// to ComputeSize in a loop (once ComputeSize depends on floatMarginWidth = FloatMarginWidth(mReflowState,
// availableWidth, which should make this work again). adjustedAvailableSpace.width,
mBlock->ReflowFloat(*this, floatAvailableSpace.mRect, aFloat, aFloat, offsets);
floatMargin, aReflowStatus);
// Get the floats bounding box and margin information
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 // 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 // We don't worry about the geometry of the prev in flow, let the continuation
@ -787,7 +799,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat,
} }
else { else {
if (!keepFloatOnSameLine) { if (!keepFloatOnSameLine) {
floatX = floatAvailableSpace.mRect.XMost() - floatSize.width; floatX = floatAvailableSpace.mRect.XMost() - floatMarginWidth;
} }
else { else {
// this is the IE quirk (see few lines above) // this is the IE quirk (see few lines above)
@ -807,6 +819,16 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat,
floatY = 0; 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 // Calculate the actual origin of the float frame's border rect
// relative to the parent block; floatX/Y must be converted from space-manager // relative to the parent block; floatX/Y must be converted from space-manager
// coordinates to parent coordinates, and the margin must be added in // coordinates to parent coordinates, and the margin must be added in