nsContentDLF.cpp (10875B)
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" 7 8 #include "DecoderTraits.h" 9 #include "imgLoader.h" 10 #include "mozilla/Encoding.h" 11 #include "mozilla/dom/Document.h" 12 #include "mozilla/dom/LoadURIOptionsBinding.h" 13 #include "nsCOMPtr.h" 14 #include "nsCRT.h" 15 #include "nsCharsetSource.h" 16 #include "nsContentUtils.h" 17 #include "nsDocShell.h" 18 #include "nsGenericHTMLElement.h" 19 #include "nsGkAtoms.h" 20 #include "nsIDocumentLoaderFactory.h" 21 #include "nsIDocumentViewer.h" 22 #include "nsIViewSourceChannel.h" 23 #include "nsMimeTypes.h" 24 #include "nsNetUtil.h" 25 #include "nsNodeInfoManager.h" 26 #include "nsString.h" 27 28 // Factory code for creating variations on html documents 29 30 #undef NOISY_REGISTRY 31 32 using namespace mozilla; 33 using mozilla::dom::Document; 34 using mozilla::dom::ForceMediaDocument; 35 36 already_AddRefed<nsIDocumentViewer> NS_NewDocumentViewer(); 37 38 static const char* const gHTMLTypes[] = {TEXT_HTML, VIEWSOURCE_CONTENT_TYPE, 39 APPLICATION_XHTML_XML, 40 APPLICATION_WAPXHTML_XML, 0}; 41 42 static const char* const gXMLTypes[] = {TEXT_XML, 43 APPLICATION_XML, 44 APPLICATION_MATHML_XML, 45 APPLICATION_RDF_XML, 46 TEXT_RDF, 47 0}; 48 49 static const char* const gSVGTypes[] = {IMAGE_SVG_XML, 0}; 50 51 static bool IsTypeInList(const nsACString& aType, const char* const aList[]) { 52 int32_t typeIndex; 53 for (typeIndex = 0; aList[typeIndex]; ++typeIndex) { 54 if (aType.Equals(aList[typeIndex])) { 55 return true; 56 } 57 } 58 59 return false; 60 } 61 62 nsresult NS_NewContentDocumentLoaderFactory( 63 nsIDocumentLoaderFactory** aResult) { 64 MOZ_ASSERT(aResult, "null OUT ptr"); 65 if (!aResult) { 66 return NS_ERROR_NULL_POINTER; 67 } 68 auto it = MakeRefPtr<nsContentDLF>(); 69 it.forget(aResult); 70 return NS_OK; 71 } 72 73 nsContentDLF::nsContentDLF() = default; 74 75 nsContentDLF::~nsContentDLF() = default; 76 77 NS_IMPL_ISUPPORTS(nsContentDLF, nsIDocumentLoaderFactory) 78 79 enum class CreateDocumentKind { HTML, XML, SVG, Video, Image, None }; 80 81 static CreateDocumentKind GetCreateDocumentKind(nsACString& aContentType) { 82 // HTML or plaintext; both use the same document CID 83 if (IsTypeInList(aContentType, gHTMLTypes) || 84 nsContentUtils::IsPlainTextType(aContentType)) { 85 return CreateDocumentKind::HTML; 86 } 87 88 if (IsTypeInList(aContentType, gXMLTypes)) { 89 return CreateDocumentKind::XML; 90 } 91 92 if (IsTypeInList(aContentType, gSVGTypes)) { 93 return CreateDocumentKind::SVG; 94 } 95 96 if (mozilla::DecoderTraits::ShouldHandleMediaType( 97 aContentType, 98 /* DecoderDoctorDiagnostics* */ nullptr)) { 99 return CreateDocumentKind::Video; 100 } 101 102 if (imgLoader::SupportImageWithMimeType(aContentType)) { 103 return CreateDocumentKind::Image; 104 } 105 106 return CreateDocumentKind::None; 107 } 108 109 static nsresult CreateDocument(const char* aCommand, nsIChannel* aChannel, 110 nsILoadGroup* aLoadGroup, 111 nsIDocShell* aContainer, 112 CreateDocumentKind aKind, 113 nsIStreamListener** aDocListener, 114 nsIDocumentViewer** aDocumentViewer) { 115 // Create the document 116 RefPtr<Document> doc; 117 nsresult rv; 118 switch (aKind) { 119 case CreateDocumentKind::HTML: 120 rv = NS_NewHTMLDocument(getter_AddRefs(doc), nullptr, nullptr); 121 break; 122 case CreateDocumentKind::XML: 123 rv = NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr); 124 break; 125 case CreateDocumentKind::SVG: 126 rv = NS_NewSVGDocument(getter_AddRefs(doc), nullptr, nullptr); 127 break; 128 case CreateDocumentKind::Video: 129 rv = NS_NewVideoDocument(getter_AddRefs(doc), nullptr, nullptr); 130 break; 131 case CreateDocumentKind::Image: 132 rv = NS_NewImageDocument(getter_AddRefs(doc), nullptr, nullptr); 133 break; 134 case CreateDocumentKind::None: 135 MOZ_ASSERT_UNREACHABLE("Invalid kind."); 136 rv = NS_ERROR_FAILURE; 137 break; 138 } 139 NS_ENSURE_SUCCESS(rv, rv); 140 141 // Create the content viewer XXX: could reuse content viewer here! 142 nsCOMPtr<nsIDocumentViewer> viewer = NS_NewDocumentViewer(); 143 144 doc->SetContainer(static_cast<nsDocShell*>(aContainer)); 145 doc->SetAllowDeclarativeShadowRoots(true); 146 147 // Initialize the document to begin loading the data. An 148 // nsIStreamListener connected to the parser is returned in 149 // aDocListener. 150 rv = doc->StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer, 151 aDocListener, true); 152 NS_ENSURE_SUCCESS(rv, rv); 153 154 // Bind the document to the Content Viewer 155 viewer->LoadStart(doc); 156 157 if (aKind != CreateDocumentKind::Image) { 158 viewer->GetDocument()->MakeBrowsingContextNonSynthetic(); 159 } 160 161 viewer.forget(aDocumentViewer); 162 return NS_OK; 163 } 164 165 NS_IMETHODIMP 166 nsContentDLF::CreateInstance(const char* aCommand, nsIChannel* aChannel, 167 nsILoadGroup* aLoadGroup, 168 const nsACString& aContentType, 169 nsIDocShell* aContainer, nsISupports* aExtraInfo, 170 nsIStreamListener** aDocListener, 171 nsIDocumentViewer** aDocViewer) { 172 // Make a copy of aContentType, because we're possibly going to change it. 173 nsAutoCString contentType(aContentType); 174 175 // Are we viewing source? 176 nsCOMPtr<nsIViewSourceChannel> viewSourceChannel = 177 do_QueryInterface(aChannel); 178 if (viewSourceChannel) { 179 aCommand = "view-source"; 180 181 // The parser freaks out when it sees the content-type that a 182 // view-source channel normally returns. Get the actual content 183 // type of the data. If it's known, use it; otherwise use 184 // text/plain. 185 nsAutoCString type; 186 (void)viewSourceChannel->GetOriginalContentType(type); 187 bool knownType = (!type.EqualsLiteral(VIEWSOURCE_CONTENT_TYPE) && 188 IsTypeInList(type, gHTMLTypes)) || 189 nsContentUtils::IsPlainTextType(type) || 190 IsTypeInList(type, gXMLTypes) || 191 IsTypeInList(type, gSVGTypes); 192 193 if (knownType) { 194 viewSourceChannel->SetContentType(type); 195 } else if (imgLoader::SupportImageWithMimeType(type)) { 196 // If it's an image, we want to display it the same way we normally would. 197 contentType = type; 198 } else { 199 viewSourceChannel->SetContentType(nsLiteralCString(TEXT_PLAIN)); 200 } 201 } else if (aContentType.EqualsLiteral(VIEWSOURCE_CONTENT_TYPE)) { 202 aChannel->SetContentType(nsLiteralCString(TEXT_PLAIN)); 203 contentType = TEXT_PLAIN; 204 } 205 206 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); 207 CreateDocumentKind kind = CreateDocumentKind::None; 208 // SVGDocumentWrapper::SetupViewer needs to be able to create a proper SVG 209 // document internally even when creating an ImageDocument. 210 if ((!aCommand || strcmp(aCommand, "external-resource") != 0) && 211 loadInfo->GetForceMediaDocument() != ForceMediaDocument::None) { 212 switch (loadInfo->GetForceMediaDocument()) { 213 case dom::ForceMediaDocument::Video: 214 kind = CreateDocumentKind::Video; 215 break; 216 case dom::ForceMediaDocument::Image: 217 kind = CreateDocumentKind::Image; 218 break; 219 case dom::ForceMediaDocument::None: 220 MOZ_ASSERT_UNREACHABLE("Can't be None"); 221 break; 222 } 223 } else { 224 kind = GetCreateDocumentKind(contentType); 225 } 226 227 if (kind == CreateDocumentKind::None) { 228 // We can't handle this content type. Sorry! 229 return NS_ERROR_FAILURE; 230 } 231 232 return CreateDocument(aCommand, aChannel, aLoadGroup, aContainer, kind, 233 aDocListener, aDocViewer); 234 } 235 236 NS_IMETHODIMP 237 nsContentDLF::CreateInstanceForDocument(nsISupports* aContainer, 238 Document* aDocument, 239 const char* aCommand, 240 nsIDocumentViewer** aDocumentViewer) { 241 MOZ_ASSERT(aDocument); 242 243 nsCOMPtr<nsIDocumentViewer> viewer = NS_NewDocumentViewer(); 244 245 // Bind the document to the Content Viewer 246 viewer->LoadStart(aDocument); 247 viewer.forget(aDocumentViewer); 248 return NS_OK; 249 } 250 251 /* static */ 252 already_AddRefed<Document> nsContentDLF::CreateBlankDocument( 253 nsILoadGroup* aLoadGroup, nsIPrincipal* aPrincipal, 254 nsIPrincipal* aPartitionedPrincipal, nsDocShell* aContainer) { 255 // create a new blank HTML document 256 RefPtr<Document> blankDoc; 257 (void)NS_NewHTMLDocument(getter_AddRefs(blankDoc), nullptr, nullptr); 258 259 if (!blankDoc) { 260 return nullptr; 261 } 262 263 // initialize 264 nsCOMPtr<nsIURI> uri; 265 NS_NewURI(getter_AddRefs(uri), "about:blank"_ns); 266 if (!uri) { 267 return nullptr; 268 } 269 blankDoc->ResetToURI(uri, aLoadGroup, aPrincipal, aPartitionedPrincipal); 270 blankDoc->SetContainer(aContainer); 271 272 blankDoc->SetAllowDeclarativeShadowRoots(true); 273 274 // add some simple content structure 275 nsNodeInfoManager* nim = blankDoc->NodeInfoManager(); 276 277 RefPtr<mozilla::dom::NodeInfo> htmlNodeInfo; 278 279 // generate an html html element 280 htmlNodeInfo = nim->GetNodeInfo(nsGkAtoms::html, 0, kNameSpaceID_XHTML, 281 nsINode::ELEMENT_NODE); 282 nsCOMPtr<nsIContent> htmlElement = 283 NS_NewHTMLHtmlElement(htmlNodeInfo.forget()); 284 285 // generate an html head element 286 htmlNodeInfo = nim->GetNodeInfo(nsGkAtoms::head, 0, kNameSpaceID_XHTML, 287 nsINode::ELEMENT_NODE); 288 nsCOMPtr<nsIContent> headElement = 289 NS_NewHTMLHeadElement(htmlNodeInfo.forget()); 290 291 // generate an html body elemment 292 htmlNodeInfo = nim->GetNodeInfo(nsGkAtoms::body, 0, kNameSpaceID_XHTML, 293 nsINode::ELEMENT_NODE); 294 nsCOMPtr<nsIContent> bodyElement = 295 NS_NewHTMLBodyElement(htmlNodeInfo.forget()); 296 297 // blat in the structure 298 NS_ASSERTION(blankDoc->GetChildCount() == 0, "Shouldn't have children"); 299 if (!htmlElement || !headElement || !bodyElement) { 300 return nullptr; 301 } 302 303 mozilla::IgnoredErrorResult rv; 304 blankDoc->AppendChildTo(htmlElement, false, rv); 305 if (rv.Failed()) { 306 return nullptr; 307 } 308 309 htmlElement->AppendChildTo(headElement, false, rv); 310 if (rv.Failed()) { 311 return nullptr; 312 } 313 314 // XXXbz Why not notifying here? 315 htmlElement->AppendChildTo(bodyElement, false, rv); 316 if (rv.Failed()) { 317 return nullptr; 318 } 319 320 // add a nice bow 321 blankDoc->SetDocumentCharacterSetSource(kCharsetFromDocTypeDefault); 322 blankDoc->SetDocumentCharacterSet(UTF_8_ENCODING); 323 return blankDoc.forget(); 324 }