From c855b6a51286a4b83a5b48999aa2c3188401af77 Mon Sep 17 00:00:00 2001 From: "jst%netscape.com" Date: Mon, 8 May 2000 14:29:44 +0000 Subject: [PATCH] Checking in new files for (the not yet checked in) shared node info code. Not part of the build yet. r=buster@netscape.com --- content/base/public/nsINodeInfo.h | 209 +++++++++++++++++ content/base/src/nsNodeInfo.cpp | 307 +++++++++++++++++++++++++ content/base/src/nsNodeInfo.h | 108 +++++++++ content/base/src/nsNodeInfoManager.cpp | 272 ++++++++++++++++++++++ content/base/src/nsNodeInfoManager.h | 80 +++++++ layout/base/public/nsINodeInfo.h | 209 +++++++++++++++++ layout/base/src/nsNodeInfo.cpp | 307 +++++++++++++++++++++++++ layout/base/src/nsNodeInfo.h | 108 +++++++++ layout/base/src/nsNodeInfoManager.cpp | 272 ++++++++++++++++++++++ layout/base/src/nsNodeInfoManager.h | 80 +++++++ 10 files changed, 1952 insertions(+) create mode 100644 content/base/public/nsINodeInfo.h create mode 100644 content/base/src/nsNodeInfo.cpp create mode 100644 content/base/src/nsNodeInfo.h create mode 100644 content/base/src/nsNodeInfoManager.cpp create mode 100644 content/base/src/nsNodeInfoManager.h create mode 100644 layout/base/public/nsINodeInfo.h create mode 100644 layout/base/src/nsNodeInfo.cpp create mode 100644 layout/base/src/nsNodeInfo.h create mode 100644 layout/base/src/nsNodeInfoManager.cpp create mode 100644 layout/base/src/nsNodeInfoManager.h diff --git a/content/base/public/nsINodeInfo.h b/content/base/public/nsINodeInfo.h new file mode 100644 index 00000000000..f3b1b90fca1 --- /dev/null +++ b/content/base/public/nsINodeInfo.h @@ -0,0 +1,209 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* + * nsINodeInfo is an interface to node info, such as name, prefix, namespace + * ID and possibly other data that is shared shared between nodes (elements + * and attributes) that have the same name, prefix and namespace ID within + * the same document. + * + * nsINodeInfoManager is an interface to an object that manages a list of + * nsINodeInfo's, every document object should hold a strong reference to + * a nsINodeInfoManager and every nsINodeInfo also holds a string reference + * to their owning manager. When a nsINodeInfo is no longer used it will + * automatically remove itself from its owner manager, and when all + * nsINodeInfo's have been removed from a nsINodeInfoManager and all external + * references are released the nsINodeInfoManager deletes itself. + * + * -- jst@netscape.com + */ + +#ifndef nsINodeInfo_h___ +#define nsINodeInfo_h___ + +#include "nsISupports.h" + +// Forward declarations +class nsIAtom; +class nsINodeInfoManager; +class nsINameSpaceManager; +class nsString; + + +// IID for the nsINodeInfo interface +#define NS_INODEINFO_IID \ +{ 0x93dbfd8c, 0x2fb3, 0x4ef5, \ + {0xa2, 0xa0, 0xcf, 0xf2, 0x69, 0x6f, 0x07, 0x88} } + +// IID for the nsINodeInfoManager interface +#define NS_INODEINFOMANAGER_IID \ +{ 0xb622469b, 0x4dcf, 0x45c4, \ + {0xb0, 0xb9, 0xa7, 0x32, 0xbc, 0xee, 0xa5, 0xcc} } + +#define NS_NODEINFOMANAGER_PROGID "component://netscape/layout/nodeinfomanager" + + +class nsINodeInfo : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_INODEINFO_IID) + + /* + * Get the name from this node as a string, this does not include the prefix. + * + * For the HTML element "" this will return "body" and for the XML + * element "" this will return "body". + */ + NS_IMETHOD GetName(nsString& aName) = 0; + + /* + * Get the name from this node as an atom, this does not include the prefix. + * This function never returns a null atom. + * + * For the HTML element "" this will return the "body" atom and for + * the XML element "" this will return the "body" atom. + */ + NS_IMETHOD GetNameAtom(nsIAtom*& aAtom) = 0; + + /* + * Get the qualified name from this node as a string, the qualified name + * includes the prefix, if one exists. + * + * For the HTML element "" this will return "body" and for the XML + * element "" this will return "html:body". + */ + NS_IMETHOD GetQualifiedName(nsString& aQualifiedName) = 0; + + /* + * Get the local name from this node as a string, GetLocalName() gets the + * same string as GetName() but only if the node has a prefix and/or a + * namespace URI. If the node has neither a prefix nor a namespace URI the + * local name is a null string. + * + * For the HTML element "" in a HTML document this will return a null + * string and for the XML element "" this will return "body". + */ + NS_IMETHOD GetLocalName(nsString& aLocalName) = 0; + + /* + * Get the prefix from this node as a string. + * + * For the HTML element "" this will return a null string and for + * the XML element "" this will return the string "html". + */ + NS_IMETHOD GetPrefix(nsString& aPrefix) = 0; + + /* + * Get the prefix from this node as an atom. + * + * For the HTML element "" this will return a null atom and for + * the XML element "" this will return the "html" atom. + */ + NS_IMETHOD GetPrefixAtom(nsIAtom*& aAtom) = 0; + + /* + * Get the namespace URI for a node, if the node has a namespace URI. + * + * For the HTML element "" in a HTML document this will return a null + * string and for the XML element "" (assuming that this element, + * or one of it's ancestors has an + * xmlns:html='http://www.w3.org/TR/REC-html40' attribute) this will return + * the string "http://www.w3.org/TR/REC-html40". + */ + NS_IMETHOD GetNamespaceURI(nsString& aNameSpaceURI) = 0; + + /* + * Get the namespace ID for a node if the node has a namespace, if not this + * returns kNameSpaceID_None. + * + * For the HTML element "" in a HTML document this will return + * kNameSpaceID_None and for the XML element "" (assuming that + * this element, or one of it's ancestors has an + * xmlns:html='http://www.w3.org/TR/REC-html40' attribute) this will return + * the namespace ID for "http://www.w3.org/TR/REC-html40". + */ + NS_IMETHOD GetNamespaceID(PRInt32& aResult) = 0; + + /* + * Get the owning node info manager, this will never return null. + */ + NS_IMETHOD GetNodeInfoManager(nsINodeInfoManager*& aNodeInfoManager) = 0; + + /* + * Utility functions that can be used to check if a nodeinfo holds a spcific + * name, name and prefix, name and prefix and namespace ID, or just + * namespace ID. + */ + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom) = 0; + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom, nsIAtom *aPrefixAtom) = 0; + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom, PRInt32 aNamespaceID) = 0; + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom, nsIAtom *aPrefixAtom, + PRInt32 aNamespaceID) = 0; + NS_IMETHOD_(PRBool) NamespaceEquals(PRInt32 aNamespaceID) = 0; + + /* + * This is a convinience method that creates a new nsINodeInfo that differs + * only by name from the one this is called on. + */ + NS_IMETHOD NameChanged(nsIAtom *aName, nsINodeInfo*& aResult) = 0; + + /* + * This is a convinience method that creates a new nsINodeInfo that differs + * only by prefix from the one this is called on. + */ + NS_IMETHOD PrefixChanged(nsIAtom *aPrefix, nsINodeInfo*& aResult) = 0; +}; + + +class nsINodeInfoManager : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_INODEINFOMANAGER_IID) + + /* + * Initialize the nodeinfo manager with a namespace manager, this should + * allways be done. + */ + NS_IMETHOD Init(nsINameSpaceManager *aNameSpaceManager) = 0; + + /* + * Methods for creating nodeinfo's from atoms and/or strings. + */ + NS_IMETHOD GetNodeInfo(nsIAtom *aName, nsIAtom *aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo) = 0; + NS_IMETHOD GetNodeInfo(const nsString& aName, nsIAtom *aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo) = 0; + NS_IMETHOD GetNodeInfo(const nsString& aName, const nsString& aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo) = 0; + NS_IMETHOD GetNodeInfo(const nsString& aName, const nsString& aPrefix, + const nsString& aNamespaceURI, + nsINodeInfo*& aNodeInfo) = 0; + + /* + * Getter for the namespace manager used by this nodeinfo manager. + */ + NS_IMETHOD GetNamespaceManager(nsINameSpaceManager*& aNameSpaceManager) = 0; +}; + +extern nsresult NS_NewNodeInfoManager(nsINodeInfoManager** aResult); + +#endif /* nsINodeInfo_h___ */ diff --git a/content/base/src/nsNodeInfo.cpp b/content/base/src/nsNodeInfo.cpp new file mode 100644 index 00000000000..1fd7e4e955b --- /dev/null +++ b/content/base/src/nsNodeInfo.cpp @@ -0,0 +1,307 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +#include "nsNodeInfo.h" +#include "nsNodeInfoManager.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsIAtom.h" +#include "nsINameSpaceManager.h" + + +nsNodeInfo::nsNodeInfo() + : mInner(), mOwnerManager(nsnull) +{ + NS_INIT_REFCNT(); +} + + +nsNodeInfo::~nsNodeInfo() +{ + if (mOwnerManager) { + mOwnerManager->RemoveNodeInfo(this); + NS_RELEASE(mOwnerManager); + } + + NS_IF_RELEASE(mInner.mName); + NS_IF_RELEASE(mInner.mPrefix); +} + + +nsresult +nsNodeInfo::Init(nsIAtom *aName, nsIAtom *aPrefix, PRInt32 aNamespaceID, + nsNodeInfoManager *aOwnerManager) +{ + NS_ENSURE_TRUE(!mInner.mName && !mInner.mPrefix && !mOwnerManager, + NS_ERROR_ALREADY_INITIALIZED); + NS_ENSURE_ARG_POINTER(aName); + NS_ENSURE_ARG_POINTER(aOwnerManager); + + mInner.mName = aName; + NS_ADDREF(mInner.mName); + + mInner.mPrefix = aPrefix; + NS_IF_ADDREF(mInner.mPrefix); + + mInner.mNamespaceID = aNamespaceID; + + mOwnerManager = aOwnerManager; + NS_ADDREF(mOwnerManager); + + return NS_OK; +} + + +// nsISupports + +NS_IMPL_THREADSAFE_ISUPPORTS(nsNodeInfo, NS_GET_IID(nsINodeInfo)); + + +// nsINodeInfo + +NS_IMETHODIMP +nsNodeInfo::GetName(nsString& aName) +{ + NS_ENSURE_TRUE(mInner.mName, NS_ERROR_NOT_INITIALIZED); + + return mInner.mName->ToString(aName); +} + + +NS_IMETHODIMP +nsNodeInfo::GetNameAtom(nsIAtom*& aAtom) +{ + NS_ABORT_IF_FALSE(mInner.mName, "nsNodeInfo not initialized!"); + + aAtom = mInner.mName; + NS_IF_ADDREF(aAtom); + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfo::GetQualifiedName(nsString& aQualifiedName) +{ + NS_ENSURE_TRUE(mInner.mName, NS_ERROR_NOT_INITIALIZED); + +#ifdef MOZILLA_IS_READY_FOR_THIS + if (mInner.mPrefix) { + mInner.mPrefix->ToString(aQualifiedName); + + aQualifiedName.Append(':'); + } + + nsAutoString tmp; + mInner.mName->ToString(tmp); + + aQualifiedName.Append(tmp); + +#else + mInner.mName->ToString(aQualifiedName); +#endif + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfo::GetLocalName(nsString& aLocalName) +{ + NS_ENSURE_TRUE(mInner.mName, NS_ERROR_NOT_INITIALIZED); + + if (mInner.mNamespaceID > 0) { + return mInner.mName->ToString(aLocalName); + } + + aLocalName.Truncate(); + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfo::GetPrefix(nsString& aPrefix) +{ + if (mInner.mPrefix) { + mInner.mPrefix->ToString(aPrefix); + } else { + aPrefix.Truncate(); + } + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfo::GetPrefixAtom(nsIAtom*& aAtom) +{ + aAtom = mInner.mPrefix; + NS_IF_ADDREF(aAtom); + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfo::GetNamespaceURI(nsString& aNameSpaceURI) +{ + NS_ENSURE_TRUE(mOwnerManager, NS_ERROR_NOT_INITIALIZED); + nsresult rv = NS_OK; + + if (mInner.mNamespaceID > 0) { + nsCOMPtr nsm; + + mOwnerManager->GetNamespaceManager(*getter_AddRefs(nsm)); + NS_ENSURE_TRUE(nsm, NS_ERROR_NOT_INITIALIZED); + + rv = nsm->GetNameSpaceURI(mInner.mNamespaceID, aNameSpaceURI); + } else { + aNameSpaceURI.Truncate(); + } + + return rv; +} + + +NS_IMETHODIMP +nsNodeInfo::GetNamespaceID(PRInt32& aResult) +{ + aResult = mInner.mNamespaceID; + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfo::GetNodeInfoManager(nsINodeInfoManager*& aNodeInfoManager) +{ + NS_ENSURE_TRUE(mOwnerManager, NS_ERROR_NOT_INITIALIZED); + + aNodeInfoManager = mOwnerManager; + + NS_ADDREF(aNodeInfoManager); + + return NS_OK; +} + + +NS_IMETHODIMP_(PRBool) +nsNodeInfo::Equals(nsIAtom *aNameAtom) +{ + return mInner.mName == aNameAtom; +} + + +NS_IMETHODIMP_(PRBool) +nsNodeInfo::Equals(nsIAtom *aNameAtom, nsIAtom *aPrefixAtom) +{ + return (mInner.mName == aNameAtom) && (mInner.mPrefix == aPrefixAtom); +} + + +NS_IMETHODIMP_(PRBool) +nsNodeInfo::Equals(nsIAtom *aNameAtom, PRInt32 aNamespaceID) +{ + return (mInner.mName == aNameAtom) && (mInner.mNamespaceID == aNamespaceID); +} + + +NS_IMETHODIMP_(PRBool) +nsNodeInfo::Equals(nsIAtom *aNameAtom, nsIAtom *aPrefixAtom, + PRInt32 aNamespaceID) +{ + return (mInner.mName == aNameAtom) && + (mInner.mPrefix == aPrefixAtom) && + (mInner.mNamespaceID == aNamespaceID); +} + + +NS_IMETHODIMP_(PRBool) +nsNodeInfo::NamespaceEquals(PRInt32 aNamespaceID) +{ + return mInner.mNamespaceID == aNamespaceID; +} + + +NS_IMETHODIMP +nsNodeInfo::NameChanged(nsIAtom *aName, nsINodeInfo*& aResult) +{ + NS_ENSURE_TRUE(mOwnerManager, NS_ERROR_NOT_INITIALIZED); + + return mOwnerManager->GetNodeInfo(aName, mInner.mPrefix, mInner.mNamespaceID, + aResult); +} + + +NS_IMETHODIMP +nsNodeInfo::PrefixChanged(nsIAtom *aPrefix, nsINodeInfo*& aResult) +{ + NS_ENSURE_TRUE(mOwnerManager, NS_ERROR_NOT_INITIALIZED); + + return mOwnerManager->GetNodeInfo(mInner.mName, aPrefix, mInner.mNamespaceID, + aResult); +} + + +PLHashNumber +nsNodeInfoInner::GetHashValue(const void *key) +{ +#ifdef NS_DEBUG // Just to shut down a compiler warning + NS_WARN_IF_FALSE(key, "Null key passed to nsNodeInfo::GetHashValue!"); +#endif + + if (key) { + const nsNodeInfoInner *node = (const nsNodeInfoInner *)key; + + // Is this an acceptable has value? + return (((PLHashNumber)node->mName) & 0xffff) >> 8; + } + + return 0; +} + + +PRIntn +nsNodeInfoInner::KeyCompare(const void *key1, const void *key2) +{ +#ifdef NS_DEBUG // Just to shut down a compiler warning + NS_WARN_IF_FALSE(key1 && key2, "Null key passed to nsNodeInfo::KeyCompare!"); +#endif + + if (!key1 || !key2) { + return PR_FALSE; + } + + const nsNodeInfoInner *node1 = (const nsNodeInfoInner *)key1; + const nsNodeInfoInner *node2 = (const nsNodeInfoInner *)key2; + + if (node1->mName == node2->mName && + node1->mPrefix == node2->mPrefix && + node1->mNamespaceID == node2->mNamespaceID) { + + return PR_TRUE; + } + + return PR_FALSE; +} + diff --git a/content/base/src/nsNodeInfo.h b/content/base/src/nsNodeInfo.h new file mode 100644 index 00000000000..c97ba39e1c8 --- /dev/null +++ b/content/base/src/nsNodeInfo.h @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +#ifndef nsNodeInfo_h___ +#define nsNodeInfo_h___ + +#include "nsINodeInfo.h" +#include "nsINameSpaceManager.h" +#include "plhash.h" + +/* + * nsNodeInfoInner is used for two things: + * + * 1. as a member in nsNodeInfo for holding the name, prefix and + * namespace ID + * 2. as the hash key in the hash table in nsNodeInfoManager + * + * nsNodeInfoInner does not do any kind of reference counting, that's up + * to the user of this class, since nsNodeInfoInner is a member of + * nsNodeInfo the hash table doesn't need to delete the keys, when the + * value (nsNodeInfo) the key is automatically deleted. + */ + +struct nsNodeInfoInner +{ + nsNodeInfoInner(nsIAtom *aName, nsIAtom *aPrefix, PRInt32 aNamespaceID) + : mName(aName), mPrefix(aPrefix), mNamespaceID(aNamespaceID) {} + + nsNodeInfoInner() + : mName(nsnull), mPrefix(nsnull), mNamespaceID(kNameSpaceID_None) {} + + static PR_CALLBACK PRIntn KeyCompare(const void *key1, const void *key2); + static PR_CALLBACK PLHashNumber GetHashValue(const void *key); + + nsIAtom* mName; + nsIAtom* mPrefix; + PRInt32 mNamespaceID; +}; + + +class nsNodeInfoManager; + +class nsNodeInfo : public nsINodeInfo +{ +public: + NS_DECL_ISUPPORTS + + // nsINodeInfo + NS_IMETHOD GetName(nsString& aName); + NS_IMETHOD GetNameAtom(nsIAtom*& aAtom); + NS_IMETHOD GetQualifiedName(nsString& aQualifiedName); + NS_IMETHOD GetLocalName(nsString& aLocalName); + NS_IMETHOD GetPrefix(nsString& aPrefix); + NS_IMETHOD GetPrefixAtom(nsIAtom*& aAtom); + NS_IMETHOD GetNamespaceURI(nsString& aNameSpaceURI); + NS_IMETHOD GetNamespaceID(PRInt32& aResult); + NS_IMETHOD GetNodeInfoManager(nsINodeInfoManager*& aNodeInfoManager); + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom); + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom, nsIAtom *aPrefixAtom); + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom, PRInt32 aNamespaceID); + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom, nsIAtom *aPrefixAtom, + PRInt32 aNamespaceID); + NS_IMETHOD_(PRBool) NamespaceEquals(PRInt32 aNamespaceID); + NS_IMETHOD NameChanged(nsIAtom *aName, nsINodeInfo*& aResult); + NS_IMETHOD PrefixChanged(nsIAtom *aPrefix, nsINodeInfo*& aResult); + + // nsNodeInfo + nsNodeInfo(); + virtual ~nsNodeInfo(); + + /* + * Note! Init() must be called exactly once on every nsNodeInfo before + * the object is used, if Init() returns an error code the nsNodeInfo + * should not be used. + * + * aName and aOwnerManager may not be null. + */ + nsresult Init(nsIAtom *aName, nsIAtom *aPrefix, PRInt32 aNamespaceID, + nsNodeInfoManager *aOwnerManager); + +protected: + friend class nsNodeInfoManager; // The NodeInfoManager needs to pass this + // to the hash table. + nsNodeInfoInner mInner; + + nsNodeInfoManager* mOwnerManager; // Strong reference! +}; + +#endif /* nsNodeInfo_h___ */ diff --git a/content/base/src/nsNodeInfoManager.cpp b/content/base/src/nsNodeInfoManager.cpp new file mode 100644 index 00000000000..5df9cfc189f --- /dev/null +++ b/content/base/src/nsNodeInfoManager.cpp @@ -0,0 +1,272 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +#include "nsNodeInfoManager.h" +#include "nsNodeInfo.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsIAtom.h" + +nsNodeInfoManager* nsNodeInfoManager::gAnonymousNodeInfoManager = nsnull; +PRUint32 nsNodeInfoManager::gNodeManagerCount = 0; + + +nsresult NS_NewNodeInfoManager(nsINodeInfoManager** aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + + *aResult = new nsNodeInfoManager; + NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); + + NS_ADDREF(*aResult); + + return NS_OK; +} + + +nsNodeInfoManager::nsNodeInfoManager() + : mNameSpaceManager(nsnull) +{ + NS_INIT_REFCNT(); + + if (gNodeManagerCount == 1 && gAnonymousNodeInfoManager) { + /* + * If we get here the global nodeinfo manager was the first one created, + * in that case we're not holding a strong reference to the global nodeinfo + * manager. Now we're creating one more nodeinfo manager so we'll grab + * a strong reference to the global nodeinfo manager so that it's + * lifetime will be longer than the lifetime of the other node managers. + */ + NS_ADDREF(gAnonymousNodeInfoManager); + } + + gNodeManagerCount++; + + mNodeInfoHash = PL_NewHashTable(32, nsNodeInfoInner::GetHashValue, + nsNodeInfoInner::KeyCompare, + PL_CompareValues, nsnull, nsnull); + +#ifdef DEBUG_jst + printf ("Creating NodeInfoManager, gcount = %d\n", gNodeManagerCount); +#endif +} + + +nsNodeInfoManager::~nsNodeInfoManager() +{ + gNodeManagerCount--; + + if (gNodeManagerCount == 1 && gAnonymousNodeInfoManager) { + NS_RELEASE(gAnonymousNodeInfoManager); + } else if (!gNodeManagerCount) { + /* + * Here we just make sure that we don't leave a dangling pointer to + * the global nodeinfo manager after it's deleted. + */ + gAnonymousNodeInfoManager = nsnull; + } + + if (mNodeInfoHash) + PL_HashTableDestroy(mNodeInfoHash); + +#ifdef DEBUG_jst + printf ("Removing NodeInfoManager, gcount = %d\n", gNodeManagerCount); +#endif +} + + +NS_IMPL_THREADSAFE_ISUPPORTS(nsNodeInfoManager, + NS_GET_IID(nsINodeInfoManager)); + + +// nsINodeInfoManager + +NS_IMETHODIMP +nsNodeInfoManager::Init(nsINameSpaceManager *aNameSpaceManager) +{ + NS_ENSURE_ARG_POINTER(aNameSpaceManager); + NS_ENSURE_TRUE(mNodeInfoHash, NS_ERROR_OUT_OF_MEMORY); + + mNameSpaceManager = aNameSpaceManager; + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfoManager::GetNodeInfo(nsIAtom *aName, nsIAtom *aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo) +{ + NS_ENSURE_ARG_POINTER(aName); + + nsNodeInfoInner tmpKey(aName, aPrefix, aNamespaceID); + + void *node = PL_HashTableLookup(mNodeInfoHash, &tmpKey); + + if (node) { + aNodeInfo = NS_STATIC_CAST(nsINodeInfo *, node); + + NS_ADDREF(aNodeInfo); + + return NS_OK; + } + + nsNodeInfo *newNodeInfo = new nsNodeInfo(); + NS_ENSURE_TRUE(newNodeInfo, NS_ERROR_OUT_OF_MEMORY); + + NS_ADDREF(newNodeInfo); + + nsresult rv = newNodeInfo->Init(aName, aPrefix, aNamespaceID, this); + NS_ENSURE_SUCCESS(rv, rv); + + PLHashEntry *he; + he = PL_HashTableAdd(mNodeInfoHash, &newNodeInfo->mInner, newNodeInfo); + NS_ENSURE_TRUE(he, NS_ERROR_OUT_OF_MEMORY); + + aNodeInfo = newNodeInfo; + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfoManager::GetNodeInfo(const nsString& aName, nsIAtom *aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo) +{ + NS_ENSURE_ARG(aName.Length()); + + nsCOMPtr name(dont_AddRef(NS_NewAtom(aName))); + NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY); + + return GetNodeInfo(name, aPrefix, aNamespaceID, aNodeInfo); +} + + +NS_IMETHODIMP +nsNodeInfoManager::GetNodeInfo(const nsString& aName, const nsString& aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo) +{ + NS_ENSURE_ARG(aName.Length()); + + nsCOMPtr name(dont_AddRef(NS_NewAtom(aName))); + NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY); + + nsCOMPtr prefix; + + if (aPrefix.Length()) { + prefix = dont_AddRef(NS_NewAtom(aPrefix)); + NS_ENSURE_TRUE(prefix, NS_ERROR_OUT_OF_MEMORY); + } + + return GetNodeInfo(name, prefix, aNamespaceID, aNodeInfo); +} + + +NS_IMETHODIMP +nsNodeInfoManager::GetNodeInfo(const nsString& aName, const nsString& aPrefix, + const nsString& aNamespaceURI, + nsINodeInfo*& aNodeInfo) +{ + NS_ENSURE_ARG(aName.Length()); + + nsCOMPtr name(dont_AddRef(NS_NewAtom(aName))); + NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY); + + nsCOMPtr prefix; + + if (aPrefix.Length()) { + prefix = dont_AddRef(NS_NewAtom(aPrefix)); + NS_ENSURE_TRUE(prefix, NS_ERROR_OUT_OF_MEMORY); + } + + PRInt32 nsid = kNameSpaceID_None; + + if (aNamespaceURI.Length()) { + if (!mNameSpaceManager) { + return NS_ERROR_NOT_INITIALIZED; + } + + mNameSpaceManager->GetNameSpaceID(aNamespaceURI, nsid); + } + + return GetNodeInfo(name, prefix, nsid, aNodeInfo); +} + + +NS_IMETHODIMP +nsNodeInfoManager::GetNamespaceManager(nsINameSpaceManager*& aNameSpaceManager) +{ + aNameSpaceManager = mNameSpaceManager; + + NS_IF_ADDREF(aNameSpaceManager); + + return NS_OK; +} + + +void +nsNodeInfoManager::RemoveNodeInfo(nsNodeInfo *aNodeInfo) +{ + NS_WARN_IF_FALSE(aNodeInfo, "Trying to remove null nodeinfo from manager!"); + + if (aNodeInfo) { + PRBool ret = PL_HashTableRemove(mNodeInfoHash, aNodeInfo); + + NS_WARN_IF_FALSE(!ret, "Can't find nsINodeInfo to remove!!!"); + } +} + + +nsresult +nsNodeInfoManager::GetAnonymousManager(nsINodeInfoManager*& aNodeInfoManager) +{ + if (!gAnonymousNodeInfoManager) { + gAnonymousNodeInfoManager = new nsNodeInfoManager; + + if (!gAnonymousNodeInfoManager) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(gAnonymousNodeInfoManager); + + nsresult rv = NS_NewNameSpaceManager(getter_AddRefs(gAnonymousNodeInfoManager->mNameSpaceManager)); + + if (NS_FAILED(rv)) { + NS_RELEASE(gAnonymousNodeInfoManager); + + return rv; + } + } + + aNodeInfoManager = gAnonymousNodeInfoManager; + + /* + * If the only nodeinfo manager is the global one we don't hold a ref + * since the global nodeinfo manager should be destroyed when it's released, + * even if it's the last one arround. + */ + if (gNodeManagerCount > 1) { + NS_ADDREF(aNodeInfoManager); + } + + return NS_OK; +} + diff --git a/content/base/src/nsNodeInfoManager.h b/content/base/src/nsNodeInfoManager.h new file mode 100644 index 00000000000..0738fcef8a0 --- /dev/null +++ b/content/base/src/nsNodeInfoManager.h @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +#ifndef nsNodeInfoManager_h___ +#define nsNodeInfoManager_h___ + +#include "nsINodeInfo.h" +#include "nsINameSpaceManager.h" +#include "nsCOMPtr.h" +#include "plhash.h" + +class nsNodeInfo; + + +class nsNodeInfoManager : public nsINodeInfoManager +{ +public: + NS_DECL_ISUPPORTS + + // nsINodeInfoManager + NS_IMETHOD Init(nsINameSpaceManager *aNameSpaceManager); + NS_IMETHOD GetNodeInfo(nsIAtom *aName, nsIAtom *aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo); + NS_IMETHOD GetNodeInfo(const nsString& aName, nsIAtom *aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo); + NS_IMETHOD GetNodeInfo(const nsString& aName, const nsString& aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo); + NS_IMETHOD GetNodeInfo(const nsString& aName, const nsString& aPrefix, + const nsString& aNamespaceURI, + nsINodeInfo*& aNodeInfo); + NS_IMETHOD GetNamespaceManager(nsINameSpaceManager*& aNameSpaceManager); + + // nsNodeInfoManager + nsNodeInfoManager(); + virtual ~nsNodeInfoManager(); + + void RemoveNodeInfo(nsNodeInfo *aNodeInfo); + + static nsresult GetAnonymousManager(nsINodeInfoManager*& aNodeInfoManager); + +private: + PLHashTable *mNodeInfoHash; + nsCOMPtr mNameSpaceManager; + + /* + * gAnonymousNodeInfoManager is a global nodeinfo manager used for nodes + * that are no longer part of a document and for nodes that are created + * where no document is accessible. + * + * gAnonymousNodeInfoManager is allocated when requested for the first time + * and once the last nodeinfo manager (appart from gAnonymousNodeInfoManager) + * is destroyed gAnonymousNodeInfoManager is destroyed. If the global + * nodeinfo manager is the only nodeinfo manager used it can be deleted + * and later reallocated if all users of the nodeinfo manager drops the + * referernces to it. + */ + static nsNodeInfoManager *gAnonymousNodeInfoManager; + static PRUint32 gNodeManagerCount; +}; + +#endif /* nsNodeInfoManager_h___ */ diff --git a/layout/base/public/nsINodeInfo.h b/layout/base/public/nsINodeInfo.h new file mode 100644 index 00000000000..f3b1b90fca1 --- /dev/null +++ b/layout/base/public/nsINodeInfo.h @@ -0,0 +1,209 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* + * nsINodeInfo is an interface to node info, such as name, prefix, namespace + * ID and possibly other data that is shared shared between nodes (elements + * and attributes) that have the same name, prefix and namespace ID within + * the same document. + * + * nsINodeInfoManager is an interface to an object that manages a list of + * nsINodeInfo's, every document object should hold a strong reference to + * a nsINodeInfoManager and every nsINodeInfo also holds a string reference + * to their owning manager. When a nsINodeInfo is no longer used it will + * automatically remove itself from its owner manager, and when all + * nsINodeInfo's have been removed from a nsINodeInfoManager and all external + * references are released the nsINodeInfoManager deletes itself. + * + * -- jst@netscape.com + */ + +#ifndef nsINodeInfo_h___ +#define nsINodeInfo_h___ + +#include "nsISupports.h" + +// Forward declarations +class nsIAtom; +class nsINodeInfoManager; +class nsINameSpaceManager; +class nsString; + + +// IID for the nsINodeInfo interface +#define NS_INODEINFO_IID \ +{ 0x93dbfd8c, 0x2fb3, 0x4ef5, \ + {0xa2, 0xa0, 0xcf, 0xf2, 0x69, 0x6f, 0x07, 0x88} } + +// IID for the nsINodeInfoManager interface +#define NS_INODEINFOMANAGER_IID \ +{ 0xb622469b, 0x4dcf, 0x45c4, \ + {0xb0, 0xb9, 0xa7, 0x32, 0xbc, 0xee, 0xa5, 0xcc} } + +#define NS_NODEINFOMANAGER_PROGID "component://netscape/layout/nodeinfomanager" + + +class nsINodeInfo : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_INODEINFO_IID) + + /* + * Get the name from this node as a string, this does not include the prefix. + * + * For the HTML element "" this will return "body" and for the XML + * element "" this will return "body". + */ + NS_IMETHOD GetName(nsString& aName) = 0; + + /* + * Get the name from this node as an atom, this does not include the prefix. + * This function never returns a null atom. + * + * For the HTML element "" this will return the "body" atom and for + * the XML element "" this will return the "body" atom. + */ + NS_IMETHOD GetNameAtom(nsIAtom*& aAtom) = 0; + + /* + * Get the qualified name from this node as a string, the qualified name + * includes the prefix, if one exists. + * + * For the HTML element "" this will return "body" and for the XML + * element "" this will return "html:body". + */ + NS_IMETHOD GetQualifiedName(nsString& aQualifiedName) = 0; + + /* + * Get the local name from this node as a string, GetLocalName() gets the + * same string as GetName() but only if the node has a prefix and/or a + * namespace URI. If the node has neither a prefix nor a namespace URI the + * local name is a null string. + * + * For the HTML element "" in a HTML document this will return a null + * string and for the XML element "" this will return "body". + */ + NS_IMETHOD GetLocalName(nsString& aLocalName) = 0; + + /* + * Get the prefix from this node as a string. + * + * For the HTML element "" this will return a null string and for + * the XML element "" this will return the string "html". + */ + NS_IMETHOD GetPrefix(nsString& aPrefix) = 0; + + /* + * Get the prefix from this node as an atom. + * + * For the HTML element "" this will return a null atom and for + * the XML element "" this will return the "html" atom. + */ + NS_IMETHOD GetPrefixAtom(nsIAtom*& aAtom) = 0; + + /* + * Get the namespace URI for a node, if the node has a namespace URI. + * + * For the HTML element "" in a HTML document this will return a null + * string and for the XML element "" (assuming that this element, + * or one of it's ancestors has an + * xmlns:html='http://www.w3.org/TR/REC-html40' attribute) this will return + * the string "http://www.w3.org/TR/REC-html40". + */ + NS_IMETHOD GetNamespaceURI(nsString& aNameSpaceURI) = 0; + + /* + * Get the namespace ID for a node if the node has a namespace, if not this + * returns kNameSpaceID_None. + * + * For the HTML element "" in a HTML document this will return + * kNameSpaceID_None and for the XML element "" (assuming that + * this element, or one of it's ancestors has an + * xmlns:html='http://www.w3.org/TR/REC-html40' attribute) this will return + * the namespace ID for "http://www.w3.org/TR/REC-html40". + */ + NS_IMETHOD GetNamespaceID(PRInt32& aResult) = 0; + + /* + * Get the owning node info manager, this will never return null. + */ + NS_IMETHOD GetNodeInfoManager(nsINodeInfoManager*& aNodeInfoManager) = 0; + + /* + * Utility functions that can be used to check if a nodeinfo holds a spcific + * name, name and prefix, name and prefix and namespace ID, or just + * namespace ID. + */ + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom) = 0; + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom, nsIAtom *aPrefixAtom) = 0; + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom, PRInt32 aNamespaceID) = 0; + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom, nsIAtom *aPrefixAtom, + PRInt32 aNamespaceID) = 0; + NS_IMETHOD_(PRBool) NamespaceEquals(PRInt32 aNamespaceID) = 0; + + /* + * This is a convinience method that creates a new nsINodeInfo that differs + * only by name from the one this is called on. + */ + NS_IMETHOD NameChanged(nsIAtom *aName, nsINodeInfo*& aResult) = 0; + + /* + * This is a convinience method that creates a new nsINodeInfo that differs + * only by prefix from the one this is called on. + */ + NS_IMETHOD PrefixChanged(nsIAtom *aPrefix, nsINodeInfo*& aResult) = 0; +}; + + +class nsINodeInfoManager : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_INODEINFOMANAGER_IID) + + /* + * Initialize the nodeinfo manager with a namespace manager, this should + * allways be done. + */ + NS_IMETHOD Init(nsINameSpaceManager *aNameSpaceManager) = 0; + + /* + * Methods for creating nodeinfo's from atoms and/or strings. + */ + NS_IMETHOD GetNodeInfo(nsIAtom *aName, nsIAtom *aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo) = 0; + NS_IMETHOD GetNodeInfo(const nsString& aName, nsIAtom *aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo) = 0; + NS_IMETHOD GetNodeInfo(const nsString& aName, const nsString& aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo) = 0; + NS_IMETHOD GetNodeInfo(const nsString& aName, const nsString& aPrefix, + const nsString& aNamespaceURI, + nsINodeInfo*& aNodeInfo) = 0; + + /* + * Getter for the namespace manager used by this nodeinfo manager. + */ + NS_IMETHOD GetNamespaceManager(nsINameSpaceManager*& aNameSpaceManager) = 0; +}; + +extern nsresult NS_NewNodeInfoManager(nsINodeInfoManager** aResult); + +#endif /* nsINodeInfo_h___ */ diff --git a/layout/base/src/nsNodeInfo.cpp b/layout/base/src/nsNodeInfo.cpp new file mode 100644 index 00000000000..1fd7e4e955b --- /dev/null +++ b/layout/base/src/nsNodeInfo.cpp @@ -0,0 +1,307 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +#include "nsNodeInfo.h" +#include "nsNodeInfoManager.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsIAtom.h" +#include "nsINameSpaceManager.h" + + +nsNodeInfo::nsNodeInfo() + : mInner(), mOwnerManager(nsnull) +{ + NS_INIT_REFCNT(); +} + + +nsNodeInfo::~nsNodeInfo() +{ + if (mOwnerManager) { + mOwnerManager->RemoveNodeInfo(this); + NS_RELEASE(mOwnerManager); + } + + NS_IF_RELEASE(mInner.mName); + NS_IF_RELEASE(mInner.mPrefix); +} + + +nsresult +nsNodeInfo::Init(nsIAtom *aName, nsIAtom *aPrefix, PRInt32 aNamespaceID, + nsNodeInfoManager *aOwnerManager) +{ + NS_ENSURE_TRUE(!mInner.mName && !mInner.mPrefix && !mOwnerManager, + NS_ERROR_ALREADY_INITIALIZED); + NS_ENSURE_ARG_POINTER(aName); + NS_ENSURE_ARG_POINTER(aOwnerManager); + + mInner.mName = aName; + NS_ADDREF(mInner.mName); + + mInner.mPrefix = aPrefix; + NS_IF_ADDREF(mInner.mPrefix); + + mInner.mNamespaceID = aNamespaceID; + + mOwnerManager = aOwnerManager; + NS_ADDREF(mOwnerManager); + + return NS_OK; +} + + +// nsISupports + +NS_IMPL_THREADSAFE_ISUPPORTS(nsNodeInfo, NS_GET_IID(nsINodeInfo)); + + +// nsINodeInfo + +NS_IMETHODIMP +nsNodeInfo::GetName(nsString& aName) +{ + NS_ENSURE_TRUE(mInner.mName, NS_ERROR_NOT_INITIALIZED); + + return mInner.mName->ToString(aName); +} + + +NS_IMETHODIMP +nsNodeInfo::GetNameAtom(nsIAtom*& aAtom) +{ + NS_ABORT_IF_FALSE(mInner.mName, "nsNodeInfo not initialized!"); + + aAtom = mInner.mName; + NS_IF_ADDREF(aAtom); + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfo::GetQualifiedName(nsString& aQualifiedName) +{ + NS_ENSURE_TRUE(mInner.mName, NS_ERROR_NOT_INITIALIZED); + +#ifdef MOZILLA_IS_READY_FOR_THIS + if (mInner.mPrefix) { + mInner.mPrefix->ToString(aQualifiedName); + + aQualifiedName.Append(':'); + } + + nsAutoString tmp; + mInner.mName->ToString(tmp); + + aQualifiedName.Append(tmp); + +#else + mInner.mName->ToString(aQualifiedName); +#endif + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfo::GetLocalName(nsString& aLocalName) +{ + NS_ENSURE_TRUE(mInner.mName, NS_ERROR_NOT_INITIALIZED); + + if (mInner.mNamespaceID > 0) { + return mInner.mName->ToString(aLocalName); + } + + aLocalName.Truncate(); + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfo::GetPrefix(nsString& aPrefix) +{ + if (mInner.mPrefix) { + mInner.mPrefix->ToString(aPrefix); + } else { + aPrefix.Truncate(); + } + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfo::GetPrefixAtom(nsIAtom*& aAtom) +{ + aAtom = mInner.mPrefix; + NS_IF_ADDREF(aAtom); + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfo::GetNamespaceURI(nsString& aNameSpaceURI) +{ + NS_ENSURE_TRUE(mOwnerManager, NS_ERROR_NOT_INITIALIZED); + nsresult rv = NS_OK; + + if (mInner.mNamespaceID > 0) { + nsCOMPtr nsm; + + mOwnerManager->GetNamespaceManager(*getter_AddRefs(nsm)); + NS_ENSURE_TRUE(nsm, NS_ERROR_NOT_INITIALIZED); + + rv = nsm->GetNameSpaceURI(mInner.mNamespaceID, aNameSpaceURI); + } else { + aNameSpaceURI.Truncate(); + } + + return rv; +} + + +NS_IMETHODIMP +nsNodeInfo::GetNamespaceID(PRInt32& aResult) +{ + aResult = mInner.mNamespaceID; + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfo::GetNodeInfoManager(nsINodeInfoManager*& aNodeInfoManager) +{ + NS_ENSURE_TRUE(mOwnerManager, NS_ERROR_NOT_INITIALIZED); + + aNodeInfoManager = mOwnerManager; + + NS_ADDREF(aNodeInfoManager); + + return NS_OK; +} + + +NS_IMETHODIMP_(PRBool) +nsNodeInfo::Equals(nsIAtom *aNameAtom) +{ + return mInner.mName == aNameAtom; +} + + +NS_IMETHODIMP_(PRBool) +nsNodeInfo::Equals(nsIAtom *aNameAtom, nsIAtom *aPrefixAtom) +{ + return (mInner.mName == aNameAtom) && (mInner.mPrefix == aPrefixAtom); +} + + +NS_IMETHODIMP_(PRBool) +nsNodeInfo::Equals(nsIAtom *aNameAtom, PRInt32 aNamespaceID) +{ + return (mInner.mName == aNameAtom) && (mInner.mNamespaceID == aNamespaceID); +} + + +NS_IMETHODIMP_(PRBool) +nsNodeInfo::Equals(nsIAtom *aNameAtom, nsIAtom *aPrefixAtom, + PRInt32 aNamespaceID) +{ + return (mInner.mName == aNameAtom) && + (mInner.mPrefix == aPrefixAtom) && + (mInner.mNamespaceID == aNamespaceID); +} + + +NS_IMETHODIMP_(PRBool) +nsNodeInfo::NamespaceEquals(PRInt32 aNamespaceID) +{ + return mInner.mNamespaceID == aNamespaceID; +} + + +NS_IMETHODIMP +nsNodeInfo::NameChanged(nsIAtom *aName, nsINodeInfo*& aResult) +{ + NS_ENSURE_TRUE(mOwnerManager, NS_ERROR_NOT_INITIALIZED); + + return mOwnerManager->GetNodeInfo(aName, mInner.mPrefix, mInner.mNamespaceID, + aResult); +} + + +NS_IMETHODIMP +nsNodeInfo::PrefixChanged(nsIAtom *aPrefix, nsINodeInfo*& aResult) +{ + NS_ENSURE_TRUE(mOwnerManager, NS_ERROR_NOT_INITIALIZED); + + return mOwnerManager->GetNodeInfo(mInner.mName, aPrefix, mInner.mNamespaceID, + aResult); +} + + +PLHashNumber +nsNodeInfoInner::GetHashValue(const void *key) +{ +#ifdef NS_DEBUG // Just to shut down a compiler warning + NS_WARN_IF_FALSE(key, "Null key passed to nsNodeInfo::GetHashValue!"); +#endif + + if (key) { + const nsNodeInfoInner *node = (const nsNodeInfoInner *)key; + + // Is this an acceptable has value? + return (((PLHashNumber)node->mName) & 0xffff) >> 8; + } + + return 0; +} + + +PRIntn +nsNodeInfoInner::KeyCompare(const void *key1, const void *key2) +{ +#ifdef NS_DEBUG // Just to shut down a compiler warning + NS_WARN_IF_FALSE(key1 && key2, "Null key passed to nsNodeInfo::KeyCompare!"); +#endif + + if (!key1 || !key2) { + return PR_FALSE; + } + + const nsNodeInfoInner *node1 = (const nsNodeInfoInner *)key1; + const nsNodeInfoInner *node2 = (const nsNodeInfoInner *)key2; + + if (node1->mName == node2->mName && + node1->mPrefix == node2->mPrefix && + node1->mNamespaceID == node2->mNamespaceID) { + + return PR_TRUE; + } + + return PR_FALSE; +} + diff --git a/layout/base/src/nsNodeInfo.h b/layout/base/src/nsNodeInfo.h new file mode 100644 index 00000000000..c97ba39e1c8 --- /dev/null +++ b/layout/base/src/nsNodeInfo.h @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +#ifndef nsNodeInfo_h___ +#define nsNodeInfo_h___ + +#include "nsINodeInfo.h" +#include "nsINameSpaceManager.h" +#include "plhash.h" + +/* + * nsNodeInfoInner is used for two things: + * + * 1. as a member in nsNodeInfo for holding the name, prefix and + * namespace ID + * 2. as the hash key in the hash table in nsNodeInfoManager + * + * nsNodeInfoInner does not do any kind of reference counting, that's up + * to the user of this class, since nsNodeInfoInner is a member of + * nsNodeInfo the hash table doesn't need to delete the keys, when the + * value (nsNodeInfo) the key is automatically deleted. + */ + +struct nsNodeInfoInner +{ + nsNodeInfoInner(nsIAtom *aName, nsIAtom *aPrefix, PRInt32 aNamespaceID) + : mName(aName), mPrefix(aPrefix), mNamespaceID(aNamespaceID) {} + + nsNodeInfoInner() + : mName(nsnull), mPrefix(nsnull), mNamespaceID(kNameSpaceID_None) {} + + static PR_CALLBACK PRIntn KeyCompare(const void *key1, const void *key2); + static PR_CALLBACK PLHashNumber GetHashValue(const void *key); + + nsIAtom* mName; + nsIAtom* mPrefix; + PRInt32 mNamespaceID; +}; + + +class nsNodeInfoManager; + +class nsNodeInfo : public nsINodeInfo +{ +public: + NS_DECL_ISUPPORTS + + // nsINodeInfo + NS_IMETHOD GetName(nsString& aName); + NS_IMETHOD GetNameAtom(nsIAtom*& aAtom); + NS_IMETHOD GetQualifiedName(nsString& aQualifiedName); + NS_IMETHOD GetLocalName(nsString& aLocalName); + NS_IMETHOD GetPrefix(nsString& aPrefix); + NS_IMETHOD GetPrefixAtom(nsIAtom*& aAtom); + NS_IMETHOD GetNamespaceURI(nsString& aNameSpaceURI); + NS_IMETHOD GetNamespaceID(PRInt32& aResult); + NS_IMETHOD GetNodeInfoManager(nsINodeInfoManager*& aNodeInfoManager); + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom); + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom, nsIAtom *aPrefixAtom); + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom, PRInt32 aNamespaceID); + NS_IMETHOD_(PRBool) Equals(nsIAtom *aNameAtom, nsIAtom *aPrefixAtom, + PRInt32 aNamespaceID); + NS_IMETHOD_(PRBool) NamespaceEquals(PRInt32 aNamespaceID); + NS_IMETHOD NameChanged(nsIAtom *aName, nsINodeInfo*& aResult); + NS_IMETHOD PrefixChanged(nsIAtom *aPrefix, nsINodeInfo*& aResult); + + // nsNodeInfo + nsNodeInfo(); + virtual ~nsNodeInfo(); + + /* + * Note! Init() must be called exactly once on every nsNodeInfo before + * the object is used, if Init() returns an error code the nsNodeInfo + * should not be used. + * + * aName and aOwnerManager may not be null. + */ + nsresult Init(nsIAtom *aName, nsIAtom *aPrefix, PRInt32 aNamespaceID, + nsNodeInfoManager *aOwnerManager); + +protected: + friend class nsNodeInfoManager; // The NodeInfoManager needs to pass this + // to the hash table. + nsNodeInfoInner mInner; + + nsNodeInfoManager* mOwnerManager; // Strong reference! +}; + +#endif /* nsNodeInfo_h___ */ diff --git a/layout/base/src/nsNodeInfoManager.cpp b/layout/base/src/nsNodeInfoManager.cpp new file mode 100644 index 00000000000..5df9cfc189f --- /dev/null +++ b/layout/base/src/nsNodeInfoManager.cpp @@ -0,0 +1,272 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +#include "nsNodeInfoManager.h" +#include "nsNodeInfo.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsIAtom.h" + +nsNodeInfoManager* nsNodeInfoManager::gAnonymousNodeInfoManager = nsnull; +PRUint32 nsNodeInfoManager::gNodeManagerCount = 0; + + +nsresult NS_NewNodeInfoManager(nsINodeInfoManager** aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + + *aResult = new nsNodeInfoManager; + NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); + + NS_ADDREF(*aResult); + + return NS_OK; +} + + +nsNodeInfoManager::nsNodeInfoManager() + : mNameSpaceManager(nsnull) +{ + NS_INIT_REFCNT(); + + if (gNodeManagerCount == 1 && gAnonymousNodeInfoManager) { + /* + * If we get here the global nodeinfo manager was the first one created, + * in that case we're not holding a strong reference to the global nodeinfo + * manager. Now we're creating one more nodeinfo manager so we'll grab + * a strong reference to the global nodeinfo manager so that it's + * lifetime will be longer than the lifetime of the other node managers. + */ + NS_ADDREF(gAnonymousNodeInfoManager); + } + + gNodeManagerCount++; + + mNodeInfoHash = PL_NewHashTable(32, nsNodeInfoInner::GetHashValue, + nsNodeInfoInner::KeyCompare, + PL_CompareValues, nsnull, nsnull); + +#ifdef DEBUG_jst + printf ("Creating NodeInfoManager, gcount = %d\n", gNodeManagerCount); +#endif +} + + +nsNodeInfoManager::~nsNodeInfoManager() +{ + gNodeManagerCount--; + + if (gNodeManagerCount == 1 && gAnonymousNodeInfoManager) { + NS_RELEASE(gAnonymousNodeInfoManager); + } else if (!gNodeManagerCount) { + /* + * Here we just make sure that we don't leave a dangling pointer to + * the global nodeinfo manager after it's deleted. + */ + gAnonymousNodeInfoManager = nsnull; + } + + if (mNodeInfoHash) + PL_HashTableDestroy(mNodeInfoHash); + +#ifdef DEBUG_jst + printf ("Removing NodeInfoManager, gcount = %d\n", gNodeManagerCount); +#endif +} + + +NS_IMPL_THREADSAFE_ISUPPORTS(nsNodeInfoManager, + NS_GET_IID(nsINodeInfoManager)); + + +// nsINodeInfoManager + +NS_IMETHODIMP +nsNodeInfoManager::Init(nsINameSpaceManager *aNameSpaceManager) +{ + NS_ENSURE_ARG_POINTER(aNameSpaceManager); + NS_ENSURE_TRUE(mNodeInfoHash, NS_ERROR_OUT_OF_MEMORY); + + mNameSpaceManager = aNameSpaceManager; + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfoManager::GetNodeInfo(nsIAtom *aName, nsIAtom *aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo) +{ + NS_ENSURE_ARG_POINTER(aName); + + nsNodeInfoInner tmpKey(aName, aPrefix, aNamespaceID); + + void *node = PL_HashTableLookup(mNodeInfoHash, &tmpKey); + + if (node) { + aNodeInfo = NS_STATIC_CAST(nsINodeInfo *, node); + + NS_ADDREF(aNodeInfo); + + return NS_OK; + } + + nsNodeInfo *newNodeInfo = new nsNodeInfo(); + NS_ENSURE_TRUE(newNodeInfo, NS_ERROR_OUT_OF_MEMORY); + + NS_ADDREF(newNodeInfo); + + nsresult rv = newNodeInfo->Init(aName, aPrefix, aNamespaceID, this); + NS_ENSURE_SUCCESS(rv, rv); + + PLHashEntry *he; + he = PL_HashTableAdd(mNodeInfoHash, &newNodeInfo->mInner, newNodeInfo); + NS_ENSURE_TRUE(he, NS_ERROR_OUT_OF_MEMORY); + + aNodeInfo = newNodeInfo; + + return NS_OK; +} + + +NS_IMETHODIMP +nsNodeInfoManager::GetNodeInfo(const nsString& aName, nsIAtom *aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo) +{ + NS_ENSURE_ARG(aName.Length()); + + nsCOMPtr name(dont_AddRef(NS_NewAtom(aName))); + NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY); + + return GetNodeInfo(name, aPrefix, aNamespaceID, aNodeInfo); +} + + +NS_IMETHODIMP +nsNodeInfoManager::GetNodeInfo(const nsString& aName, const nsString& aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo) +{ + NS_ENSURE_ARG(aName.Length()); + + nsCOMPtr name(dont_AddRef(NS_NewAtom(aName))); + NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY); + + nsCOMPtr prefix; + + if (aPrefix.Length()) { + prefix = dont_AddRef(NS_NewAtom(aPrefix)); + NS_ENSURE_TRUE(prefix, NS_ERROR_OUT_OF_MEMORY); + } + + return GetNodeInfo(name, prefix, aNamespaceID, aNodeInfo); +} + + +NS_IMETHODIMP +nsNodeInfoManager::GetNodeInfo(const nsString& aName, const nsString& aPrefix, + const nsString& aNamespaceURI, + nsINodeInfo*& aNodeInfo) +{ + NS_ENSURE_ARG(aName.Length()); + + nsCOMPtr name(dont_AddRef(NS_NewAtom(aName))); + NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY); + + nsCOMPtr prefix; + + if (aPrefix.Length()) { + prefix = dont_AddRef(NS_NewAtom(aPrefix)); + NS_ENSURE_TRUE(prefix, NS_ERROR_OUT_OF_MEMORY); + } + + PRInt32 nsid = kNameSpaceID_None; + + if (aNamespaceURI.Length()) { + if (!mNameSpaceManager) { + return NS_ERROR_NOT_INITIALIZED; + } + + mNameSpaceManager->GetNameSpaceID(aNamespaceURI, nsid); + } + + return GetNodeInfo(name, prefix, nsid, aNodeInfo); +} + + +NS_IMETHODIMP +nsNodeInfoManager::GetNamespaceManager(nsINameSpaceManager*& aNameSpaceManager) +{ + aNameSpaceManager = mNameSpaceManager; + + NS_IF_ADDREF(aNameSpaceManager); + + return NS_OK; +} + + +void +nsNodeInfoManager::RemoveNodeInfo(nsNodeInfo *aNodeInfo) +{ + NS_WARN_IF_FALSE(aNodeInfo, "Trying to remove null nodeinfo from manager!"); + + if (aNodeInfo) { + PRBool ret = PL_HashTableRemove(mNodeInfoHash, aNodeInfo); + + NS_WARN_IF_FALSE(!ret, "Can't find nsINodeInfo to remove!!!"); + } +} + + +nsresult +nsNodeInfoManager::GetAnonymousManager(nsINodeInfoManager*& aNodeInfoManager) +{ + if (!gAnonymousNodeInfoManager) { + gAnonymousNodeInfoManager = new nsNodeInfoManager; + + if (!gAnonymousNodeInfoManager) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(gAnonymousNodeInfoManager); + + nsresult rv = NS_NewNameSpaceManager(getter_AddRefs(gAnonymousNodeInfoManager->mNameSpaceManager)); + + if (NS_FAILED(rv)) { + NS_RELEASE(gAnonymousNodeInfoManager); + + return rv; + } + } + + aNodeInfoManager = gAnonymousNodeInfoManager; + + /* + * If the only nodeinfo manager is the global one we don't hold a ref + * since the global nodeinfo manager should be destroyed when it's released, + * even if it's the last one arround. + */ + if (gNodeManagerCount > 1) { + NS_ADDREF(aNodeInfoManager); + } + + return NS_OK; +} + diff --git a/layout/base/src/nsNodeInfoManager.h b/layout/base/src/nsNodeInfoManager.h new file mode 100644 index 00000000000..0738fcef8a0 --- /dev/null +++ b/layout/base/src/nsNodeInfoManager.h @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +#ifndef nsNodeInfoManager_h___ +#define nsNodeInfoManager_h___ + +#include "nsINodeInfo.h" +#include "nsINameSpaceManager.h" +#include "nsCOMPtr.h" +#include "plhash.h" + +class nsNodeInfo; + + +class nsNodeInfoManager : public nsINodeInfoManager +{ +public: + NS_DECL_ISUPPORTS + + // nsINodeInfoManager + NS_IMETHOD Init(nsINameSpaceManager *aNameSpaceManager); + NS_IMETHOD GetNodeInfo(nsIAtom *aName, nsIAtom *aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo); + NS_IMETHOD GetNodeInfo(const nsString& aName, nsIAtom *aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo); + NS_IMETHOD GetNodeInfo(const nsString& aName, const nsString& aPrefix, + PRInt32 aNamespaceID, nsINodeInfo*& aNodeInfo); + NS_IMETHOD GetNodeInfo(const nsString& aName, const nsString& aPrefix, + const nsString& aNamespaceURI, + nsINodeInfo*& aNodeInfo); + NS_IMETHOD GetNamespaceManager(nsINameSpaceManager*& aNameSpaceManager); + + // nsNodeInfoManager + nsNodeInfoManager(); + virtual ~nsNodeInfoManager(); + + void RemoveNodeInfo(nsNodeInfo *aNodeInfo); + + static nsresult GetAnonymousManager(nsINodeInfoManager*& aNodeInfoManager); + +private: + PLHashTable *mNodeInfoHash; + nsCOMPtr mNameSpaceManager; + + /* + * gAnonymousNodeInfoManager is a global nodeinfo manager used for nodes + * that are no longer part of a document and for nodes that are created + * where no document is accessible. + * + * gAnonymousNodeInfoManager is allocated when requested for the first time + * and once the last nodeinfo manager (appart from gAnonymousNodeInfoManager) + * is destroyed gAnonymousNodeInfoManager is destroyed. If the global + * nodeinfo manager is the only nodeinfo manager used it can be deleted + * and later reallocated if all users of the nodeinfo manager drops the + * referernces to it. + */ + static nsNodeInfoManager *gAnonymousNodeInfoManager; + static PRUint32 gNodeManagerCount; +}; + +#endif /* nsNodeInfoManager_h___ */