diff --git a/mozilla/content/base/public/nsContentUtils.h b/mozilla/content/base/public/nsContentUtils.h index 5583882351f..3aa409df286 100644 --- a/mozilla/content/base/public/nsContentUtils.h +++ b/mozilla/content/base/public/nsContentUtils.h @@ -868,25 +868,6 @@ public: static PRBool IsValidNodeName(nsIAtom *aLocalName, nsIAtom *aPrefix, PRInt32 aNamespaceID); - /** - * Associate an object aData to aKey on node aNode. If aData is null any - * previously registered object and UserDataHandler associated to aKey on - * aNode will be removed. - * Should only be used to implement the DOM Level 3 UserData API. - * - * @param aNode canonical nsINode pointer of the node to add aData to - * @param aKey the key to associate the object to - * @param aData the object to associate to aKey on aNode (may be nulll) - * @param aHandler the UserDataHandler to call when the node is - * cloned/deleted/imported/renamed (may be nulll) - * @param aResult [out] the previously registered object for aKey on aNode, if - * any - * @return whether adding the object and UserDataHandler succeeded - */ - static nsresult SetUserData(nsINode *aNode, nsIAtom *aKey, nsIVariant *aData, - nsIDOMUserDataHandler *aHandler, - nsIVariant **aResult); - /** * Creates a DocumentFragment from text using a context node to resolve * namespaces. diff --git a/mozilla/content/base/public/nsIContent.h b/mozilla/content/base/public/nsIContent.h index 342144c88f7..f80e02af8fe 100644 --- a/mozilla/content/base/public/nsIContent.h +++ b/mozilla/content/base/public/nsIContent.h @@ -839,6 +839,11 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIContent, NS_ICONTENT_IID) cb.NoteXPCOMChild(preservedWrapper); \ } +#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_USERDATA \ + if (tmp->HasProperties()) { \ + nsNodeUtils::TraverseUserData(tmp, cb); \ + } + #define NS_IMPL_CYCLE_COLLECTION_UNLINK_LISTENERMANAGER \ if (tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) { \ nsContentUtils::RemoveListenerManager(tmp); \ @@ -849,5 +854,10 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIContent, NS_ICONTENT_IID) if (tmp->GetOwnerDoc()) \ tmp->GetOwnerDoc()->RemoveReference(tmp); +#define NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA \ + if (tmp->HasProperties()) { \ + nsNodeUtils::UnlinkUserData(tmp); \ + } + #endif /* nsIContent_h___ */ diff --git a/mozilla/content/base/src/nsContentUtils.cpp b/mozilla/content/base/src/nsContentUtils.cpp index 89963890ce7..6d1e02a8855 100644 --- a/mozilla/content/base/src/nsContentUtils.cpp +++ b/mozilla/content/base/src/nsContentUtils.cpp @@ -3147,52 +3147,6 @@ nsContentUtils::IsValidNodeName(nsIAtom *aLocalName, nsIAtom *aPrefix, (aNamespaceID == kNameSpaceID_XML || aPrefix != nsGkAtoms::xml); } -/* static */ -nsresult -nsContentUtils::SetUserData(nsINode *aNode, nsIAtom *aKey, - nsIVariant *aData, nsIDOMUserDataHandler *aHandler, - nsIVariant **aResult) -{ - *aResult = nsnull; - - nsresult rv; - void *data; - if (aData) { - rv = aNode->SetProperty(DOM_USER_DATA, aKey, aData, - nsPropertyTable::SupportsDtorFunc, PR_TRUE, - &data); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ADDREF(aData); - } - else { - data = aNode->UnsetProperty(DOM_USER_DATA, aKey); - } - - // Take over ownership of the old data from the property table. - nsCOMPtr oldData = dont_AddRef(NS_STATIC_CAST(nsIVariant*, data)); - - if (aData && aHandler) { - rv = aNode->SetProperty(DOM_USER_DATA_HANDLER, aKey, aHandler, - nsPropertyTable::SupportsDtorFunc, PR_TRUE); - if (NS_FAILED(rv)) { - // We failed to set the handler, remove the data. - aNode->DeleteProperty(DOM_USER_DATA, aKey); - - return rv; - } - - NS_ADDREF(aHandler); - } - else { - aNode->DeleteProperty(DOM_USER_DATA_HANDLER, aKey); - } - - oldData.swap(*aResult); - - return NS_OK; -} - /* static */ nsresult nsContentUtils::CreateContextualFragment(nsIDOMNode* aContextNode, diff --git a/mozilla/content/base/src/nsDOMAttribute.cpp b/mozilla/content/base/src/nsDOMAttribute.cpp index ed82910b0c5..36ec9498a91 100644 --- a/mozilla/content/base/src/nsDOMAttribute.cpp +++ b/mozilla/content/base/src/nsDOMAttribute.cpp @@ -77,12 +77,14 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMAttribute) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMAttribute) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChild) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_LISTENERMANAGER + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_USERDATA NS_IMPL_CYCLE_COLLECTION_TRAVERSE_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMAttribute) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChild) NS_IMPL_CYCLE_COLLECTION_UNLINK_LISTENERMANAGER + NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_END // QueryInterface implementation for nsDOMAttribute @@ -102,7 +104,7 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDOMAttribute, nsIDOMAttr) NS_IMPL_CYCLE_COLLECTING_RELEASE_FULL(nsDOMAttribute, nsIDOMAttr, - nsNodeUtils::LastRelease(this, PR_TRUE)) + nsNodeUtils::LastRelease(this)) void nsDOMAttribute::SetMap(nsDOMAttributeMap *aMap) @@ -578,29 +580,13 @@ nsDOMAttribute::SetUserData(const nsAString& aKey, nsIVariant* aData, nsIDOMUserDataHandler* aHandler, nsIVariant** aResult) { - nsCOMPtr key = do_GetAtom(aKey); - if (!key) { - return NS_ERROR_OUT_OF_MEMORY; - } - - return nsContentUtils::SetUserData(this, key, aData, aHandler, aResult); + return nsNodeUtils::SetUserData(this, aKey, aData, aHandler, aResult); } NS_IMETHODIMP nsDOMAttribute::GetUserData(const nsAString& aKey, nsIVariant** aResult) { - nsIDocument *document = GetOwnerDoc(); - NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); - - nsCOMPtr key = do_GetAtom(aKey); - if (!key) { - return NS_ERROR_OUT_OF_MEMORY; - } - - *aResult = NS_STATIC_CAST(nsIVariant*, GetProperty(DOM_USER_DATA, key)); - NS_IF_ADDREF(*aResult); - - return NS_OK; + return nsNodeUtils::GetUserData(this, aKey, aResult); } NS_IMETHODIMP diff --git a/mozilla/content/base/src/nsDocument.cpp b/mozilla/content/base/src/nsDocument.cpp index efc3bc91fdc..508641a3401 100644 --- a/mozilla/content/base/src/nsDocument.cpp +++ b/mozilla/content/base/src/nsDocument.cpp @@ -857,11 +857,6 @@ nsDocument::~nsDocument() NS_RELEASE(mCSSLoader); } - // We must delete properties before dropping document reference from - // NodeInfoManager, because nsNodeUtils::LastRelease can't remove properties - // when owner document is null. - mPropertyTable.DeleteAllProperties(); - // XXX Ideally we'd do this cleanup in the nsIDocument destructor. if (mNodeInfoManager) { mNodeInfoManager->DropDocumentReference(); @@ -884,18 +879,6 @@ nsDocument::~nsDocument() nsLayoutStatics::Release(); } -void -nsDocument::LastRelease() -{ - nsNodeUtils::LastRelease(this, PR_FALSE); - // Delete properties before starting to destruct the document. - // Some of the properties are bound to nsINode objects and the destructor - // functions of the properties may want to use the owner document of the - // nsINode. - mPropertyTable.DeleteAllProperties(); - delete this; -} - NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDocument) @@ -943,7 +926,7 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDocument, nsIDocument) NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS_WITH_DESTROY(nsDocument, nsIDocument, - LastRelease()) + nsNodeUtils::LastRelease(this)) PR_STATIC_CALLBACK(PLDHashOperator) @@ -1020,6 +1003,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDocument) cb.NoteXPCOMChild(tmp->mChildren.ChildAt(indx - 1)); } + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_USERDATA + // Traverse all nsIDocument pointer members. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mBindingManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSecurityInfo) @@ -1074,6 +1059,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument) tmp->mChildren.RemoveChildAt(indx); } + NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA + // Unlink any associated preserved wrapper. tmp->RemoveReference(tmp); @@ -4167,27 +4154,14 @@ nsDocument::SetUserData(const nsAString &aKey, nsIDOMUserDataHandler *aHandler, nsIVariant **aResult) { - nsCOMPtr key = do_GetAtom(aKey); - if (!key) { - return NS_ERROR_OUT_OF_MEMORY; - } - - return nsContentUtils::SetUserData(this, key, aData, aHandler, aResult); + return nsNodeUtils::SetUserData(this, aKey, aData, aHandler, aResult); } NS_IMETHODIMP nsDocument::GetUserData(const nsAString &aKey, nsIVariant **aResult) { - nsCOMPtr key = do_GetAtom(aKey); - if (!key) { - return NS_ERROR_OUT_OF_MEMORY; - } - - *aResult = NS_STATIC_CAST(nsIVariant*, GetProperty(DOM_USER_DATA, key)); - NS_IF_ADDREF(*aResult); - - return NS_OK; + return nsNodeUtils::GetUserData(this, aKey, aResult); } NS_IMETHODIMP diff --git a/mozilla/content/base/src/nsDocument.h b/mozilla/content/base/src/nsDocument.h index 17d38c01380..72c62b2e490 100644 --- a/mozilla/content/base/src/nsDocument.h +++ b/mozilla/content/base/src/nsDocument.h @@ -723,8 +723,6 @@ protected: nsDocument(const char* aContentType); virtual ~nsDocument(); - void LastRelease(); - nsCString mReferrer; nsString mLastModified; diff --git a/mozilla/content/base/src/nsGenericDOMDataNode.cpp b/mozilla/content/base/src/nsGenericDOMDataNode.cpp index 1d9480753aa..e30186489d6 100644 --- a/mozilla/content/base/src/nsGenericDOMDataNode.cpp +++ b/mozilla/content/base/src/nsGenericDOMDataNode.cpp @@ -80,11 +80,13 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericDOMDataNode) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericDOMDataNode) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_LISTENERMANAGER + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_USERDATA NS_IMPL_CYCLE_COLLECTION_TRAVERSE_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericDOMDataNode) NS_IMPL_CYCLE_COLLECTION_UNLINK_LISTENERMANAGER + NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_END @@ -108,7 +110,7 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsGenericDOMDataNode, nsIContent) NS_IMPL_CYCLE_COLLECTING_RELEASE_FULL(nsGenericDOMDataNode, nsIContent, - nsNodeUtils::LastRelease(this, PR_TRUE)) + nsNodeUtils::LastRelease(this)) nsresult diff --git a/mozilla/content/base/src/nsGenericElement.cpp b/mozilla/content/base/src/nsGenericElement.cpp index 7cfdfa8acfb..c6078055ed6 100644 --- a/mozilla/content/base/src/nsGenericElement.cpp +++ b/mozilla/content/base/src/nsGenericElement.cpp @@ -525,31 +525,14 @@ nsNode3Tearoff::SetUserData(const nsAString& aKey, nsIDOMUserDataHandler* aHandler, nsIVariant** aResult) { - nsCOMPtr key = do_GetAtom(aKey); - if (!key) { - return NS_ERROR_OUT_OF_MEMORY; - } - - return nsContentUtils::SetUserData(mContent, key, aData, aHandler, aResult); + return nsNodeUtils::SetUserData(mContent, aKey, aData, aHandler, aResult); } NS_IMETHODIMP nsNode3Tearoff::GetUserData(const nsAString& aKey, nsIVariant** aResult) { - nsIDocument *document = mContent->GetOwnerDoc(); - NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); - - nsCOMPtr key = do_GetAtom(aKey); - if (!key) { - return NS_ERROR_OUT_OF_MEMORY; - } - - *aResult = NS_STATIC_CAST(nsIVariant*, - mContent->GetProperty(DOM_USER_DATA, key)); - NS_IF_ADDREF(*aResult); - - return NS_OK; + return nsNodeUtils::GetUserData(mContent, aKey, aResult); } NS_IMETHODIMP @@ -2987,6 +2970,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericElement) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericElement) NS_IMPL_CYCLE_COLLECTION_UNLINK_LISTENERMANAGER + NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER // Unlink child content (and unbind our subtree). @@ -3021,6 +3005,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericElement) } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_LISTENERMANAGER + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_USERDATA NS_IMPL_CYCLE_COLLECTION_TRAVERSE_PRESERVED_WRAPPER if (tmp->HasProperties() && tmp->IsNodeOfType(nsINode::eXUL)) { @@ -3075,7 +3060,7 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsGenericElement, nsIContent) NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS_WITH_DESTROY(nsGenericElement, nsIContent, - nsNodeUtils::LastRelease(this, PR_TRUE)) + nsNodeUtils::LastRelease(this)) nsresult nsGenericElement::PostQueryInterface(REFNSIID aIID, void** aInstancePtr) diff --git a/mozilla/content/base/src/nsNodeUtils.cpp b/mozilla/content/base/src/nsNodeUtils.cpp index 76d499dd620..59c962d6168 100755 --- a/mozilla/content/base/src/nsNodeUtils.cpp +++ b/mozilla/content/base/src/nsNodeUtils.cpp @@ -174,32 +174,8 @@ nsNodeUtils::ParentChainChanged(nsIContent *aContent) } } -struct nsHandlerData -{ - PRUint16 mOperation; - nsCOMPtr mSource, mDest; -}; - -static void -CallHandler(void *aObject, nsIAtom *aKey, void *aHandler, void *aData) -{ - nsHandlerData *handlerData = NS_STATIC_CAST(nsHandlerData*, aData); - nsCOMPtr handler = - NS_STATIC_CAST(nsIDOMUserDataHandler*, aHandler); - - nsINode *node = NS_STATIC_CAST(nsINode*, aObject); - nsCOMPtr data = - NS_STATIC_CAST(nsIVariant*, node->GetProperty(DOM_USER_DATA, aKey)); - NS_ASSERTION(data, "Handler without data?"); - - nsAutoString key; - aKey->ToString(key); - handler->Handle(handlerData->mOperation, key, data, handlerData->mSource, - handlerData->mDest); -} - void -nsNodeUtils::LastRelease(nsINode* aNode, PRBool aDelete) +nsNodeUtils::LastRelease(nsINode* aNode) { nsINode::nsSlots* slots = aNode->GetExistingSlots(); if (slots) { @@ -216,21 +192,21 @@ nsNodeUtils::LastRelease(nsINode* aNode, PRBool aDelete) // Kill properties first since that may run external code, so we want to // be in as complete state as possible at that time. - if (aNode->HasProperties()) { + if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) { + // Delete all properties before tearing down the document. Some of the + // properties are bound to nsINode objects and the destructor functions of + // the properties may want to use the owner document of the nsINode. + NS_STATIC_CAST(nsIDocument*, aNode)->PropertyTable()->DeleteAllProperties(); + } + else if (aNode->HasProperties()) { // Strong reference to the document so that deleting properties can't // delete the document. nsCOMPtr document = aNode->GetOwnerDoc(); if (document) { - nsHandlerData handlerData; - handlerData.mOperation = nsIDOMUserDataHandler::NODE_DELETED; - - nsPropertyTable *table = document->PropertyTable(); - - table->Enumerate(aNode, DOM_USER_DATA_HANDLER, CallHandler, &handlerData); - table->DeleteAllPropertiesFor(aNode); + document->PropertyTable()->DeleteAllPropertiesFor(aNode); } - aNode->UnsetFlags(NODE_HAS_PROPERTIES); } + aNode->UnsetFlags(NODE_HAS_PROPERTIES); if (aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) { #ifdef DEBUG @@ -249,9 +225,108 @@ nsNodeUtils::LastRelease(nsINode* aNode, PRBool aDelete) aNode->UnsetFlags(NODE_HAS_LISTENERMANAGER); } - if (aDelete) { - delete aNode; + delete aNode; +} + +static nsresult +SetUserDataProperty(PRUint16 aCategory, nsINode *aNode, nsIAtom *aKey, + nsISupports* aValue, void** aOldValue) +{ + nsresult rv = aNode->SetProperty(aCategory, aKey, aValue, + nsPropertyTable::SupportsDtorFunc, PR_TRUE, + aOldValue); + NS_ENSURE_SUCCESS(rv, rv); + + // Property table owns it now. + NS_ADDREF(aValue); + + return NS_OK; +} + +/* static */ +nsresult +nsNodeUtils::SetUserData(nsINode *aNode, const nsAString &aKey, + nsIVariant *aData, nsIDOMUserDataHandler *aHandler, + nsIVariant **aResult) +{ + *aResult = nsnull; + + nsCOMPtr key = do_GetAtom(aKey); + if (!key) { + return NS_ERROR_OUT_OF_MEMORY; } + + nsresult rv; + void *data; + if (aData) { + rv = SetUserDataProperty(DOM_USER_DATA, aNode, key, aData, &data); + NS_ENSURE_SUCCESS(rv, rv); + } + else { + data = aNode->UnsetProperty(DOM_USER_DATA, key); + } + + // Take over ownership of the old data from the property table. + nsCOMPtr oldData = dont_AddRef(NS_STATIC_CAST(nsIVariant*, data)); + + if (aData && aHandler) { + nsCOMPtr oldHandler; + rv = SetUserDataProperty(DOM_USER_DATA_HANDLER, aNode, key, aHandler, + getter_AddRefs(oldHandler)); + if (NS_FAILED(rv)) { + // We failed to set the handler, remove the data. + aNode->DeleteProperty(DOM_USER_DATA, key); + + return rv; + } + } + else { + aNode->DeleteProperty(DOM_USER_DATA_HANDLER, key); + } + + oldData.swap(*aResult); + + return NS_OK; +} + +/* static */ +nsresult +nsNodeUtils::GetUserData(nsINode *aNode, const nsAString &aKey, + nsIVariant **aResult) +{ + nsCOMPtr key = do_GetAtom(aKey); + if (!key) { + return NS_ERROR_OUT_OF_MEMORY; + } + + *aResult = NS_STATIC_CAST(nsIVariant*, + aNode->GetProperty(DOM_USER_DATA, key)); + NS_IF_ADDREF(*aResult); + + return NS_OK; +} + +struct nsHandlerData +{ + PRUint16 mOperation; + nsCOMPtr mSource, mDest; +}; + +static void +CallHandler(void *aObject, nsIAtom *aKey, void *aHandler, void *aData) +{ + nsHandlerData *handlerData = NS_STATIC_CAST(nsHandlerData*, aData); + nsCOMPtr handler = + NS_STATIC_CAST(nsIDOMUserDataHandler*, aHandler); + nsINode *node = NS_STATIC_CAST(nsINode*, aObject); + nsCOMPtr data = + NS_STATIC_CAST(nsIVariant*, node->GetProperty(DOM_USER_DATA, aKey)); + NS_ASSERTION(data, "Handler without data?"); + + nsAutoString key; + aKey->ToString(key); + handler->Handle(handlerData->mOperation, key, data, handlerData->mSource, + handlerData->mDest); } /* static */ @@ -293,6 +368,30 @@ nsNodeUtils::CallUserDataHandlers(nsCOMArray &aNodesWithProperties, return NS_OK; } +static void +NoteUserData(void *aObject, nsIAtom *aKey, void *aXPCOMChild, void *aData) +{ + nsCycleCollectionTraversalCallback* cb = + NS_STATIC_CAST(nsCycleCollectionTraversalCallback*, aData); + cb->NoteXPCOMChild(NS_STATIC_CAST(nsISupports*, aXPCOMChild)); +} + +/* static */ +void +nsNodeUtils::TraverseUserData(nsINode* aNode, + nsCycleCollectionTraversalCallback &aCb) +{ + nsIDocument* ownerDoc = aNode->GetOwnerDoc(); + if (!ownerDoc) { + return; + } + + nsPropertyTable *table = ownerDoc->PropertyTable(); + + table->Enumerate(aNode, DOM_USER_DATA, NoteUserData, &aCb); + table->Enumerate(aNode, DOM_USER_DATA_HANDLER, NoteUserData, &aCb); +} + /* static */ nsresult nsNodeUtils::CloneNodeImpl(nsINode *aNode, PRBool aDeep, nsIDOMNode **aResult) @@ -563,3 +662,20 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep, return clone ? CallQueryInterface(clone, aResult) : NS_OK; } + + +/* static */ +void +nsNodeUtils::UnlinkUserData(nsINode *aNode) +{ + NS_ASSERTION(aNode->HasProperties(), "Call to UnlinkUserData not needed."); + + // Strong reference to the document so that deleting properties can't + // delete the document. + nsCOMPtr document = aNode->GetOwnerDoc(); + if (document) { + document->PropertyTable()->DeleteAllPropertiesFor(aNode, DOM_USER_DATA); + document->PropertyTable()->DeleteAllPropertiesFor(aNode, + DOM_USER_DATA_HANDLER); + } +} diff --git a/mozilla/content/base/src/nsNodeUtils.h b/mozilla/content/base/src/nsNodeUtils.h index bb7deb6a90f..c43a0f0e96e 100755 --- a/mozilla/content/base/src/nsNodeUtils.h +++ b/mozilla/content/base/src/nsNodeUtils.h @@ -46,7 +46,11 @@ struct JSContext; struct JSObject; class nsINode; class nsNodeInfoManager; +class nsIVariant; +class nsIDOMUserDataHandler; template class nsCOMArray; +struct nsCycleCollectionTraversalCallback; +struct CharacterDataChangeInfo; class nsNodeUtils { @@ -112,9 +116,8 @@ public: /** * To be called when reference count of aNode drops to zero. * @param aNode The node which is going to be deleted. - * @param aDelete If PR_TRUE, calling this method also deletes aNode. */ - static void LastRelease(nsINode* aNode, PRBool aDelete); + static void LastRelease(nsINode* aNode); /** * Clones aNode, its attributes and, if aDeep is PR_TRUE, its descendant nodes @@ -175,6 +178,39 @@ public: nsnull, getter_AddRefs(dummy)); } + /** + * Associate an object aData to aKey on node aNode. If aData is null any + * previously registered object and UserDataHandler associated to aKey on + * aNode will be removed. + * Should only be used to implement the DOM Level 3 UserData API. + * + * @param aNode canonical nsINode pointer of the node to add aData to + * @param aKey the key to associate the object to + * @param aData the object to associate to aKey on aNode (may be nulll) + * @param aHandler the UserDataHandler to call when the node is + * cloned/deleted/imported/renamed (may be nulll) + * @param aResult [out] the previously registered object for aKey on aNode, if + * any + * @return whether adding the object and UserDataHandler succeeded + */ + static nsresult SetUserData(nsINode *aNode, const nsAString &aKey, + nsIVariant *aData, + nsIDOMUserDataHandler *aHandler, + nsIVariant **aResult); + + /** + * Get the UserData object registered for a Key on node aNode, if any. + * Should only be used to implement the DOM Level 3 UserData API. + * + * @param aNode canonical nsINode pointer of the node to get UserData for + * @param aKey the key to get UserData for + * @param aResult [out] the previously registered object for aKey on aNode, if + * any + * @return whether getting the object and UserDataHandler succeeded + */ + static nsresult GetUserData(nsINode *aNode, const nsAString &aKey, + nsIVariant **aResult); + /** * Call registered userdata handlers for operation aOperation for the nodes in * aNodesWithProperties. If aCloned is PR_TRUE aNodesWithProperties should @@ -194,6 +230,16 @@ public: nsIDocument *aOwnerDocument, PRUint16 aOperation, PRBool aCloned); + /** + * Helper for the cycle collector to traverse the DOM UserData and + * UserDataHandlers for aNode. + * + * @param aNode the node to traverse UserData and UserDataHandlers for + * @param aCb the cycle collection callback + */ + static void TraverseUserData(nsINode* aNode, + nsCycleCollectionTraversalCallback &aCb); + /** * A basic implementation of the DOM cloneNode method. Calls nsINode::Clone to * do the actual cloning of the node. @@ -205,6 +251,13 @@ public: static nsresult CloneNodeImpl(nsINode *aNode, PRBool aDeep, nsIDOMNode **aResult); + /** + * Release the UserData and UserDataHandlers for aNode. + * + * @param aNode the node to release the UserData and UserDataHandlers for + */ + static void UnlinkUserData(nsINode *aNode); + private: friend PLDHashOperator PR_CALLBACK AdoptFunc(nsAttrHashKey::KeyType aKey, nsIDOMNode *aData, void* aUserArg); diff --git a/mozilla/content/base/src/nsPropertyTable.cpp b/mozilla/content/base/src/nsPropertyTable.cpp index e7f60da230e..8f0f0ca33b1 100644 --- a/mozilla/content/base/src/nsPropertyTable.cpp +++ b/mozilla/content/base/src/nsPropertyTable.cpp @@ -116,6 +116,16 @@ nsPropertyTable::DeleteAllPropertiesFor(nsPropertyOwner aObject) } } +void +nsPropertyTable::DeleteAllPropertiesFor(nsPropertyOwner aObject, + PRUint16 aCategory) +{ + for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) { + if (prop->mCategory == aCategory) + prop->DeletePropertyFor(aObject); + } +} + nsresult nsPropertyTable::TransferOrDeleteAllPropertiesFor(nsPropertyOwner aObject, nsPropertyTable *aOtherTable) diff --git a/mozilla/content/base/src/nsPropertyTable.h b/mozilla/content/base/src/nsPropertyTable.h index 97ab2c91052..55ae3ea2859 100644 --- a/mozilla/content/base/src/nsPropertyTable.h +++ b/mozilla/content/base/src/nsPropertyTable.h @@ -232,6 +232,13 @@ class nsPropertyTable */ NS_HIDDEN_(void) DeleteAllPropertiesFor(nsPropertyOwner aObject); + /** + * Deletes all of the properties in category |aCategory| for object |aObject|, + * calling the destructor function for each property. + */ + NS_HIDDEN_(void) DeleteAllPropertiesFor(nsPropertyOwner aObject, + PRUint16 aCategory); + /** * Transfers all properties for object |aObject| that were set with the * |aTransfer| argument as PR_TRUE to |aTable|. Deletes the other properties