Bug 539356 - Make the table code use rect invalidation to avoid over invalidation. r=roc

This commit is contained in:
Matt Woodrow 2012-08-29 17:48:45 +12:00
parent 5eaaebce0e
commit 9a9168f55a
16 changed files with 330 additions and 36 deletions

View File

@ -472,6 +472,14 @@ nsFrameManager::RemoveFrame(ChildListID aListID,
bool wasDestroyingFrames = mIsDestroyingFrames; bool wasDestroyingFrames = mIsDestroyingFrames;
mIsDestroyingFrames = true; mIsDestroyingFrames = true;
// In case the reflow doesn't invalidate anything since it just leaves
// a gap where the old frame was, we invalidate it here. (This is
// reasonably likely to happen when removing a last child in a way
// that doesn't change the size of the parent.)
// This has to sure to invalidate the entire overflow rect; this
// is important in the presence of absolute positioning
aOldFrame->InvalidateFrameForRemoval();
NS_ASSERTION(!aOldFrame->GetPrevContinuation() || NS_ASSERTION(!aOldFrame->GetPrevContinuation() ||
// exception for nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames // exception for nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames
aOldFrame->GetType() == nsGkAtoms::textFrame, aOldFrame->GetType() == nsGkAtoms::textFrame,

View File

@ -4794,30 +4794,35 @@ nsIFrame::ClearInvalidationStateBits()
NS_FRAME_ALL_DESCENDANTS_NEED_PAINT); NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
} }
void static void InvalidateFrameInternal(nsIFrame *aFrame)
nsIFrame::InvalidateFrame()
{ {
AddStateBits(NS_FRAME_NEEDS_PAINT); aFrame->AddStateBits(NS_FRAME_NEEDS_PAINT);
nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(this); nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) { while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT); parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
parent = nsLayoutUtils::GetCrossDocParentFrame(parent); parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
} }
if (!parent) { if (!parent) {
SchedulePaint(); aFrame->SchedulePaint();
} }
if (HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) { if (aFrame->HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
Properties().Delete(InvalidationRect()); aFrame->Properties().Delete(nsIFrame::InvalidationRect());
RemoveStateBits(NS_FRAME_HAS_INVALID_RECT); aFrame->RemoveStateBits(NS_FRAME_HAS_INVALID_RECT);
} }
} }
void
nsIFrame::InvalidateFrame()
{
InvalidateFrameInternal(this);
}
void void
nsIFrame::InvalidateFrameWithRect(const nsRect& aRect) nsIFrame::InvalidateFrameWithRect(const nsRect& aRect)
{ {
bool alreadyInvalid = false; bool alreadyInvalid = false;
if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) { if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) {
InvalidateFrame(); InvalidateFrameInternal(this);
} else { } else {
alreadyInvalid = true; alreadyInvalid = true;
} }

View File

