Fix abs.pos. shrink-to-fit regressions. b=201897 (rubber-stamp) r=bzbarsky sr=dbaron

This commit is contained in:
mats.palmgren@bredband.net
2004-12-06 00:27:21 +00:00
parent ce3da71b14
commit 6d4641becb
2 changed files with 88 additions and 40 deletions

View File

@@ -539,7 +539,7 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
} }
nscoord availWidth = aReflowState.mComputedWidth; nscoord availWidth = aReflowState.mComputedWidth;
enum { NOT_SHRINK_TO_FIT, SHRINK_TO_FIT_UNCONSTRAINED, SHRINK_TO_FIT_CONSTRAINED }; enum { NOT_SHRINK_TO_FIT, SHRINK_TO_FIT_AVAILWIDTH, SHRINK_TO_FIT_MEW };
PRUint32 situation = NOT_SHRINK_TO_FIT; PRUint32 situation = NOT_SHRINK_TO_FIT;
while (1) { while (1) {
nsHTMLReflowMetrics kidDesiredSize(nsnull); nsHTMLReflowMetrics kidDesiredSize(nsnull);
@@ -549,8 +549,12 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
if (eStyleUnit_Auto == stylePosition->mWidth.GetUnit() && if (eStyleUnit_Auto == stylePosition->mWidth.GetUnit() &&
(eStyleUnit_Auto == stylePosition->mOffset.GetLeftUnit() || (eStyleUnit_Auto == stylePosition->mOffset.GetLeftUnit() ||
eStyleUnit_Auto == stylePosition->mOffset.GetRightUnit())) { eStyleUnit_Auto == stylePosition->mOffset.GetRightUnit())) {
situation = SHRINK_TO_FIT_UNCONSTRAINED; situation = SHRINK_TO_FIT_AVAILWIDTH;
availWidth = NS_UNCONSTRAINEDSIZE; // first reflow is unconstrained if (aContainingBlockWidth != -1) {
availWidth = aContainingBlockWidth;
} else {
availWidth = aReflowState.mComputedWidth;
}
kidDesiredSize.mComputeMEW = PR_TRUE; kidDesiredSize.mComputeMEW = PR_TRUE;
} }
} }
@@ -561,6 +565,33 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
aContainingBlockHeight, aContainingBlockHeight,
aReason); aReason);
if (situation == SHRINK_TO_FIT_MEW) {
situation = NOT_SHRINK_TO_FIT; // This is the last reflow
kidReflowState.mComputedWidth = PR_MIN(availWidth, kidReflowState.mComputedMaxWidth);
if (kidReflowState.mComputedWidth < kidReflowState.mComputedMinWidth) {
kidReflowState.mComputedWidth = kidReflowState.mComputedMinWidth;
}
} else if (NS_UNCONSTRAINEDSIZE != availWidth) {
if (aContainingBlockWidth != -1) {
availWidth = aContainingBlockWidth;
} else {
availWidth = aReflowState.mComputedWidth;
}
PRInt32 maxWidth = availWidth -
(kidReflowState.mComputedMargin.left + kidReflowState.mComputedBorderPadding.left +
kidReflowState.mComputedBorderPadding.right + kidReflowState.mComputedMargin.right);
if (NS_AUTOOFFSET != kidReflowState.mComputedOffsets.right) {
maxWidth -= kidReflowState.mComputedOffsets.right;
}
if (NS_AUTOOFFSET != kidReflowState.mComputedOffsets.left) {
maxWidth -= kidReflowState.mComputedOffsets.left;
}
// The following also takes care of maxWidth<0
if (kidReflowState.mComputedMaxWidth > maxWidth) {
kidReflowState.mComputedMaxWidth = PR_MAX(maxWidth, kidReflowState.mComputedMinWidth);
}
}
// Send the WillReflow() notification and position the frame // Send the WillReflow() notification and position the frame
aKidFrame->WillReflow(aPresContext); aKidFrame->WillReflow(aPresContext);
@@ -586,17 +617,9 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
// Do the reflow // Do the reflow
rv = aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus); rv = aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus);
if (situation == SHRINK_TO_FIT_UNCONSTRAINED) { if (situation == SHRINK_TO_FIT_AVAILWIDTH) {
// ...continued CSS2.1 10.3.7 width:auto and at least one of left/right is auto // ...continued CSS2.1 10.3.7 width:auto and at least one of left/right is auto
if (aContainingBlockWidth == -1) { availWidth -= kidReflowState.mComputedMargin.left + kidReflowState.mComputedMargin.right;
kidReflowState.ComputeContainingBlockRectangle(aPresContext,
&aReflowState,
aContainingBlockWidth,
aContainingBlockHeight);
}
availWidth = aContainingBlockWidth -
kidReflowState.mComputedMargin.left -
kidReflowState.mComputedMargin.right;
if (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.right) { if (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.right) {
NS_ASSERTION(NS_AUTOOFFSET != kidReflowState.mComputedOffsets.left, NS_ASSERTION(NS_AUTOOFFSET != kidReflowState.mComputedOffsets.left,
@@ -611,16 +634,17 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
availWidth = 0; availWidth = 0;
} }
aKidFrame->DidReflow(aPresContext, &kidReflowState, NS_FRAME_REFLOW_FINISHED);
// Shrink-to-fit: min(max(preferred minimum width, available width), preferred width). // Shrink-to-fit: min(max(preferred minimum width, available width), preferred width).
// XXX this is not completely correct - see bug 201897 comment 56/58 and bug 268499.
if (kidDesiredSize.mMaxElementWidth > availWidth) { if (kidDesiredSize.mMaxElementWidth > availWidth) {
availWidth = kidDesiredSize.mMaxElementWidth; aKidFrame->DidReflow(aPresContext, &kidReflowState, NS_FRAME_REFLOW_FINISHED);
} else if (kidDesiredSize.width < availWidth) { availWidth = PR_MAX(0, kidDesiredSize.mMaxElementWidth -
availWidth = kidDesiredSize.width; kidReflowState.mComputedBorderPadding.left -
kidReflowState.mComputedBorderPadding.right);
situation = SHRINK_TO_FIT_MEW;
aReason = eReflowReason_Resize;
continue; // Do a second reflow constrained to MEW.
} }
situation = SHRINK_TO_FIT_CONSTRAINED;
continue; // do a second reflow (constrained this time)
} }
// If we're solving for 'left' or 'top', then compute it now that we know the // If we're solving for 'left' or 'top', then compute it now that we know the

View File

@@ -539,7 +539,7 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
} }
nscoord availWidth = aReflowState.mComputedWidth; nscoord availWidth = aReflowState.mComputedWidth;
enum { NOT_SHRINK_TO_FIT, SHRINK_TO_FIT_UNCONSTRAINED, SHRINK_TO_FIT_CONSTRAINED }; enum { NOT_SHRINK_TO_FIT, SHRINK_TO_FIT_AVAILWIDTH, SHRINK_TO_FIT_MEW };
PRUint32 situation = NOT_SHRINK_TO_FIT; PRUint32 situation = NOT_SHRINK_TO_FIT;
while (1) { while (1) {
nsHTMLReflowMetrics kidDesiredSize(nsnull); nsHTMLReflowMetrics kidDesiredSize(nsnull);
@@ -549,8 +549,12 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
if (eStyleUnit_Auto == stylePosition->mWidth.GetUnit() && if (eStyleUnit_Auto == stylePosition->mWidth.GetUnit() &&
(eStyleUnit_Auto == stylePosition->mOffset.GetLeftUnit() || (eStyleUnit_Auto == stylePosition->mOffset.GetLeftUnit() ||
eStyleUnit_Auto == stylePosition->mOffset.GetRightUnit())) { eStyleUnit_Auto == stylePosition->mOffset.GetRightUnit())) {
situation = SHRINK_TO_FIT_UNCONSTRAINED; situation = SHRINK_TO_FIT_AVAILWIDTH;
availWidth = NS_UNCONSTRAINEDSIZE; // first reflow is unconstrained if (aContainingBlockWidth != -1) {
availWidth = aContainingBlockWidth;
} else {
availWidth = aReflowState.mComputedWidth;
}
kidDesiredSize.mComputeMEW = PR_TRUE; kidDesiredSize.mComputeMEW = PR_TRUE;
} }
} }
@@ -561,6 +565,33 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
aContainingBlockHeight, aContainingBlockHeight,
aReason); aReason);
if (situation == SHRINK_TO_FIT_MEW) {
situation = NOT_SHRINK_TO_FIT; // This is the last reflow
kidReflowState.mComputedWidth = PR_MIN(availWidth, kidReflowState.mComputedMaxWidth);
if (kidReflowState.mComputedWidth < kidReflowState.mComputedMinWidth) {
kidReflowState.mComputedWidth = kidReflowState.mComputedMinWidth;
}
} else if (NS_UNCONSTRAINEDSIZE != availWidth) {
if (aContainingBlockWidth != -1) {
availWidth = aContainingBlockWidth;
} else {
availWidth = aReflowState.mComputedWidth;
}
PRInt32 maxWidth = availWidth -
(kidReflowState.mComputedMargin.left + kidReflowState.mComputedBorderPadding.left +
kidReflowState.mComputedBorderPadding.right + kidReflowState.mComputedMargin.right);
if (NS_AUTOOFFSET != kidReflowState.mComputedOffsets.right) {
maxWidth -= kidReflowState.mComputedOffsets.right;
}
if (NS_AUTOOFFSET != kidReflowState.mComputedOffsets.left) {
maxWidth -= kidReflowState.mComputedOffsets.left;
}
// The following also takes care of maxWidth<0
if (kidReflowState.mComputedMaxWidth > maxWidth) {
kidReflowState.mComputedMaxWidth = PR_MAX(maxWidth, kidReflowState.mComputedMinWidth);
}
}
// Send the WillReflow() notification and position the frame // Send the WillReflow() notification and position the frame
aKidFrame->WillReflow(aPresContext); aKidFrame->WillReflow(aPresContext);
@@ -586,17 +617,9 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
// Do the reflow // Do the reflow
rv = aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus); rv = aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus);
if (situation == SHRINK_TO_FIT_UNCONSTRAINED) { if (situation == SHRINK_TO_FIT_AVAILWIDTH) {
// ...continued CSS2.1 10.3.7 width:auto and at least one of left/right is auto // ...continued CSS2.1 10.3.7 width:auto and at least one of left/right is auto
if (aContainingBlockWidth == -1) { availWidth -= kidReflowState.mComputedMargin.left + kidReflowState.mComputedMargin.right;
kidReflowState.ComputeContainingBlockRectangle(aPresContext,
&aReflowState,
aContainingBlockWidth,
aContainingBlockHeight);
}
availWidth = aContainingBlockWidth -
kidReflowState.mComputedMargin.left -
kidReflowState.mComputedMargin.right;
if (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.right) { if (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.right) {
NS_ASSERTION(NS_AUTOOFFSET != kidReflowState.mComputedOffsets.left, NS_ASSERTION(NS_AUTOOFFSET != kidReflowState.mComputedOffsets.left,
@@ -611,16 +634,17 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
availWidth = 0; availWidth = 0;
} }
aKidFrame->DidReflow(aPresContext, &kidReflowState, NS_FRAME_REFLOW_FINISHED);
// Shrink-to-fit: min(max(preferred minimum width, available width), preferred width). // Shrink-to-fit: min(max(preferred minimum width, available width), preferred width).
// XXX this is not completely correct - see bug 201897 comment 56/58 and bug 268499.
if (kidDesiredSize.mMaxElementWidth > availWidth) { if (kidDesiredSize.mMaxElementWidth > availWidth) {
availWidth = kidDesiredSize.mMaxElementWidth; aKidFrame->DidReflow(aPresContext, &kidReflowState, NS_FRAME_REFLOW_FINISHED);
} else if (kidDesiredSize.width < availWidth) { availWidth = PR_MAX(0, kidDesiredSize.mMaxElementWidth -
availWidth = kidDesiredSize.width; kidReflowState.mComputedBorderPadding.left -
kidReflowState.mComputedBorderPadding.right);
situation = SHRINK_TO_FIT_MEW;
aReason = eReflowReason_Resize;
continue; // Do a second reflow constrained to MEW.
} }
situation = SHRINK_TO_FIT_CONSTRAINED;
continue; // do a second reflow (constrained this time)
} }
// If we're solving for 'left' or 'top', then compute it now that we know the // If we're solving for 'left' or 'top', then compute it now that we know the