michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0:
michael@0: #include "MediaDocument.h"
michael@0: #include "nsGkAtoms.h"
michael@0: #include "nsNodeInfoManager.h"
michael@0: #include "nsContentCreatorFunctions.h"
michael@0: #include "mozilla/dom/HTMLMediaElement.h"
michael@0: #include "nsIDocumentInlines.h"
michael@0: #include "nsContentUtils.h"
michael@0: #include "mozilla/dom/Element.h"
michael@0:
michael@0: namespace mozilla {
michael@0: namespace dom {
michael@0:
michael@0: class VideoDocument MOZ_FINAL : public MediaDocument
michael@0: {
michael@0: public:
michael@0: virtual nsresult StartDocumentLoad(const char* aCommand,
michael@0: nsIChannel* aChannel,
michael@0: nsILoadGroup* aLoadGroup,
michael@0: nsISupports* aContainer,
michael@0: nsIStreamListener** aDocListener,
michael@0: bool aReset = true,
michael@0: nsIContentSink* aSink = nullptr);
michael@0: virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject);
michael@0:
michael@0: protected:
michael@0:
michael@0: // Sets document
to reflect the file name and description.
michael@0: void UpdateTitle(nsIChannel* aChannel);
michael@0:
michael@0: nsresult CreateSyntheticVideoDocument(nsIChannel* aChannel,
michael@0: nsIStreamListener** aListener);
michael@0:
michael@0: nsRefPtr mStreamListener;
michael@0: };
michael@0:
michael@0: nsresult
michael@0: VideoDocument::StartDocumentLoad(const char* aCommand,
michael@0: nsIChannel* aChannel,
michael@0: nsILoadGroup* aLoadGroup,
michael@0: nsISupports* aContainer,
michael@0: nsIStreamListener** aDocListener,
michael@0: bool aReset,
michael@0: nsIContentSink* aSink)
michael@0: {
michael@0: nsresult rv =
michael@0: MediaDocument::StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer,
michael@0: aDocListener, aReset, aSink);
michael@0: NS_ENSURE_SUCCESS(rv, rv);
michael@0:
michael@0: mStreamListener = new MediaDocumentStreamListener(this);
michael@0:
michael@0: // Create synthetic document
michael@0: rv = CreateSyntheticVideoDocument(aChannel,
michael@0: getter_AddRefs(mStreamListener->mNextStream));
michael@0: NS_ENSURE_SUCCESS(rv, rv);
michael@0:
michael@0: NS_ADDREF(*aDocListener = mStreamListener);
michael@0: return rv;
michael@0: }
michael@0:
michael@0: void
michael@0: VideoDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
michael@0: {
michael@0: // Set the script global object on the superclass before doing
michael@0: // anything that might require it....
michael@0: MediaDocument::SetScriptGlobalObject(aScriptGlobalObject);
michael@0:
michael@0: if (aScriptGlobalObject) {
michael@0: if (!nsContentUtils::IsChildOfSameType(this) &&
michael@0: GetReadyStateEnum() != nsIDocument::READYSTATE_COMPLETE) {
michael@0: LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/TopLevelVideoDocument.css"));
michael@0: LinkStylesheet(NS_LITERAL_STRING("chrome://global/skin/media/TopLevelVideoDocument.css"));
michael@0: }
michael@0: BecomeInteractive();
michael@0: }
michael@0: }
michael@0:
michael@0: nsresult
michael@0: VideoDocument::CreateSyntheticVideoDocument(nsIChannel* aChannel,
michael@0: nsIStreamListener** aListener)
michael@0: {
michael@0: // make our generic document
michael@0: nsresult rv = MediaDocument::CreateSyntheticDocument();
michael@0: NS_ENSURE_SUCCESS(rv, rv);
michael@0:
michael@0: Element* body = GetBodyElement();
michael@0: if (!body) {
michael@0: NS_WARNING("no body on video document!");
michael@0: return NS_ERROR_FAILURE;
michael@0: }
michael@0:
michael@0: // make content
michael@0: nsCOMPtr nodeInfo;
michael@0: nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::video, nullptr,
michael@0: kNameSpaceID_XHTML,
michael@0: nsIDOMNode::ELEMENT_NODE);
michael@0:
michael@0: nsRefPtr element =
michael@0: static_cast(NS_NewHTMLVideoElement(nodeInfo.forget(),
michael@0: NOT_FROM_PARSER));
michael@0: if (!element)
michael@0: return NS_ERROR_OUT_OF_MEMORY;
michael@0: element->SetAutoplay(true);
michael@0: element->SetControls(true);
michael@0: element->LoadWithChannel(aChannel, aListener);
michael@0: UpdateTitle(aChannel);
michael@0:
michael@0: if (nsContentUtils::IsChildOfSameType(this)) {
michael@0: // Video documents that aren't toplevel should fill their frames and
michael@0: // not have margins
michael@0: element->SetAttr(kNameSpaceID_None, nsGkAtoms::style,
michael@0: NS_LITERAL_STRING("position:absolute; top:0; left:0; width:100%; height:100%"),
michael@0: true);
michael@0: }
michael@0:
michael@0: return body->AppendChildTo(element, false);
michael@0: }
michael@0:
michael@0: void
michael@0: VideoDocument::UpdateTitle(nsIChannel* aChannel)
michael@0: {
michael@0: if (!aChannel)
michael@0: return;
michael@0:
michael@0: nsAutoString fileName;
michael@0: GetFileName(fileName);
michael@0: SetTitle(fileName);
michael@0: }
michael@0:
michael@0: } // namespace dom
michael@0: } // namespace mozilla
michael@0:
michael@0: nsresult
michael@0: NS_NewVideoDocument(nsIDocument** aResult)
michael@0: {
michael@0: mozilla::dom::VideoDocument* doc = new mozilla::dom::VideoDocument();
michael@0:
michael@0: NS_ADDREF(doc);
michael@0: nsresult rv = doc->Init();
michael@0:
michael@0: if (NS_FAILED(rv)) {
michael@0: NS_RELEASE(doc);
michael@0: }
michael@0:
michael@0: *aResult = doc;
michael@0:
michael@0: return rv;
michael@0: }