diff --git a/mozilla/content/base/src/nsDOMAttribute.cpp b/mozilla/content/base/src/nsDOMAttribute.cpp index 273df8a5302..9f15dbb351b 100644 --- a/mozilla/content/base/src/nsDOMAttribute.cpp +++ b/mozilla/content/base/src/nsDOMAttribute.cpp @@ -98,7 +98,8 @@ NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsDOMAttribute) -NS_IMPL_RELEASE(nsDOMAttribute) +NS_IMPL_RELEASE_WITH_DESTROY(nsDOMAttribute, + nsNodeUtils::LastRelease(this)) // nsIDOMGCParticipant methods nsIDOMGCParticipant* diff --git a/mozilla/content/base/src/nsDocument.cpp b/mozilla/content/base/src/nsDocument.cpp index 831bc7e56f7..6cd6a765835 100644 --- a/mozilla/content/base/src/nsDocument.cpp +++ b/mozilla/content/base/src/nsDocument.cpp @@ -748,6 +748,10 @@ nsDocument::~nsDocument() NS_RELEASE(mCSSLoader); } + // Delete properties before dropping the document reference from + // NodeInfoManager! + mPropertyTable.DeleteAllProperties(); + // XXX Ideally we'd do this cleanup in the nsIDocument destructor. if (mNodeInfoManager) { mNodeInfoManager->DropDocumentReference(); @@ -809,7 +813,8 @@ NS_INTERFACE_MAP_BEGIN(nsDocument) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsDocument) -NS_IMPL_RELEASE(nsDocument) +NS_IMPL_RELEASE_WITH_DESTROY(nsDocument, + nsNodeUtils::LastRelease(this)) nsresult nsDocument::Init() diff --git a/mozilla/content/base/src/nsDocumentFragment.cpp b/mozilla/content/base/src/nsDocumentFragment.cpp index c7c6b9bece9..3aa793f0754 100644 --- a/mozilla/content/base/src/nsDocumentFragment.cpp +++ b/mozilla/content/base/src/nsDocumentFragment.cpp @@ -213,8 +213,8 @@ NS_INTERFACE_MAP_BEGIN(nsDocumentFragment) NS_INTERFACE_MAP_END -NS_IMPL_ADDREF(nsDocumentFragment) -NS_IMPL_RELEASE(nsDocumentFragment) +NS_IMPL_ADDREF_INHERITED(nsDocumentFragment, nsGenericElement) +NS_IMPL_RELEASE_INHERITED(nsDocumentFragment, nsGenericElement) NS_IMETHODIMP nsDocumentFragment::GetNodeType(PRUint16* aNodeType) diff --git a/mozilla/content/base/src/nsGenericDOMDataNode.cpp b/mozilla/content/base/src/nsGenericDOMDataNode.cpp index 4197e125982..3a716a17b7d 100644 --- a/mozilla/content/base/src/nsGenericDOMDataNode.cpp +++ b/mozilla/content/base/src/nsGenericDOMDataNode.cpp @@ -97,7 +97,8 @@ nsGenericDOMDataNode::~nsGenericDOMDataNode() NS_IMPL_ADDREF(nsGenericDOMDataNode) -NS_IMPL_RELEASE(nsGenericDOMDataNode) +NS_IMPL_RELEASE_WITH_DESTROY(nsGenericDOMDataNode, + nsNodeUtils::LastRelease(this)) NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataNode) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent) diff --git a/mozilla/content/base/src/nsGenericElement.cpp b/mozilla/content/base/src/nsGenericElement.cpp index ed75f8f86bc..a57ef6c48e0 100644 --- a/mozilla/content/base/src/nsGenericElement.cpp +++ b/mozilla/content/base/src/nsGenericElement.cpp @@ -145,14 +145,6 @@ nsINode::~nsINode() { NS_ASSERTION(!HasSlots(), "Don't know how to kill the slots"); - nsIDocument *document = GetOwnerDoc(); - if (document && HasProperties()) { - nsContentUtils::CallUserDataHandler(document, - nsIDOMUserDataHandler::NODE_DELETED, - this, nsnull, nsnull); - document->PropertyTable()->DeleteAllPropertiesFor(this); - } - if (HasFlag(NODE_HAS_RANGELIST)) { #ifdef DEBUG if (!nsContentUtils::LookupRangeList(this) && @@ -3099,7 +3091,8 @@ NS_INTERFACE_MAP_BEGIN(nsGenericElement) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsGenericElement) -NS_IMPL_RELEASE(nsGenericElement) +NS_IMPL_RELEASE_WITH_DESTROY(nsGenericElement, + nsNodeUtils::LastRelease(this)) nsresult nsGenericElement::PostQueryInterface(REFNSIID aIID, void** aInstancePtr) diff --git a/mozilla/content/base/src/nsGkAtomList.h b/mozilla/content/base/src/nsGkAtomList.h index 8b804fda9e6..1e514347235 100755 --- a/mozilla/content/base/src/nsGkAtomList.h +++ b/mozilla/content/base/src/nsGkAtomList.h @@ -620,6 +620,7 @@ GK_ATOM(popupanchor, "popupanchor") GK_ATOM(popupgroup, "popupgroup") GK_ATOM(popuphidden, "popuphidden") GK_ATOM(popuphiding, "popuphiding") +GK_ATOM(popuplistener, "popuplistener") GK_ATOM(popupset, "popupset") GK_ATOM(popupshowing, "popupshowing") GK_ATOM(popupshown, "popupshown") @@ -791,6 +792,7 @@ GK_ATOM(toolbarbutton, "toolbarbutton") GK_ATOM(toolbaritem, "toolbaritem") GK_ATOM(toolbox, "toolbox") GK_ATOM(tooltip, "tooltip") +GK_ATOM(tooltiplistener, "tooltiplistener") GK_ATOM(tooltiptext, "tooltiptext") GK_ATOM(top, "top") GK_ATOM(topmargin, "topmargin") diff --git a/mozilla/content/base/src/nsNodeUtils.cpp b/mozilla/content/base/src/nsNodeUtils.cpp index 56616ea987f..7d3b28de981 100755 --- a/mozilla/content/base/src/nsNodeUtils.cpp +++ b/mozilla/content/base/src/nsNodeUtils.cpp @@ -36,11 +36,13 @@ * ***** END LICENSE BLOCK ***** */ #include "nsNodeUtils.h" +#include "nsContentUtils.h" #include "nsINode.h" #include "nsIContent.h" #include "nsTArray.h" #include "nsIMutationObserver.h" #include "nsIDocument.h" +#include "nsIDOMUserDataHandler.h" #define IMPL_MUTATION_NOTIFICATION(func_, content_, params_) \ PR_BEGIN_MACRO \ @@ -160,3 +162,19 @@ nsNodeUtils::NodeWillBeDestroyed(nsINode* aNode) aNode->mFlagsOrSlots = flags; } } + +void +nsNodeUtils::LastRelease(nsINode* aNode) +{ + if (aNode->HasProperties()) { + nsIDocument* document = aNode->GetOwnerDoc(); + if (document) { + nsContentUtils::CallUserDataHandler(document, + nsIDOMUserDataHandler::NODE_DELETED, + aNode, nsnull, nsnull); + document->PropertyTable()->DeleteAllPropertiesFor(aNode); + } + } + delete aNode; +} + diff --git a/mozilla/content/base/src/nsNodeUtils.h b/mozilla/content/base/src/nsNodeUtils.h index 5cd934f4669..2459fd3d84e 100755 --- a/mozilla/content/base/src/nsNodeUtils.h +++ b/mozilla/content/base/src/nsNodeUtils.h @@ -108,6 +108,12 @@ public: * @see nsIMutationObserver::NodeWillBeDestroyed */ static void NodeWillBeDestroyed(nsINode* aNode); + + /** + * To be called when reference count of aNode drops to zero. + * @param aNode The node which is going to be deleted. + */ + static void LastRelease(nsINode* aNode); }; #endif // nsNodeUtils_h___ diff --git a/mozilla/content/xul/content/src/nsXULElement.cpp b/mozilla/content/xul/content/src/nsXULElement.cpp index abe21c24dc6..0ced69336d6 100644 --- a/mozilla/content/xul/content/src/nsXULElement.cpp +++ b/mozilla/content/xul/content/src/nsXULElement.cpp @@ -865,43 +865,37 @@ nsXULElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, rv = slots->mAttributeMap->SetOwnerDocument(newOwnerDocument); NS_ENSURE_SUCCESS(rv, rv); } - } - } - if (aDocument) { - // we need to (re-)initialize several attributes that are dependant on - // the document. Do that now. - // XXXbz why do we have attributes depending on the current document? - // Shouldn't they depend on the owner document? Or is this code just - // misplaced, basically? - - PRInt32 count = mAttrsAndChildren.AttrCount(); - PRBool haveLocalAttributes = (count > 0); - PRInt32 i; - for (i = 0; i < count; i++) { - AddListenerFor(*mAttrsAndChildren.AttrNameAt(i), - aCompileEventHandlers); - } - - if (mPrototype) { - // If we have a prototype, the node we are binding to should - // have the same script-type - otherwise we will compile the - // event handlers incorrectly. - NS_ASSERTION(mPrototype->mScriptTypeID == GetScriptTypeID(), - "Prototype and node confused about default language?"); - PRInt32 count = mPrototype->mNumAttributes; + // we need to (re-)initialize several attributes that are dependant on + // the document. Do that now. + PRInt32 count = mAttrsAndChildren.AttrCount(); + PRBool haveLocalAttributes = (count > 0); + PRInt32 i; for (i = 0; i < count; i++) { - nsXULPrototypeAttribute *protoattr = - &mPrototype->mAttributes[i]; + AddListenerFor(*mAttrsAndChildren.AttrNameAt(i), + aCompileEventHandlers); + } - // Don't clobber a locally modified attribute. - if (haveLocalAttributes && - mAttrsAndChildren.GetAttr(protoattr->mName.LocalName(), - protoattr->mName.NamespaceID())) { - continue; + if (mPrototype) { + // If we have a prototype, the node we are binding to should + // have the same script-type - otherwise we will compile the + // event handlers incorrectly. + NS_ASSERTION(mPrototype->mScriptTypeID == GetScriptTypeID(), + "Prototype and node confused about default language?"); + PRInt32 count = mPrototype->mNumAttributes; + for (i = 0; i < count; i++) { + nsXULPrototypeAttribute *protoattr = + &mPrototype->mAttributes[i]; + + // Don't clobber a locally modified attribute. + if (haveLocalAttributes && + mAttrsAndChildren.GetAttr(protoattr->mName.LocalName(), + protoattr->mName.NamespaceID())) { + continue; + } + + AddListenerFor(protoattr->mName, aCompileEventHandlers); } - - AddListenerFor(protoattr->mName, aCompileEventHandlers); } } } @@ -965,13 +959,6 @@ nsXULElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) NS_IF_RELEASE(slots->mControllers); } - // XXXbz why are we nuking our listener manager? We can get events while - // not in a document! - if (mListenerManager) { - mListenerManager->Disconnect(); - mListenerManager = nsnull; - } - // Unset things in the reverse order from how we set them in BindToTree mParentPtrBits = aNullParent ? 0 : mParentPtrBits & ~PARENT_BIT_INDOCUMENT; @@ -2300,14 +2287,41 @@ nsXULElement::IsNodeOfType(PRUint32 aFlags) const return !(aFlags & ~(eCONTENT | eELEMENT | eXUL)); } +static void +PopupListenerPropertyDtor(void* aObject, nsIAtom* aPropertyName, + void* aPropertyValue, void* aData) +{ + nsIXULPopupListener* listener = + NS_STATIC_CAST(nsIXULPopupListener*, aPropertyValue); + if (!listener) { + return; + } + nsCOMPtr eventListener = do_QueryInterface(listener); + nsCOMPtr target = + do_QueryInterface(NS_STATIC_CAST(nsINode*, aObject)); + if (target) { + target->RemoveEventListener(NS_LITERAL_STRING("mousedown"), eventListener, + PR_FALSE); + target->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), eventListener, + PR_FALSE); + } + NS_RELEASE(listener); +} + nsresult nsXULElement::AddPopupListener(nsIAtom* aName) { + nsCOMPtr popupListener = + NS_STATIC_CAST(nsIXULPopupListener*, + GetProperty(nsXULAtoms::popuplistener)); + if (popupListener) { + // Popup listener is already installed. + return NS_OK; + } // Add a popup listener to the element nsresult rv; - nsCOMPtr popupListener = - do_CreateInstance(kXULPopupListenerCID, &rv); + popupListener = do_CreateInstance(kXULPopupListenerCID, &rv); NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to create an instance of the popup listener object."); if (NS_FAILED(rv)) return rv; @@ -2326,9 +2340,12 @@ nsXULElement::AddPopupListener(nsIAtom* aName) nsCOMPtr eventListener = do_QueryInterface(popupListener); nsCOMPtr target(do_QueryInterface(NS_STATIC_CAST(nsIContent *, this))); NS_ENSURE_TRUE(target, NS_ERROR_FAILURE); + rv = SetProperty(nsXULAtoms::popuplistener, popupListener, + PopupListenerPropertyDtor); + NS_ENSURE_SUCCESS(rv, rv); + NS_ADDREF(popupListener); target->AddEventListener(NS_LITERAL_STRING("mousedown"), eventListener, PR_FALSE); target->AddEventListener(NS_LITERAL_STRING("contextmenu"), eventListener, PR_FALSE); - return NS_OK; } diff --git a/mozilla/layout/xul/base/src/nsRootBoxFrame.cpp b/mozilla/layout/xul/base/src/nsRootBoxFrame.cpp index 86154c659e9..60642b5e33b 100644 --- a/mozilla/layout/xul/base/src/nsRootBoxFrame.cpp +++ b/mozilla/layout/xul/base/src/nsRootBoxFrame.cpp @@ -61,6 +61,7 @@ #include "nsIContent.h" #include "nsXULTooltipListener.h" #include "nsFrameManager.h" +#include "nsXULAtoms.h" // Interface IDs @@ -318,17 +319,40 @@ nsRootBoxFrame::SetDefaultTooltip(nsIContent* aTooltip) mDefaultTooltip = aTooltip; } +static void +TooltipListenerPropertyDtor(void *aObject, nsIAtom *aPropertyName, + void *aPropertyValue, void *aData) +{ + nsXULTooltipListener* listener = + NS_STATIC_CAST(nsXULTooltipListener*, aPropertyValue); + if (listener) { + listener->RemoveTooltipSupport(NS_STATIC_CAST(nsIContent*, aObject)); + NS_RELEASE(listener); + } +} + nsresult nsRootBoxFrame::AddTooltipSupport(nsIContent* aNode) { - // listener will be refcounted by dom event targets that - // it will add itself to, and destroyed when those targets - // are destroyed - nsXULTooltipListener* listener = new nsXULTooltipListener(); + NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER); + nsRefPtr listener = + NS_STATIC_CAST(nsXULTooltipListener*, + aNode->GetProperty(nsXULAtoms::tooltiplistener)); + if (listener) { + // Tooltip listener is already installed. + return NS_OK; + } + + listener = new nsXULTooltipListener(); if (!listener) return NS_ERROR_OUT_OF_MEMORY; - listener->Init(aNode); + if (NS_SUCCEEDED(listener->Init(aNode))) { + nsresult rv = aNode->SetProperty(nsXULAtoms::tooltiplistener, listener, + TooltipListenerPropertyDtor); + NS_ENSURE_SUCCESS(rv, rv); + NS_ADDREF(listener); + } return NS_OK; }