VideoDocument.cpp (5222B)
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 7 #include "DocumentInlines.h" 8 #include "MediaDocument.h" 9 #include "mozilla/dom/Element.h" 10 #include "mozilla/dom/HTMLMediaElement.h" 11 #include "nsContentCreatorFunctions.h" 12 #include "nsContentUtils.h" 13 #include "nsGkAtoms.h" 14 #include "nsNodeInfoManager.h" 15 16 namespace mozilla::dom { 17 18 class VideoDocument final : public MediaDocument { 19 public: 20 enum MediaDocumentKind MediaDocumentKind() const override { 21 return MediaDocumentKind::Video; 22 } 23 24 virtual nsresult StartDocumentLoad(const char* aCommand, nsIChannel* aChannel, 25 nsILoadGroup* aLoadGroup, 26 nsISupports* aContainer, 27 nsIStreamListener** aDocListener, 28 bool aReset = true) override; 29 virtual void SetScriptGlobalObject( 30 nsIScriptGlobalObject* aScriptGlobalObject) override; 31 32 virtual void Destroy() override { 33 if (mStreamListener) { 34 mStreamListener->DropDocumentRef(); 35 } 36 MediaDocument::Destroy(); 37 } 38 39 nsresult StartLayout() override; 40 41 protected: 42 nsresult CreateVideoElement(); 43 // Sets document <title> to reflect the file name and description. 44 void UpdateTitle(nsIChannel* aChannel); 45 46 RefPtr<MediaDocumentStreamListener> mStreamListener; 47 }; 48 49 nsresult VideoDocument::StartDocumentLoad( 50 const char* aCommand, nsIChannel* aChannel, nsILoadGroup* aLoadGroup, 51 nsISupports* aContainer, nsIStreamListener** aDocListener, bool aReset) { 52 nsresult rv = MediaDocument::StartDocumentLoad( 53 aCommand, aChannel, aLoadGroup, aContainer, aDocListener, aReset); 54 NS_ENSURE_SUCCESS(rv, rv); 55 56 mStreamListener = new MediaDocumentStreamListener(this); 57 NS_ADDREF(*aDocListener = mStreamListener); 58 return rv; 59 } 60 61 nsresult VideoDocument::StartLayout() { 62 // Create video element, and begin loading the media resource. Note we 63 // delay creating the video element until now (we're called from 64 // MediaDocumentStreamListener::OnStartRequest) as the PresShell is likely 65 // to have been created by now, so the MediaDecoder will be able to tell 66 // what kind of compositor we have, so the video element knows whether 67 // it can create a hardware accelerated video decoder or not. 68 nsresult rv = CreateVideoElement(); 69 NS_ENSURE_SUCCESS(rv, rv); 70 71 rv = MediaDocument::StartLayout(); 72 NS_ENSURE_SUCCESS(rv, rv); 73 74 return NS_OK; 75 } 76 77 void VideoDocument::SetScriptGlobalObject( 78 nsIScriptGlobalObject* aScriptGlobalObject) { 79 // Set the script global object on the superclass before doing 80 // anything that might require it.... 81 MediaDocument::SetScriptGlobalObject(aScriptGlobalObject); 82 83 if (aScriptGlobalObject && !InitialSetupHasBeenDone()) { 84 DebugOnly<nsresult> rv = CreateSyntheticDocument(); 85 NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic video document"); 86 87 InitialSetupDone(); 88 } 89 } 90 91 nsresult VideoDocument::CreateVideoElement() { 92 RefPtr<Element> body = GetBodyElement(); 93 if (!body) { 94 NS_WARNING("no body on video document!"); 95 return NS_ERROR_FAILURE; 96 } 97 98 // make content 99 RefPtr<mozilla::dom::NodeInfo> nodeInfo; 100 nodeInfo = mNodeInfoManager->GetNodeInfo( 101 nsGkAtoms::video, nullptr, kNameSpaceID_XHTML, nsINode::ELEMENT_NODE); 102 103 RefPtr<HTMLMediaElement> element = static_cast<HTMLMediaElement*>( 104 NS_NewHTMLVideoElement(nodeInfo.forget(), NOT_FROM_PARSER)); 105 if (!element) return NS_ERROR_OUT_OF_MEMORY; 106 element->SetAutoplay(true, IgnoreErrors()); 107 element->SetControls(true, IgnoreErrors()); 108 element->LoadWithChannel(mChannel, 109 getter_AddRefs(mStreamListener->mNextStream)); 110 UpdateTitle(mChannel); 111 112 if (nsContentUtils::IsChildOfSameType(this)) { 113 // Video documents that aren't toplevel should fill their frames and 114 // not have margins 115 element->SetAttr( 116 kNameSpaceID_None, nsGkAtoms::style, 117 nsLiteralString( 118 u"position:absolute; top:0; left:0; width:100%; height:100%"), 119 true); 120 } else { 121 LinkStylesheet(nsLiteralString( 122 u"resource://content-accessible/TopLevelVideoDocument.css")); 123 LinkScript(u"chrome://global/content/TopLevelVideoDocument.js"_ns); 124 } 125 126 ErrorResult rv; 127 body->AppendChildTo(element, false, rv); 128 return rv.StealNSResult(); 129 } 130 131 void VideoDocument::UpdateTitle(nsIChannel* aChannel) { 132 if (!aChannel) return; 133 134 nsAutoString fileName; 135 GetFileName(fileName, aChannel); 136 IgnoredErrorResult ignored; 137 SetTitle(fileName, ignored); 138 } 139 140 } // namespace mozilla::dom 141 142 nsresult NS_NewVideoDocument(mozilla::dom::Document** aResult, 143 nsIPrincipal* aPrincipal, 144 nsIPrincipal* aPartitionedPrincipal) { 145 auto* doc = new mozilla::dom::VideoDocument(); 146 147 NS_ADDREF(doc); 148 nsresult rv = doc->Init(aPrincipal, aPartitionedPrincipal); 149 150 if (NS_FAILED(rv)) { 151 NS_RELEASE(doc); 152 } 153 154 *aResult = doc; 155 156 return rv; 157 }