Bug 383883: {inc} issues with block moving through non-moving float. r+sr+a=dbaron

This commit is contained in:
sharparrow1@yahoo.com 2007-08-20 13:07:50 -07:00
parent 20b0394d68
commit ded759b0cc
5 changed files with 80 additions and 112 deletions

View File

@ -1577,10 +1577,17 @@ nsBlockFrame::PropagateFloatDamage(nsBlockReflowState& aState,
nsLineBox* aLine,
nscoord aDeltaY)
{
NS_PRECONDITION(!aLine->IsDirty(), "should never be called on dirty lines");
nsSpaceManager *spaceManager = aState.mReflowState.mSpaceManager;
NS_ASSERTION((aState.mReflowState.parentReflowState &&
aState.mReflowState.parentReflowState->mSpaceManager == spaceManager) ||
aState.mReflowState.mBlockDelta == 0, "Bad block delta passed in");
// Check to see if there are any floats; if there aren't, there can't
// be any float damage
if (!spaceManager->HasAnyFloats())
return;
// Check the damage region recorded in the float damage.
nsSpaceManager *spaceManager = aState.mReflowState.mSpaceManager;
if (spaceManager->HasFloatDamage()) {
nscoord lineYA = aLine->mBounds.y + aDeltaY;
nscoord lineYB = lineYA + aLine->mBounds.height;
@ -1590,39 +1597,32 @@ nsBlockFrame::PropagateFloatDamage(nsBlockReflowState& aState,
}
}
if (aDeltaY) {
// Cases we need to find:
//
// 1. the line was impacted by a float and now isn't
// 2. the line wasn't impacted by a float and now is
// 3. the line is impacted by a float both before and after and
// the float has changed position relative to the line (or it's
// a different float). (XXXPerf we don't currently
// check whether the float changed size. We currently just
// mark blocks dirty and ignore any possibility of damage to
// inlines by it being a different float with a different
// size.)
//
// XXXPerf: An optimization: if the line was and is completely
// impacted by a float and the float hasn't changed size,
// then we don't need to mark the line dirty.
aState.GetAvailableSpace(aLine->mBounds.y + aDeltaY, PR_FALSE);
PRBool wasImpactedByFloat = aLine->IsImpactedByFloat();
PRBool isImpactedByFloat = aState.IsImpactedByFloat();
// Check if the line is moving relative to the space manager
if (aDeltaY + aState.mReflowState.mBlockDelta != 0) {
if (aLine->IsBlock()) {
// Unconditionally reflow sliding blocks; we only really need to reflow
// if there's a float impacting this block, but the current space 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
aState.GetAvailableSpace(aLine->mBounds.y + aDeltaY, PR_FALSE);
PRBool wasImpactedByFloat = aLine->IsImpactedByFloat();
PRBool isImpactedByFloat = aState.IsImpactedByFloat();
#ifdef REALLY_NOISY_REFLOW
printf("nsBlockFrame::PropagateFloatDamage %p was = %d, is=%d\n",
this, wasImpactedByFloat, isImpactedByFloat);
#endif
// Mark the line dirty if:
// 1. It used to be impacted by a float and now isn't, or vice
// versa.
// 2. It is impacted by a float and it is a block, which means
// that more or less of the line could be impacted than was in
// the past. (XXXPerf This could be optimized further, since
// we're marking the whole line dirty.)
if ((wasImpactedByFloat != isImpactedByFloat) ||
(isImpactedByFloat && aLine->IsBlock())) {
aLine->MarkDirty();
// 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) {
aLine->MarkDirty();
}
}
}
}
@ -2919,7 +2919,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
nsReflowStatus frameReflowStatus = NS_FRAME_COMPLETE;
rv = brc.ReflowBlock(availSpace, applyTopMargin, aState.mPrevBottomMargin,
clearance, aState.IsAdjacentWithTop(), computedOffsets,
blockHtmlRS, frameReflowStatus);
aLine.get(), blockHtmlRS, frameReflowStatus);
// If this was a second-pass reflow and the block's vertical position
// changed, invalidates from the first pass might have happened in the
@ -5484,7 +5484,7 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
// on a frame property anyawy
rv = brc.ReflowBlock(availSpace, PR_TRUE, margin,
0, isAdjacentWithTop,
offsets, floatRS,
offsets, nsnull, floatRS,
aReflowStatus);
} while (NS_SUCCEEDED(rv) && clearanceFrame);
@ -5526,7 +5526,7 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
}
// Capture the margin information for the caller
const nsMargin& m = brc.GetMargin();
const nsMargin& m = floatRS.mComputedMargin;
aFloatMargin.top = brc.GetTopMargin();
aFloatMargin.right = m.right;
// Only last in flows get a bottom margin

View File

