summaryrefslogtreecommitdiffstats
path: root/dom/html/PluginDocument.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/html/PluginDocument.cpp')
-rw-r--r--dom/html/PluginDocument.cpp302
1 files changed, 302 insertions, 0 deletions
diff --git a/dom/html/PluginDocument.cpp b/dom/html/PluginDocument.cpp
new file mode 100644
index 000000000..1c923ecc6
--- /dev/null
+++ b/dom/html/PluginDocument.cpp
@@ -0,0 +1,302 @@
+/* -*- 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 "nsIPluginDocument.h"
+#include "nsGkAtoms.h"
+#include "nsIPresShell.h"
+#include "nsIObjectFrame.h"
+#include "nsNPAPIPluginInstance.h"
+#include "nsIDocumentInlines.h"
+#include "nsIDocShellTreeItem.h"
+#include "nsNodeInfoManager.h"
+#include "nsContentCreatorFunctions.h"
+#include "nsContentPolicyUtils.h"
+#include "nsIPropertyBag2.h"
+#include "mozilla/dom/Element.h"
+#include "nsObjectLoadingContent.h"
+#include "GeckoProfiler.h"
+
+namespace mozilla {
+namespace dom {
+
+class PluginDocument final : public MediaDocument
+ , public nsIPluginDocument
+{
+public:
+ PluginDocument();
+
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIPLUGINDOCUMENT
+
+ virtual nsresult StartDocumentLoad(const char* aCommand,
+ nsIChannel* aChannel,
+ nsILoadGroup* aLoadGroup,
+ nsISupports* aContainer,
+ nsIStreamListener** aDocListener,
+ bool aReset = true,
+ nsIContentSink* aSink = nullptr) override;
+
+ virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject) override;
+ virtual bool CanSavePresentation(nsIRequest *aNewRequest) override;
+
+ const nsCString& GetType() const { return mMimeType; }
+ Element* GetPluginContent() { return mPluginContent; }
+
+ void StartLayout() { MediaDocument::StartLayout(); }
+
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PluginDocument, MediaDocument)
+protected:
+ virtual ~PluginDocument();
+
+ nsresult CreateSyntheticPluginDocument();
+
+ nsCOMPtr<Element> mPluginContent;
+ RefPtr<MediaDocumentStreamListener> mStreamListener;
+ nsCString mMimeType;
+};
+
+class PluginStreamListener : public MediaDocumentStreamListener
+{
+public:
+ explicit PluginStreamListener(PluginDocument* aDoc)
+ : MediaDocumentStreamListener(aDoc)
+ , mPluginDoc(aDoc)
+ {}
+ NS_IMETHOD OnStartRequest(nsIRequest* request, nsISupports *ctxt);
+private:
+ RefPtr<PluginDocument> mPluginDoc;
+};
+
+
+NS_IMETHODIMP
+PluginStreamListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
+{
+ PROFILER_LABEL("PluginStreamListener", "OnStartRequest",
+ js::ProfileEntry::Category::NETWORK);
+
+ nsCOMPtr<nsIContent> embed = mPluginDoc->GetPluginContent();
+ nsCOMPtr<nsIObjectLoadingContent> objlc = do_QueryInterface(embed);
+ nsCOMPtr<nsIStreamListener> objListener = do_QueryInterface(objlc);
+
+ if (!objListener) {
+ NS_NOTREACHED("PluginStreamListener without appropriate content node");
+ return NS_BINDING_ABORTED;
+ }
+
+ SetStreamListener(objListener);
+
+ // Sets up the ObjectLoadingContent tag as if it is waiting for a
+ // channel, so it can proceed with a load normally once it gets OnStartRequest
+ nsresult rv = objlc->InitializeFromChannel(request);
+ if (NS_FAILED(rv)) {
+ NS_NOTREACHED("InitializeFromChannel failed");
+ return rv;
+ }
+
+ // Note that because we're now hooked up to a plugin listener, this will
+ // likely spawn a plugin, which may re-enter.
+ return MediaDocumentStreamListener::OnStartRequest(request, ctxt);
+}
+
+ // NOTE! nsDocument::operator new() zeroes out all members, so don't
+ // bother initializing members to 0.
+
+PluginDocument::PluginDocument()
+{}
+
+PluginDocument::~PluginDocument()
+{}
+
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(PluginDocument, MediaDocument,
+ mPluginContent)
+
+NS_IMPL_ADDREF_INHERITED(PluginDocument, MediaDocument)
+NS_IMPL_RELEASE_INHERITED(PluginDocument, MediaDocument)
+
+NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(PluginDocument)
+ NS_INTERFACE_TABLE_INHERITED(PluginDocument, nsIPluginDocument)
+NS_INTERFACE_TABLE_TAIL_INHERITING(MediaDocument)
+
+void
+PluginDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
+{
+ // Set the script global object on the superclass before doing
+ // anything that might require it....
+ MediaDocument::SetScriptGlobalObject(aScriptGlobalObject);
+
+ if (aScriptGlobalObject) {
+ if (!mPluginContent) {
+ // Create synthetic document
+#ifdef DEBUG
+ nsresult rv =
+#endif
+ CreateSyntheticPluginDocument();
+ NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic document");
+ }
+ BecomeInteractive();
+ } else {
+ mStreamListener = nullptr;
+ }
+}
+
+
+bool
+PluginDocument::CanSavePresentation(nsIRequest *aNewRequest)
+{
+ // Full-page plugins cannot be cached, currently, because we don't have
+ // the stream listener data to feed to the plugin instance.
+ return false;
+}
+
+
+nsresult
+PluginDocument::StartDocumentLoad(const char* aCommand,
+ nsIChannel* aChannel,
+ nsILoadGroup* aLoadGroup,
+ nsISupports* aContainer,
+ nsIStreamListener** aDocListener,
+ bool aReset,
+ nsIContentSink* aSink)
+{
+ // do not allow message panes to host full-page plugins
+ // returning an error causes helper apps to take over
+ nsCOMPtr<nsIDocShellTreeItem> dsti (do_QueryInterface(aContainer));
+ if (dsti) {
+ bool isMsgPane = false;
+ dsti->NameEquals(NS_LITERAL_STRING("messagepane"), &isMsgPane);
+ if (isMsgPane) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ nsresult rv =
+ MediaDocument::StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer,
+ aDocListener, aReset, aSink);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = aChannel->GetContentType(mMimeType);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ MediaDocument::UpdateTitleAndCharset(mMimeType, aChannel);
+
+ mStreamListener = new PluginStreamListener(this);
+ NS_ASSERTION(aDocListener, "null aDocListener");
+ NS_ADDREF(*aDocListener = mStreamListener);
+
+ return rv;
+}
+
+nsresult
+PluginDocument::CreateSyntheticPluginDocument()
+{
+ NS_ASSERTION(!GetShell() || !GetShell()->DidInitialize(),
+ "Creating synthetic plugin document content too late");
+
+ // make our generic document
+ nsresult rv = MediaDocument::CreateSyntheticDocument();
+ NS_ENSURE_SUCCESS(rv, rv);
+ // then attach our plugin
+
+ Element* body = GetBodyElement();
+ if (!body) {
+ NS_WARNING("no body on plugin document!");
+ return NS_ERROR_FAILURE;
+ }
+
+ // remove margins from body
+ NS_NAMED_LITERAL_STRING(zero, "0");
+ body->SetAttr(kNameSpaceID_None, nsGkAtoms::marginwidth, zero, false);
+ body->SetAttr(kNameSpaceID_None, nsGkAtoms::marginheight, zero, false);
+
+
+ // make plugin content
+ RefPtr<mozilla::dom::NodeInfo> nodeInfo;
+ nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::embed, nullptr,
+ kNameSpaceID_XHTML,
+ nsIDOMNode::ELEMENT_NODE);
+ rv = NS_NewHTMLElement(getter_AddRefs(mPluginContent), nodeInfo.forget(),
+ NOT_FROM_PARSER);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // make it a named element
+ mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::name,
+ NS_LITERAL_STRING("plugin"), false);
+
+ // fill viewport and auto-resize
+ NS_NAMED_LITERAL_STRING(percent100, "100%");
+ mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::width, percent100,
+ false);
+ mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::height, percent100,
+ false);
+
+ // set URL
+ nsAutoCString src;
+ mDocumentURI->GetSpec(src);
+ mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::src,
+ NS_ConvertUTF8toUTF16(src), false);
+
+ // set mime type
+ mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
+ NS_ConvertUTF8toUTF16(mMimeType), false);
+
+ // nsHTML(Shared)ObjectElement does not kick off a load on BindToTree if it is
+ // to a PluginDocument
+ body->AppendChildTo(mPluginContent, false);
+
+ return NS_OK;
+
+
+}
+
+NS_IMETHODIMP
+PluginDocument::Print()
+{
+ NS_ENSURE_TRUE(mPluginContent, NS_ERROR_FAILURE);
+
+ nsIObjectFrame* objectFrame =
+ do_QueryFrame(mPluginContent->GetPrimaryFrame());
+ if (objectFrame) {
+ RefPtr<nsNPAPIPluginInstance> pi;
+ objectFrame->GetPluginInstance(getter_AddRefs(pi));
+ if (pi) {
+ NPPrint npprint;
+ npprint.mode = NP_FULL;
+ npprint.print.fullPrint.pluginPrinted = false;
+ npprint.print.fullPrint.printOne = false;
+ npprint.print.fullPrint.platformPrint = nullptr;
+
+ pi->Print(&npprint);
+ }
+ }
+
+ return NS_OK;
+}
+
+} // namespace dom
+} // namespace mozilla
+
+nsresult
+NS_NewPluginDocument(nsIDocument** aResult)
+{
+ mozilla::dom::PluginDocument* doc = new mozilla::dom::PluginDocument();
+
+ NS_ADDREF(doc);
+ nsresult rv = doc->Init();
+
+ if (NS_FAILED(rv)) {
+ NS_RELEASE(doc);
+ }
+
+ *aResult = doc;
+
+ return rv;
+}