@ -2204,6 +2204,12 @@ public:
*/ */
void InvalidateFrameSubtree(); void InvalidateFrameSubtree();
/**
* Called when a frame is about to be removed and needs to be invalidated.
* Normally does nothing since DLBI handles removed frames.
*/
virtual void InvalidateFrameForRemoval() {}
/** /**
* Checks if a frame has had InvalidateFrame() called on it since the * Checks if a frame has had InvalidateFrame() called on it since the
* last paint. * last paint.

View File

@ -28,6 +28,7 @@
#include "nsDisplayList.h" #include "nsDisplayList.h"
#include "nsLayoutUtils.h" #include "nsLayoutUtils.h"
#include "nsTextFrame.h" #include "nsTextFrame.h"
#include "FrameLayerBuilder.h"
//TABLECELL SELECTION //TABLECELL SELECTION
#include "nsFrameSelection.h" #include "nsFrameSelection.h"
@ -396,6 +397,21 @@ nsDisplayTableCellBackground::GetBounds(nsDisplayListBuilder* aBuilder,
return nsDisplayItem::GetBounds(aBuilder, aSnap); return nsDisplayItem::GetBounds(aBuilder, aSnap);
} }
void nsTableCellFrame::InvalidateFrame(uint32_t aDisplayItemKey)
{
nsIFrame::InvalidateFrame(aDisplayItemKey);
GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
}
void nsTableCellFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
{
nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
// If we have filters applied that would affects our bounds, then
// we get an inactive layer created and this is computed
// within FrameLayerBuilder
GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
}
static void static void
PaintTableCellSelection(nsIFrame* aFrame, nsRenderingContext* aCtx, PaintTableCellSelection(nsIFrame* aFrame, nsRenderingContext* aCtx,
const nsRect& aRect, nsPoint aPt) const nsRect& aRect, nsPoint aPt)
@ -561,6 +577,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 = NS_MAX(0, kidYTop); kidYTop = NS_MAX(0, kidYTop);
if (kidYTop != kidRect.y) {
// Invalidate at the old position first
firstKid->InvalidateFrameSubtree();
}
firstKid->SetPosition(nsPoint(kidRect.x, kidYTop)); firstKid->SetPosition(nsPoint(kidRect.x, kidYTop));
nsHTMLReflowMetrics desiredSize; nsHTMLReflowMetrics desiredSize;
desiredSize.width = mRect.width; desiredSize.width = mRect.width;
@ -575,6 +596,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->InvalidateFrameSubtree();
} }
if (HasView()) { if (HasView()) {
nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this, nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this,
@ -865,6 +889,9 @@ NS_METHOD nsTableCellFrame::Reflow(nsPresContext* aPresContext,
} }
nsPoint kidOrigin(leftInset, topInset); nsPoint kidOrigin(leftInset, topInset);
nsRect origRect = firstKid->GetRect();
nsRect origVisualOverflow = firstKid->GetVisualOverflowRect();
bool firstReflow = (firstKid->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
ReflowChild(firstKid, aPresContext, kidSize, kidReflowState, ReflowChild(firstKid, aPresContext, kidSize, kidReflowState,
kidOrigin.x, kidOrigin.y, NS_FRAME_INVALIDATE_ON_MOVE, aStatus); kidOrigin.x, kidOrigin.y, NS_FRAME_INVALIDATE_ON_MOVE, aStatus);
@ -875,6 +902,11 @@ NS_METHOD nsTableCellFrame::Reflow(nsPresContext* aPresContext,
printf("Set table cell incomplete %p\n", static_cast<void*>(this)); printf("Set table cell incomplete %p\n", static_cast<void*>(this));
} }
// XXXbz is this invalidate actually needed, really?
if (GetStateBits() & NS_FRAME_IS_DIRTY) {
InvalidateFrameSubtree();
}
#ifdef DEBUG #ifdef DEBUG
DebugCheckChildSize(firstKid, kidSize, availSize); DebugCheckChildSize(firstKid, kidSize, availSize);
#endif #endif
@ -894,6 +926,9 @@ 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::InvalidateTableFrame(firstKid, origRect, origVisualOverflow,
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;
@ -926,6 +961,13 @@ NS_METHOD nsTableCellFrame::Reflow(nsPresContext* aPresContext,
} }
} }
// If our parent is in initial reflow, it'll handle invalidating our
// entire overflow rect.
if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
nsSize(aDesiredSize.width, aDesiredSize.height) != mRect.Size()) {
InvalidateFrame();
}
// remember the desired size for this reflow // remember the desired size for this reflow
SetDesiredSize(aDesiredSize); SetDesiredSize(aDesiredSize);

View File

@ -211,12 +211,9 @@ public:
virtual bool UpdateOverflow(); virtual bool UpdateOverflow();
virtual void InvalidateFrame() virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
{ virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
nsIFrame::InvalidateFrame(); virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); }
nsTableFrame *tableFrame = nsTableFrame::GetTableFrame(this);
tableFrame->InvalidateFrame();
}
protected: protected:
/** implement abstract method on nsContainerFrame */ /** implement abstract method on nsContainerFrame */

View File

@ -191,10 +191,20 @@ nsTableColFrame::GetSplittableType() const
} }
void void
nsTableColFrame::InvalidateFrame() nsTableColFrame::InvalidateFrame(uint32_t aDisplayItemKey)
{ {
nsIFrame::InvalidateFrame(); nsIFrame::InvalidateFrame(aDisplayItemKey);
nsTableFrame *tableFrame = nsTableFrame::GetTableFrame(this); GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
tableFrame->InvalidateFrame(); }
void
nsTableColFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
{
nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
// If we have filters applied that would affects our bounds, then
// we get an inactive layer created and this is computed
// within FrameLayerBuilder
GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
} }

