mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
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:
parent
015af08fd4
commit
efc1d5a1dd
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,8 +688,20 @@ 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();
|
||||
nsBlockFrame* GetContainer() { return mFrame; }
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user