Line data Source code
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 "nscore.h"
15 : #include "mozilla/dom/NodeInfo.h"
16 : #include "nsCOMArray.h"
17 : #include "nsContentCreatorFunctions.h"
18 : #include "nsContentUtils.h"
19 : #include "nsGkAtoms.h"
20 : #include "nsIDocument.h"
21 : #include "nsString.h"
22 : #include "mozilla/dom/NodeInfo.h"
23 : #include "mozilla/ClearOnShutdown.h"
24 : #include "mozilla/dom/XBLChildrenElement.h"
25 : #include "mozilla/dom/Element.h"
26 : #include "mozilla/Preferences.h"
27 :
28 : using namespace mozilla;
29 : using namespace mozilla::dom;
30 :
31 : static const char* kPrefSVGDisabled = "svg.disabled";
32 : static const char* kPrefMathMLDisabled = "mathml.disabled";
33 : static const char* kObservedPrefs[] = {
34 : kPrefMathMLDisabled,
35 : kPrefSVGDisabled,
36 : nullptr
37 3 : };
38 3 : StaticRefPtr<nsNameSpaceManager> nsNameSpaceManager::sInstance;
39 :
40 : /* static */ nsNameSpaceManager*
41 136 : nsNameSpaceManager::GetInstance() {
42 136 : if (!sInstance) {
43 3 : sInstance = new nsNameSpaceManager();
44 3 : if (sInstance->Init()) {
45 3 : ClearOnShutdown(&sInstance);
46 : } else {
47 0 : delete sInstance;
48 0 : sInstance = nullptr;
49 : }
50 : }
51 :
52 136 : return sInstance;
53 : }
54 :
55 3 : bool nsNameSpaceManager::Init()
56 : {
57 : nsresult rv;
58 : #define REGISTER_NAMESPACE(uri, id) \
59 : rv = AddNameSpace(dont_AddRef(uri), id); \
60 : NS_ENSURE_SUCCESS(rv, false)
61 :
62 : #define REGISTER_DISABLED_NAMESPACE(uri, id) \
63 : rv = AddDisabledNameSpace(dont_AddRef(uri), id); \
64 : NS_ENSURE_SUCCESS(rv, false)
65 :
66 3 : mozilla::Preferences::AddStrongObservers(this, kObservedPrefs);
67 3 : mMathMLDisabled = mozilla::Preferences::GetBool(kPrefMathMLDisabled);
68 3 : mSVGDisabled = mozilla::Preferences::GetBool(kPrefSVGDisabled);
69 :
70 :
71 : // Need to be ordered according to ID.
72 3 : MOZ_ASSERT(mURIArray.IsEmpty());
73 3 : REGISTER_NAMESPACE(nsGkAtoms::empty, kNameSpaceID_None);
74 3 : REGISTER_NAMESPACE(nsGkAtoms::nsuri_xmlns, kNameSpaceID_XMLNS);
75 3 : REGISTER_NAMESPACE(nsGkAtoms::nsuri_xml, kNameSpaceID_XML);
76 3 : REGISTER_NAMESPACE(nsGkAtoms::nsuri_xhtml, kNameSpaceID_XHTML);
77 3 : REGISTER_NAMESPACE(nsGkAtoms::nsuri_xlink, kNameSpaceID_XLink);
78 3 : REGISTER_NAMESPACE(nsGkAtoms::nsuri_xslt, kNameSpaceID_XSLT);
79 3 : REGISTER_NAMESPACE(nsGkAtoms::nsuri_xbl, kNameSpaceID_XBL);
80 3 : REGISTER_NAMESPACE(nsGkAtoms::nsuri_mathml, kNameSpaceID_MathML);
81 3 : REGISTER_NAMESPACE(nsGkAtoms::nsuri_rdf, kNameSpaceID_RDF);
82 3 : REGISTER_NAMESPACE(nsGkAtoms::nsuri_xul, kNameSpaceID_XUL);
83 3 : REGISTER_NAMESPACE(nsGkAtoms::nsuri_svg, kNameSpaceID_SVG);
84 3 : REGISTER_DISABLED_NAMESPACE(nsGkAtoms::nsuri_mathml, kNameSpaceID_disabled_MathML);
85 3 : REGISTER_DISABLED_NAMESPACE(nsGkAtoms::nsuri_svg, kNameSpaceID_disabled_SVG);
86 :
87 : #undef REGISTER_NAMESPACE
88 : #undef REGISTER_DISABLED_NAMESPACE
89 :
90 3 : return true;
91 : }
92 :
93 : nsresult
94 625 : nsNameSpaceManager::RegisterNameSpace(const nsAString& aURI,
95 : int32_t& aNameSpaceID)
96 : {
97 625 : if (aURI.IsEmpty()) {
98 0 : aNameSpaceID = kNameSpaceID_None; // xmlns="", see bug 75700 for details
99 :
100 0 : return NS_OK;
101 : }
102 :
103 1250 : nsCOMPtr<nsIAtom> atom = NS_Atomize(aURI);
104 625 : nsresult rv = NS_OK;
105 625 : if (!mURIToIDTable.Get(atom, &aNameSpaceID)) {
106 17 : aNameSpaceID = mURIArray.Length();
107 :
108 17 : rv = AddNameSpace(atom.forget(), aNameSpaceID);
109 17 : if (NS_FAILED(rv)) {
110 0 : aNameSpaceID = kNameSpaceID_Unknown;
111 : }
112 : }
113 :
114 625 : NS_POSTCONDITION(aNameSpaceID >= -1, "Bogus namespace ID");
115 :
116 625 : return rv;
117 : }
118 :
119 : nsresult
120 1 : nsNameSpaceManager::GetNameSpaceURI(int32_t aNameSpaceID, nsAString& aURI)
121 : {
122 1 : NS_PRECONDITION(aNameSpaceID >= 0, "Bogus namespace ID");
123 :
124 : // We have historically treated GetNameSpaceURI calls for kNameSpaceID_None
125 : // as erroneous.
126 1 : if (aNameSpaceID <= 0 || aNameSpaceID >= int32_t(mURIArray.Length())) {
127 0 : aURI.Truncate();
128 :
129 0 : return NS_ERROR_ILLEGAL_VALUE;
130 : }
131 :
132 1 : mURIArray.ElementAt(aNameSpaceID)->ToString(aURI);
133 :
134 1 : return NS_OK;
135 : }
136 :
137 : int32_t
138 1 : nsNameSpaceManager::GetNameSpaceID(const nsAString& aURI,
139 : bool aInChromeDoc)
140 : {
141 1 : if (aURI.IsEmpty()) {
142 0 : return kNameSpaceID_None; // xmlns="", see bug 75700 for details
143 : }
144 :
145 2 : nsCOMPtr<nsIAtom> atom = NS_Atomize(aURI);
146 1 : return GetNameSpaceID(atom, aInChromeDoc);
147 : }
148 :
149 : int32_t
150 1 : nsNameSpaceManager::GetNameSpaceID(nsIAtom* aURI,
151 : bool aInChromeDoc)
152 : {
153 1 : if (aURI == nsGkAtoms::_empty) {
154 0 : return kNameSpaceID_None; // xmlns="", see bug 75700 for details
155 : }
156 :
157 : int32_t nameSpaceID;
158 2 : if (!aInChromeDoc
159 0 : && (mMathMLDisabled || mSVGDisabled)
160 0 : && mDisabledURIToIDTable.Get(aURI, &nameSpaceID)
161 1 : && ((mMathMLDisabled && kNameSpaceID_disabled_MathML == nameSpaceID) ||
162 0 : (mSVGDisabled && kNameSpaceID_disabled_SVG == nameSpaceID))) {
163 0 : NS_POSTCONDITION(nameSpaceID >= 0, "Bogus namespace ID");
164 0 : return nameSpaceID;
165 : }
166 1 : if (mURIToIDTable.Get(aURI, &nameSpaceID)) {
167 1 : NS_POSTCONDITION(nameSpaceID >= 0, "Bogus namespace ID");
168 1 : return nameSpaceID;
169 : }
170 :
171 0 : return kNameSpaceID_Unknown;
172 : }
173 :
174 : nsresult
175 558 : NS_NewElement(Element** aResult,
176 : already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
177 : FromParser aFromParser,
178 : const nsAString* aIs)
179 : {
180 1116 : RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
181 558 : int32_t ns = ni->NamespaceID();
182 558 : if (ns == kNameSpaceID_XHTML) {
183 47 : return NS_NewHTMLElement(aResult, ni.forget(), aFromParser, aIs);
184 : }
185 : #ifdef MOZ_XUL
186 511 : if (ns == kNameSpaceID_XUL) {
187 56 : return NS_NewXULElement(aResult, ni.forget());
188 : }
189 : #endif
190 455 : if (ns == kNameSpaceID_MathML) {
191 : // If the mathml.disabled pref. is true, convert all MathML nodes into
192 : // disabled MathML nodes by swapping the namespace.
193 0 : nsNameSpaceManager* nsmgr = nsNameSpaceManager::GetInstance();
194 0 : if ((nsmgr && !nsmgr->mMathMLDisabled) ||
195 0 : nsContentUtils::IsSystemPrincipal(ni->GetDocument()->NodePrincipal())) {
196 0 : return NS_NewMathMLElement(aResult, ni.forget());
197 : }
198 :
199 : RefPtr<mozilla::dom::NodeInfo> genericXMLNI =
200 : ni->NodeInfoManager()->
201 0 : GetNodeInfo(ni->NameAtom(), ni->GetPrefixAtom(),
202 0 : kNameSpaceID_disabled_MathML, ni->NodeType(), ni->GetExtraName());
203 0 : return NS_NewXMLElement(aResult, genericXMLNI.forget());
204 : }
205 455 : if (ns == kNameSpaceID_SVG) {
206 : // If the svg.disabled pref. is true, convert all SVG nodes into
207 : // disabled SVG nodes by swapping the namespace.
208 133 : nsNameSpaceManager* nsmgr = nsNameSpaceManager::GetInstance();
209 266 : nsCOMPtr<nsILoadInfo> loadInfo;
210 133 : bool SVGEnabled = false;
211 :
212 133 : if (nsmgr && !nsmgr->mSVGDisabled) {
213 133 : SVGEnabled = true;
214 : } else {
215 0 : nsCOMPtr<nsIChannel> channel = ni->GetDocument()->GetChannel();
216 : // We don't have a channel for SVGs constructed inside a SVG script
217 0 : if (channel) {
218 0 : loadInfo = channel->GetLoadInfo();
219 : }
220 : }
221 133 : if (SVGEnabled ||
222 266 : nsContentUtils::IsSystemPrincipal(ni->GetDocument()->NodePrincipal()) ||
223 0 : (loadInfo &&
224 0 : (loadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_IMAGE ||
225 0 : loadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_OTHER) &&
226 0 : (nsContentUtils::IsSystemPrincipal(loadInfo->LoadingPrincipal()) ||
227 0 : nsContentUtils::IsSystemPrincipal(loadInfo->TriggeringPrincipal())
228 : )
229 : )
230 : ) {
231 133 : return NS_NewSVGElement(aResult, ni.forget(), aFromParser);
232 : }
233 : RefPtr<mozilla::dom::NodeInfo> genericXMLNI =
234 : ni->NodeInfoManager()->
235 0 : GetNodeInfo(ni->NameAtom(), ni->GetPrefixAtom(),
236 0 : kNameSpaceID_disabled_SVG, ni->NodeType(), ni->GetExtraName());
237 0 : return NS_NewXMLElement(aResult, genericXMLNI.forget());
238 : }
239 322 : if (ns == kNameSpaceID_XBL && ni->Equals(nsGkAtoms::children)) {
240 142 : NS_ADDREF(*aResult = new XBLChildrenElement(ni.forget()));
241 71 : return NS_OK;
242 : }
243 :
244 251 : return NS_NewXMLElement(aResult, ni.forget());
245 : }
246 :
247 : bool
248 0 : nsNameSpaceManager::HasElementCreator(int32_t aNameSpaceID)
249 : {
250 0 : return aNameSpaceID == kNameSpaceID_XHTML ||
251 : #ifdef MOZ_XUL
252 0 : aNameSpaceID == kNameSpaceID_XUL ||
253 : #endif
254 0 : aNameSpaceID == kNameSpaceID_MathML ||
255 : aNameSpaceID == kNameSpaceID_SVG ||
256 0 : false;
257 : }
258 :
259 50 : nsresult nsNameSpaceManager::AddNameSpace(already_AddRefed<nsIAtom> aURI,
260 : const int32_t aNameSpaceID)
261 : {
262 100 : nsCOMPtr<nsIAtom> uri = aURI;
263 50 : if (aNameSpaceID < 0) {
264 : // We've wrapped... Can't do anything else here; just bail.
265 0 : return NS_ERROR_OUT_OF_MEMORY;
266 : }
267 :
268 50 : MOZ_ASSERT(aNameSpaceID == (int32_t) mURIArray.Length());
269 50 : mURIArray.AppendElement(uri.forget());
270 50 : mURIToIDTable.Put(mURIArray.LastElement(), aNameSpaceID);
271 :
272 50 : return NS_OK;
273 : }
274 :
275 : nsresult
276 6 : nsNameSpaceManager::AddDisabledNameSpace(already_AddRefed<nsIAtom> aURI,
277 : const int32_t aNameSpaceID)
278 : {
279 12 : nsCOMPtr<nsIAtom> uri = aURI;
280 6 : if (aNameSpaceID < 0) {
281 : // We've wrapped... Can't do anything else here; just bail.
282 0 : return NS_ERROR_OUT_OF_MEMORY;
283 : }
284 :
285 6 : MOZ_ASSERT(aNameSpaceID == (int32_t) mURIArray.Length());
286 6 : mURIArray.AppendElement(uri.forget());
287 6 : mDisabledURIToIDTable.Put(mURIArray.LastElement(), aNameSpaceID);
288 :
289 6 : return NS_OK;
290 : }
291 :
292 : // nsISupports
293 51 : NS_IMPL_ISUPPORTS(nsNameSpaceManager,
294 : nsIObserver)
295 :
296 : // nsIObserver
297 : NS_IMETHODIMP
298 0 : nsNameSpaceManager::Observe(nsISupports* aObject, const char* aTopic,
299 : const char16_t* aMessage)
300 : {
301 0 : mMathMLDisabled = mozilla::Preferences::GetBool(kPrefMathMLDisabled);
302 0 : mSVGDisabled = mozilla::Preferences::GetBool(kPrefSVGDisabled);
303 0 : return NS_OK;
304 : }
|