Bug 269905. Remember emptiness state on line boxes, but be selective about to to minimize the invalidation burden. r+sr=dbaron

This commit is contained in:
roc+%cs.cmu.edu 2004-11-24 13:22:10 +00:00
Родитель 471522f868
Коммит 352f29c25c
6 изменённых файлов: 80 добавлений и 12 удалений

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

@ -2211,7 +2211,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
// and also because our final height may depend on it. Only // and also because our final height may depend on it. Only
// update mY if the line is not empty, because that's what // update mY if the line is not empty, because that's what
// PlaceLine does. // PlaceLine does.
if (!line->IsEmpty()) { if (!line->CachedIsEmpty()) {
aState.mY = line->mBounds.YMost(); aState.mY = line->mBounds.YMost();
// This will include any pending float clearing height, so // This will include any pending float clearing height, so
// don't bother clearing previous lines' floats // don't bother clearing previous lines' floats
@ -2483,6 +2483,7 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
// Setup the line-layout for the new line // Setup the line-layout for the new line
aState.mCurrentLine = aLine; aState.mCurrentLine = aLine;
aLine->ClearDirty(); aLine->ClearDirty();
aLine->InvalidateCachedIsEmpty();
// Now that we know what kind of line we have, reflow it // Now that we know what kind of line we have, reflow it
if (aLine->IsBlock()) { if (aLine->IsBlock()) {
@ -3027,7 +3028,7 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
// Determine if this line is "essentially" the first line // Determine if this line is "essentially" the first line
for (line_iterator line = begin_lines(); line != aLine; ++line) { for (line_iterator line = begin_lines(); line != aLine; ++line) {
if (!line->IsEmpty()) { if (!line->CachedIsEmpty()) {
// A line which preceeds aLine is non-empty, so therefore the // A line which preceeds aLine is non-empty, so therefore the
// top margin applies. // top margin applies.
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE); aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
@ -3053,7 +3054,7 @@ nsBlockFrame::GetTopBlockChild(nsPresContext* aPresContext)
if (firstLine->IsBlock()) if (firstLine->IsBlock())
return firstLine->mFirstChild; return firstLine->mFirstChild;
if (!firstLine->IsEmpty()) if (!firstLine->CachedIsEmpty())
return nsnull; return nsnull;
line_iterator secondLine = begin_lines(); line_iterator secondLine = begin_lines();
@ -4195,7 +4196,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
// collapsed with a block that follows. // collapsed with a block that follows.
nscoord newY; nscoord newY;
if (!aLine->IsEmpty()) { if (!aLine->CachedIsEmpty()) {
// This line has some height. Therefore the application of the // This line has some height. Therefore the application of the
// previous-bottom-margin should stick. // previous-bottom-margin should stick.
aState.mPrevBottomMargin.Zero(); aState.mPrevBottomMargin.Zero();

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

@ -288,6 +288,23 @@ nsLineBox::IsEmpty() const
return PR_TRUE; return PR_TRUE;
} }
PRBool
nsLineBox::CachedIsEmpty()
{
if (mFlags.mDirty) {
return IsEmpty();
}
if (mFlags.mEmptyCacheValid) {
return mFlags.mEmptyCacheState;
}
PRBool result = IsEmpty();
mFlags.mEmptyCacheValid = PR_TRUE;
mFlags.mEmptyCacheState = result;
return result;
}
void void
nsLineBox::DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines) nsLineBox::DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines)
{ {

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

@ -400,6 +400,20 @@ public:
// whether the line box is "logically" empty (just like nsIFrame::IsEmpty) // whether the line box is "logically" empty (just like nsIFrame::IsEmpty)
PRBool IsEmpty() const; PRBool IsEmpty() const;
// Call this only while in Reflow() for the block the line belongs
// to, only between reflowing the line (or sliding it, if we skip
// reflowing it) and the end of reflowing the the block.
PRBool CachedIsEmpty();
void InvalidateCachedIsEmpty() {
mFlags.mEmptyCacheValid = PR_FALSE;
}
// For debugging purposes
PRBool IsValidCachedIsEmpty() {
return mFlags.mEmptyCacheValid;
}
#ifdef DEBUG #ifdef DEBUG
static PRInt32 GetCtorCount(); static PRInt32 GetCtorCount();
#endif #endif
@ -418,9 +432,11 @@ public:
PRUint32 mHasPercentageChild : 1; PRUint32 mHasPercentageChild : 1;
PRUint32 mLineWrapped: 1; PRUint32 mLineWrapped: 1;
PRUint32 mResizeReflowOptimizationDisabled: 1; // default 0 = means that the opt potentially applies to this line. 1 = never skip reflowing this line for a resize reflow PRUint32 mResizeReflowOptimizationDisabled: 1; // default 0 = means that the opt potentially applies to this line. 1 = never skip reflowing this line for a resize reflow
PRUint32 mEmptyCacheValid: 1;
PRUint32 mEmptyCacheState: 1;
PRUint32 mBreakType : 4; PRUint32 mBreakType : 4;
PRUint32 mChildCount : 21; PRUint32 mChildCount : 19;
}; };
struct ExtraData { struct ExtraData {

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

@ -2211,7 +2211,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
// and also because our final height may depend on it. Only // and also because our final height may depend on it. Only
// update mY if the line is not empty, because that's what // update mY if the line is not empty, because that's what
// PlaceLine does. // PlaceLine does.
if (!line->IsEmpty()) { if (!line->CachedIsEmpty()) {
aState.mY = line->mBounds.YMost(); aState.mY = line->mBounds.YMost();
// This will include any pending float clearing height, so // This will include any pending float clearing height, so
// don't bother clearing previous lines' floats // don't bother clearing previous lines' floats
@ -2483,6 +2483,7 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
// Setup the line-layout for the new line // Setup the line-layout for the new line
aState.mCurrentLine = aLine; aState.mCurrentLine = aLine;
aLine->ClearDirty(); aLine->ClearDirty();
aLine->InvalidateCachedIsEmpty();
// Now that we know what kind of line we have, reflow it // Now that we know what kind of line we have, reflow it
if (aLine->IsBlock()) { if (aLine->IsBlock()) {
@ -3027,7 +3028,7 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
// Determine if this line is "essentially" the first line // Determine if this line is "essentially" the first line
for (line_iterator line = begin_lines(); line != aLine; ++line) { for (line_iterator line = begin_lines(); line != aLine; ++line) {
if (!line->IsEmpty()) { if (!line->CachedIsEmpty()) {
// A line which preceeds aLine is non-empty, so therefore the // A line which preceeds aLine is non-empty, so therefore the
// top margin applies. // top margin applies.
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE); aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
@ -3053,7 +3054,7 @@ nsBlockFrame::GetTopBlockChild(nsPresContext* aPresContext)
if (firstLine->IsBlock()) if (firstLine->IsBlock())
return firstLine->mFirstChild; return firstLine->mFirstChild;
if (!firstLine->IsEmpty()) if (!firstLine->CachedIsEmpty())
return nsnull; return nsnull;
line_iterator secondLine = begin_lines(); line_iterator secondLine = begin_lines();
@ -4195,7 +4196,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
// collapsed with a block that follows. // collapsed with a block that follows.
nscoord newY; nscoord newY;
if (!aLine->IsEmpty()) { if (!aLine->CachedIsEmpty()) {
// This line has some height. Therefore the application of the // This line has some height. Therefore the application of the
// previous-bottom-margin should stick. // previous-bottom-margin should stick.
aState.mPrevBottomMargin.Zero(); aState.mPrevBottomMargin.Zero();

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

@ -288,6 +288,23 @@ nsLineBox::IsEmpty() const
return PR_TRUE; return PR_TRUE;
} }
PRBool
nsLineBox::CachedIsEmpty()
{
if (mFlags.mDirty) {
return IsEmpty();
}
if (mFlags.mEmptyCacheValid) {
return mFlags.mEmptyCacheState;
}
PRBool result = IsEmpty();
mFlags.mEmptyCacheValid = PR_TRUE;
mFlags.mEmptyCacheState = result;
return result;
}
void void
nsLineBox::DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines) nsLineBox::DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines)
{ {

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

@ -400,6 +400,20 @@ public:
// whether the line box is "logically" empty (just like nsIFrame::IsEmpty) // whether the line box is "logically" empty (just like nsIFrame::IsEmpty)
PRBool IsEmpty() const; PRBool IsEmpty() const;
// Call this only while in Reflow() for the block the line belongs
// to, only between reflowing the line (or sliding it, if we skip
// reflowing it) and the end of reflowing the the block.
PRBool CachedIsEmpty();
void InvalidateCachedIsEmpty() {
mFlags.mEmptyCacheValid = PR_FALSE;
}
// For debugging purposes
PRBool IsValidCachedIsEmpty() {
return mFlags.mEmptyCacheValid;
}
#ifdef DEBUG #ifdef DEBUG
static PRInt32 GetCtorCount(); static PRInt32 GetCtorCount();
#endif #endif
@ -418,9 +432,11 @@ public:
PRUint32 mHasPercentageChild : 1; PRUint32 mHasPercentageChild : 1;
PRUint32 mLineWrapped: 1; PRUint32 mLineWrapped: 1;
PRUint32 mResizeReflowOptimizationDisabled: 1; // default 0 = means that the opt potentially applies to this line. 1 = never skip reflowing this line for a resize reflow PRUint32 mResizeReflowOptimizationDisabled: 1; // default 0 = means that the opt potentially applies to this line. 1 = never skip reflowing this line for a resize reflow
PRUint32 mEmptyCacheValid: 1;
PRUint32 mEmptyCacheState: 1;
PRUint32 mBreakType : 4; PRUint32 mBreakType : 4;
PRUint32 mChildCount : 21; PRUint32 mChildCount : 19;
}; };
struct ExtraData { struct ExtraData {