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