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

This commit is contained in:
Boris Zbarsky 2009-07-28 08:51:08 -04:00
parent b47c10e3d6
commit 58ab0561e4
3 changed files with 182 additions and 53 deletions

View File

@ -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
{

View File

@ -40,27 +40,43 @@
#ifndef nsFrameList_h___
#define nsFrameList_h___
#include "nsIFrame.h"
#include "nscore.h"
#include "nsTraceRefcnt.h"
#include <stdio.h> /* 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();

View File

@ -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___ */