View File

@ -264,7 +264,9 @@ public:
return mFinalWidth; return mFinalWidth;
} }
virtual void InvalidateFrame(); virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); }
protected: protected:

View File

@ -465,11 +465,20 @@ nsTableColGroupFrame::GetType() const
} }
void void
nsTableColGroupFrame::InvalidateFrame() nsTableColGroupFrame::InvalidateFrame(uint32_t aDisplayItemKey)
{ {
nsIFrame::InvalidateFrame(); nsIFrame::InvalidateFrame(aDisplayItemKey);
nsTableFrame *tableFrame = nsTableFrame::GetTableFrame(this); GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
tableFrame->InvalidateFrame(); }
void
nsTableColGroupFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
{
nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
// If we have filters applied that would affects our bounds, then
// we get an inactive layer created and this is computed
// within FrameLayerBuilder
GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
} }
#ifdef DEBUG #ifdef DEBUG

View File

@ -197,7 +197,9 @@ public:
void SetContinuousBCBorderWidth(uint8_t aForSide, void SetContinuousBCBorderWidth(uint8_t aForSide,
BCPixelSize aPixelValue); BCPixelSize aPixelValue);
virtual void InvalidateFrame(); virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); }
protected: protected:
nsTableColGroupFrame(nsStyleContext* aContext); nsTableColGroupFrame(nsStyleContext* aContext);

View File

