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

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

@ -743,6 +743,11 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame,
aKidFrame->WillReflow(aPresContext);
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));
}

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

@ -60,6 +60,9 @@
#define NS_FRAME_NO_MOVE_FRAME (0x0002 | NS_FRAME_NO_MOVE_VIEW)
#define NS_FRAME_NO_SIZE_VIEW 0x0004
#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;

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

@ -3600,6 +3600,21 @@ nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
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
nsIFrame::InvalidateRoot(const nsRect& aDamageRect,
nscoord aX, nscoord aY, PRBool aImmediate)

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

@ -1655,6 +1655,21 @@ public:
nscoord aOffsetX, nscoord aOffsetY,
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
* 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
kidYTop = PR_MAX(0, kidYTop);
if (kidYTop != kidRect.y) {
// Invalidate at the old position first
firstKid->InvalidateOverflowRect();
}
firstKid->SetPosition(nsPoint(kidRect.x, kidYTop));
nsHTMLReflowMetrics desiredSize;
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
// cell won't have a view
nsContainerFrame::PositionChildViews(firstKid);
// Invalidate new overflow rect
firstKid->InvalidateOverflowRect();
}
if (HasView()) {
nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this,
@ -861,15 +869,19 @@ NS_METHOD nsTableCellFrame::Reflow(nsPresContext* aPresContext,
}
nsPoint kidOrigin(leftInset, topInset);
nsRect origRect = firstKid->GetRect();
PRBool firstReflow = (firstKid->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
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)) {
// 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)
NS_FRAME_SET_INCOMPLETE(aStatus);
printf("Set table cell incomplete %p\n", this);
}
// XXXbz is this invalidate actually needed, really?
if (GetStateBits() & NS_FRAME_IS_DIRTY) {
Invalidate(GetOverflowRect(), PR_FALSE);
}
@ -885,6 +897,8 @@ NS_METHOD nsTableCellFrame::Reflow(nsPresContext* aPresContext,
// Place the child
FinishReflowChild(firstKid, aPresContext, &kidReflowState, kidSize,
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
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);
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
return rv;
@ -2578,13 +2583,18 @@ nsTableFrame::InitChildReflowState(nsHTMLReflowState& aReflowState)
// aKidRect is relative to the upper-left origin of our frame
void nsTableFrame::PlaceChild(nsTableReflowState& aReflowState,
nsIFrame* aKidFrame,
nsHTMLReflowMetrics& aKidDesiredSize)
nsHTMLReflowMetrics& aKidDesiredSize,
const nsRect& aOriginalKidRect)
{
PRBool isFirstReflow =
(aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
// Place and size the child
FinishReflowChild(aKidFrame, PresContext(), nsnull, aKidDesiredSize,
aReflowState.x, aReflowState.y, 0);
InvalidateFrame(aKidFrame, aOriginalKidRect, isFirstReflow);
// Adjust the running y-offset
aReflowState.y += aKidDesiredSize.height;
@ -2934,9 +2944,10 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
PRBool reorder = PR_FALSE;
if (kidFrame->GetNextInFlow())
reorder = PR_TRUE;
rv = ReflowChild(kidFrame, presContext, desiredSize, kidReflowState,
aReflowState.x, aReflowState.y, 0, aStatus);
aReflowState.x, aReflowState.y,
NS_FRAME_INVALIDATE_ON_MOVE, aStatus);
if (reorder) {
// reorder row groups the reflow may have changed the nextinflows
@ -2957,7 +2968,7 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
if (childX+1 < rowGroups.Length()) {
nsIFrame* nextRowGroupFrame = rowGroups[childX + 1];
if (nextRowGroupFrame) {
PlaceChild(aReflowState, kidFrame, desiredSize);
PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect);
aStatus = NS_FRAME_NOT_COMPLETE;
PushChildren(rowGroups, childX + 1);
aLastChildReflowed = kidFrame;
@ -2988,7 +2999,7 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
}
// Place the child
PlaceChild(aReflowState, kidFrame, desiredSize);
PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect);
// Remember where we just were in case we end up pushing children
prevKidFrame = kidFrame;
@ -3036,10 +3047,14 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
-1, -1, PR_FALSE);
InitChildReflowState(footerReflowState);
aReflowState.y += cellSpacingY;
nsRect origTfootRect = tfoot->GetRect();
nsReflowStatus footerStatus;
rv = ReflowChild(tfoot, presContext, desiredSize, footerReflowState,
aReflowState.x, aReflowState.y, 0, footerStatus);
PlaceChild(aReflowState, tfoot, desiredSize);
aReflowState.x, aReflowState.y,
NS_FRAME_INVALIDATE_ON_MOVE, footerStatus);
PlaceChild(aReflowState, tfoot, desiredSize, origTfootRect);
}
break;
}
@ -3048,11 +3063,13 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
aReflowState.y += cellSpacingY;
nsRect kidRect = kidFrame->GetRect();
if (kidRect.y != aReflowState.y) {
Invalidate(kidRect); // invalidate the old position
// invalidate the old position
kidFrame->InvalidateOverflowRect();
kidRect.y = aReflowState.y;
kidFrame->SetRect(kidRect); // move to the new position
RePositionViews(kidFrame);
Invalidate(kidRect); // invalidate the new position
// invalidate the new position
kidFrame->InvalidateOverflowRect();
}
aReflowState.y += kidRect.height;
@ -3226,7 +3243,9 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
nscoord pctHeight = rowFrame->GetHeight(pctBasis);
nscoord amountForRow = PR_MIN(aAmount - amountUsed, pctHeight - rowRect.height);
if (amountForRow > 0) {
nsRect oldRowRect = rowRect;
rowRect.height += amountForRow;
// XXXbz we don't need to change rowRect.y to be yOriginRow?
rowFrame->SetRect(rowRect);
yOriginRow += rowRect.height + cellSpacingY;
yEndRG += rowRect.height + cellSpacingY;
@ -3234,12 +3253,17 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
amountUsedByRG += amountForRow;
//rowFrame->DidResize();
nsTableFrame::RePositionViews(rowFrame);
rgFrame->InvalidateRectDifference(oldRowRect, rowRect);
}
}
else {
if (amountUsed > 0) {
if (amountUsed > 0 && yOriginRow != rowRect.y &&
!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
rowFrame->InvalidateOverflowRect();
rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow));
nsTableFrame::RePositionViews(rowFrame);
rowFrame->InvalidateOverflowRect();
}
yOriginRow += rowRect.height + cellSpacingY;
yEndRG += rowRect.height + cellSpacingY;
@ -3247,15 +3271,27 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
rowFrame = rowFrame->GetNextRow();
}
if (amountUsed > 0) {
if (rgRect.y != yOriginRG) {
rgFrame->InvalidateOverflowRect();
}
nsRect origRgRect = rgRect;
rgRect.y = yOriginRG;
rgRect.height += amountUsedByRG;
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));
// Make sure child views are properly positioned
nsTableFrame::RePositionViews(rgFrame);
rgFrame->InvalidateOverflowRect();
}
yOriginRG = yEndRG;
}
@ -3360,9 +3396,16 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
nscoord amountForRow = (rowFrame == lastEligibleRow)
? aAmount - amountUsed : NSToCoordRound(((float)(heightToDistribute)) * ratio);
amountForRow = PR_MIN(amountForRow, aAmount - amountUsed);
if (yOriginRow != rowRect.y) {
rowFrame->InvalidateOverflowRect();
}
// 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);
yOriginRow += newRowRect.height + cellSpacingY;
yEndRG += newRowRect.height + cellSpacingY;
@ -3371,11 +3414,15 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
NS_ASSERTION((amountUsed <= aAmount), "invalid row allocation");
//rowFrame->DidResize();
nsTableFrame::RePositionViews(rowFrame);
nsTableFrame::InvalidateFrame(rowFrame, rowRect, PR_FALSE);
}
else {
if (amountUsed > 0) {
if (amountUsed > 0 && yOriginRow != rowRect.y) {
rowFrame->InvalidateOverflowRect();
rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow));
nsTableFrame::RePositionViews(rowFrame);
rowFrame->InvalidateOverflowRect();
}
yOriginRow += rowRect.height + cellSpacingY;
yEndRG += rowRect.height + cellSpacingY;
@ -3383,17 +3430,25 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
rowFrame = rowFrame->GetNextRow();
}
if (amountUsed > 0) {
rgRect.y = yOriginRG;
rgRect.height += amountUsedByRG;
rgFrame->SetRect(rgRect);
if (rgRect.y != yOriginRG) {
rgFrame->InvalidateOverflowRect();
}
rgFrame->SetRect(nsRect(rgRect.x, yOriginRG, rgRect.width,
rgRect.height + amountUsedByRG));
nsTableFrame::InvalidateFrame(rgFrame, rgRect, PR_FALSE);
}
// Make sure child views are properly positioned
// 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));
// Make sure child views are properly positioned
nsTableFrame::RePositionViews(rgFrame);
rgFrame->InvalidateOverflowRect();
}
yOriginRG = yEndRG;
}
@ -6718,6 +6773,27 @@ nsTableFrame::GetProperty(nsIFrame* aFrame,
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
#define MAX_SIZE 128
#define MIN_INDENT 30

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

@ -480,6 +480,20 @@ public:
PRBool HasCellSpanningPctCol() const;
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 constructor.
@ -567,7 +581,8 @@ protected:
void PlaceChild(nsTableReflowState& aReflowState,
nsIFrame* aKidFrame,
nsHTMLReflowMetrics& aKidDesiredSize);
nsHTMLReflowMetrics& aKidDesiredSize,
const nsRect& aOriginalKidRect);
nsIFrame* GetFirstBodyRowGroupFrame();
PRBool MoveOverflowToChildList(nsPresContext* aPresContext);

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

