nsNameSpaceManager.cpp (9670B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * A class for managing namespace IDs and mapping back and forth 9 * between namespace IDs and namespace URIs. 10 */ 11 12 #include "nsNameSpaceManager.h" 13 14 #include "mozilla/ClearOnShutdown.h" 15 #include "mozilla/Preferences.h" 16 #include "mozilla/dom/Document.h" 17 #include "mozilla/dom/Element.h" 18 #include "mozilla/dom/NodeInfo.h" 19 #include "nsAtom.h" 20 #include "nsCOMArray.h" 21 #include "nsContentCreatorFunctions.h" 22 #include "nsGkAtoms.h" 23 #include "nsString.h" 24 #include "nscore.h" 25 26 using namespace mozilla; 27 using namespace mozilla::dom; 28 29 static constexpr const char* kPrefSVGDisabled = "svg.disabled"; 30 static constexpr const char* kPrefMathMLDisabled = "mathml.disabled"; 31 static constexpr const char* kObservedNSPrefs[] = {kPrefMathMLDisabled, 32 kPrefSVGDisabled, nullptr}; 33 34 StaticRefPtr<nsNameSpaceManager> nsNameSpaceManager::sInstance; 35 36 /* static */ 37 nsNameSpaceManager* nsNameSpaceManager::GetInstance() { 38 if (!sInstance) { 39 sInstance = new nsNameSpaceManager(); 40 if (sInstance->Init()) { 41 ClearOnShutdown(&sInstance); 42 } else { 43 delete sInstance; 44 sInstance = nullptr; 45 } 46 } 47 48 return sInstance; 49 } 50 51 bool nsNameSpaceManager::Init() { 52 nsresult rv; 53 #define REGISTER_NAMESPACE(uri, id) \ 54 rv = AddNameSpace(dont_AddRef(uri), id); \ 55 NS_ENSURE_SUCCESS(rv, false) 56 57 #define REGISTER_DISABLED_NAMESPACE(uri, id) \ 58 rv = AddDisabledNameSpace(dont_AddRef(uri), id); \ 59 NS_ENSURE_SUCCESS(rv, false) 60 61 mozilla::Preferences::RegisterCallbacks(nsNameSpaceManager::PrefChanged, 62 kObservedNSPrefs, this); 63 64 PrefChanged(nullptr); 65 66 // Need to be ordered according to ID. 67 MOZ_ASSERT(mURIArray.IsEmpty()); 68 REGISTER_NAMESPACE(nsGkAtoms::_empty, kNameSpaceID_None); 69 REGISTER_NAMESPACE(nsGkAtoms::nsuri_xmlns, kNameSpaceID_XMLNS); 70 REGISTER_NAMESPACE(nsGkAtoms::nsuri_xml, kNameSpaceID_XML); 71 REGISTER_NAMESPACE(nsGkAtoms::nsuri_xhtml, kNameSpaceID_XHTML); 72 REGISTER_NAMESPACE(nsGkAtoms::nsuri_xlink, kNameSpaceID_XLink); 73 REGISTER_NAMESPACE(nsGkAtoms::nsuri_xslt, kNameSpaceID_XSLT); 74 REGISTER_NAMESPACE(nsGkAtoms::nsuri_mathml, kNameSpaceID_MathML); 75 REGISTER_NAMESPACE(nsGkAtoms::nsuri_rdf, kNameSpaceID_RDF); 76 REGISTER_NAMESPACE(nsGkAtoms::nsuri_xul, kNameSpaceID_XUL); 77 REGISTER_NAMESPACE(nsGkAtoms::nsuri_svg, kNameSpaceID_SVG); 78 REGISTER_DISABLED_NAMESPACE(nsGkAtoms::nsuri_mathml, 79 kNameSpaceID_disabled_MathML); 80 REGISTER_DISABLED_NAMESPACE(nsGkAtoms::nsuri_svg, kNameSpaceID_disabled_SVG); 81 82 #undef REGISTER_NAMESPACE 83 #undef REGISTER_DISABLED_NAMESPACE 84 85 return true; 86 } 87 88 nsresult nsNameSpaceManager::RegisterNameSpace(const nsAString& aURI, 89 int32_t& aNameSpaceID) { 90 RefPtr<nsAtom> atom = NS_Atomize(aURI); 91 return RegisterNameSpace(atom.forget(), aNameSpaceID); 92 } 93 94 nsresult nsNameSpaceManager::RegisterNameSpace(already_AddRefed<nsAtom> aURI, 95 int32_t& aNameSpaceID) { 96 RefPtr<nsAtom> atom = aURI; 97 nsresult rv = NS_OK; 98 if (atom == nsGkAtoms::_empty) { 99 aNameSpaceID = kNameSpaceID_None; // xmlns="", see bug 75700 for details 100 return NS_OK; 101 } 102 103 if (!mURIToIDTable.Get(atom, &aNameSpaceID)) { 104 aNameSpaceID = mURIArray.Length(); 105 106 rv = AddNameSpace(atom.forget(), aNameSpaceID); 107 if (NS_FAILED(rv)) { 108 aNameSpaceID = kNameSpaceID_Unknown; 109 } 110 } 111 112 MOZ_ASSERT(aNameSpaceID >= -1, "Bogus namespace ID"); 113 114 return rv; 115 } 116 117 nsresult nsNameSpaceManager::GetNameSpaceURI(int32_t aNameSpaceID, 118 nsAString& aURI) { 119 MOZ_ASSERT(aNameSpaceID >= 0, "Bogus namespace ID"); 120 121 // We have historically treated GetNameSpaceURI calls for kNameSpaceID_None 122 // as erroneous. 123 if (aNameSpaceID <= 0 || aNameSpaceID >= int32_t(mURIArray.Length())) { 124 aURI.Truncate(); 125 126 return NS_ERROR_ILLEGAL_VALUE; 127 } 128 129 mURIArray.ElementAt(aNameSpaceID)->ToString(aURI); 130 131 return NS_OK; 132 } 133 134 int32_t nsNameSpaceManager::GetNameSpaceID(const nsAString& aURI, 135 bool aInChromeDoc) { 136 if (aURI.IsEmpty()) { 137 return kNameSpaceID_None; // xmlns="", see bug 75700 for details 138 } 139 140 RefPtr<nsAtom> atom = NS_Atomize(aURI); 141 return GetNameSpaceID(atom, aInChromeDoc); 142 } 143 144 int32_t nsNameSpaceManager::GetNameSpaceID(nsAtom* aURI, bool aInChromeDoc) { 145 if (aURI == nsGkAtoms::_empty) { 146 return kNameSpaceID_None; // xmlns="", see bug 75700 for details 147 } 148 149 int32_t nameSpaceID; 150 if (!aInChromeDoc && (mMathMLDisabled || mSVGDisabled) && 151 mDisabledURIToIDTable.Get(aURI, &nameSpaceID) && 152 ((mMathMLDisabled && kNameSpaceID_disabled_MathML == nameSpaceID) || 153 (mSVGDisabled && kNameSpaceID_disabled_SVG == nameSpaceID))) { 154 MOZ_ASSERT(nameSpaceID >= 0, "Bogus namespace ID"); 155 return nameSpaceID; 156 } 157 if (mURIToIDTable.Get(aURI, &nameSpaceID)) { 158 MOZ_ASSERT(nameSpaceID >= 0, "Bogus namespace ID"); 159 return nameSpaceID; 160 } 161 162 return kNameSpaceID_Unknown; 163 } 164 165 // static 166 const char* nsNameSpaceManager::GetNameSpaceDisplayName(uint32_t aNameSpaceID) { 167 static const char* kNSURIs[] = {"([none])", "(xmlns)", "(xml)", "(xhtml)", 168 "(XLink)", "(XSLT)", "(MathML)", "(RDF)", 169 "(XUL)", "(SVG)"}; 170 if (aNameSpaceID < std::size(kNSURIs)) { 171 return kNSURIs[aNameSpaceID]; 172 } 173 return ""; 174 } 175 176 nsresult NS_NewElement(Element** aResult, 177 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, 178 FromParser aFromParser, const nsAString* aIs) { 179 RefPtr<nsAtom> isAtom = aIs ? NS_AtomizeMainThread(*aIs) : nullptr; 180 return NS_NewElement(aResult, std::move(aNodeInfo), aFromParser, isAtom); 181 } 182 183 nsresult NS_NewElement(Element** aResult, 184 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, 185 FromParser aFromParser, nsAtom* aIsAtom, 186 CustomElementDefinition* aDefinition) { 187 RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo; 188 int32_t ns = ni->NamespaceID(); 189 if (ns == kNameSpaceID_XHTML) { 190 return NS_NewHTMLElement(aResult, ni.forget(), aFromParser, aIsAtom, 191 aDefinition); 192 } 193 if (ns == kNameSpaceID_XUL) { 194 return NS_NewXULElement(aResult, ni.forget(), aFromParser, aIsAtom, 195 aDefinition); 196 } 197 if (ns == kNameSpaceID_MathML) { 198 // If the mathml.disabled pref. is true, convert all MathML nodes into 199 // disabled MathML nodes by swapping the namespace. 200 if (ni->NodeInfoManager()->MathMLEnabled()) { 201 return NS_NewMathMLElement(aResult, ni.forget()); 202 } 203 204 RefPtr<mozilla::dom::NodeInfo> genericXMLNI = 205 ni->NodeInfoManager()->GetNodeInfo(ni->NameAtom(), ni->GetPrefixAtom(), 206 kNameSpaceID_disabled_MathML, 207 ni->NodeType(), ni->GetExtraName()); 208 return NS_NewXMLElement(aResult, genericXMLNI.forget()); 209 } 210 if (ns == kNameSpaceID_SVG) { 211 // If the svg.disabled pref. is true, convert all SVG nodes into 212 // disabled SVG nodes by swapping the namespace. 213 if (ni->NodeInfoManager()->SVGEnabled()) { 214 return NS_NewSVGElement(aResult, ni.forget(), aFromParser); 215 } 216 RefPtr<mozilla::dom::NodeInfo> genericXMLNI = 217 ni->NodeInfoManager()->GetNodeInfo(ni->NameAtom(), ni->GetPrefixAtom(), 218 kNameSpaceID_disabled_SVG, 219 ni->NodeType(), ni->GetExtraName()); 220 return NS_NewXMLElement(aResult, genericXMLNI.forget()); 221 } 222 223 return NS_NewXMLElement(aResult, ni.forget()); 224 } 225 226 bool nsNameSpaceManager::HasElementCreator(int32_t aNameSpaceID) { 227 return aNameSpaceID == kNameSpaceID_XHTML || 228 aNameSpaceID == kNameSpaceID_XUL || 229 aNameSpaceID == kNameSpaceID_MathML || 230 aNameSpaceID == kNameSpaceID_SVG || false; 231 } 232 233 nsresult nsNameSpaceManager::AddNameSpace(already_AddRefed<nsAtom> aURI, 234 const int32_t aNameSpaceID) { 235 RefPtr<nsAtom> uri = aURI; 236 if (aNameSpaceID < 0) { 237 // We've wrapped... Can't do anything else here; just bail. 238 return NS_ERROR_OUT_OF_MEMORY; 239 } 240 241 MOZ_ASSERT(aNameSpaceID == (int32_t)mURIArray.Length()); 242 mURIArray.AppendElement(uri.forget()); 243 mURIToIDTable.InsertOrUpdate(mURIArray.LastElement(), aNameSpaceID); 244 245 return NS_OK; 246 } 247 248 nsresult nsNameSpaceManager::AddDisabledNameSpace(already_AddRefed<nsAtom> aURI, 249 const int32_t aNameSpaceID) { 250 RefPtr<nsAtom> uri = aURI; 251 if (aNameSpaceID < 0) { 252 // We've wrapped... Can't do anything else here; just bail. 253 return NS_ERROR_OUT_OF_MEMORY; 254 } 255 256 MOZ_ASSERT(aNameSpaceID == (int32_t)mURIArray.Length()); 257 mURIArray.AppendElement(uri.forget()); 258 mDisabledURIToIDTable.InsertOrUpdate(mURIArray.LastElement(), aNameSpaceID); 259 260 return NS_OK; 261 } 262 263 // static 264 void nsNameSpaceManager::PrefChanged(const char* aPref, void* aSelf) { 265 static_cast<nsNameSpaceManager*>(aSelf)->PrefChanged(aPref); 266 } 267 268 void nsNameSpaceManager::PrefChanged(const char* aPref) { 269 mMathMLDisabled = mozilla::Preferences::GetBool(kPrefMathMLDisabled); 270 mSVGDisabled = mozilla::Preferences::GetBool(kPrefSVGDisabled); 271 }