@ -1391,7 +1391,7 @@ nsTableFrame::ProcessRowInserted(nscoord aNewHeight)
if (rowFrame->IsFirstInserted()) { if (rowFrame->IsFirstInserted()) {
rowFrame->SetFirstInserted(false); rowFrame->SetFirstInserted(false);
// damage the table from the 1st row inserted to the end of the table // damage the table from the 1st row inserted to the end of the table
InvalidateFrame(); nsIFrame::InvalidateFrame();
// XXXbz didn't we do this up front? Why do we need to do it again? // XXXbz didn't we do this up front? Why do we need to do it again?
SetRowInserted(false); SetRowInserted(false);
return; // found it, so leave return; // found it, so leave
@ -1806,6 +1806,11 @@ NS_METHOD nsTableFrame::Reflow(nsPresContext* aPresContext,
} }
aDesiredSize.mOverflowAreas.UnionAllWith(tableRect); aDesiredSize.mOverflowAreas.UnionAllWith(tableRect);
if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) ||
nsSize(aDesiredSize.width, aDesiredSize.height) != mRect.Size()) {
nsIFrame::InvalidateFrame();
}
FinishAndStoreOverflow(&aDesiredSize); FinishAndStoreOverflow(&aDesiredSize);
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
return rv; return rv;
@ -2491,10 +2496,16 @@ void nsTableFrame::PlaceChild(nsTableReflowState& aReflowState,
const nsRect& aOriginalKidRect, const nsRect& aOriginalKidRect,
const nsRect& aOriginalKidVisualOverflow) const nsRect& aOriginalKidVisualOverflow)
{ {
bool isFirstReflow =
(aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
// Place and size the child // Place and size the child
FinishReflowChild(aKidFrame, PresContext(), nullptr, aKidDesiredSize, FinishReflowChild(aKidFrame, PresContext(), nullptr, aKidDesiredSize,
aReflowState.x, aReflowState.y, 0); aReflowState.x, aReflowState.y, 0);
InvalidateTableFrame(aKidFrame, aOriginalKidRect, aOriginalKidVisualOverflow,
isFirstReflow);
// Adjust the running y-offset // Adjust the running y-offset
aReflowState.y += aKidDesiredSize.height; aReflowState.y += aKidDesiredSize.height;
@ -2929,9 +2940,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 the old position
kidFrame->InvalidateFrameSubtree();
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 the new position
kidFrame->InvalidateFrameSubtree();
} }
aReflowState.y += kidRect.height; aReflowState.y += kidRect.height;
@ -3105,13 +3120,18 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
amountUsedByRG += amountForRow; amountUsedByRG += amountForRow;
//rowFrame->DidResize(); //rowFrame->DidResize();
nsTableFrame::RePositionViews(rowFrame); nsTableFrame::RePositionViews(rowFrame);
rgFrame->InvalidateFrameWithRect(oldRowRect);
rgFrame->InvalidateFrame();
} }
} }
else { else {
if (amountUsed > 0 && yOriginRow != rowRect.y && if (amountUsed > 0 && yOriginRow != rowRect.y &&
!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { !(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
rowFrame->InvalidateFrameSubtree();
rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow)); rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow));
nsTableFrame::RePositionViews(rowFrame); nsTableFrame::RePositionViews(rowFrame);
rowFrame->InvalidateFrameSubtree();
} }
yOriginRow += rowRect.height + cellSpacingY; yOriginRow += rowRect.height + cellSpacingY;
yEndRG += rowRect.height + cellSpacingY; yEndRG += rowRect.height + cellSpacingY;
@ -3119,18 +3139,28 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
rowFrame = rowFrame->GetNextRow(); rowFrame = rowFrame->GetNextRow();
} }
if (amountUsed > 0) { if (amountUsed > 0) {
if (rgRect.y != yOriginRG) {
rgFrame->InvalidateFrameSubtree();
}
nsRect origRgRect = rgRect; nsRect origRgRect = rgRect;
nsRect origRgVisualOverflow = rgFrame->GetVisualOverflowRect();
rgRect.y = yOriginRG; rgRect.y = yOriginRG;
rgRect.height += amountUsedByRG; rgRect.height += amountUsedByRG;
rgFrame->SetRect(rgRect); rgFrame->SetRect(rgRect);
nsTableFrame::InvalidateTableFrame(rgFrame, origRgRect,
origRgVisualOverflow, false);
} }
} }
else if (amountUsed > 0 && yOriginRG != rgRect.y) { else if (amountUsed > 0 && yOriginRG != rgRect.y) {
rgFrame->InvalidateFrameSubtree();
rgFrame->SetPosition(nsPoint(rgRect.x, yOriginRG)); rgFrame->SetPosition(nsPoint(rgRect.x, yOriginRG));
// Make sure child views are properly positioned // Make sure child views are properly positioned
nsTableFrame::RePositionViews(rgFrame); nsTableFrame::RePositionViews(rgFrame);
rgFrame->InvalidateFrameSubtree();
} }
yOriginRG = yEndRG; yOriginRG = yEndRG;
} }
@ -3238,6 +3268,10 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
? aAmount - amountUsed : NSToCoordRound(((float)(heightToDistribute)) * ratio); ? aAmount - amountUsed : NSToCoordRound(((float)(heightToDistribute)) * ratio);
amountForRow = NS_MIN(amountForRow, aAmount - amountUsed); amountForRow = NS_MIN(amountForRow, aAmount - amountUsed);
if (yOriginRow != rowRect.y) {
rowFrame->InvalidateFrameSubtree();
}
// update the row height // update the row height
nsRect newRowRect(rowRect.x, yOriginRow, rowRect.width, nsRect newRowRect(rowRect.x, yOriginRow, rowRect.width,
rowRect.height + amountForRow); rowRect.height + amountForRow);
@ -3251,11 +3285,16 @@ 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::InvalidateTableFrame(rowFrame, rowRect, rowVisualOverflow,
false);
} }
else { else {
if (amountUsed > 0 && yOriginRow != rowRect.y) { if (amountUsed > 0 && yOriginRow != rowRect.y) {
rowFrame->InvalidateFrameSubtree();
rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow)); rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow));
nsTableFrame::RePositionViews(rowFrame); nsTableFrame::RePositionViews(rowFrame);
rowFrame->InvalidateFrameSubtree();
} }
yOriginRow += rowRect.height + cellSpacingY; yOriginRow += rowRect.height + cellSpacingY;
yEndRG += rowRect.height + cellSpacingY; yEndRG += rowRect.height + cellSpacingY;
@ -3263,15 +3302,24 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
rowFrame = rowFrame->GetNextRow(); rowFrame = rowFrame->GetNextRow();
} }
if (amountUsed > 0) { if (amountUsed > 0) {
if (rgRect.y != yOriginRG) {
rgFrame->InvalidateFrameSubtree();
}
rgFrame->SetRect(nsRect(rgRect.x, yOriginRG, rgRect.width, rgFrame->SetRect(nsRect(rgRect.x, yOriginRG, rgRect.width,
rgRect.height + amountUsedByRG)); rgRect.height + amountUsedByRG));
nsTableFrame::InvalidateTableFrame(rgFrame, rgRect, rgVisualOverflow,
false);
} }
// Make sure child views are properly positioned // Make sure child views are properly positioned
} }
else if (amountUsed > 0 && yOriginRG != rgRect.y) { else if (amountUsed > 0 && yOriginRG != rgRect.y) {
rgFrame->InvalidateFrameSubtree();
rgFrame->SetPosition(nsPoint(rgRect.x, yOriginRG)); rgFrame->SetPosition(nsPoint(rgRect.x, yOriginRG));
// Make sure child views are properly positioned // Make sure child views are properly positioned
nsTableFrame::RePositionViews(rgFrame); nsTableFrame::RePositionViews(rgFrame);
rgFrame->InvalidateFrameSubtree();
} }
yOriginRG = yEndRG; yOriginRG = yEndRG;
} }
@ -7183,3 +7231,45 @@ bool nsTableFrame::RowIsSpannedInto(int32_t aRowIndex, int32_t aNumEffCols)
} }
return result; return result;
} }
/* static */
void
nsTableFrame::InvalidateTableFrame(nsIFrame* aFrame,
const nsRect& aOrigRect,
const nsRect& aOrigVisualOverflow,
bool 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;
}
// The part that looks at both the rect and the overflow rect is a
// bit of a hack. See nsBlockFrame::ReflowLine for an eloquent
// description of its hackishness.
//
// This doesn't really make sense now that we have DLBI.
// This code can probably be simplified a fair bit.
nsRect visualOverflow = aFrame->GetVisualOverflowRect();
if (aIsFirstReflow ||
aOrigRect.TopLeft() != aFrame->GetPosition() ||
aOrigVisualOverflow.TopLeft() != visualOverflow.TopLeft()) {
// Invalidate the old and new overflow rects. Note that if the
// frame moved, we can't just use aOrigVisualOverflow, since it's in
// coordinates relative to the old position. So invalidate via
// aFrame's parent, and reposition that overflow rect to the right
// place.
// XXXbz this doesn't handle outlines, does it?
aFrame->InvalidateFrame();
parent->InvalidateFrameWithRect(aOrigVisualOverflow + aOrigRect.TopLeft());
} else {
aFrame->InvalidateFrameWithRect(aOrigVisualOverflow);;
aFrame->InvalidateFrame();
parent->InvalidateFrameWithRect(aOrigRect);;
parent->InvalidateFrame();
}
}

