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 // XXXbz if you change the MIME types here, be sure to update
52 // nsIParser.h and DetermineParseMode in nsParser.cpp and
53 // nsHTMLDocument::StartDocumentLoad accordingly.
54 static const char* const gHTMLTypes
[] = {
61 APPLICATION_JAVASCRIPT
,
62 APPLICATION_ECMASCRIPT
,
63 APPLICATION_XJAVASCRIPT
,
65 VIEWSOURCE_CONTENT_TYPE
,
66 APPLICATION_XHTML_XML
,
70 static const char* const gXMLTypes
[] = {
73 APPLICATION_MATHML_XML
,
79 static const char* const gSVGTypes
[] = {
84 static const char* const gXULTypes
[] = {
86 APPLICATION_CACHED_XUL
,
91 NS_NewContentDocumentLoaderFactory(nsIDocumentLoaderFactory
** aResult
)
93 NS_PRECONDITION(aResult
, "null OUT ptr");
95 return NS_ERROR_NULL_POINTER
;
97 nsContentDLF
* it
= new nsContentDLF();
99 return NS_ERROR_OUT_OF_MEMORY
;
102 return CallQueryInterface(it
, aResult
);
105 nsContentDLF::nsContentDLF()
109 nsContentDLF::~nsContentDLF()
113 NS_IMPL_ISUPPORTS(nsContentDLF
,
114 nsIDocumentLoaderFactory
)
117 MayUseXULXBL(nsIChannel
* aChannel
)
119 nsIScriptSecurityManager
*securityManager
=
120 nsContentUtils::GetSecurityManager();
121 if (!securityManager
) {
125 nsCOMPtr
<nsIPrincipal
> principal
;
126 securityManager
->GetChannelPrincipal(aChannel
, getter_AddRefs(principal
));
127 NS_ENSURE_TRUE(principal
, false);
129 return nsContentUtils::AllowXULXBLForPrincipal(principal
);
133 nsContentDLF::CreateInstance(const char* aCommand
,
134 nsIChannel
* aChannel
,
135 nsILoadGroup
* aLoadGroup
,
136 const char* aContentType
,
137 nsIDocShell
* aContainer
,
138 nsISupports
* aExtraInfo
,
139 nsIStreamListener
** aDocListener
,
140 nsIContentViewer
** aDocViewer
)
142 // Declare "type" here. This is because although the variable itself only
143 // needs limited scope, we need to use the raw string memory -- as returned
144 // by "type.get()" farther down in the function.
147 // Are we viewing source?
148 nsCOMPtr
<nsIViewSourceChannel
> viewSourceChannel
= do_QueryInterface(aChannel
);
149 if (viewSourceChannel
)
151 aCommand
= "view-source";
153 // The parser freaks out when it sees the content-type that a
154 // view-source channel normally returns. Get the actual content
155 // type of the data. If it's known, use it; otherwise use
157 viewSourceChannel
->GetOriginalContentType(type
);
158 bool knownType
= false;
160 for (typeIndex
= 0; gHTMLTypes
[typeIndex
] && !knownType
; ++typeIndex
) {
161 if (type
.Equals(gHTMLTypes
[typeIndex
]) &&
162 !type
.EqualsLiteral(VIEWSOURCE_CONTENT_TYPE
)) {
167 for (typeIndex
= 0; gXMLTypes
[typeIndex
] && !knownType
; ++typeIndex
) {
168 if (type
.Equals(gXMLTypes
[typeIndex
])) {
173 for (typeIndex
= 0; gSVGTypes
[typeIndex
] && !knownType
; ++typeIndex
) {
174 if (type
.Equals(gSVGTypes
[typeIndex
])) {
179 for (typeIndex
= 0; gXULTypes
[typeIndex
] && !knownType
; ++typeIndex
) {
180 if (type
.Equals(gXULTypes
[typeIndex
])) {
186 viewSourceChannel
->SetContentType(type
);
187 } else if (IsImageContentType(type
.get())) {
188 // If it's an image, we want to display it the same way we normally would.
189 // Also note the lifetime of "type" allows us to safely use "get()" here.
190 aContentType
= type
.get();
192 viewSourceChannel
->SetContentType(NS_LITERAL_CSTRING(TEXT_PLAIN
));
194 } else if (0 == PL_strcmp(VIEWSOURCE_CONTENT_TYPE
, aContentType
)) {
195 aChannel
->SetContentType(NS_LITERAL_CSTRING(TEXT_PLAIN
));
196 aContentType
= TEXT_PLAIN
;
200 while(gHTMLTypes
[typeIndex
]) {
201 if (0 == PL_strcmp(gHTMLTypes
[typeIndex
++], aContentType
)) {
202 return CreateDocument(aCommand
,
203 aChannel
, aLoadGroup
,
204 aContainer
, kHTMLDocumentCID
,
205 aDocListener
, aDocViewer
);
211 while(gXMLTypes
[typeIndex
]) {
212 if (0== PL_strcmp(gXMLTypes
[typeIndex
++], aContentType
)) {
213 return CreateDocument(aCommand
,
214 aChannel
, aLoadGroup
,
215 aContainer
, kXMLDocumentCID
,
216 aDocListener
, aDocViewer
);
222 while(gSVGTypes
[typeIndex
]) {
223 if (!PL_strcmp(gSVGTypes
[typeIndex
++], aContentType
)) {
224 return CreateDocument(aCommand
,
225 aChannel
, aLoadGroup
,
226 aContainer
, kSVGDocumentCID
,
227 aDocListener
, aDocViewer
);
233 while (gXULTypes
[typeIndex
]) {
234 if (0 == PL_strcmp(gXULTypes
[typeIndex
++], aContentType
)) {
235 if (!MayUseXULXBL(aChannel
)) {
236 return NS_ERROR_REMOTE_XUL
;
239 return CreateXULDocument(aCommand
,
240 aChannel
, aLoadGroup
,
241 aContentType
, aContainer
,
242 aExtraInfo
, aDocListener
, aDocViewer
);
246 if (mozilla::DecoderTraits::ShouldHandleMediaType(aContentType
)) {
247 return CreateDocument(aCommand
,
248 aChannel
, aLoadGroup
,
249 aContainer
, kVideoDocumentCID
,
250 aDocListener
, aDocViewer
);
254 if (IsImageContentType(aContentType
)) {
255 return CreateDocument(aCommand
,
256 aChannel
, aLoadGroup
,
257 aContainer
, kImageDocumentCID
,
258 aDocListener
, aDocViewer
);
261 nsCOMPtr
<nsIPluginHost
> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID
));
262 nsPluginHost
*pluginHost
= static_cast<nsPluginHost
*>(pluginHostCOM
.get());
264 pluginHost
->PluginExistsForType(aContentType
)) {
265 return CreateDocument(aCommand
,
266 aChannel
, aLoadGroup
,
267 aContainer
, kPluginDocumentCID
,
268 aDocListener
, aDocViewer
);
271 // If we get here, then we weren't able to create anything. Sorry!
272 return NS_ERROR_FAILURE
;
277 nsContentDLF::CreateInstanceForDocument(nsISupports
* aContainer
,
278 nsIDocument
* aDocument
,
279 const char *aCommand
,
280 nsIContentViewer
** aContentViewer
)
282 MOZ_ASSERT(aDocument
);
284 nsCOMPtr
<nsIContentViewer
> contentViewer
= NS_NewContentViewer();
286 // Bind the document to the Content Viewer
287 contentViewer
->LoadStart(aDocument
);
288 contentViewer
.forget(aContentViewer
);
293 nsContentDLF::CreateBlankDocument(nsILoadGroup
*aLoadGroup
,
294 nsIPrincipal
* aPrincipal
,
295 nsIDocument
**aDocument
)
297 *aDocument
= nullptr;
299 nsresult rv
= NS_ERROR_FAILURE
;
301 // create a new blank HTML document
302 nsCOMPtr
<nsIDocument
> blankDoc(do_CreateInstance(kHTMLDocumentCID
));
306 nsCOMPtr
<nsIURI
> uri
;
307 NS_NewURI(getter_AddRefs(uri
), NS_LITERAL_CSTRING("about:blank"));
309 blankDoc
->ResetToURI(uri
, aLoadGroup
, aPrincipal
);
314 // add some simple content structure
315 if (NS_SUCCEEDED(rv
)) {
316 rv
= NS_ERROR_FAILURE
;
318 nsNodeInfoManager
*nim
= blankDoc
->NodeInfoManager();
320 nsRefPtr
<mozilla::dom::NodeInfo
> htmlNodeInfo
;
322 // generate an html html element
323 htmlNodeInfo
= nim
->GetNodeInfo(nsGkAtoms::html
, 0, kNameSpaceID_XHTML
,
324 nsIDOMNode::ELEMENT_NODE
);
325 nsCOMPtr
<nsIContent
> htmlElement
=
326 NS_NewHTMLHtmlElement(htmlNodeInfo
.forget());
328 // generate an html head element
329 htmlNodeInfo
= nim
->GetNodeInfo(nsGkAtoms::head
, 0, kNameSpaceID_XHTML
,
330 nsIDOMNode::ELEMENT_NODE
);
331 nsCOMPtr
<nsIContent
> headElement
=
332 NS_NewHTMLHeadElement(htmlNodeInfo
.forget());
334 // generate an html body elemment
335 htmlNodeInfo
= nim
->GetNodeInfo(nsGkAtoms::body
, 0, kNameSpaceID_XHTML
,
336 nsIDOMNode::ELEMENT_NODE
);
337 nsCOMPtr
<nsIContent
> bodyElement
=
338 NS_NewHTMLBodyElement(htmlNodeInfo
.forget());
340 // blat in the structure
341 if (htmlElement
&& headElement
&& bodyElement
) {
342 NS_ASSERTION(blankDoc
->GetChildCount() == 0,
343 "Shouldn't have children");
344 rv
= blankDoc
->AppendChildTo(htmlElement
, false);
345 if (NS_SUCCEEDED(rv
)) {
346 rv
= htmlElement
->AppendChildTo(headElement
, false);
348 if (NS_SUCCEEDED(rv
)) {
349 // XXXbz Why not notifying here?
350 htmlElement
->AppendChildTo(bodyElement
, false);
357 if (NS_SUCCEEDED(rv
)) {
358 blankDoc
->SetDocumentCharacterSetSource(kCharsetFromDocTypeDefault
);
359 blankDoc
->SetDocumentCharacterSet(NS_LITERAL_CSTRING("UTF-8"));
361 *aDocument
= blankDoc
;
362 NS_ADDREF(*aDocument
);
369 nsContentDLF::CreateDocument(const char* aCommand
,
370 nsIChannel
* aChannel
,
371 nsILoadGroup
* aLoadGroup
,
372 nsIDocShell
* aContainer
,
373 const nsCID
& aDocumentCID
,
374 nsIStreamListener
** aDocListener
,
375 nsIContentViewer
** aContentViewer
)
377 nsresult rv
= NS_ERROR_FAILURE
;
379 nsCOMPtr
<nsIURI
> aURL
;
380 rv
= aChannel
->GetURI(getter_AddRefs(aURL
));
381 if (NS_FAILED(rv
)) return rv
;
383 #ifdef NOISY_CREATE_DOC
384 if (nullptr != aURL
) {
387 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), stdout
);
388 printf(": creating document\n");
392 // Create the document
393 nsCOMPtr
<nsIDocument
> doc
= do_CreateInstance(aDocumentCID
, &rv
);
394 NS_ENSURE_SUCCESS(rv
, rv
);
396 // Create the content viewer XXX: could reuse content viewer here!
397 nsCOMPtr
<nsIContentViewer
> contentViewer
= NS_NewContentViewer();
399 doc
->SetContainer(static_cast<nsDocShell
*>(aContainer
));
401 // Initialize the document to begin loading the data. An
402 // nsIStreamListener connected to the parser is returned in
404 rv
= doc
->StartDocumentLoad(aCommand
, aChannel
, aLoadGroup
, aContainer
, aDocListener
, true);
405 NS_ENSURE_SUCCESS(rv
, rv
);
407 // Bind the document to the Content Viewer
408 contentViewer
->LoadStart(doc
);
409 contentViewer
.forget(aContentViewer
);
414 nsContentDLF::CreateXULDocument(const char* aCommand
,
415 nsIChannel
* aChannel
,
416 nsILoadGroup
* aLoadGroup
,
417 const char* aContentType
,
418 nsIDocShell
* aContainer
,
419 nsISupports
* aExtraInfo
,
420 nsIStreamListener
** aDocListener
,
421 nsIContentViewer
** aContentViewer
)
424 nsCOMPtr
<nsIDocument
> doc
= do_CreateInstance(kXULDocumentCID
, &rv
);
425 if (NS_FAILED(rv
)) return rv
;
427 nsCOMPtr
<nsIContentViewer
> contentViewer
= NS_NewContentViewer();
429 nsCOMPtr
<nsIURI
> aURL
;
430 rv
= aChannel
->GetURI(getter_AddRefs(aURL
));
431 if (NS_FAILED(rv
)) return rv
;
434 * Initialize the document to begin loading the data...
436 * An nsIStreamListener connected to the parser is returned in
440 doc
->SetContainer(static_cast<nsDocShell
*>(aContainer
));
442 rv
= doc
->StartDocumentLoad(aCommand
, aChannel
, aLoadGroup
, aContainer
, aDocListener
, true);
443 if (NS_FAILED(rv
)) return rv
;
446 * Bind the document to the Content Viewer...
448 contentViewer
->LoadStart(doc
);
449 contentViewer
.forget(aContentViewer
);
453 bool nsContentDLF::IsImageContentType(const char* aContentType
) {
454 return imgLoader::SupportImageWithMimeType(aContentType
);