@ -72,9 +72,6 @@ nsBlockReflowContext::nsBlockReflowContext(nsPresContext* aPresContext,
mOuterReflowState(aParentRS),
mMetrics()
{
mStyleBorder = nsnull;
mStyleMargin = nsnull;
mStylePadding = nsnull;
}
static nsIFrame* DescendIntoBlockLevelFrame(nsIFrame* aFrame)
@ -251,6 +248,7 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
nscoord aClearance,
PRBool aIsAdjacentWithTop,
nsMargin& aComputedOffsets,
nsLineBox* aLine,
nsHTMLReflowState& aFrameRS,
nsReflowStatus& aFrameReflowStatus)
{
@ -280,7 +278,6 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
if (!aIsAdjacentWithTop) {
aFrameRS.mFlags.mIsTopOfPage = PR_FALSE; // make sure this is cleared
}
mComputedWidth = aFrameRS.ComputedWidth();
if (aApplyTopMargin) {
mTopMargin = aPrevMargin;
@ -299,68 +296,39 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
}
}
// Compute x/y coordinate where reflow will begin. Use the rules
// from 10.3.3 to determine what to apply. At this point in the
// reflow auto left/right margins will have a zero value.
mMargin = aFrameRS.mComputedMargin;
mStyleBorder = aFrameRS.mStyleBorder;
mStyleMargin = aFrameRS.mStyleMargin;
mStylePadding = aFrameRS.mStylePadding;
nscoord x;
nscoord y = mSpace.y + mTopMargin.get() + aClearance;
nscoord tx = 0, ty = 0;
// The values of x and y do not matter for floats, so don't bother calculating
// them. Floats are guaranteed to have their own space manager, so tx and ty
// don't matter. mX and mY don't matter becacuse they are only used in
// PlaceBlock, which is not used for floats.
if (aLine) {
// Compute x/y coordinate where reflow will begin. Use the rules
// from 10.3.3 to determine what to apply. At this point in the
// reflow auto left/right margins will have a zero value.
// If it's a right floated element, then calculate the x-offset
// differently
if (NS_STYLE_FLOAT_RIGHT == aFrameRS.mStyleDisplay->mFloats) {
nscoord frameWidth;
if (NS_UNCONSTRAINEDSIZE == aFrameRS.ComputedWidth()) {
// Use the current frame width
frameWidth = mFrame->GetSize().width;
} else {
frameWidth = aFrameRS.ComputedWidth() +
aFrameRS.mComputedBorderPadding.left +
aFrameRS.mComputedBorderPadding.right;
}
nscoord x = mSpace.x + aFrameRS.mComputedMargin.left;
nscoord y = mSpace.y + mTopMargin.get() + aClearance;
// if this is an unconstrained width reflow, then just place the float at the left margin
if (NS_UNCONSTRAINEDSIZE == mSpace.width)
x = mSpace.x;
else
x = mSpace.XMost() - mMargin.right - frameWidth;
if ((mFrame->GetStateBits() & NS_BLOCK_SPACE_MGR) == 0)
aFrameRS.mBlockDelta = mOuterReflowState.mBlockDelta + y - aLine->mBounds.y;
} else {
x = mSpace.x + mMargin.left;
}
mX = x;
mY = y;
mX = x;
mY = y;
// Compute the translation to be used for adjusting the spacemanagager
// coordinate system for the frame. The spacemanager coordinates are
// <b>inside</b> the callers border+padding, but the x/y coordinates
// are not (recall that frame coordinates are relative to the parents
// origin and that the parents border/padding is <b>inside</b> the
// parent frame. Therefore we have to subtract out the parents
// border+padding before translating.
nscoord tx = x - mOuterReflowState.mComputedBorderPadding.left;
nscoord ty = y - mOuterReflowState.mComputedBorderPadding.top;
// If the element is relatively positioned, then adjust x and y accordingly
if (NS_STYLE_POSITION_RELATIVE == aFrameRS.mStyleDisplay->mPosition) {
x += aFrameRS.mComputedOffsets.left;
y += aFrameRS.mComputedOffsets.top;
// Compute the translation to be used for adjusting the spacemanagager
// coordinate system for the frame. The spacemanager coordinates are
// <b>inside</b> the callers border+padding, but the x/y coordinates
// are not (recall that frame coordinates are relative to the parents
// origin and that the parents border/padding is <b>inside</b> the
// parent frame. Therefore we have to subtract out the parents
// border+padding before translating.
tx = x - mOuterReflowState.mComputedBorderPadding.left;
ty = y - mOuterReflowState.mComputedBorderPadding.top;
}
// Let frame know that we are reflowing it
mFrame->WillReflow(mPresContext);
// Position it and its view (if it has one)
// Note: Use "x" and "y" and not "mX" and "mY" because they more accurately
// represents where we think the block will be placed
// XXXldb That's fine for view positioning, but not for reflow!
mFrame->SetPosition(nsPoint(x, y));
nsContainerFrame::PositionFrameView(mFrame);
#ifdef DEBUG
mMetrics.width = nscoord(0xdeadbeef);
mMetrics.height = nscoord(0xdeadbeef);
@ -436,7 +404,7 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
// Compute collapsed bottom margin value.
if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
aBottomMarginResult = mMetrics.mCarriedOutBottomMargin;
aBottomMarginResult.Include(mMargin.bottom);
aBottomMarginResult.Include(aReflowState.mComputedMargin.bottom);
} else {
// The used bottom-margin is set to zero above a break.
aBottomMarginResult.Zero();

View File

@ -69,6 +69,7 @@ public:
nscoord aClearance,
PRBool aIsAdjacentWithTop,
nsMargin& aComputedOffsets,
nsLineBox* aLine,
nsHTMLReflowState& aReflowState,
nsReflowStatus& aReflowStatus);
@ -89,10 +90,6 @@ public:
return mTopMargin.get();
}
const nsMargin& GetMargin() const {
return mMargin;
}
const nsHTMLReflowMetrics& GetMetrics() const {
return mMetrics;
}
@ -122,13 +119,6 @@ protected:
nsIFrame* mFrame;
nsRect mSpace;
// Spacing style for the frame we are reflowing; only valid after reflow
const nsStyleBorder* mStyleBorder;
const nsStyleMargin* mStyleMargin;
const nsStylePadding* mStylePadding;
nscoord mComputedWidth; // copy of reflowstate's computedWidth
nsMargin mMargin;
nscoord mX, mY;
nsHTMLReflowMetrics mMetrics;
nsCollapsingMargin mTopMargin;

