Bug 411870. Make bidi resolution track lines across block continuation boundaries. r=smontagu

This commit is contained in:
roc+@cs.cmu.edu 2008-01-27 21:07:14 -08:00
parent 3f16295798
commit fbf20e6e5d
7 changed files with 59 additions and 58 deletions

View File

@ -196,29 +196,37 @@ CreateBidiContinuation(nsIFrame* aFrame,
}
static PRBool
IsFrameInCurrentLine(nsBlockInFlowLineIterator* aLineIter,
nsIFrame* aPrevFrame, nsIFrame* aFrame)
{
nsIFrame* endFrame = aLineIter->IsLastLineInList() ? nsnull :
aLineIter->GetLine().next()->mFirstChild;
nsIFrame* startFrame = aPrevFrame ? aPrevFrame : aLineIter->GetLine()->mFirstChild;
return nsFrameList(startFrame).ContainsFrameBefore(aFrame, endFrame);
}
static void
AdvanceLineIteratorToFrame(nsIFrame* aFrame,
nsIFrame* aBlockFrame,
nsBlockFrame::line_iterator& aLine,
nsIFrame*& aPrevFrame,
const nsBlockFrame::line_iterator& aEndLines)
nsBlockInFlowLineIterator* aLineIter,
nsIFrame*& aPrevFrame)
{
// Advance aLine to the line containing aFrame
nsIFrame* child = aFrame;
nsIFrame* parent = child->GetParent();
while (parent && parent != aBlockFrame) {
if (parent->GetStyleDisplay()->IsBlockOutside())
return PR_FALSE;
while (parent && parent->IsFrameOfType(nsIFrame::eLineParticipant)) {
child = parent;
parent = child->GetParent();
}
NS_ASSERTION (parent, "aFrame is not a descendent of aBlockFrame");
while (aLine != aEndLines && !aLine->ContainsAfter(aPrevFrame, child, aLine, aEndLines)) {
++aLine;
while (!IsFrameInCurrentLine(aLineIter, aPrevFrame, child)) {
#ifdef DEBUG
PRBool hasNext =
#endif
aLineIter->Next();
NS_ASSERTION(hasNext, "Can't find frame in lines!");
aPrevFrame = nsnull;
}
aPrevFrame = child;
NS_ASSERTION (aLine != aEndLines, "frame not found on any line");
return PR_TRUE;
}
/*
@ -345,8 +353,11 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame,
nsPropertyTable *propTable = presContext->PropertyTable();
nsBlockFrame::line_iterator line = aBlockFrame->begin_lines();
nsBlockFrame::line_iterator endLines = aBlockFrame->end_lines();
nsBlockInFlowLineIterator lineIter(aBlockFrame, aBlockFrame->begin_lines(), PR_FALSE);
if (lineIter.GetLine() == aBlockFrame->end_lines()) {
// Advance to first valid line (might be in a next-continuation)
lineIter.Next();
}
nsIFrame* prevFrame = nsnull;
PRBool lineNeedsUpdate = PR_FALSE;
@ -419,12 +430,10 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame,
break;
}
if (lineNeedsUpdate) {
if (AdvanceLineIteratorToFrame(frame, aBlockFrame, line,
prevFrame, endLines)) {
lineNeedsUpdate = PR_FALSE;
}
AdvanceLineIteratorToFrame(frame, &lineIter, prevFrame);
lineNeedsUpdate = PR_FALSE;
}
line->MarkDirty();
lineIter.GetLine()->MarkDirty();
frame = nextBidi;
contentOffset += runLength;
} // if (runLength < fragmentLength)
@ -434,12 +443,10 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame,
if (newIndex > frameIndex) {
RemoveBidiContinuation(frame, frameIndex, newIndex, temp);
if (lineNeedsUpdate) {
if (AdvanceLineIteratorToFrame(frame, aBlockFrame, line,
prevFrame, endLines)) {
lineNeedsUpdate = PR_FALSE;
}
AdvanceLineIteratorToFrame(frame, &lineIter, prevFrame);
lineNeedsUpdate = PR_FALSE;
}
line->MarkDirty();
lineIter.GetLine()->MarkDirty();
runLength -= temp;
fragmentLength -= temp;
lineOffset += temp;

View File

@ -5128,7 +5128,7 @@ nsBlockFrame::TryAllLines(nsLineList::iterator* aIterator,
}
nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame,
line_iterator& aLine, PRBool aInOverflow)
line_iterator aLine, PRBool aInOverflow)
: mFrame(aFrame), mLine(aLine), mInOverflowLines(nsnull)
{
if (aInOverflow) {
@ -5137,6 +5137,13 @@ nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame,
}
}
PRBool
nsBlockInFlowLineIterator::IsLastLineInList()
{
line_iterator end = mInOverflowLines ? mInOverflowLines->end() : mFrame->end_lines();
return mLine != end && mLine.next() == end;
}
PRBool
nsBlockInFlowLineIterator::Next()
{

View File

@ -674,9 +674,10 @@ private:
class nsBlockInFlowLineIterator {
public:
typedef nsBlockFrame::line_iterator line_iterator;
nsBlockInFlowLineIterator(nsBlockFrame* aFrame, line_iterator& aLine, PRBool aInOverflow);
nsBlockInFlowLineIterator(nsBlockFrame* aFrame, line_iterator aLine, PRBool aInOverflow);
line_iterator GetLine() { return mLine; }
PRBool IsLastLineInList();
nsBlockFrame* GetContainer() { return mFrame; }
PRBool GetInOverflow() { return mInOverflowLines != nsnull; }
/**

View File

@ -296,6 +296,23 @@ nsFrameList::ContainsFrame(const nsIFrame* aFrame) const
return PR_FALSE;
}
PRBool
nsFrameList::ContainsFrameBefore(const nsIFrame* aFrame, const nsIFrame* aEnd) const
{
NS_PRECONDITION(nsnull != aFrame, "null ptr");
nsIFrame* frame = mFirstChild;
while (frame) {
if (frame == aEnd) {
return PR_FALSE;
}
if (frame == aFrame) {
return PR_TRUE;
}
frame = frame->GetNextSibling();
}
return PR_FALSE;
}
PRInt32
nsFrameList::GetLength() const
{

View File

@ -153,6 +153,7 @@ public:
}
PRBool ContainsFrame(const nsIFrame* aFrame) const;
PRBool ContainsFrameBefore(const nsIFrame* aFrame, const nsIFrame* aEnd) const;
PRInt32 GetLength() const;

View File

@ -276,29 +276,6 @@ nsLineBox::IndexOf(nsIFrame* aFrame) const
return -1;
}
PRBool
nsLineBox::ContainsAfter(nsIFrame* aFrameInLine,
nsIFrame* aFrameToFind,
nsLineList::iterator aLineIter,
const nsLineList::iterator& aEndLines) const
{
nsIFrame* firstFrameOnNextLine = nsnull;
++aLineIter;
if (aLineIter != aEndLines)
firstFrameOnNextLine = aLineIter->mFirstChild;
nsIFrame* frame = aFrameInLine;
if (!frame)
frame = mFirstChild;
while (frame && frame != firstFrameOnNextLine) {
if (frame == aFrameToFind)
return PR_TRUE;
frame = frame->GetNextSibling();
}
return PR_FALSE;
}
PRBool
nsLineBox::IsEmpty() const
{

View File

@ -455,15 +455,6 @@ public:
return IndexOf(aFrame) >= 0;
}
// Search the line for aFrameToFind, going forward from aFrameInLine
// (or from the beginning of the line, if aFrameInLine is null).
// aLineIterator is a line iterator pointing to the line.
// aEndLine should point to the block's end_lines.
PRBool ContainsAfter(nsIFrame* aFrameInLine,
nsIFrame* aFrameToFind,
nsLineList_iterator aLineIter,
const nsLineList_iterator& aEndLines) const;
// whether the line box is "logically" empty (just like nsIFrame::IsEmpty)
PRBool IsEmpty() const;