diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index bacda5c31e00..a12fb5966b4d 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -4044,13 +4044,19 @@ PresShell::ScrollToAnchor() * we should include the top of the line in the added rectangle * @param aRect [inout] rect into which its bounds should be unioned * @param aHaveRect [inout] whether aRect contains data yet + * @param aPrevBlock [inout] the block aLines is a line iterator for + * @param aLines [inout] the line iterator we're using + * @param aCurLine [inout] the line to start looking from in this iterator */ static void AccumulateFrameBounds(nsIFrame* aContainerFrame, nsIFrame* aFrame, PRBool aUseWholeLineHeightForInlines, nsRect& aRect, - PRBool& aHaveRect) + PRBool& aHaveRect, + nsIFrame*& aPrevBlock, + nsAutoLineIterator& aLines, + PRInt32& aCurLine) { nsRect frameBounds = aFrame->GetRect() + aFrame->GetParent()->GetOffsetTo(aContainerFrame); @@ -4073,17 +4079,22 @@ AccumulateFrameBounds(nsIFrame* aContainerFrame, f && frameType == nsGkAtoms::blockFrame) { // find the line containing aFrame and increase the top of |offset|. - nsAutoLineIterator lines = f->GetLineIterator(); - if (lines) { - PRInt32 index = lines->FindLineContaining(prevFrame); + if (f != aPrevBlock) { + aLines = f->GetLineIterator(); + aPrevBlock = f; + aCurLine = 0; + } + if (aLines) { + PRInt32 index = aLines->FindLineContaining(prevFrame, aCurLine); if (index >= 0) { + aCurLine = index; nsIFrame *trash1; PRInt32 trash2; nsRect lineBounds; PRUint32 trash3; - if (NS_SUCCEEDED(lines->GetLine(index, &trash1, &trash2, - lineBounds, &trash3))) { + if (NS_SUCCEEDED(aLines->GetLine(index, &trash1, &trash2, + lineBounds, &trash3))) { lineBounds += f->GetOffsetTo(aContainerFrame); if (lineBounds.y < frameBounds.y) { frameBounds.height = frameBounds.YMost() - lineBounds.y; @@ -4286,9 +4297,16 @@ PresShell::DoScrollContentIntoView(nsIContent* aContent, nsRect frameBounds; PRBool haveRect = PR_FALSE; PRBool useWholeLineHeightForInlines = aVPercent != NS_PRESSHELL_SCROLL_ANYWHERE; + // Reuse the same line iterator across calls to AccumulateFrameBounds. We set + // it every time we detect a new block (stored in prevBlock). + nsIFrame* prevBlock = nsnull; + nsAutoLineIterator lines; + // The last line we found a continuation on in |lines|. We assume that later + // continuations cannot come on earlier lines. + PRInt32 curLine = 0; do { AccumulateFrameBounds(container, frame, useWholeLineHeightForInlines, - frameBounds, haveRect); + frameBounds, haveRect, prevBlock, lines, curLine); } while ((frame = frame->GetNextContinuation())); ScrollFrameRectIntoView(container, frameBounds, aVPercent, aHPercent, diff --git a/layout/generic/nsILineIterator.h b/layout/generic/nsILineIterator.h index 2ff673036b40..06a697c6a631 100644 --- a/layout/generic/nsILineIterator.h +++ b/layout/generic/nsILineIterator.h @@ -104,9 +104,12 @@ public: /** * Given a frame that's a child of the block, find which line its on - * and return that line index. Returns -1 if the frame cannot be found. + * and return that line index, as long as it's at least as big as + * aStartLine. Returns -1 if the frame cannot be found on lines + * starting with aStartLine. */ - virtual PRInt32 FindLineContaining(nsIFrame* aFrame) = 0; + virtual PRInt32 FindLineContaining(nsIFrame* aFrame, + PRInt32 aStartLine = 0) = 0; // Given a line number and an X coordinate, find the frame on the // line that is nearest to the X coordinate. The diff --git a/layout/generic/nsLineBox.cpp b/layout/generic/nsLineBox.cpp index 0ccb8b0b23eb..9d445bde5b99 100644 --- a/layout/generic/nsLineBox.cpp +++ b/layout/generic/nsLineBox.cpp @@ -626,15 +626,16 @@ nsLineIterator::GetLine(PRInt32 aLineNumber, } PRInt32 -nsLineIterator::FindLineContaining(nsIFrame* aFrame) +nsLineIterator::FindLineContaining(nsIFrame* aFrame, PRInt32 aStartLine) { - nsLineBox* line = mLines[0]; - PRInt32 lineNumber = 0; + NS_PRECONDITION(aStartLine <= mNumLines, "Bogus line numbers"); + PRInt32 lineNumber = aStartLine; while (lineNumber != mNumLines) { + nsLineBox* line = mLines[lineNumber]; if (line->Contains(aFrame)) { return lineNumber; } - line = mLines[++lineNumber]; + ++lineNumber; } return -1; } diff --git a/layout/generic/nsLineBox.h b/layout/generic/nsLineBox.h index 27ea5345d883..2ac7c9338f5c 100644 --- a/layout/generic/nsLineBox.h +++ b/layout/generic/nsLineBox.h @@ -1581,7 +1581,7 @@ public: PRInt32* aNumFramesOnLine, nsRect& aLineBounds, PRUint32* aLineFlags); - virtual PRInt32 FindLineContaining(nsIFrame* aFrame); + virtual PRInt32 FindLineContaining(nsIFrame* aFrame, PRInt32 aStartLine = 0); NS_IMETHOD FindFrameAt(PRInt32 aLineNumber, nscoord aX, nsIFrame** aFrameFound, diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index f4730c489d95..030e9ee0d6d3 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -1706,14 +1706,16 @@ nsTableRowGroupFrame::GetLine(PRInt32 aLineNumber, } PRInt32 -nsTableRowGroupFrame::FindLineContaining(nsIFrame* aFrame) +nsTableRowGroupFrame::FindLineContaining(nsIFrame* aFrame, PRInt32 aStartLine) { NS_ENSURE_ARG_POINTER(aFrame); nsTableRowFrame *rowFrame = do_QueryFrame(aFrame); NS_ASSERTION(rowFrame, "RowGroup contains a frame that is not a row"); - return rowFrame->GetRowIndex() - GetStartRowIndex(); + PRInt32 rowIndexInGroup = rowFrame->GetRowIndex() - GetStartRowIndex(); + + return rowIndexInGroup >= aStartLine ? rowIndexInGroup : -1; } #ifdef IBMBIDI diff --git a/layout/tables/nsTableRowGroupFrame.h b/layout/tables/nsTableRowGroupFrame.h index b7aa90138533..84dd119e3a8b 100644 --- a/layout/tables/nsTableRowGroupFrame.h +++ b/layout/tables/nsTableRowGroupFrame.h @@ -258,10 +258,12 @@ public: /** Given a frame that's a child of the rowgroup, find which line its on. * @param aFrame - frame, should be a row + * @param aStartLine - minimal index to return * @return row index relative to the row group if this a row - * frame. -1 if the frame cannot be found. + * frame and the index is at least aStartLine. + * -1 if the frame cannot be found. */ - virtual PRInt32 FindLineContaining(nsIFrame* aFrame); + virtual PRInt32 FindLineContaining(nsIFrame* aFrame, PRInt32 aStartLine = 0); /** Find the orginating cell frame on a row that is the nearest to the * coordinate X.