Bug 282173. Remove BuildFloatList. r+sr=dbaron

git-svn-id: svn://10.0.0.236/trunk@193974 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
roc+%cs.cmu.edu 2006-04-09 22:56:27 +00:00
parent b1fa15f4dc
commit cbc5855a71
3 changed files with 140 additions and 83 deletions

View File

@ -925,8 +925,9 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
ReparentFrame(oof, this, ancestorRS->frame);
// Clear the next-sibling in case the frame wasn't in mFloats
oof->SetNextSibling(nsnull);
NS_STATIC_CAST(nsBlockFrame*, ancestorRS->frame)
->mFloats.AppendFrame(nsnull, oof);
// Do not put the float into any child frame list, because
// placeholders in the overflow-placeholder block-state list
// don't keep their out of flows in a child frame list.
}
ancestorPlace->AppendFrames(nsnull, state.mOverflowPlaceholders.FirstChild());
gaveToAncestor = PR_TRUE;
@ -944,6 +945,22 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
if (newLine) {
nsLineList* overflowLines = GetOverflowLines();
if (overflowLines) {
// Need to put the overflow placeholders' floats into our
// overflow-out-of-flows list, since the overflow placeholders are
// going onto our overflow line list. Put them last, because that's
// where the placeholders are going.
nsFrameList floats;
nsIFrame* lastFloat = nsnull;
for (nsIFrame* f = state.mOverflowPlaceholders.FirstChild();
f; f = f->GetNextSibling()) {
NS_ASSERTION(IsContinuationPlaceholder(f),
"Overflow placeholders must be continuation placeholders");
nsIFrame* oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
// oof is not currently in any child list
floats.InsertFrames(nsnull, lastFloat, oof);
lastFloat = oof;
}
// Put the new placeholders *last* in the overflow lines
// because they might have previnflows in the overflow lines.
nsIFrame* lastChild = overflowLines->back()->LastChild();
@ -951,6 +968,9 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
// Create a new line as the last line and put the
// placeholders there
overflowLines->push_back(newLine);
nsAutoOOFFrameList oofs(this);
oofs.mList.AppendFrames(nsnull, floats.FirstChild());
}
else {
mLines.push_back(newLine);
@ -977,9 +997,7 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
}
}
// XXX_perf get rid of this! This is one of the things that makes
// incremental reflow O(N^2).
BuildFloatList(state);
CheckFloats(state);
// Compute our final size
ComputeFinalSize(aReflowState, state, aMetrics);
@ -4257,7 +4275,7 @@ nsBlockFrame::SplitPlaceholder(nsBlockReflowState& aState,
{
nsIFrame* nextInFlow;
nsresult rv = CreateNextInFlow(aState.mPresContext, this, aPlaceholder, nextInFlow);
if (NS_FAILED(rv))
if (NS_FAILED(rv))
return rv;
if (!nextInFlow) {
@ -4270,9 +4288,12 @@ nsBlockFrame::SplitPlaceholder(nsBlockReflowState& aState,
nsIFrame *next = contFrame->GetNextSibling();
aPlaceholder->SetNextSibling(next);
contFrame->SetNextSibling(nsnull);
NS_ASSERTION(IsContinuationPlaceholder(contFrame),
"Didn't create the right kind of frame");
// The new out of flow frame does not get put anywhere; the out-of-flows
// for placeholders in mOverflowPlaceholders are not kept in any child list
aState.mOverflowPlaceholders.AppendFrame(this, contFrame);
return NS_OK;
}
@ -4687,6 +4708,20 @@ nsBlockFrame::PushLines(nsBlockReflowState& aState,
PRBool firstLine = overBegin == begin_lines();
if (overBegin != end_lines()) {
// Remove floats in the lines from mFloats
nsFrameList floats;
nsIFrame* tail = nsnull;
CollectFloats(overBegin->mFirstChild, floats, &tail, PR_FALSE);
if (floats.NotEmpty()) {
// Push the floats onto the front of the overflow out-of-flows list
nsFrameList oofs = GetOverflowOutOfFlows();
if (oofs.NotEmpty()) {
floats.InsertFrames(nsnull, tail, oofs.FirstChild());
}
SetOverflowOutOfFlows(floats);
}
// overflow lines can already exist in some cases, in particular,
// when shrinkwrapping and we discover that the shrinkwap causes
// the height of some child block to grow which creates additional
@ -4812,11 +4847,11 @@ nsBlockFrame::HandleOverflowPlaceholdersForPulledFrame(
}
ReparentFrame(outOfFlow, parent, this);
aState.mOverflowPlaceholders.AppendFrame(nsnull, frame);
aState.mOverflowPlaceholders.InsertFrames(nsnull, lastOverflowPlace, frame);
// outOfFlow isn't inserted anywhere yet. Eventually the overflow
// placeholders get put into the overflow lines, then
// BuildFloatList collects their out-of-flows and puts them on the
// overflow out-of-flows list.
// placeholders get put into the overflow lines, and at the same time we
// insert the placeholders' out of flows into the overflow out-of-flows
// list.
lastOverflowPlace = frame;
frame = frame->GetNextInFlow();
@ -4908,7 +4943,8 @@ nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState)
if (ourOverflowLines) {
nsAutoOOFFrameList oofs(this);
if (oofs.mList.NotEmpty()) {
mFloats.InsertFrames(nsnull, nsnull, oofs.mList.FirstChild());
// The overflow floats go after our regular floats
mFloats.AppendFrames(nsnull, oofs.mList.FirstChild());
oofs.mList.SetFrames(nsnull);
}
}
@ -4921,11 +4957,14 @@ nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState)
NS_ASSERTION(aState.mOverflowPlaceholders.IsEmpty(),
"Should have no overflow placeholders yet");
// HANDLING CONTINUATION PLACEHOLDERS (floats only at the moment, because
// abs-pos frames don't have continuations)
//
// All continuation placeholders need to be moved to the front of
// our line list. We also need to maintain the invariant that at
// most one frame for a given piece of content is in our normal
// child list, by pushing all but the first placeholder to our
// overflow placeholders list
// overflow placeholders list.
//
// One problem we have to deal with is that some of these
// continuation placeholders may have been donated to us by a
@ -4936,9 +4975,16 @@ nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState)
// next in flows. We do not worry about properly ordering the
// placeholders for different content relative to each other until
// the end. Then we sort them.
//
// When we're shuffling placeholders we also need to shuffle their out of
// flows to match. As we put placeholders into keepPlaceholders, we unhook
// their floats from mFloats. Later we put the floats back based on the
// order of the placeholders.
nsIFrame* lastOP = nsnull;
nsFrameList keepPlaceholders;
nsFrameList keepOutOfFlows;
nsIFrame* lastKP = nsnull;
nsIFrame* lastKOOF = nsnull;
nsLineList* lineLists[3] = { overflowLines, &mLines, ourOverflowLines };
static const PRPackedBool searchFirstLinesOnly[3] = { PR_FALSE, PR_TRUE, PR_FALSE };
for (PRInt32 i = 0; i < 3; ++i) {
@ -4968,17 +5014,31 @@ nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState)
"Line frames should all be continuation placeholders");
next = f->GetNextSibling();
nsIFrame* fpif = f->GetPrevInFlow();
nsIFrame* oof = f->GetOutOfFlowFrame();
// Take this out of mFloats for now. We may put it back later in
// this function
#ifdef DEBUG
PRBool found =
#endif
mFloats.RemoveFrame(oof);
NS_ASSERTION(found, "Float should have been put in our mFloats list");
PRBool isAncestor = nsLayoutUtils::IsProperAncestorFrame(this, fpif);
if (isAncestor) {
// oops. we already have a prev-in-flow for this
// placeholder. We have to move this frame out of here. We
// can put it in our overflow placeholders.
aState.mOverflowPlaceholders.InsertFrame(nsnull, lastOP, f);
// Let oof dangle for now, because placeholders in
// mOverflowPlaceholders do not keep their floats in any child list
lastOP = f;
} else {
if (fpif->GetParent() == prevBlock) {
keepPlaceholders.InsertFrame(nsnull, lastKP, f);
keepOutOfFlows.InsertFrame(nsnull, lastKOOF, oof);
lastKP = f;
lastKOOF = oof;
} else {
// Ok, now we're in the tough situation where some child
// of prevBlock was complete and pushed its overflow
@ -4998,7 +5058,9 @@ nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState)
if (fpAncestor == prevBlock) {
// We're still the best parent.
keepPlaceholders.InsertFrame(nsnull, lastKP, f);
keepOutOfFlows.InsertFrame(nsnull, lastKOOF, oof);
lastKP = f;
lastKOOF = oof;
} else {
// Just put it at the front of
// fpAncestor->GetNextInFlow()'s lines.
@ -5014,12 +5076,6 @@ nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState)
target->mLines.push_front(newLine);
ReparentFrame(f, this, target);
nsIFrame* oof = f->GetOutOfFlowFrame();
#ifdef DEBUG
PRBool found =
#endif
mFloats.RemoveFrame(oof);
NS_ASSERTION(found, "Float should have been put in our mFloats list");
target->mFloats.InsertFrame(nsnull, nsnull, oof);
ReparentFrame(oof, this, target);
}
@ -5078,6 +5134,10 @@ nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState)
}
mLines.push_front(newLine);
}
// Put the placeholders' out of flows into the float list
keepOutOfFlows.SortByContentOrder();
mFloats.InsertFrames(nsnull, nsnull, keepOutOfFlows.FirstChild());
}
return PR_TRUE;
@ -5201,8 +5261,8 @@ nsBlockFrame::LastChild()
}
NS_IMETHODIMP
nsBlockFrame::AppendFrames(nsIAtom* aListName,
nsIFrame* aFrameList)
nsBlockFrame::AppendFrames(nsIAtom* aListName,
nsIFrame* aFrameList)
{
if (nsnull == aFrameList) {
return NS_OK;
@ -5211,8 +5271,6 @@ nsBlockFrame::AppendFrames(nsIAtom* aListName,
return mAbsoluteContainer.AppendFrames(this, aListName, aFrameList);
}
else if (nsLayoutAtoms::floatList == aListName) {
// XXX we don't *really* care about this right now because we are
// BuildFloatList ing still
mFloats.AppendFrames(nsnull, aFrameList);
return NS_OK;
}
@ -5247,18 +5305,16 @@ nsBlockFrame::AppendFrames(nsIAtom* aListName,
}
NS_IMETHODIMP
nsBlockFrame::InsertFrames(nsIAtom* aListName,
nsIFrame* aPrevFrame,
nsIFrame* aFrameList)
nsBlockFrame::InsertFrames(nsIAtom* aListName,
nsIFrame* aPrevFrame,
nsIFrame* aFrameList)
{
if (mAbsoluteContainer.GetChildListName() == aListName) {
return mAbsoluteContainer.InsertFrames(this, aListName, aPrevFrame,
aFrameList);
}
else if (nsLayoutAtoms::floatList == aListName) {
// XXX we don't *really* care about this right now because we are
// BuildFloatList'ing still
mFloats.AppendFrames(nsnull, aFrameList);
mFloats.InsertFrames(this, aPrevFrame, aFrameList);
return NS_OK;
}
#ifdef IBMBIDI
@ -5435,9 +5491,10 @@ nsBlockFrame::RemoveFloat(nsIFrame* aFloat) {
return line_end;
}
}
// If aFloat's parent is being reflowed then mFloats may not be up
// to date so we won't find the float above. Just delete it.
// If this is during reflow, it could be the out-of-flow frame for a
// placeholder in our block reflow state's mOverflowPlaceholders. But that's
// OK; it's not part of any child list, so we can just go ahead and delete it.
aFloat->Destroy(GetPresContext());
return line_end;
}
@ -5501,8 +5558,8 @@ static PRBool BlockHasAnyFloats(nsIFrame* aFrame)
}
NS_IMETHODIMP
nsBlockFrame::RemoveFrame(nsIAtom* aListName,
nsIFrame* aOldFrame)
nsBlockFrame::RemoveFrame(nsIAtom* aListName,
nsIFrame* aOldFrame)
{
nsresult rv = NS_OK;
@ -5940,7 +5997,7 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
// An incomplete reflow status means we should split the float
// if the height is constrained (bug 145305).
if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) && (NS_UNCONSTRAINEDSIZE == availHeight))
if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) && (NS_UNCONSTRAINEDSIZE == availHeight))
aReflowStatus = NS_FRAME_COMPLETE;
if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
@ -6964,7 +7021,6 @@ void nsBlockFrame::CollectFloats(nsIFrame* aFrame, nsFrameList& aList, nsIFrame*
oofs.mList.RemoveFrame(outOfFlowFrame);
} else {
mFloats.RemoveFrame(outOfFlowFrame);
}
aList.InsertFrame(nsnull, *aTail, outOfFlowFrame);
*aTail = outOfFlowFrame;
@ -6977,63 +7033,60 @@ void nsBlockFrame::CollectFloats(nsIFrame* aFrame, nsFrameList& aList, nsIFrame*
}
}
//XXX get rid of this -- it's slow
void
nsBlockFrame::BuildFloatList(nsBlockReflowState& aState)
nsBlockFrame::CheckFloats(nsBlockReflowState& aState)
{
// Accumulate float list into mFloats.
// Use the float cache to speed up searching the lines for floats.
nsIFrame* head = nsnull;
nsIFrame* current = nsnull;
#ifdef DEBUG
// Check that the float list is what we would have built
nsAutoVoidArray lineFloats;
for (line_iterator line = begin_lines(), line_end = end_lines();
line != line_end;
++line) {
line != line_end; ++line) {
if (line->HasFloats()) {
nsFloatCache* fc = line->GetFirstFloat();
while (fc) {
nsIFrame* floatFrame = fc->mPlaceholder->GetOutOfFlowFrame();
if (!head) {
current = head = floatFrame;
} else {
current->SetNextSibling(floatFrame);
current = floatFrame;
}
lineFloats.AppendElement(floatFrame);
fc = fc->Next();
}
}
}
// Terminate end of float list just in case a float was removed
if (current) {
current->SetNextSibling(nsnull);
}
mFloats.SetFrames(head);
// ensure that the floats in the overflow lines are put on a child list
// and not dropped from the frame tree!
// Note that overflow lines do not have any float cache set up for them,
// because the float cache contains only laid-out floats
nsLineList* overflowLines = GetOverflowLines();
if (overflowLines) {
nsFrameList oofs;
nsIFrame* tail = nsnull;
CollectFloats(overflowLines->front()->mFirstChild, oofs, &tail, PR_TRUE);
if (oofs.NotEmpty()) {
// Floats that were pushed should be removed from our space
// manager. Otherwise the space manager's YMost or XMost might
// be larger than necessary, causing this block to get an
// incorrect desired height (or width). Some of these floats
// may not actually have been added to the space manager because
// they weren't reflowed before being pushed; that's OK,
// RemoveRegions will ignore them. It is safe to do this here
// because we know from here on the space manager will only be
// used for its XMost and YMost, not to place new floats and
// lines.
aState.mSpaceManager->RemoveTrailingRegions(oofs.FirstChild());
SetOverflowOutOfFlows(oofs);
nsAutoVoidArray storedFloats;
PRBool equal = PR_TRUE;
PRInt32 i = 0;
for (nsIFrame* f = mFloats.FirstChild(); f; f = f->GetNextSibling()) {
storedFloats.AppendElement(f);
if (i < lineFloats.Count() && lineFloats.ElementAt(i) != f) {
equal = PR_FALSE;
}
++i;
}
if (!equal || lineFloats.Count() != storedFloats.Count()) {
NS_WARNING("nsBlockFrame::CheckFloats: Explicit float list is out of sync with float cache");
nsIFrameDebug::RootFrameList(GetPresContext(), stdout, 0);
for (i = 0; i < lineFloats.Count(); ++i) {
printf("Line float: %p\n", lineFloats.ElementAt(i));
}
for (i = 0; i < storedFloats.Count(); ++i) {
printf("Stored float: %p\n", storedFloats.ElementAt(i));
}
}
#endif
nsFrameList oofs = GetOverflowOutOfFlows();
if (oofs.NotEmpty()) {
// Floats that were pushed should be removed from our space
// manager. Otherwise the space manager's YMost or XMost might
// be larger than necessary, causing this block to get an
// incorrect desired height (or width). Some of these floats
// may not actually have been added to the space manager because
// they weren't reflowed before being pushed; that's OK,
// RemoveRegions will ignore them. It is safe to do this here
// because we know from here on the space manager will only be
// used for its XMost and YMost, not to place new floats and
// lines.
aState.mSpaceManager->RemoveTrailingRegions(oofs.FirstChild());
}
}

View File

@ -525,7 +525,7 @@ protected:
nsLineBox* aLine,
nscoord aDeltaY);
void BuildFloatList(nsBlockReflowState& aState);
void CheckFloats(nsBlockReflowState& aState);
//----------------------------------------
// List handling kludge

View File

@ -189,7 +189,11 @@ public:
nsSize mContentArea;
// Placeholders for continuation out-of-flow frames that need to
// move to our next in flow are placed here during reflow.
// move to our next in flow are placed here during reflow. At the end of reflow
// they move to the end of the overflow lines.
// Their out-of-flows are not in any child list during reflow, but are added
// to the overflow-out-of-flow list when the placeholders are appended to
// the overflow lines.
nsFrameList mOverflowPlaceholders;
//----------------------------------------