Bug 400057. Make nsBlockInFlowLineIterator useful for finding the line containing a frame, searching across block continuations and their overflow lines. Use it in various places, especially in textrun construction. r+sr=dbaron

This commit is contained in:
roc+@cs.cmu.edu 2008-02-27 01:53:48 -08:00
parent 015af08fd4
commit efc1d5a1dd
5 changed files with 90 additions and 67 deletions

View File

@ -646,8 +646,9 @@ FindContainingLine(nsIFrame* aFrame)
nsBlockFrame* blockParent;
if (NS_SUCCEEDED(parent->QueryInterface(kBlockFrameCID, (void**)&blockParent)))
{
nsBlockFrame::line_iterator line = blockParent->FindLineFor(aFrame);
return line != blockParent->end_lines() ? line.get() : nsnull;
PRBool isValid;
nsBlockInFlowLineIterator iter(blockParent, aFrame, &isValid);
return isValid ? iter.GetLine().get() : nsnull;
}
aFrame = parent;
}

View File

@ -1582,33 +1582,6 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
//----------------------------------------
nsBlockFrame::line_iterator
nsBlockFrame::FindLineFor(nsIFrame* aFrame)
{
NS_PRECONDITION(aFrame, "why pass a null frame?");
line_iterator line = begin_lines(),
line_end = end_lines();
for ( ; line != line_end; ++line) {
// If the target frame is in-flow, and this line contains the it,
// then we've found our line.
if (line->Contains(aFrame))
return line;
// If the target frame is floated, and this line contains the
// float's placeholder, then we've found our line.
if (line->HasFloats()) {
for (nsFloatCache *fc = line->GetFirstFloat();
fc != nsnull;
fc = fc->Next()) {
if (aFrame == fc->mPlaceholder->GetOutOfFlowFrame())
return line;
}
}
}
return line_end;
}
/**
* Propagate reflow "damage" from from earlier lines to the current
* line. The reflow damage comes from the following sources:
@ -3597,9 +3570,10 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
nsBlockFrame* ourNext = static_cast<nsBlockFrame*>(GetNextInFlow());
if (ourNext && aFrame->GetNextInFlow()) {
line_iterator f = ourNext->FindLineFor(aFrame->GetNextInFlow());
if (f != ourNext->end_lines()) {
f->MarkDirty();
PRBool isValid;
nsBlockInFlowLineIterator iter(ourNext, aFrame->GetNextInFlow(), &isValid);
if (isValid) {
iter.GetLine()->MarkDirty();
}
}
}
@ -5161,6 +5135,51 @@ nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame,
*aFoundValidLine = FindValidLine();
}
static nsIFrame*
FindChildContaining(nsBlockFrame* aFrame, nsIFrame* aFindFrame)
{
nsIFrame* child;
while (PR_TRUE) {
nsIFrame* block = aFrame;
while (PR_TRUE) {
child = nsLayoutUtils::FindChildContainingDescendant(block, aFindFrame);
if (child)
break;
block = block->GetNextContinuation();
}
if (!child)
return nsnull;
if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW))
break;
aFindFrame = aFrame->PresContext()->FrameManager()->GetPlaceholderFrameFor(child);
}
return child;
}
nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame,
nsIFrame* aFindFrame, PRBool* aFoundValidLine)
: mFrame(aFrame), mInOverflowLines(nsnull)
{
mLine = aFrame->begin_lines();
*aFoundValidLine = PR_FALSE;
nsIFrame* child = FindChildContaining(aFrame, aFindFrame);
if (!child)
return;
if (!FindValidLine())
return;
do {
if (mLine->Contains(child)) {
*aFoundValidLine = PR_TRUE;
return;
}
} while (Next());
}
PRBool
nsBlockInFlowLineIterator::IsLastLineInList()
{
@ -6244,9 +6263,10 @@ nsBlockFrame::ChildIsDirty(nsIFrame* aChild)
// Mark the line containing the child frame dirty. We would rather do this
// in MarkIntrinsicWidthsDirty but that currently won't tell us which
// child is being dirtied.
line_iterator fline = FindLineFor(aChild);
if (fline != end_lines()) {
MarkLineDirty(fline);
PRBool isValid;
nsBlockInFlowLineIterator iter(this, aChild, &isValid);
if (isValid) {
MarkLineDirty(iter.GetLine());
}
}

View File

@ -273,10 +273,6 @@ public:
*/
nsIFrame* GetTopBlockChild(nsPresContext *aPresContext);
// Returns the line containing aFrame, or end_lines() if the frame
// isn't in the block.
line_iterator FindLineFor(nsIFrame* aFrame);
static nsresult GetCurrentLine(nsBlockReflowState *aState, nsLineBox **aOutCurrentLine);
// Create a contination for aPlaceholder and its out of flow frame and
@ -692,7 +688,19 @@ class nsBlockInFlowLineIterator {
public:
typedef nsBlockFrame::line_iterator line_iterator;
nsBlockInFlowLineIterator(nsBlockFrame* aFrame, line_iterator aLine, PRBool aInOverflow);
/**
* Set up the iterator to point to the first line found starting from
* aFrame. Sets aFoundValidLine to false if there is no such line.
*/
nsBlockInFlowLineIterator(nsBlockFrame* aFrame, PRBool* aFoundValidLine);
/**
* Set up the iterator to point to the line that contains aFindFrame (either
* directly or indirectly). If aFrame is out of flow, or contained in an
* out-of-flow, finds the line containing the out-of-flow's placeholder. If
* the frame is not found, sets aFoundValidLine to false.
*/
nsBlockInFlowLineIterator(nsBlockFrame* aFrame, nsIFrame* aFindFrame,
PRBool* aFoundValidLine);
line_iterator GetLine() { return mLine; }
PRBool IsLastLineInList();

View File

@ -936,11 +936,11 @@ nsHTMLReflowState::CalculateHypotheticalBox(nsPresContext* aPresContext,
nsBlockFrame* blockFrame;
if (NS_SUCCEEDED(aContainingBlock->QueryInterface(kBlockFrameCID,
reinterpret_cast<void**>(&blockFrame)))) {
// We need the immediate child of the block frame, and that may not be
// the placeholder frame
nsIFrame *blockChild =
nsLayoutUtils::FindChildContainingDescendant(blockFrame, aPlaceholderFrame);
nsBlockFrame::line_iterator lineBox = blockFrame->FindLineFor(blockChild);
PRBool isValid;
nsBlockInFlowLineIterator iter(blockFrame, aPlaceholderFrame, &isValid);
NS_ASSERTION(isValid, "Can't find placeholder!");
NS_ASSERTION(iter.GetContainer() == blockFrame, "Found placeholder in wrong block!");
nsBlockFrame::line_iterator lineBox = iter.GetLine();
// How we determine the hypothetical box depends on whether the element
// would have been inline-level or block-level

View File

@ -838,6 +838,9 @@ static void
BuildTextRuns(gfxContext* aContext, nsTextFrame* aForFrame,
nsIFrame* aLineContainer, const nsLineList::iterator* aForFrameLine)
{
NS_ASSERTION(aForFrame || aForFrameLine,
"One of aForFrame or aForFrameLine must be set!");
if (!aLineContainer) {
aLineContainer = FindLineContainer(aForFrame);
} else {
@ -869,23 +872,18 @@ BuildTextRuns(gfxContext* aContext, nsTextFrame* aForFrame,
}
// Find the line containing aForFrame
nsBlockFrame::line_iterator startLine;
PRBool isValid = PR_TRUE;
nsBlockInFlowLineIterator backIterator(block, &isValid);
if (aForFrameLine) {
startLine = *aForFrameLine;
backIterator = nsBlockInFlowLineIterator(block, *aForFrameLine, PR_FALSE);
} else {
NS_ASSERTION(aForFrame, "One of aForFrame or aForFrameLine must be set!");
nsIFrame* immediateChild =
nsLayoutUtils::FindChildContainingDescendant(block, aForFrame);
// This may be a float e.g. for a floated first-letter
if (immediateChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
immediateChild =
nsLayoutUtils::FindChildContainingDescendant(block,
presContext->FrameManager()->GetPlaceholderFrameFor(immediateChild));
}
startLine = block->FindLineFor(immediateChild);
NS_ASSERTION(startLine != block->end_lines(),
"Frame is not in the block!!!");
backIterator = nsBlockInFlowLineIterator(block, aForFrame, &isValid);
NS_ASSERTION(isValid, "aForFrame not found in block, someone lied to us");
NS_ASSERTION(backIterator.GetContainer() == block,
"Someone lied to us about the block");
}
nsBlockFrame::line_iterator startLine = backIterator.GetLine();
// Find a line where we can start building text runs. We choose the last line
// where:
@ -900,17 +898,14 @@ BuildTextRuns(gfxContext* aContext, 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.
nsBlockInFlowLineIterator backIterator(block, startLine, PR_FALSE);
nsBlockInFlowLineIterator forwardIterator = backIterator;
nsTextFrame* stopAtFrame = aForFrame;
nsTextFrame* nextLineFirstTextFrame = nsnull;
PRBool seenTextRunBoundaryOnLaterLine = PR_FALSE;
PRBool mayBeginInTextRun = PR_TRUE;
PRBool inOverflow = PR_FALSE;
nsBlockFrame::line_iterator line;
while (PR_TRUE) {
line = backIterator.GetLine();
block = backIterator.GetContainer();
inOverflow = backIterator.GetInOverflow();
forwardIterator = backIterator;
nsBlockFrame::line_iterator line = backIterator.GetLine();
if (!backIterator.Prev() || backIterator.GetLine()->IsBlock()) {
mayBeginInTextRun = PR_FALSE;
break;
@ -954,11 +949,10 @@ BuildTextRuns(gfxContext* aContext, 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).
nsBlockInFlowLineIterator forwardIterator(block, line, inOverflow);
PRBool seenStartLine = PR_FALSE;
PRUint32 linesAfterStartLine = 0;
do {
line = forwardIterator.GetLine();
nsBlockFrame::line_iterator line = forwardIterator.GetLine();
if (line->IsBlock())
break;
line->SetInvalidateTextRuns(PR_FALSE);