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
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) {

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

@ -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);

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

@ -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