diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 3c0690ff418b..d32ea43ccda9 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -53,6 +53,8 @@ #include "nsIDOMText.h" #include "nsDocumentFragment.h" +#include "nsINameSpaceManager.h" + #include "nsLayoutCID.h" #include "nsIDOMRange.h" #include "nsICollection.h" @@ -413,6 +415,7 @@ nsDocument::nsDocument() printf("*************** Error: nsDocument::nsDocument - Creation of Selection failed!\n"); } mDOMStyleSheets = nsnull; + mNameSpaceManager = nsnull; Init();/* XXX */ } @@ -462,6 +465,7 @@ nsDocument::~nsDocument() NS_IF_RELEASE(mScriptContextOwner); NS_IF_RELEASE(mListenerManager); NS_IF_RELEASE(mDOMStyleSheets); + NS_IF_RELEASE(mNameSpaceManager); } nsresult nsDocument::QueryInterface(REFNSIID aIID, void** aInstancePtr) @@ -531,7 +535,9 @@ nsresult nsDocument::Init() if (NS_OK != rv) { return rv; } - return NS_OK; + + rv = NS_NewNameSpaceManager(&mNameSpaceManager); + return rv; } nsIArena* nsDocument::GetArena() @@ -812,6 +818,15 @@ void nsDocument::SetScriptContextOwner(nsIScriptContextOwner *aScriptContextOwne } } +NS_IMETHODIMP +nsDocument::GetNameSpaceManager(nsINameSpaceManager*& aManager) +{ + aManager = mNameSpaceManager; + NS_IF_ADDREF(aManager); + return NS_OK; +} + + // Note: We don't hold a reference to the document observer; we assume // that it has a live reference to the document. void nsDocument::AddObserver(nsIDocumentObserver* aObserver) diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index 3c347272be75..d94feb53bb86 100644 --- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -140,6 +140,11 @@ public: virtual nsIScriptContextOwner *GetScriptContextOwner(); virtual void SetScriptContextOwner(nsIScriptContextOwner *aScriptContextOwner); + /** + * Get the name space manager for this document + */ + NS_IMETHOD GetNameSpaceManager(nsINameSpaceManager*& aManager); + /** * Add a new observer of document change notifications. Whenever * content is changed, appended, inserted or removed the observers are @@ -315,6 +320,7 @@ protected: PRBool mDisplaySelection; PRBool mInDestructor; nsDOMStyleSheetCollection *mDOMStyleSheets; + nsINameSpaceManager* mNameSpaceManager; }; #endif /* nsDocument_h___ */ diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index 42473a9be46f..70b47b47fff1 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -49,6 +49,7 @@ #include "nsIDOMScriptObjectFactory.h" #include "nsIDOMCSSStyleDeclaration.h" #include "nsDOMCSSDeclaration.h" +#include "nsINameSpaceManager.h" #include "prprf.h" #include "prmem.h" @@ -934,6 +935,13 @@ nsGenericElement::SetParent(nsIContent* aParent) return NS_OK; } +nsresult +nsGenericElement::GetNameSpaceID(PRInt32& aResult) const +{ + aResult = kNameSpaceID_None; + return NS_OK; +} + nsresult nsGenericElement::GetTag(nsIAtom*& aResult) const { diff --git a/content/base/src/nsGenericElement.h b/content/base/src/nsGenericElement.h index 992f5a2a5d04..bed6e303553c 100644 --- a/content/base/src/nsGenericElement.h +++ b/content/base/src/nsGenericElement.h @@ -208,6 +208,7 @@ public: aResult = PR_FALSE; return NS_OK; } + nsresult GetNameSpaceID(PRInt32& aNameSpaceID) const; nsresult GetTag(nsIAtom*& aResult) const; nsresult HandleDOMEvent(nsIPresContext& aPresContext, nsEvent* aEvent, @@ -484,6 +485,9 @@ public: NS_IMETHOD IsSynthetic(PRBool& aResult) { \ return _g.IsSynthetic(aResult); \ } \ + NS_IMETHOD GetNameSpaceID(PRInt32& aResult) const { \ + return _g.GetNameSpaceID(aResult); \ + } \ NS_IMETHOD GetTag(nsIAtom*& aResult) const { \ return _g.GetTag(aResult); \ } \ diff --git a/content/base/src/nsNameSpaceManager.cpp b/content/base/src/nsNameSpaceManager.cpp new file mode 100644 index 000000000000..ed681e503e1a --- /dev/null +++ b/content/base/src/nsNameSpaceManager.cpp @@ -0,0 +1,418 @@ +/* -*- 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.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsINameSpaceManager.h" +#include "nsINameSpace.h" +#include "nsHashtable.h" +#include "nsVoidArray.h" +#include "nsLayoutAtoms.h" +#include "nsString.h" +#include "nsCRT.h" + +static NS_DEFINE_IID(kINameSpaceManagerIID, NS_INAMESPACEMANAGER_IID); +static NS_DEFINE_IID(kINameSpaceIID, NS_INAMESPACE_IID); + + +static const char kHTMLNameSpaceURI[] = "http://www.w3.org/TR/REC-html40"; // XXX?? "urn:w3-org-ns:HTML"?? +static const char kXMLNameSpaceURI[] = "urn:Connolly:input:required"; // XXX ?? what is it really? + +//----------------------------------------------------------- +// Name Space + +class NameSpaceImpl : public nsINameSpace { +public: + NameSpaceImpl(nsINameSpaceManager* aManager, + NameSpaceImpl* aParent, + nsIAtom* aPrefix, + const nsString& aURI); + NameSpaceImpl(nsINameSpaceManager* aManager, + NameSpaceImpl* aParent, + nsIAtom* aPrefix, + PRInt32 aNameSpaceID); + virtual ~NameSpaceImpl(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD GetNameSpaceManager(nsINameSpaceManager*& aManager) const; + + NS_IMETHOD GetNameSpaceID(PRInt32& aID) const; + NS_IMETHOD GetNameSpaceURI(nsString& aURI) const; + NS_IMETHOD GetNameSpacePrefix(nsIAtom*& aPrefix) const; + + NS_IMETHOD GetParentNameSpace(nsINameSpace*& aParent) const; + + NS_IMETHOD FindNameSpace(nsIAtom* aPrefix, nsINameSpace*& aNameSpace) const; + NS_IMETHOD FindNameSpaceID(nsIAtom* aPrefix, PRInt32& aNameSpaceID) const; + NS_IMETHOD FindNameSpacePrefix(PRInt32 aNameSpaceID, nsIAtom*& aPrefix) const; + + NS_IMETHOD CreateChildNameSpace(nsIAtom* aPrefix, const nsString& aURI, + nsINameSpace*& aChildNameSpace); + +private: + // These are not supported and are not implemented! + NameSpaceImpl(const NameSpaceImpl& aCopy); + NameSpaceImpl& operator=(const NameSpaceImpl& aCopy); + +public: + nsINameSpaceManager* mManager; + NameSpaceImpl* mParent; + nsIAtom* mPrefix; + PRInt32 mID; +}; + + +NameSpaceImpl::NameSpaceImpl(nsINameSpaceManager* aManager, + NameSpaceImpl* aParent, + nsIAtom* aPrefix, + const nsString& aURI) + : mManager(aManager), + mParent(aParent), + mPrefix(aPrefix) +{ + NS_ASSERTION(nsnull != aManager, "null namespace manager"); + NS_INIT_REFCNT(); + NS_ADDREF(mManager); + NS_IF_ADDREF(mParent); + NS_IF_ADDREF(mPrefix); + mManager->RegisterNameSpace(aURI, mID); +} + +NameSpaceImpl::NameSpaceImpl(nsINameSpaceManager* aManager, + NameSpaceImpl* aParent, + nsIAtom* aPrefix, + PRInt32 aNameSpaceID) + : mManager(aManager), + mParent(aParent), + mPrefix(aPrefix), + mID(aNameSpaceID) +{ + NS_ASSERTION(nsnull != aManager, "null namespace manager"); + NS_INIT_REFCNT(); + NS_ADDREF(mManager); + NS_IF_ADDREF(mParent); + NS_IF_ADDREF(mPrefix); +} + +NameSpaceImpl::~NameSpaceImpl() +{ + NS_RELEASE(mManager); + NS_IF_RELEASE(mParent); + NS_IF_RELEASE(mPrefix); +} + +NS_IMPL_ISUPPORTS(NameSpaceImpl, kINameSpaceIID) + +NS_IMETHODIMP +NameSpaceImpl::GetNameSpaceManager(nsINameSpaceManager*& aManager) const +{ + NS_ASSERTION(nsnull != aManager, "null namespace manager"); + aManager = mManager; + NS_ADDREF(aManager); + return NS_OK; +} + +NS_IMETHODIMP +NameSpaceImpl::GetNameSpaceID(PRInt32& aID) const +{ + aID = mID; + return NS_OK; +} + +NS_IMETHODIMP +NameSpaceImpl::GetNameSpaceURI(nsString& aURI) const +{ + NS_ASSERTION(nsnull != mManager, "null namespace manager"); + return mManager->GetNameSpaceURI(mID, aURI); +} + +NS_IMETHODIMP +NameSpaceImpl::GetNameSpacePrefix(nsIAtom*& aPrefix) const +{ + aPrefix = mPrefix; + NS_IF_ADDREF(aPrefix); + return NS_OK; +} + +NS_IMETHODIMP +NameSpaceImpl::GetParentNameSpace(nsINameSpace*& aParent) const +{ + aParent = mParent; + NS_IF_ADDREF(aParent); + return NS_OK; +} + +NS_IMETHODIMP +NameSpaceImpl::FindNameSpace(nsIAtom* aPrefix, nsINameSpace*& aNameSpace) const +{ + const NameSpaceImpl* nameSpace = this; + do { + if (aPrefix == nameSpace->mPrefix) { + aNameSpace = (nsINameSpace*)nameSpace; + NS_ADDREF(aNameSpace); + return NS_OK; + } + nameSpace = nameSpace->mParent; + } + while (nsnull != nameSpace); + aNameSpace = nsnull; + return NS_ERROR_ILLEGAL_VALUE; +} + +NS_IMETHODIMP +NameSpaceImpl::FindNameSpaceID(nsIAtom* aPrefix, PRInt32& aNameSpaceID) const +{ + const NameSpaceImpl* nameSpace = this; + do { + if (aPrefix == nameSpace->mPrefix) { + aNameSpaceID = nameSpace->mID; + return NS_OK; + } + nameSpace = nameSpace->mParent; + } + while (nsnull != nameSpace); + aNameSpaceID = kNameSpaceID_Unknown; + return NS_ERROR_ILLEGAL_VALUE; +} + +NS_IMETHODIMP +NameSpaceImpl::FindNameSpacePrefix(PRInt32 aNameSpaceID, nsIAtom*& aPrefix) const +{ + const NameSpaceImpl* nameSpace = this; + do { + if (aNameSpaceID == nameSpace->mID) { + aPrefix = nameSpace->mPrefix; + NS_IF_ADDREF(aPrefix); + return NS_OK; + } + nameSpace = nameSpace->mParent; + } + while (nsnull != nameSpace); + aPrefix = nsnull; + return NS_ERROR_ILLEGAL_VALUE; +} + +NS_IMETHODIMP +NameSpaceImpl::CreateChildNameSpace(nsIAtom* aPrefix, const nsString& aURI, + nsINameSpace*& aChildNameSpace) +{ + NameSpaceImpl* child = new NameSpaceImpl(mManager, this, aPrefix, aURI); + + return child->QueryInterface(kINameSpaceIID, (void**)&aChildNameSpace); +} + +//----------------------------------------------------------- +// Name Space Manager + +static PRInt32 gNameSpaceTableRefs; +static nsHashtable* gURIToIDTable; +static nsVoidArray* gURIArray; + +class StringKey : public nsHashKey { +public: + StringKey(const nsString* aString) + : mString(aString) + { } + + virtual ~StringKey(void) + { } + + virtual PRUint32 HashValue(void) const + { + if (nsnull != mString) { + return nsCRT::HashValue(mString->GetUnicode()); + } + return 0; + } + + virtual PRBool Equals(const nsHashKey *aKey) const + { + const nsString* other = ((const StringKey*)aKey)->mString; + if (nsnull != mString) { + if (nsnull != other) { + return mString->Equals(*other); + } + return PR_FALSE; + } + return PRBool(nsnull == other); + } + + virtual nsHashKey *Clone(void) const + { + return new StringKey(mString); + } + + const nsString* mString; +}; + +static void AddRefTable() +{ + if (0 == gNameSpaceTableRefs++) { + NS_ASSERTION(nsnull == gURIToIDTable, "already have URI table"); + NS_ASSERTION(nsnull == gURIArray, "already have URI array"); + + gURIToIDTable = new nsHashtable(); + gURIArray = new nsVoidArray(); + + nsString* html = new nsString(kHTMLNameSpaceURI); + nsString* xml = new nsString(kXMLNameSpaceURI); + gURIArray->AppendElement(html); + gURIArray->AppendElement(xml); + gURIToIDTable->Put(&StringKey(html), (void*)kNameSpaceID_HTML); + gURIToIDTable->Put(&StringKey(xml), (void*)kNameSpaceID_XML); + } + NS_ASSERTION(nsnull != gURIToIDTable, "no URI table"); + NS_ASSERTION(nsnull != gURIArray, "no URI array"); +} + +static void ReleaseTable() +{ + if (0 == --gNameSpaceTableRefs) { + delete gURIToIDTable; + PRInt32 index = gURIArray->Count(); + while (0 < index--) { + nsString* str = (nsString*)gURIArray->ElementAt(index); + delete str; + } + delete gURIArray; + gURIToIDTable = nsnull; + gURIArray = nsnull; + } +} + +static PRInt32 FindNameSpaceID(const nsString& aURI) +{ + NS_ASSERTION(nsnull != gURIToIDTable, "no URI table"); + void* value = gURIToIDTable->Get(&StringKey(&aURI)); + if (nsnull != value) { + return PRInt32(value); + } + return kNameSpaceID_Unknown; +} + +static const nsString* FindNameSpaceURI(PRInt32 aID) +{ + NS_ASSERTION(nsnull != gURIArray, "no URI array"); + return (const nsString*)gURIArray->ElementAt(aID - 1); +} + +class NameSpaceManagerImpl : public nsINameSpaceManager { +public: + NameSpaceManagerImpl(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD CreateRootNameSpace(nsINameSpace*& aRootNameSpace); + + NS_IMETHOD RegisterNameSpace(const nsString& aURI, + PRInt32& aNameSpaceID); + + NS_IMETHOD GetNameSpaceURI(PRInt32 aNameSpaceID, nsString& aURI); + NS_IMETHOD GetNameSpaceID(const nsString& aURI, PRInt32& aNameSpaceID); + +private: + // These are not supported and are not implemented! + NameSpaceManagerImpl(const NameSpaceManagerImpl& aCopy); + NameSpaceManagerImpl& operator=(const NameSpaceManagerImpl& aCopy); + +protected: + virtual ~NameSpaceManagerImpl(); + +}; + + +NameSpaceManagerImpl::NameSpaceManagerImpl() +{ + NS_INIT_REFCNT(); + AddRefTable(); +} + +NameSpaceManagerImpl::~NameSpaceManagerImpl() +{ + ReleaseTable(); +} + +NS_IMPL_ISUPPORTS(NameSpaceManagerImpl, kINameSpaceManagerIID) + +NS_IMETHODIMP +NameSpaceManagerImpl::CreateRootNameSpace(nsINameSpace*& aRootNameSpace) +{ + nsresult rv = NS_ERROR_OUT_OF_MEMORY; + aRootNameSpace = nsnull; + + NameSpaceImpl* html = new NameSpaceImpl(this, nsnull, nsLayoutAtoms::htmlNameSpace, kNameSpaceID_HTML); + if (nsnull != html) { + NameSpaceImpl* xml = new NameSpaceImpl(this, html, nsLayoutAtoms::xmlNameSpace, kNameSpaceID_XML); + if (nsnull != xml) { + rv = xml->QueryInterface(kINameSpaceIID, (void**)&aRootNameSpace); + } + else { + delete html; + } + } + return rv; +} + +NS_IMETHODIMP +NameSpaceManagerImpl::RegisterNameSpace(const nsString& aURI, + PRInt32& aNameSpaceID) +{ + PRInt32 id = FindNameSpaceID(aURI); + + if (kNameSpaceID_Unknown == id) { + nsString* uri = new nsString(aURI); + gURIArray->AppendElement(uri); + id = gURIArray->Count(); // id is index + 1 + gURIToIDTable->Put(&StringKey(uri), (void*)id); + } + aNameSpaceID = id; + return NS_OK; +} + +NS_IMETHODIMP +NameSpaceManagerImpl::GetNameSpaceURI(PRInt32 aNameSpaceID, nsString& aURI) +{ + const nsString* result = FindNameSpaceURI(aNameSpaceID); + if (nsnull != result) { + aURI = *result; + return NS_OK; + } + aURI.Truncate(); + return NS_ERROR_ILLEGAL_VALUE; +} + +NS_IMETHODIMP +NameSpaceManagerImpl::GetNameSpaceID(const nsString& aURI, PRInt32& aNameSpaceID) +{ + aNameSpaceID = FindNameSpaceID(aURI); + return NS_OK; +} + +NS_LAYOUT nsresult +NS_NewNameSpaceManager(nsINameSpaceManager** aInstancePtrResult) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + NameSpaceManagerImpl *it = new NameSpaceManagerImpl(); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kINameSpaceManagerIID, (void **) aInstancePtrResult); +} diff --git a/layout/base/src/Makefile.in b/layout/base/src/Makefile.in index d9a304acad6e..66a20e0f1a8b 100644 --- a/layout/base/src/Makefile.in +++ b/layout/base/src/Makefile.in @@ -35,6 +35,7 @@ CPPSRCS = \ nsFrameImageLoader.cpp \ nsFrameUtil.cpp \ nsGalleyContext.cpp \ + nsNameSpaceManager.cpp \ nsPresContext.cpp \ nsPrintContext.cpp \ nsPrintPreviewContext.cpp \ diff --git a/layout/base/src/makefile.win b/layout/base/src/makefile.win index 7de695efba24..751b45769d81 100644 --- a/layout/base/src/makefile.win +++ b/layout/base/src/makefile.win @@ -31,6 +31,7 @@ CPPSRCS = \ nsFrameImageLoader.cpp \ nsFrameUtil.cpp \ nsGalleyContext.cpp \ + nsNameSpaceManager.cpp \ nsPresContext.cpp \ nsPrintContext.cpp \ nsPrintPreviewContext.cpp \ @@ -57,6 +58,7 @@ CPP_OBJS= \ .\$(OBJDIR)\nsFrameImageLoader.obj \ .\$(OBJDIR)\nsFrameUtil.obj \ .\$(OBJDIR)\nsGalleyContext.obj \ + .\$(OBJDIR)\nsNameSpaceManager.obj \ .\$(OBJDIR)\nsPresContext.obj \ .\$(OBJDIR)\nsPrintContext.obj \ .\$(OBJDIR)\nsPrintPreviewContext.obj \ diff --git a/layout/base/src/nsDocument.cpp b/layout/base/src/nsDocument.cpp index 3c0690ff418b..d32ea43ccda9 100644 --- a/layout/base/src/nsDocument.cpp +++ b/layout/base/src/nsDocument.cpp @@ -53,6 +53,8 @@ #include "nsIDOMText.h" #include "nsDocumentFragment.h" +#include "nsINameSpaceManager.h" + #include "nsLayoutCID.h" #include "nsIDOMRange.h" #include "nsICollection.h" @@ -413,6 +415,7 @@ nsDocument::nsDocument() printf("*************** Error: nsDocument::nsDocument - Creation of Selection failed!\n"); } mDOMStyleSheets = nsnull; + mNameSpaceManager = nsnull; Init();/* XXX */ } @@ -462,6 +465,7 @@ nsDocument::~nsDocument() NS_IF_RELEASE(mScriptContextOwner); NS_IF_RELEASE(mListenerManager); NS_IF_RELEASE(mDOMStyleSheets); + NS_IF_RELEASE(mNameSpaceManager); } nsresult nsDocument::QueryInterface(REFNSIID aIID, void** aInstancePtr) @@ -531,7 +535,9 @@ nsresult nsDocument::Init() if (NS_OK != rv) { return rv; } - return NS_OK; + + rv = NS_NewNameSpaceManager(&mNameSpaceManager); + return rv; } nsIArena* nsDocument::GetArena() @@ -812,6 +818,15 @@ void nsDocument::SetScriptContextOwner(nsIScriptContextOwner *aScriptContextOwne } } +NS_IMETHODIMP +nsDocument::GetNameSpaceManager(nsINameSpaceManager*& aManager) +{ + aManager = mNameSpaceManager; + NS_IF_ADDREF(aManager); + return NS_OK; +} + + // Note: We don't hold a reference to the document observer; we assume // that it has a live reference to the document. void nsDocument::AddObserver(nsIDocumentObserver* aObserver) diff --git a/layout/base/src/nsDocument.h b/layout/base/src/nsDocument.h index 3c347272be75..d94feb53bb86 100644 --- a/layout/base/src/nsDocument.h +++ b/layout/base/src/nsDocument.h @@ -140,6 +140,11 @@ public: virtual nsIScriptContextOwner *GetScriptContextOwner(); virtual void SetScriptContextOwner(nsIScriptContextOwner *aScriptContextOwner); + /** + * Get the name space manager for this document + */ + NS_IMETHOD GetNameSpaceManager(nsINameSpaceManager*& aManager); + /** * Add a new observer of document change notifications. Whenever * content is changed, appended, inserted or removed the observers are @@ -315,6 +320,7 @@ protected: PRBool mDisplaySelection; PRBool mInDestructor; nsDOMStyleSheetCollection *mDOMStyleSheets; + nsINameSpaceManager* mNameSpaceManager; }; #endif /* nsDocument_h___ */ diff --git a/layout/base/src/nsDocumentFragment.h b/layout/base/src/nsDocumentFragment.h index d725ea5c563a..7cc8e23cc5b7 100644 --- a/layout/base/src/nsDocumentFragment.h +++ b/layout/base/src/nsDocumentFragment.h @@ -22,6 +22,7 @@ #include "nsIScriptObjectOwner.h" #include "nsGenericElement.h" #include "nsISizeOfHandler.h" +#include "nsINameSpaceManager.h" class nsIDocument; @@ -98,6 +99,11 @@ public: } NS_IMETHOD SetParent(nsIContent* aParent) { return NS_OK; } + NS_IMETHOD GetNameSpaceID(PRInt32& aResult) const + { + aResult = kNameSpaceID_None; + return NS_OK; + } NS_IMETHOD GetTag(nsIAtom*& aResult) const { aResult = nsnull; diff --git a/layout/base/src/nsGenericElement.cpp b/layout/base/src/nsGenericElement.cpp index 42473a9be46f..70b47b47fff1 100644 --- a/layout/base/src/nsGenericElement.cpp +++ b/layout/base/src/nsGenericElement.cpp @@ -49,6 +49,7 @@ #include "nsIDOMScriptObjectFactory.h" #include "nsIDOMCSSStyleDeclaration.h" #include "nsDOMCSSDeclaration.h" +#include "nsINameSpaceManager.h" #include "prprf.h" #include "prmem.h" @@ -934,6 +935,13 @@ nsGenericElement::SetParent(nsIContent* aParent) return NS_OK; } +nsresult +nsGenericElement::GetNameSpaceID(PRInt32& aResult) const +{ + aResult = kNameSpaceID_None; + return NS_OK; +} + nsresult nsGenericElement::GetTag(nsIAtom*& aResult) const { diff --git a/layout/base/src/nsGenericElement.h b/layout/base/src/nsGenericElement.h index 992f5a2a5d04..bed6e303553c 100644 --- a/layout/base/src/nsGenericElement.h +++ b/layout/base/src/nsGenericElement.h @@ -208,6 +208,7 @@ public: aResult = PR_FALSE; return NS_OK; } + nsresult GetNameSpaceID(PRInt32& aNameSpaceID) const; nsresult GetTag(nsIAtom*& aResult) const; nsresult HandleDOMEvent(nsIPresContext& aPresContext, nsEvent* aEvent, @@ -484,6 +485,9 @@ public: NS_IMETHOD IsSynthetic(PRBool& aResult) { \ return _g.IsSynthetic(aResult); \ } \ + NS_IMETHOD GetNameSpaceID(PRInt32& aResult) const { \ + return _g.GetNameSpaceID(aResult); \ + } \ NS_IMETHOD GetTag(nsIAtom*& aResult) const { \ return _g.GetTag(aResult); \ } \ diff --git a/layout/base/src/nsNameSpaceManager.cpp b/layout/base/src/nsNameSpaceManager.cpp new file mode 100644 index 000000000000..ed681e503e1a --- /dev/null +++ b/layout/base/src/nsNameSpaceManager.cpp @@ -0,0 +1,418 @@ +/* -*- 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.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsINameSpaceManager.h" +#include "nsINameSpace.h" +#include "nsHashtable.h" +#include "nsVoidArray.h" +#include "nsLayoutAtoms.h" +#include "nsString.h" +#include "nsCRT.h" + +static NS_DEFINE_IID(kINameSpaceManagerIID, NS_INAMESPACEMANAGER_IID); +static NS_DEFINE_IID(kINameSpaceIID, NS_INAMESPACE_IID); + + +static const char kHTMLNameSpaceURI[] = "http://www.w3.org/TR/REC-html40"; // XXX?? "urn:w3-org-ns:HTML"?? +static const char kXMLNameSpaceURI[] = "urn:Connolly:input:required"; // XXX ?? what is it really? + +//----------------------------------------------------------- +// Name Space + +class NameSpaceImpl : public nsINameSpace { +public: + NameSpaceImpl(nsINameSpaceManager* aManager, + NameSpaceImpl* aParent, + nsIAtom* aPrefix, + const nsString& aURI); + NameSpaceImpl(nsINameSpaceManager* aManager, + NameSpaceImpl* aParent, + nsIAtom* aPrefix, + PRInt32 aNameSpaceID); + virtual ~NameSpaceImpl(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD GetNameSpaceManager(nsINameSpaceManager*& aManager) const; + + NS_IMETHOD GetNameSpaceID(PRInt32& aID) const; + NS_IMETHOD GetNameSpaceURI(nsString& aURI) const; + NS_IMETHOD GetNameSpacePrefix(nsIAtom*& aPrefix) const; + + NS_IMETHOD GetParentNameSpace(nsINameSpace*& aParent) const; + + NS_IMETHOD FindNameSpace(nsIAtom* aPrefix, nsINameSpace*& aNameSpace) const; + NS_IMETHOD FindNameSpaceID(nsIAtom* aPrefix, PRInt32& aNameSpaceID) const; + NS_IMETHOD FindNameSpacePrefix(PRInt32 aNameSpaceID, nsIAtom*& aPrefix) const; + + NS_IMETHOD CreateChildNameSpace(nsIAtom* aPrefix, const nsString& aURI, + nsINameSpace*& aChildNameSpace); + +private: + // These are not supported and are not implemented! + NameSpaceImpl(const NameSpaceImpl& aCopy); + NameSpaceImpl& operator=(const NameSpaceImpl& aCopy); + +public: + nsINameSpaceManager* mManager; + NameSpaceImpl* mParent; + nsIAtom* mPrefix; + PRInt32 mID; +}; + + +NameSpaceImpl::NameSpaceImpl(nsINameSpaceManager* aManager, + NameSpaceImpl* aParent, + nsIAtom* aPrefix, + const nsString& aURI) + : mManager(aManager), + mParent(aParent), + mPrefix(aPrefix) +{ + NS_ASSERTION(nsnull != aManager, "null namespace manager"); + NS_INIT_REFCNT(); + NS_ADDREF(mManager); + NS_IF_ADDREF(mParent); + NS_IF_ADDREF(mPrefix); + mManager->RegisterNameSpace(aURI, mID); +} + +NameSpaceImpl::NameSpaceImpl(nsINameSpaceManager* aManager, + NameSpaceImpl* aParent, + nsIAtom* aPrefix, + PRInt32 aNameSpaceID) + : mManager(aManager), + mParent(aParent), + mPrefix(aPrefix), + mID(aNameSpaceID) +{ + NS_ASSERTION(nsnull != aManager, "null namespace manager"); + NS_INIT_REFCNT(); + NS_ADDREF(mManager); + NS_IF_ADDREF(mParent); + NS_IF_ADDREF(mPrefix); +} + +NameSpaceImpl::~NameSpaceImpl() +{ + NS_RELEASE(mManager); + NS_IF_RELEASE(mParent); + NS_IF_RELEASE(mPrefix); +} + +NS_IMPL_ISUPPORTS(NameSpaceImpl, kINameSpaceIID) + +NS_IMETHODIMP +NameSpaceImpl::GetNameSpaceManager(nsINameSpaceManager*& aManager) const +{ + NS_ASSERTION(nsnull != aManager, "null namespace manager"); + aManager = mManager; + NS_ADDREF(aManager); + return NS_OK; +} + +NS_IMETHODIMP +NameSpaceImpl::GetNameSpaceID(PRInt32& aID) const +{ + aID = mID; + return NS_OK; +} + +NS_IMETHODIMP +NameSpaceImpl::GetNameSpaceURI(nsString& aURI) const +{ + NS_ASSERTION(nsnull != mManager, "null namespace manager"); + return mManager->GetNameSpaceURI(mID, aURI); +} + +NS_IMETHODIMP +NameSpaceImpl::GetNameSpacePrefix(nsIAtom*& aPrefix) const +{ + aPrefix = mPrefix; + NS_IF_ADDREF(aPrefix); + return NS_OK; +} + +NS_IMETHODIMP +NameSpaceImpl::GetParentNameSpace(nsINameSpace*& aParent) const +{ + aParent = mParent; + NS_IF_ADDREF(aParent); + return NS_OK; +} + +NS_IMETHODIMP +NameSpaceImpl::FindNameSpace(nsIAtom* aPrefix, nsINameSpace*& aNameSpace) const +{ + const NameSpaceImpl* nameSpace = this; + do { + if (aPrefix == nameSpace->mPrefix) { + aNameSpace = (nsINameSpace*)nameSpace; + NS_ADDREF(aNameSpace); + return NS_OK; + } + nameSpace = nameSpace->mParent; + } + while (nsnull != nameSpace); + aNameSpace = nsnull; + return NS_ERROR_ILLEGAL_VALUE; +} + +NS_IMETHODIMP +NameSpaceImpl::FindNameSpaceID(nsIAtom* aPrefix, PRInt32& aNameSpaceID) const +{ + const NameSpaceImpl* nameSpace = this; + do { + if (aPrefix == nameSpace->mPrefix) { + aNameSpaceID = nameSpace->mID; + return NS_OK; + } + nameSpace = nameSpace->mParent; + } + while (nsnull != nameSpace); + aNameSpaceID = kNameSpaceID_Unknown; + return NS_ERROR_ILLEGAL_VALUE; +} + +NS_IMETHODIMP +NameSpaceImpl::FindNameSpacePrefix(PRInt32 aNameSpaceID, nsIAtom*& aPrefix) const +{ + const NameSpaceImpl* nameSpace = this; + do { + if (aNameSpaceID == nameSpace->mID) { + aPrefix = nameSpace->mPrefix; + NS_IF_ADDREF(aPrefix); + return NS_OK; + } + nameSpace = nameSpace->mParent; + } + while (nsnull != nameSpace); + aPrefix = nsnull; + return NS_ERROR_ILLEGAL_VALUE; +} + +NS_IMETHODIMP +NameSpaceImpl::CreateChildNameSpace(nsIAtom* aPrefix, const nsString& aURI, + nsINameSpace*& aChildNameSpace) +{ + NameSpaceImpl* child = new NameSpaceImpl(mManager, this, aPrefix, aURI); + + return child->QueryInterface(kINameSpaceIID, (void**)&aChildNameSpace); +} + +//----------------------------------------------------------- +// Name Space Manager + +static PRInt32 gNameSpaceTableRefs; +static nsHashtable* gURIToIDTable; +static nsVoidArray* gURIArray; + +class StringKey : public nsHashKey { +public: + StringKey(const nsString* aString) + : mString(aString) + { } + + virtual ~StringKey(void) + { } + + virtual PRUint32 HashValue(void) const + { + if (nsnull != mString) { + return nsCRT::HashValue(mString->GetUnicode()); + } + return 0; + } + + virtual PRBool Equals(const nsHashKey *aKey) const + { + const nsString* other = ((const StringKey*)aKey)->mString; + if (nsnull != mString) { + if (nsnull != other) { + return mString->Equals(*other); + } + return PR_FALSE; + } + return PRBool(nsnull == other); + } + + virtual nsHashKey *Clone(void) const + { + return new StringKey(mString); + } + + const nsString* mString; +}; + +static void AddRefTable() +{ + if (0 == gNameSpaceTableRefs++) { + NS_ASSERTION(nsnull == gURIToIDTable, "already have URI table"); + NS_ASSERTION(nsnull == gURIArray, "already have URI array"); + + gURIToIDTable = new nsHashtable(); + gURIArray = new nsVoidArray(); + + nsString* html = new nsString(kHTMLNameSpaceURI); + nsString* xml = new nsString(kXMLNameSpaceURI); + gURIArray->AppendElement(html); + gURIArray->AppendElement(xml); + gURIToIDTable->Put(&StringKey(html), (void*)kNameSpaceID_HTML); + gURIToIDTable->Put(&StringKey(xml), (void*)kNameSpaceID_XML); + } + NS_ASSERTION(nsnull != gURIToIDTable, "no URI table"); + NS_ASSERTION(nsnull != gURIArray, "no URI array"); +} + +static void ReleaseTable() +{ + if (0 == --gNameSpaceTableRefs) { + delete gURIToIDTable; + PRInt32 index = gURIArray->Count(); + while (0 < index--) { + nsString* str = (nsString*)gURIArray->ElementAt(index); + delete str; + } + delete gURIArray; + gURIToIDTable = nsnull; + gURIArray = nsnull; + } +} + +static PRInt32 FindNameSpaceID(const nsString& aURI) +{ + NS_ASSERTION(nsnull != gURIToIDTable, "no URI table"); + void* value = gURIToIDTable->Get(&StringKey(&aURI)); + if (nsnull != value) { + return PRInt32(value); + } + return kNameSpaceID_Unknown; +} + +static const nsString* FindNameSpaceURI(PRInt32 aID) +{ + NS_ASSERTION(nsnull != gURIArray, "no URI array"); + return (const nsString*)gURIArray->ElementAt(aID - 1); +} + +class NameSpaceManagerImpl : public nsINameSpaceManager { +public: + NameSpaceManagerImpl(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD CreateRootNameSpace(nsINameSpace*& aRootNameSpace); + + NS_IMETHOD RegisterNameSpace(const nsString& aURI, + PRInt32& aNameSpaceID); + + NS_IMETHOD GetNameSpaceURI(PRInt32 aNameSpaceID, nsString& aURI); + NS_IMETHOD GetNameSpaceID(const nsString& aURI, PRInt32& aNameSpaceID); + +private: + // These are not supported and are not implemented! + NameSpaceManagerImpl(const NameSpaceManagerImpl& aCopy); + NameSpaceManagerImpl& operator=(const NameSpaceManagerImpl& aCopy); + +protected: + virtual ~NameSpaceManagerImpl(); + +}; + + +NameSpaceManagerImpl::NameSpaceManagerImpl() +{ + NS_INIT_REFCNT(); + AddRefTable(); +} + +NameSpaceManagerImpl::~NameSpaceManagerImpl() +{ + ReleaseTable(); +} + +NS_IMPL_ISUPPORTS(NameSpaceManagerImpl, kINameSpaceManagerIID) + +NS_IMETHODIMP +NameSpaceManagerImpl::CreateRootNameSpace(nsINameSpace*& aRootNameSpace) +{ + nsresult rv = NS_ERROR_OUT_OF_MEMORY; + aRootNameSpace = nsnull; + + NameSpaceImpl* html = new NameSpaceImpl(this, nsnull, nsLayoutAtoms::htmlNameSpace, kNameSpaceID_HTML); + if (nsnull != html) { + NameSpaceImpl* xml = new NameSpaceImpl(this, html, nsLayoutAtoms::xmlNameSpace, kNameSpaceID_XML); + if (nsnull != xml) { + rv = xml->QueryInterface(kINameSpaceIID, (void**)&aRootNameSpace); + } + else { + delete html; + } + } + return rv; +} + +NS_IMETHODIMP +NameSpaceManagerImpl::RegisterNameSpace(const nsString& aURI, + PRInt32& aNameSpaceID) +{ + PRInt32 id = FindNameSpaceID(aURI); + + if (kNameSpaceID_Unknown == id) { + nsString* uri = new nsString(aURI); + gURIArray->AppendElement(uri); + id = gURIArray->Count(); // id is index + 1 + gURIToIDTable->Put(&StringKey(uri), (void*)id); + } + aNameSpaceID = id; + return NS_OK; +} + +NS_IMETHODIMP +NameSpaceManagerImpl::GetNameSpaceURI(PRInt32 aNameSpaceID, nsString& aURI) +{ + const nsString* result = FindNameSpaceURI(aNameSpaceID); + if (nsnull != result) { + aURI = *result; + return NS_OK; + } + aURI.Truncate(); + return NS_ERROR_ILLEGAL_VALUE; +} + +NS_IMETHODIMP +NameSpaceManagerImpl::GetNameSpaceID(const nsString& aURI, PRInt32& aNameSpaceID) +{ + aNameSpaceID = FindNameSpaceID(aURI); + return NS_OK; +} + +NS_LAYOUT nsresult +NS_NewNameSpaceManager(nsINameSpaceManager** aInstancePtrResult) +{ + if (aInstancePtrResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } + + NameSpaceManagerImpl *it = new NameSpaceManagerImpl(); + + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(kINameSpaceManagerIID, (void **) aInstancePtrResult); +}