1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "MediaDocument.h"
7 #include "nsIPluginDocument.h"
9 #include "nsIPresShell.h"
10 #include "nsIObjectFrame.h"
11 #include "nsNPAPIPluginInstance.h"
12 #include "nsIDocumentInlines.h"
13 #include "nsIDocShellTreeItem.h"
14 #include "nsNodeInfoManager.h"
15 #include "nsContentCreatorFunctions.h"
16 #include "nsContentPolicyUtils.h"
17 #include "nsIPropertyBag2.h"
18 #include "mozilla/dom/Element.h"
19 #include "nsObjectLoadingContent.h"
20 #include "GeckoProfiler.h"
25 class PluginDocument MOZ_FINAL
: public MediaDocument
26 , public nsIPluginDocument
31 NS_DECL_ISUPPORTS_INHERITED
32 NS_DECL_NSIPLUGINDOCUMENT
34 virtual nsresult
StartDocumentLoad(const char* aCommand
,
36 nsILoadGroup
* aLoadGroup
,
37 nsISupports
* aContainer
,
38 nsIStreamListener
** aDocListener
,
40 nsIContentSink
* aSink
= nullptr) MOZ_OVERRIDE
;
42 virtual void SetScriptGlobalObject(nsIScriptGlobalObject
* aScriptGlobalObject
) MOZ_OVERRIDE
;
43 virtual bool CanSavePresentation(nsIRequest
*aNewRequest
) MOZ_OVERRIDE
;
45 const nsCString
& GetType() const { return mMimeType
; }
46 Element
* GetPluginContent() { return mPluginContent
; }
48 void StartLayout() { MediaDocument::StartLayout(); }
50 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PluginDocument
, MediaDocument
)
52 virtual ~PluginDocument();
54 nsresult
CreateSyntheticPluginDocument();
56 nsCOMPtr
<Element
> mPluginContent
;
57 nsRefPtr
<MediaDocumentStreamListener
> mStreamListener
;
61 class PluginStreamListener
: public MediaDocumentStreamListener
64 explicit PluginStreamListener(PluginDocument
* aDoc
)
65 : MediaDocumentStreamListener(aDoc
)
68 NS_IMETHOD
OnStartRequest(nsIRequest
* request
, nsISupports
*ctxt
);
70 nsRefPtr
<PluginDocument
> mPluginDoc
;
75 PluginStreamListener::OnStartRequest(nsIRequest
* request
, nsISupports
*ctxt
)
77 PROFILER_LABEL("PluginStreamListener", "OnStartRequest",
78 js::ProfileEntry::Category::NETWORK
);
80 nsCOMPtr
<nsIContent
> embed
= mPluginDoc
->GetPluginContent();
81 nsCOMPtr
<nsIObjectLoadingContent
> objlc
= do_QueryInterface(embed
);
82 nsCOMPtr
<nsIStreamListener
> objListener
= do_QueryInterface(objlc
);
85 NS_NOTREACHED("PluginStreamListener without appropriate content node");
86 return NS_BINDING_ABORTED
;
89 SetStreamListener(objListener
);
91 // Sets up the ObjectLoadingContent tag as if it is waiting for a
92 // channel, so it can proceed with a load normally once it gets OnStartRequest
93 nsresult rv
= objlc
->InitializeFromChannel(request
);
95 NS_NOTREACHED("InitializeFromChannel failed");
99 // Note that because we're now hooked up to a plugin listener, this will
100 // likely spawn a plugin, which may re-enter.
101 return MediaDocumentStreamListener::OnStartRequest(request
, ctxt
);
104 // NOTE! nsDocument::operator new() zeroes out all members, so don't
105 // bother initializing members to 0.
107 PluginDocument::PluginDocument()
110 PluginDocument::~PluginDocument()
114 NS_IMPL_CYCLE_COLLECTION_INHERITED(PluginDocument
, MediaDocument
,
117 NS_IMPL_ADDREF_INHERITED(PluginDocument
, MediaDocument
)
118 NS_IMPL_RELEASE_INHERITED(PluginDocument
, MediaDocument
)
120 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(PluginDocument
)
121 NS_INTERFACE_TABLE_INHERITED(PluginDocument
, nsIPluginDocument
)
122 NS_INTERFACE_TABLE_TAIL_INHERITING(MediaDocument
)
125 PluginDocument::SetScriptGlobalObject(nsIScriptGlobalObject
* aScriptGlobalObject
)
127 // Set the script global object on the superclass before doing
128 // anything that might require it....
129 MediaDocument::SetScriptGlobalObject(aScriptGlobalObject
);
131 if (aScriptGlobalObject
) {
132 if (!mPluginContent
) {
133 // Create synthetic document
137 CreateSyntheticPluginDocument();
138 NS_ASSERTION(NS_SUCCEEDED(rv
), "failed to create synthetic document");
142 mStreamListener
= nullptr;
148 PluginDocument::CanSavePresentation(nsIRequest
*aNewRequest
)
150 // Full-page plugins cannot be cached, currently, because we don't have
151 // the stream listener data to feed to the plugin instance.
157 PluginDocument::StartDocumentLoad(const char* aCommand
,
158 nsIChannel
* aChannel
,
159 nsILoadGroup
* aLoadGroup
,
160 nsISupports
* aContainer
,
161 nsIStreamListener
** aDocListener
,
163 nsIContentSink
* aSink
)
165 // do not allow message panes to host full-page plugins
166 // returning an error causes helper apps to take over
167 nsCOMPtr
<nsIDocShellTreeItem
> dsti (do_QueryInterface(aContainer
));
169 bool isMsgPane
= false;
170 dsti
->NameEquals(MOZ_UTF16("messagepane"), &isMsgPane
);
172 return NS_ERROR_FAILURE
;
177 MediaDocument::StartDocumentLoad(aCommand
, aChannel
, aLoadGroup
, aContainer
,
178 aDocListener
, aReset
, aSink
);
183 rv
= aChannel
->GetContentType(mMimeType
);
188 MediaDocument::UpdateTitleAndCharset(mMimeType
, aChannel
);
190 mStreamListener
= new PluginStreamListener(this);
191 NS_ASSERTION(aDocListener
, "null aDocListener");
192 NS_ADDREF(*aDocListener
= mStreamListener
);
198 PluginDocument::CreateSyntheticPluginDocument()
200 NS_ASSERTION(!GetShell() || !GetShell()->DidInitialize(),
201 "Creating synthetic plugin document content too late");
203 // make our generic document
204 nsresult rv
= MediaDocument::CreateSyntheticDocument();
205 NS_ENSURE_SUCCESS(rv
, rv
);
206 // then attach our plugin
208 Element
* body
= GetBodyElement();
210 NS_WARNING("no body on plugin document!");
211 return NS_ERROR_FAILURE
;
214 // remove margins from body
215 NS_NAMED_LITERAL_STRING(zero
, "0");
216 body
->SetAttr(kNameSpaceID_None
, nsGkAtoms::marginwidth
, zero
, false);
217 body
->SetAttr(kNameSpaceID_None
, nsGkAtoms::marginheight
, zero
, false);
220 // make plugin content
221 nsRefPtr
<mozilla::dom::NodeInfo
> nodeInfo
;
222 nodeInfo
= mNodeInfoManager
->GetNodeInfo(nsGkAtoms::embed
, nullptr,
224 nsIDOMNode::ELEMENT_NODE
);
225 rv
= NS_NewHTMLElement(getter_AddRefs(mPluginContent
), nodeInfo
.forget(),
227 NS_ENSURE_SUCCESS(rv
, rv
);
229 // make it a named element
230 mPluginContent
->SetAttr(kNameSpaceID_None
, nsGkAtoms::name
,
231 NS_LITERAL_STRING("plugin"), false);
233 // fill viewport and auto-resize
234 NS_NAMED_LITERAL_STRING(percent100
, "100%");
235 mPluginContent
->SetAttr(kNameSpaceID_None
, nsGkAtoms::width
, percent100
,
237 mPluginContent
->SetAttr(kNameSpaceID_None
, nsGkAtoms::height
, percent100
,
242 mDocumentURI
->GetSpec(src
);
243 mPluginContent
->SetAttr(kNameSpaceID_None
, nsGkAtoms::src
,
244 NS_ConvertUTF8toUTF16(src
), false);
247 mPluginContent
->SetAttr(kNameSpaceID_None
, nsGkAtoms::type
,
248 NS_ConvertUTF8toUTF16(mMimeType
), false);
250 // nsHTML(Shared)ObjectElement does not kick off a load on BindToTree if it is
251 // to a PluginDocument
252 body
->AppendChildTo(mPluginContent
, false);
260 PluginDocument::Print()
262 NS_ENSURE_TRUE(mPluginContent
, NS_ERROR_FAILURE
);
264 nsIObjectFrame
* objectFrame
=
265 do_QueryFrame(mPluginContent
->GetPrimaryFrame());
267 nsRefPtr
<nsNPAPIPluginInstance
> pi
;
268 objectFrame
->GetPluginInstance(getter_AddRefs(pi
));
271 npprint
.mode
= NP_FULL
;
272 npprint
.print
.fullPrint
.pluginPrinted
= false;
273 npprint
.print
.fullPrint
.printOne
= false;
274 npprint
.print
.fullPrint
.platformPrint
= nullptr;
284 } // namespace mozilla
287 NS_NewPluginDocument(nsIDocument
** aResult
)
289 mozilla::dom::PluginDocument
* doc
= new mozilla::dom::PluginDocument();
292 nsresult rv
= doc
->Init();