From e0411e35529c1f83d8b1b5a2ec5e02714649ce64 Mon Sep 17 00:00:00 2001 From: "roc+%cs.cmu.edu" Date: Tue, 29 Jun 2004 12:46:46 +0000 Subject: [PATCH] Bug 244017. Hack invalidation of block children of blocks to avoid answering the question of whether we're supposed to invalidate the difference in frame bounds or the difference in overflow areas. r+sr=dbaron --- layout/generic/nsBlockFrame.cpp | 94 +++++++++++++++------------ layout/html/base/src/nsBlockFrame.cpp | 94 +++++++++++++++------------ 2 files changed, 108 insertions(+), 80 deletions(-) diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 0ce46077ff85..687b13001892 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -2275,6 +2275,28 @@ nsBlockFrame::DeleteLine(nsBlockReflowState& aState, } } +/** + * Takes two rectangles whose origins must be the same, and computes + * the difference between their union and their intersection as two + * rectangles. (This difference is a superset of the difference + * between the two rectangles.) + */ +static void GetRectDifferenceStrips(const nsRect& aR1, const nsRect& aR2, + nsRect* aHStrip, nsRect* aVStrip) { + NS_ASSERTION(aR1.TopLeft() == aR2.TopLeft(), + "expected rects at the same position"); + nsRect unionRect(aR1.x, aR1.y, PR_MAX(aR1.width, aR2.width), + PR_MAX(aR1.height, aR2.height)); + nscoord VStripStart = PR_MIN(aR1.width, aR2.width); + nscoord HStripStart = PR_MIN(aR1.height, aR2.height); + *aVStrip = unionRect; + aVStrip->x += VStripStart; + aVStrip->width -= VStripStart; + *aHStrip = unionRect; + aHStrip->y += HStripStart; + aHStrip->height -= HStripStart; +} + /** * Reflow a line. The line will either contain a single block frame * or contain 1 or more inline frames. aKeepReflowGoing indicates @@ -2295,18 +2317,24 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, aLine->ClearDirty(); // Now that we know what kind of line we have, reflow it - nsRect oldCombinedArea(aLine->GetCombinedArea()); - if (aLine->IsBlock()) { + nsRect oldBounds = aLine->mFirstChild->GetRect(); + nsRect oldCombinedArea(aLine->GetCombinedArea()); rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); + nsRect newBounds = aLine->mFirstChild->GetRect(); // We expect blocks to damage any area inside their bounds that is // dirty; however, if the frame changes size or position then we - // need to do some repainting + // need to do some repainting. + // XXX roc --- the above statement is ambiguous about whether 'bounds' + // means the frame's bounds or overflowArea, and in fact this is a source + // of much confusion and bugs. Thus the following hack considers *both* + // overflowArea and bounds. This should be considered a temporary hack + // until we decide how it's really supposed to work. if (aDamageDirtyArea) { nsRect lineCombinedArea(aLine->GetCombinedArea()); - if ((oldCombinedArea.x != lineCombinedArea.x) || - (oldCombinedArea.y != lineCombinedArea.y)) { + if (oldCombinedArea.TopLeft() != lineCombinedArea.TopLeft() || + oldBounds.TopLeft() != newBounds.TopLeft()) { // The block has moved, and so to be safe we need to repaint // XXX We need to improve on this... nsRect dirtyRect; @@ -2317,48 +2345,34 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, #endif Invalidate(dirtyRect); } else { - if (oldCombinedArea.width != lineCombinedArea.width) { - nsRect dirtyRect; + nsRect combinedAreaHStrip, combinedAreaVStrip; + nsRect boundsHStrip, boundsVStrip; + GetRectDifferenceStrips(oldBounds, newBounds, + &boundsHStrip, &boundsVStrip); + GetRectDifferenceStrips(oldCombinedArea, lineCombinedArea, + &combinedAreaHStrip, &combinedAreaVStrip); - // Just damage the vertical strip that was either added or went - // away - dirtyRect.x = PR_MIN(oldCombinedArea.XMost(), - lineCombinedArea.XMost()); - dirtyRect.y = lineCombinedArea.y; - dirtyRect.width = PR_MAX(oldCombinedArea.XMost(), - lineCombinedArea.XMost()) - - dirtyRect.x; - dirtyRect.height = PR_MAX(oldCombinedArea.height, - lineCombinedArea.height); #ifdef NOISY_BLOCK_INVALIDATE - printf("%p invalidate 7 (%d, %d, %d, %d)\n", - this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height); + printf("%p invalidate boundsVStrip (%d, %d, %d, %d)\n", + this, boundsVStrip.x, boundsVStrip.y, boundsVStrip.width, boundsVStrip.height); + printf("%p invalidate boundsHStrip (%d, %d, %d, %d)\n", + this, boundsHStrip.x, boundsHStrip.y, boundsHStrip.width, boundsHStrip.height); + printf("%p invalidate combinedAreaVStrip (%d, %d, %d, %d)\n", + this, combinedAreaVStrip.x, combinedAreaVStrip.y, combinedAreaVStrip.width, combinedAreaVStrip.height); + printf("%p invalidate combinedAreaHStrip (%d, %d, %d, %d)\n", + this, combinedAreaHStrip.x, combinedAreaHStrip.y, combinedAreaHStrip.width, combinedAreaHStrip.height); #endif - Invalidate(dirtyRect); - } - if (oldCombinedArea.height != lineCombinedArea.height) { - nsRect dirtyRect; - - // Just damage the horizontal strip that was either added or went - // away - dirtyRect.x = lineCombinedArea.x; - dirtyRect.y = PR_MIN(oldCombinedArea.YMost(), - lineCombinedArea.YMost()); - dirtyRect.width = PR_MAX(oldCombinedArea.width, - lineCombinedArea.width); - dirtyRect.height = PR_MAX(oldCombinedArea.YMost(), - lineCombinedArea.YMost()) - - dirtyRect.y; -#ifdef NOISY_BLOCK_INVALIDATE - printf("%p invalidate 8 (%d, %d, %d, %d)\n", - this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height); -#endif - Invalidate(dirtyRect); - } + // The first thing Invalidate does is check if the rect is empty, so + // don't bother doing that here. + Invalidate(boundsVStrip); + Invalidate(boundsHStrip); + Invalidate(combinedAreaVStrip); + Invalidate(combinedAreaHStrip); } } } else { + nsRect oldCombinedArea(aLine->GetCombinedArea()); aLine->SetLineWrapped(PR_FALSE); // If we're supposed to update the maximum width, then we'll need to reflow diff --git a/layout/html/base/src/nsBlockFrame.cpp b/layout/html/base/src/nsBlockFrame.cpp index 0ce46077ff85..687b13001892 100644 --- a/layout/html/base/src/nsBlockFrame.cpp +++ b/layout/html/base/src/nsBlockFrame.cpp @@ -2275,6 +2275,28 @@ nsBlockFrame::DeleteLine(nsBlockReflowState& aState, } } +/** + * Takes two rectangles whose origins must be the same, and computes + * the difference between their union and their intersection as two + * rectangles. (This difference is a superset of the difference + * between the two rectangles.) + */ +static void GetRectDifferenceStrips(const nsRect& aR1, const nsRect& aR2, + nsRect* aHStrip, nsRect* aVStrip) { + NS_ASSERTION(aR1.TopLeft() == aR2.TopLeft(), + "expected rects at the same position"); + nsRect unionRect(aR1.x, aR1.y, PR_MAX(aR1.width, aR2.width), + PR_MAX(aR1.height, aR2.height)); + nscoord VStripStart = PR_MIN(aR1.width, aR2.width); + nscoord HStripStart = PR_MIN(aR1.height, aR2.height); + *aVStrip = unionRect; + aVStrip->x += VStripStart; + aVStrip->width -= VStripStart; + *aHStrip = unionRect; + aHStrip->y += HStripStart; + aHStrip->height -= HStripStart; +} + /** * Reflow a line. The line will either contain a single block frame * or contain 1 or more inline frames. aKeepReflowGoing indicates @@ -2295,18 +2317,24 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, aLine->ClearDirty(); // Now that we know what kind of line we have, reflow it - nsRect oldCombinedArea(aLine->GetCombinedArea()); - if (aLine->IsBlock()) { + nsRect oldBounds = aLine->mFirstChild->GetRect(); + nsRect oldCombinedArea(aLine->GetCombinedArea()); rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); + nsRect newBounds = aLine->mFirstChild->GetRect(); // We expect blocks to damage any area inside their bounds that is // dirty; however, if the frame changes size or position then we - // need to do some repainting + // need to do some repainting. + // XXX roc --- the above statement is ambiguous about whether 'bounds' + // means the frame's bounds or overflowArea, and in fact this is a source + // of much confusion and bugs. Thus the following hack considers *both* + // overflowArea and bounds. This should be considered a temporary hack + // until we decide how it's really supposed to work. if (aDamageDirtyArea) { nsRect lineCombinedArea(aLine->GetCombinedArea()); - if ((oldCombinedArea.x != lineCombinedArea.x) || - (oldCombinedArea.y != lineCombinedArea.y)) { + if (oldCombinedArea.TopLeft() != lineCombinedArea.TopLeft() || + oldBounds.TopLeft() != newBounds.TopLeft()) { // The block has moved, and so to be safe we need to repaint // XXX We need to improve on this... nsRect dirtyRect; @@ -2317,48 +2345,34 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, #endif Invalidate(dirtyRect); } else { - if (oldCombinedArea.width != lineCombinedArea.width) { - nsRect dirtyRect; + nsRect combinedAreaHStrip, combinedAreaVStrip; + nsRect boundsHStrip, boundsVStrip; + GetRectDifferenceStrips(oldBounds, newBounds, + &boundsHStrip, &boundsVStrip); + GetRectDifferenceStrips(oldCombinedArea, lineCombinedArea, + &combinedAreaHStrip, &combinedAreaVStrip); - // Just damage the vertical strip that was either added or went - // away - dirtyRect.x = PR_MIN(oldCombinedArea.XMost(), - lineCombinedArea.XMost()); - dirtyRect.y = lineCombinedArea.y; - dirtyRect.width = PR_MAX(oldCombinedArea.XMost(), - lineCombinedArea.XMost()) - - dirtyRect.x; - dirtyRect.height = PR_MAX(oldCombinedArea.height, - lineCombinedArea.height); #ifdef NOISY_BLOCK_INVALIDATE - printf("%p invalidate 7 (%d, %d, %d, %d)\n", - this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height); + printf("%p invalidate boundsVStrip (%d, %d, %d, %d)\n", + this, boundsVStrip.x, boundsVStrip.y, boundsVStrip.width, boundsVStrip.height); + printf("%p invalidate boundsHStrip (%d, %d, %d, %d)\n", + this, boundsHStrip.x, boundsHStrip.y, boundsHStrip.width, boundsHStrip.height); + printf("%p invalidate combinedAreaVStrip (%d, %d, %d, %d)\n", + this, combinedAreaVStrip.x, combinedAreaVStrip.y, combinedAreaVStrip.width, combinedAreaVStrip.height); + printf("%p invalidate combinedAreaHStrip (%d, %d, %d, %d)\n", + this, combinedAreaHStrip.x, combinedAreaHStrip.y, combinedAreaHStrip.width, combinedAreaHStrip.height); #endif - Invalidate(dirtyRect); - } - if (oldCombinedArea.height != lineCombinedArea.height) { - nsRect dirtyRect; - - // Just damage the horizontal strip that was either added or went - // away - dirtyRect.x = lineCombinedArea.x; - dirtyRect.y = PR_MIN(oldCombinedArea.YMost(), - lineCombinedArea.YMost()); - dirtyRect.width = PR_MAX(oldCombinedArea.width, - lineCombinedArea.width); - dirtyRect.height = PR_MAX(oldCombinedArea.YMost(), - lineCombinedArea.YMost()) - - dirtyRect.y; -#ifdef NOISY_BLOCK_INVALIDATE - printf("%p invalidate 8 (%d, %d, %d, %d)\n", - this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height); -#endif - Invalidate(dirtyRect); - } + // The first thing Invalidate does is check if the rect is empty, so + // don't bother doing that here. + Invalidate(boundsVStrip); + Invalidate(boundsHStrip); + Invalidate(combinedAreaVStrip); + Invalidate(combinedAreaHStrip); } } } else { + nsRect oldCombinedArea(aLine->GetCombinedArea()); aLine->SetLineWrapped(PR_FALSE); // If we're supposed to update the maximum width, then we'll need to reflow