View File

@ -90,6 +90,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
const nsSize& aAvailableSpace)
: nsCSSOffsetState(aFrame, aRenderingContext)
, mReflowDepth(0)
, mBlockDelta(0)
{
NS_PRECONDITION(aPresContext, "no pres context");
NS_PRECONDITION(aRenderingContext, "no rendering context");
@ -134,6 +135,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
: nsCSSOffsetState(aFrame, aParentReflowState.rendContext)
, mReflowDepth(aParentReflowState.mReflowDepth + 1)
, mFlags(aParentReflowState.mFlags)
, mBlockDelta(0)
{
NS_PRECONDITION(aPresContext, "no pres context");
NS_PRECONDITION(aFrame, "no frame");

View File

@ -168,10 +168,6 @@ public:
InitOffsets(aContainingBlockWidth);
}
void InitOffsets(nscoord aContainingBlockWidth,
const nsMargin *aBorder = nsnull,
const nsMargin *aPadding = nsnull);
// Destructor for usedPaddingProperty
static void DestroyMarginFunc(void* aFrame,
nsIAtom* aPropertyName,
@ -189,6 +185,10 @@ private:
protected:
void InitOffsets(nscoord aContainingBlockWidth,
const nsMargin *aBorder = nsnull,
const nsMargin *aPadding = nsnull);
/*
* Convert nsStyleCoord to nscoord when percentages depend on the
* containing block width.
@ -260,6 +260,16 @@ struct nsHTMLReflowState : public nsCSSOffsetState {
// pointer to the space manager associated with this area
nsSpaceManager* mSpaceManager;
// The amount the in-flow position of the block is moving vertically relative
// to its previous in-flow position (i.e. the amount the line containing the
// block is moving).
// This should be zero for anything which is not a block outside, and it
// should be zero for anything which has a non-block parent.
// The intended use of this value is to allow the accurate determination
// of the potential impact of a float
// This takes on an arbitrary value the first time a block is reflowed
nscoord mBlockDelta;
// LineLayout object (only for inline reflow; set to NULL otherwise)
nsLineLayout* mLineLayout;
@ -416,16 +426,12 @@ public:
static nscoord CalcLineHeight(nsStyleContext* aStyleContext,
nsIDeviceContext* aDeviceContext);
void InitFrameType();
void ComputeContainingBlockRectangle(nsPresContext* aPresContext,
const nsHTMLReflowState* aContainingBlockRS,
nscoord& aContainingBlockWidth,
nscoord& aContainingBlockHeight);
void CalculateBlockSideMargins(nscoord aAvailWidth,
nscoord aComputedWidth);
/**
* Apply the mComputed(Min/Max)(Width/Height) values to the content
* size computed so far. If a passed-in pointer is null, we skip
@ -457,7 +463,7 @@ public:
void SetTruncated(const nsHTMLReflowMetrics& aMetrics, nsReflowStatus* aStatus) const;
protected:
void InitFrameType();
void InitCBReflowState();
void InitResizeFlags(nsPresContext* aPresContext);
@ -501,6 +507,8 @@ protected:
nscoord* aInsideBoxSizing,
nscoord* aOutsideBoxSizing);
void CalculateBlockSideMargins(nscoord aAvailWidth,
nscoord aComputedWidth);
};
#endif /* nsHTMLReflowState_h___ */