Fix bug 416073: invalidate more things as needed during table reflow to prevent glitches. r+sr=roc

This commit is contained in:
bzbarsky@mit.edu 2008-02-08 01:36:32 -08:00
Родитель 7d5dd48b52
Коммит d6526d103e
13 изменённых файлов: 309 добавлений и 74 удалений

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

@ -2486,3 +2486,21 @@ nsLayoutUtils::GetTextRunFlagsForStyle(nsStyleContext* aStyleContext,
#endif #endif
return result; return result;
} }
/* static */ void
nsLayoutUtils::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;
}

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

@ -754,6 +754,15 @@ public:
const nsStyleText* aStyleText, const nsStyleText* aStyleText,
const nsStyleFont* aStyleFont); const nsStyleFont* aStyleFont);
/**
* 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);
/** /**
* Indicates if the nsIFrame::GetUsedXXX assertions in nsFrame.cpp should * Indicates if the nsIFrame::GetUsedXXX assertions in nsFrame.cpp should
* disabled. * disabled.

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

@ -2234,28 +2234,6 @@ 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 * Reflow a line. The line will either contain a single block frame
* or contain 1 or more inline frames. aKeepReflowGoing indicates * or contain 1 or more inline frames. aKeepReflowGoing indicates
@ -2305,10 +2283,11 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
} else { } else {
nsRect combinedAreaHStrip, combinedAreaVStrip; nsRect combinedAreaHStrip, combinedAreaVStrip;
nsRect boundsHStrip, boundsVStrip; nsRect boundsHStrip, boundsVStrip;
GetRectDifferenceStrips(oldBounds, newBounds, nsLayoutUtils::GetRectDifferenceStrips(oldBounds, newBounds,
&boundsHStrip, &boundsVStrip); &boundsHStrip, &boundsVStrip);
GetRectDifferenceStrips(oldCombinedArea, lineCombinedArea, nsLayoutUtils::GetRectDifferenceStrips(oldCombinedArea, lineCombinedArea,
&combinedAreaHStrip, &combinedAreaVStrip); &combinedAreaHStrip,
&combinedAreaVStrip);
#ifdef NOISY_BLOCK_INVALIDATE #ifdef NOISY_BLOCK_INVALIDATE
printf("%p invalidate boundsVStrip (%d, %d, %d, %d)\n", printf("%p invalidate boundsVStrip (%d, %d, %d, %d)\n",

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

@ -743,6 +743,11 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame,
aKidFrame->WillReflow(aPresContext); aKidFrame->WillReflow(aPresContext);
if (0 == (aFlags & NS_FRAME_NO_MOVE_FRAME)) { if (0 == (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
if ((aFlags & NS_FRAME_INVALIDATE_ON_MOVE) &&
!(aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
aKidFrame->GetPosition() != nsPoint(aX, aY)) {
aKidFrame->InvalidateOverflowRect();
}
aKidFrame->SetPosition(nsPoint(aX, aY)); aKidFrame->SetPosition(nsPoint(aX, aY));
} }

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

@ -60,6 +60,9 @@
#define NS_FRAME_NO_MOVE_FRAME (0x0002 | NS_FRAME_NO_MOVE_VIEW) #define NS_FRAME_NO_MOVE_FRAME (0x0002 | NS_FRAME_NO_MOVE_VIEW)
#define NS_FRAME_NO_SIZE_VIEW 0x0004 #define NS_FRAME_NO_SIZE_VIEW 0x0004
#define NS_FRAME_NO_VISIBILITY 0x0008 #define NS_FRAME_NO_VISIBILITY 0x0008
// Only applies to ReflowChild: if true, invalidate the child if it's
// being moved
#define NS_FRAME_INVALIDATE_ON_MOVE 0x0010
class nsOverflowContinuationTracker; class nsOverflowContinuationTracker;

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

@ -3600,6 +3600,21 @@ nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aImmediate); InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aImmediate);
} }
void
nsIFrame::InvalidateRectDifference(const nsRect& aR1, const nsRect& aR2)
{
nsRect sizeHStrip, sizeVStrip;
nsLayoutUtils::GetRectDifferenceStrips(aR1, aR2, &sizeHStrip, &sizeVStrip);
Invalidate(sizeVStrip);
Invalidate(sizeHStrip);
}
void
nsIFrame::InvalidateOverflowRect()
{
Invalidate(GetOverflowRect());
}
void void
nsIFrame::InvalidateRoot(const nsRect& aDamageRect, nsIFrame::InvalidateRoot(const nsRect& aDamageRect,
nscoord aX, nscoord aY, PRBool aImmediate) nscoord aX, nscoord aY, PRBool aImmediate)

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

@ -1655,6 +1655,21 @@ public:
nscoord aOffsetX, nscoord aOffsetY, nscoord aOffsetX, nscoord aOffsetY,
nsIFrame* aForChild, PRBool aImmediate); nsIFrame* aForChild, PRBool aImmediate);
/**
* Take two rectangles in the coordinate system of this frame which
* have the same origin and invalidate the difference between them.
* This is a helper method to be used when a frame is being resized.
*
* @param aR1 the first rectangle
* @param aR2 the second rectangle
*/
void InvalidateRectDifference(const nsRect& aR1, const nsRect& aR2);
/**
* Invalidate the overflow rect of this frame
*/
void InvalidateOverflowRect();
/** /**
* Computes a rect that encompasses everything that might be painted by * Computes a rect that encompasses everything that might be painted by
* this frame. This includes this frame, all its descendent frames, this * this frame. This includes this frame, all its descendent frames, this

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

@ -593,6 +593,11 @@ void nsTableCellFrame::VerticallyAlignChild(nscoord aMaxAscent)
// if the content is larger than the cell height align from top // if the content is larger than the cell height align from top
kidYTop = PR_MAX(0, kidYTop); kidYTop = PR_MAX(0, kidYTop);
if (kidYTop != kidRect.y) {
// Invalidate at the old position first
firstKid->InvalidateOverflowRect();
}
firstKid->SetPosition(nsPoint(kidRect.x, kidYTop)); firstKid->SetPosition(nsPoint(kidRect.x, kidYTop));
nsHTMLReflowMetrics desiredSize; nsHTMLReflowMetrics desiredSize;
desiredSize.width = mRect.width; desiredSize.width = mRect.width;
@ -604,6 +609,9 @@ void nsTableCellFrame::VerticallyAlignChild(nscoord aMaxAscent)
// Make sure any child views are correctly positioned. We know the inner table // Make sure any child views are correctly positioned. We know the inner table
// cell won't have a view // cell won't have a view
nsContainerFrame::PositionChildViews(firstKid); nsContainerFrame::PositionChildViews(firstKid);
// Invalidate new overflow rect
firstKid->InvalidateOverflowRect();
} }
if (HasView()) { if (HasView()) {
nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this, nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this,
@ -861,15 +869,19 @@ NS_METHOD nsTableCellFrame::Reflow(nsPresContext* aPresContext,
} }
nsPoint kidOrigin(leftInset, topInset); nsPoint kidOrigin(leftInset, topInset);
nsRect origRect = firstKid->GetRect();
PRBool firstReflow = (firstKid->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
ReflowChild(firstKid, aPresContext, kidSize, kidReflowState, ReflowChild(firstKid, aPresContext, kidSize, kidReflowState,
kidOrigin.x, kidOrigin.y, 0, aStatus); kidOrigin.x, kidOrigin.y, NS_FRAME_INVALIDATE_ON_MOVE, aStatus);
if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) { if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
// Don't pass OVERFLOW_INCOMPLETE through tables until they can actually handle it // Don't pass OVERFLOW_INCOMPLETE through tables until they can actually handle it
//XXX should paginate overflow as overflow, but not in this patch (bug 379349) //XXX should paginate overflow as overflow, but not in this patch (bug 379349)
NS_FRAME_SET_INCOMPLETE(aStatus); NS_FRAME_SET_INCOMPLETE(aStatus);
printf("Set table cell incomplete %p\n", this); printf("Set table cell incomplete %p\n", this);
} }
// XXXbz is this invalidate actually needed, really?
if (GetStateBits() & NS_FRAME_IS_DIRTY) { if (GetStateBits() & NS_FRAME_IS_DIRTY) {
Invalidate(GetOverflowRect(), PR_FALSE); Invalidate(GetOverflowRect(), PR_FALSE);
} }
@ -886,6 +898,8 @@ NS_METHOD nsTableCellFrame::Reflow(nsPresContext* aPresContext,
FinishReflowChild(firstKid, aPresContext, &kidReflowState, kidSize, FinishReflowChild(firstKid, aPresContext, &kidReflowState, kidSize,
kidOrigin.x, kidOrigin.y, 0); kidOrigin.x, kidOrigin.y, 0);
nsTableFrame::InvalidateFrame(firstKid, origRect, firstReflow);
// first, compute the height which can be set w/o being restricted by aMaxSize.height // first, compute the height which can be set w/o being restricted by aMaxSize.height
nscoord cellHeight = kidSize.height; nscoord cellHeight = kidSize.height;

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

@ -1957,6 +1957,11 @@ NS_METHOD nsTableFrame::Reflow(nsPresContext* aPresContext,
} }
} }
if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
// Fulfill the promise InvalidateFrame makes.
Invalidate(aDesiredSize.mOverflowArea);
}
FinishAndStoreOverflow(&aDesiredSize); FinishAndStoreOverflow(&aDesiredSize);
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
return rv; return rv;
@ -2578,13 +2583,18 @@ nsTableFrame::InitChildReflowState(nsHTMLReflowState& aReflowState)
// aKidRect is relative to the upper-left origin of our frame // aKidRect is relative to the upper-left origin of our frame
void nsTableFrame::PlaceChild(nsTableReflowState& aReflowState, void nsTableFrame::PlaceChild(nsTableReflowState& aReflowState,
nsIFrame* aKidFrame, nsIFrame* aKidFrame,
nsHTMLReflowMetrics& aKidDesiredSize) nsHTMLReflowMetrics& aKidDesiredSize,
const nsRect& aOriginalKidRect)
{ {
PRBool isFirstReflow =
(aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
// Place and size the child // Place and size the child
FinishReflowChild(aKidFrame, PresContext(), nsnull, aKidDesiredSize, FinishReflowChild(aKidFrame, PresContext(), nsnull, aKidDesiredSize,
aReflowState.x, aReflowState.y, 0); aReflowState.x, aReflowState.y, 0);
InvalidateFrame(aKidFrame, aOriginalKidRect, isFirstReflow);
// Adjust the running y-offset // Adjust the running y-offset
aReflowState.y += aKidDesiredSize.height; aReflowState.y += aKidDesiredSize.height;
@ -2936,7 +2946,8 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
reorder = PR_TRUE; reorder = PR_TRUE;
rv = ReflowChild(kidFrame, presContext, desiredSize, kidReflowState, rv = ReflowChild(kidFrame, presContext, desiredSize, kidReflowState,
aReflowState.x, aReflowState.y, 0, aStatus); aReflowState.x, aReflowState.y,
NS_FRAME_INVALIDATE_ON_MOVE, aStatus);
if (reorder) { if (reorder) {
// reorder row groups the reflow may have changed the nextinflows // reorder row groups the reflow may have changed the nextinflows
@ -2957,7 +2968,7 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
if (childX+1 < rowGroups.Length()) { if (childX+1 < rowGroups.Length()) {
nsIFrame* nextRowGroupFrame = rowGroups[childX + 1]; nsIFrame* nextRowGroupFrame = rowGroups[childX + 1];
if (nextRowGroupFrame) { if (nextRowGroupFrame) {
PlaceChild(aReflowState, kidFrame, desiredSize); PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect);
aStatus = NS_FRAME_NOT_COMPLETE; aStatus = NS_FRAME_NOT_COMPLETE;
PushChildren(rowGroups, childX + 1); PushChildren(rowGroups, childX + 1);
aLastChildReflowed = kidFrame; aLastChildReflowed = kidFrame;
@ -2988,7 +2999,7 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
} }
// Place the child // Place the child
PlaceChild(aReflowState, kidFrame, desiredSize); PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect);
// Remember where we just were in case we end up pushing children // Remember where we just were in case we end up pushing children
prevKidFrame = kidFrame; prevKidFrame = kidFrame;
@ -3036,10 +3047,14 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
-1, -1, PR_FALSE); -1, -1, PR_FALSE);
InitChildReflowState(footerReflowState); InitChildReflowState(footerReflowState);
aReflowState.y += cellSpacingY; aReflowState.y += cellSpacingY;
nsRect origTfootRect = tfoot->GetRect();
nsReflowStatus footerStatus; nsReflowStatus footerStatus;
rv = ReflowChild(tfoot, presContext, desiredSize, footerReflowState, rv = ReflowChild(tfoot, presContext, desiredSize, footerReflowState,
aReflowState.x, aReflowState.y, 0, footerStatus); aReflowState.x, aReflowState.y,
PlaceChild(aReflowState, tfoot, desiredSize); NS_FRAME_INVALIDATE_ON_MOVE, footerStatus);
PlaceChild(aReflowState, tfoot, desiredSize, origTfootRect);
} }
break; break;
} }
@ -3048,11 +3063,13 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
aReflowState.y += cellSpacingY; aReflowState.y += cellSpacingY;
nsRect kidRect = kidFrame->GetRect(); nsRect kidRect = kidFrame->GetRect();
if (kidRect.y != aReflowState.y) { if (kidRect.y != aReflowState.y) {
Invalidate(kidRect); // invalidate the old position // invalidate the old position
kidFrame->InvalidateOverflowRect();
kidRect.y = aReflowState.y; kidRect.y = aReflowState.y;
kidFrame->SetRect(kidRect); // move to the new position kidFrame->SetRect(kidRect); // move to the new position
RePositionViews(kidFrame); RePositionViews(kidFrame);
Invalidate(kidRect); // invalidate the new position // invalidate the new position
kidFrame->InvalidateOverflowRect();
} }
aReflowState.y += kidRect.height; aReflowState.y += kidRect.height;
@ -3226,7 +3243,9 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
nscoord pctHeight = rowFrame->GetHeight(pctBasis); nscoord pctHeight = rowFrame->GetHeight(pctBasis);
nscoord amountForRow = PR_MIN(aAmount - amountUsed, pctHeight - rowRect.height); nscoord amountForRow = PR_MIN(aAmount - amountUsed, pctHeight - rowRect.height);
if (amountForRow > 0) { if (amountForRow > 0) {
nsRect oldRowRect = rowRect;
rowRect.height += amountForRow; rowRect.height += amountForRow;
// XXXbz we don't need to change rowRect.y to be yOriginRow?
rowFrame->SetRect(rowRect); rowFrame->SetRect(rowRect);
yOriginRow += rowRect.height + cellSpacingY; yOriginRow += rowRect.height + cellSpacingY;
yEndRG += rowRect.height + cellSpacingY; yEndRG += rowRect.height + cellSpacingY;
@ -3234,12 +3253,17 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
amountUsedByRG += amountForRow; amountUsedByRG += amountForRow;
//rowFrame->DidResize(); //rowFrame->DidResize();
nsTableFrame::RePositionViews(rowFrame); nsTableFrame::RePositionViews(rowFrame);
rgFrame->InvalidateRectDifference(oldRowRect, rowRect);
} }
} }
else { else {
if (amountUsed > 0) { if (amountUsed > 0 && yOriginRow != rowRect.y &&
!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
rowFrame->InvalidateOverflowRect();
rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow)); rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow));
nsTableFrame::RePositionViews(rowFrame); nsTableFrame::RePositionViews(rowFrame);
rowFrame->InvalidateOverflowRect();
} }
yOriginRow += rowRect.height + cellSpacingY; yOriginRow += rowRect.height + cellSpacingY;
yEndRG += rowRect.height + cellSpacingY; yEndRG += rowRect.height + cellSpacingY;
@ -3247,15 +3271,27 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
rowFrame = rowFrame->GetNextRow(); rowFrame = rowFrame->GetNextRow();
} }
if (amountUsed > 0) { if (amountUsed > 0) {
if (rgRect.y != yOriginRG) {
rgFrame->InvalidateOverflowRect();
}
nsRect origRgRect = rgRect;
rgRect.y = yOriginRG; rgRect.y = yOriginRG;
rgRect.height += amountUsedByRG; rgRect.height += amountUsedByRG;
rgFrame->SetRect(rgRect); rgFrame->SetRect(rgRect);
nsTableFrame::InvalidateFrame(rgFrame, origRgRect, PR_FALSE);
} }
} }
else if (amountUsed > 0) { else if (amountUsed > 0 && yOriginRG != rgFrame->GetPosition().y) {
NS_ASSERTION(rgFrame->GetPosition().x == 0, "Unexpected position");
rgFrame->InvalidateOverflowRect();
rgFrame->SetPosition(nsPoint(0, yOriginRG)); rgFrame->SetPosition(nsPoint(0, yOriginRG));
// Make sure child views are properly positioned // Make sure child views are properly positioned
nsTableFrame::RePositionViews(rgFrame); nsTableFrame::RePositionViews(rgFrame);
rgFrame->InvalidateOverflowRect();
} }
yOriginRG = yEndRG; yOriginRG = yEndRG;
} }
@ -3360,9 +3396,16 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
nscoord amountForRow = (rowFrame == lastEligibleRow) nscoord amountForRow = (rowFrame == lastEligibleRow)
? aAmount - amountUsed : NSToCoordRound(((float)(heightToDistribute)) * ratio); ? aAmount - amountUsed : NSToCoordRound(((float)(heightToDistribute)) * ratio);
amountForRow = PR_MIN(amountForRow, aAmount - amountUsed); amountForRow = PR_MIN(amountForRow, aAmount - amountUsed);
if (yOriginRow != rowRect.y) {
rowFrame->InvalidateOverflowRect();
}
// update the row height // update the row height
nsRect newRowRect(rowRect.x, yOriginRow, rowRect.width, rowRect.height + amountForRow); nsRect newRowRect(rowRect.x, yOriginRow, rowRect.width,
rowRect.height + amountForRow);
rowFrame->SetRect(newRowRect); rowFrame->SetRect(newRowRect);
yOriginRow += newRowRect.height + cellSpacingY; yOriginRow += newRowRect.height + cellSpacingY;
yEndRG += newRowRect.height + cellSpacingY; yEndRG += newRowRect.height + cellSpacingY;
@ -3371,11 +3414,15 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
NS_ASSERTION((amountUsed <= aAmount), "invalid row allocation"); NS_ASSERTION((amountUsed <= aAmount), "invalid row allocation");
//rowFrame->DidResize(); //rowFrame->DidResize();
nsTableFrame::RePositionViews(rowFrame); nsTableFrame::RePositionViews(rowFrame);
nsTableFrame::InvalidateFrame(rowFrame, rowRect, PR_FALSE);
} }
else { else {
if (amountUsed > 0) { if (amountUsed > 0 && yOriginRow != rowRect.y) {
rowFrame->InvalidateOverflowRect();
rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow)); rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow));
nsTableFrame::RePositionViews(rowFrame); nsTableFrame::RePositionViews(rowFrame);
rowFrame->InvalidateOverflowRect();
} }
yOriginRow += rowRect.height + cellSpacingY; yOriginRow += rowRect.height + cellSpacingY;
yEndRG += rowRect.height + cellSpacingY; yEndRG += rowRect.height + cellSpacingY;
@ -3383,17 +3430,25 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
rowFrame = rowFrame->GetNextRow(); rowFrame = rowFrame->GetNextRow();
} }
if (amountUsed > 0) { if (amountUsed > 0) {
rgRect.y = yOriginRG; if (rgRect.y != yOriginRG) {
rgRect.height += amountUsedByRG; rgFrame->InvalidateOverflowRect();
rgFrame->SetRect(rgRect); }
rgFrame->SetRect(nsRect(rgRect.x, yOriginRG, rgRect.width,
rgRect.height + amountUsedByRG));
nsTableFrame::InvalidateFrame(rgFrame, rgRect, PR_FALSE);
} }
// Make sure child views are properly positioned // Make sure child views are properly positioned
// XXX what happens if childFrame is a scroll frame and this gets skipped? see also below // XXX what happens if childFrame is a scroll frame and this gets skipped? see also below
} }
else if (amountUsed > 0) { else if (amountUsed > 0 && yOriginRG != rgFrame->GetPosition().y) {
NS_ASSERTION(rgFrame->GetPosition().x == 0, "Unexpected position");
rgFrame->InvalidateOverflowRect();
rgFrame->SetPosition(nsPoint(0, yOriginRG)); rgFrame->SetPosition(nsPoint(0, yOriginRG));
// Make sure child views are properly positioned // Make sure child views are properly positioned
nsTableFrame::RePositionViews(rgFrame); nsTableFrame::RePositionViews(rgFrame);
rgFrame->InvalidateOverflowRect();
} }
yOriginRG = yEndRG; yOriginRG = yEndRG;
} }
@ -6718,6 +6773,27 @@ nsTableFrame::GetProperty(nsIFrame* aFrame,
return nsnull; return nsnull;
} }
/* static */
void
nsTableFrame::InvalidateFrame(nsIFrame* aFrame, const nsRect& aOrigRect,
PRBool aIsFirstReflow)
{
nsIFrame* parent = aFrame->GetParent();
NS_ASSERTION(parent, "What happened here?");
if (parent->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
// Don't bother; we'll invalidate the parent's overflow rect when
// we finish reflowing it.
return;
}
if (aIsFirstReflow || aOrigRect.TopLeft() != aFrame->GetPosition()) {
aFrame->InvalidateOverflowRect();
} else {
parent->InvalidateRectDifference(aOrigRect, aFrame->GetRect());
}
}
#ifdef DEBUG #ifdef DEBUG
#define MAX_SIZE 128 #define MAX_SIZE 128
#define MIN_INDENT 30 #define MIN_INDENT 30

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

