From 58ab0561e40cb48e7b5b76d8346c1a6fc7d8e36f Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 28 Jul 2009 08:51:08 -0400 Subject: [PATCH] Bug 504221 part 1. Introduce framelist slice and enumerator classes and make the framelist versions of nsFrameList::AppendFrames/InsertFrames return a slice for the new frames. r=fantasai, r+sr=roc --- layout/generic/nsFrameList.cpp | 16 +-- layout/generic/nsFrameList.h | 201 ++++++++++++++++++++++++++------- layout/generic/nsIFrame.h | 18 +++ 3 files changed, 182 insertions(+), 53 deletions(-) diff --git a/layout/generic/nsFrameList.cpp b/layout/generic/nsFrameList.cpp index 5587fb5b753..9c891c3fadb 100644 --- a/layout/generic/nsFrameList.cpp +++ b/layout/generic/nsFrameList.cpp @@ -39,7 +39,8 @@ /* class for maintaining a linked list of child frames */ #include "nsFrameList.h" -#ifdef NS_DEBUG +#include "nsIFrame.h" +#ifdef DEBUG #include "nsIFrameDebug.h" #endif #include "nsLayoutUtils.h" @@ -417,18 +418,7 @@ nsFrameList::GetPrevSiblingFor(nsIFrame* aFrame) const return frame; } -void -nsFrameList::VerifyParent(nsIFrame* aParent) const -{ -#ifdef NS_DEBUG - for (nsIFrame* frame = mFirstChild; frame; - frame = frame->GetNextSibling()) { - NS_ASSERTION(frame->GetParent() == aParent, "bad parent"); - } -#endif -} - -#ifdef NS_DEBUG +#ifdef DEBUG void nsFrameList::List(FILE* out) const { diff --git a/layout/generic/nsFrameList.h b/layout/generic/nsFrameList.h index 6f694c66fe6..fda43970623 100644 --- a/layout/generic/nsFrameList.h +++ b/layout/generic/nsFrameList.h @@ -40,27 +40,43 @@ #ifndef nsFrameList_h___ #define nsFrameList_h___ -#include "nsIFrame.h" +#include "nscore.h" +#include "nsTraceRefcnt.h" +#include /* for FILE* */ +#include "nsDebug.h" + +class nsIFrame; /** - * A class for managing a singly linked list of frames. Frames are - * linked together through their next-sibling pointer. + * A class for managing a list of frames. */ - class nsFrameList { public: - nsFrameList() { - mFirstChild = nsnull; + nsFrameList() : + mFirstChild(nsnull) + { + MOZ_COUNT_CTOR(nsFrameList); } - nsFrameList(nsIFrame* aHead) { - mFirstChild = aHead; + // XXX We should make this explicit when we can! + nsFrameList(nsIFrame* aHead) : + mFirstChild(aHead) + { + MOZ_COUNT_CTOR(nsFrameList); #ifdef DEBUG CheckForLoops(); #endif } + nsFrameList(const nsFrameList& aOther) : + mFirstChild(aOther.mFirstChild) + { + MOZ_COUNT_CTOR(nsFrameList); + } + ~nsFrameList() { + MOZ_COUNT_DTOR(nsFrameList); + // Don't destroy our frames here, so that we can have temporary nsFrameLists } void DestroyFrames(); @@ -75,56 +91,83 @@ public: #endif } - // Appends frames from aFrameList to this list. If aParent - // is not null, reparents the newly-added frames. + class Slice; + + /** + * Appends frames from aFrameList to this list. If aParent + * is not null, reparents the newly-added frames. + */ void AppendFrames(nsIFrame* aParent, nsIFrame* aFrameList); - void AppendFrames(nsIFrame* aParent, nsFrameList& aFrameList) { - AppendFrames(aParent, aFrameList.mFirstChild); + /** + * Appends aFrameList to this list. If aParent is not null, + * reparents the newly added frames. Clears out aFrameList and + * returns a list slice represening the newly-appended frames. + */ + Slice AppendFrames(nsIFrame* aParent, nsFrameList& aFrameList) { + NS_PRECONDITION(!aFrameList.IsEmpty(), "Unexpected empty list"); + nsIFrame* firstNewFrame = aFrameList.FirstChild(); + AppendFrames(aParent, firstNewFrame); aFrameList.mFirstChild = nsnull; + return Slice(*this, firstNewFrame, nsnull); } void AppendFrame(nsIFrame* aParent, nsIFrame* aFrame); - // Take aFrame out of the frame list. This also disconnects aFrame - // from the sibling list. This will return PR_FALSE if aFrame is - // nsnull or if aFrame is not in the list. The second frame is - // a hint for the prev-sibling of aFrame; if the hint is correct, - // then this is O(1) time. If successfully removed, the child's - // NextSibling pointer is cleared. + /** + * Take aFrame out of the frame list. This also disconnects aFrame + * from the sibling list. This will return PR_FALSE if aFrame is + * nsnull or if aFrame is not in the list. The second frame is + * a hint for the prev-sibling of aFrame; if the hint is correct, + * then this is O(1) time. If successfully removed, the child's + * NextSibling pointer is cleared. + */ PRBool RemoveFrame(nsIFrame* aFrame, nsIFrame* aPrevSiblingHint = nsnull); - // Remove the first child from the list. The caller is assumed to be - // holding a reference to the first child. This call is equivalent - // in behavior to calling RemoveFrame(FirstChild()). If successfully - // removed the first child's NextSibling pointer is cleared. + /** + * Remove the first child from the list. The caller is assumed to be + * holding a reference to the first child. This call is equivalent + * in behavior to calling RemoveFrame(FirstChild()). If successfully + * removed the first child's NextSibling pointer is cleared. + */ PRBool RemoveFirstChild(); - // Take aFrame out of the frame list and then destroy it. This also - // disconnects aFrame from the sibling list. This will return - // PR_FALSE if aFrame is nsnull or if aFrame is not in the list. + /** + * Take aFrame out of the frame list and then destroy it. This also + * disconnects aFrame from the sibling list. This will return + * PR_FALSE if aFrame is nsnull or if aFrame is not in the list. + */ PRBool DestroyFrame(nsIFrame* aFrame); - // Inserts aNewFrame right after aPrevSibling, or prepends to - // list if aPrevSibling is null. If aParent is not null, also - // reparents newly-added frame. Note that this method always - // sets the frame's nextSibling pointer. + /** + * Inserts aNewFrame right after aPrevSibling, or prepends to + * list if aPrevSibling is null. If aParent is not null, also + * reparents newly-added frame. Note that this method always + * sets the frame's nextSibling pointer. + */ void InsertFrame(nsIFrame* aParent, nsIFrame* aPrevSibling, nsIFrame* aNewFrame); - // Inserts aFrameList right after aPrevSibling, or prepends to - // list if aPrevSibling is null. If aParent is not null, also - // reparents newly-added frame. + /** + * Inserts aFrameList right after aPrevSibling, or prepends to + * list if aPrevSibling is null. If aParent is not null, also + * reparents newly-added frame. + */ void InsertFrames(nsIFrame* aParent, nsIFrame* aPrevSibling, nsIFrame* aFrameList); - void InsertFrames(nsIFrame* aParent, nsIFrame* aPrevSibling, - nsFrameList& aFrameList) { - InsertFrames(aParent, aPrevSibling, aFrameList.FirstChild()); - aFrameList.mFirstChild = nsnull; - } + /** + * Inserts aFrameList into this list after aPrevSibling (at the beginning if + * aPrevSibling is null). If aParent is not null, reparents the newly added + * frames. Clears out aFrameList and returns a list slice representing the + * newly-inserted frames. + * + * This is implemented in nsIFrame.h because it needs to know about nsIFrame. + */ + inline Slice InsertFrames(nsIFrame* aParent, nsIFrame* aPrevSibling, + nsFrameList& aFrameList); PRBool Split(nsIFrame* aAfterFrame, nsIFrame** aNextFrameResult); @@ -174,12 +217,90 @@ public: nsIFrame* GetNextVisualFor(nsIFrame* aFrame) const; #endif // IBMBIDI - void VerifyParent(nsIFrame* aParent) const; - -#ifdef NS_DEBUG +#ifdef DEBUG void List(FILE* out) const; #endif + class Enumerator; + + /** + * A class representing a slice of a frame list. + */ + class Slice { + friend class Enumerator; + + public: + // Implicit on purpose, so that we can easily create enumerators from + // nsFrameList via this impicit constructor. + Slice(const nsFrameList& aList) : +#ifdef DEBUG + mList(aList), +#endif + mStart(aList.FirstChild()), + mEnd(nsnull) + {} + + Slice(const nsFrameList& aList, nsIFrame* aStart, nsIFrame* aEnd) : +#ifdef DEBUG + mList(aList), +#endif + mStart(aStart), + mEnd(aEnd) + {} + + Slice(const Slice& aOther) : +#ifdef DEBUG + mList(aOther.mList), +#endif + mStart(aOther.mStart), + mEnd(aOther.mEnd) + {} + + private: +#ifdef DEBUG + const nsFrameList& mList; +#endif + nsIFrame* const mStart; // our starting frame + const nsIFrame* const mEnd; // The first frame that is NOT in the slice. + // May be null. + }; + + class Enumerator { + public: + Enumerator(const Slice& aSlice) : +#ifdef DEBUG + mSlice(aSlice), +#endif + mFrame(aSlice.mStart), + mEnd(aSlice.mEnd) + {} + + Enumerator(const Enumerator& aOther) : +#ifdef DEBUG + mSlice(aOther.mSlice), +#endif + mFrame(aOther.mFrame), + mEnd(aOther.mEnd) + {} + + PRBool AtEnd() const { return mFrame == mEnd; } + + /* Next() 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 void Next(); + + nsIFrame* get() const { return mFrame; } + + private: +#ifdef DEBUG + const Slice& mSlice; +#endif + nsIFrame* mFrame; // our current frame. + const nsIFrame* const mEnd; // The first frame we should NOT enumerate. + // May be null. + }; + private: #ifdef DEBUG void CheckForLoops(); diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index f42460b6750..55749f329d9 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -54,6 +54,7 @@ #include "nsIContent.h" #include "nsHTMLReflowMetrics.h" #include "gfxMatrix.h" +#include "nsFrameList.h" /** * New rules of reflow: @@ -2535,4 +2536,21 @@ private: nsIFrame* mFrame; }; +inline void +nsFrameList::Enumerator::Next() { + NS_ASSERTION(!AtEnd(), "Should have checked AtEnd()!"); + mFrame = mFrame->GetNextSibling(); +} + +inline nsFrameList::Slice +nsFrameList::InsertFrames(nsIFrame* aParent, nsIFrame* aPrevSibling, + nsFrameList& aFrameList) { + NS_PRECONDITION(!aFrameList.IsEmpty(), "Unexpected empty list"); + nsIFrame* firstNewFrame = aFrameList.FirstChild(); + nsIFrame* nextSibling = + aPrevSibling ? aPrevSibling->GetNextSibling() : FirstChild(); + InsertFrames(aParent, aPrevSibling, firstNewFrame); + aFrameList.mFirstChild = nsnull; + return Slice(*this, firstNewFrame, nextSibling); +} #endif /* nsIFrame_h___ */