diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index da85e6bd4d35..4405d698294f 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -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 { diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h index cf8fe05ef2d2..46d56c0f4127 100644 --- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -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 /** diff --git a/layout/generic/nsFrameList.h b/layout/generic/nsFrameList.h index 57a0b95c9b12..6fd0377af8ba 100644 --- a/layout/generic/nsFrameList.h +++ b/layout/generic/nsFrameList.h @@ -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; diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 9f629cf5382a..47727d098640 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -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___ */