Bug 565820. Use Element as the return value for ReferencedElement. r=roc

This commit is contained in:
Boris Zbarsky 2010-05-14 13:04:51 -04:00
parent 3f415094ff
commit 626e1bb052
14 changed files with 113 additions and 107 deletions

View File

@ -172,6 +172,8 @@ struct nsShortcutCandidate {
class nsContentUtils
{
typedef mozilla::dom::Element Element;
public:
static nsresult Init();
@ -314,14 +316,12 @@ public:
* an element with the given id. aId must be nonempty, otherwise
* this method may return nodes even if they have no id!
*/
static nsIContent* MatchElementId(nsIContent *aContent,
const nsAString& aId);
static Element* MatchElementId(nsIContent *aContent, const nsAString& aId);
/**
* Similar to above, but to be used if one already has an atom for the ID
*/
static nsIContent* MatchElementId(nsIContent *aContent,
nsIAtom* aId);
static Element* MatchElementId(nsIContent *aContent, nsIAtom* aId);
/**
* Given a URI containing an element reference (#whatever),
@ -1349,7 +1349,7 @@ public:
* If aContent is an HTML element with a DOM level 0 'name', then
* return the name. Otherwise return null.
*/
static nsIAtom* IsNamedItem(mozilla::dom::Element* aElement);
static nsIAtom* IsNamedItem(Element* aElement);
/**
* Get the application manifest URI for this document. The manifest URI

View File

@ -136,6 +136,8 @@ class Element;
class nsIDocument : public nsINode
{
public:
typedef mozilla::dom::Element Element;
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOCUMENT_IID)
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
@ -303,8 +305,8 @@ public:
* @return PR_TRUE to keep the callback in the callback set, PR_FALSE
* to remove it.
*/
typedef PRBool (* IDTargetObserver)(nsIContent* aOldContent,
nsIContent* aNewContent, void* aData);
typedef PRBool (* IDTargetObserver)(Element* aOldElement,
Element* aNewelement, void* aData);
/**
* Add an IDTargetObserver for a specific ID. The IDTargetObserver
@ -313,8 +315,8 @@ public:
* for each ID.
* @return the content currently associated with the ID.
*/
virtual nsIContent* AddIDTargetObserver(nsIAtom* aID,
IDTargetObserver aObserver, void* aData) = 0;
virtual Element* AddIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver,
void* aData) = 0;
/**
* Remove the (aObserver, aData) pair for a specific ID, if registered.
*/
@ -480,31 +482,31 @@ public:
/**
* Return the root element for this document.
*/
mozilla::dom::Element *GetRootElement() const
Element *GetRootElement() const
{
return (mCachedRootElement &&
mCachedRootElement->GetNodeParent() == this) ?
reinterpret_cast<mozilla::dom::Element*>(mCachedRootElement.get()) :
reinterpret_cast<Element*>(mCachedRootElement.get()) :
GetRootElementInternal();
}
protected:
virtual mozilla::dom::Element *GetRootElementInternal() const = 0;
virtual Element *GetRootElementInternal() const = 0;
public:
// Get the root <html> element, or return null if there isn't one (e.g.
// if the root isn't <html>)
mozilla::dom::Element* GetHtmlElement();
Element* GetHtmlElement();
// Returns the first child of GetHtmlContent which has the given tag,
// or nsnull if that doesn't exist.
mozilla::dom::Element* GetHtmlChildElement(nsIAtom* aTag);
Element* GetHtmlChildElement(nsIAtom* aTag);
// Get the canonical <body> element, or return null if there isn't one (e.g.
// if the root isn't <html> or if the <body> isn't there)
mozilla::dom::Element* GetBodyElement() {
Element* GetBodyElement() {
return GetHtmlChildElement(nsGkAtoms::body);
}
// Get the canonical <head> element, or return null if there isn't one (e.g.
// if the root isn't <html> or if the <head> isn't there)
mozilla::dom::Element* GetHeadElement() {
Element* GetHeadElement() {
return GetHtmlChildElement(nsGkAtoms::head);
}
@ -1377,7 +1379,7 @@ protected:
virtual void MutationEventDispatched(nsINode* aTarget) = 0;
friend class mozAutoSubtreeModified;
virtual mozilla::dom::Element* GetNameSpaceElement()
virtual Element* GetNameSpaceElement()
{
return GetRootElement();
}

View File

@ -39,7 +39,7 @@
#ifndef NSREFERENCEDELEMENT_H_
#define NSREFERENCEDELEMENT_H_
#include "nsIContent.h"
#include "mozilla/dom/Element.h"
#include "nsIAtom.h"
#include "nsIDocument.h"
#include "nsThreadUtils.h"
@ -49,17 +49,17 @@ class nsIURI;
class nsCycleCollectionCallback;
/**
* Class to track what content is referenced by a given ID.
* Class to track what element is referenced by a given ID.
*
* To use it, call Reset() to set it up to watch a given URI. Call get()
* anytime to determine the referenced element (which may be null if
* the element isn't found). When the element changes, ContentChanged
* the element isn't found). When the element changes, ElementChanged
* will be called, so subclass this class if you want to receive that
* notification. ContentChanged runs at safe-for-script time, i.e. outside
* notification. ElementChanged runs at safe-for-script time, i.e. outside
* of the content update. Call Unlink() if you want to stop watching
* for changes (get() will then return null).
*
* By default this is a single-shot tracker --- i.e., when ContentChanged
* By default this is a single-shot tracker --- i.e., when ElementChanged
* fires, we will automatically stop tracking. get() will continue to return
* the changed-to element.
* Override IsPersistent to return PR_TRUE if you want to keep tracking after
@ -67,6 +67,8 @@ class nsCycleCollectionCallback;
*/
class nsReferencedElement {
public:
typedef mozilla::dom::Element Element;
nsReferencedElement() {}
~nsReferencedElement() {
Unlink();
@ -75,16 +77,16 @@ public:
/**
* Find which element, if any, is referenced.
*/
nsIContent* get() { return mContent; }
Element* get() { return mElement; }
/**
* Set up the reference. This can be called multiple times to
* change which reference is being tracked, but these changes
* do not trigger ContentChanged.
* do not trigger ElementChanged.
* @param aFrom the source element for context
* @param aURI the URI containing a hash-reference to the element
* @param aWatch if false, then we do not set up the notifications to track
* changes, so ContentChanged won't fire and get() will always return the same
* changes, so ElementChanged won't fire and get() will always return the same
* value, the current element for the ID.
*/
void Reset(nsIContent* aFrom, nsIURI* aURI, PRBool aWatch = PR_TRUE);
@ -95,14 +97,14 @@ public:
* @param aFrom the source element for context
* @param aID the ID of the element
* @param aWatch if false, then we do not set up the notifications to track
* changes, so ContentChanged won't fire and get() will always return the same
* changes, so ElementChanged won't fire and get() will always return the same
* value, the current element for the ID.
*/
void ResetWithID(nsIContent* aFrom, const nsString& aID,
PRBool aWatch = PR_TRUE);
/**
* Clears the reference. ContentChanged is not triggered. get() will return
* Clears the reference. ElementChanged is not triggered. get() will return
* null.
*/
void Unlink();
@ -111,12 +113,12 @@ public:
protected:
/**
* Override this to be notified of content changes. Don't forget
* to call this superclass method to change mContent. This is called
* Override this to be notified of element changes. Don't forget
* to call this superclass method to change mElement. This is called
* at script-runnable time.
*/
virtual void ContentChanged(nsIContent* aFrom, nsIContent* aTo) {
mContent = aTo;
virtual void ElementChanged(Element* aFrom, Element* aTo) {
mElement = aTo;
}
/**
@ -133,12 +135,12 @@ protected:
const nsString& aRef);
private:
static PRBool Observe(nsIContent* aOldContent,
nsIContent* aNewContent, void* aData);
static PRBool Observe(Element* aOldElement,
Element* aNewElement, void* aData);
class Notification : public nsISupports {
public:
virtual void SetTo(nsIContent* aTo) = 0;
virtual void SetTo(Element* aTo) = 0;
virtual void Clear() { mTarget = nsnull; }
virtual ~Notification() {}
protected:
@ -154,7 +156,8 @@ private:
public Notification
{
public:
ChangeNotification(nsReferencedElement* aTarget, nsIContent* aFrom, nsIContent* aTo)
ChangeNotification(nsReferencedElement* aTarget,
Element* aFrom, Element* aTo)
: Notification(aTarget), mFrom(aFrom), mTo(aTo)
{}
virtual ~ChangeNotification() {}
@ -163,18 +166,18 @@ private:
NS_IMETHOD Run() {
if (mTarget) {
mTarget->mPendingNotification = nsnull;
mTarget->ContentChanged(mFrom, mTo);
mTarget->ElementChanged(mFrom, mTo);
}
return NS_OK;
}
virtual void SetTo(nsIContent* aTo) { mTo = aTo; }
virtual void SetTo(Element* aTo) { mTo = aTo; }
virtual void Clear()
{
Notification::Clear(); mFrom = nsnull; mTo = nsnull;
}
protected:
nsCOMPtr<nsIContent> mFrom;
nsCOMPtr<nsIContent> mTo;
nsCOMPtr<Element> mFrom;
nsCOMPtr<Element> mTo;
};
friend class ChangeNotification;
@ -195,7 +198,7 @@ private:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
private:
virtual void SetTo(nsIContent* aTo) { }
virtual void SetTo(Element* aTo) { }
nsString mRef;
};
@ -203,7 +206,7 @@ private:
nsCOMPtr<nsIAtom> mWatchID;
nsCOMPtr<nsIDocument> mWatchDocument;
nsCOMPtr<nsIContent> mContent;
nsCOMPtr<Element> mElement;
nsRefPtr<Notification> mPendingNotification;
};

View File

@ -3200,27 +3200,22 @@ nsContentUtils::DispatchChromeEvent(nsIDocument *aDoc,
}
/* static */
nsIContent*
Element*
nsContentUtils::MatchElementId(nsIContent *aContent, nsIAtom* aId)
{
if (aId == aContent->GetID()) {
return aContent;
}
nsIContent *result = nsnull;
PRUint32 i, count = aContent->GetChildCount();
for (i = 0; i < count && result == nsnull; i++) {
result = MatchElementId(aContent->GetChildAt(i), aId);
for (nsIContent* cur = aContent;
cur;
cur = cur->GetNextNode(aContent)) {
if (aId == cur->GetID()) {
return cur->AsElement();
}
}
return result;
return nsnull;
}
// Id attribute matching function used by nsXMLDocument and
// nsHTMLDocument and others.
/* static */
nsIContent *
Element *
nsContentUtils::MatchElementId(nsIContent *aContent, const nsAString& aId)
{
NS_PRECONDITION(!aId.IsEmpty(), "Will match random elements");

View File

@ -3914,7 +3914,7 @@ nsDocument::GetElementById(const nsAString& aElementId,
return CallQueryInterface(e, aReturn);
}
nsIContent*
Element*
nsDocument::AddIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver,
void* aData)
{

View File

@ -151,6 +151,8 @@ class nsChildContentList;
class nsIdentifierMapEntry : public nsISupportsHashKey
{
public:
typedef mozilla::dom::Element Element;
nsIdentifierMapEntry(const nsISupports* aKey) :
nsISupportsHashKey(aKey), mNameContentList(nsnull)
{
@ -164,8 +166,8 @@ public:
void SetInvalidName();
PRBool IsInvalidName();
void AddNameElement(mozilla::dom::Element* aElement);
void RemoveNameElement(mozilla::dom::Element* aElement);
void AddNameElement(Element* aElement);
void RemoveNameElement(Element* aElement);
PRBool HasNameContentList() {
return mNameContentList != nsnull;
}
@ -178,7 +180,7 @@ public:
* Returns the element if we know the element associated with this
* id. Otherwise returns null.
*/
mozilla::dom::Element* GetIdElement();
Element* GetIdElement();
/**
* Append all the elements with this id to aElements
*/
@ -188,12 +190,12 @@ public:
* @return true if the content could be added, false if we failed due
* to OOM.
*/
PRBool AddIdElement(mozilla::dom::Element* aElement);
PRBool AddIdElement(Element* aElement);
/**
* This can fire ID change callbacks.
* @return true if this map entry should be removed
*/
PRBool RemoveIdElement(mozilla::dom::Element* aElement);
PRBool RemoveIdElement(Element* aElement);
PRBool HasContentChangeCallback() { return mChangeCallbacks != nsnull; }
void AddContentChangeCallback(nsIDocument::IDTargetObserver aCallback, void* aData);
@ -236,8 +238,7 @@ public:
};
private:
void FireChangeCallbacks(mozilla::dom::Element* aOldElement,
mozilla::dom::Element* aNewElement);
void FireChangeCallbacks(Element* aOldElement, Element* aNewElement);
// empty if there are no elementswith this ID.
// The elementsnodes are stored addrefed.
@ -562,8 +563,8 @@ public:
*/
virtual void RemoveCharSetObserver(nsIObserver* aObserver);
virtual nsIContent* AddIDTargetObserver(nsIAtom* aID,
IDTargetObserver aObserver, void* aData);
virtual Element* AddIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver,
void* aData);
virtual void RemoveIDTargetObserver(nsIAtom* aID,
IDTargetObserver aObserver, void* aData);
@ -589,7 +590,7 @@ public:
nsIDocument* aSubDoc);
virtual nsIDocument* GetSubDocumentFor(nsIContent *aContent) const;
virtual nsIContent* FindContentForSubDocument(nsIDocument *aDocument) const;
virtual mozilla::dom::Element* GetRootElementInternal() const;
virtual Element* GetRootElementInternal() const;
/**
* Get the style sheets owned by this document.
@ -934,10 +935,10 @@ protected:
friend class nsNodeUtils;
void RegisterNamedItems(nsIContent *aContent);
void UnregisterNamedItems(nsIContent *aContent);
void UpdateNameTableEntry(mozilla::dom::Element *aElement);
void UpdateIdTableEntry(mozilla::dom::Element *aElement);
void RemoveFromNameTable(mozilla::dom::Element *aElement);
void RemoveFromIdTable(mozilla::dom::Element *aElement);
void UpdateNameTableEntry(Element *aElement);
void UpdateIdTableEntry(Element *aElement);
void RemoveFromNameTable(Element *aElement);
void RemoveFromIdTable(Element *aElement);
/**
* Check that aId is not empty and log a message to the console

View File

@ -152,20 +152,15 @@ nsReferencedElement::Reset(nsIContent* aFromContent, nsIURI* aURI, PRBool aWatch
// Get the element
if (isXBL) {
nsCOMPtr<nsIDOMNodeList> anonymousChildren;
doc->BindingManager()->
GetAnonymousNodesFor(bindingParent, getter_AddRefs(anonymousChildren));
nsINodeList* anonymousChildren =
doc->BindingManager()-> GetAnonymousNodesFor(bindingParent);
if (anonymousChildren) {
PRUint32 length;
anonymousChildren->GetLength(&length);
for (PRUint32 i = 0; i < length && !mContent; ++i) {
nsCOMPtr<nsIDOMNode> node;
anonymousChildren->Item(i, getter_AddRefs(node));
nsCOMPtr<nsIContent> c = do_QueryInterface(node);
if (c) {
mContent = nsContentUtils::MatchElementId(c, ref);
}
for (PRUint32 i = 0; i < length && !mElement; ++i) {
mElement =
nsContentUtils::MatchElementId(anonymousChildren->GetNodeAt(i), ref);
}
}
@ -210,7 +205,7 @@ nsReferencedElement::HaveNewDocument(nsIDocument* aDocument, PRBool aWatch,
if (aWatch) {
mWatchDocument = aDocument;
if (mWatchDocument) {
mContent = mWatchDocument->AddIDTargetObserver(mWatchID, Observe, this);
mElement = mWatchDocument->AddIDTargetObserver(mWatchID, Observe, this);
}
return;
}
@ -221,10 +216,12 @@ nsReferencedElement::HaveNewDocument(nsIDocument* aDocument, PRBool aWatch,
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDocument);
NS_ASSERTION(domDoc, "Content doesn't reference a dom Document");
// XXXbz we should really have a sane GetElementById on nsIDocument.
nsCOMPtr<nsIDOMElement> element;
domDoc->GetElementById(aRef, getter_AddRefs(element));
if (element) {
mContent = do_QueryInterface(element);
nsCOMPtr<nsIContent> content = do_QueryInterface(element);
mElement = content->AsElement();
}
}
@ -234,7 +231,7 @@ nsReferencedElement::Traverse(nsCycleCollectionTraversalCallback* aCB)
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCB, "mWatchDocument");
aCB->NoteXPCOMChild(mWatchDocument);
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCB, "mContent");
aCB->NoteXPCOMChild(mContent);
aCB->NoteXPCOMChild(mElement);
}
void
@ -249,20 +246,20 @@ nsReferencedElement::Unlink()
}
mWatchDocument = nsnull;
mWatchID = nsnull;
mContent = nsnull;
mElement = nsnull;
}
PRBool
nsReferencedElement::Observe(nsIContent* aOldContent,
nsIContent* aNewContent, void* aData)
nsReferencedElement::Observe(Element* aOldElement,
Element* aNewElement, void* aData)
{
nsReferencedElement* p = static_cast<nsReferencedElement*>(aData);
if (p->mPendingNotification) {
p->mPendingNotification->SetTo(aNewContent);
p->mPendingNotification->SetTo(aNewElement);
} else {
NS_ASSERTION(aOldContent == p->mContent, "Failed to track content!");
NS_ASSERTION(aOldElement == p->mElement, "Failed to track content!");
ChangeNotification* watcher =
new ChangeNotification(p, aOldContent, aNewContent);
new ChangeNotification(p, aOldElement, aNewElement);
p->mPendingNotification = watcher;
nsContentUtils::AddScriptRunner(watcher);
}
@ -290,11 +287,11 @@ nsReferencedElement::DocumentLoadNotification::Observe(nsISupports* aSubject,
if (mTarget) {
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aSubject);
mTarget->mPendingNotification = nsnull;
NS_ASSERTION(!mTarget->mContent, "Why do we have content here?");
NS_ASSERTION(!mTarget->mElement, "Why do we have content here?");
// If we got here, that means we had Reset() called with aWatch ==
// PR_TRUE. So keep watching if IsPersistent().
mTarget->HaveNewDocument(doc, mTarget->IsPersistent(), mRef);
mTarget->ContentChanged(nsnull, mTarget->mContent);
mTarget->ElementChanged(nsnull, mTarget->mElement);
}
return NS_OK;
}

View File

@ -105,8 +105,8 @@ protected:
TimebaseElement(nsSMILTimeValueSpec* aOwner) : mSpec(aOwner) { }
protected:
virtual void ContentChanged(nsIContent* aFrom, nsIContent* aTo) {
nsReferencedElement::ContentChanged(aFrom, aTo);
virtual void ElementChanged(Element* aFrom, Element* aTo) {
nsReferencedElement::ElementChanged(aFrom, aTo);
mSpec->UpdateTimebase(aFrom, aTo);
}
virtual PRBool IsPersistent() { return PR_TRUE; }

View File

@ -109,8 +109,8 @@ protected:
// We need to be notified when target changes, in order to request a
// sample (which will clear animation effects from old target and apply
// them to the new target).
virtual void ContentChanged(nsIContent* aFrom, nsIContent* aTo) {
nsReferencedElement::ContentChanged(aFrom, aTo);
virtual void ElementChanged(Element* aFrom, Element* aTo) {
nsReferencedElement::ElementChanged(aFrom, aTo);
mAnimationElement->AnimationNeedsResample();
}

View File

@ -106,8 +106,8 @@ protected:
// We need to be notified when target changes, in order to request a sample
// (which will clear animation effects that used the old target-path
// and recompute the animation effects using the new target-path).
virtual void ContentChanged(nsIContent* aFrom, nsIContent* aTo) {
nsReferencedElement::ContentChanged(aFrom, aTo);
virtual void ElementChanged(Element* aFrom, Element* aTo) {
nsReferencedElement::ElementChanged(aFrom, aTo);
if (aFrom) {
aFrom->RemoveMutationObserver(mMpathElement);
}

View File

@ -113,8 +113,8 @@ protected:
public:
SourceReference(nsSVGUseElement* aContainer) : mContainer(aContainer) {}
protected:
virtual void ContentChanged(nsIContent* aFrom, nsIContent* aTo) {
nsReferencedElement::ContentChanged(aFrom, aTo);
virtual void ElementChanged(Element* aFrom, Element* aTo) {
nsReferencedElement::ElementChanged(aFrom, aTo);
if (aFrom) {
aFrom->RemoveMutationObserver(mContainer);
}

View File

@ -503,13 +503,9 @@ RemoveInsertionParentForNodeList(nsIDOMNodeList* aList, nsIContent* aParent)
void
nsBindingManager::RemoveInsertionParent(nsIContent* aParent)
{
nsCOMPtr<nsIDOMNodeList> contentlist;
GetContentListFor(aParent, getter_AddRefs(contentlist));
RemoveInsertionParentForNodeList(contentlist, aParent);
RemoveInsertionParentForNodeList(GetContentListFor(aParent), aParent);
nsCOMPtr<nsIDOMNodeList> anonnodes;
GetAnonymousNodesFor(aParent, getter_AddRefs(anonnodes));
RemoveInsertionParentForNodeList(anonnodes, aParent);
RemoveInsertionParentForNodeList(GetAnonymousNodesFor(aParent), aParent);
if (mInsertionParentTable.ops) {
PL_DHashTableEnumerate(&mInsertionParentTable, RemoveInsertionParentCB,
@ -766,6 +762,13 @@ nsBindingManager::GetAnonymousNodesFor(nsIContent* aContent,
return NS_OK;
}
nsINodeList*
nsBindingManager::GetAnonymousNodesFor(nsIContent* aContent)
{
PRBool dummy;
return GetAnonymousNodesInternal(aContent, &dummy);
}
nsresult
nsBindingManager::SetAnonymousNodesFor(nsIContent* aContent,
nsInsertionPointList* aList)

View File

@ -134,6 +134,11 @@ public:
*/
nsresult GetAnonymousNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult);
/**
* Same as above, but without the XPCOM goop
*/
nsINodeList* GetAnonymousNodesFor(nsIContent* aContent);
/**
* Set the anonymous child content for the specified element.
* The binding manager assumes ownership of aList.

View File

@ -90,11 +90,11 @@ protected:
public:
SourceReference(nsSVGRenderingObserver* aContainer) : mContainer(aContainer) {}
protected:
virtual void ContentChanged(nsIContent* aFrom, nsIContent* aTo) {
virtual void ElementChanged(Element* aFrom, Element* aTo) {
if (aFrom) {
aFrom->RemoveMutationObserver(mContainer);
}
nsReferencedElement::ContentChanged(aFrom, aTo);
nsReferencedElement::ElementChanged(aFrom, aTo);
if (aTo) {
aTo->AddMutationObserver(mContainer);
}