Bug 390050. Scan all blocks in a flow-chain, and their overflow lines, when iterating through lines to build text runs. r=smontagu,mats,sr=mats,a=bz

This commit is contained in:
roc+@cs.cmu.edu 2007-08-22 02:08:13 -07:00
Родитель 65af55c036
Коммит 1131fb1665
3 изменённых файлов: 115 добавлений и 16 удалений

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

@ -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<nsBlockFrame*>(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<nsBlockFrame*>(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)

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

@ -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___ */

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

@ -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();