Fix for bug 264308 (Implement DOM Level 3 UserData API). r/sr=jst.

git-svn-id: svn://10.0.0.236/trunk@183126 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
peterv%propagandism.org 2005-10-27 14:09:23 +00:00
parent 28f860e4f4
commit 7645808305
20 changed files with 777 additions and 125 deletions

View File

@ -748,6 +748,8 @@ public:
{ if (aStatus) *aStatus = NS_ERROR_NOT_IMPLEMENTED; return nsnull; }
virtual void SetHasProperties() = 0;
/**
* Clones this node, using aNodeInfoManager to get the nodeinfo for the
* clone. When cloning an element, all attributes of the element will be

View File

@ -54,8 +54,8 @@
#include "nsPropertyTable.h"
#include "nsHashSets.h"
#include "nsAutoPtr.h"
#include "nsIAtom.h"
class nsIAtom;
class nsIContent;
class nsIStyledContent;
class nsPresContext;
@ -91,6 +91,8 @@ class nsICSSLoader;
class nsHTMLStyleSheet;
class nsIHTMLCSSStyleSheet;
class nsILayoutHistoryState;
class nsIVariant;
class nsIDOMUserDataHandler;
// IID for the nsIDocument interface
#define NS_IDOCUMENT_IID \
@ -780,6 +782,114 @@ 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 cannonical nsISupports 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 nsISupports *aObject, const nsAString &aKey,
nsIVariant *aData, nsIDOMUserDataHandler *aHandler,
nsIVariant **aResult)
{
nsCOMPtr<nsIAtom> 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 cannonical nsISupports 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 nsISupports *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 cannonical nsISupports 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(nsISupports *aObject, const nsAString &aKey,
nsIVariant **aResult)
{
nsCOMPtr<nsIAtom> 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 cannonical nsISupports 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 nsISupports *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 cannonical nsISupports 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 nsISupports *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 cannonical nsISupports pointer of the node to copy objects
* and UserDataHandlers for
* @param aDestination the new document
*/
virtual void CopyUserData(const nsISupports *aObject,
nsIDocument *aDestination) = 0;
protected:
~nsIDocument()
{

View File

@ -46,6 +46,7 @@
#include "nsDOMString.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsIDOMUserDataHandler.h"
//----------------------------------------------------------------------
PRBool nsDOMAttribute::sInitialized;
@ -67,6 +68,9 @@ nsDOMAttribute::~nsDOMAttribute()
{
nsIDocument *doc = GetOwnerDoc();
if (doc)
doc->CallUserDataHandler(nsIDOMUserDataHandler::NODE_DELETED,
NS_STATIC_CAST(nsIDOMAttr*, this), nsnull,
nsnull);
doc->PropertyTable()->DeleteAllPropertiesFor(this);
NS_IF_RELEASE(mChild);
@ -347,17 +351,37 @@ nsDOMAttribute::AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn)
NS_IMETHODIMP
nsDOMAttribute::CloneNode(PRBool aDeep, nsIDOMNode** aReturn)
{
nsDOMAttribute* newAttr;
*aReturn = nsnull;
nsAutoString value;
GetValue(value);
newAttr = new nsDOMAttribute(nsnull, mNodeInfo, value);
nsCOMPtr<nsIDOMNode> newAttr = new nsDOMAttribute(nsnull, mNodeInfo, value);
if (!newAttr) {
return NS_ERROR_OUT_OF_MEMORY;
}
return CallQueryInterface(newAttr, 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<nsIDOMNode> child, newChild;
GetFirstChild(getter_AddRefs(child));
newAttr->GetFirstChild(getter_AddRefs(newChild));
nsCOMPtr<nsISupports> childSupports = do_QueryInterface(child);
if (childSupports && newChild) {
document->CallUserDataHandler(nsIDOMUserDataHandler::NODE_CLONED,
childSupports, child, newChild);
}
document->CallUserDataHandler(nsIDOMUserDataHandler::NODE_CLONED,
NS_STATIC_CAST(nsIDOMAttr*, this), this,
newAttr);
}
newAttr.swap(*aReturn);
return NS_OK;
}
NS_IMETHODIMP
@ -625,23 +649,25 @@ nsDOMAttribute::GetFeature(const nsAString& aFeature,
}
NS_IMETHODIMP
nsDOMAttribute::SetUserData(const nsAString& aKey,
nsIVariant* aData,
nsDOMAttribute::SetUserData(const nsAString& aKey, nsIVariant* aData,
nsIDOMUserDataHandler* aHandler,
nsIVariant** aReturn)
nsIVariant** aResult)
{
NS_NOTYETIMPLEMENTED("nsDocument::SetUserData()");
nsIDocument *document = GetOwnerDoc();
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
return NS_ERROR_NOT_IMPLEMENTED;
return document->SetUserData(NS_STATIC_CAST(nsIDOMAttr*, this), aKey, aData,
aHandler, aResult);
}
NS_IMETHODIMP
nsDOMAttribute::GetUserData(const nsAString& aKey,
nsIVariant** aReturn)
nsDOMAttribute::GetUserData(const nsAString& aKey, nsIVariant** aResult)
{
NS_NOTYETIMPLEMENTED("nsDocument::GetUserData()");
nsIDocument *document = GetOwnerDoc();
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
return NS_ERROR_NOT_IMPLEMENTED;
return document->GetUserData(NS_STATIC_CAST(nsIDOMAttr*, this), aKey,
aResult);
}
NS_IMETHODIMP

View File

@ -116,7 +116,7 @@
static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
#include "nsHTMLAtoms.h"
#include "nsIDOMUserDataHandler.h"
#include "nsScriptEventManager.h"
#include "nsIDOMXPathEvaluator.h"
#include "nsIXPathEvaluatorInternal.h"
@ -685,6 +685,9 @@ nsDocument::~nsDocument()
{
mInDestructor = PR_TRUE;
CallUserDataHandler(nsIDOMUserDataHandler::NODE_DELETED,
NS_STATIC_CAST(nsIDocument*, this), nsnull, nsnull);
// XXX Inform any remaining observers that we are going away.
// Note that this currently contradicts the rule that all
// observers must hold on to live references to the document.
@ -2821,6 +2824,7 @@ nsDocument::ImportNode(nsIDOMNode* aImportedNode,
return rv;
}
nsIDocument *document;
PRUint16 nodeType;
aImportedNode->GetNodeType(&nodeType);
switch (nodeType) {
@ -2829,7 +2833,7 @@ nsDocument::ImportNode(nsIDOMNode* aImportedNode,
nsCOMPtr<nsIAttribute> attr = do_QueryInterface(aImportedNode);
NS_ENSURE_TRUE(attr, NS_ERROR_FAILURE);
nsIDocument *document = attr->GetOwnerDoc();
document = attr->GetOwnerDoc();
nsCOMPtr<nsIDOMAttr> domAttr = do_QueryInterface(aImportedNode);
nsAutoString value;
@ -2854,9 +2858,22 @@ nsDocument::ImportNode(nsIDOMNode* aImportedNode,
return NS_ERROR_OUT_OF_MEMORY;
}
clone.swap(*aResult);
if (document) {
// XXX For now, nsDOMAttribute has only one child. We need to notify
// about importing it, so we force creation here.
nsCOMPtr<nsIDOMNode> child, newChild;
aImportedNode->GetFirstChild(getter_AddRefs(child));
clone->GetFirstChild(getter_AddRefs(newChild));
return NS_OK;
nsCOMPtr<nsISupports> childSupports = do_QueryInterface(child);
if (childSupports && newChild) {
document->CallUserDataHandler(nsIDOMUserDataHandler::NODE_IMPORTED,
childSupports, child, newChild);
}
}
clone.swap(*aResult);
break;
}
case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
case nsIDOMNode::ELEMENT_NODE:
@ -2868,12 +2885,16 @@ nsDocument::ImportNode(nsIDOMNode* aImportedNode,
nsCOMPtr<nsIContent> imported = do_QueryInterface(aImportedNode);
NS_ENSURE_TRUE(imported, NS_ERROR_FAILURE);
document = imported->GetOwnerDoc();
nsCOMPtr<nsIContent> clone;
rv = imported->CloneContent(mNodeInfoManager, aDeep,
getter_AddRefs(clone));
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(clone, aResult);
rv = CallQueryInterface(clone, aResult);
NS_ENSURE_SUCCESS(rv, rv);
break;
}
case nsIDOMNode::ENTITY_NODE:
case nsIDOMNode::ENTITY_REFERENCE_NODE:
@ -2888,6 +2909,14 @@ nsDocument::ImportNode(nsIDOMNode* aImportedNode,
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
}
if (document) {
nsCOMPtr<nsISupports> importedNode = do_QueryInterface(aImportedNode);
document->CallUserDataHandler(nsIDOMUserDataHandler::NODE_IMPORTED,
importedNode, aImportedNode, *aResult);
}
return NS_OK;
}
NS_IMETHODIMP
@ -3743,25 +3772,206 @@ nsDocument::GetFeature(const nsAString& aFeature,
}
NS_IMETHODIMP
nsDocument::SetUserData(const nsAString& aKey,
nsIVariant* aData,
nsIDOMUserDataHandler* aHandler,
nsIVariant** aReturn)
nsDocument::SetUserData(const nsAString &aKey,
nsIVariant *aData,
nsIDOMUserDataHandler *aHandler,
nsIVariant **aResult)
{
NS_NOTYETIMPLEMENTED("nsDocument::SetUserData()");
nsCOMPtr<nsIAtom> key = do_GetAtom(aKey);
if (!key) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_ERROR_NOT_IMPLEMENTED;
return SetUserData(NS_STATIC_CAST(nsIDocument*, this), key, aData, aHandler,
aResult);
}
NS_IMETHODIMP
nsDocument::GetUserData(const nsAString& aKey,
nsIVariant** aReturn)
nsDocument::GetUserData(const nsAString &aKey,
nsIVariant **aResult)
{
NS_NOTYETIMPLEMENTED("nsDocument::GetUserData()");
nsCOMPtr<nsIAtom> key = do_GetAtom(aKey);
if (!key) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_ERROR_NOT_IMPLEMENTED;
return GetUserData(NS_STATIC_CAST(nsIDocument*, this), key, aResult);
}
static void
ReleaseDOMUserData(void *aObject,
nsIAtom *aPropertyName,
void *aPropertyValue,
void *aData)
{
nsISupports *propertyValue = NS_STATIC_CAST(nsISupports*, aPropertyValue);
NS_RELEASE(propertyValue);
}
nsresult
nsDocument::SetUserData(const nsISupports *aObject,
nsIAtom *aKey,
nsIVariant *aData,
nsIDOMUserDataHandler *aHandler,
nsIVariant **aResult)
{
#ifdef DEBUG
nsCOMPtr<nsISupports> object =
do_QueryInterface(NS_CONST_CAST(nsISupports*, aObject));
NS_ASSERTION(object == aObject, "Use cannonical nsISupports pointer!");
#endif
*aResult = nsnull;
nsresult rv = NS_OK;
void *data;
if (aData) {
rv = mPropertyTable.SetProperty(aObject, DOM_USER_DATA, aKey, aData,
ReleaseDOMUserData, &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<nsIVariant> oldData = dont_AddRef(NS_STATIC_CAST(nsIVariant*,
data));
if (aData && aHandler) {
rv = mPropertyTable.SetProperty(aObject, DOM_USER_DATA_HANDLER, aKey,
aHandler, ReleaseDOMUserData);
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 nsISupports *aObject, nsIAtom *aKey,
nsIVariant **aResult)
{
#ifdef DEBUG
nsCOMPtr<nsISupports> object =
do_QueryInterface(NS_CONST_CAST(nsISupports*, aObject));
NS_ASSERTION(object == aObject, "Use cannonical nsISupports pointer!");
#endif
*aResult = NS_STATIC_CAST(nsIVariant*,
mPropertyTable.GetProperty(aObject, DOM_USER_DATA,
aKey));
NS_IF_ADDREF(*aResult);
return NS_OK;
}
struct nsHandlerData
{
PRUint16 mOperation;
nsCOMPtr<nsIDOMNode> mSource;
nsCOMPtr<nsIDOMNode> mDest;
nsDocument *mDocument;
};
static void
CallHandler(void *aObject, nsIAtom *aKey, void *aHandler, void *aData)
{
nsHandlerData *handlerData = NS_STATIC_CAST(nsHandlerData*, aData);
nsCOMPtr<nsIDOMUserDataHandler> handler =
NS_STATIC_CAST(nsIDOMUserDataHandler*, aHandler);
nsCOMPtr<nsIVariant> data;
nsISupports *object = NS_STATIC_CAST(nsISupports*, 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 nsISupports *aObject,
nsIDOMNode *aSource, nsIDOMNode *aDest)
{
#ifdef DEBUG
// XXX Should we guard from QI'ing nodes that are being destroyed?
nsCOMPtr<nsISupports> object =
do_QueryInterface(NS_CONST_CAST(nsISupports*, aObject));
NS_ASSERTION(object == aObject, "Use cannonical nsISupports pointer!");
#endif
nsHandlerData handlerData = { aOperation, aSource, aDest, 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();
nsISupports *object = NS_STATIC_CAST(nsISupports*, aObject);
nsIDOMUserDataHandler *handler =
NS_STATIC_CAST(nsIDOMUserDataHandler*,
propertyTable->GetProperty(object, DOM_USER_DATA_HANDLER,
aKey));
nsCOMPtr<nsIVariant> result;
data->mDestDocument->SetUserData(object, aKey,
NS_STATIC_CAST(nsIVariant*, aUserData),
handler, getter_AddRefs(result));
}
void
nsDocument::CopyUserData(const nsISupports *aObject, nsIDocument *aDestination)
{
#ifdef DEBUG
nsCOMPtr<nsISupports> object =
do_QueryInterface(NS_CONST_CAST(nsISupports*, aObject));
NS_ASSERTION(object == aObject, "Use cannonical nsISupports pointer!");
#endif
nsCopyData copyData = { this, aDestination };
mPropertyTable.Enumerate(aObject, DOM_USER_DATA, Copy, &copyData);
}
NS_IMETHODIMP
nsDocument::LookupPrefix(const nsAString& aNamespaceURI,
@ -3885,6 +4095,13 @@ nsDocument::AdoptNode(nsIDOMNode *source, nsIDOMNode **aReturn)
{
// Not allowing this yet, need to think about the security ramifications
// of giving a node a brand new node info.
// if (NS_SUCCEEDED(rv)) {
// nsCOMPtr<nsISupports> object = do_QueryInterface(source);
// CallUserDataHandler(nsIDOMUserDataHandler::NODE_ADOPTED, object, source,
// *aReturn);
// }
return NS_ERROR_NOT_IMPLEMENTED;
}
@ -3921,6 +4138,12 @@ nsDocument::RenameNode(nsIDOMNode *aNode,
return NS_ERROR_NOT_IMPLEMENTED;
}
// if (NS_SUCCEEDED(rv)) {
// nsCOMPtr<nsISupports> object = do_QueryInterface(aNode);
// CallUserDataHandler(nsIDOMUserDataHandler::NODE_RENAMED, object, aNode,
// *aReturn);
// }
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}

View File

@ -651,6 +651,21 @@ public:
virtual NS_HIDDEN_(void) ForgetLink(nsIContent* aContent);
virtual NS_HIDDEN_(void) NotifyURIVisitednessChanged(nsIURI* aURI);
NS_HIDDEN_(nsresult) SetUserData(const nsISupports *aObject,
nsIAtom *aKey,
nsIVariant *aData,
nsIDOMUserDataHandler *aHandler,
nsIVariant **aReturn);
NS_HIDDEN_(nsresult) GetUserData(const nsISupports *aObject,
nsIAtom *aKey,
nsIVariant **aResult);
NS_HIDDEN_(void) CallUserDataHandler(PRUint16 aOperation,
const nsISupports *aObject,
nsIDOMNode *aSource,
nsIDOMNode *aDest);
NS_HIDDEN_(void) CopyUserData(const nsISupports *aObject,
nsIDocument *aDestination);
protected:
void DispatchContentLoadedEvents();

View File

@ -49,6 +49,7 @@
#include "nsIDOM3Node.h"
#include "nsLayoutAtoms.h"
#include "nsDOMString.h"
#include "nsIDOMUserDataHandler.h"
class nsDocumentFragment : public nsGenericElement,
public nsIDocumentFragment,
@ -423,20 +424,24 @@ NS_IMETHODIMP
nsDocumentFragment::SetUserData(const nsAString& aKey,
nsIVariant* aData,
nsIDOMUserDataHandler* aHandler,
nsIVariant** aReturn)
nsIVariant** aResult)
{
NS_NOTYETIMPLEMENTED("nsDocumentFragment::SetUserData()");
nsIDocument *document = GetOwnerDoc();
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
return NS_ERROR_NOT_IMPLEMENTED;
return document->SetUserData(NS_STATIC_CAST(nsIContent*, this), aKey, aData,
aHandler, aResult);
}
NS_IMETHODIMP
nsDocumentFragment::GetUserData(const nsAString& aKey,
nsIVariant** aReturn)
nsIVariant** aResult)
{
NS_NOTYETIMPLEMENTED("nsDocumentFragment::GetUserData()");
nsIDocument *document = GetOwnerDoc();
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
return NS_ERROR_NOT_IMPLEMENTED;
return document->GetUserData(NS_STATIC_CAST(nsIContent*, this), aKey,
aResult);
}
NS_IMETHODIMP

View File

@ -54,6 +54,7 @@
#include "nsCOMPtr.h"
#include "nsDOMString.h"
#include "nsLayoutAtoms.h"
#include "nsIDOMUserDataHandler.h"
#include "pldhash.h"
#include "prprf.h"
@ -65,6 +66,16 @@ nsGenericDOMDataNode::nsGenericDOMDataNode(nsINodeInfo *aNodeInfo)
nsGenericDOMDataNode::~nsGenericDOMDataNode()
{
if (CouldHaveProperties()) {
nsIDocument *document = GetOwnerDoc();
if (document) {
nsISupports *thisSupports = NS_STATIC_CAST(nsIContent*, this);
document->CallUserDataHandler(nsIDOMUserDataHandler::NODE_DELETED,
thisSupports, nsnull, nsnull);
document->PropertyTable()->DeleteAllPropertiesFor(thisSupports);
}
}
if (CouldHaveEventListenerManager()) {
PL_DHashTableOperate(&nsGenericElement::sEventListenerManagersHash,
this, PL_DHASH_REMOVE);
@ -283,7 +294,8 @@ nsGenericDOMDataNode::GetBaseURI(nsAString& aURI)
}
nsresult
nsGenericDOMDataNode::CloneNode(PRBool aDeep, nsIDOMNode **aResult) const
nsGenericDOMDataNode::CloneNode(PRBool aDeep, nsIDOMNode *aSource,
nsIDOMNode **aResult) const
{
*aResult = nsnull;
@ -292,7 +304,16 @@ nsGenericDOMDataNode::CloneNode(PRBool aDeep, nsIDOMNode **aResult) const
getter_AddRefs(newContent));
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(newContent, aResult);
rv = CallQueryInterface(newContent, aResult);
nsIDocument *ownerDoc = GetOwnerDoc();
if (NS_SUCCEEDED(rv) && ownerDoc && CouldHaveProperties()) {
ownerDoc->CallUserDataHandler(nsIDOMUserDataHandler::NODE_CLONED,
NS_STATIC_CAST(const nsIContent*, this),
aSource, *aResult);
}
return rv;
}
nsresult
@ -656,6 +677,16 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIDocument *ownerDocument = GetOwnerDoc();
if (aDocument != ownerDocument) {
if (ownerDocument && CouldHaveProperties()) {
nsISupports *thisSupports = NS_STATIC_CAST(nsIContent*, this);
// Copy UserData to the new document.
ownerDocument->CopyUserData(thisSupports, aDocument);
// Remove all properties.
ownerDocument->PropertyTable()->DeleteAllPropertiesFor(thisSupports);
}
// get a new nodeinfo
nsNodeInfoManager *nodeInfoManager = aDocument->NodeInfoManager();
nsCOMPtr<nsINodeInfo> newNodeInfo;

View File

@ -151,9 +151,11 @@ public:
* do the actual cloning of the node.
*
* @param aDeep if true all descendants will be cloned too
* @param aSource nsIDOMNode pointer to this node
* @param aResult the clone
*/
nsresult CloneNode(PRBool aDeep, nsIDOMNode **aResult) const;
nsresult CloneNode(PRBool aDeep, nsIDOMNode *aSource,
nsIDOMNode **aResult) const;
nsresult LookupPrefix(const nsAString& aNamespaceURI,
nsAString& aPrefix);
@ -226,6 +228,10 @@ public:
virtual nsresult AppendChildTo(nsIContent* aKid, PRBool aNotify);
virtual nsresult RemoveChildAt(PRUint32 aIndex, PRBool aNotify);
virtual PRBool MayHaveFrame() const;
virtual void SetHasProperties()
{
SetIsInAHash();
}
/**
* This calls Clone to do the actual cloning so that we end up with the
@ -265,6 +271,11 @@ protected:
virtual nsGenericDOMDataNode *Clone(nsINodeInfo *aNodeInfo,
PRBool aCloneText) const = 0;
PRBool CouldHaveProperties() const
{
return GetIsInAHash();
}
nsTextFragment mText;
private:
@ -390,7 +401,7 @@ private:
return nsGenericDOMDataNode::IsSupported(aFeature, aVersion, aReturn); \
} \
NS_IMETHOD CloneNode(PRBool aDeep, nsIDOMNode** aReturn) { \
return nsGenericDOMDataNode::CloneNode(aDeep, aReturn); \
return nsGenericDOMDataNode::CloneNode(aDeep, this, aReturn); \
} \
virtual nsGenericDOMDataNode *Clone(nsINodeInfo *aNodeInfo, \
PRBool aCloneText) const;

View File

@ -107,6 +107,7 @@
#include "nsICategoryManager.h"
#include "nsIDOMNSFeatureFactory.h"
#include "nsIDOMDocumentType.h"
#include "nsIDOMUserDataHandler.h"
/**
@ -431,20 +432,28 @@ NS_IMETHODIMP
nsNode3Tearoff::SetUserData(const nsAString& aKey,
nsIVariant* aData,
nsIDOMUserDataHandler* aHandler,
nsIVariant** aReturn)
nsIVariant** aResult)
{
NS_NOTYETIMPLEMENTED("nsNode3Tearoff::SetUserData()");
nsIDocument *document = mContent->GetOwnerDoc();
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
return NS_ERROR_NOT_IMPLEMENTED;
nsresult rv = document->SetUserData(mContent, aKey, aData, aHandler,
aResult);
if (NS_SUCCEEDED(rv)) {
mContent->SetHasProperties();
}
return rv;
}
NS_IMETHODIMP
nsNode3Tearoff::GetUserData(const nsAString& aKey,
nsIVariant** aReturn)
nsIVariant** aResult)
{
NS_NOTYETIMPLEMENTED("nsNode3Tearoff::GetUserData()");
nsIDocument *document = mContent->GetOwnerDoc();
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
return NS_ERROR_NOT_IMPLEMENTED;
return document->GetUserData(mContent, aKey, aResult);
}
NS_IMETHODIMP
@ -857,7 +866,17 @@ nsGenericElement::~nsGenericElement()
{
NS_PRECONDITION(!IsInDoc(),
"Please remove this from the document properly");
if (HasProperties()) {
nsIDocument *document = GetOwnerDoc();
if (document) {
nsISupports *thisSupports = NS_STATIC_CAST(nsIContent*, this);
document->CallUserDataHandler(nsIDOMUserDataHandler::NODE_DELETED,
thisSupports, nsnull, nsnull);
document->PropertyTable()->DeleteAllPropertiesFor(thisSupports);
}
}
// pop any enclosed ranges out
// nsRange::OwnerGone(mContent); not used for now
@ -1878,9 +1897,14 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
// XXXbz sXBL/XBL2 issue!
nsIDocument *ownerDocument = GetOwnerDoc();
if (aDocument != ownerDocument) {
if (ownerDocument && HasProperties()) {
nsISupports *thisSupports = NS_STATIC_CAST(nsIContent*, this);
if (HasProperties()) {
ownerDocument->PropertyTable()->DeleteAllPropertiesFor(this);
// Copy UserData to the new document.
ownerDocument->CopyUserData(thisSupports, aDocument);
// Remove all properties.
ownerDocument->PropertyTable()->DeleteAllPropertiesFor(thisSupports);
}
// get a new nodeinfo
@ -4399,7 +4423,9 @@ nsGenericElement::GetProperty(nsIAtom *aPropertyName, nsresult *aStatus) const
if (!doc)
return nsnull;
return doc->PropertyTable()->GetProperty(this, aPropertyName, aStatus);
const nsISupports *thisSupports = NS_STATIC_CAST(const nsIContent*, this);
return doc->PropertyTable()->GetProperty(thisSupports, aPropertyName,
aStatus);
}
nsresult
@ -4411,7 +4437,8 @@ nsGenericElement::SetProperty(nsIAtom *aPropertyName,
if (!doc)
return NS_ERROR_FAILURE;
nsresult rv = doc->PropertyTable()->SetProperty(this, aPropertyName,
nsISupports *thisSupports = NS_STATIC_CAST(nsIContent*, this);
nsresult rv = doc->PropertyTable()->SetProperty(thisSupports, aPropertyName,
aValue, aDtor, nsnull);
if (NS_SUCCEEDED(rv))
SetFlags(GENERIC_ELEMENT_HAS_PROPERTIES);
@ -4426,7 +4453,8 @@ nsGenericElement::DeleteProperty(nsIAtom *aPropertyName)
if (!doc)
return nsnull;
return doc->PropertyTable()->DeleteProperty(this, aPropertyName);
nsISupports *thisSupports = NS_STATIC_CAST(nsIContent*, this);
return doc->PropertyTable()->DeleteProperty(thisSupports, aPropertyName);
}
void*
@ -4436,11 +4464,20 @@ nsGenericElement::UnsetProperty(nsIAtom *aPropertyName, nsresult *aStatus)
if (!doc)
return nsnull;
return doc->PropertyTable()->UnsetProperty(this, aPropertyName, aStatus);
nsISupports *thisSupports = NS_STATIC_CAST(nsIContent*, this);
return doc->PropertyTable()->UnsetProperty(thisSupports, aPropertyName,
aStatus);
}
void
nsGenericElement::SetHasProperties()
{
SetFlags(GENERIC_ELEMENT_HAS_PROPERTIES);
}
nsresult
nsGenericElement::CloneNode(PRBool aDeep, nsIDOMNode **aResult) const
nsGenericElement::CloneNode(PRBool aDeep, nsIDOMNode *aSource,
nsIDOMNode **aResult) const
{
*aResult = nsnull;
@ -4449,7 +4486,16 @@ nsGenericElement::CloneNode(PRBool aDeep, nsIDOMNode **aResult) const
getter_AddRefs(newContent));
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(newContent, aResult);
rv = CallQueryInterface(newContent, aResult);
nsIDocument *ownerDoc = GetOwnerDoc();
if (NS_SUCCEEDED(rv) && ownerDoc && HasProperties()) {
ownerDoc->CallUserDataHandler(nsIDOMUserDataHandler::NODE_CLONED,
NS_STATIC_CAST(const nsIContent*, this),
aSource, *aResult);
}
return rv;
}
nsresult

View File

@ -433,6 +433,7 @@ public:
nsresult *aStatus = nsnull);
virtual void SetMayHaveFrame(PRBool aMayHaveFrame);
virtual PRBool MayHaveFrame() const;
void SetHasProperties();
/**
* This calls Clone to do the actual cloning so that we end up with the
@ -856,9 +857,11 @@ protected:
*
* @param aDeep if true all descendants will be cloned too (attributes on the
* element are always cloned)
* @param aSource nsIDOMNode pointer to this node
* @param aResult the clone
*/
nsresult CloneNode(PRBool aDeep, nsIDOMNode **aResult) const;
nsresult CloneNode(PRBool aDeep, nsIDOMNode *aSource,
nsIDOMNode **aResult) const;
/**
* Used for either storing flags for this element or a pointer to
@ -990,9 +993,11 @@ public:
/**
* Macros to implement CloneNode().
* Macros to implement CloneNode(). _elementName is the class for which to
* implement CloneNode, _implClass is the class to use to cast to
* nsIDOMNode*.
*/
#define NS_IMPL_DOM_CLONENODE(_elementName) \
#define NS_IMPL_DOM_CLONENODE_AMBIGUOUS(_elementName, _implClass) \
nsresult \
_elementName::Clone(nsINodeInfo *aNodeInfo, PRBool aDeep, \
nsIContent **aResult) const \
@ -1015,9 +1020,14 @@ _elementName::Clone(nsINodeInfo *aNodeInfo, PRBool aDeep, \
NS_IMETHODIMP \
_elementName::CloneNode(PRBool aDeep, nsIDOMNode **aResult) \
{ \
return nsGenericElement::CloneNode(aDeep, aResult); \
return nsGenericElement::CloneNode(aDeep, \
NS_STATIC_CAST(_implClass*, this), \
aResult); \
}
#define NS_IMPL_DOM_CLONENODE(_elementName) \
NS_IMPL_DOM_CLONENODE_AMBIGUOUS(_elementName, _elementName)
#define NS_IMPL_DOM_CLONENODE_WITH_INIT(_elementName) \
nsresult \
_elementName::Clone(nsINodeInfo *aNodeInfo, PRBool aDeep, \
@ -1042,7 +1052,7 @@ _elementName::Clone(nsINodeInfo *aNodeInfo, PRBool aDeep, \
NS_IMETHODIMP \
_elementName::CloneNode(PRBool aDeep, nsIDOMNode **aResult) \
{ \
return nsGenericElement::CloneNode(aDeep, aResult); \
return nsGenericElement::CloneNode(aDeep, this, aResult); \
}
#endif /* nsGenericElement_h___ */

View File

@ -50,6 +50,9 @@
#include "nsContentErrors.h"
#include "nsIAtom.h"
#define CATEGORY_BIT 0x00000001U
#define CATEGORY_MASK ~CATEGORY_BIT
struct PropertyListMapEntry : public PLDHashEntryHdr {
const void *key;
void *value;
@ -57,14 +60,10 @@ struct PropertyListMapEntry : public PLDHashEntryHdr {
//----------------------------------------------------------------------
struct nsPropertyTable::PropertyList {
nsCOMPtr<nsIAtom> mName; // property name
PLDHashTable mObjectValueMap; // map of object/value pairs
NSPropertyDtorFunc mDtorFunc; // property specific value dtor function
void* mDtorData;
PropertyList* mNext;
PropertyList(nsIAtom* aName,
class nsPropertyTable::PropertyList {
public:
PropertyList(PRUint32 aCategory,
nsIAtom* aName,
NSPropertyDtorFunc aDtorFunc,
void* aDtorData) NS_HIDDEN;
~PropertyList() NS_HIDDEN;
@ -75,6 +74,37 @@ struct nsPropertyTable::PropertyList {
// Destroy all remaining properties (without removing them)
NS_HIDDEN_(void) Destroy();
NS_HIDDEN_(PRBool) Equals(PRUint32 aCategory, nsIAtom *aPropertyName)
{
PRUint32 category = mBits & CATEGORY_BIT ? mBits & CATEGORY_MASK : 0;
return mName == aPropertyName && category == aCategory;
}
NS_HIDDEN_(PRBool) IsInCategory(PRUint32 aCategory)
{
PRUint32 category = mBits & CATEGORY_BIT ? mBits & CATEGORY_MASK : 0;
return category == aCategory;
}
NS_HIDDEN_(void*) GetDtorData()
{
return mBits & CATEGORY_BIT ? nsnull : NS_REINTERPRET_CAST(void*, mBits);
}
NS_HIDDEN_(void) SetDtorData(void *aDtorData)
{
NS_ASSERTION(!(mBits & CATEGORY_BIT),
"Can't set both DtorData and category!");
mBits = NS_REINTERPRET_CAST(PtrBits, aDtorData);
}
nsCOMPtr<nsIAtom> mName; // property name
PLDHashTable mObjectValueMap; // map of object/value pairs
NSPropertyDtorFunc mDtorFunc; // property specific value dtor function
PropertyList* mNext;
private:
PtrBits mBits; // pointer to pass to dtor or category
};
nsPropertyTable::~nsPropertyTable()
@ -98,8 +128,27 @@ nsPropertyTable::DeleteAllPropertiesFor(const void *aObject)
}
}
void
nsPropertyTable::Enumerate(const void *aObject, PRUint32 aCategory,
NSPropertyFunc aCallback, void *aData)
{
PropertyList* prop;
for (prop = mPropertyList; prop; prop = prop->mNext) {
if (prop->IsInCategory(aCategory)) {
PropertyListMapEntry *entry = NS_STATIC_CAST(PropertyListMapEntry*,
PL_DHashTableOperate(&prop->mObjectValueMap, aObject,
PL_DHASH_LOOKUP));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
aCallback(NS_CONST_CAST(void*, aObject), prop->mName, entry->value,
aData);
}
}
}
}
void*
nsPropertyTable::GetPropertyInternal(const void *aObject,
PRUint32 aCategory,
nsIAtom *aPropertyName,
PRBool aRemove,
nsresult *aResult)
@ -108,7 +157,7 @@ nsPropertyTable::GetPropertyInternal(const void *aObject,
nsresult rv = NS_PROPTABLE_PROP_NOT_THERE;
void *propValue = nsnull;
PropertyList* propertyList = GetPropertyListFor(aPropertyName);
PropertyList* propertyList = GetPropertyListFor(aCategory, aPropertyName);
if (propertyList) {
PropertyListMapEntry *entry = NS_STATIC_CAST(PropertyListMapEntry*,
PL_DHashTableOperate(&propertyList->mObjectValueMap, aObject,
@ -130,29 +179,29 @@ nsPropertyTable::GetPropertyInternal(const void *aObject,
}
nsresult
nsPropertyTable::SetProperty(const void *aObject,
nsIAtom *aPropertyName,
void *aPropertyValue,
NSPropertyDtorFunc aPropDtorFunc,
void *aPropDtorData)
nsPropertyTable::SetPropertyInternal(const void *aObject,
PRUint32 aCategory,
nsIAtom *aPropertyName,
void *aPropertyValue,
NSPropertyDtorFunc aPropDtorFunc,
void *aPropDtorData,
void **aOldValue)
{
NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
PropertyList* propertyList = GetPropertyListFor(aPropertyName);
PropertyList* propertyList = GetPropertyListFor(aCategory, aPropertyName);
if (propertyList) {
// Make sure the dtor function and data match
if (aPropDtorFunc != propertyList->mDtorFunc ||
aPropDtorData != propertyList->mDtorData) {
aPropDtorData != propertyList->GetDtorData()) {
return NS_ERROR_INVALID_ARG;
}
} else {
propertyList = new PropertyList(aPropertyName, aPropDtorFunc,
propertyList = new PropertyList(aCategory, aPropertyName, aPropDtorFunc,
aPropDtorData);
if (!propertyList)
return NS_ERROR_OUT_OF_MEMORY;
if (!propertyList->mObjectValueMap.ops) {
if (!propertyList || !propertyList->mObjectValueMap.ops) {
delete propertyList;
return NS_ERROR_OUT_OF_MEMORY;
}
@ -170,11 +219,17 @@ nsPropertyTable::SetProperty(const void *aObject,
return NS_ERROR_OUT_OF_MEMORY;
// A NULL entry->key is the sign that the entry has just been allocated
// for us. If it's non-NULL then we have an existing entry.
if (entry->key && propertyList->mDtorFunc) {
propertyList->mDtorFunc(NS_CONST_CAST(void*, entry->key), aPropertyName,
entry->value, propertyList->mDtorData);
if (entry->key) {
if (aOldValue)
*aOldValue = entry->value;
else if (propertyList->mDtorFunc)
propertyList->mDtorFunc(NS_CONST_CAST(void*, entry->key), aPropertyName,
entry->value, propertyList->GetDtorData());
result = NS_PROPTABLE_PROP_OVERWRITTEN;
}
else if (aOldValue) {
*aOldValue = nsnull;
}
entry->key = aObject;
entry->value = aPropertyValue;
@ -183,11 +238,12 @@ nsPropertyTable::SetProperty(const void *aObject,
nsresult
nsPropertyTable::DeleteProperty(const void *aObject,
PRUint32 aCategory,
nsIAtom *aPropertyName)
{
NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
PropertyList* propertyList = GetPropertyListFor(aPropertyName);
PropertyList* propertyList = GetPropertyListFor(aCategory, aPropertyName);
if (propertyList) {
if (propertyList->DeletePropertyFor(aObject))
return NS_OK;
@ -197,12 +253,13 @@ nsPropertyTable::DeleteProperty(const void *aObject,
}
nsPropertyTable::PropertyList*
nsPropertyTable::GetPropertyListFor(nsIAtom* aPropertyName) const
nsPropertyTable::GetPropertyListFor(PRUint32 aCategory,
nsIAtom* aPropertyName) const
{
PropertyList* result;
for (result = mPropertyList; result; result = result->mNext) {
if (result->mName.get() == aPropertyName) {
if (result->Equals(aCategory, aPropertyName)) {
break;
}
}
@ -212,11 +269,20 @@ nsPropertyTable::GetPropertyListFor(nsIAtom* aPropertyName) const
//----------------------------------------------------------------------
nsPropertyTable::PropertyList::PropertyList(nsIAtom *aName,
nsPropertyTable::PropertyList::PropertyList(PRUint32 aCategory,
nsIAtom *aName,
NSPropertyDtorFunc aDtorFunc,
void *aDtorData)
: mName(aName), mDtorFunc(aDtorFunc), mDtorData(aDtorData), mNext(nsnull)
: mName(aName),
mDtorFunc(aDtorFunc),
mNext(nsnull),
mBits(aCategory == 0 ? NS_REINTERPRET_CAST(PtrBits, aDtorData) :
aCategory | CATEGORY_BIT)
{
NS_ASSERTION(!(aCategory & CATEGORY_BIT), "Don't set the reserved bit!");
NS_ASSERTION(aCategory == 0 || !aDtorData,
"Can't set both DtorData and category!");
PL_DHashTableInit(&mObjectValueMap, PL_DHashGetStubOps(), this,
sizeof(PropertyListMapEntry), 16);
}
@ -236,14 +302,14 @@ DestroyPropertyEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr,
PropertyListMapEntry* entry = NS_STATIC_CAST(PropertyListMapEntry*, hdr);
propList->mDtorFunc(NS_CONST_CAST(void*, entry->key), propList->mName,
entry->value, propList->mDtorData);
entry->value, propList->GetDtorData());
return PL_DHASH_NEXT;
}
void
nsPropertyTable::PropertyList::Destroy()
{
// Enumerate any remaining frame/value pairs and destroy the value object
// Enumerate any remaining object/value pairs and destroy the value object
if (mDtorFunc)
PL_DHashTableEnumerate(&mObjectValueMap, DestroyPropertyEnumerator,
nsnull);
@ -259,7 +325,7 @@ nsPropertyTable::PropertyList::DeletePropertyFor(const void* aObject)
if (mDtorFunc)
mDtorFunc(NS_CONST_CAST(void*, aObject), mName,
entry->value, mDtorData);
entry->value, GetDtorData());
PL_DHashTableRawRemove(&mObjectValueMap, entry);

View File

@ -58,6 +58,13 @@
#include "nscore.h"
class nsIAtom;
typedef unsigned long PtrBits;
typedef void
(*NSPropertyFunc)(void *aObject,
nsIAtom *aPropertyName,
void *aPropertyValue,
void *aData);
/**
* Callback type for property destructors. |aObject| is the object
@ -65,11 +72,13 @@ class nsIAtom;
* being removed, |aPropertyValue| is the value of the property, and |aData|
* is the opaque destructor data that was passed to SetProperty().
**/
typedef void
(*NSPropertyDtorFunc)(void *aObject,
nsIAtom *aPropertyName,
void *aPropertyValue,
void *aData);
typedef NSPropertyFunc NSPropertyDtorFunc;
// Categories of properties
// 0x00000000U is global.
// 0x00000001U is reserved.
#define DOM_USER_DATA 0x00000002U
#define DOM_USER_DATA_HANDLER 0x00000004U
class nsPropertyTable
{
@ -81,57 +90,142 @@ class nsPropertyTable
void* GetProperty(const void *aObject,
nsIAtom *aPropertyName,
nsresult *aResult = nsnull)
{ return GetPropertyInternal(aObject, aPropertyName, PR_FALSE, aResult); }
{
return GetPropertyInternal(aObject, 0, aPropertyName, PR_FALSE, aResult);
}
void* GetProperty(const void *aObject,
PRUint32 aCategory,
nsIAtom *aPropertyName,
nsresult *aResult = nsnull)
{
return GetPropertyInternal(aObject, aCategory, aPropertyName, PR_FALSE,
aResult);
}
/**
* Set the value of the property |aPropertyName| to |aPropertyValue|
* for node |aObject|. |aDtor| is a destructor for the property value
* to be called if the property is removed. It can be null if no
* destructor is required. |aDtorData| is an optional opaque context to
* be passed to the property destructor. Note that the destructor is
* global for each property name regardless of node; it is an error
* to set a given property with a different destructor than was used before
* (this will return NS_ERROR_INVALID_ARG).
**/
* Set the value of the property |aPropertyName| in the global category to
* |aPropertyValue| for node |aObject|. |aDtor| is a destructor for the
* property value to be called if the property is removed. It can be null
* if no destructor is required. |aDtorData| is an optional pointer to an
* opaque context to be passed to the property destructor. Note that the
* destructor is global for each property name regardless of node; it is an
* error to set a given property with a different destructor than was used
* before (this will return NS_ERROR_INVALID_ARG). If aOldValue is non-null
* it will contain the old value after the function returns (the destructor
* for the old value will not be run in that case).
*/
NS_HIDDEN_(nsresult) SetProperty(const void *aObject,
nsIAtom *aPropertyName,
void *aPropertyValue,
NSPropertyDtorFunc aDtor,
void *aDtorData);
void *aDtorData,
void **aOldValue = nsnull)
{
return SetPropertyInternal(aObject, 0, aPropertyName, aPropertyValue,
aDtor, aDtorData, aOldValue);
}
/**
* Delete the property |aPropertyName| for object |aObject|.
* The property's destructor function will be called.
**/
* Set the value of the property |aPropertyName| in the category |aCategory|
* to |aPropertyValue| for node |aObject|. |aDtor| is a destructor for the
* property value to be called if the property is removed. It can be null
* if no destructor is required. Note that the destructor is global for
* each property name regardless of node; it is an error to set a given
* property with a different destructor than was used before (this will
* return NS_ERROR_INVALID_ARG). If aOldValue is non-null it will contain the
* old value after the function returns (the destructor for the old value
* will not be run in that case).
*/
NS_HIDDEN_(nsresult) SetProperty(const void *aObject,
PRUint32 aCategory,
nsIAtom *aPropertyName,
void *aPropertyValue,
NSPropertyDtorFunc aDtor,
void **aOldValue = nsnull)
{
return SetPropertyInternal(aObject, aCategory, aPropertyName,
aPropertyValue, aDtor, nsnull, aOldValue);
}
/**
* Delete the property |aPropertyName| in the global category for object
* |aObject|. The property's destructor function will be called.
*/
NS_HIDDEN_(nsresult) DeleteProperty(const void *aObject,
nsIAtom *aPropertyName)
{
return DeleteProperty(aObject, 0, aPropertyName);
}
/**
* Delete the property |aPropertyName| in category |aCategory| for object
* |aObject|. The property's destructor function will be called.
*/
NS_HIDDEN_(nsresult) DeleteProperty(const void *aObject,
PRUint32 aCategory,
nsIAtom *aPropertyName);
/**
* Unset the property |aPropertyName| for object |aObject|, but do not
* call the property's destructor function. The property value is returned.
**/
* Unset the property |aPropertyName| in the global category for object
* |aObject|, but do not call the property's destructor function. The
* property value is returned.
*/
void* UnsetProperty(const void *aObject,
nsIAtom *aPropertyName,
nsresult *aStatus = nsnull)
{ return GetPropertyInternal(aObject, aPropertyName, PR_TRUE, aStatus); }
{
return GetPropertyInternal(aObject, 0, aPropertyName, PR_TRUE, aStatus);
}
/**
* Unset the property |aPropertyName| in category |aCategory| for object
* |aObject|, but do not call the property's destructor function. The
* property value is returned.
*/
void* UnsetProperty(const void *aObject,
PRUint32 aCategory,
nsIAtom *aPropertyName,
nsresult *aStatus = nsnull)
{
return GetPropertyInternal(aObject, aCategory, aPropertyName, PR_TRUE,
aStatus);
}
/**
* Deletes all of the properties for object |aObject|, calling the
* destructor function for each property.
**/
*/
NS_HIDDEN_(void) DeleteAllPropertiesFor(const void *aObject);
/**
* Enumerate the properties in category |aCategory| for object |aObject|.
* For every property |aCallback| will be called with as arguments |aObject|,
* the property name, the property value and |aData|.
*/
NS_HIDDEN_(void) Enumerate(const void *aObject, PRUint32 aCategory,
NSPropertyFunc aCallback, void *aData);
~nsPropertyTable() NS_HIDDEN;
struct PropertyList;
private:
NS_HIDDEN_(void) DestroyPropertyList();
NS_HIDDEN_(PropertyList*) GetPropertyListFor(nsIAtom *aPropertyName) const;
NS_HIDDEN_(PropertyList*) GetPropertyListFor(PRUint32 aCategory,
nsIAtom *aPropertyName) const;
NS_HIDDEN_(void*) GetPropertyInternal(const void *aObject,
PRUint32 aCategory,
nsIAtom *aPropertyName,
PRBool aRemove,
nsresult *aStatus);
NS_HIDDEN_(nsresult) SetPropertyInternal(const void *aObject,
PRUint32 aCategory,
nsIAtom *aPropertyName,
void *aPropertyValue,
NSPropertyDtorFunc aDtor,
void *aDtorData,
void **aOldValue);
PropertyList *mPropertyList;
};

View File

@ -435,7 +435,7 @@ nsHTMLInputElement::Clone(nsINodeInfo *aNodeInfo, PRBool aDeep,
NS_IMETHODIMP
nsHTMLInputElement::CloneNode(PRBool aDeep, nsIDOMNode **aResult)
{
return nsGenericElement::CloneNode(aDeep, aResult);
return nsGenericElement::CloneNode(aDeep, this, aResult);
}
void

View File

@ -114,7 +114,8 @@ NS_HTML_CONTENT_INTERFACE_MAP_AMBIGOUS_BEGIN(nsHTMLSharedListElement,
NS_HTML_CONTENT_INTERFACE_MAP_END
NS_IMPL_DOM_CLONENODE(nsHTMLSharedListElement)
NS_IMPL_DOM_CLONENODE_AMBIGUOUS(nsHTMLSharedListElement,
nsIDOMHTMLOListElement)
NS_IMPL_BOOL_ATTR(nsHTMLSharedListElement, Compact, compact)

View File

@ -513,7 +513,7 @@ nsHTMLScriptElement::Clone(nsINodeInfo *aNodeInfo, PRBool aDeep,
NS_IMETHODIMP
nsHTMLScriptElement::CloneNode(PRBool aDeep, nsIDOMNode **aResult)
{
return nsGenericElement::CloneNode(aDeep, aResult);
return nsGenericElement::CloneNode(aDeep, this, aResult);
}
NS_IMETHODIMP

View File

@ -212,7 +212,7 @@ NS_HTML_CONTENT_INTERFACE_MAP_AMBIGOUS_BEGIN(nsHTMLSharedElement,
NS_HTML_CONTENT_INTERFACE_MAP_END
NS_IMPL_DOM_CLONENODE(nsHTMLSharedElement)
NS_IMPL_DOM_CLONENODE_AMBIGUOUS(nsHTMLSharedElement, nsIDOMHTMLEmbedElement)
/////////////////////////////////////////////

View File

@ -329,7 +329,7 @@ nsSVGUseElement::Clone(nsINodeInfo *aNodeInfo, PRBool aDeep,
NS_IMETHODIMP
nsSVGUseElement::CloneNode(PRBool aDeep, nsIDOMNode **aResult)
{
return nsGenericElement::CloneNode(aDeep, aResult);
return nsGenericElement::CloneNode(aDeep, this, aResult);
}
//----------------------------------------------------------------------

View File

@ -89,6 +89,7 @@
#include "nsIScriptGlobalObjectOwner.h"
#include "nsIJSContextStack.h"
#include "nsContentCreatorFunctions.h"
#include "nsIDOMUserDataHandler.h"
// XXX The XML world depends on the html atoms
#include "nsHTMLAtoms.h"
@ -725,7 +726,13 @@ nsXMLDocument::CloneNode(PRBool aDeep, nsIDOMNode** aReturn)
}
}
return CallQueryInterface(newDoc, aReturn);
rv = CallQueryInterface(newDoc, aReturn);
if (NS_SUCCEEDED(rv)) {
CallUserDataHandler(nsIDOMUserDataHandler::NODE_CLONED,
NS_STATIC_CAST(nsIDocument*, this), this, *aReturn);
}
return rv;
}
// nsIDOMDocument interface

View File

@ -514,7 +514,7 @@ nsXULElement::Clone(nsINodeInfo *aNodeInfo, PRBool aDeep,
NS_IMETHODIMP
nsXULElement::CloneNode(PRBool aDeep, nsIDOMNode **aResult)
{
return nsGenericElement::CloneNode(aDeep, aResult);
return nsGenericElement::CloneNode(aDeep, this, aResult);
}
//----------------------------------------------------------------------
@ -860,9 +860,14 @@ nsXULElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
// XXXbz sXBL/XBL2 issue!
nsIDocument *ownerDocument = GetOwnerDoc();
if (aDocument != ownerDocument) {
if (ownerDocument && HasProperties()) {
nsISupports *thisSupports = NS_STATIC_CAST(nsIContent*, this);
if (HasProperties()) {
ownerDocument->PropertyTable()->DeleteAllPropertiesFor(this);
// Copy UserData to the new document.
ownerDocument->CopyUserData(thisSupports, aDocument);
// Remove all properties.
ownerDocument->PropertyTable()->DeleteAllPropertiesFor(thisSupports);
}
// get a new nodeinfo
@ -1080,7 +1085,7 @@ nsXULElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
// and cells going away.
// First, retrieve the tree.
// Check first whether this element IS the tree
controlElement = do_QueryInterface((nsIDOMXULElement*)this);
controlElement = do_QueryInterface(NS_STATIC_CAST(nsIContent*, this));
// If it's not, look at our parent
if (!controlElement)

View File

@ -42,7 +42,7 @@
// Introduced in DOM Level 3:
[scriptable, function, uuid(5470deff-03c9-41b7-a824-e3225266b343)]
interface nsIDOMUserDataHandler
interface nsIDOMUserDataHandler : nsISupports
{
// OperationType
const unsigned short NODE_CLONED = 1;