From fe441abc3a887725984e6d9a98df383a68c7f9cc Mon Sep 17 00:00:00 2001 From: "roc+%cs.cmu.edu" Date: Tue, 24 Sep 2002 11:43:48 +0000 Subject: [PATCH] Bug 75121. Incrementally reflow absolute frames without doing a resize-reflow of the container. Patch by dbaron and roc. r=dbaron,r=roc,sr=kin git-svn-id: svn://10.0.0.236/trunk@130340 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/layout/base/nsPresShell.cpp | 19 +-- .../generic/nsAbsoluteContainingBlock.cpp | 28 +++-- .../generic/nsAbsoluteContainingBlock.h | 3 +- mozilla/layout/generic/nsBlockFrame.cpp | 108 +++++++++--------- mozilla/layout/generic/nsBlockFrame.h | 3 + mozilla/layout/generic/nsInlineFrame.cpp | 5 +- .../base/src/nsAbsoluteContainingBlock.cpp | 28 +++-- .../html/base/src/nsAbsoluteContainingBlock.h | 3 +- mozilla/layout/html/base/src/nsBlockFrame.cpp | 108 +++++++++--------- mozilla/layout/html/base/src/nsBlockFrame.h | 3 + .../layout/html/base/src/nsInlineFrame.cpp | 5 +- mozilla/layout/html/base/src/nsPresShell.cpp | 19 +-- 12 files changed, 180 insertions(+), 152 deletions(-) diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index 67b586370de..bb00138c142 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -3703,15 +3703,20 @@ PresShell::AlreadyInQueue(nsHTMLReflowCommand* aReflowCommand, aReflowCommand->GetType(RCType); rc->GetType(queuedRCType); if (targetFrame == targetOfQueuedRC && - RCType == queuedRCType) { + RCType == queuedRCType) { + nsCOMPtr CLName, queuedCLName; + aReflowCommand->GetChildListName(*getter_AddRefs(CLName)); + rc->GetChildListName(*getter_AddRefs(queuedCLName)); + if (CLName == queuedCLName) { #ifdef DEBUG - if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) { - printf("*** PresShell::AlreadyInQueue(): Discarding reflow command: this=%p\n", (void*)this); - aReflowCommand->List(stdout); - } + if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) { + printf("*** PresShell::AlreadyInQueue(): Discarding reflow command: this=%p\n", (void*)this); + aReflowCommand->List(stdout); + } #endif - inQueue = PR_TRUE; - break; + inQueue = PR_TRUE; + break; + } } } } diff --git a/mozilla/layout/generic/nsAbsoluteContainingBlock.cpp b/mozilla/layout/generic/nsAbsoluteContainingBlock.cpp index 720056b27d9..5587ac90b07 100644 --- a/mozilla/layout/generic/nsAbsoluteContainingBlock.cpp +++ b/mozilla/layout/generic/nsAbsoluteContainingBlock.cpp @@ -199,6 +199,8 @@ nsAbsoluteContainingBlock::Reflow(nsIFrame* aDelegatingFrame, // is the frame for which this is the absolute container or that the // container changed size due to incremental reflow of its children), // then change it to eReflowReason_Resize. + // XXXldb If the target is this frame, shouldn't we be setting it + // appropriately (which might mean to StyleChanged)? nsHTMLReflowState reflowState(aReflowState); if (eReflowReason_Incremental == reflowState.reason) { reflowState.reason = eReflowReason_Resize; @@ -253,6 +255,9 @@ void nsAbsoluteContainingBlock::CalculateChildBounds(nsIPresContext* aPresContext, nsRect& aChildBounds) { + // Initialize the OUT parameters + aChildBounds.SetRect(0, 0, 0, 0); + for (nsIFrame* f = mAbsoluteFrames.FirstChild(); f; f->GetNextSibling(&f)) { // Add in the child's bounds nsRect bounds; @@ -284,12 +289,10 @@ nsAbsoluteContainingBlock::IncrementalReflow(nsIFrame* aDelegatin const nsHTMLReflowState& aReflowState, nscoord aContainingBlockWidth, nscoord aContainingBlockHeight, - PRBool& aWasHandled, - nsRect& aChildBounds) + PRBool& aWasHandled) { - // Initialize the OUT paremeters + // Initialize the OUT parameters aWasHandled = PR_FALSE; - aChildBounds.SetRect(0, 0, 0, 0); // See if the reflow command is targeted at us. nsReflowPath *path = aReflowState.path; @@ -308,7 +311,7 @@ nsAbsoluteContainingBlock::IncrementalReflow(nsIFrame* aDelegatin // The only type of reflow command we expect is that we have dirty // child frames to reflow - NS_ASSERTION(eReflowType_ReflowDirty, "unexpected reflow type"); + NS_ASSERTION(type == eReflowType_ReflowDirty, "unexpected reflow type"); // Walk the positioned frames and reflow the dirty frames for (nsIFrame* f = mAbsoluteFrames.FirstChild(); f; f->GetNextSibling(&f)) { @@ -331,9 +334,12 @@ nsAbsoluteContainingBlock::IncrementalReflow(nsIFrame* aDelegatin // Indicate we handled the reflow command. aWasHandled = PR_TRUE; - - // Calculate the total child bounds. - CalculateChildBounds(aPresContext, aChildBounds); + } else { + // Reflow command is targeted directly at this block. + // We cannot handle this incrementally, we have to go to full reflow. + // Full reflow of nsBlockFrame reflows all absolutely positioned children, + // so skip the incremental update below. + return NS_OK; } } @@ -359,9 +365,6 @@ nsAbsoluteContainingBlock::IncrementalReflow(nsIFrame* aDelegatin // repainting, and because it has a view if it changes size // the view manager will damage the dirty area - // Calculate the total child bounds - CalculateChildBounds(aPresContext, aChildBounds); - // Prune the path so we don't flow the block frame _again_ // when returning to the caller. aReflowState.path->Remove(iter); @@ -409,7 +412,7 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat if (!aReflowState.mStyleBorder->GetBorder(border)) { NS_NOTYETIMPLEMENTED("percentage border"); } - + nsFrameState kidFrameState; nsSize availSize(aReflowState.mComputedWidth, NS_UNCONSTRAINEDSIZE); nsHTMLReflowMetrics kidDesiredSize(nsnull); @@ -494,6 +497,7 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat // Get the property (creating a rect struct if necessary) nsRect* overflowArea = ::GetOverflowAreaProperty(aPresContext, aKidFrame, PR_TRUE); + NS_ASSERTION(overflowArea, "should have created rect"); if (overflowArea) { *overflowArea = kidDesiredSize.mOverflowArea; } diff --git a/mozilla/layout/generic/nsAbsoluteContainingBlock.h b/mozilla/layout/generic/nsAbsoluteContainingBlock.h index 7f5adcb4000..911cf420210 100644 --- a/mozilla/layout/generic/nsAbsoluteContainingBlock.h +++ b/mozilla/layout/generic/nsAbsoluteContainingBlock.h @@ -109,8 +109,7 @@ public: const nsHTMLReflowState& aReflowState, nscoord aContainingBlockWidth, nscoord aContainingBlockHeight, - PRBool& aWasHandled, - nsRect& aChildBounds); + PRBool& aWasHandled); void DestroyFrames(nsIFrame* aDelegatingFrame, nsIPresContext* aPresContext); diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index b1932264fb0..d2a129f153e 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -748,38 +748,31 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, nscoord containingBlockWidth; nscoord containingBlockHeight; PRBool handled; - nsRect childBounds; CalculateContainingBlock(aReflowState, mRect.width, mRect.height, containingBlockWidth, containingBlockHeight); mAbsoluteContainer.IncrementalReflow(this, aPresContext, aReflowState, - containingBlockWidth, containingBlockHeight, - handled, childBounds); + containingBlockWidth, + containingBlockHeight, + handled); // If the incremental reflow command was handled by the absolute positioning // code, then we're all done if (handled) { // Just return our current size as our desired size. - // XXX We need to know the overflow area for the flowed content, and - // we don't have a way to get that currently so for the time being pretend - // a resize reflow occured -#if 0 aMetrics.width = mRect.width; aMetrics.height = mRect.height; - aMetrics.ascent = mRect.height; - aMetrics.descent = 0; - + aMetrics.ascent = mAscent; + aMetrics.descent = aMetrics.height - aMetrics.ascent; + // Whether or not we're complete hasn't changed aStatus = (nsnull != mNextInFlow) ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE; -#else - nsHTMLReflowState reflowState(aReflowState); - reflowState.reason = eReflowReason_Resize; - reflowState.path = nsnull; - nsBlockFrame::Reflow(aPresContext, aMetrics, reflowState, aStatus); -#endif // Factor the absolutely positioned child bounds into the overflow area + ComputeCombinedArea(aReflowState, aMetrics); + nsRect childBounds; + mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds); // Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly @@ -1497,6 +1490,51 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, #endif } + ComputeCombinedArea(aReflowState, aMetrics); + + // If the combined area of our children exceeds our bounding box + // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear it. + if ((aMetrics.mOverflowArea.x < 0) || + (aMetrics.mOverflowArea.y < 0) || + (aMetrics.mOverflowArea.XMost() > aMetrics.width) || + (aMetrics.mOverflowArea.YMost() > aMetrics.height)) { + mState |= NS_FRAME_OUTSIDE_CHILDREN; + } + else { + mState &= ~NS_FRAME_OUTSIDE_CHILDREN; + } + + if (NS_BLOCK_WRAP_SIZE & mState) { + // When the area frame is supposed to wrap around all in-flow + // children, make sure it is big enough to include those that stick + // outside the box. + if (NS_FRAME_OUTSIDE_CHILDREN & mState) { + nscoord xMost = aMetrics.mOverflowArea.XMost(); + if (xMost > aMetrics.width) { +#ifdef NOISY_FINAL_SIZE + ListTag(stdout); + printf(": changing desired width from %d to %d\n", aMetrics.width, xMost); +#endif + aMetrics.width = xMost; + } + nscoord yMost = aMetrics.mOverflowArea.YMost(); + if (yMost > aMetrics.height) { +#ifdef NOISY_FINAL_SIZE + ListTag(stdout); + printf(": changing desired height from %d to %d\n", aMetrics.height, yMost); +#endif + aMetrics.height = yMost; + // adjust descent to absorb any excess difference + aMetrics.descent = aMetrics.height - aMetrics.ascent; + } + } + } +} + +void +nsBlockFrame::ComputeCombinedArea(const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aMetrics) +{ // Compute the combined area of our children // XXX_perf: This can be done incrementally. It is currently one of // the things that makes incremental reflow O(N^2). @@ -1549,47 +1587,11 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, printf(": ca=%d,%d,%d,%d\n", xa, ya, xb-xa, yb-ya); #endif - // If the combined area of our children exceeds our bounding box - // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear it. aMetrics.mOverflowArea.x = xa; aMetrics.mOverflowArea.y = ya; aMetrics.mOverflowArea.width = xb - xa; aMetrics.mOverflowArea.height = yb - ya; - if ((aMetrics.mOverflowArea.x < 0) || - (aMetrics.mOverflowArea.y < 0) || - (aMetrics.mOverflowArea.XMost() > aMetrics.width) || - (aMetrics.mOverflowArea.YMost() > aMetrics.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } - else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } - if (NS_BLOCK_WRAP_SIZE & mState) { - // When the area frame is supposed to wrap around all in-flow - // children, make sure it is big enough to include those that stick - // outside the box. - if (NS_FRAME_OUTSIDE_CHILDREN & mState) { - nscoord xMost = aMetrics.mOverflowArea.XMost(); - if (xMost > aMetrics.width) { -#ifdef NOISY_FINAL_SIZE - ListTag(stdout); - printf(": changing desired width from %d to %d\n", aMetrics.width, xMost); -#endif - aMetrics.width = xMost; - } - nscoord yMost = aMetrics.mOverflowArea.YMost(); - if (yMost > aMetrics.height) { -#ifdef NOISY_FINAL_SIZE - ListTag(stdout); - printf(": changing desired height from %d to %d\n", aMetrics.height, yMost); -#endif - aMetrics.height = yMost; - // adjust descent to absorb any excess difference - aMetrics.descent = aMetrics.height - aMetrics.ascent; - } - } - } } nsresult @@ -5632,7 +5634,7 @@ nsBlockFrame::Paint(nsIPresContext* aPresContext, if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { PRInt32 depth = GetDepth(); nsRect ca; - ComputeCombinedArea(mLines, mRect.width, mRect.height, ca); + ::ComputeCombinedArea(mLines, mRect.width, mRect.height, ca); nsFrame::IndentBy(stdout, depth); ListTag(stdout); printf(": bounds=%d,%d,%d,%d dirty=%d,%d,%d,%d ca=%d,%d,%d,%d\n", diff --git a/mozilla/layout/generic/nsBlockFrame.h b/mozilla/layout/generic/nsBlockFrame.h index 9676ba4df9a..dd1b272c9fa 100644 --- a/mozilla/layout/generic/nsBlockFrame.h +++ b/mozilla/layout/generic/nsBlockFrame.h @@ -248,6 +248,9 @@ protected: nsBlockReflowState& aState, nsHTMLReflowMetrics& aMetrics); + void ComputeCombinedArea(const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aMetrics); + /** add the frames in aFrameList to this block after aPrevSibling * this block thinks in terms of lines, but the frame construction code * knows nothing about lines at all. So we need to find the line that diff --git a/mozilla/layout/generic/nsInlineFrame.cpp b/mozilla/layout/generic/nsInlineFrame.cpp index 56b09b15bec..2ec7330b5f5 100644 --- a/mozilla/layout/generic/nsInlineFrame.cpp +++ b/mozilla/layout/generic/nsInlineFrame.cpp @@ -1238,13 +1238,12 @@ nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext, eReflowReason_Incremental == aReflowState.reason) { // Give the absolute positioning code a chance to handle it PRBool handled; - nsRect childBounds; nscoord containingBlockWidth = -1; nscoord containingBlockHeight = -1; mAbsoluteContainer.IncrementalReflow(this, aPresContext, aReflowState, containingBlockWidth, containingBlockHeight, - handled, childBounds); + handled); // If the incremental reflow command was handled by the absolute positioning // code, then we're all done @@ -1261,6 +1260,8 @@ nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext, // code seems to reset the NS_FRAME_OUTSIDE_CHILDREN and so it is ignored #if 0 // Factor the absolutely positioned child bounds into the overflow area + nsRect childBounds; + mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, childBounds); // Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly diff --git a/mozilla/layout/html/base/src/nsAbsoluteContainingBlock.cpp b/mozilla/layout/html/base/src/nsAbsoluteContainingBlock.cpp index 720056b27d9..5587ac90b07 100644 --- a/mozilla/layout/html/base/src/nsAbsoluteContainingBlock.cpp +++ b/mozilla/layout/html/base/src/nsAbsoluteContainingBlock.cpp @@ -199,6 +199,8 @@ nsAbsoluteContainingBlock::Reflow(nsIFrame* aDelegatingFrame, // is the frame for which this is the absolute container or that the // container changed size due to incremental reflow of its children), // then change it to eReflowReason_Resize. + // XXXldb If the target is this frame, shouldn't we be setting it + // appropriately (which might mean to StyleChanged)? nsHTMLReflowState reflowState(aReflowState); if (eReflowReason_Incremental == reflowState.reason) { reflowState.reason = eReflowReason_Resize; @@ -253,6 +255,9 @@ void nsAbsoluteContainingBlock::CalculateChildBounds(nsIPresContext* aPresContext, nsRect& aChildBounds) { + // Initialize the OUT parameters + aChildBounds.SetRect(0, 0, 0, 0); + for (nsIFrame* f = mAbsoluteFrames.FirstChild(); f; f->GetNextSibling(&f)) { // Add in the child's bounds nsRect bounds; @@ -284,12 +289,10 @@ nsAbsoluteContainingBlock::IncrementalReflow(nsIFrame* aDelegatin const nsHTMLReflowState& aReflowState, nscoord aContainingBlockWidth, nscoord aContainingBlockHeight, - PRBool& aWasHandled, - nsRect& aChildBounds) + PRBool& aWasHandled) { - // Initialize the OUT paremeters + // Initialize the OUT parameters aWasHandled = PR_FALSE; - aChildBounds.SetRect(0, 0, 0, 0); // See if the reflow command is targeted at us. nsReflowPath *path = aReflowState.path; @@ -308,7 +311,7 @@ nsAbsoluteContainingBlock::IncrementalReflow(nsIFrame* aDelegatin // The only type of reflow command we expect is that we have dirty // child frames to reflow - NS_ASSERTION(eReflowType_ReflowDirty, "unexpected reflow type"); + NS_ASSERTION(type == eReflowType_ReflowDirty, "unexpected reflow type"); // Walk the positioned frames and reflow the dirty frames for (nsIFrame* f = mAbsoluteFrames.FirstChild(); f; f->GetNextSibling(&f)) { @@ -331,9 +334,12 @@ nsAbsoluteContainingBlock::IncrementalReflow(nsIFrame* aDelegatin // Indicate we handled the reflow command. aWasHandled = PR_TRUE; - - // Calculate the total child bounds. - CalculateChildBounds(aPresContext, aChildBounds); + } else { + // Reflow command is targeted directly at this block. + // We cannot handle this incrementally, we have to go to full reflow. + // Full reflow of nsBlockFrame reflows all absolutely positioned children, + // so skip the incremental update below. + return NS_OK; } } @@ -359,9 +365,6 @@ nsAbsoluteContainingBlock::IncrementalReflow(nsIFrame* aDelegatin // repainting, and because it has a view if it changes size // the view manager will damage the dirty area - // Calculate the total child bounds - CalculateChildBounds(aPresContext, aChildBounds); - // Prune the path so we don't flow the block frame _again_ // when returning to the caller. aReflowState.path->Remove(iter); @@ -409,7 +412,7 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat if (!aReflowState.mStyleBorder->GetBorder(border)) { NS_NOTYETIMPLEMENTED("percentage border"); } - + nsFrameState kidFrameState; nsSize availSize(aReflowState.mComputedWidth, NS_UNCONSTRAINEDSIZE); nsHTMLReflowMetrics kidDesiredSize(nsnull); @@ -494,6 +497,7 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat // Get the property (creating a rect struct if necessary) nsRect* overflowArea = ::GetOverflowAreaProperty(aPresContext, aKidFrame, PR_TRUE); + NS_ASSERTION(overflowArea, "should have created rect"); if (overflowArea) { *overflowArea = kidDesiredSize.mOverflowArea; } diff --git a/mozilla/layout/html/base/src/nsAbsoluteContainingBlock.h b/mozilla/layout/html/base/src/nsAbsoluteContainingBlock.h index 7f5adcb4000..911cf420210 100644 --- a/mozilla/layout/html/base/src/nsAbsoluteContainingBlock.h +++ b/mozilla/layout/html/base/src/nsAbsoluteContainingBlock.h @@ -109,8 +109,7 @@ public: const nsHTMLReflowState& aReflowState, nscoord aContainingBlockWidth, nscoord aContainingBlockHeight, - PRBool& aWasHandled, - nsRect& aChildBounds); + PRBool& aWasHandled); void DestroyFrames(nsIFrame* aDelegatingFrame, nsIPresContext* aPresContext); diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp index b1932264fb0..d2a129f153e 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.cpp +++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp @@ -748,38 +748,31 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, nscoord containingBlockWidth; nscoord containingBlockHeight; PRBool handled; - nsRect childBounds; CalculateContainingBlock(aReflowState, mRect.width, mRect.height, containingBlockWidth, containingBlockHeight); mAbsoluteContainer.IncrementalReflow(this, aPresContext, aReflowState, - containingBlockWidth, containingBlockHeight, - handled, childBounds); + containingBlockWidth, + containingBlockHeight, + handled); // If the incremental reflow command was handled by the absolute positioning // code, then we're all done if (handled) { // Just return our current size as our desired size. - // XXX We need to know the overflow area for the flowed content, and - // we don't have a way to get that currently so for the time being pretend - // a resize reflow occured -#if 0 aMetrics.width = mRect.width; aMetrics.height = mRect.height; - aMetrics.ascent = mRect.height; - aMetrics.descent = 0; - + aMetrics.ascent = mAscent; + aMetrics.descent = aMetrics.height - aMetrics.ascent; + // Whether or not we're complete hasn't changed aStatus = (nsnull != mNextInFlow) ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE; -#else - nsHTMLReflowState reflowState(aReflowState); - reflowState.reason = eReflowReason_Resize; - reflowState.path = nsnull; - nsBlockFrame::Reflow(aPresContext, aMetrics, reflowState, aStatus); -#endif // Factor the absolutely positioned child bounds into the overflow area + ComputeCombinedArea(aReflowState, aMetrics); + nsRect childBounds; + mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds); // Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly @@ -1497,6 +1490,51 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, #endif } + ComputeCombinedArea(aReflowState, aMetrics); + + // If the combined area of our children exceeds our bounding box + // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear it. + if ((aMetrics.mOverflowArea.x < 0) || + (aMetrics.mOverflowArea.y < 0) || + (aMetrics.mOverflowArea.XMost() > aMetrics.width) || + (aMetrics.mOverflowArea.YMost() > aMetrics.height)) { + mState |= NS_FRAME_OUTSIDE_CHILDREN; + } + else { + mState &= ~NS_FRAME_OUTSIDE_CHILDREN; + } + + if (NS_BLOCK_WRAP_SIZE & mState) { + // When the area frame is supposed to wrap around all in-flow + // children, make sure it is big enough to include those that stick + // outside the box. + if (NS_FRAME_OUTSIDE_CHILDREN & mState) { + nscoord xMost = aMetrics.mOverflowArea.XMost(); + if (xMost > aMetrics.width) { +#ifdef NOISY_FINAL_SIZE + ListTag(stdout); + printf(": changing desired width from %d to %d\n", aMetrics.width, xMost); +#endif + aMetrics.width = xMost; + } + nscoord yMost = aMetrics.mOverflowArea.YMost(); + if (yMost > aMetrics.height) { +#ifdef NOISY_FINAL_SIZE + ListTag(stdout); + printf(": changing desired height from %d to %d\n", aMetrics.height, yMost); +#endif + aMetrics.height = yMost; + // adjust descent to absorb any excess difference + aMetrics.descent = aMetrics.height - aMetrics.ascent; + } + } + } +} + +void +nsBlockFrame::ComputeCombinedArea(const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aMetrics) +{ // Compute the combined area of our children // XXX_perf: This can be done incrementally. It is currently one of // the things that makes incremental reflow O(N^2). @@ -1549,47 +1587,11 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, printf(": ca=%d,%d,%d,%d\n", xa, ya, xb-xa, yb-ya); #endif - // If the combined area of our children exceeds our bounding box - // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear it. aMetrics.mOverflowArea.x = xa; aMetrics.mOverflowArea.y = ya; aMetrics.mOverflowArea.width = xb - xa; aMetrics.mOverflowArea.height = yb - ya; - if ((aMetrics.mOverflowArea.x < 0) || - (aMetrics.mOverflowArea.y < 0) || - (aMetrics.mOverflowArea.XMost() > aMetrics.width) || - (aMetrics.mOverflowArea.YMost() > aMetrics.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } - else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } - if (NS_BLOCK_WRAP_SIZE & mState) { - // When the area frame is supposed to wrap around all in-flow - // children, make sure it is big enough to include those that stick - // outside the box. - if (NS_FRAME_OUTSIDE_CHILDREN & mState) { - nscoord xMost = aMetrics.mOverflowArea.XMost(); - if (xMost > aMetrics.width) { -#ifdef NOISY_FINAL_SIZE - ListTag(stdout); - printf(": changing desired width from %d to %d\n", aMetrics.width, xMost); -#endif - aMetrics.width = xMost; - } - nscoord yMost = aMetrics.mOverflowArea.YMost(); - if (yMost > aMetrics.height) { -#ifdef NOISY_FINAL_SIZE - ListTag(stdout); - printf(": changing desired height from %d to %d\n", aMetrics.height, yMost); -#endif - aMetrics.height = yMost; - // adjust descent to absorb any excess difference - aMetrics.descent = aMetrics.height - aMetrics.ascent; - } - } - } } nsresult @@ -5632,7 +5634,7 @@ nsBlockFrame::Paint(nsIPresContext* aPresContext, if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { PRInt32 depth = GetDepth(); nsRect ca; - ComputeCombinedArea(mLines, mRect.width, mRect.height, ca); + ::ComputeCombinedArea(mLines, mRect.width, mRect.height, ca); nsFrame::IndentBy(stdout, depth); ListTag(stdout); printf(": bounds=%d,%d,%d,%d dirty=%d,%d,%d,%d ca=%d,%d,%d,%d\n", diff --git a/mozilla/layout/html/base/src/nsBlockFrame.h b/mozilla/layout/html/base/src/nsBlockFrame.h index 9676ba4df9a..dd1b272c9fa 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.h +++ b/mozilla/layout/html/base/src/nsBlockFrame.h @@ -248,6 +248,9 @@ protected: nsBlockReflowState& aState, nsHTMLReflowMetrics& aMetrics); + void ComputeCombinedArea(const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aMetrics); + /** add the frames in aFrameList to this block after aPrevSibling * this block thinks in terms of lines, but the frame construction code * knows nothing about lines at all. So we need to find the line that diff --git a/mozilla/layout/html/base/src/nsInlineFrame.cpp b/mozilla/layout/html/base/src/nsInlineFrame.cpp index 56b09b15bec..2ec7330b5f5 100644 --- a/mozilla/layout/html/base/src/nsInlineFrame.cpp +++ b/mozilla/layout/html/base/src/nsInlineFrame.cpp @@ -1238,13 +1238,12 @@ nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext, eReflowReason_Incremental == aReflowState.reason) { // Give the absolute positioning code a chance to handle it PRBool handled; - nsRect childBounds; nscoord containingBlockWidth = -1; nscoord containingBlockHeight = -1; mAbsoluteContainer.IncrementalReflow(this, aPresContext, aReflowState, containingBlockWidth, containingBlockHeight, - handled, childBounds); + handled); // If the incremental reflow command was handled by the absolute positioning // code, then we're all done @@ -1261,6 +1260,8 @@ nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext, // code seems to reset the NS_FRAME_OUTSIDE_CHILDREN and so it is ignored #if 0 // Factor the absolutely positioned child bounds into the overflow area + nsRect childBounds; + mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, childBounds); // Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly diff --git a/mozilla/layout/html/base/src/nsPresShell.cpp b/mozilla/layout/html/base/src/nsPresShell.cpp index 67b586370de..bb00138c142 100644 --- a/mozilla/layout/html/base/src/nsPresShell.cpp +++ b/mozilla/layout/html/base/src/nsPresShell.cpp @@ -3703,15 +3703,20 @@ PresShell::AlreadyInQueue(nsHTMLReflowCommand* aReflowCommand, aReflowCommand->GetType(RCType); rc->GetType(queuedRCType); if (targetFrame == targetOfQueuedRC && - RCType == queuedRCType) { + RCType == queuedRCType) { + nsCOMPtr CLName, queuedCLName; + aReflowCommand->GetChildListName(*getter_AddRefs(CLName)); + rc->GetChildListName(*getter_AddRefs(queuedCLName)); + if (CLName == queuedCLName) { #ifdef DEBUG - if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) { - printf("*** PresShell::AlreadyInQueue(): Discarding reflow command: this=%p\n", (void*)this); - aReflowCommand->List(stdout); - } + if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) { + printf("*** PresShell::AlreadyInQueue(): Discarding reflow command: this=%p\n", (void*)this); + aReflowCommand->List(stdout); + } #endif - inQueue = PR_TRUE; - break; + inQueue = PR_TRUE; + break; + } } } }