nsContentList.h

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */#ifndef nsContentList_h___#define nsContentList_h___#include "nsISupports.h"#include "nsCOMArray.h"#include "nsString.h"#include "nsIDOMHTMLCollection.h"#include "nsIDOMNodeList.h"#include "nsStubDocumentObserver.h"#include "nsIAtom.h"#include "nsINameSpaceManager.h"// This is a callback function type that can be used to implement an// arbitrary matching algorithm. aContent is the content that may// match the list, while aNamespaceID, aAtom, and aData are whatever// was passed to the list's constructor.typedef PRBool (*nsContentListMatchFunc)(nsIContent* aContent,
PRInt32 aNamespaceID,
nsIAtom* aAtom,
const nsAString& aData);
class nsIDocument;
class nsIDOMHTMLFormElement;
class nsBaseContentList : publicnsIDOMNodeList
{
public:
nsBaseContentList();
virtual ~nsBaseContentList();
NS_DECL_ISUPPORTS
// nsIDOMNodeList
NS_DECL_NSIDOMNODELIST
virtualvoid AppendElement(nsIContent *aContent);
virtualvoid RemoveElement(nsIContent *aContent);
virtual PRInt32 IndexOf(nsIContent *aContent, PRBool aDoFlush);
virtualvoid Reset();
staticvoid Shutdown();
protected:
nsCOMArray<nsIContent> mElements;
};
// This class is used only by form element code and this is a static// list of elements. NOTE! This list holds strong references to// the elements in the list.class nsFormContentList : public nsBaseContentList
{
public:
nsFormContentList(nsIDOMHTMLFormElement *aForm,
nsBaseContentList& aContentList);
};
/** * Class that's used as the key to hash nsContentList implementations * for fast retrieval */00099class nsContentListKey
{
public:
nsContentListKey(nsIDocument *aDocument,
nsIAtom* aMatchAtom,
PRInt32 aMatchNameSpaceId,
nsIContent* aRootContent)
: mMatchAtom(aMatchAtom),
mMatchNameSpaceId(aMatchNameSpaceId),
mDocument(aDocument),
mRootContent(aRootContent)
{
}
nsContentListKey(constnsContentListKey& aContentListKey)
: mMatchAtom(aContentListKey.mMatchAtom),
mMatchNameSpaceId(aContentListKey.mMatchNameSpaceId),
mDocument(aContentListKey.mDocument),
mRootContent(aContentListKey.mRootContent)
{
}
PRBool Equals(constnsContentListKey& aContentListKey) const{
return
mMatchAtom == aContentListKey.mMatchAtom &&
mMatchNameSpaceId == aContentListKey.mMatchNameSpaceId &&
mDocument == aContentListKey.mDocument &&
mRootContent == aContentListKey.mRootContent;
}
inline PRUint32 GetHash(void) const{
return
NS_PTR_TO_INT32(mMatchAtom.get()) ^
(NS_PTR_TO_INT32(mRootContent) << 8) ^
(NS_PTR_TO_INT32(mDocument) << 16) ^
(mMatchNameSpaceId << 24);
}
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)? Note that we work around// that a little by not caching lists with an mRootContent in// gCachedContentList. If we fix this, we can remove that check.nsIContent* mRootContent; // Weak ref
};
/** * 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/** * Class that implements a live NodeList that matches nodes in the * tree based on some criterion */00173class nsContentList : public nsBaseContentList,
protectednsContentListKey,
publicnsIDOMHTMLCollection,
publicnsStubDocumentObserver
{
public:
NS_DECL_ISUPPORTS_INHERITED
nsContentList(nsIDocument *aDocument,
nsIAtom* aMatchAtom,
PRInt32 aMatchNameSpaceId,
nsIContent* aRootContent = nsnull,
PRBool aDeep = PR_TRUE);
nsContentList(nsIDocument *aDocument,
nsContentListMatchFunc aFunc,
const nsAString& aData,
nsIContent* aRootContent = nsnull,
PRBool aDeep = PR_TRUE,
nsIAtom* aMatchAtom = nsnull,
PRInt32 aMatchNameSpaceId = kNameSpaceID_None);
virtual ~nsContentList();
// nsIDOMHTMLCollection
NS_DECL_NSIDOMHTMLCOLLECTION
// nsBaseContentList overridesvirtual PRInt32 IndexOf(nsIContent *aContent, PRBool aDoFlush);
// nsContentList public methods
NS_HIDDEN_(nsISupports*) GetParentObject();
NS_HIDDEN_(PRUint32) Length(PRBool aDoFlush);
NS_HIDDEN_(nsIContent*) Item(PRUint32 aIndex, PRBool aDoFlush);
NS_HIDDEN_(nsIContent*) NamedItem(const nsAString& aName, PRBool aDoFlush);
NS_HIDDEN_(void) RootDestroyed();
nsContentListKey* GetKey() {
return NS_STATIC_CAST(nsContentListKey*, this);
}
// nsIDocumentObservervirtualvoid AttributeChanged(nsIDocument *aDocument, nsIContent* aContent,
PRInt32 aNameSpaceID, nsIAtom* aAttribute,
PRInt32 aModType);
virtualvoid ContentAppended(nsIDocument *aDocument, nsIContent* aContainer,
PRInt32 aNewIndexInContainer);
virtualvoid ContentInserted(nsIDocument *aDocument, nsIContent* aContainer,
nsIContent* aChild, PRInt32 aIndexInContainer);
virtualvoid ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer,
nsIContent* aChild, PRInt32 aIndexInContainer);
virtualvoid DocumentWillBeDestroyed(nsIDocument *aDocument);
staticvoid OnDocumentDestroy(nsIDocument *aDocument);
protected:
void Init(nsIDocument *aDocument); /** * 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);
/** * 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 */voidPopulateWith(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 */voidPopulateWithStartingAfter(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). If mDocument is null, * the caller of PopulateSelf is responsible for calling SetDirty * once it's gotten the information it wants from the list. * * @param aNeededLength the length the list should have when we are * done (unless it exhausts the document) */voidPopulateSelf(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. */voidDisconnectFromDocument();
/** * @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 * (though if mDeep is false, only aContainer == mRootContent * counts), PR_FALSE otherwise */
PRBool MayContainRelevantNodes(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. */voidCheckDocumentExistence(); /** * Remove ourselves from the hashtable that caches commonly accessed * content lists. Generally done on destruction. */voidRemoveFromHashtable(); /** * If state is not LIST_UP_TO_DATE, fully populate ourselves with * all the nodes we can find. If mDocument is null, the caller of * BringSelfUpToDate is responsible for calling SetDirty once it's * gotten the information it wants from the list. */inlinevoidBringSelfUpToDate(PRBool aDoFlush); /** * A function to check whether aContent is anonymous from our point * of view. If it is, we don't care about it, since we should never * contain it or any of its kids. */
PRBool IsContentAnonymous(nsIContent* aContent);
/** * Sets the state to LIST_DIRTY and clears mElements array. * @note This is the only acceptable way to set state to LIST_DIRTY. */00340voidSetDirty()
{
mState = LIST_DIRTY;
Reset();
}
/** * Function to use to determine whether a piece of content matches * our criterion */00350 nsContentListMatchFunc mFunc; /** * Closure data to pass to mFunc when we call it */00354constnsAFlatString* mData; /** * True if we are looking for elements named "*" */00358 PRPackedBool mMatchAll; /** * The current state of the list (possible values are: * LIST_UP_TO_DATE, LIST_LAZY, LIST_DIRTY */00363 PRUint8 mState; /** * Whether to actually descend the tree. If this is false, we won't * consider grandkids of mRootContent. */00368 PRPackedBool mDeep;
};
already_AddRefed<nsContentList>
NS_GetContentList(nsIDocument* aDocument, nsIAtom* aMatchAtom,
PRInt32 aMatchNameSpaceId, nsIContent* aRootContent);
#endif // nsContentList_h___