Bug 512471. Make nsBlockFrame's mFrames track its principal child list. r=roc,fantasai

This commit is contained in:
Boris Zbarsky 2009-09-29 15:47:05 -04:00
Родитель cc84606bde
Коммит 7761f7af77
4 изменённых файлов: 129 добавлений и 83 удалений

Просмотреть файл

@ -299,6 +299,8 @@ nsBlockFrame::Destroy()
nsPresContext* presContext = PresContext();
nsLineBox::DeleteLineList(presContext, mLines);
// Now clear mFrames, since we've destroyed all the frames in it.
mFrames.Clear();
// destroy overflow lines now
nsLineList* overflowLines = RemoveOverflowLines();
@ -521,14 +523,11 @@ nsBlockFrame::GetChildList(nsIAtom* aListName) const
return mAbsoluteContainer.GetChildList();
}
else if (nsnull == aListName) {
// XXXbz once we start using mFrames, or some other sane storage for our
// in-flow kids, we could switch GetChildList to returning a |const
// nsFrameList&|.
return mLines.empty() ? nsFrameList::EmptyList()
: nsFrameList(mLines.front()->mFirstChild,
mLines.back()->LastChild());
return mFrames;
}
else if (aListName == nsGkAtoms::overflowList) {
// XXXbz once we start using nsFrameList for our overflow list, we
// could switch GetChildList to returning a |const nsFrameList&|.
nsLineList* overflowLines = GetOverflowLines();
return overflowLines ? nsFrameList(overflowLines->front()->mFirstChild,
overflowLines->back()->LastChild())
@ -2093,11 +2092,11 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
nsBlockFrame* nextInFlow = aState.mNextInFlow;
line_iterator nifLine = nextInFlow->begin_lines();
nsLineBox *toMove;
PRBool collectOverflowFloats;
PRBool toMoveIsOverflowLine;
if (nifLine != nextInFlow->end_lines()) {
toMove = nifLine;
nextInFlow->mLines.erase(nifLine);
collectOverflowFloats = PR_FALSE;
toMoveIsOverflowLine = PR_FALSE;
} else {
// Grab an overflow line if there are any
nsLineList* overflowLines = nextInFlow->GetOverflowLines();
@ -2121,7 +2120,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
} else {
delete overflowLines;
}
collectOverflowFloats = PR_TRUE;
toMoveIsOverflowLine = PR_TRUE;
}
if (0 == toMove->GetChildCount()) {
@ -2141,20 +2140,37 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
lastFrame = frame;
frame = frame->GetNextSibling();
}
lastFrame->SetNextSibling(nsnull);
// Reparent floats whose placeholders are in the line.
ReparentFloats(toMove->mFirstChild, nextInFlow, collectOverflowFloats, PR_TRUE);
NS_ASSERTION(lastFrame == toMove->LastChild(), "Unexpected lastFrame");
NS_ASSERTION(aState.mPrevChild || mLines.empty(), "should have a prevchild here");
// Add line to our line list, and set its last child as our new prev-child
if (aState.mPrevChild) {
aState.mPrevChild->SetNextSibling(toMove->mFirstChild);
}
aState.mPrevChild = toMove->LastChild();
NS_ASSERTION(aState.mPrevChild == mFrames.LastChild(),
"Incorrect aState.mPrevChild before inserting line at end");
// Shift toMove's frames into our mFrames list.
if (toMoveIsOverflowLine) {
// Pulling from an overflow list
// XXXbz If we switch overflow lines to nsFrameList, we should
// change this SetNextSibling call.
lastFrame->SetNextSibling(nsnull);
} else {
// Pulling from nextInFlow->mFrames
nsFrameList::FrameLinkEnumerator linkToBreak(nextInFlow->mFrames, lastFrame);
nextInFlow->mFrames.ExtractHead(linkToBreak);
}
nsFrameList newFrames(toMove->mFirstChild, lastFrame);
mFrames.AppendFrames(nsnull, newFrames);
// Add line to our line list, and set its last child as our new prev-child
line = mLines.before_insert(end_lines(), toMove);
aState.mPrevChild = lastFrame;
NS_ASSERTION(aState.mPrevChild == mFrames.LastChild(),
"Incorrect aState.mPrevChild after inserting line at end");
// Reparent floats whose placeholders are in the line.
ReparentFloats(toMove->mFirstChild, nextInFlow, toMoveIsOverflowLine, PR_TRUE);
DumpLine(aState, toMove, deltaY, 0);
#ifdef DEBUG
@ -2523,8 +2539,26 @@ nsBlockFrame::PullFrameFrom(nsBlockReflowState& aState,
"mPrevChild should be the LastChild of the line we are adding to");
// The frame is being pulled from a next-in-flow; therefore we
// need to add it to our sibling list.
frame->SetNextSibling(nsnull);
aState.mPrevChild->SetNextSibling(frame);
if (fromLine == aFromContainer->mLines.begin()) {
// Pulling from the next-in-flow's normal line list
aFromContainer->mFrames.RemoveFrame(frame);
} else {
// Pulling from the next-in-flow's overflow list
// XXXbz If we switch overflow lines to nsFrameList, we should
// change this SetNextSibling call.
frame->SetNextSibling(nsnull);
}
// When pushing and pulling frames we need to check for whether any
// views need to be reparented
NS_ASSERTION(frame->GetParent() == aFromContainer, "unexpected parent frame");
ReparentFrame(frame, aFromContainer, this);
mFrames.InsertFrame(nsnull, aState.mPrevChild, frame);
// The frame might have (or contain) floats that need to be
// brought over too.
ReparentFloats(frame, aFromContainer, aFromOverflowLine, PR_TRUE);
}
// when aFromContainer is 'this', then aLine->LastChild()'s next sibling
// is already set correctly.
@ -2564,19 +2598,6 @@ nsBlockFrame::PullFrameFrom(nsBlockReflowState& aState,
}
}
// Change geometric parents
if (aFromContainer != this) {
// When pushing and pulling frames we need to check for whether any
// views need to be reparented
NS_ASSERTION(frame->GetParent() == aFromContainer, "unexpected parent frame");
ReparentFrame(frame, aFromContainer, this);
// The frame might have (or contain) floats that need to be
// brought over too.
ReparentFloats(frame, aFromContainer, aFromOverflowLine, PR_TRUE);
}
// Stop pulling because we found a frame to pull
aFrameResult = frame;
#ifdef DEBUG
@ -3172,8 +3193,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
NS_ENSURE_SUCCESS(rv, rv);
if (parent != this)
ReparentFrame(nextFrame, parent, this);
nextFrame->SetNextSibling(frame->GetNextSibling());
frame->SetNextSibling(nextFrame);
mFrames.InsertFrame(nsnull, frame, nextFrame);
madeContinuation = PR_TRUE; // needs to be added to mLines
nextFrame->RemoveStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
frameReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
@ -3241,8 +3261,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
NS_ENSURE_SUCCESS(rv, rv);
}
else if (madeContinuation) {
frame->SetNextSibling(nextFrame->GetNextSibling());
nextFrame->SetNextSibling(nsnull);
mFrames.RemoveFrame(nextFrame, frame);
}
// Put it in our overflow list
@ -3861,9 +3880,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
return rv;
}
nsIFrame* sib = aFrame->GetNextSibling();
aFrame->SetNextSibling(newFrame);
newFrame->SetNextSibling(sib);
mFrames.InsertFrame(nsnull, aFrame, newFrame);
if (aLine) {
aLine->SetChildCount(aLine->GetChildCount() + 1);
@ -4278,8 +4295,17 @@ nsBlockFrame::PushLines(nsBlockReflowState& aState,
overflowLines = new nsLineList();
}
if (overflowLines) {
// First, remove the frames we're pushing from mFrames
nsIFrame* oldLastChild = mFrames.LastChild();
if (firstLine) {
mFrames.Clear();
} else {
mFrames.RemoveFramesAfter(aLineBefore->LastChild());
}
if (!overflowLines->empty()) {
mLines.back()->LastChild()->SetNextSibling(overflowLines->front()->mFirstChild);
// XXXbz If we switch overflow lines to nsFrameList, we should
// change this SetNextSibling call.
oldLastChild->SetNextSibling(overflowLines->front()->mFirstChild);
}
overflowLines->splice(overflowLines->begin(), mLines, overBegin,
end_lines());
@ -4307,10 +4333,6 @@ nsBlockFrame::PushLines(nsBlockReflowState& aState,
}
}
// Break frame sibling list
if (!firstLine)
aLineBefore->LastChild()->SetNextSibling(nsnull);
#ifdef DEBUG
VerifyOverflowSituation();
#endif
@ -4379,15 +4401,18 @@ nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState)
if (overflowLines) {
if (!overflowLines->empty()) {
// Join the line lists
if (! mLines.empty())
{
if (!mLines.empty()) {
// Remember to recompute the margins on the first line. This will
// also recompute the correct deltaY if necessary.
mLines.front()->MarkPreviousMarginDirty();
// Join the sibling lists together
nsIFrame* lastFrame = overflowLines->back()->LastChild();
lastFrame->SetNextSibling(mLines.front()->mFirstChild);
}
}
// Join the sibling lists together
nsIFrame* firstFrame = overflowLines->front()->mFirstChild;
nsIFrame* lastFrame = overflowLines->back()->LastChild();
nsFrameList framesToInsert(firstFrame, lastFrame);
mFrames.InsertFrames(nsnull, nsnull, framesToInsert);
// Place overflow lines at the front of our line list
mLines.splice(mLines.begin(), *overflowLines);
NS_ASSERTION(overflowLines->empty(), "splice should empty list");
@ -4396,10 +4421,11 @@ nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState)
}
if (ourOverflowLines) {
if (!ourOverflowLines->empty()) {
if (!mLines.empty()) {
mLines.back()->LastChild()->
SetNextSibling(ourOverflowLines->front()->mFirstChild);
}
nsIFrame* firstFrame = ourOverflowLines->front()->mFirstChild;
nsIFrame* lastFrame = ourOverflowLines->back()->LastChild();
nsFrameList framesToAppend(firstFrame, lastFrame);
mFrames.AppendFrames(nsnull, framesToAppend);
// append the overflow to mLines
mLines.splice(mLines.end(), *ourOverflowLines);
}
@ -4664,7 +4690,6 @@ nsBlockFrame::InsertFrames(nsIAtom* aListName,
if (NS_FAILED(rv)) {
return rv;
}
aFrameList.Clear();
#ifdef IBMBIDI
if (aListName != nsGkAtoms::nextBidi)
#endif // IBMBIDI
@ -4687,8 +4712,7 @@ ShouldPutNextSiblingOnNewLine(nsIFrame* aLastFrame)
}
nsresult
nsBlockFrame::AddFrames(const nsFrameList& aFrameList,
nsIFrame* aPrevSibling)
nsBlockFrame::AddFrames(nsFrameList& aFrameList, nsIFrame* aPrevSibling)
{
// Clear our line cursor, since our lines may change.
ClearLineCursor();
@ -4729,16 +4753,13 @@ nsBlockFrame::AddFrames(const nsFrameList& aFrameList,
// Find the frame following aPrevSibling so that we can join up the
// two lists of frames.
nsIFrame* prevSiblingNextFrame = nsnull;
if (aPrevSibling) {
prevSiblingNextFrame = aPrevSibling->GetNextSibling();
// Split line containing aPrevSibling in two if the insertion
// point is somewhere in the middle of the line.
PRInt32 rem = prevSibLine->GetChildCount() - prevSiblingIndex - 1;
if (rem) {
// Split the line in two where the frame(s) are being inserted.
nsLineBox* line = NS_NewLineBox(presShell, prevSiblingNextFrame, rem, PR_FALSE);
nsLineBox* line = NS_NewLineBox(presShell, aPrevSibling->GetNextSibling(), rem, PR_FALSE);
if (!line) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -4753,20 +4774,20 @@ nsBlockFrame::AddFrames(const nsFrameList& aFrameList,
line->MarkDirty();
line->SetInvalidateTextRuns(PR_TRUE);
}
// Now (partially) join the sibling lists together
aPrevSibling->SetNextSibling(aFrameList.FirstChild());
}
else if (! mLines.empty()) {
prevSiblingNextFrame = mLines.front()->mFirstChild;
mLines.front()->MarkDirty();
mLines.front()->SetInvalidateTextRuns(PR_TRUE);
}
const nsFrameList::Slice& newFrames =
mFrames.InsertFrames(nsnull, aPrevSibling, aFrameList);
// Walk through the new frames being added and update the line data
// structures to fit.
nsIFrame* newFrame = aFrameList.FirstChild();
while (newFrame) {
for (nsFrameList::Enumerator e(newFrames); !e.AtEnd(); e.Next()) {
nsIFrame* newFrame = e.get();
NS_ASSERTION(!aPrevSibling || aPrevSibling->GetNextSibling() == newFrame,
"Unexpected aPrevSibling");
NS_ASSERTION(newFrame->GetType() != nsGkAtoms::placeholderFrame ||
(!newFrame->GetStyleDisplay()->IsAbsolutelyPositioned() &&
!newFrame->GetStyleDisplay()->IsFloating()),
@ -4807,11 +4828,6 @@ nsBlockFrame::AddFrames(const nsFrameList& aFrameList,
}
aPrevSibling = newFrame;
newFrame = newFrame->GetNextSibling();
}
if (prevSiblingNextFrame) {
// Connect the last new frame to the remainder of the sibling list
aPrevSibling->SetNextSibling(prevSiblingNextFrame);
}
#ifdef DEBUG
@ -5270,8 +5286,14 @@ found_frame:;
// Take aDeletedFrame out of the sibling list. Note that
// prevSibling will only be nsnull when we are deleting the very
// first frame in the main or overflow list.
if (prevSibling) {
prevSibling->SetNextSibling(nextFrame);
if (searchingOverflowList) {
if (prevSibling) {
// XXXbz If we switch overflow lines to nsFrameList, we should
// change this SetNextSibling call.
prevSibling->SetNextSibling(nextFrame);
}
} else {
mFrames.RemoveFrame(aDeletedFrame, prevSibling);
}
// Update the child count of the line to be accurate
@ -5370,7 +5392,7 @@ found_frame:;
// We switched to the overflow line list and we have a prev sibling
// (in the main list), in this case we don't want to pick up any
// sibling list from the deceased frames (bug 344557).
prevSibling->SetNextSibling(nsnull);
NS_ASSERTION(!prevSibling->GetNextSibling(), "Unexpected next sibling");
prevSibling = nsnull;
}
#ifdef NOISY_REMOVE_FRAME
@ -5435,11 +5457,18 @@ nsBlockFrame::StealFrame(nsPresContext* aPresContext,
while (--n >= 0) {
if (frame == aChild) {
// Disconnect from sibling list
if (prevSibling)
prevSibling->SetNextSibling(frame->GetNextSibling());
else
if (frame == line->mFirstChild) {
line->mFirstChild = frame->GetNextSibling();
frame->SetNextSibling(nsnull);
}
if (searchingOverflowList) {
// XXXbz If we switch overflow lines to nsFrameList, we should
// change this SetNextSibling call.
if (prevSibling)
prevSibling->SetNextSibling(frame->GetNextSibling());
frame->SetNextSibling(nsnull);
} else {
mFrames.RemoveFrame(frame, prevSibling);
}
// Register removal with the line boxes
PRInt32 count = line->GetChildCount();
@ -5479,6 +5508,10 @@ nsBlockFrame::StealFrame(nsPresContext* aPresContext,
}
++line;
TryAllLines(&line, &line_start, &line_end, &searchingOverflowList);
if (prevSibling && !prevSibling->GetNextSibling()) {
// We just switched to the overflow list. Null out prevSibling
prevSibling = nsnull;
}
}
return NS_ERROR_UNEXPECTED;
}
@ -6325,7 +6358,6 @@ nsBlockFrame::SetInitialChildList(nsIAtom* aListName,
if (NS_FAILED(rv)) {
return rv;
}
aChildList.Clear();
// Create list bullet if this is a list-item. Note that this is done
// here so that RenumberLists will work (it needs the bullets to
@ -6366,7 +6398,8 @@ nsBlockFrame::SetInitialChildList(nsIAtom* aListName,
// it to the flow now.
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE ==
styleList->mListStylePosition) {
AddFrames(nsFrameList(bullet, bullet), nsnull);
nsFrameList bulletList(bullet, bullet);
AddFrames(bulletList, nsnull);
mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET;
}
else {

Просмотреть файл

@ -400,9 +400,9 @@ protected:
* knows nothing about lines at all. So we need to find the line that
* contains aPrevSibling and add aFrameList after aPrevSibling on that line.
* new lines are created as necessary to handle block data in aFrameList.
* This function will clear aFrameList.
*/
virtual nsresult AddFrames(const nsFrameList& aFrameList,
nsIFrame* aPrevSibling);
virtual nsresult AddFrames(nsFrameList& aFrameList, nsIFrame* aPrevSibling);
#ifdef IBMBIDI
/**

Просмотреть файл

@ -416,6 +416,11 @@ public:
mPrev(aOther.mPrev)
{}
/* This constructor needs to know about nsIFrame, and nsIFrame will need to
know about nsFrameList methods, so in order to inline this put
the implementation in nsIFrame.h */
inline FrameLinkEnumerator(const nsFrameList& aList, nsIFrame* aPrevFrame);
void operator=(const FrameLinkEnumerator& aOther) {
NS_PRECONDITION(&List() == &aOther.List(), "Different lists?");
mFrame = aOther.mFrame;

Просмотреть файл

@ -2543,4 +2543,12 @@ nsFrameList::Enumerator::Next()
mFrame = mFrame->GetNextSibling();
}
inline
nsFrameList::FrameLinkEnumerator::
FrameLinkEnumerator(const nsFrameList& aList, nsIFrame* aPrevFrame)
: Enumerator(aList)
{
mPrev = aPrevFrame;
mFrame = aPrevFrame ? aPrevFrame->GetNextSibling() : aList.FirstChild();
}
#endif /* nsIFrame_h___ */