summaryrefslogtreecommitdiffstats
path: root/dom/html/VideoDocument.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/html/VideoDocument.cpp')
-rw-r--r--dom/html/VideoDocument.cpp158
1 files changed, 158 insertions, 0 deletions
diff --git a/dom/html/VideoDocument.cpp b/dom/html/VideoDocument.cpp
new file mode 100644
index 0000000000..00b5bf5308
--- /dev/null
+++ b/dom/html/VideoDocument.cpp
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "MediaDocument.h"
+#include "nsGkAtoms.h"
+#include "nsNodeInfoManager.h"
+#include "nsContentCreatorFunctions.h"
+#include "mozilla/dom/HTMLMediaElement.h"
+#include "DocumentInlines.h"
+#include "nsContentUtils.h"
+#include "mozilla/dom/Element.h"
+
+namespace mozilla::dom {
+
+class VideoDocument final : public MediaDocument {
+ public:
+ enum MediaDocumentKind MediaDocumentKind() const override {
+ return MediaDocumentKind::Video;
+ }
+
+ virtual nsresult StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
+ nsILoadGroup* aLoadGroup,
+ nsISupports* aContainer,
+ nsIStreamListener** aDocListener,
+ bool aReset = true) override;
+ virtual void SetScriptGlobalObject(
+ nsIScriptGlobalObject* aScriptGlobalObject) override;
+
+ virtual void Destroy() override {
+ if (mStreamListener) {
+ mStreamListener->DropDocumentRef();
+ }
+ MediaDocument::Destroy();
+ }
+
+ nsresult StartLayout() override;
+
+ protected:
+ nsresult CreateVideoElement();
+ // Sets document <title> to reflect the file name and description.
+ void UpdateTitle(nsIChannel* aChannel);
+
+ RefPtr<MediaDocumentStreamListener> mStreamListener;
+};
+
+nsresult VideoDocument::StartDocumentLoad(
+ const char* aCommand, nsIChannel* aChannel, nsILoadGroup* aLoadGroup,
+ nsISupports* aContainer, nsIStreamListener** aDocListener, bool aReset) {
+ nsresult rv = MediaDocument::StartDocumentLoad(
+ aCommand, aChannel, aLoadGroup, aContainer, aDocListener, aReset);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mStreamListener = new MediaDocumentStreamListener(this);
+ NS_ADDREF(*aDocListener = mStreamListener);
+ return rv;
+}
+
+nsresult VideoDocument::StartLayout() {
+ // Create video element, and begin loading the media resource. Note we
+ // delay creating the video element until now (we're called from
+ // MediaDocumentStreamListener::OnStartRequest) as the PresShell is likely
+ // to have been created by now, so the MediaDecoder will be able to tell
+ // what kind of compositor we have, so the video element knows whether
+ // it can create a hardware accelerated video decoder or not.
+ nsresult rv = CreateVideoElement();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = MediaDocument::StartLayout();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
+void VideoDocument::SetScriptGlobalObject(
+ nsIScriptGlobalObject* aScriptGlobalObject) {
+ // Set the script global object on the superclass before doing
+ // anything that might require it....
+ MediaDocument::SetScriptGlobalObject(aScriptGlobalObject);
+
+ if (aScriptGlobalObject && !InitialSetupHasBeenDone()) {
+ DebugOnly<nsresult> rv = CreateSyntheticDocument();
+ NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic video document");
+
+ if (!nsContentUtils::IsChildOfSameType(this)) {
+ LinkStylesheet(nsLiteralString(
+ u"resource://content-accessible/TopLevelVideoDocument.css"));
+ LinkScript(u"chrome://global/content/TopLevelVideoDocument.js"_ns);
+ }
+ InitialSetupDone();
+ }
+}
+
+nsresult VideoDocument::CreateVideoElement() {
+ RefPtr<Element> body = GetBodyElement();
+ if (!body) {
+ NS_WARNING("no body on video document!");
+ return NS_ERROR_FAILURE;
+ }
+
+ // make content
+ RefPtr<mozilla::dom::NodeInfo> nodeInfo;
+ nodeInfo = mNodeInfoManager->GetNodeInfo(
+ nsGkAtoms::video, nullptr, kNameSpaceID_XHTML, nsINode::ELEMENT_NODE);
+
+ RefPtr<HTMLMediaElement> element = static_cast<HTMLMediaElement*>(
+ NS_NewHTMLVideoElement(nodeInfo.forget(), NOT_FROM_PARSER));
+ if (!element) return NS_ERROR_OUT_OF_MEMORY;
+ element->SetAutoplay(true, IgnoreErrors());
+ element->SetControls(true, IgnoreErrors());
+ element->LoadWithChannel(mChannel,
+ getter_AddRefs(mStreamListener->mNextStream));
+ UpdateTitle(mChannel);
+
+ if (nsContentUtils::IsChildOfSameType(this)) {
+ // Video documents that aren't toplevel should fill their frames and
+ // not have margins
+ element->SetAttr(
+ kNameSpaceID_None, nsGkAtoms::style,
+ nsLiteralString(
+ u"position:absolute; top:0; left:0; width:100%; height:100%"),
+ true);
+ }
+
+ ErrorResult rv;
+ body->AppendChildTo(element, false, rv);
+ return rv.StealNSResult();
+}
+
+void VideoDocument::UpdateTitle(nsIChannel* aChannel) {
+ if (!aChannel) return;
+
+ nsAutoString fileName;
+ GetFileName(fileName, aChannel);
+ IgnoredErrorResult ignored;
+ SetTitle(fileName, ignored);
+}
+
+} // namespace mozilla::dom
+
+nsresult NS_NewVideoDocument(mozilla::dom::Document** aResult,
+ nsIPrincipal* aPrincipal,
+ nsIPrincipal* aPartitionedPrincipal) {
+ auto* doc = new mozilla::dom::VideoDocument();
+
+ NS_ADDREF(doc);
+ nsresult rv = doc->Init(aPrincipal, aPartitionedPrincipal);
+
+ if (NS_FAILED(rv)) {
+ NS_RELEASE(doc);
+ }
+
+ *aResult = doc;
+
+ return rv;
+}