@ -353,15 +353,23 @@ nsTableRowFrame::DidResize()
nscoord cellHeight = mRect.height + GetHeightOfRowsSpannedBelowFirst(*cellFrame, *tableFrame);
// resize the cell's height
//if (cellFrameSize.height!=cellHeight)
nsRect cellRect = cellFrame->GetRect();
if (cellRect.height != cellHeight)
{
cellFrame->SetSize(nsSize(cellFrame->GetSize().width, cellHeight));
// realign cell content based on the new height
cellFrame->VerticallyAlignChild(mMaxCellAscent);
ConsiderChildOverflow(desiredSize.mOverflowArea, cellFrame);
// Note that if the cell's *content* needs to change in response
// to this height, it will get a special height reflow.
cellFrame->SetSize(nsSize(cellRect.width, cellHeight));
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);
// 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);
// Note that if the cell's *content* needs to change in response
// to this height, it will get a special height reflow.
}
// Get the next child
childFrame = iter.Next();
@ -855,6 +863,10 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext,
prevColIndex = (iter.IsLeftToRight()) ? cellColIndex + (cellColSpan - 1) : cellColIndex;
// Reflow the child frame
nsRect kidRect = kidFrame->GetRect();
PRBool firstReflow =
(kidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
if (doReflowChild) {
// Calculate the available width for the table cell using the known column widths
nscoord availColWidth, availCellWidth;
@ -889,7 +901,7 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext,
nsReflowStatus status;
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
// If any of the cells are not complete, then we're not complete
@ -898,6 +910,10 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext,
}
}
else {
if (x != kidRect.x) {
kidFrame->InvalidateOverflowRect();
}
desiredSize.width = cellDesiredSize.width;
desiredSize.height = cellDesiredSize.height;
nsRect *overflowArea =
@ -949,17 +965,20 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext,
}
FinishReflowChild(kidFrame, aPresContext, nsnull, desiredSize, x, 0, 0);
nsTableFrame::InvalidateFrame(kidFrame, kidRect, firstReflow);
x += desiredSize.width;
}
else {
nsRect kidRect = kidFrame->GetRect();
if (kidRect.x != x) {
Invalidate(kidRect); // invalidate the old position
kidRect.x = x;
kidFrame->SetRect(kidRect); // move to the new position
// Invalidate the old position
kidFrame->InvalidateOverflowRect();
// move to the new position
kidFrame->SetPosition(nsPoint(x, kidRect.y));
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
x += kidRect.width;
@ -1066,9 +1085,9 @@ nsTableRowFrame::ReflowCellFrame(nsPresContext* aPresContext,
ABORT1(NS_ERROR_NULL_POINTER);
// 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();
nsTableCellReflowState cellReflowState(aPresContext, aReflowState,
aCellFrame, availSize, PR_FALSE);
@ -1083,8 +1102,12 @@ nsTableRowFrame::ReflowCellFrame(nsPresContext* aPresContext,
if (fullyComplete) {
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 Why is it assumed that the cell's ascent hasn't changed ?
if (fullyComplete) {
@ -1110,7 +1133,14 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
tableFrame->SetNeedToCollapse(PR_TRUE);
}
if (aRowOffset != 0) {
// We're moving, so invalidate our old position
InvalidateOverflowRect();
}
nsRect rowRect = GetRect();
nsRect oldRect = rowRect;
rowRect.y -= aRowOffset;
rowRect.width = aWidth;
nsRect overflowArea(0, 0, 0, 0);
@ -1124,6 +1154,13 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
shift = rowRect.height + cellSpacingY;
while (cellFrame) {
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;
cellFrame->SetRect(cRect);
cellFrame = cellFrame->GetNextCell();
@ -1161,7 +1198,7 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
*tableFrame, cellSpacingX, iter.IsLeftToRight(),
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
// spans into
@ -1216,23 +1253,40 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
}
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);
// XXXbz This looks completely bogus in the cases when we didn't
// collapse the cell!
nsRect cellOverflow = nsRect(0, 0, cRect.width, cRect.height);
cellFrame->FinishAndStoreOverflow(&cellOverflow, nsSize(cRect.width,
cRect.height));
nsTableFrame::RePositionViews(cellFrame);
ConsiderChildOverflow(overflowArea, cellFrame);
if (aRowOffset == 0) {
nsTableFrame::InvalidateFrame(cellFrame, oldCellRect, PR_FALSE);
}
}
kidFrame = iter.Next(); // Get the next child
}
}
SetRect(rowRect);
overflowArea.UnionRect(nsRect(0,0,rowRect.width, rowRect.height),
overflowArea);
FinishAndStoreOverflow(&overflowArea, nsSize(rowRect.width,
rowRect.height));
nsTableFrame::RePositionViews(this);
nsTableFrame::InvalidateFrame(this, oldRect, PR_FALSE);
return shift;
}

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

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

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

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