Make content lists lazy. Bug 104603, r=jkeiser, sr=jst

This commit is contained in:
bzbarsky%mit.edu 2002-06-28 01:30:09 +00:00
Родитель f3834c4493
Коммит b477bcd31e
5 изменённых файлов: 408 добавлений и 160 удалений

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

@ -69,6 +69,22 @@ public:
static PRBool InSameDoc(nsIDOMNode *aNode,
nsIDOMNode *aOther);
/**
* Do not ever pass null pointers to this method. If one of your
* nsIContents is null, you have to decide for yourself what
* "IsDescendantOf" really means.
*
* @param aPossibleDescendant node to test for being a descendant of
* aPossibleAncestor
* @param aPossibleAncestor node to test for being an ancestor of
* aPossibleDescendant
* @return PR_TRUE if aPossibleDescendant is a descendant of
* aPossibleAncestor (or is aPossibleAncestor). PR_FALSE
* otherwise.
*/
static PRBool ContentIsDescendantOf(nsIContent* aPossibleDescendant,
nsIContent* aPossibleAncestor);
/*
* This method fills the |aArray| with all ancestor nodes of |aNode|
* including |aNode| at the zero index.

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

@ -39,6 +39,7 @@
#include "nsContentList.h"
#include "nsIContent.h"
#include "nsIDOMNode.h"
#include "nsIDOM3Node.h"
#include "nsIDocument.h"
#include "nsINameSpaceManager.h"
#include "nsGenericElement.h"
@ -381,29 +382,6 @@ NS_GetContentList(nsIDocument* aDocument, nsIAtom* aMatchAtom,
// nsContentList implementation
nsContentList::nsContentList(const nsContentList& aContentList)
: nsBaseContentList(), nsContentListKey(aContentList)
{
mFunc = aContentList.mFunc;
if (aContentList.mData) {
mData = new nsString(*aContentList.mData);
} else {
mData = nsnull;
}
mMatchAll = aContentList.mMatchAll;
mElements = aContentList.mElements;
}
nsContentList::nsContentList(nsIDocument *aDocument)
: nsBaseContentList(), nsContentListKey(aDocument, nsnull, kNameSpaceID_Unknown, nsnull)
{
mFunc = nsnull;
mData = nsnull;
mMatchAll = PR_FALSE;
}
nsContentList::nsContentList(nsIDocument *aDocument,
nsIAtom* aMatchAtom,
PRInt32 aMatchNameSpaceId,
@ -418,6 +396,7 @@ nsContentList::nsContentList(nsIDocument *aDocument,
}
mFunc = nsnull;
mData = nsnull;
mState = LIST_DIRTY;
Init(aDocument);
}
@ -438,6 +417,7 @@ nsContentList::nsContentList(nsIDocument *aDocument,
mMatchAtom = nsnull;
mRootContent = aRootContent;
mMatchAll = PR_FALSE;
mState = LIST_DIRTY;
Init(aDocument);
}
@ -452,7 +432,6 @@ void nsContentList::Init(nsIDocument *aDocument)
if (mDocument) {
mDocument->AddObserver(this);
}
PopulateSelf();
}
nsContentList::~nsContentList()
@ -483,9 +462,7 @@ nsContentList::GetLength(PRUint32* aLength, PRBool aDoFlush)
{
nsresult result = CheckDocumentExistence();
if (NS_SUCCEEDED(result)) {
if (mDocument && aDoFlush) {
mDocument->FlushPendingNotifications(PR_FALSE);
}
BringSelfUpToDate(aDoFlush);
*aLength = mElements.Count();
}
@ -503,7 +480,13 @@ nsContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn, PRBool aDoFlush)
mDocument->FlushPendingNotifications(PR_FALSE);
}
nsISupports *element = NS_STATIC_CAST(nsISupports *,
if (mState != LIST_UP_TO_DATE)
PopulateSelf(aIndex+1);
NS_ASSERTION(!mDocument || mState != LIST_DIRTY,
"PopulateSelf left the list in a dirty (useless) state!");
nsIContent *element = NS_STATIC_CAST(nsIContent *,
mElements.SafeElementAt(aIndex));
if (element) {
@ -523,9 +506,7 @@ nsContentList::NamedItem(const nsAString& aName, nsIDOMNode** aReturn, PRBool aD
nsresult result = CheckDocumentExistence();
if (NS_SUCCEEDED(result)) {
if (mDocument && aDoFlush) {
mDocument->FlushPendingNotifications(PR_FALSE); // Flush pending content changes Bug 4891
}
BringSelfUpToDate(aDoFlush);
PRInt32 i, count = mElements.Count();
@ -556,9 +537,7 @@ nsContentList::IndexOf(nsIContent *aContent, PRInt32& aIndex, PRBool aDoFlush)
{
nsresult result = CheckDocumentExistence();
if (NS_SUCCEEDED(result)) {
if (mDocument && aDoFlush) {
mDocument->FlushPendingNotifications(PR_FALSE);
}
BringSelfUpToDate(aDoFlush);
aIndex = mElements.IndexOf(aContent);
}
@ -588,22 +567,93 @@ NS_IMETHODIMP
nsContentList::ContentAppended(nsIDocument *aDocument, nsIContent* aContainer,
PRInt32 aNewIndexInContainer)
{
PRInt32 i, count;
/*
* If the state is LIST_DIRTY then we have no useful information in
* our list and we want to put off doing work as much as possible.
*/
if (mState == LIST_DIRTY)
return NS_OK;
PRInt32 count;
aContainer->ChildCount(count);
if ((count > 0) && IsDescendantOfRoot(aContainer)) {
PRBool repopulate = PR_FALSE;
/*
* We want to handle the case of ContentAppended by sometimes
* appending the content to our list, not just setting state to
* LIST_DIRTY, since most of our ContentAppended notifications
* should come during pageload and be at the end of the document.
* Do a bit of work to see whether we could just append to what we
* already have.
*/
for (i = aNewIndexInContainer; i <= count-1; i++) {
if ((count > 0) && IsDescendantOfRoot(aContainer)) {
PRInt32 ourCount = mElements.Count();
PRBool appendToList = PR_FALSE;
if (ourCount == 0) {
appendToList = PR_TRUE;
} else {
nsIContent* ourLastContent =
NS_STATIC_CAST(nsIContent*, mElements.ElementAt(ourCount - 1));
/*
* We want to append instead of invalidating in two cases:
* 1) aContainer is an ancestor of ourLastContent (this case
covers aContainer == ourLastContent)
* 2) aContainer comes after ourLastContent in document order
*/
if (nsContentUtils::ContentIsDescendantOf(ourLastContent, aContainer)) {
appendToList = PR_TRUE;
} else {
nsCOMPtr<nsIDOM3Node> ourLastDOM3Node(do_QueryInterface(ourLastContent));
nsCOMPtr<nsIDOMNode> newNodeContainer(do_QueryInterface(aContainer));
if (ourLastDOM3Node && newNodeContainer) {
PRUint16 comparisonFlags;
nsresult rv = ourLastDOM3Node->CompareTreePosition(newNodeContainer,
&comparisonFlags);
if (NS_SUCCEEDED(rv) &&
(comparisonFlags & nsIDOMNode::TREE_POSITION_FOLLOWING)) {
appendToList = PR_TRUE;
}
}
}
}
PRInt32 i;
if (!appendToList) {
// The new stuff is somewhere in the middle of our list; check
// whether we need to invalidate
nsCOMPtr<nsIContent> content;
for (i = aNewIndexInContainer; i <= count-1; ++i) {
aContainer->ChildAt(i, *getter_AddRefs(content));
if (mMatchAll || MatchSelf(content)) {
repopulate = PR_TRUE;
if (MatchSelf(content)) {
// Uh-oh. We're gonna have to add elements into the middle
// of our list. That's not worth the effort.
mState = LIST_DIRTY;
break;
}
}
if (repopulate) {
PopulateSelf();
return NS_OK;
}
/*
* At this point we know we could append. If we're not up to
* date, however, that would be a bad idea -- it could miss some
* content that we never picked up due to being lazy. Further, we
* may never get asked for this content... so don't grab it yet.
*/
if (mState == LIST_LAZY) // be lazy
return NS_OK;
/*
* We're up to date. That means someone's actively using us; we
* may as well grab this content....
*/
nsCOMPtr<nsIContent> content;
for (i = aNewIndexInContainer; i <= count-1; ++i) {
aContainer->ChildAt(i, *getter_AddRefs(content));
PRUint32 limit = PRUint32(-1);
PopulateWith(content, PR_TRUE, limit);
}
}
@ -616,11 +666,11 @@ nsContentList::ContentInserted(nsIDocument *aDocument,
nsIContent* aChild,
PRInt32 aIndexInContainer)
{
if (IsDescendantOfRoot(aContainer)) {
if (mMatchAll || MatchSelf(aChild)) {
PopulateSelf();
}
}
if (mState == LIST_DIRTY)
return NS_OK;
if (IsDescendantOfRoot(aContainer) && MatchSelf(aChild))
mState = LIST_DIRTY;
return NS_OK;
}
@ -632,9 +682,12 @@ nsContentList::ContentReplaced(nsIDocument *aDocument,
nsIContent* aNewChild,
PRInt32 aIndexInContainer)
{
if (mState == LIST_DIRTY)
return NS_OK;
if (IsDescendantOfRoot(aContainer)) {
if (mMatchAll || MatchSelf(aOldChild) || MatchSelf(aNewChild)) {
PopulateSelf();
if (MatchSelf(aOldChild) || MatchSelf(aNewChild)) {
mState = LIST_DIRTY;
}
}
else if (ContainsRoot(aOldChild)) {
@ -650,8 +703,10 @@ nsContentList::ContentRemoved(nsIDocument *aDocument,
nsIContent* aChild,
PRInt32 aIndexInContainer)
{
if (IsDescendantOfRoot(aContainer) && MatchSelf(aChild)) {
PopulateSelf();
if (IsDescendantOfRoot(aContainer)) {
if (MatchSelf(aChild)) {
mState = LIST_DIRTY;
}
}
else if (ContainsRoot(aChild)) {
DisconnectFromDocument();
@ -663,66 +718,50 @@ nsContentList::ContentRemoved(nsIDocument *aDocument,
NS_IMETHODIMP
nsContentList::DocumentWillBeDestroyed(nsIDocument *aDocument)
{
if (mDocument) {
// Our key will change... Best remove ourselves before that happens.
RemoveFromHashtable();
aDocument->RemoveObserver(this);
mDocument = nsnull;
}
DisconnectFromDocument();
Reset();
return NS_OK;
}
// Returns whether the content element matches the
// criterion
nsresult
nsContentList::Match(nsIContent *aContent, PRBool *aMatch)
PRBool
nsContentList::Match(nsIContent *aContent)
{
*aMatch = PR_FALSE;
if (!aContent) {
return NS_OK;
}
if (!aContent)
return PR_FALSE;
if (mMatchAtom) {
nsCOMPtr<nsINodeInfo> ni;
aContent->GetNodeInfo(*getter_AddRefs(ni));
if (!ni)
return NS_OK;
return PR_FALSE;
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
if (!node)
return NS_OK;
return PR_FALSE;
PRUint16 type;
node->GetNodeType(&type);
if (type != nsIDOMNode::ELEMENT_NODE)
return NS_OK;
return PR_FALSE;
if (mMatchNameSpaceId == kNameSpaceID_Unknown) {
if (mMatchAll || ni->Equals(mMatchAtom)) {
*aMatch = PR_TRUE;
}
} else if ((mMatchAll && ni->NamespaceEquals(mMatchNameSpaceId)) ||
ni->Equals(mMatchAtom, mMatchNameSpaceId)) {
*aMatch = PR_TRUE;
return (mMatchAll || ni->Equals(mMatchAtom));
}
return ((mMatchAll && ni->NamespaceEquals(mMatchNameSpaceId)) ||
ni->Equals(mMatchAtom, mMatchNameSpaceId));
}
else if (mFunc) {
*aMatch = (*mFunc)(aContent, mData);
return (*mFunc)(aContent, mData);
}
return NS_OK;
return PR_FALSE;
}
// If we were created outside the context of a document and we
// have root content, then check if our content has been added
// to a document yet. If so, we'll become an observer of the document.
nsresult
nsContentList::CheckDocumentExistence()
{
@ -731,25 +770,21 @@ nsContentList::CheckDocumentExistence()
result = mRootContent->GetDocument(mDocument);
if (mDocument) {
mDocument->AddObserver(this);
PopulateSelf();
mState = LIST_DIRTY;
}
}
return result;
}
// Match recursively. See if anything in the subtree
// matches the criterion.
PRBool
nsContentList::MatchSelf(nsIContent *aContent)
{
PRBool match;
PRInt32 i, count;
Match(aContent, &match);
if (match) {
if (Match(aContent))
return PR_TRUE;
}
PRInt32 i, count = -1;
aContent->ChildCount(count);
nsCOMPtr<nsIContent> child;
@ -763,103 +798,142 @@ nsContentList::MatchSelf(nsIContent *aContent)
return PR_FALSE;
}
// Add all elements in this subtree that match to our list.
void
nsContentList::PopulateWith(nsIContent *aContent, PRBool aIncludeRoot)
nsContentList::PopulateWith(nsIContent *aContent, PRBool aIncludeRoot,
PRUint32 & aElementsToAppend)
{
PRBool match;
PRInt32 i, count;
if (aIncludeRoot) {
Match(aContent, &match);
if (match) {
if (Match(aContent)) {
mElements.AppendElement(aContent);
--aElementsToAppend;
if (aElementsToAppend == 0)
return;
}
}
PRInt32 i, count;
aContent->ChildCount(count);
nsCOMPtr<nsIContent> child;
for (i = 0; i < count; i++) {
aContent->ChildAt(i, *getter_AddRefs(child));
PopulateWith(child, PR_TRUE);
PopulateWith(child, PR_TRUE, aElementsToAppend);
if (aElementsToAppend == 0)
return;
}
}
// Clear out our old list and build up a new one
void
nsContentList::PopulateSelf()
nsContentList::PopulateWithStartingAfter(nsIContent *aStartRoot,
nsIContent *aStartChild,
PRUint32 & aElementsToAppend)
{
#ifdef DEBUG
PRUint32 invariant = aElementsToAppend + mElements.Count();
#endif
PRInt32 i = 0;
if (aStartChild) {
aStartRoot->IndexOf(aStartChild, i);
NS_ASSERTION(i >= 0, "The start child must be a child of the start root!");
++i; // move to one past
}
PRInt32 childCount;
aStartRoot->ChildCount(childCount);
nsCOMPtr<nsIContent> child;
for ( ; i < childCount; ++i) {
aStartRoot->ChildAt(i, *getter_AddRefs(child));
PopulateWith(child, PR_TRUE, aElementsToAppend);
NS_ASSERTION(aElementsToAppend + mElements.Count() == invariant,
"Something is awry in PopulateWith!");
if (aElementsToAppend == 0)
return;
}
nsCOMPtr<nsIContent> parent;
aStartRoot->GetParent(*getter_AddRefs(parent));
if (parent)
PopulateWithStartingAfter(parent, aStartRoot, aElementsToAppend);
}
void
nsContentList::PopulateSelf(PRUint32 aNeededLength)
{
if (mState == LIST_DIRTY) {
Reset();
if (mRootContent) {
PopulateWith(mRootContent, PR_FALSE);
}
PRUint32 count = mElements.Count();
if (count >= aNeededLength) // We're all set
return;
PRUint32 elementsToAppend = aNeededLength - count;
#ifdef DEBUG
PRUint32 invariant = elementsToAppend + mElements.Count();
#endif
if (count != 0) {
PopulateWithStartingAfter(NS_STATIC_CAST(nsIContent*,
mElements.ElementAt(count - 1)),
nsnull,
elementsToAppend);
NS_ASSERTION(elementsToAppend + mElements.Count() == invariant,
"Something is awry in PopulateWithStartingAfter!");
} else if (mRootContent) {
PopulateWith(mRootContent, PR_FALSE, elementsToAppend);
NS_ASSERTION(elementsToAppend + mElements.Count() == invariant,
"Something is awry in PopulateWith!");
}
else if (mDocument) {
nsCOMPtr<nsIContent> root;
mDocument->GetRootContent(getter_AddRefs(root));
if (root) {
PopulateWith(root, PR_TRUE);
}
PopulateWith(root, PR_TRUE, elementsToAppend);
NS_ASSERTION(elementsToAppend + mElements.Count() == invariant,
"Something is awry in PopulateWith!");
}
}
if (mDocument) {
if (elementsToAppend != 0)
mState = LIST_UP_TO_DATE;
else
mState = LIST_LAZY;
} else {
// No document means we have to stay on our toes since we don't
// get content notifications.
mState = LIST_DIRTY;
}
}
// Is the specified element a descendant of the root? If there
// is no root, then yes. Otherwise keep tracing up the tree from
// the element till we find our root, or until we reach the
// document root.
PRBool
nsContentList::IsDescendantOfRoot(nsIContent* aContainer)
{
if (!mRootContent) {
#ifdef DEBUG
nsCOMPtr<nsIDocument> doc;
aContainer->GetDocument(*getter_AddRefs(doc));
NS_ASSERTION(doc == mDocument, "We should not get in here if aContainer is appended to some _other_ document!");
#endif
return PR_TRUE;
}
else if (mRootContent == aContainer) {
return PR_TRUE;
}
else if (!aContainer) {
if (!aContainer) {
return PR_FALSE;
}
else {
nsCOMPtr<nsIContent> parent;
PRBool ret;
aContainer->GetParent(*getter_AddRefs(parent));
ret = IsDescendantOfRoot(parent);
return ret;
}
return nsContentUtils::ContentIsDescendantOf(aContainer, mRootContent);
}
// Does this subtree contain the root?
PRBool
nsContentList::ContainsRoot(nsIContent* aContent)
{
if (!mRootContent) {
if (!mRootContent || !aContent) {
return PR_FALSE;
}
else if (mRootContent == aContent) {
return PR_TRUE;
}
else {
PRInt32 i, count;
aContent->ChildCount(count);
for (i = 0; i < count; i++) {
nsCOMPtr<nsIContent> child;
aContent->ChildAt(i, *getter_AddRefs(child));
if (ContainsRoot(child)) {
return PR_TRUE;
}
return nsContentUtils::ContentIsDescendantOf(mRootContent, aContent);
}
return PR_FALSE;
}
}
// Our root content has been disconnected from the
// document, so stop observing. The list then becomes
// a snapshot rather than a dynamic list.
void
nsContentList::DisconnectFromDocument()
{
@ -869,6 +943,10 @@ nsContentList::DisconnectFromDocument()
mDocument->RemoveObserver(this);
mDocument = nsnull;
}
// We will get no more updates, so we can never know we're up to
// date
mState = LIST_DIRTY;
}
void
@ -887,3 +965,16 @@ nsContentList::RemoveFromHashtable()
}
}
void
nsContentList::BringSelfUpToDate(PRBool aDoFlush)
{
if (mDocument && aDoFlush) {
mDocument->FlushPendingNotifications(PR_FALSE); // Flush pending content changes Bug 4891
}
if (mState != LIST_UP_TO_DATE)
PopulateSelf(PRUint32(-1));
NS_ASSERTION(!mDocument || mState == LIST_UP_TO_DATE,
"PopulateSelf dod not bring content list up to date!");
}

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

@ -90,6 +90,10 @@ public:
NS_IMETHOD Reset();
};
/**
* Class that's used as the key to hash nsContentList implementations
* for fast retrieval
*/
class nsContentListKey
{
public:
@ -133,9 +137,15 @@ protected:
nsCOMPtr<nsIAtom> mMatchAtom;
PRInt32 mMatchNameSpaceId;
nsIDocument* mDocument; // Weak ref
// XXX What if the mRootContent is detached from the doc and _then_
// goes away (so we never get notified)?
nsIContent* mRootContent; // Weak ref
};
/**
* Class that implements a live NodeList that matches nodes in the
* tree based on some criterion
*/
class nsContentList : public nsBaseContentList,
protected nsContentListKey,
public nsIDOMHTMLCollection,
@ -145,8 +155,6 @@ class nsContentList : public nsBaseContentList,
public:
NS_DECL_ISUPPORTS_INHERITED
nsContentList(const nsContentList& aContentList);
nsContentList(nsIDocument *aDocument);
nsContentList(nsIDocument *aDocument,
nsIAtom* aMatchAtom,
PRInt32 aMatchNameSpaceId,
@ -234,22 +242,135 @@ public:
}
protected:
nsresult Match(nsIContent *aContent, PRBool *aMatch);
void Init(nsIDocument *aDocument);
void PopulateWith(nsIContent *aContent, PRBool aIncludeRoot);
/**
* Returns whether the content element matches our criterion
*
* @param aContent the content to attempt to match
* @return whether we match
*/
PRBool Match(nsIContent *aContent);
/**
* Match recursively. See if anything in the subtree rooted at
* aContent matches our criterion.
*
* @param aContent the root of the subtree to match against
* @return whether we match something in the tree rooted at aContent
*/
PRBool MatchSelf(nsIContent *aContent);
void PopulateSelf();
/**
* Add elements in the subtree rooted in aContent that match our
* criterion to our list until we've picked up aElementsToAppend
* elements. This function enforces the invariant that
* |aElementsToAppend + mElements.Count()| is a constant.
*
* @param aContent the root of the subtree we want to traverse
* @param aIncludeRoot whether to include the root in the traversal
* @param aElementsToAppend how many elements to append to the list
* before stopping
*/
void PopulateWith(nsIContent *aContent, PRBool aIncludeRoot,
PRUint32 & aElementsToAppend);
/**
* Populate our list starting at the child of aStartRoot that comes
* after aStartChild (if such exists) and continuing in document
* order. Stop once we've picked up aElementsToAppend elements.
* This function enforces the invariant that |aElementsToAppend +
* mElements.Count()| is a constant.
*
* @param aStartRoot the node with whose children we want to start traversal
* @param aStartChild the child after which we want to start
* @param aElementsToAppend how many elements to append to the list
* before stopping
*/
void PopulateWithStartingAfter(nsIContent *aStartRoot,
nsIContent *aStartChild,
PRUint32 & aElementsToAppend);
/**
* Populate our list. Stop once we have at least aNeededLength
* elements. At the end of PopulateSelf running, either the last
* node we examined is the last node in our array or we have
* traversed the whole document (or both).
*
* @param aNeededLength the length the list should have when we are
* done (unless it exhausts the document)
*/
void PopulateSelf(PRUint32 aNeededLength);
/**
* Our root content has been disconnected from the document, so stop
* observing. From this point on, if someone asks us something we
* walk the tree rooted at mRootContent starting at the beginning
* and going as far as we need to to answer the question.
*/
void DisconnectFromDocument();
/**
* @param aContainer a content node which could be a descendant of
* mRootContent
* @return PR_TRUE if mRootContent is null, PR_FALSE if aContainer
* is null, PR_TRUE if aContainer is a descendant of mRootContent,
* PR_FALSE otherwise
*/
PRBool IsDescendantOfRoot(nsIContent* aContainer);
/**
* Does this subtree contain our mRootContent?
*
* @param aContainer the root of the subtree
* @return PR_FALSE if mRootContent is null, otherwise whether
* mRootContent is a descendant of aContainer
*/
PRBool ContainsRoot(nsIContent* aContent);
/**
* If we have no document and we have a root content, then check if
* our content has been added to a document. If so, we'll become an
* observer of the document.
*/
nsresult CheckDocumentExistence();
void RemoveFromHashtable();
inline void BringSelfUpToDate(PRBool aDoFlush);
/**
* Function to use to determine whether a piece of content matches
* our criterion
*/
nsContentListMatchFunc mFunc;
/**
* Closure data to pass to mFunc when we call it
*/
nsString* mData;
PRBool mMatchAll;
/**
* True if we are looking for elements named "*"
*/
PRPackedBool mMatchAll;
/**
* The current state of the list (possible values are:
* LIST_UP_TO_DATE, LIST_LAZY, LIST_DIRTY
*/
PRUint8 mState;
};
/**
* LIST_UP_TO_DATE means that the list is up to date and need not do
* any walking to be able to answer any questions anyone may have.
*/
#define LIST_UP_TO_DATE 0
/**
* LIST_DIRTY means that the list contains no useful information and
* if anyone asks it anything it will have to populate itself before
* answering.
*/
#define LIST_DIRTY 1
/**
* LIST_LAZY means that the list has populated itself to a certain
* extent and that that part of the list is still valid. Requests for
* things outside that part of the list will require walking the tree
* some more. When a list is in this state, the last thing in
* mElements is the last node in the tree that the list looked at.
*/
#define LIST_LAZY 2
extern nsresult
NS_GetContentList(nsIDocument* aDocument, nsIAtom* aMatchAtom,
PRInt32 aMatchNameSpaceId, nsIContent* aRootContent,

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

@ -584,6 +584,26 @@ nsContentUtils::InSameDoc(nsIDOMNode* aNode, nsIDOMNode* aOther)
return PR_FALSE;
}
// static
PRBool
nsContentUtils::ContentIsDescendantOf(nsIContent* aPossibleDescendant,
nsIContent* aPossibleAncestor)
{
NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!");
NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!");
nsCOMPtr<nsIContent> parent;
do {
if (aPossibleDescendant == aPossibleAncestor)
return PR_TRUE;
aPossibleDescendant->GetParent(*getter_AddRefs(parent));
aPossibleDescendant = parent;
} while (aPossibleDescendant);
return PR_FALSE;
}
// static
nsresult
nsContentUtils::GetAncestors(nsIDOMNode* aNode,

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

@ -1600,7 +1600,7 @@ nsFormControlList::AddElementToTable(nsIFormControl* aChild,
// Found an element, create a list, add the element to the list and put
// the list in the hash
nsContentList *list = new nsContentList(nsnull);
nsBaseContentList *list = new nsBaseContentList();
NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
list->AppendElement(content);
@ -1620,11 +1620,11 @@ nsFormControlList::AddElementToTable(nsIFormControl* aChild,
NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
// Upcast, uggly, but it works!
nsContentList *list = NS_STATIC_CAST(nsContentList *,
nsBaseContentList *list = NS_STATIC_CAST(nsBaseContentList *,
(nsIDOMNodeList *)nodeList.get());
PRInt32 oldIndex = -1;
list->IndexOf(newChild, oldIndex, PR_TRUE);
list->IndexOf(newChild, oldIndex);
// Add the new child only if it's not in our list already
if (oldIndex < 0) {
@ -1686,7 +1686,7 @@ nsFormControlList::RemoveElementFromTable(nsIFormControl* aChild,
NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
// Upcast, uggly, but it works!
nsContentList *list = NS_STATIC_CAST(nsContentList *,
nsBaseContentList *list = NS_STATIC_CAST(nsBaseContentList *,
(nsIDOMNodeList *)nodeList.get());
list->RemoveElement(content);