diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index 08871532822..f73645e4d29 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -665,6 +665,7 @@ nsBlockFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) } // XXX Bug NNNNNN Should probably handle percentage text-indent. + data.line = &line; nsIFrame *kid = line->mFirstChild; for (PRInt32 i = 0, i_end = line->GetChildCount(); i != i_end; ++i, kid = kid->GetNextSibling()) { @@ -736,6 +737,7 @@ nsBlockFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) } // XXX Bug NNNNNN Should probably handle percentage text-indent. + data.line = &line; nsIFrame *kid = line->mFirstChild; for (PRInt32 i = 0, i_end = line->GetChildCount(); i != i_end; ++i, kid = kid->GetNextSibling()) { @@ -4798,12 +4800,19 @@ nsBlockFrame::AddFrames(nsIFrame* aFrameList, prevSibLine->SetChildCount(prevSibLine->GetChildCount() - rem); prevSibLine->MarkDirty(); } + // Force the lines next to where we're inserting content to regenerate + // their textruns + prevSibLine->SetInvalidateTextRuns(PR_TRUE); + if (prevSibLine.next() != end_lines()) { + prevSibLine.next()->SetInvalidateTextRuns(PR_TRUE); + } // Now (partially) join the sibling lists together aPrevSibling->SetNextSibling(aFrameList); } else if (! mLines.empty()) { prevSiblingNextFrame = mLines.front()->mFirstChild; + mLines.front()->SetInvalidateTextRuns(PR_TRUE); } // Walk through the new frames being added and update the line data @@ -5212,6 +5221,10 @@ found_frame:; NS_ERROR("can't find deleted frame in lines"); return NS_ERROR_FAILURE; } + + if (line != mLines.front()) { + line.prev()->SetInvalidateTextRuns(PR_TRUE); + } if (prevSibling && !prevSibling->GetNextSibling()) { // We must have found the first frame in the overflow line list. So @@ -5224,6 +5237,8 @@ found_frame:; NS_ASSERTION(this == aDeletedFrame->GetParent(), "messed up delete code"); NS_ASSERTION(line->Contains(aDeletedFrame), "frame not in line"); + line->SetInvalidateTextRuns(PR_TRUE); + // If the frame being deleted is the last one on the line then // optimize away the line->Contains(next-in-flow) call below. PRBool isLastFrameOnLine = (1 == line->GetChildCount() || @@ -5370,6 +5385,10 @@ found_frame:; } } } + + if (line.next() != line_end) { + line.next()->SetInvalidateTextRuns(PR_TRUE); + } #ifdef DEBUG VerifyLines(PR_TRUE); @@ -6104,10 +6123,16 @@ nsBlockFrame::ChildIsDirty(nsIFrame* aChild) // otherwise we have an empty line list, and ReflowDirtyLines // will handle reflowing the bullet. } else { - // Mark the line containing the child frame dirty. + // Mark the line containing the child frame dirty. We would rather do this + // in MarkIntrinsicWidthsDirty but that currently won't tell us which + // child is being dirtied. line_iterator fline = FindLineFor(aChild); - if (fline != end_lines()) + if (fline != end_lines()) { + // An inline descendant might have been added or removed, so we should + // reconstruct textruns. + fline->SetInvalidateTextRuns(PR_TRUE); MarkLineDirty(fline); + } } nsBlockFrameSuper::ChildIsDirty(aChild); diff --git a/mozilla/layout/generic/nsIFrame.h b/mozilla/layout/generic/nsIFrame.h index 66f8ca36dde..a61c8a675d3 100644 --- a/mozilla/layout/generic/nsIFrame.h +++ b/mozilla/layout/generic/nsIFrame.h @@ -92,6 +92,7 @@ class nsDisplayListSet; class nsDisplayList; class gfxSkipChars; class gfxSkipCharsIterator; +class nsLineList_iterator; struct nsPeekOffsetStruct; struct nsPoint; @@ -1137,12 +1138,16 @@ public: */ struct InlineIntrinsicWidthData { InlineIntrinsicWidthData() - : prevLines(0) + : line(nsnull) + , prevLines(0) , currentLine(0) , skipWhitespace(PR_TRUE) , trailingWhitespace(0) {} + // The line. This may be null if the inlines are not associated with a block. + const nsLineList_iterator* line; + // The maximum intrinsic width for all previous lines. nscoord prevLines; diff --git a/mozilla/layout/generic/nsLineBox.h b/mozilla/layout/generic/nsLineBox.h index faa97e01ec2..bb032a4a0af 100644 --- a/mozilla/layout/generic/nsLineBox.h +++ b/mozilla/layout/generic/nsLineBox.h @@ -305,6 +305,15 @@ public: return mFlags.mLineWrapped; } + // mInvalidateTextRuns bit + void SetInvalidateTextRuns(PRBool aOn) { + NS_ASSERTION((PR_FALSE==aOn || PR_TRUE==aOn), "somebody is playing fast and loose with bools and bits!"); + mFlags.mInvalidateTextRuns = aOn; + } + PRBool GetInvalidateTextRuns() const { + return mFlags.mInvalidateTextRuns; + } + // mResizeReflowOptimizationDisabled bit void DisableResizeReflowOptimization() { mFlags.mResizeReflowOptimizationDisabled = PR_TRUE; @@ -487,6 +496,7 @@ public: PRUint32 mBlock : 1; PRUint32 mImpactedByFloat : 1; PRUint32 mLineWrapped: 1; + PRUint32 mInvalidateTextRuns : 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 mEmptyCacheValid: 1; PRUint32 mEmptyCacheState: 1; diff --git a/mozilla/layout/generic/nsTextFrameThebes.cpp b/mozilla/layout/generic/nsTextFrameThebes.cpp index 0b907023ba9..2b394ad6e7e 100644 --- a/mozilla/layout/generic/nsTextFrameThebes.cpp +++ b/mozilla/layout/generic/nsTextFrameThebes.cpp @@ -1206,6 +1206,7 @@ BuildTextRuns(nsIRenderingContext* aRC, nsTextFrame* aForFrame, line = forwardIterator.GetLine(); if (line->IsBlock()) break; + line->SetInvalidateTextRuns(PR_FALSE); scanner.SetAtStartOfLine(); scanner.SetCommonAncestorWithLastFrame(nsnull); nsIFrame* child = line->mFirstChild; @@ -1966,7 +1967,7 @@ nsTextFrame::EnsureTextRun(nsIRenderingContext* aRC, nsIFrame* aLineContainer, const nsLineList::iterator* aLine, PRUint32* aFlowEndInTextRun) { - if (mTextRun) { + if (mTextRun && (!aLine || !(*aLine)->GetInvalidateTextRuns())) { if (mTextRun->GetExpirationState()->IsTracked()) { gTextRuns->MarkUsed(mTextRun); } @@ -5001,7 +5002,7 @@ nsTextFrame::AddInlineMinWidthForFlow(nsIRenderingContext *aRenderingContext, { PRUint32 flowEndInTextRun; gfxSkipCharsIterator iter = - EnsureTextRun(aRenderingContext, nsnull, nsnull, &flowEndInTextRun); + EnsureTextRun(aRenderingContext, nsnull, aData->line, &flowEndInTextRun); if (!mTextRun) return; @@ -5099,7 +5100,7 @@ nsTextFrame::AddInlinePrefWidthForFlow(nsIRenderingContext *aRenderingContext, { PRUint32 flowEndInTextRun; gfxSkipCharsIterator iter = - EnsureTextRun(aRenderingContext, nsnull, nsnull, &flowEndInTextRun); + EnsureTextRun(aRenderingContext, nsnull, aData->line, &flowEndInTextRun); if (!mTextRun) return;