Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "MediaDocument.h"
8 : #include "nsIPluginDocument.h"
9 : #include "nsGkAtoms.h"
10 : #include "nsIPresShell.h"
11 : #include "nsIObjectFrame.h"
12 : #include "nsNPAPIPluginInstance.h"
13 : #include "nsIDocumentInlines.h"
14 : #include "nsIDocShellTreeItem.h"
15 : #include "nsNodeInfoManager.h"
16 : #include "nsContentCreatorFunctions.h"
17 : #include "nsContentPolicyUtils.h"
18 : #include "nsIPropertyBag2.h"
19 : #include "mozilla/dom/Element.h"
20 : #include "nsObjectLoadingContent.h"
21 : #include "GeckoProfiler.h"
22 :
23 : namespace mozilla {
24 : namespace dom {
25 :
26 0 : class PluginDocument final : public MediaDocument
27 : , public nsIPluginDocument
28 : {
29 : public:
30 : PluginDocument();
31 :
32 : NS_DECL_ISUPPORTS_INHERITED
33 : NS_DECL_NSIPLUGINDOCUMENT
34 :
35 : nsresult StartDocumentLoad(const char* aCommand,
36 : nsIChannel* aChannel,
37 : nsILoadGroup* aLoadGroup,
38 : nsISupports* aContainer,
39 : nsIStreamListener** aDocListener,
40 : bool aReset = true,
41 : nsIContentSink* aSink = nullptr) override;
42 :
43 : void SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject) override;
44 : bool CanSavePresentation(nsIRequest *aNewRequest) override;
45 :
46 : const nsCString& GetType() const { return mMimeType; }
47 0 : Element* GetPluginContent() { return mPluginContent; }
48 :
49 : void StartLayout() { MediaDocument::StartLayout(); }
50 :
51 0 : NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PluginDocument, MediaDocument)
52 : protected:
53 : ~PluginDocument() override;
54 :
55 : nsresult CreateSyntheticPluginDocument();
56 :
57 : nsCOMPtr<Element> mPluginContent;
58 : RefPtr<MediaDocumentStreamListener> mStreamListener;
59 : nsCString mMimeType;
60 : };
61 :
62 0 : class PluginStreamListener : public MediaDocumentStreamListener
63 : {
64 : public:
65 0 : explicit PluginStreamListener(PluginDocument* aDoc)
66 0 : : MediaDocumentStreamListener(aDoc)
67 0 : , mPluginDoc(aDoc)
68 0 : {}
69 : NS_IMETHOD OnStartRequest(nsIRequest* request, nsISupports *ctxt) override;
70 : private:
71 : RefPtr<PluginDocument> mPluginDoc;
72 : };
73 :
74 :
75 : NS_IMETHODIMP
76 0 : PluginStreamListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
77 : {
78 0 : AUTO_PROFILER_LABEL("PluginStreamListener::OnStartRequest", NETWORK);
79 :
80 0 : nsCOMPtr<nsIContent> embed = mPluginDoc->GetPluginContent();
81 0 : nsCOMPtr<nsIObjectLoadingContent> objlc = do_QueryInterface(embed);
82 0 : nsCOMPtr<nsIStreamListener> objListener = do_QueryInterface(objlc);
83 :
84 0 : if (!objListener) {
85 0 : NS_NOTREACHED("PluginStreamListener without appropriate content node");
86 0 : return NS_BINDING_ABORTED;
87 : }
88 :
89 0 : SetStreamListener(objListener);
90 :
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 0 : nsresult rv = objlc->InitializeFromChannel(request);
94 0 : if (NS_FAILED(rv)) {
95 0 : NS_NOTREACHED("InitializeFromChannel failed");
96 0 : return rv;
97 : }
98 :
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 0 : return MediaDocumentStreamListener::OnStartRequest(request, ctxt);
102 : }
103 :
104 0 : PluginDocument::PluginDocument()
105 0 : {}
106 :
107 : PluginDocument::~PluginDocument() = default;
108 :
109 :
110 0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(PluginDocument, MediaDocument,
111 : mPluginContent)
112 :
113 0 : NS_IMPL_ADDREF_INHERITED(PluginDocument, MediaDocument)
114 0 : NS_IMPL_RELEASE_INHERITED(PluginDocument, MediaDocument)
115 :
116 0 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(PluginDocument)
117 0 : NS_INTERFACE_TABLE_INHERITED(PluginDocument, nsIPluginDocument)
118 0 : NS_INTERFACE_TABLE_TAIL_INHERITING(MediaDocument)
119 :
120 : void
121 0 : PluginDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
122 : {
123 : // Set the script global object on the superclass before doing
124 : // anything that might require it....
125 0 : MediaDocument::SetScriptGlobalObject(aScriptGlobalObject);
126 :
127 0 : if (aScriptGlobalObject) {
128 0 : if (!mPluginContent) {
129 : // Create synthetic document
130 : #ifdef DEBUG
131 : nsresult rv =
132 : #endif
133 0 : CreateSyntheticPluginDocument();
134 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic document");
135 : }
136 0 : BecomeInteractive();
137 : } else {
138 0 : mStreamListener = nullptr;
139 : }
140 0 : }
141 :
142 :
143 : bool
144 0 : PluginDocument::CanSavePresentation(nsIRequest *aNewRequest)
145 : {
146 : // Full-page plugins cannot be cached, currently, because we don't have
147 : // the stream listener data to feed to the plugin instance.
148 0 : return false;
149 : }
150 :
151 :
152 : nsresult
153 0 : PluginDocument::StartDocumentLoad(const char* aCommand,
154 : nsIChannel* aChannel,
155 : nsILoadGroup* aLoadGroup,
156 : nsISupports* aContainer,
157 : nsIStreamListener** aDocListener,
158 : bool aReset,
159 : nsIContentSink* aSink)
160 : {
161 : // do not allow message panes to host full-page plugins
162 : // returning an error causes helper apps to take over
163 0 : nsCOMPtr<nsIDocShellTreeItem> dsti (do_QueryInterface(aContainer));
164 0 : if (dsti) {
165 0 : bool isMsgPane = false;
166 0 : dsti->NameEquals(NS_LITERAL_STRING("messagepane"), &isMsgPane);
167 0 : if (isMsgPane) {
168 0 : return NS_ERROR_FAILURE;
169 : }
170 : }
171 :
172 : nsresult rv =
173 0 : MediaDocument::StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer,
174 0 : aDocListener, aReset, aSink);
175 0 : if (NS_FAILED(rv)) {
176 0 : return rv;
177 : }
178 :
179 0 : rv = aChannel->GetContentType(mMimeType);
180 0 : if (NS_FAILED(rv)) {
181 0 : return rv;
182 : }
183 :
184 0 : MediaDocument::UpdateTitleAndCharset(mMimeType, aChannel);
185 :
186 0 : mStreamListener = new PluginStreamListener(this);
187 0 : NS_ASSERTION(aDocListener, "null aDocListener");
188 0 : NS_ADDREF(*aDocListener = mStreamListener);
189 :
190 0 : return rv;
191 : }
192 :
193 : nsresult
194 0 : PluginDocument::CreateSyntheticPluginDocument()
195 : {
196 0 : NS_ASSERTION(!GetShell() || !GetShell()->DidInitialize(),
197 : "Creating synthetic plugin document content too late");
198 :
199 : // make our generic document
200 0 : nsresult rv = MediaDocument::CreateSyntheticDocument();
201 0 : NS_ENSURE_SUCCESS(rv, rv);
202 : // then attach our plugin
203 :
204 0 : Element* body = GetBodyElement();
205 0 : if (!body) {
206 0 : NS_WARNING("no body on plugin document!");
207 0 : return NS_ERROR_FAILURE;
208 : }
209 :
210 : // remove margins from body
211 0 : NS_NAMED_LITERAL_STRING(zero, "0");
212 0 : body->SetAttr(kNameSpaceID_None, nsGkAtoms::marginwidth, zero, false);
213 0 : body->SetAttr(kNameSpaceID_None, nsGkAtoms::marginheight, zero, false);
214 :
215 :
216 : // make plugin content
217 0 : RefPtr<mozilla::dom::NodeInfo> nodeInfo;
218 0 : nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::embed, nullptr,
219 : kNameSpaceID_XHTML,
220 0 : nsIDOMNode::ELEMENT_NODE);
221 0 : rv = NS_NewHTMLElement(getter_AddRefs(mPluginContent), nodeInfo.forget(),
222 0 : NOT_FROM_PARSER);
223 0 : NS_ENSURE_SUCCESS(rv, rv);
224 :
225 : // make it a named element
226 0 : mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::name,
227 0 : NS_LITERAL_STRING("plugin"), false);
228 :
229 : // fill viewport and auto-resize
230 0 : NS_NAMED_LITERAL_STRING(percent100, "100%");
231 0 : mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::width, percent100,
232 0 : false);
233 0 : mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::height, percent100,
234 0 : false);
235 :
236 : // set URL
237 0 : nsAutoCString src;
238 0 : mDocumentURI->GetSpec(src);
239 0 : mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::src,
240 0 : NS_ConvertUTF8toUTF16(src), false);
241 :
242 : // set mime type
243 0 : mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
244 0 : NS_ConvertUTF8toUTF16(mMimeType), false);
245 :
246 : // nsHTML(Shared)ObjectElement does not kick off a load on BindToTree if it is
247 : // to a PluginDocument
248 0 : body->AppendChildTo(mPluginContent, false);
249 :
250 0 : return NS_OK;
251 :
252 :
253 : }
254 :
255 : NS_IMETHODIMP
256 0 : PluginDocument::Print()
257 : {
258 0 : NS_ENSURE_TRUE(mPluginContent, NS_ERROR_FAILURE);
259 :
260 : nsIObjectFrame* objectFrame =
261 0 : do_QueryFrame(mPluginContent->GetPrimaryFrame());
262 0 : if (objectFrame) {
263 0 : RefPtr<nsNPAPIPluginInstance> pi;
264 0 : objectFrame->GetPluginInstance(getter_AddRefs(pi));
265 0 : if (pi) {
266 : NPPrint npprint;
267 0 : npprint.mode = NP_FULL;
268 0 : npprint.print.fullPrint.pluginPrinted = false;
269 0 : npprint.print.fullPrint.printOne = false;
270 0 : npprint.print.fullPrint.platformPrint = nullptr;
271 :
272 0 : pi->Print(&npprint);
273 : }
274 : }
275 :
276 0 : return NS_OK;
277 : }
278 :
279 : } // namespace dom
280 : } // namespace mozilla
281 :
282 : nsresult
283 0 : NS_NewPluginDocument(nsIDocument** aResult)
284 : {
285 0 : auto* doc = new mozilla::dom::PluginDocument();
286 :
287 0 : NS_ADDREF(doc);
288 0 : nsresult rv = doc->Init();
289 :
290 0 : if (NS_FAILED(rv)) {
291 0 : NS_RELEASE(doc);
292 : }
293 :
294 0 : *aResult = doc;
295 :
296 0 : return rv;
297 : }
|