1 /* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=78: */
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 "nsContentDLF.h"
8 #include "nsDocShell.h"
9 #include "nsGenericHTMLElement.h"
10 #include "nsGkAtoms.h"
11 #include "nsIComponentManager.h"
12 #include "nsIComponentRegistrar.h"
13 #include "nsIContentViewer.h"
14 #include "nsICategoryManager.h"
15 #include "nsIDocumentLoaderFactory.h"
16 #include "nsIDocument.h"
18 #include "nsNodeInfoManager.h"
19 #include "nsIScriptSecurityManager.h"
21 #include "nsContentCID.h"
23 #include "nsNetUtil.h"
25 #include "nsIViewSourceChannel.h"
26 #include "nsContentUtils.h"
27 #include "imgLoader.h"
28 #include "nsCharsetSource.h"
29 #include "nsMimeTypes.h"
30 #include "DecoderTraits.h"
34 #include "nsIPluginHost.h"
35 #include "nsPluginHost.h"
36 static NS_DEFINE_CID(kPluginDocumentCID
, NS_PLUGINDOCUMENT_CID
);
38 // Factory code for creating variations on html documents
42 static NS_DEFINE_IID(kHTMLDocumentCID
, NS_HTMLDOCUMENT_CID
);
43 static NS_DEFINE_IID(kXMLDocumentCID
, NS_XMLDOCUMENT_CID
);
44 static NS_DEFINE_IID(kSVGDocumentCID
, NS_SVGDOCUMENT_CID
);
45 static NS_DEFINE_IID(kVideoDocumentCID
, NS_VIDEODOCUMENT_CID
);
46 static NS_DEFINE_IID(kImageDocumentCID
, NS_IMAGEDOCUMENT_CID
);
47 static NS_DEFINE_IID(kXULDocumentCID
, NS_XULDOCUMENT_CID
);
49 already_AddRefed
<nsIContentViewer
> NS_NewContentViewer();
51 static const char* const gHTMLTypes
[] = {
53 VIEWSOURCE_CONTENT_TYPE
,
54 APPLICATION_XHTML_XML
,
58 static const char* const gXMLTypes
[] = {
61 APPLICATION_MATHML_XML
,
67 static const char* const gSVGTypes
[] = {
72 static const char* const gXULTypes
[] = {
74 APPLICATION_CACHED_XUL
,
79 IsTypeInList(const nsACString
& aType
, const char* const aList
[])
82 for (typeIndex
= 0; aList
[typeIndex
]; ++typeIndex
) {
83 if (aType
.Equals(aList
[typeIndex
])) {
92 NS_NewContentDocumentLoaderFactory(nsIDocumentLoaderFactory
** aResult
)
94 NS_PRECONDITION(aResult
, "null OUT ptr");
96 return NS_ERROR_NULL_POINTER
;
98 nsContentDLF
* it
= new nsContentDLF();
100 return NS_ERROR_OUT_OF_MEMORY
;
103 return CallQueryInterface(it
, aResult
);
106 nsContentDLF::nsContentDLF()
110 nsContentDLF::~nsContentDLF()
114 NS_IMPL_ISUPPORTS(nsContentDLF
,
115 nsIDocumentLoaderFactory
)
118 MayUseXULXBL(nsIChannel
* aChannel
)
120 nsIScriptSecurityManager
*securityManager
=
121 nsContentUtils::GetSecurityManager();
122 if (!securityManager
) {
126 nsCOMPtr
<nsIPrincipal
> principal
;
127 securityManager
->GetChannelResultPrincipal(aChannel
, getter_AddRefs(principal
));
128 NS_ENSURE_TRUE(principal
, false);
130 return nsContentUtils::AllowXULXBLForPrincipal(principal
);
134 nsContentDLF::CreateInstance(const char* aCommand
,
135 nsIChannel
* aChannel
,
136 nsILoadGroup
* aLoadGroup
,
137 const nsACString
& aContentType
,
138 nsIDocShell
* aContainer
,
139 nsISupports
* aExtraInfo
,
140 nsIStreamListener
** aDocListener
,
141 nsIContentViewer
** aDocViewer
)
143 // Make a copy of aContentType, because we're possibly going to change it.
144 nsAutoCString
contentType(aContentType
);
146 // Are we viewing source?
147 nsCOMPtr
<nsIViewSourceChannel
> viewSourceChannel
= do_QueryInterface(aChannel
);
148 if (viewSourceChannel
)
150 aCommand
= "view-source";
152 // The parser freaks out when it sees the content-type that a
153 // view-source channel normally returns. Get the actual content
154 // type of the data. If it's known, use it; otherwise use
157 viewSourceChannel
->GetOriginalContentType(type
);
159 (!type
.EqualsLiteral(VIEWSOURCE_CONTENT_TYPE
) &&
160 IsTypeInList(type
, gHTMLTypes
)) ||
161 nsContentUtils::IsPlainTextType(type
) ||
162 IsTypeInList(type
, gXMLTypes
) ||
163 IsTypeInList(type
, gSVGTypes
) ||
164 IsTypeInList(type
, gXMLTypes
);
167 viewSourceChannel
->SetContentType(type
);
168 } else if (IsImageContentType(type
.get())) {
169 // If it's an image, we want to display it the same way we normally would.
170 // Also note the lifetime of "type" allows us to safely use "get()" here.
173 viewSourceChannel
->SetContentType(NS_LITERAL_CSTRING(TEXT_PLAIN
));
175 } else if (aContentType
.EqualsLiteral(VIEWSOURCE_CONTENT_TYPE
)) {
176 aChannel
->SetContentType(NS_LITERAL_CSTRING(TEXT_PLAIN
));
177 contentType
= TEXT_PLAIN
;
180 // Try html or plaintext; both use the same document CID
181 if (IsTypeInList(contentType
, gHTMLTypes
) ||
182 nsContentUtils::IsPlainTextType(contentType
)) {
183 return CreateDocument(aCommand
,
184 aChannel
, aLoadGroup
,
185 aContainer
, kHTMLDocumentCID
,
186 aDocListener
, aDocViewer
);
190 if (IsTypeInList(contentType
, gXMLTypes
)) {
191 return CreateDocument(aCommand
,
192 aChannel
, aLoadGroup
,
193 aContainer
, kXMLDocumentCID
,
194 aDocListener
, aDocViewer
);
198 if (IsTypeInList(contentType
, gSVGTypes
)) {
199 return CreateDocument(aCommand
,
200 aChannel
, aLoadGroup
,
201 aContainer
, kSVGDocumentCID
,
202 aDocListener
, aDocViewer
);
206 if (IsTypeInList(contentType
, gXULTypes
)) {
207 if (!MayUseXULXBL(aChannel
)) {
208 return NS_ERROR_REMOTE_XUL
;
211 return CreateXULDocument(aCommand
, aChannel
, aLoadGroup
, aContainer
,
212 aExtraInfo
, aDocListener
, aDocViewer
);
215 if (mozilla::DecoderTraits::ShouldHandleMediaType(contentType
.get())) {
216 return CreateDocument(aCommand
,
217 aChannel
, aLoadGroup
,
218 aContainer
, kVideoDocumentCID
,
219 aDocListener
, aDocViewer
);
223 if (IsImageContentType(contentType
.get())) {
224 return CreateDocument(aCommand
,
225 aChannel
, aLoadGroup
,
226 aContainer
, kImageDocumentCID
,
227 aDocListener
, aDocViewer
);
230 RefPtr
<nsPluginHost
> pluginHost
= nsPluginHost::GetInst();
231 // Don't exclude disabled plugins, which will still trigger the "this plugin
232 // is disabled" placeholder.
233 if (pluginHost
&& pluginHost
->HavePluginForType(contentType
,
234 nsPluginHost::eExcludeNone
)) {
235 return CreateDocument(aCommand
,
236 aChannel
, aLoadGroup
,
237 aContainer
, kPluginDocumentCID
,
238 aDocListener
, aDocViewer
);
241 // If we get here, then we weren't able to create anything. Sorry!
242 return NS_ERROR_FAILURE
;
247 nsContentDLF::CreateInstanceForDocument(nsISupports
* aContainer
,
248 nsIDocument
* aDocument
,
249 const char *aCommand
,
250 nsIContentViewer
** aContentViewer
)
252 MOZ_ASSERT(aDocument
);
254 nsCOMPtr
<nsIContentViewer
> contentViewer
= NS_NewContentViewer();
256 // Bind the document to the Content Viewer
257 contentViewer
->LoadStart(aDocument
);
258 contentViewer
.forget(aContentViewer
);
263 nsContentDLF::CreateBlankDocument(nsILoadGroup
*aLoadGroup
,
264 nsIPrincipal
* aPrincipal
,
265 nsIDocument
**aDocument
)
267 *aDocument
= nullptr;
269 nsresult rv
= NS_ERROR_FAILURE
;
271 // create a new blank HTML document
272 nsCOMPtr
<nsIDocument
> blankDoc(do_CreateInstance(kHTMLDocumentCID
));
276 nsCOMPtr
<nsIURI
> uri
;
277 NS_NewURI(getter_AddRefs(uri
), NS_LITERAL_CSTRING("about:blank"));
279 blankDoc
->ResetToURI(uri
, aLoadGroup
, aPrincipal
);
284 // add some simple content structure
285 if (NS_SUCCEEDED(rv
)) {
286 rv
= NS_ERROR_FAILURE
;
288 nsNodeInfoManager
*nim
= blankDoc
->NodeInfoManager();
290 RefPtr
<mozilla::dom::NodeInfo
> htmlNodeInfo
;
292 // generate an html html element
293 htmlNodeInfo
= nim
->GetNodeInfo(nsGkAtoms::html
, 0, kNameSpaceID_XHTML
,
294 nsIDOMNode::ELEMENT_NODE
);
295 nsCOMPtr
<nsIContent
> htmlElement
=
296 NS_NewHTMLHtmlElement(htmlNodeInfo
.forget());
298 // generate an html head element
299 htmlNodeInfo
= nim
->GetNodeInfo(nsGkAtoms::head
, 0, kNameSpaceID_XHTML
,
300 nsIDOMNode::ELEMENT_NODE
);
301 nsCOMPtr
<nsIContent
> headElement
=
302 NS_NewHTMLHeadElement(htmlNodeInfo
.forget());
304 // generate an html body elemment
305 htmlNodeInfo
= nim
->GetNodeInfo(nsGkAtoms::body
, 0, kNameSpaceID_XHTML
,
306 nsIDOMNode::ELEMENT_NODE
);
307 nsCOMPtr
<nsIContent
> bodyElement
=
308 NS_NewHTMLBodyElement(htmlNodeInfo
.forget());
310 // blat in the structure
311 if (htmlElement
&& headElement
&& bodyElement
) {
312 NS_ASSERTION(blankDoc
->GetChildCount() == 0,
313 "Shouldn't have children");
314 rv
= blankDoc
->AppendChildTo(htmlElement
, false);
315 if (NS_SUCCEEDED(rv
)) {
316 rv
= htmlElement
->AppendChildTo(headElement
, false);
318 if (NS_SUCCEEDED(rv
)) {
319 // XXXbz Why not notifying here?
320 htmlElement
->AppendChildTo(bodyElement
, false);
327 if (NS_SUCCEEDED(rv
)) {
328 blankDoc
->SetDocumentCharacterSetSource(kCharsetFromDocTypeDefault
);
329 blankDoc
->SetDocumentCharacterSet(NS_LITERAL_CSTRING("UTF-8"));
331 *aDocument
= blankDoc
;
332 NS_ADDREF(*aDocument
);
339 nsContentDLF::CreateDocument(const char* aCommand
,
340 nsIChannel
* aChannel
,
341 nsILoadGroup
* aLoadGroup
,
342 nsIDocShell
* aContainer
,
343 const nsCID
& aDocumentCID
,
344 nsIStreamListener
** aDocListener
,
345 nsIContentViewer
** aContentViewer
)
347 nsresult rv
= NS_ERROR_FAILURE
;
349 nsCOMPtr
<nsIURI
> aURL
;
350 rv
= aChannel
->GetURI(getter_AddRefs(aURL
));
351 if (NS_FAILED(rv
)) return rv
;
353 #ifdef NOISY_CREATE_DOC
354 if (nullptr != aURL
) {
357 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), stdout
);
358 printf(": creating document\n");
362 // Create the document
363 nsCOMPtr
<nsIDocument
> doc
= do_CreateInstance(aDocumentCID
, &rv
);
364 NS_ENSURE_SUCCESS(rv
, rv
);
366 // Create the content viewer XXX: could reuse content viewer here!
367 nsCOMPtr
<nsIContentViewer
> contentViewer
= NS_NewContentViewer();
369 doc
->SetContainer(static_cast<nsDocShell
*>(aContainer
));
371 // Initialize the document to begin loading the data. An
372 // nsIStreamListener connected to the parser is returned in
374 rv
= doc
->StartDocumentLoad(aCommand
, aChannel
, aLoadGroup
, aContainer
, aDocListener
, true);
375 NS_ENSURE_SUCCESS(rv
, rv
);
377 // Bind the document to the Content Viewer
378 contentViewer
->LoadStart(doc
);
379 contentViewer
.forget(aContentViewer
);
384 nsContentDLF::CreateXULDocument(const char* aCommand
,
385 nsIChannel
* aChannel
,
386 nsILoadGroup
* aLoadGroup
,
387 nsIDocShell
* aContainer
,
388 nsISupports
* aExtraInfo
,
389 nsIStreamListener
** aDocListener
,
390 nsIContentViewer
** aContentViewer
)
393 nsCOMPtr
<nsIDocument
> doc
= do_CreateInstance(kXULDocumentCID
, &rv
);
394 if (NS_FAILED(rv
)) return rv
;
396 nsCOMPtr
<nsIContentViewer
> contentViewer
= NS_NewContentViewer();
398 nsCOMPtr
<nsIURI
> aURL
;
399 rv
= aChannel
->GetURI(getter_AddRefs(aURL
));
400 if (NS_FAILED(rv
)) return rv
;
403 * Initialize the document to begin loading the data...
405 * An nsIStreamListener connected to the parser is returned in
409 doc
->SetContainer(static_cast<nsDocShell
*>(aContainer
));
411 rv
= doc
->StartDocumentLoad(aCommand
, aChannel
, aLoadGroup
, aContainer
, aDocListener
, true);
412 if (NS_FAILED(rv
)) return rv
;
415 * Bind the document to the Content Viewer...
417 contentViewer
->LoadStart(doc
);
418 contentViewer
.forget(aContentViewer
);
422 bool nsContentDLF::IsImageContentType(const char* aContentType
) {
423 return imgLoader::SupportImageWithMimeType(aContentType
);