@ -480,6 +480,20 @@ public:
PRBool HasCellSpanningPctCol() const; PRBool HasCellSpanningPctCol() const;
void SetHasCellSpanningPctCol(PRBool aValue); void SetHasCellSpanningPctCol(PRBool aValue);
/**
* To be called on a frame by its parent after setting its size/position and
* calling DidReflow (possibly via FinishReflowChild()). This can also be
* used for child frames which are not being reflown but did have their size
* or position changed.
*
* @param aFrame The frame to invalidate
* @param aOrigRect The original rect of aFrame (before the change).
* @param aIsFirstReflow True if the size/position change is due to the
* first reflow of aFrame.
*/
static void InvalidateFrame(nsIFrame* aFrame, const nsRect& aOrigRect,
PRBool aIsFirstReflow);
protected: protected:
/** protected constructor. /** protected constructor.
@ -567,7 +581,8 @@ protected:
void PlaceChild(nsTableReflowState& aReflowState, void PlaceChild(nsTableReflowState& aReflowState,
nsIFrame* aKidFrame, nsIFrame* aKidFrame,
nsHTMLReflowMetrics& aKidDesiredSize); nsHTMLReflowMetrics& aKidDesiredSize,
const nsRect& aOriginalKidRect);
nsIFrame* GetFirstBodyRowGroupFrame(); nsIFrame* GetFirstBodyRowGroupFrame();
PRBool MoveOverflowToChildList(nsPresContext* aPresContext); PRBool MoveOverflowToChildList(nsPresContext* aPresContext);

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

@ -353,16 +353,24 @@ nsTableRowFrame::DidResize()
nscoord cellHeight = mRect.height + GetHeightOfRowsSpannedBelowFirst(*cellFrame, *tableFrame); nscoord cellHeight = mRect.height + GetHeightOfRowsSpannedBelowFirst(*cellFrame, *tableFrame);
// resize the cell's height // resize the cell's height
//if (cellFrameSize.height!=cellHeight) nsRect cellRect = cellFrame->GetRect();
if (cellRect.height != cellHeight)
{ {
cellFrame->SetSize(nsSize(cellFrame->GetSize().width, cellHeight)); cellFrame->SetSize(nsSize(cellRect.width, cellHeight));
// realign cell content based on the new height nsTableFrame::InvalidateFrame(cellFrame, cellRect, PR_FALSE);
}
// realign cell content based on the new height. We might be able to
// skip this if the height didn't change... maybe. Hard to tell.
cellFrame->VerticallyAlignChild(mMaxCellAscent); cellFrame->VerticallyAlignChild(mMaxCellAscent);
// Always store the overflow, even if the height didn't change, since
// we'll lose part of our overflow area otherwise.
ConsiderChildOverflow(desiredSize.mOverflowArea, cellFrame); ConsiderChildOverflow(desiredSize.mOverflowArea, cellFrame);
// Note that if the cell's *content* needs to change in response // Note that if the cell's *content* needs to change in response
// to this height, it will get a special height reflow. // to this height, it will get a special height reflow.
} }
}
// Get the next child // Get the next child
childFrame = iter.Next(); childFrame = iter.Next();
} }
@ -855,6 +863,10 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext,
prevColIndex = (iter.IsLeftToRight()) ? cellColIndex + (cellColSpan - 1) : cellColIndex; prevColIndex = (iter.IsLeftToRight()) ? cellColIndex + (cellColSpan - 1) : cellColIndex;
// Reflow the child frame // Reflow the child frame
nsRect kidRect = kidFrame->GetRect();
PRBool firstReflow =
(kidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
if (doReflowChild) { if (doReflowChild) {
// Calculate the available width for the table cell using the known column widths // Calculate the available width for the table cell using the known column widths
nscoord availColWidth, availCellWidth; nscoord availColWidth, availCellWidth;
@ -889,7 +901,7 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext,
nsReflowStatus status; nsReflowStatus status;
rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState,
x, 0, 0, status); x, 0, NS_FRAME_INVALIDATE_ON_MOVE, status);
// allow the table to determine if/how the table needs to be rebalanced // allow the table to determine if/how the table needs to be rebalanced
// If any of the cells are not complete, then we're not complete // If any of the cells are not complete, then we're not complete
@ -898,6 +910,10 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext,
} }
} }
else { else {
if (x != kidRect.x) {
kidFrame->InvalidateOverflowRect();
}
desiredSize.width = cellDesiredSize.width; desiredSize.width = cellDesiredSize.width;
desiredSize.height = cellDesiredSize.height; desiredSize.height = cellDesiredSize.height;
nsRect *overflowArea = nsRect *overflowArea =
@ -950,16 +966,19 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext,
FinishReflowChild(kidFrame, aPresContext, nsnull, desiredSize, x, 0, 0); FinishReflowChild(kidFrame, aPresContext, nsnull, desiredSize, x, 0, 0);
nsTableFrame::InvalidateFrame(kidFrame, kidRect, firstReflow);
x += desiredSize.width; x += desiredSize.width;
} }
else { else {
nsRect kidRect = kidFrame->GetRect();
if (kidRect.x != x) { if (kidRect.x != x) {
Invalidate(kidRect); // invalidate the old position // Invalidate the old position
kidRect.x = x; kidFrame->InvalidateOverflowRect();
kidFrame->SetRect(kidRect); // move to the new position // move to the new position
kidFrame->SetPosition(nsPoint(x, kidRect.y));
nsTableFrame::RePositionViews(kidFrame); nsTableFrame::RePositionViews(kidFrame);
Invalidate(kidRect); // invalidate the new position // invalidate the new position
kidFrame->InvalidateOverflowRect();
} }
// we need to account for the cell's width even if it isn't reflowed // we need to account for the cell's width even if it isn't reflowed
x += kidRect.width; x += kidRect.width;
@ -1066,9 +1085,9 @@ nsTableRowFrame::ReflowCellFrame(nsPresContext* aPresContext,
ABORT1(NS_ERROR_NULL_POINTER); ABORT1(NS_ERROR_NULL_POINTER);
// Reflow the cell frame with the specified height. Use the existing width // Reflow the cell frame with the specified height. Use the existing width
nsSize cellSize = aCellFrame->GetSize(); nsRect cellRect = aCellFrame->GetRect();
nsSize availSize(cellSize.width, aAvailableHeight); nsSize availSize(cellRect.width, aAvailableHeight);
PRBool borderCollapse = ((nsTableFrame*)tableFrame->GetFirstInFlow())->IsBorderCollapse(); PRBool borderCollapse = ((nsTableFrame*)tableFrame->GetFirstInFlow())->IsBorderCollapse();
nsTableCellReflowState cellReflowState(aPresContext, aReflowState, nsTableCellReflowState cellReflowState(aPresContext, aReflowState,
aCellFrame, availSize, PR_FALSE); aCellFrame, availSize, PR_FALSE);
@ -1083,7 +1102,11 @@ nsTableRowFrame::ReflowCellFrame(nsPresContext* aPresContext,
if (fullyComplete) { if (fullyComplete) {
desiredSize.height = aAvailableHeight; desiredSize.height = aAvailableHeight;
} }
aCellFrame->SetSize(nsSize(cellSize.width, desiredSize.height)); aCellFrame->SetSize(nsSize(cellRect.width, desiredSize.height));
nsTableFrame::InvalidateFrame(aCellFrame, cellRect,
(aCellFrame->GetStateBits() &
NS_FRAME_FIRST_REFLOW) != 0);
// XXX What happens if this cell has 'vertical-align: baseline' ? // XXX What happens if this cell has 'vertical-align: baseline' ?
// XXX Why is it assumed that the cell's ascent hasn't changed ? // XXX Why is it assumed that the cell's ascent hasn't changed ?
@ -1110,7 +1133,14 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
tableFrame->SetNeedToCollapse(PR_TRUE); tableFrame->SetNeedToCollapse(PR_TRUE);
} }
if (aRowOffset != 0) {
// We're moving, so invalidate our old position
InvalidateOverflowRect();
}
nsRect rowRect = GetRect(); nsRect rowRect = GetRect();
nsRect oldRect = rowRect;
rowRect.y -= aRowOffset; rowRect.y -= aRowOffset;
rowRect.width = aWidth; rowRect.width = aWidth;
nsRect overflowArea(0, 0, 0, 0); nsRect overflowArea(0, 0, 0, 0);
@ -1124,6 +1154,13 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
shift = rowRect.height + cellSpacingY; shift = rowRect.height + cellSpacingY;
while (cellFrame) { while (cellFrame) {
nsRect cRect = cellFrame->GetRect(); nsRect cRect = cellFrame->GetRect();
// If aRowOffset != 0, there's no point in invalidating the cells, since
// we've already invalidated our overflow area. Note that we _do_ still
// need to invalidate if our row is not moving, because the cell might
// span out of this row, so invalidating our row rect won't do enough.
if (aRowOffset == 0) {
Invalidate(cRect);
}
cRect.height = 0; cRect.height = 0;
cellFrame->SetRect(cRect); cellFrame->SetRect(cRect);
cellFrame = cellFrame->GetNextCell(); cellFrame = cellFrame->GetNextCell();
@ -1161,7 +1198,7 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
*tableFrame, cellSpacingX, iter.IsLeftToRight(), *tableFrame, cellSpacingX, iter.IsLeftToRight(),
PR_TRUE); PR_TRUE);
} }
nsRect cRect(x, 0, 0,rowRect.height); nsRect cRect(x, 0, 0, rowRect.height);
// remember the rightmost (ltr) or leftmost (rtl) column this cell // remember the rightmost (ltr) or leftmost (rtl) column this cell
// spans into // spans into
@ -1216,23 +1253,40 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
} }
rowFrame = rowFrame->GetNextRow(); rowFrame = rowFrame->GetNextRow();
} }
nsRect oldCellRect = cellFrame->GetRect();
if (aRowOffset == 0 && cRect.TopLeft() != oldCellRect.TopLeft()) {
// We're moving the cell. Invalidate the old overflow area
cellFrame->InvalidateOverflowRect();
}
cellFrame->SetRect(cRect); cellFrame->SetRect(cRect);
// XXXbz This looks completely bogus in the cases when we didn't
// collapse the cell!
nsRect cellOverflow = nsRect(0, 0, cRect.width, cRect.height); nsRect cellOverflow = nsRect(0, 0, cRect.width, cRect.height);
cellFrame->FinishAndStoreOverflow(&cellOverflow, nsSize(cRect.width, cellFrame->FinishAndStoreOverflow(&cellOverflow, nsSize(cRect.width,
cRect.height)); cRect.height));
nsTableFrame::RePositionViews(cellFrame); nsTableFrame::RePositionViews(cellFrame);
ConsiderChildOverflow(overflowArea, cellFrame); ConsiderChildOverflow(overflowArea, cellFrame);
if (aRowOffset == 0) {
nsTableFrame::InvalidateFrame(cellFrame, oldCellRect, PR_FALSE);
}
} }
kidFrame = iter.Next(); // Get the next child kidFrame = iter.Next(); // Get the next child
} }
} }
SetRect(rowRect); SetRect(rowRect);
overflowArea.UnionRect(nsRect(0,0,rowRect.width, rowRect.height), overflowArea.UnionRect(nsRect(0,0,rowRect.width, rowRect.height),
overflowArea); overflowArea);
FinishAndStoreOverflow(&overflowArea, nsSize(rowRect.width, FinishAndStoreOverflow(&overflowArea, nsSize(rowRect.width,
rowRect.height)); rowRect.height));
nsTableFrame::RePositionViews(this); nsTableFrame::RePositionViews(this);
nsTableFrame::InvalidateFrame(this, oldRect, PR_FALSE);
return shift; return shift;
} }

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

@ -294,10 +294,17 @@ void
nsTableRowGroupFrame::PlaceChild(nsPresContext* aPresContext, nsTableRowGroupFrame::PlaceChild(nsPresContext* aPresContext,
nsRowGroupReflowState& aReflowState, nsRowGroupReflowState& aReflowState,
nsIFrame* aKidFrame, nsIFrame* aKidFrame,
nsHTMLReflowMetrics& aDesiredSize) nsHTMLReflowMetrics& aDesiredSize,
const nsRect& aOriginalKidRect)
{ {
PRBool isFirstReflow =
(aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
// Place and size the child // Place and size the child
FinishReflowChild(aKidFrame, aPresContext, nsnull, aDesiredSize, 0, aReflowState.y, 0); FinishReflowChild(aKidFrame, aPresContext, nsnull, aDesiredSize, 0,
aReflowState.y, 0);
nsTableFrame::InvalidateFrame(aKidFrame, aOriginalKidRect, isFirstReflow);
// Adjust the running y-offset // Adjust the running y-offset
aReflowState.y += aDesiredSize.height; aReflowState.y += aDesiredSize.height;
@ -384,7 +391,7 @@ nsTableRowGroupFrame::ReflowChildren(nsPresContext* aPresContext,
(aReflowState.reflowState.mFlags.mSpecialHeightReflow && (aReflowState.reflowState.mFlags.mSpecialHeightReflow &&
(isPaginated || (kidFrame->GetStateBits() & (isPaginated || (kidFrame->GetStateBits() &
NS_FRAME_CONTAINS_RELATIVE_HEIGHT)))) { NS_FRAME_CONTAINS_RELATIVE_HEIGHT)))) {
nsSize oldKidSize = kidFrame->GetSize(); nsRect oldKidRect = kidFrame->GetRect();
// XXXldb We used to only pass aDesiredSize.mFlags through for the // XXXldb We used to only pass aDesiredSize.mFlags through for the
// incremental reflow codepath. // incremental reflow codepath.
@ -410,10 +417,12 @@ nsTableRowGroupFrame::ReflowChildren(nsPresContext* aPresContext,
} }
rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState,
0, aReflowState.y, 0, aStatus); 0, aReflowState.y, NS_FRAME_INVALIDATE_ON_MOVE,
aStatus);
// Place the child // Place the child
PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize); PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize,
oldKidRect);
aReflowState.y += cellSpacingY; aReflowState.y += cellSpacingY;
if (!reflowAllKids) { if (!reflowAllKids) {
@ -436,7 +445,7 @@ nsTableRowGroupFrame::ReflowChildren(nsPresContext* aPresContext,
Invalidate(dirtyRect); Invalidate(dirtyRect);
} }
} }
else if (oldKidSize.height != desiredSize.height) else if (oldKidRect.height != desiredSize.height)
needToCalcRowHeights = PR_TRUE; needToCalcRowHeights = PR_TRUE;
} else { } else {
needToCalcRowHeights = PR_TRUE; needToCalcRowHeights = PR_TRUE;
@ -798,13 +807,19 @@ nsTableRowGroupFrame::CalculateRowHeights(nsPresContext* aPresContext,
nscoord rowHeight = (rowInfo[rowIndex].height > 0) ? rowInfo[rowIndex].height : 0; nscoord rowHeight = (rowInfo[rowIndex].height > 0) ? rowInfo[rowIndex].height : 0;
if (movedFrame || (rowHeight != rowBounds.height)) { if (movedFrame || (rowHeight != rowBounds.height)) {
// Resize the row to its final size and position // Resize/move the row to its final size and position
rowBounds.y = yOrigin; if (movedFrame) {
rowBounds.height = rowHeight; rowFrame->InvalidateOverflowRect();
rowFrame->SetRect(rowBounds); }
rowFrame->SetRect(nsRect(rowBounds.x, yOrigin, rowBounds.width,
rowHeight));
nsTableFrame::InvalidateFrame(rowFrame, rowBounds, PR_FALSE);
} }
if (movedFrame) { if (movedFrame) {
nsTableFrame::RePositionViews(rowFrame); nsTableFrame::RePositionViews(rowFrame);
// XXXbz we don't need to update our overflow area?
} }
yOrigin += rowHeight + cellSpacingY; yOrigin += rowHeight + cellSpacingY;
} }
@ -845,6 +860,8 @@ nsTableRowGroupFrame::CollapseRowGroupIfNecessary(nscoord aYTotalOffset,
} }
nsRect groupRect = GetRect(); nsRect groupRect = GetRect();
nsRect oldGroupRect = groupRect;
groupRect.height -= yGroupOffset; groupRect.height -= yGroupOffset;
if (didCollapse) { if (didCollapse) {
// add back the cellspacing between rowgroups // add back the cellspacing between rowgroups
@ -853,12 +870,19 @@ nsTableRowGroupFrame::CollapseRowGroupIfNecessary(nscoord aYTotalOffset,
groupRect.y -= aYTotalOffset; groupRect.y -= aYTotalOffset;
groupRect.width = aWidth; groupRect.width = aWidth;
if (aYTotalOffset != 0) {
InvalidateOverflowRect();
}
SetRect(groupRect); SetRect(groupRect);
overflowArea.UnionRect(nsRect(0, 0, groupRect.width, groupRect.height), overflowArea.UnionRect(nsRect(0, 0, groupRect.width, groupRect.height),
overflowArea); overflowArea);
FinishAndStoreOverflow(&overflowArea, nsSize(groupRect.width, FinishAndStoreOverflow(&overflowArea, nsSize(groupRect.width,
groupRect.height)); groupRect.height));
nsTableFrame::RePositionViews(this); nsTableFrame::RePositionViews(this);
nsTableFrame::InvalidateFrame(this, oldGroupRect, PR_FALSE);
return yGroupOffset; return yGroupOffset;
} }
@ -880,8 +904,10 @@ nsTableRowGroupFrame::SlideChild(nsRowGroupReflowState& aReflowState,
nsPoint newPosition = oldPosition; nsPoint newPosition = oldPosition;
newPosition.y = aReflowState.y; newPosition.y = aReflowState.y;
if (oldPosition.y != newPosition.y) { if (oldPosition.y != newPosition.y) {
aKidFrame->InvalidateOverflowRect();
aKidFrame->SetPosition(newPosition); aKidFrame->SetPosition(newPosition);
nsTableFrame::RePositionViews(aKidFrame); nsTableFrame::RePositionViews(aKidFrame);
aKidFrame->InvalidateOverflowRect();
} }
} }
@ -1079,6 +1105,9 @@ nsTableRowGroupFrame::SplitRowGroup(nsPresContext* aPresContext,
rowReflowState.mFlags.mIsTopOfPage = isTopOfPage; // set top of page rowReflowState.mFlags.mIsTopOfPage = isTopOfPage; // set top of page
nsHTMLReflowMetrics rowMetrics; nsHTMLReflowMetrics rowMetrics;
// Get the old size before we reflow.
nsRect oldRowRect = rowFrame->GetRect();
// Reflow the cell with the constrained height. A cell with rowspan >1 will get this // Reflow the cell with the constrained height. A cell with rowspan >1 will get this
// reflow later during SplitSpanningCells. // reflow later during SplitSpanningCells.
rv = ReflowChild(rowFrame, aPresContext, rowMetrics, rowReflowState, rv = ReflowChild(rowFrame, aPresContext, rowMetrics, rowReflowState,
@ -1088,6 +1117,8 @@ nsTableRowGroupFrame::SplitRowGroup(nsPresContext* aPresContext,
rowFrame->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED); rowFrame->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
rowFrame->DidResize(); rowFrame->DidResize();
nsTableFrame::InvalidateFrame(rowFrame, oldRowRect, PR_FALSE);
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
// The row frame is incomplete and all of the rowspan 1 cells' block frames split // The row frame is incomplete and all of the rowspan 1 cells' block frames split
if ((rowMetrics.height <= rowReflowState.availableHeight) || isTopOfPage) { if ((rowMetrics.height <= rowReflowState.availableHeight) || isTopOfPage) {

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

@ -313,7 +313,8 @@ protected:
void PlaceChild(nsPresContext* aPresContext, void PlaceChild(nsPresContext* aPresContext,
nsRowGroupReflowState& aReflowState, nsRowGroupReflowState& aReflowState,
nsIFrame* aKidFrame, nsIFrame* aKidFrame,
nsHTMLReflowMetrics& aDesiredSize); nsHTMLReflowMetrics& aDesiredSize,
const nsRect& aOriginalKidRect);
void CalculateRowHeights(nsPresContext* aPresContext, void CalculateRowHeights(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize, nsHTMLReflowMetrics& aDesiredSize,