View File

@ -464,6 +464,23 @@ public:
bool HasCellSpanningPctCol() const; bool HasCellSpanningPctCol() const;
void SetHasCellSpanningPctCol(bool aValue); void SetHasCellSpanningPctCol(bool 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 reflowed 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 aOrigVisualOverflow The original overflow rect of aFrame.
* @param aIsFirstReflow True if the size/position change is due to the
* first reflow of aFrame.
*/
static void InvalidateTableFrame(nsIFrame* aFrame,
const nsRect& aOrigRect,
const nsRect& aOrigVisualOverflow,
bool aIsFirstReflow);
virtual bool UpdateOverflow(); virtual bool UpdateOverflow();
protected: protected:

View File

@ -916,6 +916,21 @@ NS_METHOD nsTableOuterFrame::Reflow(nsPresContext* aPresContext,
nsHTMLReflowState *innerRS = nsHTMLReflowState *innerRS =
static_cast<nsHTMLReflowState*>((void*) innerRSSpace); static_cast<nsHTMLReflowState*>((void*) innerRSSpace);
nsRect origInnerRect = InnerTableFrame()->GetRect();
nsRect origInnerVisualOverflow = InnerTableFrame()->GetVisualOverflowRect();
bool innerFirstReflow =
(InnerTableFrame()->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
nsRect origCaptionRect;
nsRect origCaptionVisualOverflow;
bool captionFirstReflow;
if (mCaptionFrames.NotEmpty()) {
origCaptionRect = mCaptionFrames.FirstChild()->GetRect();
origCaptionVisualOverflow =
mCaptionFrames.FirstChild()->GetVisualOverflowRect();
captionFirstReflow =
(mCaptionFrames.FirstChild()->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
}
// ComputeAutoSize has to match this logic. // ComputeAutoSize has to match this logic.
if (captionSide == NO_SIDE) { if (captionSide == NO_SIDE) {
// We don't have a caption. // We don't have a caption.
@ -1037,6 +1052,14 @@ NS_METHOD nsTableOuterFrame::Reflow(nsPresContext* aPresContext,
innerOrigin.x, innerOrigin.y, 0); innerOrigin.x, innerOrigin.y, 0);
innerRS->~nsHTMLReflowState(); innerRS->~nsHTMLReflowState();
nsTableFrame::InvalidateTableFrame(InnerTableFrame(), origInnerRect,
origInnerVisualOverflow, innerFirstReflow);
if (mCaptionFrames.NotEmpty()) {
nsTableFrame::InvalidateTableFrame(mCaptionFrames.FirstChild(), origCaptionRect,
origCaptionVisualOverflow,
captionFirstReflow);
}
UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, captionMargin); UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, captionMargin);
FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aOuterRS, aStatus); FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aOuterRS, aStatus);

View File

@ -335,9 +335,13 @@ nsTableRowFrame::DidResize()
// resize the cell's height // resize the cell's height
nsRect cellRect = cellFrame->GetRect(); nsRect cellRect = cellFrame->GetRect();
nsRect cellVisualOverflow = cellFrame->GetVisualOverflowRect();
if (cellRect.height != cellHeight) if (cellRect.height != cellHeight)
{ {
cellFrame->SetSize(nsSize(cellRect.width, cellHeight)); cellFrame->SetSize(nsSize(cellRect.width, cellHeight));
nsTableFrame::InvalidateTableFrame(cellFrame, cellRect,
cellVisualOverflow,
false);
} }
// realign cell content based on the new height. We might be able to // realign cell content based on the new height. We might be able to
@ -834,6 +838,9 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext,
// Reflow the child frame // Reflow the child frame
nsRect kidRect = kidFrame->GetRect(); nsRect kidRect = kidFrame->GetRect();
nsRect kidVisualOverflow = kidFrame->GetVisualOverflowRect();
bool 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
@ -923,6 +930,9 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext,
FinishReflowChild(kidFrame, aPresContext, nullptr, desiredSize, x, 0, 0); FinishReflowChild(kidFrame, aPresContext, nullptr, desiredSize, x, 0, 0);
nsTableFrame::InvalidateTableFrame(kidFrame, kidRect, kidVisualOverflow,
firstReflow);
x += desiredSize.width; x += desiredSize.width;
} }
else { else {
@ -1016,6 +1026,13 @@ nsTableRowFrame::Reflow(nsPresContext* aPresContext,
// just set our width to what was available. The table will calculate the width and not use our value. // just set our width to what was available. The table will calculate the width and not use our value.
aDesiredSize.width = aReflowState.availableWidth; aDesiredSize.width = aReflowState.availableWidth;
// If our parent is in initial reflow, it'll handle invalidating our
// entire overflow rect.
if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
nsSize(aDesiredSize.width, aDesiredSize.height) != mRect.Size()) {
InvalidateFrame();
}
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
return rv; return rv;
} }
@ -1062,6 +1079,11 @@ nsTableRowFrame::ReflowCellFrame(nsPresContext* aPresContext,
aCellFrame->VerticallyAlignChild(mMaxCellAscent); aCellFrame->VerticallyAlignChild(mMaxCellAscent);
} }
nsTableFrame::InvalidateTableFrame(aCellFrame, cellRect,
cellVisualOverflow,
(aCellFrame->GetStateBits() &
NS_FRAME_FIRST_REFLOW) != 0);
aCellFrame->DidReflow(aPresContext, nullptr, NS_FRAME_REFLOW_FINISHED); aCellFrame->DidReflow(aPresContext, nullptr, NS_FRAME_REFLOW_FINISHED);
return desiredSize.height; return desiredSize.height;
@ -1087,6 +1109,8 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
} }
nsRect rowRect = GetRect(); nsRect rowRect = GetRect();
nsRect oldRect = rowRect;
nsRect oldVisualOverflow = GetVisualOverflowRect();
rowRect.y -= aRowOffset; rowRect.y -= aRowOffset;
rowRect.width = aWidth; rowRect.width = aWidth;
@ -1215,6 +1239,12 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
nsSize(cRect.width, cRect.height)); nsSize(cRect.width, cRect.height));
nsTableFrame::RePositionViews(cellFrame); nsTableFrame::RePositionViews(cellFrame);
ConsiderChildOverflow(overflow, cellFrame); ConsiderChildOverflow(overflow, cellFrame);
if (aRowOffset == 0) {
nsTableFrame::InvalidateTableFrame(cellFrame, oldCellRect,
oldCellVisualOverflow,
false);
}
} }
kidFrame = iter.Next(); // Get the next child kidFrame = iter.Next(); // Get the next child
} }
@ -1225,6 +1255,7 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
FinishAndStoreOverflow(overflow, nsSize(rowRect.width, rowRect.height)); FinishAndStoreOverflow(overflow, nsSize(rowRect.width, rowRect.height));
nsTableFrame::RePositionViews(this); nsTableFrame::RePositionViews(this);
nsTableFrame::InvalidateTableFrame(this, oldRect, oldVisualOverflow, false);
return shift; return shift;
} }
@ -1352,11 +1383,20 @@ void nsTableRowFrame::InitHasCellWithStyleHeight(nsTableFrame* aTableFrame)
} }
void void
nsTableRowFrame::InvalidateFrame() nsTableRowFrame::InvalidateFrame(uint32_t aDisplayItemKey)
{ {
nsIFrame::InvalidateFrame(); nsIFrame::InvalidateFrame(aDisplayItemKey);
nsTableFrame *tableFrame = nsTableFrame::GetTableFrame(this); GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
tableFrame->InvalidateFrame(); }
void
nsTableRowFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
{
nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
// If we have filters applied that would affects our bounds, then
// we get an inactive layer created and this is computed
// within FrameLayerBuilder
GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
} }
/* ----- global methods ----- */ /* ----- global methods ----- */

