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 #include "nsContentDLF.h"
8 #include "mozilla/Encoding.h"
11 #include "nsDocShell.h"
12 #include "nsGenericHTMLElement.h"
13 #include "nsGkAtoms.h"
14 #include "nsIDocumentViewer.h"
15 #include "nsIDocumentLoaderFactory.h"
16 #include "mozilla/dom/Document.h"
17 #include "nsNodeInfoManager.h"
19 #include "nsContentCID.h"
20 #include "nsNetUtil.h"
22 #include "nsIViewSourceChannel.h"
23 #include "nsContentUtils.h"
24 #include "imgLoader.h"
25 #include "nsCharsetSource.h"
26 #include "nsMimeTypes.h"
27 #include "DecoderTraits.h"
29 // Factory code for creating variations on html documents
33 using mozilla::dom::Document
;
35 already_AddRefed
<nsIDocumentViewer
> NS_NewDocumentViewer();
37 static const char* const gHTMLTypes
[] = {TEXT_HTML
, VIEWSOURCE_CONTENT_TYPE
,
38 APPLICATION_XHTML_XML
,
39 APPLICATION_WAPXHTML_XML
, 0};
41 static const char* const gXMLTypes
[] = {TEXT_XML
,
43 APPLICATION_MATHML_XML
,
48 static const char* const gSVGTypes
[] = {IMAGE_SVG_XML
, 0};
50 static bool IsTypeInList(const nsACString
& aType
, const char* const aList
[]) {
52 for (typeIndex
= 0; aList
[typeIndex
]; ++typeIndex
) {
53 if (aType
.Equals(aList
[typeIndex
])) {
61 nsresult
NS_NewContentDocumentLoaderFactory(
62 nsIDocumentLoaderFactory
** aResult
) {
63 MOZ_ASSERT(aResult
, "null OUT ptr");
65 return NS_ERROR_NULL_POINTER
;
67 RefPtr
<nsContentDLF
> it
= new nsContentDLF();
72 nsContentDLF::nsContentDLF() = default;
74 nsContentDLF::~nsContentDLF() = default;
76 NS_IMPL_ISUPPORTS(nsContentDLF
, nsIDocumentLoaderFactory
)
79 nsContentDLF::CreateInstance(const char* aCommand
, nsIChannel
* aChannel
,
80 nsILoadGroup
* aLoadGroup
,
81 const nsACString
& aContentType
,
82 nsIDocShell
* aContainer
, nsISupports
* aExtraInfo
,
83 nsIStreamListener
** aDocListener
,
84 nsIDocumentViewer
** aDocViewer
) {
85 // Make a copy of aContentType, because we're possibly going to change it.
86 nsAutoCString
contentType(aContentType
);
88 // Are we viewing source?
89 nsCOMPtr
<nsIViewSourceChannel
> viewSourceChannel
=
90 do_QueryInterface(aChannel
);
91 if (viewSourceChannel
) {
92 aCommand
= "view-source";
94 // The parser freaks out when it sees the content-type that a
95 // view-source channel normally returns. Get the actual content
96 // type of the data. If it's known, use it; otherwise use
99 mozilla::Unused
<< viewSourceChannel
->GetOriginalContentType(type
);
100 bool knownType
= (!type
.EqualsLiteral(VIEWSOURCE_CONTENT_TYPE
) &&
101 IsTypeInList(type
, gHTMLTypes
)) ||
102 nsContentUtils::IsPlainTextType(type
) ||
103 IsTypeInList(type
, gXMLTypes
) ||
104 IsTypeInList(type
, gSVGTypes
) ||
105 IsTypeInList(type
, gXMLTypes
);
108 viewSourceChannel
->SetContentType(type
);
109 } else if (IsImageContentType(type
)) {
110 // If it's an image, we want to display it the same way we normally would.
113 viewSourceChannel
->SetContentType(nsLiteralCString(TEXT_PLAIN
));
115 } else if (aContentType
.EqualsLiteral(VIEWSOURCE_CONTENT_TYPE
)) {
116 aChannel
->SetContentType(nsLiteralCString(TEXT_PLAIN
));
117 contentType
= TEXT_PLAIN
;
121 bool imageDocument
= false;
122 // Try html or plaintext; both use the same document CID
123 if (IsTypeInList(contentType
, gHTMLTypes
) ||
124 nsContentUtils::IsPlainTextType(contentType
)) {
126 aCommand
, aChannel
, aLoadGroup
, aContainer
,
127 []() -> already_AddRefed
<Document
> {
128 RefPtr
<Document
> doc
;
130 NS_NewHTMLDocument(getter_AddRefs(doc
), nullptr, nullptr);
131 NS_ENSURE_SUCCESS(rv
, nullptr);
134 aDocListener
, aDocViewer
);
136 else if (IsTypeInList(contentType
, gXMLTypes
)) {
138 aCommand
, aChannel
, aLoadGroup
, aContainer
,
139 []() -> already_AddRefed
<Document
> {
140 RefPtr
<Document
> doc
;
142 NS_NewXMLDocument(getter_AddRefs(doc
), nullptr, nullptr);
143 NS_ENSURE_SUCCESS(rv
, nullptr);
146 aDocListener
, aDocViewer
);
148 else if (IsTypeInList(contentType
, gSVGTypes
)) {
150 aCommand
, aChannel
, aLoadGroup
, aContainer
,
151 []() -> already_AddRefed
<Document
> {
152 RefPtr
<Document
> doc
;
154 NS_NewSVGDocument(getter_AddRefs(doc
), nullptr, nullptr);
155 NS_ENSURE_SUCCESS(rv
, nullptr);
158 aDocListener
, aDocViewer
);
159 } else if (mozilla::DecoderTraits::ShouldHandleMediaType(
161 /* DecoderDoctorDiagnostics* */ nullptr)) {
163 aCommand
, aChannel
, aLoadGroup
, aContainer
,
164 []() -> already_AddRefed
<Document
> {
165 RefPtr
<Document
> doc
;
167 NS_NewVideoDocument(getter_AddRefs(doc
), nullptr, nullptr);
168 NS_ENSURE_SUCCESS(rv
, nullptr);
171 aDocListener
, aDocViewer
);
173 else if (IsImageContentType(contentType
)) {
174 imageDocument
= true;
176 aCommand
, aChannel
, aLoadGroup
, aContainer
,
177 []() -> already_AddRefed
<Document
> {
178 RefPtr
<Document
> doc
;
180 NS_NewImageDocument(getter_AddRefs(doc
), nullptr, nullptr);
181 NS_ENSURE_SUCCESS(rv
, nullptr);
184 aDocListener
, aDocViewer
);
186 // If we get here, then we weren't able to create anything. Sorry!
187 return NS_ERROR_FAILURE
;
190 if (NS_SUCCEEDED(rv
) && !imageDocument
) {
191 Document
* doc
= (*aDocViewer
)->GetDocument();
193 doc
->MakeBrowsingContextNonSynthetic();
200 nsContentDLF::CreateInstanceForDocument(nsISupports
* aContainer
,
202 const char* aCommand
,
203 nsIDocumentViewer
** aDocumentViewer
) {
204 MOZ_ASSERT(aDocument
);
206 nsCOMPtr
<nsIDocumentViewer
> viewer
= NS_NewDocumentViewer();
208 // Bind the document to the Content Viewer
209 viewer
->LoadStart(aDocument
);
210 viewer
.forget(aDocumentViewer
);
215 already_AddRefed
<Document
> nsContentDLF::CreateBlankDocument(
216 nsILoadGroup
* aLoadGroup
, nsIPrincipal
* aPrincipal
,
217 nsIPrincipal
* aPartitionedPrincipal
, nsDocShell
* aContainer
) {
218 // create a new blank HTML document
219 RefPtr
<Document
> blankDoc
;
220 mozilla::Unused
<< NS_NewHTMLDocument(getter_AddRefs(blankDoc
), nullptr,
228 nsCOMPtr
<nsIURI
> uri
;
229 NS_NewURI(getter_AddRefs(uri
), "about:blank"_ns
);
233 blankDoc
->ResetToURI(uri
, aLoadGroup
, aPrincipal
, aPartitionedPrincipal
);
234 blankDoc
->SetContainer(aContainer
);
236 // add some simple content structure
237 nsNodeInfoManager
* nim
= blankDoc
->NodeInfoManager();
239 RefPtr
<mozilla::dom::NodeInfo
> htmlNodeInfo
;
241 // generate an html html element
242 htmlNodeInfo
= nim
->GetNodeInfo(nsGkAtoms::html
, 0, kNameSpaceID_XHTML
,
243 nsINode::ELEMENT_NODE
);
244 nsCOMPtr
<nsIContent
> htmlElement
=
245 NS_NewHTMLHtmlElement(htmlNodeInfo
.forget());
247 // generate an html head element
248 htmlNodeInfo
= nim
->GetNodeInfo(nsGkAtoms::head
, 0, kNameSpaceID_XHTML
,
249 nsINode::ELEMENT_NODE
);
250 nsCOMPtr
<nsIContent
> headElement
=
251 NS_NewHTMLHeadElement(htmlNodeInfo
.forget());
253 // generate an html body elemment
254 htmlNodeInfo
= nim
->GetNodeInfo(nsGkAtoms::body
, 0, kNameSpaceID_XHTML
,
255 nsINode::ELEMENT_NODE
);
256 nsCOMPtr
<nsIContent
> bodyElement
=
257 NS_NewHTMLBodyElement(htmlNodeInfo
.forget());
259 // blat in the structure
260 NS_ASSERTION(blankDoc
->GetChildCount() == 0, "Shouldn't have children");
261 if (!htmlElement
|| !headElement
|| !bodyElement
) {
265 mozilla::IgnoredErrorResult rv
;
266 blankDoc
->AppendChildTo(htmlElement
, false, rv
);
271 htmlElement
->AppendChildTo(headElement
, false, rv
);
276 // XXXbz Why not notifying here?
277 htmlElement
->AppendChildTo(bodyElement
, false, rv
);
283 blankDoc
->SetDocumentCharacterSetSource(kCharsetFromDocTypeDefault
);
284 blankDoc
->SetDocumentCharacterSet(UTF_8_ENCODING
);
285 return blankDoc
.forget();
288 nsresult
nsContentDLF::CreateDocument(
289 const char* aCommand
, nsIChannel
* aChannel
, nsILoadGroup
* aLoadGroup
,
290 nsIDocShell
* aContainer
, nsContentDLF::DocumentCreator aDocumentCreator
,
291 nsIStreamListener
** aDocListener
, nsIDocumentViewer
** aDocumentViewer
) {
292 MOZ_ASSERT(aDocumentCreator
);
294 nsresult rv
= NS_ERROR_FAILURE
;
296 nsCOMPtr
<nsIURI
> aURL
;
297 rv
= aChannel
->GetURI(getter_AddRefs(aURL
));
298 if (NS_FAILED(rv
)) return rv
;
300 #ifdef NOISY_CREATE_DOC
301 if (nullptr != aURL
) {
304 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), stdout
);
305 printf(": creating document\n");
309 // Create the document
310 RefPtr
<Document
> doc
= aDocumentCreator();
311 NS_ENSURE_TRUE(doc
, NS_ERROR_FAILURE
);
313 // Create the content viewer XXX: could reuse content viewer here!
314 nsCOMPtr
<nsIDocumentViewer
> viewer
= NS_NewDocumentViewer();
316 doc
->SetContainer(static_cast<nsDocShell
*>(aContainer
));
318 // Initialize the document to begin loading the data. An
319 // nsIStreamListener connected to the parser is returned in
321 rv
= doc
->StartDocumentLoad(aCommand
, aChannel
, aLoadGroup
, aContainer
,
323 NS_ENSURE_SUCCESS(rv
, rv
);
325 // Bind the document to the Content Viewer
326 viewer
->LoadStart(doc
);
327 viewer
.forget(aDocumentViewer
);
331 bool nsContentDLF::IsImageContentType(const nsACString
& aContentType
) {
332 return imgLoader::SupportImageWithMimeType(aContentType
);