зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
65af55c036
Коммит
1131fb1665
|
@ -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();
|
||||
|
|
Загрузка…
Ссылка в новой задаче