View File

@ -224,7 +224,9 @@ public:
void SetContinuousBCBorderWidth(uint8_t aForSide, void SetContinuousBCBorderWidth(uint8_t aForSide,
BCPixelSize aPixelValue); BCPixelSize aPixelValue);
virtual void InvalidateFrame(); virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); }
#ifdef ACCESSIBILITY #ifdef ACCESSIBILITY
virtual already_AddRefed<Accessible> CreateAccessible() MOZ_OVERRIDE; virtual already_AddRefed<Accessible> CreateAccessible() MOZ_OVERRIDE;

View File

@ -254,10 +254,16 @@ nsTableRowGroupFrame::PlaceChild(nsPresContext* aPresContext,
const nsRect& aOriginalKidRect, const nsRect& aOriginalKidRect,
const nsRect& aOriginalKidVisualOverflow) const nsRect& aOriginalKidVisualOverflow)
{ {
bool isFirstReflow =
(aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
// Place and size the child // Place and size the child
FinishReflowChild(aKidFrame, aPresContext, nullptr, aDesiredSize, 0, FinishReflowChild(aKidFrame, aPresContext, nullptr, aDesiredSize, 0,
aReflowState.y, 0); aReflowState.y, 0);
nsTableFrame::InvalidateTableFrame(aKidFrame, aOriginalKidRect,
aOriginalKidVisualOverflow, isFirstReflow);
// Adjust the running y-offset // Adjust the running y-offset
aReflowState.y += aDesiredSize.height; aReflowState.y += aDesiredSize.height;
@ -743,6 +749,7 @@ nsTableRowGroupFrame::CalculateRowHeights(nsPresContext* aPresContext,
// update the rows with their (potentially) new heights // update the rows with their (potentially) new heights
for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) { for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
nsRect rowBounds = rowFrame->GetRect(); nsRect rowBounds = rowFrame->GetRect();
nsRect rowVisualOverflow = rowFrame->GetVisualOverflowRect();
bool movedFrame = (rowBounds.y != yOrigin); bool movedFrame = (rowBounds.y != yOrigin);
nscoord rowHeight = (rowInfo[rowIndex].height > 0) ? rowInfo[rowIndex].height : 0; nscoord rowHeight = (rowInfo[rowIndex].height > 0) ? rowInfo[rowIndex].height : 0;
@ -755,6 +762,9 @@ nsTableRowGroupFrame::CalculateRowHeights(nsPresContext* aPresContext,
rowFrame->SetRect(nsRect(rowBounds.x, yOrigin, rowBounds.width, rowFrame->SetRect(nsRect(rowBounds.x, yOrigin, rowBounds.width,
rowHeight)); rowHeight));
nsTableFrame::InvalidateTableFrame(rowFrame, rowBounds, rowVisualOverflow,
false);
} }
if (movedFrame) { if (movedFrame) {
nsTableFrame::RePositionViews(rowFrame); nsTableFrame::RePositionViews(rowFrame);
@ -798,6 +808,8 @@ nsTableRowGroupFrame::CollapseRowGroupIfNecessary(nscoord aYTotalOffset,
} }
nsRect groupRect = GetRect(); nsRect groupRect = GetRect();
nsRect oldGroupRect = groupRect;
nsRect oldGroupVisualOverflow = GetVisualOverflowRect();
groupRect.height -= yGroupOffset; groupRect.height -= yGroupOffset;
if (didCollapse) { if (didCollapse) {
@ -816,6 +828,9 @@ nsTableRowGroupFrame::CollapseRowGroupIfNecessary(nscoord aYTotalOffset,
overflow.UnionAllWith(nsRect(0, 0, groupRect.width, groupRect.height)); overflow.UnionAllWith(nsRect(0, 0, groupRect.width, groupRect.height));
FinishAndStoreOverflow(overflow, nsSize(groupRect.width, groupRect.height)); FinishAndStoreOverflow(overflow, nsSize(groupRect.width, groupRect.height));
nsTableFrame::RePositionViews(this); nsTableFrame::RePositionViews(this);
nsTableFrame::InvalidateTableFrame(this, oldGroupRect, oldGroupVisualOverflow,
false);
return yGroupOffset; return yGroupOffset;
} }
@ -1052,6 +1067,10 @@ 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();
nsRect oldRowVisualOverflow = rowFrame->GetVisualOverflowRect();
// 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,
@ -1061,6 +1080,10 @@ nsTableRowGroupFrame::SplitRowGroup(nsPresContext* aPresContext,
rowFrame->DidReflow(aPresContext, nullptr, NS_FRAME_REFLOW_FINISHED); rowFrame->DidReflow(aPresContext, nullptr, NS_FRAME_REFLOW_FINISHED);
rowFrame->DidResize(); rowFrame->DidResize();
nsTableFrame::InvalidateTableFrame(rowFrame, oldRowRect,
oldRowVisualOverflow,
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) {
@ -1288,6 +1311,13 @@ nsTableRowGroupFrame::Reflow(nsPresContext* aPresContext,
aDesiredSize.UnionOverflowAreasWithDesiredBounds(); aDesiredSize.UnionOverflowAreasWithDesiredBounds();
// If our parent is in initial reflow, it'll handle invalidating our
// entire overflow rect.
if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
nsSize(aDesiredSize.width, aDesiredSize.height) != mRect.Size()) {
InvalidateFrame();
}
FinishAndStoreOverflow(&aDesiredSize); FinishAndStoreOverflow(&aDesiredSize);
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
return rv; return rv;
@ -1843,9 +1873,18 @@ nsTableRowGroupFrame::FrameCursorData::AppendFrame(nsIFrame* aFrame)
} }
void void
nsTableRowGroupFrame::InvalidateFrame() nsTableRowGroupFrame::InvalidateFrame(uint32_t aDisplayItemKey)
{ {
nsIFrame::InvalidateFrame(); nsIFrame::InvalidateFrame(aDisplayItemKey);
nsTableFrame *tableFrame = nsTableFrame::GetTableFrame(this); GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
tableFrame->InvalidateFrame(); }
void
nsTableRowGroupFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
{
nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
// If we have filters applied that would affects our bounds, then
// we get an inactive layer created and this is computed
// within FrameLayerBuilder
GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
} }

View File

@ -325,7 +325,9 @@ public:
virtual nsILineIterator* GetLineIterator() { return this; } virtual nsILineIterator* GetLineIterator() { return this; }
virtual void InvalidateFrame(); virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); }
protected: protected:
nsTableRowGroupFrame(nsStyleContext* aContext); nsTableRowGroupFrame(nsStyleContext* aContext);