diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index b96e5ffd79f..cb2dfdcc934 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -5061,6 +5061,77 @@ nsBlockFrame::TryAllLines(nsLineList::iterator* aIterator, } } +nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame, + line_iterator& aLine, PRBool aInOverflow) + : mFrame(aFrame), mLine(aLine), mInOverflowLines(nsnull) +{ + if (aInOverflow) { + mInOverflowLines = aFrame->GetOverflowLines(); + NS_ASSERTION(mInOverflowLines, "How can we be in overflow if there isn't any?"); + } +} + +PRBool +nsBlockInFlowLineIterator::Next() +{ + ++mLine; + line_iterator end = mInOverflowLines ? mInOverflowLines->end() : mFrame->end_lines(); + if (mLine != end) + return PR_TRUE; + PRBool currentlyInOverflowLines = mInOverflowLines != nsnull; + while (PR_TRUE) { + if (currentlyInOverflowLines) { + mFrame = static_cast(mFrame->GetNextInFlow()); + if (!mFrame) + return PR_FALSE; + mInOverflowLines = nsnull; + mLine = mFrame->begin_lines(); + if (mLine != mFrame->end_lines()) + return PR_TRUE; + } else { + mInOverflowLines = mFrame->GetOverflowLines(); + if (mInOverflowLines) { + mLine = mInOverflowLines->begin(); + NS_ASSERTION(mLine != mInOverflowLines->end(), "empty overflow line list?"); + return PR_TRUE; + } + } + currentlyInOverflowLines = !currentlyInOverflowLines; + } +} + +PRBool +nsBlockInFlowLineIterator::Prev() +{ + line_iterator begin = mInOverflowLines ? mInOverflowLines->begin() : mFrame->begin_lines(); + if (mLine != begin) { + --mLine; + return PR_TRUE; + } + PRBool currentlyInOverflowLines = mInOverflowLines != nsnull; + while (PR_TRUE) { + if (currentlyInOverflowLines) { + mLine = mFrame->end_lines(); + if (mLine != mFrame->begin_lines()) { + --mLine; + return PR_TRUE; + } + } else { + mFrame = static_cast(mFrame->GetPrevInFlow()); + if (!mFrame) + return PR_FALSE; + mInOverflowLines = mFrame->GetOverflowLines(); + if (mInOverflowLines) { + mLine = mInOverflowLines->end(); + NS_ASSERTION(mLine != mInOverflowLines->begin(), "empty overflow line list?"); + --mLine; + return PR_TRUE; + } + } + currentlyInOverflowLines = !currentlyInOverflowLines; + } +} + static nsresult RemoveBlockChild(nsIFrame* aFrame, PRBool aDestroyFrames) { if (!aFrame) diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h index b50eefdbd38..5f063cc0e4c 100644 --- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -70,6 +70,7 @@ enum LineReflowStatus { }; class nsBlockReflowState; +class nsBlockInFlowLineIterator; class nsBulletFrame; class nsLineBox; class nsFirstLineFrame; @@ -608,6 +609,7 @@ protected: nsBulletFrame* mBullet; friend class nsBlockReflowState; + friend class nsBlockInFlowLineIterator; private: nsAbsoluteContainingBlock mAbsoluteContainer; @@ -653,5 +655,32 @@ private: }; #endif -#endif /* nsBlockFrame_h___ */ +/** + * Iterates over all lines in the prev-in-flows/next-in-flows of this block. + */ +class nsBlockInFlowLineIterator { +public: + typedef nsBlockFrame::line_iterator line_iterator; + nsBlockInFlowLineIterator(nsBlockFrame* aFrame, line_iterator& aLine, PRBool aInOverflow); + line_iterator GetLine() { return mLine; } + nsBlockFrame* GetContainer() { return mFrame; } + PRBool GetInOverflow() { return mInOverflowLines != nsnull; } + /** + * Returns false if there are no more lines. After this has returned false, + * don't call any methods on this object again. + */ + PRBool Next(); + /** + * Returns false if there are no more lines. After this has returned false, + * don't call any methods on this object again. + */ + PRBool Prev(); + +private: + nsBlockFrame* mFrame; + line_iterator mLine; + nsLineList* mInOverflowLines; +}; + +#endif /* nsBlockFrame_h___ */ diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index 5a0ec840468..729153a3578 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -1104,6 +1104,8 @@ BuildTextRuns(nsIRenderingContext* aRC, nsTextFrame* aForFrame, aLineContainer->QueryInterface(kBlockFrameCID, (void**)&block); if (!block) { + NS_ASSERTION(!aLineContainer->GetPrevInFlow() && !aLineContainer->GetNextInFlow(), + "Breakable non-block line containers not supported"); // Just loop through all the children of the linecontainer ... it's really // just one line scanner.SetAtStartOfLine(); @@ -1151,20 +1153,17 @@ BuildTextRuns(nsIRenderingContext* aRC, 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. - nsBlockFrame::line_iterator firstLine = block->begin_lines(); + nsBlockInFlowLineIterator backIterator(block, line, PR_FALSE); nsTextFrame* stopAtFrame = aForFrame; nsTextFrame* nextLineFirstTextFrame = nsnull; PRBool seenTextRunBoundaryOnLaterLine = PR_FALSE; PRBool mayBeginInTextRun = PR_TRUE; + PRBool inOverflow = PR_FALSE; while (PR_TRUE) { - if (line == firstLine) { - mayBeginInTextRun = PR_FALSE; - break; - } - --line; - PRBool prevLineIsBlock = line->IsBlock(); - ++line; - if (prevLineIsBlock) { + line = backIterator.GetLine(); + block = backIterator.GetContainer(); + inOverflow = backIterator.GetInOverflow(); + if (!backIterator.Prev() || backIterator.GetLine()->IsBlock()) { mayBeginInTextRun = PR_FALSE; break; } @@ -1200,7 +1199,6 @@ BuildTextRuns(nsIRenderingContext* aRC, nsTextFrame* aForFrame, if (state.mFirstTextFrame) { nextLineFirstTextFrame = state.mFirstTextFrame; } - --line; } scanner.SetSkipIncompleteTextRuns(mayBeginInTextRun); @@ -1208,19 +1206,20 @@ BuildTextRuns(nsIRenderingContext* aRC, nsTextFrame* aForFrame, // text frames will be accumulated into textRunFrames as we go. When a // text run boundary is required we flush textRunFrames ((re)building their // gfxTextRuns as necessary). - nsBlockFrame::line_iterator endLines = block->end_lines(); - NS_ASSERTION(line != endLines && !line->IsBlock(), "Where is this frame anyway??"); - nsIFrame* child = line->mFirstChild; + nsBlockInFlowLineIterator forwardIterator(block, line, inOverflow); do { + line = forwardIterator.GetLine(); + if (line->IsBlock()) + break; scanner.SetAtStartOfLine(); scanner.SetCommonAncestorWithLastFrame(nsnull); + nsIFrame* child = line->mFirstChild; PRInt32 i; for (i = line->GetChildCount() - 1; i >= 0; --i) { scanner.ScanFrame(child); child = child->GetNextSibling(); } - ++line; - } while (line != endLines && !line->IsBlock()); + } while (forwardIterator.Next()); // Set mStartOfLine so FlushFrames knows its textrun ends a line scanner.SetAtStartOfLine();