diff --git a/mozilla/content/base/public/nsContentUtils.h b/mozilla/content/base/public/nsContentUtils.h index 83dccfb35cd..7ef28b407e7 100644 --- a/mozilla/content/base/public/nsContentUtils.h +++ b/mozilla/content/base/public/nsContentUtils.h @@ -818,6 +818,53 @@ 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); + + /** + * Call the UserDataHandler associated with aKey on node aNode. + * Should only be used to implement the DOM Level 3 UserData API. + * + * @param aDocument the document that contains the property table for aNode + * @param aOperation the type of operation that is being performed on the + * node. @see nsIDOMUserDataHandler + * @param aNode canonical nsINode pointer of the node to call the + * UserDataHandler for + * @param aSource the node that aOperation is being performed on, or null if + * the operation is a deletion + * @param aDest the newly created node if any, or null + */ + static void CallUserDataHandler(nsIDocument *aDocument, PRUint16 aOperation, + const nsINode *aNode, nsIDOMNode *aSource, + nsIDOMNode *aDest); + + /** + * Copy the objects and UserDataHandlers for node aNode from aOldDocument to + * the current ownerDocument of aNode. + * Should only be used to implement the DOM Level 3 UserData API. + * + * @param aOldDocument the old document + * @param aNode canonical nsINode pointer of the node to copy objects + * and UserDataHandlers for + */ + static void CopyUserData(nsIDocument *aOldDocument, const nsINode *aNode); + private: static nsresult doReparentContentWrapper(nsIContent *aChild, JSContext *cx, diff --git a/mozilla/content/base/public/nsIContent.h b/mozilla/content/base/public/nsIContent.h index 6ee856f207b..1e409e70c16 100644 --- a/mozilla/content/base/public/nsIContent.h +++ b/mozilla/content/base/public/nsIContent.h @@ -60,8 +60,8 @@ class nsAttrName; // IID for the nsIContent interface #define NS_ICONTENT_IID \ -{ 0x823ca304, 0x2dc4, 0x4b06, \ - { 0x98, 0x60, 0x1a, 0x21, 0x45, 0xb9, 0xf6, 0x1c } } +{ 0x67b73e9b, 0x6ec8, 0x4f20, \ + { 0x89, 0xb2, 0xb1, 0x46, 0x9e, 0x0a, 0x51, 0x68 } } // hack to make egcs / gcc 2.95.2 happy class nsIContent_base : public nsINode { @@ -614,11 +614,6 @@ public: return 0; } - void SetHasProperties() - { - SetFlags(NODE_HAS_PROPERTIES); - } - /** * Clones this node, using aNodeInfoManager to get the nodeinfo for the * clone. When cloning an element, all attributes of the element will be @@ -691,7 +686,7 @@ public: */ virtual nsIAtom *GetClassAttributeName() const = 0; - + #ifdef DEBUG /** * List the content (and anything it contains) out to the given diff --git a/mozilla/content/base/public/nsIDocument.h b/mozilla/content/base/public/nsIDocument.h index c7b89e3f473..fe81d22e073 100644 --- a/mozilla/content/base/public/nsIDocument.h +++ b/mozilla/content/base/public/nsIDocument.h @@ -91,9 +91,8 @@ class nsIDocumentObserver; // IID for the nsIDocument interface #define NS_IDOCUMENT_IID \ -{ 0x3ab900ba, 0xe30d, 0x4a42, \ - { 0x98, 0x50, 0x21, 0x82, 0x99, 0x51, 0x6c, 0xd6 } } - +{ 0xffa1f165, 0x8b0e, 0x4010, \ + { 0xb6, 0xec, 0x6f, 0x49, 0x6b, 0x1b, 0x30, 0x3a } } // Flag for AddStyleSheet(). #define NS_STYLESHEET_FROM_CATALOG (1 << 0) @@ -793,114 +792,6 @@ public: */ virtual void NotifyURIVisitednessChanged(nsIURI* aURI) = 0; - /** - * Associate an object aData to aKey on node aObject. Should only be used to - * implement the DOM Level 3 UserData API. - * - * @param aObject 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 aObject - * @param aHandler the UserDataHandler to call when the node is - * cloned/deleted/imported/renamed - * @param aResult [out] the previously registered object for aKey on aObject, - * if any - * @return whether adding the object and UserDataHandler succeeded - */ - nsresult SetUserData(const nsINode *aObject, const nsAString &aKey, - nsIVariant *aData, nsIDOMUserDataHandler *aHandler, - nsIVariant **aResult) - { - nsCOMPtr key = do_GetAtom(aKey); - if (!key) { - return NS_ERROR_OUT_OF_MEMORY; - } - - return SetUserData(aObject, key, aData, aHandler, aResult); - } - - /** - * Associate an object aData to aKey on node aObject. If aData is null any - * previously registered object and UserDataHandler associated to aKey on - * aObject will be removed. Should only be used to implement the DOM Level 3 - * UserData API. - * - * @param aObject 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 aObject (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 aObject, - * if any - * @return whether adding the object and UserDataHandler succeeded - */ - virtual nsresult SetUserData(const nsINode *aObject, nsIAtom *aKey, - nsIVariant *aData, - nsIDOMUserDataHandler *aHandler, - nsIVariant **aResult) = 0; - - /** - * Get the object associated to aKey on node aObject. This will return NS_OK - * if no object was associated to aKey on aObject. Should only be used to - * implement the DOM Level 3 UserData API. - * - * @param aObject canonical nsINode pointer of the node to get the - * object for - * @param aKey the key the object is associated to - * @param aResult [out] the registered object for aKey on aObject, if any - * @return whether an error occured while looking up the registered object - */ - nsresult GetUserData(nsINode *aObject, const nsAString &aKey, - nsIVariant **aResult) - { - nsCOMPtr key = do_GetAtom(aKey); - if (!key) { - return NS_ERROR_OUT_OF_MEMORY; - } - - return GetUserData(aObject, key, aResult); - } - - /** - * Get the object associated to aKey on node aObject. This will return NS_OK - * if no object was associated to aKey on aObject. Should only be used to - * implement the DOM Level 3 UserData API. - * - * @param aObject canonical nsINode pointer of the node to get the - * object for - * @param aKey the key the object is associated to - * @param aResult [out] the registered object for aKey on aObject, if any - * @return whether an error occured while looking up the registered object - */ - virtual nsresult GetUserData(const nsINode *aObject, nsIAtom *aKey, - nsIVariant **aResult) = 0; - - /** - * Call the UserDataHandler associated with aKey on node aObject. Should only - * be used to implement the DOM Level 3 UserData API. - * - * @param aOperation the type of operation that is being performed on the - * node. @see nsIDOMUserDataHandler - * @param aObject canonical nsINode pointer of the node to call the - * UserDataHandler for - * @param aSource the node that aOperation is being performed on, or null if - * the operation is a deletion - * @param aDest the newly created node if any, or null - */ - virtual void CallUserDataHandler(PRUint16 aOperation, - const nsINode *aObject, - nsIDOMNode *aSource, nsIDOMNode *aDest) = 0; - - /** - * Copy the objects and UserDataHandlers for node aObject to a new document. - * Should only be used to implement the DOM Level 3 UserData API. - * - * @param aObject canonical nsINode pointer of the node to copy objects - * and UserDataHandlers for - * @param aDestination the new document - */ - virtual void CopyUserData(const nsINode *aObject, - nsIDocument *aDestination) = 0; - /** * Resets and removes a box object from the document's box object cache * diff --git a/mozilla/content/base/public/nsINode.h b/mozilla/content/base/public/nsINode.h index 55b5764547d..aac66047bc0 100644 --- a/mozilla/content/base/public/nsINode.h +++ b/mozilla/content/base/public/nsINode.h @@ -83,10 +83,9 @@ class nsVoidArray; #define NODE_TYPE_SPECIFIC_BITS_OFFSET 6 // IID for the nsINode interface -// f96eef82-43fc-4eee-9784-4259415e98a9 #define NS_INODE_IID \ -{ 0x1418310f, 0x2151, 0x47b7, \ - { 0x9f, 0x4f, 0x4a, 0xc4, 0x95, 0x82, 0xfa, 0xc8 } } +{ 0x7b23c37c, 0x18e6, 0x4d80, \ + { 0xbc, 0x95, 0xb3, 0x7b, 0x3b, 0x89, 0x7a, 0xe0 } } // hack to make egcs / gcc 2.95.2 happy class nsINode_base : public nsIDOMGCParticipant { @@ -259,7 +258,26 @@ public: * (though a null return value does not imply the * property was not set, i.e. it can be set to null). */ - virtual void* GetProperty(nsIAtom *aPropertyName, + void* GetProperty(nsIAtom *aPropertyName, + nsresult *aStatus = nsnull) const + { + return GetProperty(0, aPropertyName, aStatus); + } + + /** + * Get a property associated with this node. + * + * @param aCategory category of property to get. + * @param aPropertyName name of property to get. + * @param aStatus out parameter for storing resulting status. + * Set to NS_PROPTABLE_PROP_NOT_THERE if the property + * is not set. + * @return the property. Null if the property is not set + * (though a null return value does not imply the + * property was not set, i.e. it can be set to null). + */ + virtual void* GetProperty(PRUint32 aCategory, + nsIAtom *aPropertyName, nsresult *aStatus = nsnull) const; /** @@ -276,9 +294,34 @@ public: * was already set * @throws NS_ERROR_OUT_OF_MEMORY if that occurs */ - virtual nsresult SetProperty(nsIAtom *aPropertyName, + nsresult SetProperty(nsIAtom *aPropertyName, + void *aValue, + NSPropertyDtorFunc aDtor = nsnull) + { + return SetProperty(0, aPropertyName, aValue, aDtor); + } + + /** + * Set a property to be associated with this node. This will overwrite an + * existing value if one exists. The existing value is destroyed using the + * destructor function given when that value was set. + * + * @param aCategory category of property to set. + * @param aPropertyName name of property to set. + * @param aValue new value of property. + * @param aDtor destructor function to be used when this property + * is destroyed. + * @param aOldValue [out] previous value of property. + * + * @return NS_PROPTABLE_PROP_OVERWRITTEN (success value) if the property + * was already set + * @throws NS_ERROR_OUT_OF_MEMORY if that occurs + */ + virtual nsresult SetProperty(PRUint32 aCategory, + nsIAtom *aPropertyName, void *aValue, - NSPropertyDtorFunc aDtor = nsnull); + NSPropertyDtorFunc aDtor = nsnull, + void **aOldValue = nsnull); /** * Destroys a property associated with this node. The value is destroyed @@ -288,12 +331,26 @@ public: * * @throws NS_PROPTABLE_PROP_NOT_THERE if the property was not set */ - virtual nsresult DeleteProperty(nsIAtom *aPropertyName); + nsresult DeleteProperty(nsIAtom *aPropertyName) + { + return DeleteProperty(0, aPropertyName); + } + + /** + * Destroys a property associated with this node. The value is destroyed + * using the destruction function given when that value was set. + * + * @param aCategory category of property to destroy. + * @param aPropertyName name of property to destroy. + * + * @throws NS_PROPTABLE_PROP_NOT_THERE if the property was not set + */ + virtual nsresult DeleteProperty(PRUint32 aCategory, nsIAtom *aPropertyName); /** * Unset a property associated with this node. The value will not be * destroyed but rather returned. It is the caller's responsibility to - * destroy the value after that point + * destroy the value after that point. * * @param aPropertyName name of property to unset. * @param aStatus out parameter for storing resulting status. @@ -303,9 +360,35 @@ public: * (though a null return value does not imply the * property was not set, i.e. it can be set to null). */ - virtual void* UnsetProperty(nsIAtom *aPropertyName, + void* UnsetProperty(nsIAtom *aPropertyName, + nsresult *aStatus = nsnull) + { + return UnsetProperty(0, aPropertyName, aStatus); + } + + /** + * Unset a property associated with this node. The value will not be + * destroyed but rather returned. It is the caller's responsibility to + * destroy the value after that point. + * + * @param aCategory category of property to unset. + * @param aPropertyName name of property to unset. + * @param aStatus out parameter for storing resulting status. + * Set to NS_PROPTABLE_PROP_NOT_THERE if the property + * is not set. + * @return the property. Null if the property is not set + * (though a null return value does not imply the + * property was not set, i.e. it can be set to null). + */ + virtual void* UnsetProperty(PRUint32 aCategory, + nsIAtom *aPropertyName, nsresult *aStatus = nsnull); + PRBool HasProperties() const + { + return HasFlag(NODE_HAS_PROPERTIES); + } + /** * Inform node of range ownership changes. This allows the node to do the * right thing to ranges in the face of changes to the content model. diff --git a/mozilla/content/base/src/nsContentUtils.cpp b/mozilla/content/base/src/nsContentUtils.cpp index 301892d193e..f0e973659a7 100644 --- a/mozilla/content/base/src/nsContentUtils.cpp +++ b/mozilla/content/base/src/nsContentUtils.cpp @@ -130,6 +130,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID); #include "nsXULAtoms.h" #include "nsIEventListenerManager.h" #include "nsAttrName.h" +#include "nsIDOMUserDataHandler.h" // for ReportToConsole #include "nsIStringBundle.h" @@ -3057,3 +3058,120 @@ nsContentUtils::IsValidNodeName(nsIAtom *aLocalName, nsIAtom *aPrefix, return aPrefix != nsGkAtoms::xmlns && (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, + &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); + 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; +} + +struct nsHandlerData +{ + PRUint16 mOperation; + nsCOMPtr mSource; + nsCOMPtr 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 */ +void +nsContentUtils::CallUserDataHandler(nsIDocument *aDocument, PRUint16 aOperation, + const nsINode *aNode, nsIDOMNode *aSource, + nsIDOMNode *aDest) +{ +#ifdef DEBUG + // XXX Should we guard from QI'ing nodes that are being destroyed? + nsCOMPtr node = do_QueryInterface(NS_CONST_CAST(nsINode*, aNode)); + NS_ASSERTION(node == aNode, "Use canonical nsINode pointer!"); +#endif + + nsHandlerData handlerData = { aOperation, aSource, aDest }; + aDocument->PropertyTable()->Enumerate(aNode, DOM_USER_DATA_HANDLER, + CallHandler, &handlerData); +} + +static void +CopyData(void *aObject, nsIAtom *aKey, void *aUserData, void *aData) +{ + nsPropertyTable *propertyTable = NS_STATIC_CAST(nsPropertyTable*, aData); + nsINode *node = NS_STATIC_CAST(nsINode*, aObject); + nsIDOMUserDataHandler *handler = + NS_STATIC_CAST(nsIDOMUserDataHandler*, + propertyTable->GetProperty(node, DOM_USER_DATA_HANDLER, + aKey)); + + nsCOMPtr result; + nsContentUtils::SetUserData(node, aKey, + NS_STATIC_CAST(nsIVariant*, aUserData), handler, + getter_AddRefs(result)); +} + +/* static */ +void +nsContentUtils::CopyUserData(nsIDocument *aOldDocument, const nsINode *aNode) +{ +#ifdef DEBUG + nsCOMPtr node = do_QueryInterface(NS_CONST_CAST(nsINode*, aNode)); + NS_ASSERTION(node == aNode, "Use canonical nsINode pointer!"); +#endif + + nsPropertyTable *table = aOldDocument->PropertyTable(); + table->Enumerate(aNode, DOM_USER_DATA, CopyData, table); +} diff --git a/mozilla/content/base/src/nsDOMAttribute.cpp b/mozilla/content/base/src/nsDOMAttribute.cpp index 52d7fa14a76..7a601c038bb 100644 --- a/mozilla/content/base/src/nsDOMAttribute.cpp +++ b/mozilla/content/base/src/nsDOMAttribute.cpp @@ -386,19 +386,26 @@ nsDOMAttribute::CloneNode(PRBool aDeep, nsIDOMNode** aReturn) nsIDocument *document = GetOwnerDoc(); if (document) { - // XXX For now, nsDOMAttribute has only one child. We need to notify - // about importing it, so we force creation here. - nsCOMPtr child, newChild; + // XXX For now, nsDOMAttribute has only one child. We need to notify about + // cloning it, so we force creation here. + nsCOMPtr child; GetFirstChild(getter_AddRefs(child)); - newAttr->GetFirstChild(getter_AddRefs(newChild)); - nsCOMPtr childNode = do_QueryInterface(child); - if (childNode && newChild) { - document->CallUserDataHandler(nsIDOMUserDataHandler::NODE_CLONED, - childNode, child, newChild); + if (childNode && childNode->HasProperties()) { + nsCOMPtr newChild; + newAttr->GetFirstChild(getter_AddRefs(newChild)); + if (newChild) { + nsContentUtils::CallUserDataHandler(document, + nsIDOMUserDataHandler::NODE_CLONED, + childNode, child, newChild); + } + } + + if (HasProperties()) { + nsContentUtils::CallUserDataHandler(document, + nsIDOMUserDataHandler::NODE_CLONED, + this, this, newAttr); } - document->CallUserDataHandler(nsIDOMUserDataHandler::NODE_CLONED, - this, this, newAttr); } newAttr.swap(*aReturn); @@ -578,11 +585,12 @@ nsDOMAttribute::SetUserData(const nsAString& aKey, nsIVariant* aData, nsIDOMUserDataHandler* aHandler, 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; + } - return document->SetUserData(this, aKey, aData, - aHandler, aResult); + return nsContentUtils::SetUserData(this, key, aData, aHandler, aResult); } NS_IMETHODIMP @@ -591,8 +599,15 @@ nsDOMAttribute::GetUserData(const nsAString& aKey, nsIVariant** aResult) nsIDocument *document = GetOwnerDoc(); NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); - return document->GetUserData(this, aKey, - 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; } NS_IMETHODIMP diff --git a/mozilla/content/base/src/nsDocument.cpp b/mozilla/content/base/src/nsDocument.cpp index db18c12df40..05913dfc964 100644 --- a/mozilla/content/base/src/nsDocument.cpp +++ b/mozilla/content/base/src/nsDocument.cpp @@ -686,8 +686,11 @@ nsDocument::~nsDocument() // below, which will run before the nsINode dtor. Additionally // the properties hash and the document will have been destroyed, // so there would be no way to find the handlers. - CallUserDataHandler(nsIDOMUserDataHandler::NODE_DELETED, - this, nsnull, nsnull); + if (HasProperties()) { + nsContentUtils::CallUserDataHandler(this, + nsIDOMUserDataHandler::NODE_DELETED, + this, nsnull, nsnull); + } // XXX Inform any remaining observers that we are going away. // Note that this currently contradicts the rule that all @@ -2840,8 +2843,7 @@ nsDocument::ImportNode(nsIDOMNode* aImportedNode, nodeInfo = newNodeInfo; } - nsCOMPtr clone = new nsDOMAttribute(nsnull, nodeInfo, - value); + nsCOMPtr clone = new nsDOMAttribute(nsnull, nodeInfo, value); if (!clone) { return NS_ERROR_OUT_OF_MEMORY; } @@ -2849,14 +2851,17 @@ nsDocument::ImportNode(nsIDOMNode* aImportedNode, if (document) { // XXX For now, nsDOMAttribute has only one child. We need to notify // about importing it, so we force creation here. - nsCOMPtr child, newChild; + nsCOMPtr child; aImportedNode->GetFirstChild(getter_AddRefs(child)); - clone->GetFirstChild(getter_AddRefs(newChild)); - nsCOMPtr childNode = do_QueryInterface(child); - if (childNode && newChild) { - document->CallUserDataHandler(nsIDOMUserDataHandler::NODE_IMPORTED, - childNode, child, newChild); + if (childNode && childNode->HasProperties()) { + nsCOMPtr newChild; + clone->GetFirstChild(getter_AddRefs(newChild)); + if (newChild) { + nsContentUtils::CallUserDataHandler(document, + nsIDOMUserDataHandler::NODE_IMPORTED, + childNode, child, newChild); + } } } @@ -2898,10 +2903,11 @@ nsDocument::ImportNode(nsIDOMNode* aImportedNode, } } - if (document) { - nsCOMPtr importedNode = do_QueryInterface(aImportedNode); - document->CallUserDataHandler(nsIDOMUserDataHandler::NODE_IMPORTED, - importedNode, aImportedNode, *aResult); + nsCOMPtr importedNode = do_QueryInterface(aImportedNode); + if (document && importedNode && importedNode->HasProperties()) { + nsContentUtils::CallUserDataHandler(document, + nsIDOMUserDataHandler::NODE_IMPORTED, + importedNode, aImportedNode, *aResult); } return NS_OK; @@ -3637,8 +3643,7 @@ nsDocument::SetUserData(const nsAString &aKey, return NS_ERROR_OUT_OF_MEMORY; } - return SetUserData(this, key, aData, aHandler, - aResult); + return nsContentUtils::SetUserData(this, key, aData, aHandler, aResult); } NS_IMETHODIMP @@ -3650,179 +3655,12 @@ nsDocument::GetUserData(const nsAString &aKey, return NS_ERROR_OUT_OF_MEMORY; } - return GetUserData(this, key, aResult); -} - -nsresult -nsDocument::SetUserData(const nsINode *aObject, - nsIAtom *aKey, - nsIVariant *aData, - nsIDOMUserDataHandler *aHandler, - nsIVariant **aResult) -{ -#ifdef DEBUG - nsCOMPtr object = - do_QueryInterface(NS_CONST_CAST(nsINode*, aObject)); - NS_ASSERTION(object == aObject, "Use canonical nsINode pointer!"); -#endif - - *aResult = nsnull; - - nsresult rv = NS_OK; - void *data; - if (aData) { - rv = mPropertyTable.SetProperty(aObject, DOM_USER_DATA, aKey, aData, - nsPropertyTable::SupportsDtorFunc, &data); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ADDREF(aData); - } - else { - data = mPropertyTable.UnsetProperty(aObject, 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 = mPropertyTable.SetProperty(aObject, DOM_USER_DATA_HANDLER, aKey, - aHandler, - nsPropertyTable::SupportsDtorFunc); - if (NS_SUCCEEDED(rv)) { - NS_ADDREF(aHandler); - } - } - else { - nsIDOMUserDataHandler *oldHandler = - NS_STATIC_CAST(nsIDOMUserDataHandler*, - mPropertyTable.UnsetProperty(aObject, - DOM_USER_DATA_HANDLER, - aKey)); - NS_IF_RELEASE(oldHandler); - } - - if (NS_SUCCEEDED(rv)) { - oldData.swap(*aResult); - } - else { - // We failed to set the handler, remove the data. - nsIVariant *variant = - NS_STATIC_CAST(nsIVariant*, - mPropertyTable.UnsetProperty(aObject, DOM_USER_DATA, - aKey)); - NS_IF_RELEASE(variant); - } - - return rv; -} - -nsresult -nsDocument::GetUserData(const nsINode *aObject, nsIAtom *aKey, - nsIVariant **aResult) -{ -#ifdef DEBUG - nsCOMPtr object = - do_QueryInterface(NS_CONST_CAST(nsINode*, aObject)); - NS_ASSERTION(object == aObject, "Use canonical nsINode pointer!"); -#endif - - *aResult = NS_STATIC_CAST(nsIVariant*, - mPropertyTable.GetProperty(aObject, DOM_USER_DATA, - aKey)); - + *aResult = NS_STATIC_CAST(nsIVariant*, GetProperty(DOM_USER_DATA, key)); NS_IF_ADDREF(*aResult); return NS_OK; } -struct nsHandlerData -{ - PRUint16 mOperation; - nsCOMPtr mSource; - nsCOMPtr mDest; - nsDocument *mDocument; -}; - -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); - nsCOMPtr data; - nsINode *object = NS_STATIC_CAST(nsINode*, aObject); - nsresult rv = handlerData->mDocument->GetUserData(object, aKey, - getter_AddRefs(data)); - if (NS_SUCCEEDED(rv)) { - NS_ASSERTION(data, "Handler without data?"); - - nsAutoString key; - aKey->ToString(key); - handler->Handle(handlerData->mOperation, key, data, handlerData->mSource, - handlerData->mDest); - } -} - -void -nsDocument::CallUserDataHandler(PRUint16 aOperation, - const nsINode *aObject, - nsIDOMNode *aSource, nsIDOMNode *aDest) -{ -#ifdef DEBUG - // XXX Should we guard from QI'ing nodes that are being destroyed? - nsCOMPtr object = - do_QueryInterface(NS_CONST_CAST(nsINode*, aObject)); - NS_ASSERTION(object == aObject, "Use canonical nsINode pointer!"); -#endif - - nsHandlerData handlerData; - handlerData.mOperation = aOperation; - handlerData.mSource = aSource; - handlerData.mDest = aDest; - handlerData.mDocument = this; - - mPropertyTable.Enumerate(aObject, DOM_USER_DATA_HANDLER, CallHandler, - &handlerData); -} - -struct nsCopyData -{ - nsDocument *mSourceDocument; - nsIDocument *mDestDocument; -}; - -static void -Copy(void *aObject, nsIAtom *aKey, void *aUserData, void *aData) -{ - nsCopyData *data = NS_STATIC_CAST(nsCopyData*, aData); - nsPropertyTable *propertyTable = data->mSourceDocument->PropertyTable(); - nsINode *object = NS_STATIC_CAST(nsINode*, aObject); - nsIDOMUserDataHandler *handler = - NS_STATIC_CAST(nsIDOMUserDataHandler*, - propertyTable->GetProperty(object, DOM_USER_DATA_HANDLER, - aKey)); - - nsCOMPtr result; - data->mDestDocument->SetUserData(object, aKey, - NS_STATIC_CAST(nsIVariant*, aUserData), - handler, getter_AddRefs(result)); -} - -void -nsDocument::CopyUserData(const nsINode *aObject, nsIDocument *aDestination) -{ -#ifdef DEBUG - nsCOMPtr object = - do_QueryInterface(NS_CONST_CAST(nsINode*, aObject)); - NS_ASSERTION(object == aObject, "Use canonical nsINode pointer!"); -#endif - - nsCopyData copyData = { this, aDestination }; - - mPropertyTable.Enumerate(aObject, DOM_USER_DATA, Copy, ©Data); -} - NS_IMETHODIMP nsDocument::LookupPrefix(const nsAString& aNamespaceURI, nsAString& aPrefix) @@ -3947,9 +3785,12 @@ nsDocument::AdoptNode(nsIDOMNode *source, nsIDOMNode **aReturn) // of giving a node a brand new node info. // if (NS_SUCCEEDED(rv)) { -// nsCOMPtr object = do_QueryInterface(source); -// CallUserDataHandler(nsIDOMUserDataHandler::NODE_ADOPTED, object, source, -// *aReturn); +// nsCOMPtr node = do_QueryInterface(source); +// if (node->HasProperties()) { +// nsContentUtils::CallUserDataHandler(this, +// nsIDOMUserDataHandler::NODE_ADOPTED, +// node, source, *aReturn); +// } // } return NS_ERROR_NOT_IMPLEMENTED; @@ -3989,9 +3830,12 @@ nsDocument::RenameNode(nsIDOMNode *aNode, } // if (NS_SUCCEEDED(rv)) { -// nsCOMPtr object = do_QueryInterface(aNode); -// CallUserDataHandler(nsIDOMUserDataHandler::NODE_RENAMED, object, aNode, -// *aReturn); +// nsCOMPtr node = do_QueryInterface(aNode); +// if (node->HasProperties()) { +// nsContentUtils::CallUserDataHandler(this, +// nsIDOMUserDataHandler::NODE_RENAMED, +// node, aNode, *aReturn); +// } // } return NS_ERROR_DOM_NOT_SUPPORTED_ERR; diff --git a/mozilla/content/base/src/nsDocument.h b/mozilla/content/base/src/nsDocument.h index bfb33660a22..be5ebe158f3 100644 --- a/mozilla/content/base/src/nsDocument.h +++ b/mozilla/content/base/src/nsDocument.h @@ -642,20 +642,6 @@ public: virtual NS_HIDDEN_(void) ForgetLink(nsIContent* aContent); virtual NS_HIDDEN_(void) NotifyURIVisitednessChanged(nsIURI* aURI); - NS_HIDDEN_(nsresult) SetUserData(const nsINode *aObject, - nsIAtom *aKey, - nsIVariant *aData, - nsIDOMUserDataHandler *aHandler, - nsIVariant **aReturn); - NS_HIDDEN_(nsresult) GetUserData(const nsINode *aObject, - nsIAtom *aKey, - nsIVariant **aResult); - NS_HIDDEN_(void) CallUserDataHandler(PRUint16 aOperation, - const nsINode *aObject, - nsIDOMNode *aSource, - nsIDOMNode *aDest); - NS_HIDDEN_(void) CopyUserData(const nsINode *aObject, - nsIDocument *aDestination); NS_HIDDEN_(void) ClearBoxObjectFor(nsIContent* aContent); protected: diff --git a/mozilla/content/base/src/nsDocumentFragment.cpp b/mozilla/content/base/src/nsDocumentFragment.cpp index fc56b692708..fb59d8dd66f 100644 --- a/mozilla/content/base/src/nsDocumentFragment.cpp +++ b/mozilla/content/base/src/nsDocumentFragment.cpp @@ -312,11 +312,12 @@ nsDocumentFragment::SetUserData(const nsAString& aKey, nsIDOMUserDataHandler* aHandler, 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; + } - return document->SetUserData(NS_STATIC_CAST(nsIContent*, this), aKey, aData, - aHandler, aResult); + return nsContentUtils::SetUserData(this, key, aData, aHandler, aResult); } NS_IMETHODIMP @@ -326,8 +327,15 @@ nsDocumentFragment::GetUserData(const nsAString& aKey, nsIDocument *document = GetOwnerDoc(); NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); - return document->GetUserData(NS_STATIC_CAST(nsIContent*, this), aKey, - 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; } NS_IMETHODIMP diff --git a/mozilla/content/base/src/nsGenericDOMDataNode.cpp b/mozilla/content/base/src/nsGenericDOMDataNode.cpp index 0684ba6dbf1..54d54f0466a 100644 --- a/mozilla/content/base/src/nsGenericDOMDataNode.cpp +++ b/mozilla/content/base/src/nsGenericDOMDataNode.cpp @@ -274,10 +274,10 @@ nsGenericDOMDataNode::CloneNode(PRBool aDeep, nsIDOMNode *aSource, rv = CallQueryInterface(newContent, aResult); nsIDocument *ownerDoc = GetOwnerDoc(); - if (NS_SUCCEEDED(rv) && ownerDoc && HasFlag(NODE_HAS_PROPERTIES)) { - ownerDoc->CallUserDataHandler(nsIDOMUserDataHandler::NODE_CLONED, - NS_STATIC_CAST(const nsIContent*, this), - aSource, *aResult); + if (NS_SUCCEEDED(rv) && ownerDoc && HasProperties()) { + nsContentUtils::CallUserDataHandler(ownerDoc, + nsIDOMUserDataHandler::NODE_CLONED, + this, aSource, *aResult); } return rv; @@ -649,7 +649,7 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent, } nsresult rv = NS_OK; - nsIDocument *oldOwnerDocument = GetOwnerDoc(); + nsCOMPtr oldOwnerDocument = GetOwnerDoc(); nsIDocument *newOwnerDocument; nsNodeInfoManager* nodeInfoManager; @@ -670,16 +670,6 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent, nodeInfoManager = aParent->NodeInfo()->NodeInfoManager(); } - if (oldOwnerDocument && oldOwnerDocument != newOwnerDocument) { - if (newOwnerDocument && HasFlag(NODE_HAS_PROPERTIES)) { - // Copy UserData to the new document. - oldOwnerDocument->CopyUserData(this, newOwnerDocument); - } - - // Remove all properties. - oldOwnerDocument->PropertyTable()->DeleteAllPropertiesFor(this); - } - if (mNodeInfo->NodeInfoManager() != nodeInfoManager) { nsCOMPtr newNodeInfo; // optimize common cases @@ -702,6 +692,15 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent, mNodeInfo.swap(newNodeInfo); } + if (oldOwnerDocument && oldOwnerDocument != newOwnerDocument && + HasProperties()) { + // Copy UserData to the new document. + nsContentUtils::CopyUserData(oldOwnerDocument, this); + + // Remove all properties. + oldOwnerDocument->PropertyTable()->DeleteAllPropertiesFor(this); + } + NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document"); NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent"); NS_POSTCONDITION(aBindingParent == GetBindingParent(), diff --git a/mozilla/content/base/src/nsGenericElement.cpp b/mozilla/content/base/src/nsGenericElement.cpp index bc7776030f9..515cebeb9c4 100644 --- a/mozilla/content/base/src/nsGenericElement.cpp +++ b/mozilla/content/base/src/nsGenericElement.cpp @@ -144,13 +144,12 @@ nsINode::~nsINode() { NS_ASSERTION(!HasSlots(), "Don't know how to kill the slots"); - if (HasFlag(NODE_HAS_PROPERTIES)) { - nsIDocument *document = GetOwnerDoc(); - if (document) { - document->CallUserDataHandler(nsIDOMUserDataHandler::NODE_DELETED, - this, nsnull, nsnull); - document->PropertyTable()->DeleteAllPropertiesFor(this); - } + nsIDocument *document = GetOwnerDoc(); + if (document && HasProperties()) { + nsContentUtils::CallUserDataHandler(document, + nsIDOMUserDataHandler::NODE_DELETED, + this, nsnull, nsnull); + document->PropertyTable()->DeleteAllPropertiesFor(this); } if (HasFlag(NODE_HAS_RANGELIST)) { @@ -184,27 +183,28 @@ nsINode::~nsINode() } void* -nsINode::GetProperty(nsIAtom *aPropertyName, nsresult *aStatus) const +nsINode::GetProperty(PRUint32 aCategory, nsIAtom *aPropertyName, + nsresult *aStatus) const { nsIDocument *doc = GetOwnerDoc(); if (!doc) return nsnull; - return doc->PropertyTable()->GetProperty(this, aPropertyName, + return doc->PropertyTable()->GetProperty(this, aCategory, aPropertyName, aStatus); } nsresult -nsINode::SetProperty(nsIAtom *aPropertyName, - void *aValue, - NSPropertyDtorFunc aDtor) +nsINode::SetProperty(PRUint32 aCategory, nsIAtom *aPropertyName, void *aValue, + NSPropertyDtorFunc aDtor, void **aOldValue) { nsIDocument *doc = GetOwnerDoc(); if (!doc) return NS_ERROR_FAILURE; - nsresult rv = doc->PropertyTable()->SetProperty(this, aPropertyName, - aValue, aDtor, nsnull); + nsresult rv = doc->PropertyTable()->SetProperty(this, aCategory, + aPropertyName, aValue, aDtor, + aOldValue); if (NS_SUCCEEDED(rv)) { SetFlags(NODE_HAS_PROPERTIES); } @@ -213,23 +213,24 @@ nsINode::SetProperty(nsIAtom *aPropertyName, } nsresult -nsINode::DeleteProperty(nsIAtom *aPropertyName) +nsINode::DeleteProperty(PRUint32 aCategory, nsIAtom *aPropertyName) { nsIDocument *doc = GetOwnerDoc(); if (!doc) return nsnull; - return doc->PropertyTable()->DeleteProperty(this, aPropertyName); + return doc->PropertyTable()->DeleteProperty(this, aCategory, aPropertyName); } void* -nsINode::UnsetProperty(nsIAtom *aPropertyName, nsresult *aStatus) +nsINode::UnsetProperty(PRUint32 aCategory, nsIAtom *aPropertyName, + nsresult *aStatus) { nsIDocument *doc = GetOwnerDoc(); if (!doc) return nsnull; - return doc->PropertyTable()->UnsetProperty(this, aPropertyName, + return doc->PropertyTable()->UnsetProperty(this, aCategory, aPropertyName, aStatus); } @@ -505,16 +506,12 @@ nsNode3Tearoff::SetUserData(const nsAString& aKey, nsIDOMUserDataHandler* aHandler, nsIVariant** aResult) { - nsIDocument *document = mContent->GetOwnerDoc(); - NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); - - nsresult rv = document->SetUserData(mContent, aKey, aData, aHandler, - aResult); - if (NS_SUCCEEDED(rv)) { - mContent->SetHasProperties(); + nsCOMPtr key = do_GetAtom(aKey); + if (!key) { + return NS_ERROR_OUT_OF_MEMORY; } - return rv; + return nsContentUtils::SetUserData(mContent, key, aData, aHandler, aResult); } NS_IMETHODIMP @@ -524,7 +521,16 @@ nsNode3Tearoff::GetUserData(const nsAString& aKey, nsIDocument *document = mContent->GetOwnerDoc(); NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); - return document->GetUserData(mContent, aKey, aResult); + 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; } NS_IMETHODIMP @@ -1727,7 +1733,7 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsresult rv; - nsIDocument *oldOwnerDocument = GetOwnerDoc(); + nsCOMPtr oldOwnerDocument = GetOwnerDoc(); nsIDocument *newOwnerDocument; nsNodeInfoManager* nodeInfoManager; @@ -1756,16 +1762,6 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, // Handle a change in our owner document. - if (oldOwnerDocument && oldOwnerDocument != newOwnerDocument) { - if (newOwnerDocument && HasFlag(NODE_HAS_PROPERTIES)) { - // Copy UserData to the new document. - oldOwnerDocument->CopyUserData(this, newOwnerDocument); - } - - // Remove all properties. - oldOwnerDocument->PropertyTable()->DeleteAllPropertiesFor(this); - } - if (mNodeInfo->NodeInfoManager() != nodeInfoManager) { nsCOMPtr newNodeInfo; rv = nodeInfoManager->GetNodeInfo(mNodeInfo->NameAtom(), @@ -1777,12 +1773,22 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, mNodeInfo.swap(newNodeInfo); } - if (newOwnerDocument && newOwnerDocument != oldOwnerDocument) { - // set a new nodeinfo on attribute nodes - nsDOMSlots *slots = GetExistingDOMSlots(); - if (slots && slots->mAttributeMap) { - rv = slots->mAttributeMap->SetOwnerDocument(newOwnerDocument); - NS_ENSURE_SUCCESS(rv, rv); + if (oldOwnerDocument != newOwnerDocument) { + if (oldOwnerDocument && HasProperties()) { + // Copy UserData to the new document. + nsContentUtils::CopyUserData(oldOwnerDocument, this); + + // Remove all properties. + oldOwnerDocument->PropertyTable()->DeleteAllPropertiesFor(this); + } + + if (newOwnerDocument) { + // set a new nodeinfo on attribute nodes + nsDOMSlots *slots = GetExistingDOMSlots(); + if (slots && slots->mAttributeMap) { + rv = slots->mAttributeMap->SetOwnerDocument(newOwnerDocument); + NS_ENSURE_SUCCESS(rv, rv); + } } } @@ -3617,9 +3623,10 @@ nsGenericElement::CloneNode(PRBool aDeep, nsIDOMNode *aSource, rv = CallQueryInterface(newContent, aResult); nsIDocument *ownerDoc = GetOwnerDoc(); - if (NS_SUCCEEDED(rv) && ownerDoc && HasFlag(NODE_HAS_PROPERTIES)) { - ownerDoc->CallUserDataHandler(nsIDOMUserDataHandler::NODE_CLONED, - this, aSource, *aResult); + if (NS_SUCCEEDED(rv) && ownerDoc && HasProperties()) { + nsContentUtils::CallUserDataHandler(ownerDoc, + nsIDOMUserDataHandler::NODE_CLONED, + this, aSource, *aResult); } return rv; diff --git a/mozilla/content/xml/document/src/nsXMLDocument.cpp b/mozilla/content/xml/document/src/nsXMLDocument.cpp index 9e50c943281..aa32fd82f67 100644 --- a/mozilla/content/xml/document/src/nsXMLDocument.cpp +++ b/mozilla/content/xml/document/src/nsXMLDocument.cpp @@ -727,9 +727,10 @@ nsXMLDocument::CloneNode(PRBool aDeep, nsIDOMNode** aReturn) } rv = CallQueryInterface(newDoc, aReturn); - if (NS_SUCCEEDED(rv)) { - CallUserDataHandler(nsIDOMUserDataHandler::NODE_CLONED, - NS_STATIC_CAST(nsIDocument*, this), this, *aReturn); + if (NS_SUCCEEDED(rv) && HasProperties()) { + nsContentUtils::CallUserDataHandler(this, + nsIDOMUserDataHandler::NODE_CLONED, + this, this, *aReturn); } return rv; diff --git a/mozilla/content/xul/content/src/nsXULElement.cpp b/mozilla/content/xul/content/src/nsXULElement.cpp index 974a4f3fba6..872592b9f02 100644 --- a/mozilla/content/xul/content/src/nsXULElement.cpp +++ b/mozilla/content/xul/content/src/nsXULElement.cpp @@ -801,7 +801,7 @@ nsXULElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, mParentPtrBits = NS_REINTERPRET_CAST(PtrBits, aDocument); } - nsIDocument *oldOwnerDocument = GetOwnerDoc(); + nsCOMPtr oldOwnerDocument = GetOwnerDoc(); nsIDocument *newOwnerDocument; nsNodeInfoManager* nodeInfoManager; @@ -832,17 +832,6 @@ nsXULElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, // Handle a change in our owner document. - if (oldOwnerDocument && oldOwnerDocument != newOwnerDocument) { - if (newOwnerDocument && HasFlag(NODE_HAS_PROPERTIES)) { - // Copy UserData to the new document. - oldOwnerDocument->CopyUserData(this, aDocument); - } - - // Remove all properties. - oldOwnerDocument->PropertyTable()-> - DeleteAllPropertiesFor(NS_STATIC_CAST(nsINode*, this)); - } - if (mNodeInfo->NodeInfoManager() != nodeInfoManager) { nsCOMPtr newNodeInfo; nsresult rv = @@ -855,12 +844,22 @@ nsXULElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, mNodeInfo.swap(newNodeInfo); } - if (newOwnerDocument && newOwnerDocument != oldOwnerDocument) { - // set a new nodeinfo on attribute nodes - nsDOMSlots *slots = GetExistingDOMSlots(); - if (slots && slots->mAttributeMap) { - rv = slots->mAttributeMap->SetOwnerDocument(newOwnerDocument); - NS_ENSURE_SUCCESS(rv, rv); + if (oldOwnerDocument != newOwnerDocument) { + if (oldOwnerDocument && HasProperties()) { + // Copy UserData to the new document. + nsContentUtils::CopyUserData(oldOwnerDocument, this); + + // Remove all properties. + oldOwnerDocument->PropertyTable()->DeleteAllPropertiesFor(this); + } + + if (newOwnerDocument) { + // set a new nodeinfo on attribute nodes + nsDOMSlots *slots = GetExistingDOMSlots(); + if (slots && slots->mAttributeMap) { + rv = slots->mAttributeMap->SetOwnerDocument(newOwnerDocument); + NS_ENSURE_SUCCESS(rv, rv); + } } }