1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "MediaDocument.h"
39 : #include "nsIPluginDocument.h"
40 : #include "nsGkAtoms.h"
41 : #include "nsIPresShell.h"
42 : #include "nsIObjectFrame.h"
43 : #include "nsNPAPIPluginInstance.h"
44 : #include "nsIDocShellTreeItem.h"
45 : #include "nsNodeInfoManager.h"
46 : #include "nsContentCreatorFunctions.h"
47 : #include "nsContentPolicyUtils.h"
48 : #include "nsIPropertyBag2.h"
49 : #include "mozilla/dom/Element.h"
50 : #include "nsObjectLoadingContent.h"
51 : #include "sampler.h"
52 :
53 : namespace mozilla {
54 : namespace dom {
55 :
56 : class PluginDocument : public MediaDocument
57 : , public nsIPluginDocument
58 : {
59 : public:
60 : PluginDocument();
61 : virtual ~PluginDocument();
62 :
63 : NS_DECL_ISUPPORTS_INHERITED
64 : NS_DECL_NSIPLUGINDOCUMENT
65 :
66 : virtual nsresult StartDocumentLoad(const char* aCommand,
67 : nsIChannel* aChannel,
68 : nsILoadGroup* aLoadGroup,
69 : nsISupports* aContainer,
70 : nsIStreamListener** aDocListener,
71 : bool aReset = true,
72 : nsIContentSink* aSink = nsnull);
73 :
74 : virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject);
75 : virtual bool CanSavePresentation(nsIRequest *aNewRequest);
76 :
77 0 : const nsCString& GetType() const { return mMimeType; }
78 0 : nsIContent* GetPluginContent() { return mPluginContent; }
79 :
80 0 : void AllowNormalInstantiation() {
81 0 : mWillHandleInstantiation = false;
82 0 : }
83 :
84 0 : void StartLayout() { MediaDocument::StartLayout(); }
85 :
86 1464 : NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PluginDocument, MediaDocument)
87 : protected:
88 : nsresult CreateSyntheticPluginDocument();
89 :
90 : nsCOMPtr<nsIContent> mPluginContent;
91 : nsRefPtr<MediaDocumentStreamListener> mStreamListener;
92 : nsCString mMimeType;
93 :
94 : // Hack to handle the fact that plug-in loading lives in frames and that the
95 : // frames may not be around when we need to instantiate. Once plug-in
96 : // loading moves to content, this can all go away.
97 : bool mWillHandleInstantiation;
98 : };
99 :
100 : class PluginStreamListener : public MediaDocumentStreamListener
101 0 : {
102 : public:
103 0 : PluginStreamListener(PluginDocument* doc)
104 : : MediaDocumentStreamListener(doc)
105 0 : , mPluginDoc(doc)
106 0 : {}
107 : NS_IMETHOD OnStartRequest(nsIRequest* request, nsISupports *ctxt);
108 : private:
109 : nsresult SetupPlugin();
110 :
111 : nsRefPtr<PluginDocument> mPluginDoc;
112 : };
113 :
114 :
115 : NS_IMETHODIMP
116 0 : PluginStreamListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
117 : {
118 0 : SAMPLE_LABEL("PluginStreamListener", "OnStartRequest");
119 : // Have to set up our plugin stuff before we call OnStartRequest, so
120 : // that the plugin listener can get that call.
121 0 : nsresult rv = SetupPlugin();
122 :
123 0 : NS_ASSERTION(NS_FAILED(rv) || mNextStream,
124 : "We should have a listener by now");
125 0 : nsresult rv2 = MediaDocumentStreamListener::OnStartRequest(request, ctxt);
126 0 : return NS_SUCCEEDED(rv) ? rv2 : rv;
127 : }
128 :
129 : nsresult
130 0 : PluginStreamListener::SetupPlugin()
131 : {
132 0 : NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
133 0 : mPluginDoc->StartLayout();
134 :
135 0 : nsCOMPtr<nsIContent> embed = mPluginDoc->GetPluginContent();
136 :
137 : // Now we have a frame for our <embed>, start the load
138 0 : nsCOMPtr<nsIPresShell> shell = mDocument->GetShell();
139 0 : if (!shell) {
140 : // Can't instantiate w/o a shell
141 0 : mPluginDoc->AllowNormalInstantiation();
142 0 : return NS_BINDING_ABORTED;
143 : }
144 :
145 : // Flush out layout before we go to instantiate, because some
146 : // plug-ins depend on NPP_SetWindow() being called early enough and
147 : // nsObjectFrame does that at the end of reflow.
148 0 : shell->FlushPendingNotifications(Flush_Layout);
149 :
150 0 : nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(embed));
151 0 : if (!olc) {
152 0 : return NS_ERROR_UNEXPECTED;
153 : }
154 0 : nsObjectLoadingContent* olcc = static_cast<nsObjectLoadingContent*>(olc.get());
155 0 : nsresult rv = olcc->InstantiatePluginInstance(mPluginDoc->GetType().get(),
156 0 : mDocument->nsIDocument::GetDocumentURI());
157 0 : if (NS_FAILED(rv)) {
158 0 : return rv;
159 : }
160 :
161 : // Now that we're done, allow normal instantiation in the future
162 : // (say if there's a reframe of this entire presentation).
163 0 : mPluginDoc->AllowNormalInstantiation();
164 :
165 0 : return NS_OK;
166 : }
167 :
168 :
169 : // NOTE! nsDocument::operator new() zeroes out all members, so don't
170 : // bother initializing members to 0.
171 :
172 0 : PluginDocument::PluginDocument()
173 0 : : mWillHandleInstantiation(true)
174 : {
175 0 : }
176 :
177 0 : PluginDocument::~PluginDocument()
178 : {
179 0 : }
180 :
181 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(PluginDocument)
182 :
183 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PluginDocument, MediaDocument)
184 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPluginContent)
185 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
186 :
187 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PluginDocument, MediaDocument)
188 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPluginContent)
189 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
190 :
191 0 : NS_IMPL_ADDREF_INHERITED(PluginDocument, MediaDocument)
192 0 : NS_IMPL_RELEASE_INHERITED(PluginDocument, MediaDocument)
193 :
194 0 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(PluginDocument)
195 0 : NS_INTERFACE_TABLE_INHERITED1(PluginDocument, nsIPluginDocument)
196 0 : NS_INTERFACE_TABLE_TAIL_INHERITING(MediaDocument)
197 :
198 : void
199 0 : PluginDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
200 : {
201 : // Set the script global object on the superclass before doing
202 : // anything that might require it....
203 0 : MediaDocument::SetScriptGlobalObject(aScriptGlobalObject);
204 :
205 0 : if (aScriptGlobalObject) {
206 0 : if (!mPluginContent) {
207 : // Create synthetic document
208 : #ifdef DEBUG
209 : nsresult rv =
210 : #endif
211 0 : CreateSyntheticPluginDocument();
212 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic document");
213 : }
214 : } else {
215 0 : mStreamListener = nsnull;
216 : }
217 0 : }
218 :
219 :
220 : bool
221 0 : PluginDocument::CanSavePresentation(nsIRequest *aNewRequest)
222 : {
223 : // Full-page plugins cannot be cached, currently, because we don't have
224 : // the stream listener data to feed to the plugin instance.
225 0 : return false;
226 : }
227 :
228 :
229 : nsresult
230 0 : PluginDocument::StartDocumentLoad(const char* aCommand,
231 : nsIChannel* aChannel,
232 : nsILoadGroup* aLoadGroup,
233 : nsISupports* aContainer,
234 : nsIStreamListener** aDocListener,
235 : bool aReset,
236 : nsIContentSink* aSink)
237 : {
238 : // do not allow message panes to host full-page plugins
239 : // returning an error causes helper apps to take over
240 0 : nsCOMPtr<nsIDocShellTreeItem> dsti (do_QueryInterface(aContainer));
241 0 : if (dsti) {
242 0 : bool isMsgPane = false;
243 0 : dsti->NameEquals(NS_LITERAL_STRING("messagepane").get(), &isMsgPane);
244 0 : if (isMsgPane) {
245 0 : return NS_ERROR_FAILURE;
246 : }
247 : }
248 :
249 : nsresult rv =
250 : MediaDocument::StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer,
251 0 : aDocListener, aReset, aSink);
252 0 : if (NS_FAILED(rv)) {
253 0 : return rv;
254 : }
255 :
256 0 : rv = aChannel->GetContentType(mMimeType);
257 0 : if (NS_FAILED(rv)) {
258 0 : return rv;
259 : }
260 :
261 0 : mStreamListener = new PluginStreamListener(this);
262 0 : if (!mStreamListener) {
263 0 : return NS_ERROR_OUT_OF_MEMORY;
264 : }
265 0 : NS_ASSERTION(aDocListener, "null aDocListener");
266 0 : NS_ADDREF(*aDocListener = mStreamListener);
267 :
268 0 : return rv;
269 : }
270 :
271 : nsresult
272 0 : PluginDocument::CreateSyntheticPluginDocument()
273 : {
274 0 : NS_ASSERTION(!GetShell() || !GetShell()->DidInitialReflow(),
275 : "Creating synthetic plugin document content too late");
276 :
277 : // make our generic document
278 0 : nsresult rv = MediaDocument::CreateSyntheticDocument();
279 0 : NS_ENSURE_SUCCESS(rv, rv);
280 : // then attach our plugin
281 :
282 0 : Element* body = GetBodyElement();
283 0 : if (!body) {
284 0 : NS_WARNING("no body on plugin document!");
285 0 : return NS_ERROR_FAILURE;
286 : }
287 :
288 : // remove margins from body
289 0 : NS_NAMED_LITERAL_STRING(zero, "0");
290 0 : body->SetAttr(kNameSpaceID_None, nsGkAtoms::marginwidth, zero, false);
291 0 : body->SetAttr(kNameSpaceID_None, nsGkAtoms::marginheight, zero, false);
292 :
293 :
294 : // make plugin content
295 0 : nsCOMPtr<nsINodeInfo> nodeInfo;
296 : nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::embed, nsnull,
297 : kNameSpaceID_XHTML,
298 0 : nsIDOMNode::ELEMENT_NODE);
299 0 : NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
300 0 : rv = NS_NewHTMLElement(getter_AddRefs(mPluginContent), nodeInfo.forget(),
301 0 : NOT_FROM_PARSER);
302 0 : NS_ENSURE_SUCCESS(rv, rv);
303 :
304 : // make it a named element
305 : mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::name,
306 0 : NS_LITERAL_STRING("plugin"), false);
307 :
308 : // fill viewport and auto-resize
309 0 : NS_NAMED_LITERAL_STRING(percent100, "100%");
310 : mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::width, percent100,
311 0 : false);
312 : mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::height, percent100,
313 0 : false);
314 :
315 : // set URL
316 0 : nsCAutoString src;
317 0 : mDocumentURI->GetSpec(src);
318 : mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::src,
319 0 : NS_ConvertUTF8toUTF16(src), false);
320 :
321 : // set mime type
322 : mPluginContent->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
323 0 : NS_ConvertUTF8toUTF16(mMimeType), false);
324 :
325 : // This will not start the load because nsObjectLoadingContent checks whether
326 : // its document is an nsIPluginDocument
327 0 : body->AppendChildTo(mPluginContent, false);
328 :
329 0 : return NS_OK;
330 :
331 :
332 : }
333 :
334 : NS_IMETHODIMP
335 0 : PluginDocument::SetStreamListener(nsIStreamListener *aListener)
336 : {
337 0 : if (mStreamListener) {
338 0 : mStreamListener->SetStreamListener(aListener);
339 : }
340 :
341 0 : MediaDocument::UpdateTitleAndCharset(mMimeType);
342 :
343 0 : return NS_OK;
344 : }
345 :
346 : NS_IMETHODIMP
347 0 : PluginDocument::Print()
348 : {
349 0 : NS_ENSURE_TRUE(mPluginContent, NS_ERROR_FAILURE);
350 :
351 : nsIObjectFrame* objectFrame =
352 0 : do_QueryFrame(mPluginContent->GetPrimaryFrame());
353 0 : if (objectFrame) {
354 0 : nsRefPtr<nsNPAPIPluginInstance> pi;
355 0 : objectFrame->GetPluginInstance(getter_AddRefs(pi));
356 0 : if (pi) {
357 : NPPrint npprint;
358 0 : npprint.mode = NP_FULL;
359 0 : npprint.print.fullPrint.pluginPrinted = false;
360 0 : npprint.print.fullPrint.printOne = false;
361 0 : npprint.print.fullPrint.platformPrint = nsnull;
362 :
363 0 : pi->Print(&npprint);
364 : }
365 : }
366 :
367 0 : return NS_OK;
368 : }
369 :
370 : NS_IMETHODIMP
371 0 : PluginDocument::GetWillHandleInstantiation(bool* aWillHandle)
372 : {
373 0 : *aWillHandle = mWillHandleInstantiation;
374 0 : return NS_OK;
375 : }
376 :
377 : } // namespace dom
378 : } // namespace mozilla
379 :
380 : nsresult
381 0 : NS_NewPluginDocument(nsIDocument** aResult)
382 : {
383 0 : mozilla::dom::PluginDocument* doc = new mozilla::dom::PluginDocument();
384 0 : if (!doc) {
385 0 : return NS_ERROR_OUT_OF_MEMORY;
386 : }
387 :
388 0 : NS_ADDREF(doc);
389 0 : nsresult rv = doc->Init();
390 :
391 0 : if (NS_FAILED(rv)) {
392 0 : NS_RELEASE(doc);
393 : }
394 :
395 0 : *aResult = doc;
396 :
397 0 : return rv;
398 4392 : }
|