diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index 816fd390c92..29e82a3c0f5 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -572,6 +572,7 @@ public: void SetAtStartOfLine() { mStartOfLine = PR_TRUE; + mCanStopOnThisLine = PR_FALSE; } void SetSkipIncompleteTextRuns(PRBool aSkip) { mSkipIncompleteTextRuns = aSkip; @@ -579,6 +580,9 @@ public: void SetCommonAncestorWithLastFrame(nsIFrame* aFrame) { mCommonAncestorWithLastFrame = aFrame; } + PRBool CanStopOnThisLine() { + return mCanStopOnThisLine; + } nsIFrame* GetCommonAncestorWithLastFrame() { return mCommonAncestorWithLastFrame; } @@ -686,6 +690,7 @@ private: PRPackedBool mTrimNextRunLeadingWhitespace; PRPackedBool mCurrentRunTrimLeadingWhitespace; PRPackedBool mSkipIncompleteTextRuns; + PRPackedBool mCanStopOnThisLine; }; static nsIFrame* @@ -798,6 +803,10 @@ BuildTextRunsScanner::FindBoundaries(nsIFrame* aFrame, FindBoundaryState* aState return FB_CONTINUE; } +// build text runs for the 200 lines following aForFrame, and stop after that +// when we get a chance. +#define NUM_LINES_TO_BUILD_TEXT_RUNS 200 + /** * General routine for building text runs. This is hairy because of the need * to build text runs that span content nodes. @@ -842,9 +851,9 @@ BuildTextRuns(gfxContext* aContext, nsTextFrame* aForFrame, } // Find the line containing aForFrame - nsBlockFrame::line_iterator line; + nsBlockFrame::line_iterator startLine; if (aForFrameLine) { - line = *aForFrameLine; + startLine = *aForFrameLine; } else { NS_ASSERTION(aForFrame, "One of aForFrame or aForFrameLine must be set!"); nsIFrame* immediateChild = @@ -855,8 +864,8 @@ BuildTextRuns(gfxContext* aContext, nsTextFrame* aForFrame, nsLayoutUtils::FindChildContainingDescendant(block, presContext->FrameManager()->GetPlaceholderFrameFor(immediateChild)); } - line = block->FindLineFor(immediateChild); - NS_ASSERTION(line != block->end_lines(), + startLine = block->FindLineFor(immediateChild); + NS_ASSERTION(startLine != block->end_lines(), "Frame is not in the block!!!"); } @@ -873,12 +882,13 @@ BuildTextRuns(gfxContext* aContext, nsTextFrame* aForFrame, // but we discard them instead of assigning them to frames. // This is a little awkward because we traverse lines in the reverse direction // but we traverse the frames in each line in the forward direction. - nsBlockInFlowLineIterator backIterator(block, line, PR_FALSE); + nsBlockInFlowLineIterator backIterator(block, startLine, PR_FALSE); nsTextFrame* stopAtFrame = aForFrame; nsTextFrame* nextLineFirstTextFrame = nsnull; PRBool seenTextRunBoundaryOnLaterLine = PR_FALSE; PRBool mayBeginInTextRun = PR_TRUE; PRBool inOverflow = PR_FALSE; + nsBlockFrame::line_iterator line; while (PR_TRUE) { line = backIterator.GetLine(); block = backIterator.GetContainer(); @@ -927,6 +937,8 @@ BuildTextRuns(gfxContext* aContext, nsTextFrame* aForFrame, // text run boundary is required we flush textRunFrames ((re)building their // gfxTextRuns as necessary). nsBlockInFlowLineIterator forwardIterator(block, line, inOverflow); + PRBool seenStartLine = PR_FALSE; + PRUint32 linesAfterStartLine = 0; do { line = forwardIterator.GetLine(); if (line->IsBlock()) @@ -940,6 +952,21 @@ BuildTextRuns(gfxContext* aContext, nsTextFrame* aForFrame, scanner.ScanFrame(child); child = child->GetNextSibling(); } + if (line == startLine) { + seenStartLine = PR_TRUE; + } + if (seenStartLine) { + ++linesAfterStartLine; + if (linesAfterStartLine >= NUM_LINES_TO_BUILD_TEXT_RUNS && scanner.CanStopOnThisLine()) { + // Don't flush; we may be in the middle of a textrun that we can't + // end here. That's OK, we just won't build it. + // Note that we must already have finished the textrun for aForFrame, + // because we've seen the end of a textrun in a line after the line + // containing aForFrame. + mLineBreaker.Reset(); + return; + } + } } while (forwardIterator.Next()); // Set mStartOfLine so FlushFrames knows its textrun ends a line @@ -1018,6 +1045,7 @@ void BuildTextRunsScanner::FlushFrames(PRBool aFlushLineBreaks) mBreakSinks.Clear(); } + mCanStopOnThisLine = PR_TRUE; ResetRunInfo(); }