Merge mozilla-central to autoland on a CLOSED TREE
[gecko.git] / dom / xml / XMLDocument.cpp
bloba230c88cc19a1ca169cd5f2a5c1bf2af477fecfc
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/. */
7 #include "mozilla/dom/XMLDocument.h"
8 #include "nsCharsetSource.h"
9 #include "nsIXMLContentSink.h"
10 #include "nsPresContext.h"
11 #include "nsIContent.h"
12 #include "nsIDocShell.h"
13 #include "nsHTMLParts.h"
14 #include "nsCOMPtr.h"
15 #include "nsString.h"
16 #include "nsIURI.h"
17 #include "nsNetUtil.h"
18 #include "nsError.h"
19 #include "nsIPrincipal.h"
20 #include "nsLayoutCID.h"
21 #include "mozilla/dom/Attr.h"
22 #include "nsCExternalHandlerService.h"
23 #include "nsMimeTypes.h"
24 #include "nsContentUtils.h"
25 #include "nsThreadUtils.h"
26 #include "nsJSUtils.h"
27 #include "nsCRT.h"
28 #include "nsComponentManagerUtils.h"
29 #include "nsContentCreatorFunctions.h"
30 #include "nsContentPolicyUtils.h"
31 #include "nsIConsoleService.h"
32 #include "nsIScriptError.h"
33 #include "nsHTMLDocument.h"
34 #include "nsParser.h"
35 #include "mozilla/BasicEvents.h"
36 #include "mozilla/EventDispatcher.h"
37 #include "mozilla/Encoding.h"
38 #include "mozilla/dom/DocumentType.h"
39 #include "mozilla/dom/Element.h"
40 #include "mozilla/dom/DocGroup.h"
41 #include "mozilla/dom/XMLDocumentBinding.h"
42 #include "mozilla/dom/DocumentBinding.h"
44 using namespace mozilla;
45 using namespace mozilla::dom;
47 // ==================================================================
48 // =
49 // ==================================================================
51 nsresult NS_NewDOMDocument(Document** aInstancePtrResult,
52 const nsAString& aNamespaceURI,
53 const nsAString& aQualifiedName,
54 DocumentType* aDoctype, nsIURI* aDocumentURI,
55 nsIURI* aBaseURI, nsIPrincipal* aPrincipal,
56 bool aLoadedAsData, nsIGlobalObject* aEventObject,
57 DocumentFlavor aFlavor) {
58 // Note: can't require that aDocumentURI/aBaseURI/aPrincipal be non-null,
59 // since at least one caller (XMLHttpRequest) doesn't have decent args to
60 // pass in.
62 nsresult rv;
64 *aInstancePtrResult = nullptr;
66 nsCOMPtr<Document> d;
67 bool isHTML = false;
68 bool isXHTML = false;
69 if (aFlavor == DocumentFlavorSVG) {
70 rv = NS_NewSVGDocument(getter_AddRefs(d));
71 } else if (aFlavor == DocumentFlavorHTML) {
72 rv = NS_NewHTMLDocument(getter_AddRefs(d));
73 isHTML = true;
74 } else if (aFlavor == DocumentFlavorXML) {
75 rv = NS_NewXMLDocument(getter_AddRefs(d));
76 } else if (aFlavor == DocumentFlavorPlain) {
77 rv = NS_NewXMLDocument(getter_AddRefs(d), aLoadedAsData, true);
78 } else if (aDoctype) {
79 MOZ_ASSERT(aFlavor == DocumentFlavorLegacyGuess);
80 nsAutoString publicId, name;
81 aDoctype->GetPublicId(publicId);
82 if (publicId.IsEmpty()) {
83 aDoctype->GetName(name);
85 if (name.EqualsLiteral("html") ||
86 publicId.EqualsLiteral("-//W3C//DTD HTML 4.01//EN") ||
87 publicId.EqualsLiteral("-//W3C//DTD HTML 4.01 Frameset//EN") ||
88 publicId.EqualsLiteral("-//W3C//DTD HTML 4.01 Transitional//EN") ||
89 publicId.EqualsLiteral("-//W3C//DTD HTML 4.0//EN") ||
90 publicId.EqualsLiteral("-//W3C//DTD HTML 4.0 Frameset//EN") ||
91 publicId.EqualsLiteral("-//W3C//DTD HTML 4.0 Transitional//EN")) {
92 rv = NS_NewHTMLDocument(getter_AddRefs(d));
93 isHTML = true;
94 } else if (publicId.EqualsLiteral("-//W3C//DTD XHTML 1.0 Strict//EN") ||
95 publicId.EqualsLiteral(
96 "-//W3C//DTD XHTML 1.0 Transitional//EN") ||
97 publicId.EqualsLiteral("-//W3C//DTD XHTML 1.0 Frameset//EN")) {
98 rv = NS_NewHTMLDocument(getter_AddRefs(d));
99 isHTML = true;
100 isXHTML = true;
101 } else if (publicId.EqualsLiteral("-//W3C//DTD SVG 1.1//EN")) {
102 rv = NS_NewSVGDocument(getter_AddRefs(d));
104 // XXX Add support for XUL documents.
105 else {
106 rv = NS_NewXMLDocument(getter_AddRefs(d));
108 } else {
109 MOZ_ASSERT(aFlavor == DocumentFlavorLegacyGuess);
110 rv = NS_NewXMLDocument(getter_AddRefs(d));
113 if (NS_FAILED(rv)) {
114 return rv;
117 if (isHTML) {
118 d->SetCompatibilityMode(eCompatibility_FullStandards);
119 d->AsHTMLDocument()->SetIsXHTML(isXHTML);
121 d->SetLoadedAsData(aLoadedAsData, /* aConsiderForMemoryReporting */ true);
122 d->SetDocumentURI(aDocumentURI);
123 // Must set the principal first, since SetBaseURI checks it.
124 d->SetPrincipals(aPrincipal, aPrincipal);
125 d->SetBaseURI(aBaseURI);
127 // We need to set the script handling object after we set the principal such
128 // that the doc group is assigned correctly.
129 if (nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aEventObject)) {
130 d->SetScriptHandlingObject(sgo);
131 } else if (aEventObject) {
132 d->SetScopeObject(aEventObject);
135 // XMLDocuments and documents "created in memory" get to be UTF-8 by default,
136 // unlike the legacy HTML mess
137 d->SetDocumentCharacterSet(UTF_8_ENCODING);
139 if (aDoctype) {
140 ErrorResult result;
141 d->AppendChild(*aDoctype, result);
142 // Need to WouldReportJSException() if our callee can throw a JS
143 // exception (which it can) and we're neither propagating the
144 // error out nor unconditionally suppressing it.
145 result.WouldReportJSException();
146 if (NS_WARN_IF(result.Failed())) {
147 return result.StealNSResult();
151 if (!aQualifiedName.IsEmpty()) {
152 ErrorResult result;
153 ElementCreationOptionsOrString options;
154 Unused << options.SetAsString();
156 nsCOMPtr<Element> root =
157 d->CreateElementNS(aNamespaceURI, aQualifiedName, options, result);
158 if (NS_WARN_IF(result.Failed())) {
159 return result.StealNSResult();
162 d->AppendChild(*root, result);
163 // Need to WouldReportJSException() if our callee can throw a JS
164 // exception (which it can) and we're neither propagating the
165 // error out nor unconditionally suppressing it.
166 result.WouldReportJSException();
167 if (NS_WARN_IF(result.Failed())) {
168 return result.StealNSResult();
172 d.forget(aInstancePtrResult);
174 return NS_OK;
177 nsresult NS_NewXMLDocument(Document** aInstancePtrResult, bool aLoadedAsData,
178 bool aIsPlainDocument) {
179 RefPtr<XMLDocument> doc = new XMLDocument();
181 nsresult rv = doc->Init();
183 if (NS_FAILED(rv)) {
184 *aInstancePtrResult = nullptr;
185 return rv;
188 doc->SetLoadedAsData(aLoadedAsData, /* aConsiderForMemoryReporting */ true);
189 doc->mIsPlainDocument = aIsPlainDocument;
190 doc.forget(aInstancePtrResult);
192 return NS_OK;
195 namespace mozilla::dom {
197 XMLDocument::XMLDocument(const char* aContentType)
198 : Document(aContentType),
199 mChannelIsPending(false),
200 mIsPlainDocument(false),
201 mSuppressParserErrorElement(false),
202 mSuppressParserErrorConsoleMessages(false) {
203 mType = eGenericXML;
206 nsresult XMLDocument::Init() {
207 nsresult rv = Document::Init();
208 NS_ENSURE_SUCCESS(rv, rv);
210 return rv;
213 void XMLDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
214 Document::Reset(aChannel, aLoadGroup);
217 void XMLDocument::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
218 nsIPrincipal* aPrincipal,
219 nsIPrincipal* aPartitionedPrincipal) {
220 if (mChannelIsPending) {
221 StopDocumentLoad();
222 mChannel->CancelWithReason(NS_BINDING_ABORTED,
223 "XMLDocument::ResetToURI"_ns);
224 mChannelIsPending = false;
227 Document::ResetToURI(aURI, aLoadGroup, aPrincipal, aPartitionedPrincipal);
230 void XMLDocument::SetSuppressParserErrorElement(bool aSuppress) {
231 mSuppressParserErrorElement = aSuppress;
234 bool XMLDocument::SuppressParserErrorElement() {
235 return mSuppressParserErrorElement;
238 void XMLDocument::SetSuppressParserErrorConsoleMessages(bool aSuppress) {
239 mSuppressParserErrorConsoleMessages = aSuppress;
242 bool XMLDocument::SuppressParserErrorConsoleMessages() {
243 return mSuppressParserErrorConsoleMessages;
246 nsresult XMLDocument::StartDocumentLoad(
247 const char* aCommand, nsIChannel* aChannel, nsILoadGroup* aLoadGroup,
248 nsISupports* aContainer, nsIStreamListener** aDocListener, bool aReset) {
249 nsresult rv = Document::StartDocumentLoad(aCommand, aChannel, aLoadGroup,
250 aContainer, aDocListener, aReset);
251 if (NS_FAILED(rv)) return rv;
253 int32_t charsetSource = kCharsetFromDocTypeDefault;
254 NotNull<const Encoding*> encoding = UTF_8_ENCODING;
255 TryChannelCharset(aChannel, charsetSource, encoding, nullptr);
257 nsCOMPtr<nsIURI> aUrl;
258 rv = aChannel->GetURI(getter_AddRefs(aUrl));
259 if (NS_FAILED(rv)) return rv;
261 mParser = new nsParser();
263 nsCOMPtr<nsIXMLContentSink> sink;
265 nsCOMPtr<nsIDocShell> docShell;
266 if (aContainer) {
267 docShell = do_QueryInterface(aContainer);
268 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
270 rv = NS_NewXMLContentSink(getter_AddRefs(sink), this, aUrl, docShell,
271 aChannel);
272 NS_ENSURE_SUCCESS(rv, rv);
274 // Set the parser as the stream listener for the document loader...
275 rv = CallQueryInterface(mParser, aDocListener);
276 NS_ENSURE_SUCCESS(rv, rv);
278 NS_ASSERTION(mChannel, "How can we not have a channel here?");
279 mChannelIsPending = true;
281 SetDocumentCharacterSet(encoding);
282 mParser->SetDocumentCharset(encoding, charsetSource);
283 mParser->SetCommand(aCommand);
284 mParser->SetContentSink(sink);
285 mParser->Parse(aUrl);
287 return NS_OK;
290 void XMLDocument::EndLoad() {
291 mChannelIsPending = false;
293 mSynchronousDOMContentLoaded = mLoadedAsData;
294 Document::EndLoad();
295 if (mSynchronousDOMContentLoaded) {
296 mSynchronousDOMContentLoaded = false;
297 Document::SetReadyStateInternal(Document::READYSTATE_COMPLETE);
298 // Generate a document load event for the case when an XML
299 // document was loaded as pure data without any presentation
300 // attached to it.
301 WidgetEvent event(true, eLoad);
302 // TODO: Bug 1506441
303 EventDispatcher::Dispatch(MOZ_KnownLive(ToSupports(this)), nullptr, &event);
307 /* virtual */
308 void XMLDocument::DocAddSizeOfExcludingThis(nsWindowSizes& aWindowSizes) const {
309 Document::DocAddSizeOfExcludingThis(aWindowSizes);
312 // Document interface
314 nsresult XMLDocument::Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const {
315 NS_ASSERTION(aNodeInfo->NodeInfoManager() == mNodeInfoManager,
316 "Can't import this document into another document!");
318 RefPtr<XMLDocument> clone = new XMLDocument();
319 nsresult rv = CloneDocHelper(clone);
320 NS_ENSURE_SUCCESS(rv, rv);
322 // State from XMLDocument
323 clone->mIsPlainDocument = mIsPlainDocument;
325 clone.forget(aResult);
326 return NS_OK;
329 JSObject* XMLDocument::WrapNode(JSContext* aCx,
330 JS::Handle<JSObject*> aGivenProto) {
331 if (mIsPlainDocument) {
332 return Document_Binding::Wrap(aCx, this, aGivenProto);
335 return XMLDocument_Binding::Wrap(aCx, this, aGivenProto);
338 } // namespace mozilla::dom