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<MediaDocumentStreamListener> 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<nsINodeInfo> nodeInfo; michael@0: nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::video, nullptr, michael@0: kNameSpaceID_XHTML, michael@0: nsIDOMNode::ELEMENT_NODE); michael@0: michael@0: nsRefPtr<HTMLMediaElement> element = michael@0: static_cast<HTMLMediaElement*>(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: }