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/. */
5
6 #include "mozilla/DebugOnly.h"
7
8 #ifdef MOZ_WIDGET_ANDROID
9 // For ScreenOrientation.h and Hal.h
10 #include "base/basictypes.h"
11 #endif
12
13 #include "mozilla/Logging.h"
14 #include "prmem.h"
15 #include "nscore.h"
16 #include "prenv.h"
17
18 #include "nsNPAPIPluginInstance.h"
19 #include "nsNPAPIPlugin.h"
20 #include "nsNPAPIPluginStreamListener.h"
21 #include "nsPluginHost.h"
22 #include "nsPluginLogging.h"
23 #include "nsContentUtils.h"
24 #include "nsPluginInstanceOwner.h"
25
26 #include "nsThreadUtils.h"
27 #include "nsIDOMElement.h"
28 #include "nsIDocument.h"
29 #include "nsIDocShell.h"
30 #include "nsIScriptGlobalObject.h"
31 #include "nsIScriptContext.h"
32 #include "nsDirectoryServiceDefs.h"
33 #include "nsJSNPRuntime.h"
34 #include "nsPluginStreamListenerPeer.h"
35 #include "nsSize.h"
36 #include "nsNetCID.h"
37 #include "nsIContent.h"
38 #include "nsVersionComparator.h"
39 #include "mozilla/Preferences.h"
40 #include "mozilla/Unused.h"
41 #include "nsILoadContext.h"
42 #include "mozilla/dom/HTMLObjectElementBinding.h"
43 #include "AudioChannelService.h"
44
45 using namespace mozilla;
46 using namespace mozilla::dom;
47
48 #ifdef MOZ_WIDGET_ANDROID
49 #include "ANPBase.h"
50 #include <android/log.h>
51 #include "android_npapi.h"
52 #include "mozilla/Mutex.h"
53 #include "mozilla/CondVar.h"
54 #include "mozilla/dom/ScreenOrientation.h"
55 #include "mozilla/Hal.h"
56 #include "GLContextProvider.h"
57 #include "GLContext.h"
58 #include "TexturePoolOGL.h"
59 #include "SurfaceTypes.h"
60 #include "EGLUtils.h"
61
62 using namespace mozilla;
63 using namespace mozilla::gl;
64
65 typedef nsNPAPIPluginInstance::VideoInfo VideoInfo;
66
67 class PluginEventRunnable : public Runnable
68 {
69 public:
PluginEventRunnable(nsNPAPIPluginInstance * instance,ANPEvent * event)70 PluginEventRunnable(nsNPAPIPluginInstance* instance, ANPEvent* event)
71 : mInstance(instance), mEvent(*event), mCanceled(false) {}
72
Run()73 virtual nsresult Run() {
74 if (mCanceled)
75 return NS_OK;
76
77 mInstance->HandleEvent(&mEvent, nullptr);
78 mInstance->PopPostedEvent(this);
79 return NS_OK;
80 }
81
Cancel()82 void Cancel() { mCanceled = true; }
83 private:
84 nsNPAPIPluginInstance* mInstance;
85 ANPEvent mEvent;
86 bool mCanceled;
87 };
88
89 static RefPtr<GLContext> sPluginContext = nullptr;
90
EnsureGLContext()91 static bool EnsureGLContext()
92 {
93 if (!sPluginContext) {
94 const auto flags = CreateContextFlags::REQUIRE_COMPAT_PROFILE;
95 nsCString discardedFailureId;
96 sPluginContext = GLContextProvider::CreateHeadless(flags, &discardedFailureId);
97 }
98
99 return sPluginContext != nullptr;
100 }
101
102 static std::map<NPP, nsNPAPIPluginInstance*> sPluginNPPMap;
103
104 #endif
105
106 using namespace mozilla;
107 using namespace mozilla::plugins::parent;
108 using namespace mozilla::layers;
109
110 static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID);
111
NS_IMPL_ISUPPORTS(nsNPAPIPluginInstance,nsIAudioChannelAgentCallback)112 NS_IMPL_ISUPPORTS(nsNPAPIPluginInstance, nsIAudioChannelAgentCallback)
113
114 nsNPAPIPluginInstance::nsNPAPIPluginInstance()
115 : mDrawingModel(kDefaultDrawingModel)
116 #ifdef MOZ_WIDGET_ANDROID
117 , mANPDrawingModel(0)
118 , mFullScreenOrientation(dom::eScreenOrientation_LandscapePrimary)
119 , mWakeLocked(false)
120 , mFullScreen(false)
121 , mOriginPos(gl::OriginPos::TopLeft)
122 #endif
123 , mRunning(NOT_STARTED)
124 , mWindowless(false)
125 , mTransparent(false)
126 , mCached(false)
127 , mUsesDOMForCursor(false)
128 , mInPluginInitCall(false)
129 , mPlugin(nullptr)
130 , mMIMEType(nullptr)
131 , mOwner(nullptr)
132 #ifdef XP_MACOSX
133 , mCurrentPluginEvent(nullptr)
134 #endif
135 #ifdef MOZ_WIDGET_ANDROID
136 , mOnScreen(true)
137 #endif
138 , mHaveJavaC2PJSObjectQuirk(false)
139 , mCachedParamLength(0)
140 , mCachedParamNames(nullptr)
141 , mCachedParamValues(nullptr)
142 , mMuted(false)
143 {
144 mNPP.pdata = nullptr;
145 mNPP.ndata = this;
146
147 PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this));
148
149 #ifdef MOZ_WIDGET_ANDROID
150 sPluginNPPMap[&mNPP] = this;
151 #endif
152 }
153
~nsNPAPIPluginInstance()154 nsNPAPIPluginInstance::~nsNPAPIPluginInstance()
155 {
156 PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance dtor: this=%p\n",this));
157
158 #ifdef MOZ_WIDGET_ANDROID
159 sPluginNPPMap.erase(&mNPP);
160 #endif
161
162 if (mMIMEType) {
163 PR_Free((void *)mMIMEType);
164 mMIMEType = nullptr;
165 }
166
167 if (!mCachedParamValues || !mCachedParamNames) {
168 return;
169 }
170 MOZ_ASSERT(mCachedParamValues && mCachedParamNames);
171
172 for (uint32_t i = 0; i < mCachedParamLength; i++) {
173 if (mCachedParamNames[i]) {
174 free(mCachedParamNames[i]);
175 mCachedParamNames[i] = nullptr;
176 }
177 if (mCachedParamValues[i]) {
178 free(mCachedParamValues[i]);
179 mCachedParamValues[i] = nullptr;
180 }
181 }
182
183 free(mCachedParamNames);
184 mCachedParamNames = nullptr;
185
186 free(mCachedParamValues);
187 mCachedParamValues = nullptr;
188 }
189
190 uint32_t nsNPAPIPluginInstance::gInUnsafePluginCalls = 0;
191
192 void
Destroy()193 nsNPAPIPluginInstance::Destroy()
194 {
195 Stop();
196 mPlugin = nullptr;
197 mAudioChannelAgent = nullptr;
198
199 #if MOZ_WIDGET_ANDROID
200 if (mContentSurface)
201 mContentSurface->SetFrameAvailableCallback(nullptr);
202
203 mContentSurface = nullptr;
204
205 std::map<void*, VideoInfo*>::iterator it;
206 for (it = mVideos.begin(); it != mVideos.end(); it++) {
207 it->second->mSurfaceTexture->SetFrameAvailableCallback(nullptr);
208 delete it->second;
209 }
210 mVideos.clear();
211 SetWakeLock(false);
212 #endif
213 }
214
215 TimeStamp
StopTime()216 nsNPAPIPluginInstance::StopTime()
217 {
218 return mStopTime;
219 }
220
Initialize(nsNPAPIPlugin * aPlugin,nsPluginInstanceOwner * aOwner,const nsACString & aMIMEType)221 nsresult nsNPAPIPluginInstance::Initialize(nsNPAPIPlugin *aPlugin, nsPluginInstanceOwner* aOwner, const nsACString& aMIMEType)
222 {
223 PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
224 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::Initialize this=%p\n",this));
225
226 NS_ENSURE_ARG_POINTER(aPlugin);
227 NS_ENSURE_ARG_POINTER(aOwner);
228
229 mPlugin = aPlugin;
230 mOwner = aOwner;
231
232 if (!aMIMEType.IsEmpty()) {
233 mMIMEType = ToNewCString(aMIMEType);
234 }
235
236 return Start();
237 }
238
Stop()239 nsresult nsNPAPIPluginInstance::Stop()
240 {
241 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::Stop this=%p\n",this));
242
243 // Make sure the plugin didn't leave popups enabled.
244 if (mPopupStates.Length() > 0) {
245 nsCOMPtr<nsPIDOMWindowOuter> window = GetDOMWindow();
246
247 if (window) {
248 window->PopPopupControlState(openAbused);
249 }
250 }
251
252 if (RUNNING != mRunning) {
253 return NS_OK;
254 }
255
256 // clean up all outstanding timers
257 for (uint32_t i = mTimers.Length(); i > 0; i--)
258 UnscheduleTimer(mTimers[i - 1]->id);
259
260 // If there's code from this plugin instance on the stack, delay the
261 // destroy.
262 if (PluginDestructionGuard::DelayDestroy(this)) {
263 return NS_OK;
264 }
265
266 // Make sure we lock while we're writing to mRunning after we've
267 // started as other threads might be checking that inside a lock.
268 {
269 AsyncCallbackAutoLock lock;
270 mRunning = DESTROYING;
271 mStopTime = TimeStamp::Now();
272 }
273
274 OnPluginDestroy(&mNPP);
275
276 // clean up open streams
277 while (mStreamListeners.Length() > 0) {
278 RefPtr<nsNPAPIPluginStreamListener> currentListener(mStreamListeners[0]);
279 currentListener->CleanUpStream(NPRES_USER_BREAK);
280 mStreamListeners.RemoveElement(currentListener);
281 }
282
283 if (!mPlugin || !mPlugin->GetLibrary())
284 return NS_ERROR_FAILURE;
285
286 NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
287
288 NPError error = NPERR_GENERIC_ERROR;
289 if (pluginFunctions->destroy) {
290 NPSavedData *sdata = 0;
291
292 NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->destroy)(&mNPP, &sdata), this,
293 NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
294
295 NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
296 ("NPP Destroy called: this=%p, npp=%p, return=%d\n", this, &mNPP, error));
297 }
298 mRunning = DESTROYED;
299
300 #if MOZ_WIDGET_ANDROID
301 for (uint32_t i = 0; i < mPostedEvents.Length(); i++) {
302 mPostedEvents[i]->Cancel();
303 }
304
305 mPostedEvents.Clear();
306 #endif
307
308 nsJSNPRuntime::OnPluginDestroy(&mNPP);
309
310 if (error != NPERR_NO_ERROR)
311 return NS_ERROR_FAILURE;
312 else
313 return NS_OK;
314 }
315
316 already_AddRefed<nsPIDOMWindowOuter>
GetDOMWindow()317 nsNPAPIPluginInstance::GetDOMWindow()
318 {
319 if (!mOwner)
320 return nullptr;
321
322 RefPtr<nsPluginInstanceOwner> kungFuDeathGrip(mOwner);
323
324 nsCOMPtr<nsIDocument> doc;
325 kungFuDeathGrip->GetDocument(getter_AddRefs(doc));
326 if (!doc)
327 return nullptr;
328
329 RefPtr<nsPIDOMWindowOuter> window = doc->GetWindow();
330
331 return window.forget();
332 }
333
334 nsresult
GetTagType(nsPluginTagType * result)335 nsNPAPIPluginInstance::GetTagType(nsPluginTagType *result)
336 {
337 if (!mOwner) {
338 return NS_ERROR_FAILURE;
339 }
340
341 return mOwner->GetTagType(result);
342 }
343
344 nsresult
GetMode(int32_t * result)345 nsNPAPIPluginInstance::GetMode(int32_t *result)
346 {
347 if (mOwner)
348 return mOwner->GetMode(result);
349 else
350 return NS_ERROR_FAILURE;
351 }
352
353 nsTArray<nsNPAPIPluginStreamListener*>*
StreamListeners()354 nsNPAPIPluginInstance::StreamListeners()
355 {
356 return &mStreamListeners;
357 }
358
359 nsTArray<nsPluginStreamListenerPeer*>*
FileCachedStreamListeners()360 nsNPAPIPluginInstance::FileCachedStreamListeners()
361 {
362 return &mFileCachedStreamListeners;
363 }
364
365 nsresult
Start()366 nsNPAPIPluginInstance::Start()
367 {
368 if (mRunning == RUNNING) {
369 return NS_OK;
370 }
371
372 if (!mOwner) {
373 MOZ_ASSERT(false, "Should not be calling Start() on unowned plugin.");
374 return NS_ERROR_FAILURE;
375 }
376
377 PluginDestructionGuard guard(this);
378
379 nsTArray<MozPluginParameter> attributes;
380 nsTArray<MozPluginParameter> params;
381
382 nsPluginTagType tagtype;
383 nsresult rv = GetTagType(&tagtype);
384 if (NS_SUCCEEDED(rv)) {
385 mOwner->GetAttributes(attributes);
386 mOwner->GetParameters(params);
387 } else {
388 MOZ_ASSERT(false, "Failed to get tag type.");
389 }
390
391 mCachedParamLength = attributes.Length() + 1 + params.Length();
392
393 // We add an extra entry "PARAM" as a separator between the attribute
394 // and param values, but we don't count it if there are no <param> entries.
395 // Legacy behavior quirk.
396 uint32_t quirkParamLength = params.Length() ?
397 mCachedParamLength : attributes.Length();
398
399 mCachedParamNames = (char**)moz_xmalloc(sizeof(char*) * mCachedParamLength);
400 mCachedParamValues = (char**)moz_xmalloc(sizeof(char*) * mCachedParamLength);
401
402 for (uint32_t i = 0; i < attributes.Length(); i++) {
403 mCachedParamNames[i] = ToNewUTF8String(attributes[i].mName);
404 mCachedParamValues[i] = ToNewUTF8String(attributes[i].mValue);
405 }
406
407 // Android expects and empty string instead of null.
408 mCachedParamNames[attributes.Length()] = ToNewUTF8String(NS_LITERAL_STRING("PARAM"));
409 #ifdef MOZ_WIDGET_ANDROID
410 mCachedParamValues[attributes.Length()] = ToNewUTF8String(NS_LITERAL_STRING(""));
411 #else
412 mCachedParamValues[attributes.Length()] = nullptr;
413 #endif
414
415 for (uint32_t i = 0, pos = attributes.Length() + 1; i < params.Length(); i ++) {
416 mCachedParamNames[pos] = ToNewUTF8String(params[i].mName);
417 mCachedParamValues[pos] = ToNewUTF8String(params[i].mValue);
418 pos++;
419 }
420
421 int32_t mode;
422 const char* mimetype;
423 NPError error = NPERR_GENERIC_ERROR;
424
425 GetMode(&mode);
426 GetMIMEType(&mimetype);
427
428 CheckJavaC2PJSObjectQuirk(quirkParamLength, mCachedParamNames, mCachedParamValues);
429
430 bool oldVal = mInPluginInitCall;
431 mInPluginInitCall = true;
432
433 // Need this on the stack before calling NPP_New otherwise some callbacks that
434 // the plugin may make could fail (NPN_HasProperty, for example).
435 NPPAutoPusher autopush(&mNPP);
436
437 if (!mPlugin)
438 return NS_ERROR_FAILURE;
439
440 PluginLibrary* library = mPlugin->GetLibrary();
441 if (!library)
442 return NS_ERROR_FAILURE;
443
444 // Mark this instance as running before calling NPP_New because the plugin may
445 // call other NPAPI functions, like NPN_GetURLNotify, that assume this is set
446 // before returning. If the plugin returns failure, we'll clear it out below.
447 mRunning = RUNNING;
448
449 nsresult newResult = library->NPP_New((char*)mimetype, &mNPP, (uint16_t)mode,
450 quirkParamLength, mCachedParamNames,
451 mCachedParamValues, nullptr, &error);
452 mInPluginInitCall = oldVal;
453
454 NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
455 ("NPP New called: this=%p, npp=%p, mime=%s, mode=%d, argc=%d, return=%d\n",
456 this, &mNPP, mimetype, mode, quirkParamLength, error));
457
458 if (NS_FAILED(newResult) || error != NPERR_NO_ERROR) {
459 mRunning = DESTROYED;
460 nsJSNPRuntime::OnPluginDestroy(&mNPP);
461 return NS_ERROR_FAILURE;
462 }
463
464 return newResult;
465 }
466
SetWindow(NPWindow * window)467 nsresult nsNPAPIPluginInstance::SetWindow(NPWindow* window)
468 {
469 // NPAPI plugins don't want a SetWindow(nullptr).
470 if (!window || RUNNING != mRunning)
471 return NS_OK;
472
473 #if MOZ_WIDGET_GTK
474 // bug 108347, flash plugin on linux doesn't like window->width <=
475 // 0, but Java needs wants this call.
476 if (window && window->type == NPWindowTypeWindow &&
477 (window->width <= 0 || window->height <= 0) &&
478 (nsPluginHost::GetSpecialType(nsDependentCString(mMIMEType)) !=
479 nsPluginHost::eSpecialType_Java)) {
480 return NS_OK;
481 }
482 #endif
483
484 if (!mPlugin || !mPlugin->GetLibrary())
485 return NS_ERROR_FAILURE;
486
487 NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
488
489 if (pluginFunctions->setwindow) {
490 PluginDestructionGuard guard(this);
491
492 // XXX Turns out that NPPluginWindow and NPWindow are structurally
493 // identical (on purpose!), so there's no need to make a copy.
494
495 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetWindow (about to call it) this=%p\n",this));
496
497 bool oldVal = mInPluginInitCall;
498 mInPluginInitCall = true;
499
500 NPPAutoPusher nppPusher(&mNPP);
501
502 NPError error;
503 NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setwindow)(&mNPP, (NPWindow*)window), this,
504 NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
505 // 'error' is only used if this is a logging-enabled build.
506 // That is somewhat complex to check, so we just use "unused"
507 // to suppress any compiler warnings in build configurations
508 // where the logging is a no-op.
509 mozilla::Unused << error;
510
511 mInPluginInitCall = oldVal;
512
513 NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
514 ("NPP SetWindow called: this=%p, [x=%d,y=%d,w=%d,h=%d], clip[t=%d,b=%d,l=%d,r=%d], return=%d\n",
515 this, window->x, window->y, window->width, window->height,
516 window->clipRect.top, window->clipRect.bottom, window->clipRect.left, window->clipRect.right, error));
517 }
518 return NS_OK;
519 }
520
521 nsresult
NewStreamFromPlugin(const char * type,const char * target,nsIOutputStream ** result)522 nsNPAPIPluginInstance::NewStreamFromPlugin(const char* type, const char* target,
523 nsIOutputStream* *result)
524 {
525 nsPluginStreamToFile* stream = new nsPluginStreamToFile(target, mOwner);
526 return stream->QueryInterface(kIOutputStreamIID, (void**)result);
527 }
528
529 nsresult
NewStreamListener(const char * aURL,void * notifyData,nsNPAPIPluginStreamListener ** listener)530 nsNPAPIPluginInstance::NewStreamListener(const char* aURL, void* notifyData,
531 nsNPAPIPluginStreamListener** listener)
532 {
533 RefPtr<nsNPAPIPluginStreamListener> sl = new nsNPAPIPluginStreamListener(this, notifyData, aURL);
534
535 mStreamListeners.AppendElement(sl);
536
537 sl.forget(listener);
538
539 return NS_OK;
540 }
541
Print(NPPrint * platformPrint)542 nsresult nsNPAPIPluginInstance::Print(NPPrint* platformPrint)
543 {
544 NS_ENSURE_TRUE(platformPrint, NS_ERROR_NULL_POINTER);
545
546 PluginDestructionGuard guard(this);
547
548 if (!mPlugin || !mPlugin->GetLibrary())
549 return NS_ERROR_FAILURE;
550
551 NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
552
553 NPPrint* thePrint = (NPPrint *)platformPrint;
554
555 // to be compatible with the older SDK versions and to match what
556 // NPAPI and other browsers do, overwrite |window.type| field with one
557 // more copy of |platformPrint|. See bug 113264
558 uint16_t sdkmajorversion = (pluginFunctions->version & 0xff00)>>8;
559 uint16_t sdkminorversion = pluginFunctions->version & 0x00ff;
560 if ((sdkmajorversion == 0) && (sdkminorversion < 11)) {
561 // Let's copy platformPrint bytes over to where it was supposed to be
562 // in older versions -- four bytes towards the beginning of the struct
563 // but we should be careful about possible misalignments
564 if (sizeof(NPWindowType) >= sizeof(void *)) {
565 void* source = thePrint->print.embedPrint.platformPrint;
566 void** destination = (void **)&(thePrint->print.embedPrint.window.type);
567 *destination = source;
568 } else {
569 NS_ERROR("Incompatible OS for assignment");
570 }
571 }
572
573 if (pluginFunctions->print)
574 NS_TRY_SAFE_CALL_VOID((*pluginFunctions->print)(&mNPP, thePrint), this,
575 NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
576
577 NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
578 ("NPP PrintProc called: this=%p, pDC=%p, [x=%d,y=%d,w=%d,h=%d], clip[t=%d,b=%d,l=%d,r=%d]\n",
579 this,
580 platformPrint->print.embedPrint.platformPrint,
581 platformPrint->print.embedPrint.window.x,
582 platformPrint->print.embedPrint.window.y,
583 platformPrint->print.embedPrint.window.width,
584 platformPrint->print.embedPrint.window.height,
585 platformPrint->print.embedPrint.window.clipRect.top,
586 platformPrint->print.embedPrint.window.clipRect.bottom,
587 platformPrint->print.embedPrint.window.clipRect.left,
588 platformPrint->print.embedPrint.window.clipRect.right));
589
590 return NS_OK;
591 }
592
HandleEvent(void * event,int16_t * result,NSPluginCallReentry aSafeToReenterGecko)593 nsresult nsNPAPIPluginInstance::HandleEvent(void* event, int16_t* result,
594 NSPluginCallReentry aSafeToReenterGecko)
595 {
596 if (RUNNING != mRunning)
597 return NS_OK;
598
599 PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
600
601 if (!event)
602 return NS_ERROR_FAILURE;
603
604 PluginDestructionGuard guard(this);
605
606 if (!mPlugin || !mPlugin->GetLibrary())
607 return NS_ERROR_FAILURE;
608
609 NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
610
611 int16_t tmpResult = kNPEventNotHandled;
612
613 if (pluginFunctions->event) {
614 #ifdef XP_MACOSX
615 mCurrentPluginEvent = event;
616 #endif
617 #if defined(XP_WIN)
618 NS_TRY_SAFE_CALL_RETURN(tmpResult, (*pluginFunctions->event)(&mNPP, event), this,
619 aSafeToReenterGecko);
620 #else
621 MAIN_THREAD_JNI_REF_GUARD;
622 tmpResult = (*pluginFunctions->event)(&mNPP, event);
623 #endif
624 NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
625 ("NPP HandleEvent called: this=%p, npp=%p, event=%p, return=%d\n",
626 this, &mNPP, event, tmpResult));
627
628 if (result)
629 *result = tmpResult;
630 #ifdef XP_MACOSX
631 mCurrentPluginEvent = nullptr;
632 #endif
633 }
634
635 return NS_OK;
636 }
637
GetValueFromPlugin(NPPVariable variable,void * value)638 nsresult nsNPAPIPluginInstance::GetValueFromPlugin(NPPVariable variable, void* value)
639 {
640 if (!mPlugin || !mPlugin->GetLibrary())
641 return NS_ERROR_FAILURE;
642
643 NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
644
645 nsresult rv = NS_ERROR_FAILURE;
646
647 if (pluginFunctions->getvalue && RUNNING == mRunning) {
648 PluginDestructionGuard guard(this);
649
650 NPError pluginError = NPERR_GENERIC_ERROR;
651 NS_TRY_SAFE_CALL_RETURN(pluginError, (*pluginFunctions->getvalue)(&mNPP, variable, value), this,
652 NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
653 NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
654 ("NPP GetValue called: this=%p, npp=%p, var=%d, value=%d, return=%d\n",
655 this, &mNPP, variable, value, pluginError));
656
657 if (pluginError == NPERR_NO_ERROR) {
658 rv = NS_OK;
659 }
660 }
661
662 return rv;
663 }
664
GetPlugin()665 nsNPAPIPlugin* nsNPAPIPluginInstance::GetPlugin()
666 {
667 return mPlugin;
668 }
669
GetNPP(NPP * aNPP)670 nsresult nsNPAPIPluginInstance::GetNPP(NPP* aNPP)
671 {
672 if (aNPP)
673 *aNPP = &mNPP;
674 else
675 return NS_ERROR_NULL_POINTER;
676
677 return NS_OK;
678 }
679
SetWindowless(bool aWindowless)680 NPError nsNPAPIPluginInstance::SetWindowless(bool aWindowless)
681 {
682 mWindowless = aWindowless;
683
684 if (mMIMEType) {
685 // bug 558434 - Prior to 3.6.4, we assumed windowless was transparent.
686 // Silverlight apparently relied on this quirk, so we default to
687 // transparent unless they specify otherwise after setting the windowless
688 // property. (Last tested version: sl 4.0).
689 // Changes to this code should be matched with changes in
690 // PluginInstanceChild::InitQuirksMode.
691 if (nsPluginHost::GetSpecialType(nsDependentCString(mMIMEType)) ==
692 nsPluginHost::eSpecialType_Silverlight) {
693 mTransparent = true;
694 }
695 }
696
697 return NPERR_NO_ERROR;
698 }
699
SetTransparent(bool aTransparent)700 NPError nsNPAPIPluginInstance::SetTransparent(bool aTransparent)
701 {
702 mTransparent = aTransparent;
703 return NPERR_NO_ERROR;
704 }
705
SetUsesDOMForCursor(bool aUsesDOMForCursor)706 NPError nsNPAPIPluginInstance::SetUsesDOMForCursor(bool aUsesDOMForCursor)
707 {
708 mUsesDOMForCursor = aUsesDOMForCursor;
709 return NPERR_NO_ERROR;
710 }
711
712 bool
UsesDOMForCursor()713 nsNPAPIPluginInstance::UsesDOMForCursor()
714 {
715 return mUsesDOMForCursor;
716 }
717
SetDrawingModel(NPDrawingModel aModel)718 void nsNPAPIPluginInstance::SetDrawingModel(NPDrawingModel aModel)
719 {
720 mDrawingModel = aModel;
721 }
722
RedrawPlugin()723 void nsNPAPIPluginInstance::RedrawPlugin()
724 {
725 mOwner->RedrawPlugin();
726 }
727
728 #if defined(XP_MACOSX)
SetEventModel(NPEventModel aModel)729 void nsNPAPIPluginInstance::SetEventModel(NPEventModel aModel)
730 {
731 // the event model needs to be set for the object frame immediately
732 if (!mOwner) {
733 NS_WARNING("Trying to set event model without a plugin instance owner!");
734 return;
735 }
736
737 mOwner->SetEventModel(aModel);
738 }
739 #endif
740
741 #if defined(MOZ_WIDGET_ANDROID)
742
SendLifecycleEvent(nsNPAPIPluginInstance * aInstance,uint32_t aAction)743 static void SendLifecycleEvent(nsNPAPIPluginInstance* aInstance, uint32_t aAction)
744 {
745 ANPEvent event;
746 event.inSize = sizeof(ANPEvent);
747 event.eventType = kLifecycle_ANPEventType;
748 event.data.lifecycle.action = aAction;
749 aInstance->HandleEvent(&event, nullptr);
750 }
751
NotifyForeground(bool aForeground)752 void nsNPAPIPluginInstance::NotifyForeground(bool aForeground)
753 {
754 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetForeground this=%p\n foreground=%d",this, aForeground));
755 if (RUNNING != mRunning)
756 return;
757
758 SendLifecycleEvent(this, aForeground ? kResume_ANPLifecycleAction : kPause_ANPLifecycleAction);
759 }
760
NotifyOnScreen(bool aOnScreen)761 void nsNPAPIPluginInstance::NotifyOnScreen(bool aOnScreen)
762 {
763 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::SetOnScreen this=%p\n onScreen=%d",this, aOnScreen));
764 if (RUNNING != mRunning || mOnScreen == aOnScreen)
765 return;
766
767 mOnScreen = aOnScreen;
768 SendLifecycleEvent(this, aOnScreen ? kOnScreen_ANPLifecycleAction : kOffScreen_ANPLifecycleAction);
769 }
770
MemoryPressure()771 void nsNPAPIPluginInstance::MemoryPressure()
772 {
773 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::MemoryPressure this=%p\n",this));
774 if (RUNNING != mRunning)
775 return;
776
777 SendLifecycleEvent(this, kFreeMemory_ANPLifecycleAction);
778 }
779
NotifyFullScreen(bool aFullScreen)780 void nsNPAPIPluginInstance::NotifyFullScreen(bool aFullScreen)
781 {
782 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::NotifyFullScreen this=%p\n",this));
783
784 if (RUNNING != mRunning || mFullScreen == aFullScreen)
785 return;
786
787 mFullScreen = aFullScreen;
788 SendLifecycleEvent(this, mFullScreen ? kEnterFullScreen_ANPLifecycleAction : kExitFullScreen_ANPLifecycleAction);
789
790 if (mFullScreen && mFullScreenOrientation != dom::eScreenOrientation_None) {
791 java::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
792 }
793 }
794
NotifySize(nsIntSize size)795 void nsNPAPIPluginInstance::NotifySize(nsIntSize size)
796 {
797 if (kOpenGL_ANPDrawingModel != GetANPDrawingModel() ||
798 size == mCurrentSize)
799 return;
800
801 mCurrentSize = size;
802
803 ANPEvent event;
804 event.inSize = sizeof(ANPEvent);
805 event.eventType = kDraw_ANPEventType;
806 event.data.draw.model = kOpenGL_ANPDrawingModel;
807 event.data.draw.data.surfaceSize.width = size.width;
808 event.data.draw.data.surfaceSize.height = size.height;
809
810 HandleEvent(&event, nullptr);
811 }
812
SetANPDrawingModel(uint32_t aModel)813 void nsNPAPIPluginInstance::SetANPDrawingModel(uint32_t aModel)
814 {
815 mANPDrawingModel = aModel;
816 }
817
GetJavaSurface()818 void* nsNPAPIPluginInstance::GetJavaSurface()
819 {
820 void* surface = nullptr;
821 nsresult rv = GetValueFromPlugin(kJavaSurface_ANPGetValue, &surface);
822 if (NS_FAILED(rv))
823 return nullptr;
824
825 return surface;
826 }
827
PostEvent(void * event)828 void nsNPAPIPluginInstance::PostEvent(void* event)
829 {
830 PluginEventRunnable *r = new PluginEventRunnable(this, (ANPEvent*)event);
831 mPostedEvents.AppendElement(RefPtr<PluginEventRunnable>(r));
832
833 NS_DispatchToMainThread(r);
834 }
835
SetFullScreenOrientation(uint32_t orientation)836 void nsNPAPIPluginInstance::SetFullScreenOrientation(uint32_t orientation)
837 {
838 if (mFullScreenOrientation == orientation)
839 return;
840
841 uint32_t oldOrientation = mFullScreenOrientation;
842 mFullScreenOrientation = orientation;
843
844 if (mFullScreen) {
845 // We're already fullscreen so immediately apply the orientation change
846
847 if (mFullScreenOrientation != dom::eScreenOrientation_None) {
848 java::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
849 } else if (oldOrientation != dom::eScreenOrientation_None) {
850 // We applied an orientation when we entered fullscreen, but
851 // we don't want it anymore
852 java::GeckoAppShell::UnlockScreenOrientation();
853 }
854 }
855 }
856
PopPostedEvent(PluginEventRunnable * r)857 void nsNPAPIPluginInstance::PopPostedEvent(PluginEventRunnable* r)
858 {
859 mPostedEvents.RemoveElement(r);
860 }
861
SetWakeLock(bool aLocked)862 void nsNPAPIPluginInstance::SetWakeLock(bool aLocked)
863 {
864 if (aLocked == mWakeLocked)
865 return;
866
867 mWakeLocked = aLocked;
868 hal::ModifyWakeLock(NS_LITERAL_STRING("screen"),
869 mWakeLocked ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_REMOVE_ONE,
870 hal::WAKE_LOCK_NO_CHANGE);
871 }
872
GLContext()873 GLContext* nsNPAPIPluginInstance::GLContext()
874 {
875 if (!EnsureGLContext())
876 return nullptr;
877
878 return sPluginContext;
879 }
880
CreateSurfaceTexture()881 already_AddRefed<AndroidSurfaceTexture> nsNPAPIPluginInstance::CreateSurfaceTexture()
882 {
883 if (!EnsureGLContext())
884 return nullptr;
885
886 GLuint texture = TexturePoolOGL::AcquireTexture();
887 if (!texture)
888 return nullptr;
889
890 RefPtr<AndroidSurfaceTexture> surface = AndroidSurfaceTexture::Create(TexturePoolOGL::GetGLContext(),
891 texture);
892 if (!surface) {
893 return nullptr;
894 }
895
896 nsCOMPtr<nsIRunnable> frameCallback = NewRunnableMethod(this, &nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable);
897 surface->SetFrameAvailableCallback(frameCallback);
898 return surface.forget();
899 }
900
OnSurfaceTextureFrameAvailable()901 void nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable()
902 {
903 if (mRunning == RUNNING && mOwner)
904 mOwner->Recomposite();
905 }
906
AcquireContentWindow()907 void* nsNPAPIPluginInstance::AcquireContentWindow()
908 {
909 if (!mContentSurface) {
910 mContentSurface = CreateSurfaceTexture();
911
912 if (!mContentSurface)
913 return nullptr;
914 }
915
916 return mContentSurface->NativeWindow();
917 }
918
919 AndroidSurfaceTexture*
AsSurfaceTexture()920 nsNPAPIPluginInstance::AsSurfaceTexture()
921 {
922 if (!mContentSurface)
923 return nullptr;
924
925 return mContentSurface;
926 }
927
AcquireVideoWindow()928 void* nsNPAPIPluginInstance::AcquireVideoWindow()
929 {
930 RefPtr<AndroidSurfaceTexture> surface = CreateSurfaceTexture();
931 if (!surface) {
932 return nullptr;
933 }
934
935 VideoInfo* info = new VideoInfo(surface);
936
937 void* window = info->mSurfaceTexture->NativeWindow();
938 mVideos.insert(std::pair<void*, VideoInfo*>(window, info));
939
940 return window;
941 }
942
ReleaseVideoWindow(void * window)943 void nsNPAPIPluginInstance::ReleaseVideoWindow(void* window)
944 {
945 std::map<void*, VideoInfo*>::iterator it = mVideos.find(window);
946 if (it == mVideos.end())
947 return;
948
949 delete it->second;
950 mVideos.erase(window);
951 }
952
SetVideoDimensions(void * window,gfxRect aDimensions)953 void nsNPAPIPluginInstance::SetVideoDimensions(void* window, gfxRect aDimensions)
954 {
955 std::map<void*, VideoInfo*>::iterator it;
956
957 it = mVideos.find(window);
958 if (it == mVideos.end())
959 return;
960
961 it->second->mDimensions = aDimensions;
962 }
963
GetVideos(nsTArray<VideoInfo * > & aVideos)964 void nsNPAPIPluginInstance::GetVideos(nsTArray<VideoInfo*>& aVideos)
965 {
966 std::map<void*, VideoInfo*>::iterator it;
967 for (it = mVideos.begin(); it != mVideos.end(); it++)
968 aVideos.AppendElement(it->second);
969 }
970
GetFromNPP(NPP npp)971 nsNPAPIPluginInstance* nsNPAPIPluginInstance::GetFromNPP(NPP npp)
972 {
973 std::map<NPP, nsNPAPIPluginInstance*>::iterator it;
974
975 it = sPluginNPPMap.find(npp);
976 if (it == sPluginNPPMap.end())
977 return nullptr;
978
979 return it->second;
980 }
981
982 #endif
983
GetDrawingModel(int32_t * aModel)984 nsresult nsNPAPIPluginInstance::GetDrawingModel(int32_t* aModel)
985 {
986 *aModel = (int32_t)mDrawingModel;
987 return NS_OK;
988 }
989
IsRemoteDrawingCoreAnimation(bool * aDrawing)990 nsresult nsNPAPIPluginInstance::IsRemoteDrawingCoreAnimation(bool* aDrawing)
991 {
992 #ifdef XP_MACOSX
993 if (!mPlugin)
994 return NS_ERROR_FAILURE;
995
996 PluginLibrary* library = mPlugin->GetLibrary();
997 if (!library)
998 return NS_ERROR_FAILURE;
999
1000 return library->IsRemoteDrawingCoreAnimation(&mNPP, aDrawing);
1001 #else
1002 return NS_ERROR_FAILURE;
1003 #endif
1004 }
1005
1006 nsresult
ContentsScaleFactorChanged(double aContentsScaleFactor)1007 nsNPAPIPluginInstance::ContentsScaleFactorChanged(double aContentsScaleFactor)
1008 {
1009 #if defined(XP_MACOSX) || defined(XP_WIN)
1010 if (!mPlugin)
1011 return NS_ERROR_FAILURE;
1012
1013 PluginLibrary* library = mPlugin->GetLibrary();
1014 if (!library)
1015 return NS_ERROR_FAILURE;
1016
1017 // We only need to call this if the plugin is running OOP.
1018 if (!library->IsOOP())
1019 return NS_OK;
1020
1021 return library->ContentsScaleFactorChanged(&mNPP, aContentsScaleFactor);
1022 #else
1023 return NS_ERROR_FAILURE;
1024 #endif
1025 }
1026
1027 nsresult
CSSZoomFactorChanged(float aCSSZoomFactor)1028 nsNPAPIPluginInstance::CSSZoomFactorChanged(float aCSSZoomFactor)
1029 {
1030 if (RUNNING != mRunning)
1031 return NS_OK;
1032
1033 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance informing plugin of CSS Zoom Factor change this=%p\n",this));
1034
1035 if (!mPlugin || !mPlugin->GetLibrary())
1036 return NS_ERROR_FAILURE;
1037
1038 NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
1039
1040 if (!pluginFunctions->setvalue)
1041 return NS_ERROR_FAILURE;
1042
1043 PluginDestructionGuard guard(this);
1044
1045 NPError error;
1046 double value = static_cast<double>(aCSSZoomFactor);
1047 NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setvalue)(&mNPP, NPNVCSSZoomFactor, &value), this,
1048 NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
1049 return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE;
1050 }
1051
1052 nsresult
GetJSObject(JSContext * cx,JSObject ** outObject)1053 nsNPAPIPluginInstance::GetJSObject(JSContext *cx, JSObject** outObject)
1054 {
1055 if (mHaveJavaC2PJSObjectQuirk) {
1056 return NS_ERROR_FAILURE;
1057 }
1058
1059 NPObject *npobj = nullptr;
1060 nsresult rv = GetValueFromPlugin(NPPVpluginScriptableNPObject, &npobj);
1061 if (NS_FAILED(rv) || !npobj)
1062 return NS_ERROR_FAILURE;
1063
1064 *outObject = nsNPObjWrapper::GetNewOrUsed(&mNPP, cx, npobj);
1065
1066 _releaseobject(npobj);
1067
1068 return NS_OK;
1069 }
1070
1071 void
SetCached(bool aCache)1072 nsNPAPIPluginInstance::SetCached(bool aCache)
1073 {
1074 mCached = aCache;
1075 }
1076
1077 bool
ShouldCache()1078 nsNPAPIPluginInstance::ShouldCache()
1079 {
1080 return mCached;
1081 }
1082
1083 nsresult
IsWindowless(bool * isWindowless)1084 nsNPAPIPluginInstance::IsWindowless(bool* isWindowless)
1085 {
1086 #if defined(MOZ_WIDGET_ANDROID) || defined(XP_MACOSX)
1087 // All OS X plugins are windowless.
1088 // On android, pre-honeycomb, all plugins are treated as windowless.
1089 *isWindowless = true;
1090 #else
1091 *isWindowless = mWindowless;
1092 #endif
1093 return NS_OK;
1094 }
1095
1096 class MOZ_STACK_CLASS AutoPluginLibraryCall
1097 {
1098 public:
AutoPluginLibraryCall(nsNPAPIPluginInstance * aThis)1099 explicit AutoPluginLibraryCall(nsNPAPIPluginInstance* aThis)
1100 : mThis(aThis), mGuard(aThis), mLibrary(nullptr)
1101 {
1102 nsNPAPIPlugin* plugin = mThis->GetPlugin();
1103 if (plugin)
1104 mLibrary = plugin->GetLibrary();
1105 }
operator bool()1106 explicit operator bool() { return !!mLibrary; }
operator ->()1107 PluginLibrary* operator->() { return mLibrary; }
1108
1109 private:
1110 nsNPAPIPluginInstance* mThis;
1111 PluginDestructionGuard mGuard;
1112 PluginLibrary* mLibrary;
1113 };
1114
1115 nsresult
AsyncSetWindow(NPWindow * window)1116 nsNPAPIPluginInstance::AsyncSetWindow(NPWindow* window)
1117 {
1118 if (RUNNING != mRunning)
1119 return NS_OK;
1120
1121 AutoPluginLibraryCall library(this);
1122 if (!library)
1123 return NS_ERROR_FAILURE;
1124
1125 return library->AsyncSetWindow(&mNPP, window);
1126 }
1127
1128 nsresult
GetImageContainer(ImageContainer ** aContainer)1129 nsNPAPIPluginInstance::GetImageContainer(ImageContainer**aContainer)
1130 {
1131 *aContainer = nullptr;
1132
1133 if (RUNNING != mRunning)
1134 return NS_OK;
1135
1136 AutoPluginLibraryCall library(this);
1137 return !library ? NS_ERROR_FAILURE : library->GetImageContainer(&mNPP, aContainer);
1138 }
1139
1140 nsresult
GetImageSize(nsIntSize * aSize)1141 nsNPAPIPluginInstance::GetImageSize(nsIntSize* aSize)
1142 {
1143 *aSize = nsIntSize(0, 0);
1144
1145 if (RUNNING != mRunning)
1146 return NS_OK;
1147
1148 AutoPluginLibraryCall library(this);
1149 return !library ? NS_ERROR_FAILURE : library->GetImageSize(&mNPP, aSize);
1150 }
1151
1152 #if defined(XP_WIN)
1153 nsresult
GetScrollCaptureContainer(ImageContainer ** aContainer)1154 nsNPAPIPluginInstance::GetScrollCaptureContainer(ImageContainer**aContainer)
1155 {
1156 *aContainer = nullptr;
1157
1158 if (RUNNING != mRunning)
1159 return NS_OK;
1160
1161 AutoPluginLibraryCall library(this);
1162 return !library ? NS_ERROR_FAILURE : library->GetScrollCaptureContainer(&mNPP, aContainer);
1163 }
1164 #endif
1165
1166 nsresult
HandledWindowedPluginKeyEvent(const NativeEventData & aKeyEventData,bool aIsConsumed)1167 nsNPAPIPluginInstance::HandledWindowedPluginKeyEvent(
1168 const NativeEventData& aKeyEventData,
1169 bool aIsConsumed)
1170 {
1171 if (NS_WARN_IF(!mPlugin)) {
1172 return NS_ERROR_FAILURE;
1173 }
1174
1175 PluginLibrary* library = mPlugin->GetLibrary();
1176 if (NS_WARN_IF(!library)) {
1177 return NS_ERROR_FAILURE;
1178 }
1179 return library->HandledWindowedPluginKeyEvent(&mNPP, aKeyEventData,
1180 aIsConsumed);
1181 }
1182
1183 void
DidComposite()1184 nsNPAPIPluginInstance::DidComposite()
1185 {
1186 if (RUNNING != mRunning)
1187 return;
1188
1189 AutoPluginLibraryCall library(this);
1190 library->DidComposite(&mNPP);
1191 }
1192
1193 nsresult
NotifyPainted(void)1194 nsNPAPIPluginInstance::NotifyPainted(void)
1195 {
1196 NS_NOTREACHED("Dead code, shouldn't be called.");
1197 return NS_ERROR_NOT_IMPLEMENTED;
1198 }
1199
1200 nsresult
GetIsOOP(bool * aIsAsync)1201 nsNPAPIPluginInstance::GetIsOOP(bool* aIsAsync)
1202 {
1203 AutoPluginLibraryCall library(this);
1204 if (!library)
1205 return NS_ERROR_FAILURE;
1206
1207 *aIsAsync = library->IsOOP();
1208 return NS_OK;
1209 }
1210
1211 nsresult
SetBackgroundUnknown()1212 nsNPAPIPluginInstance::SetBackgroundUnknown()
1213 {
1214 if (RUNNING != mRunning)
1215 return NS_OK;
1216
1217 AutoPluginLibraryCall library(this);
1218 if (!library)
1219 return NS_ERROR_FAILURE;
1220
1221 return library->SetBackgroundUnknown(&mNPP);
1222 }
1223
1224 nsresult
BeginUpdateBackground(nsIntRect * aRect,DrawTarget ** aDrawTarget)1225 nsNPAPIPluginInstance::BeginUpdateBackground(nsIntRect* aRect,
1226 DrawTarget** aDrawTarget)
1227 {
1228 if (RUNNING != mRunning)
1229 return NS_OK;
1230
1231 AutoPluginLibraryCall library(this);
1232 if (!library)
1233 return NS_ERROR_FAILURE;
1234
1235 return library->BeginUpdateBackground(&mNPP, *aRect, aDrawTarget);
1236 }
1237
1238 nsresult
EndUpdateBackground(nsIntRect * aRect)1239 nsNPAPIPluginInstance::EndUpdateBackground(nsIntRect* aRect)
1240 {
1241 if (RUNNING != mRunning)
1242 return NS_OK;
1243
1244 AutoPluginLibraryCall library(this);
1245 if (!library)
1246 return NS_ERROR_FAILURE;
1247
1248 return library->EndUpdateBackground(&mNPP, *aRect);
1249 }
1250
1251 nsresult
IsTransparent(bool * isTransparent)1252 nsNPAPIPluginInstance::IsTransparent(bool* isTransparent)
1253 {
1254 *isTransparent = mTransparent;
1255 return NS_OK;
1256 }
1257
1258 nsresult
GetFormValue(nsAString & aValue)1259 nsNPAPIPluginInstance::GetFormValue(nsAString& aValue)
1260 {
1261 aValue.Truncate();
1262
1263 char *value = nullptr;
1264 nsresult rv = GetValueFromPlugin(NPPVformValue, &value);
1265 if (NS_FAILED(rv) || !value)
1266 return NS_ERROR_FAILURE;
1267
1268 CopyUTF8toUTF16(value, aValue);
1269
1270 // NPPVformValue allocates with NPN_MemAlloc(), which uses
1271 // nsMemory.
1272 free(value);
1273
1274 return NS_OK;
1275 }
1276
1277 nsresult
PushPopupsEnabledState(bool aEnabled)1278 nsNPAPIPluginInstance::PushPopupsEnabledState(bool aEnabled)
1279 {
1280 nsCOMPtr<nsPIDOMWindowOuter> window = GetDOMWindow();
1281 if (!window)
1282 return NS_ERROR_FAILURE;
1283
1284 PopupControlState oldState =
1285 window->PushPopupControlState(aEnabled ? openAllowed : openAbused,
1286 true);
1287
1288 if (!mPopupStates.AppendElement(oldState)) {
1289 // Appending to our state stack failed, pop what we just pushed.
1290 window->PopPopupControlState(oldState);
1291 return NS_ERROR_FAILURE;
1292 }
1293
1294 return NS_OK;
1295 }
1296
1297 nsresult
PopPopupsEnabledState()1298 nsNPAPIPluginInstance::PopPopupsEnabledState()
1299 {
1300 int32_t last = mPopupStates.Length() - 1;
1301
1302 if (last < 0) {
1303 // Nothing to pop.
1304 return NS_OK;
1305 }
1306
1307 nsCOMPtr<nsPIDOMWindowOuter> window = GetDOMWindow();
1308 if (!window)
1309 return NS_ERROR_FAILURE;
1310
1311 PopupControlState &oldState = mPopupStates[last];
1312
1313 window->PopPopupControlState(oldState);
1314
1315 mPopupStates.RemoveElementAt(last);
1316
1317 return NS_OK;
1318 }
1319
1320 nsresult
GetPluginAPIVersion(uint16_t * version)1321 nsNPAPIPluginInstance::GetPluginAPIVersion(uint16_t* version)
1322 {
1323 NS_ENSURE_ARG_POINTER(version);
1324
1325 if (!mPlugin)
1326 return NS_ERROR_FAILURE;
1327
1328 if (!mPlugin->GetLibrary())
1329 return NS_ERROR_FAILURE;
1330
1331 NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
1332
1333 *version = pluginFunctions->version;
1334
1335 return NS_OK;
1336 }
1337
1338 nsresult
PrivateModeStateChanged(bool enabled)1339 nsNPAPIPluginInstance::PrivateModeStateChanged(bool enabled)
1340 {
1341 if (RUNNING != mRunning)
1342 return NS_OK;
1343
1344 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance informing plugin of private mode state change this=%p\n",this));
1345
1346 if (!mPlugin || !mPlugin->GetLibrary())
1347 return NS_ERROR_FAILURE;
1348
1349 NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
1350
1351 if (!pluginFunctions->setvalue)
1352 return NS_ERROR_FAILURE;
1353
1354 PluginDestructionGuard guard(this);
1355
1356 NPError error;
1357 NPBool value = static_cast<NPBool>(enabled);
1358 NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setvalue)(&mNPP, NPNVprivateModeBool, &value), this,
1359 NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
1360 return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE;
1361 }
1362
1363 nsresult
IsPrivateBrowsing(bool * aEnabled)1364 nsNPAPIPluginInstance::IsPrivateBrowsing(bool* aEnabled)
1365 {
1366 if (!mOwner)
1367 return NS_ERROR_FAILURE;
1368
1369 nsCOMPtr<nsIDocument> doc;
1370 mOwner->GetDocument(getter_AddRefs(doc));
1371 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
1372
1373 nsCOMPtr<nsPIDOMWindowOuter> domwindow = doc->GetWindow();
1374 NS_ENSURE_TRUE(domwindow, NS_ERROR_FAILURE);
1375
1376 nsCOMPtr<nsIDocShell> docShell = domwindow->GetDocShell();
1377 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
1378 *aEnabled = (loadContext && loadContext->UsePrivateBrowsing());
1379 return NS_OK;
1380 }
1381
1382 static void
PluginTimerCallback(nsITimer * aTimer,void * aClosure)1383 PluginTimerCallback(nsITimer *aTimer, void *aClosure)
1384 {
1385 nsNPAPITimer* t = (nsNPAPITimer*)aClosure;
1386 NPP npp = t->npp;
1387 uint32_t id = t->id;
1388
1389 PLUGIN_LOG(PLUGIN_LOG_NOISY, ("nsNPAPIPluginInstance running plugin timer callback this=%p\n", npp->ndata));
1390
1391 MAIN_THREAD_JNI_REF_GUARD;
1392 // Some plugins (Flash on Android) calls unscheduletimer
1393 // from this callback.
1394 t->inCallback = true;
1395 (*(t->callback))(npp, id);
1396 t->inCallback = false;
1397
1398 // Make sure we still have an instance and the timer is still alive
1399 // after the callback.
1400 nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata;
1401 if (!inst || !inst->TimerWithID(id, nullptr))
1402 return;
1403
1404 // use UnscheduleTimer to clean up if this is a one-shot timer
1405 uint32_t timerType;
1406 t->timer->GetType(&timerType);
1407 if (t->needUnschedule || timerType == nsITimer::TYPE_ONE_SHOT)
1408 inst->UnscheduleTimer(id);
1409 }
1410
1411 nsNPAPITimer*
TimerWithID(uint32_t id,uint32_t * index)1412 nsNPAPIPluginInstance::TimerWithID(uint32_t id, uint32_t* index)
1413 {
1414 uint32_t len = mTimers.Length();
1415 for (uint32_t i = 0; i < len; i++) {
1416 if (mTimers[i]->id == id) {
1417 if (index)
1418 *index = i;
1419 return mTimers[i];
1420 }
1421 }
1422 return nullptr;
1423 }
1424
1425 uint32_t
ScheduleTimer(uint32_t interval,NPBool repeat,void (* timerFunc)(NPP npp,uint32_t timerID))1426 nsNPAPIPluginInstance::ScheduleTimer(uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID))
1427 {
1428 if (RUNNING != mRunning)
1429 return 0;
1430
1431 nsNPAPITimer *newTimer = new nsNPAPITimer();
1432
1433 newTimer->inCallback = newTimer->needUnschedule = false;
1434 newTimer->npp = &mNPP;
1435
1436 // generate ID that is unique to this instance
1437 uint32_t uniqueID = mTimers.Length();
1438 while ((uniqueID == 0) || TimerWithID(uniqueID, nullptr))
1439 uniqueID++;
1440 newTimer->id = uniqueID;
1441
1442 // create new xpcom timer, scheduled correctly
1443 nsresult rv;
1444 nsCOMPtr<nsITimer> xpcomTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
1445 if (NS_FAILED(rv)) {
1446 delete newTimer;
1447 return 0;
1448 }
1449 const short timerType = (repeat ? (short)nsITimer::TYPE_REPEATING_SLACK : (short)nsITimer::TYPE_ONE_SHOT);
1450 xpcomTimer->InitWithFuncCallback(PluginTimerCallback, newTimer, interval, timerType);
1451 newTimer->timer = xpcomTimer;
1452
1453 // save callback function
1454 newTimer->callback = timerFunc;
1455
1456 // add timer to timers array
1457 mTimers.AppendElement(newTimer);
1458
1459 return newTimer->id;
1460 }
1461
1462 void
UnscheduleTimer(uint32_t timerID)1463 nsNPAPIPluginInstance::UnscheduleTimer(uint32_t timerID)
1464 {
1465 // find the timer struct by ID
1466 uint32_t index;
1467 nsNPAPITimer* t = TimerWithID(timerID, &index);
1468 if (!t)
1469 return;
1470
1471 if (t->inCallback) {
1472 t->needUnschedule = true;
1473 return;
1474 }
1475
1476 // cancel the timer
1477 t->timer->Cancel();
1478
1479 // remove timer struct from array
1480 mTimers.RemoveElementAt(index);
1481
1482 // delete timer
1483 delete t;
1484 }
1485
1486 NPBool
ConvertPoint(double sourceX,double sourceY,NPCoordinateSpace sourceSpace,double * destX,double * destY,NPCoordinateSpace destSpace)1487 nsNPAPIPluginInstance::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
1488 double *destX, double *destY, NPCoordinateSpace destSpace)
1489 {
1490 if (mOwner) {
1491 return mOwner->ConvertPoint(sourceX, sourceY, sourceSpace, destX, destY, destSpace);
1492 }
1493
1494 return false;
1495 }
1496
1497 nsresult
GetDOMElement(nsIDOMElement ** result)1498 nsNPAPIPluginInstance::GetDOMElement(nsIDOMElement* *result)
1499 {
1500 if (!mOwner) {
1501 *result = nullptr;
1502 return NS_ERROR_FAILURE;
1503 }
1504
1505 return mOwner->GetDOMElement(result);
1506 }
1507
1508 nsresult
InvalidateRect(NPRect * invalidRect)1509 nsNPAPIPluginInstance::InvalidateRect(NPRect *invalidRect)
1510 {
1511 if (RUNNING != mRunning)
1512 return NS_OK;
1513
1514 if (!mOwner)
1515 return NS_ERROR_FAILURE;
1516
1517 return mOwner->InvalidateRect(invalidRect);
1518 }
1519
1520 nsresult
InvalidateRegion(NPRegion invalidRegion)1521 nsNPAPIPluginInstance::InvalidateRegion(NPRegion invalidRegion)
1522 {
1523 if (RUNNING != mRunning)
1524 return NS_OK;
1525
1526 if (!mOwner)
1527 return NS_ERROR_FAILURE;
1528
1529 return mOwner->InvalidateRegion(invalidRegion);
1530 }
1531
1532 nsresult
GetMIMEType(const char ** result)1533 nsNPAPIPluginInstance::GetMIMEType(const char* *result)
1534 {
1535 if (!mMIMEType)
1536 *result = "";
1537 else
1538 *result = mMIMEType;
1539
1540 return NS_OK;
1541 }
1542
1543 nsPluginInstanceOwner*
GetOwner()1544 nsNPAPIPluginInstance::GetOwner()
1545 {
1546 return mOwner;
1547 }
1548
1549 void
SetOwner(nsPluginInstanceOwner * aOwner)1550 nsNPAPIPluginInstance::SetOwner(nsPluginInstanceOwner *aOwner)
1551 {
1552 mOwner = aOwner;
1553 }
1554
1555 nsresult
AsyncSetWindow(NPWindow & window)1556 nsNPAPIPluginInstance::AsyncSetWindow(NPWindow& window)
1557 {
1558 return NS_ERROR_NOT_IMPLEMENTED;
1559 }
1560
1561 void
URLRedirectResponse(void * notifyData,NPBool allow)1562 nsNPAPIPluginInstance::URLRedirectResponse(void* notifyData, NPBool allow)
1563 {
1564 if (!notifyData) {
1565 return;
1566 }
1567
1568 uint32_t listenerCount = mStreamListeners.Length();
1569 for (uint32_t i = 0; i < listenerCount; i++) {
1570 nsNPAPIPluginStreamListener* currentListener = mStreamListeners[i];
1571 if (currentListener->GetNotifyData() == notifyData) {
1572 currentListener->URLRedirectResponse(allow);
1573 }
1574 }
1575 }
1576
1577 NPError
InitAsyncSurface(NPSize * size,NPImageFormat format,void * initData,NPAsyncSurface * surface)1578 nsNPAPIPluginInstance::InitAsyncSurface(NPSize *size, NPImageFormat format,
1579 void *initData, NPAsyncSurface *surface)
1580 {
1581 if (mOwner) {
1582 return mOwner->InitAsyncSurface(size, format, initData, surface);
1583 }
1584
1585 return NPERR_GENERIC_ERROR;
1586 }
1587
1588 NPError
FinalizeAsyncSurface(NPAsyncSurface * surface)1589 nsNPAPIPluginInstance::FinalizeAsyncSurface(NPAsyncSurface *surface)
1590 {
1591 if (mOwner) {
1592 return mOwner->FinalizeAsyncSurface(surface);
1593 }
1594
1595 return NPERR_GENERIC_ERROR;
1596 }
1597
1598 void
SetCurrentAsyncSurface(NPAsyncSurface * surface,NPRect * changed)1599 nsNPAPIPluginInstance::SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed)
1600 {
1601 if (mOwner) {
1602 mOwner->SetCurrentAsyncSurface(surface, changed);
1603 }
1604 }
1605
1606 class CarbonEventModelFailureEvent : public Runnable {
1607 public:
1608 nsCOMPtr<nsIContent> mContent;
1609
CarbonEventModelFailureEvent(nsIContent * aContent)1610 explicit CarbonEventModelFailureEvent(nsIContent* aContent)
1611 : mContent(aContent)
1612 {}
1613
~CarbonEventModelFailureEvent()1614 ~CarbonEventModelFailureEvent() {}
1615
1616 NS_IMETHOD Run();
1617 };
1618
1619 NS_IMETHODIMP
Run()1620 CarbonEventModelFailureEvent::Run()
1621 {
1622 nsString type = NS_LITERAL_STRING("npapi-carbon-event-model-failure");
1623 nsContentUtils::DispatchTrustedEvent(mContent->GetComposedDoc(), mContent,
1624 type, true, true);
1625 return NS_OK;
1626 }
1627
1628 void
CarbonNPAPIFailure()1629 nsNPAPIPluginInstance::CarbonNPAPIFailure()
1630 {
1631 nsCOMPtr<nsIDOMElement> element;
1632 GetDOMElement(getter_AddRefs(element));
1633 if (!element) {
1634 return;
1635 }
1636
1637 nsCOMPtr<nsIContent> content(do_QueryInterface(element));
1638 if (!content) {
1639 return;
1640 }
1641
1642 nsCOMPtr<nsIRunnable> e = new CarbonEventModelFailureEvent(content);
1643 nsresult rv = NS_DispatchToCurrentThread(e);
1644 if (NS_FAILED(rv)) {
1645 NS_WARNING("Failed to dispatch CarbonEventModelFailureEvent.");
1646 }
1647 }
1648
1649 static bool
GetJavaVersionFromMimetype(nsPluginTag * pluginTag,nsCString & version)1650 GetJavaVersionFromMimetype(nsPluginTag* pluginTag, nsCString& version)
1651 {
1652 for (uint32_t i = 0; i < pluginTag->MimeTypes().Length(); ++i) {
1653 nsCString type = pluginTag->MimeTypes()[i];
1654 nsAutoCString jpi("application/x-java-applet;jpi-version=");
1655
1656 int32_t idx = type.Find(jpi, false, 0, -1);
1657 if (idx != 0) {
1658 continue;
1659 }
1660
1661 type.Cut(0, jpi.Length());
1662 if (type.IsEmpty()) {
1663 continue;
1664 }
1665
1666 type.ReplaceChar('_', '.');
1667 version = type;
1668 return true;
1669 }
1670
1671 return false;
1672 }
1673
1674 void
CheckJavaC2PJSObjectQuirk(uint16_t paramCount,const char * const * paramNames,const char * const * paramValues)1675 nsNPAPIPluginInstance::CheckJavaC2PJSObjectQuirk(uint16_t paramCount,
1676 const char* const* paramNames,
1677 const char* const* paramValues)
1678 {
1679 if (!mMIMEType || !mPlugin) {
1680 return;
1681 }
1682
1683 nsPluginTagType tagtype;
1684 nsresult rv = GetTagType(&tagtype);
1685 if (NS_FAILED(rv) ||
1686 (tagtype != nsPluginTagType_Applet)) {
1687 return;
1688 }
1689
1690 RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
1691 if (!pluginHost) {
1692 return;
1693 }
1694
1695 nsPluginTag* pluginTag = pluginHost->TagForPlugin(mPlugin);
1696 if (!pluginTag ||
1697 !pluginTag->mIsJavaPlugin) {
1698 return;
1699 }
1700
1701 // check the params for "code" being present and non-empty
1702 bool haveCodeParam = false;
1703 bool isCodeParamEmpty = true;
1704
1705 for (uint16_t i = paramCount; i > 0; --i) {
1706 if (PL_strcasecmp(paramNames[i - 1], "code") == 0) {
1707 haveCodeParam = true;
1708 if (strlen(paramValues[i - 1]) > 0) {
1709 isCodeParamEmpty = false;
1710 }
1711 break;
1712 }
1713 }
1714
1715 // Due to the Java version being specified inconsistently across platforms
1716 // check the version via the mimetype for choosing specific Java versions
1717 nsCString javaVersion;
1718 if (!GetJavaVersionFromMimetype(pluginTag, javaVersion)) {
1719 return;
1720 }
1721
1722 mozilla::Version version(javaVersion.get());
1723
1724 if (version >= "1.7.0.4") {
1725 return;
1726 }
1727
1728 if (!haveCodeParam && version >= "1.6.0.34" && version < "1.7") {
1729 return;
1730 }
1731
1732 if (haveCodeParam && !isCodeParamEmpty) {
1733 return;
1734 }
1735
1736 mHaveJavaC2PJSObjectQuirk = true;
1737 }
1738
1739 double
GetContentsScaleFactor()1740 nsNPAPIPluginInstance::GetContentsScaleFactor()
1741 {
1742 double scaleFactor = 1.0;
1743 if (mOwner) {
1744 mOwner->GetContentsScaleFactor(&scaleFactor);
1745 }
1746 return scaleFactor;
1747 }
1748
1749 float
GetCSSZoomFactor()1750 nsNPAPIPluginInstance::GetCSSZoomFactor()
1751 {
1752 float zoomFactor = 1.0;
1753 if (mOwner) {
1754 mOwner->GetCSSZoomFactor(&zoomFactor);
1755 }
1756 return zoomFactor;
1757 }
1758
1759 nsresult
GetRunID(uint32_t * aRunID)1760 nsNPAPIPluginInstance::GetRunID(uint32_t* aRunID)
1761 {
1762 if (NS_WARN_IF(!aRunID)) {
1763 return NS_ERROR_INVALID_POINTER;
1764 }
1765
1766 if (NS_WARN_IF(!mPlugin)) {
1767 return NS_ERROR_FAILURE;
1768 }
1769
1770 PluginLibrary* library = mPlugin->GetLibrary();
1771 if (!library) {
1772 return NS_ERROR_FAILURE;
1773 }
1774
1775 return library->GetRunID(aRunID);
1776 }
1777
1778 nsresult
GetOrCreateAudioChannelAgent(nsIAudioChannelAgent ** aAgent)1779 nsNPAPIPluginInstance::GetOrCreateAudioChannelAgent(nsIAudioChannelAgent** aAgent)
1780 {
1781 if (!mAudioChannelAgent) {
1782 nsresult rv;
1783 mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1", &rv);
1784 if (NS_WARN_IF(!mAudioChannelAgent)) {
1785 return NS_ERROR_FAILURE;
1786 }
1787
1788 nsCOMPtr<nsPIDOMWindowOuter> window = GetDOMWindow();
1789 if (NS_WARN_IF(!window)) {
1790 return NS_ERROR_FAILURE;
1791 }
1792
1793 rv = mAudioChannelAgent->Init(window->GetCurrentInnerWindow(),
1794 (int32_t)AudioChannelService::GetDefaultAudioChannel(),
1795 this);
1796 if (NS_WARN_IF(NS_FAILED(rv))) {
1797 return rv;
1798 }
1799 }
1800
1801 nsCOMPtr<nsIAudioChannelAgent> agent = mAudioChannelAgent;
1802 agent.forget(aAgent);
1803 return NS_OK;
1804 }
1805
1806 NS_IMETHODIMP
WindowVolumeChanged(float aVolume,bool aMuted)1807 nsNPAPIPluginInstance::WindowVolumeChanged(float aVolume, bool aMuted)
1808 {
1809 // We just support mute/unmute
1810 nsresult rv = SetMuted(aMuted);
1811 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetMuted failed");
1812 if (mMuted != aMuted) {
1813 mMuted = aMuted;
1814 AudioChannelService::AudibleState audible = aMuted ?
1815 AudioChannelService::AudibleState::eNotAudible :
1816 AudioChannelService::AudibleState::eAudible;
1817 mAudioChannelAgent->NotifyStartedAudible(audible,
1818 AudioChannelService::AudibleChangedReasons::eVolumeChanged);
1819 }
1820 return rv;
1821 }
1822
1823 NS_IMETHODIMP
WindowSuspendChanged(nsSuspendedTypes aSuspend)1824 nsNPAPIPluginInstance::WindowSuspendChanged(nsSuspendedTypes aSuspend)
1825 {
1826 // It doesn't support suspended, so we just do something like mute/unmute.
1827 WindowVolumeChanged(1.0, /* useless */
1828 aSuspend != nsISuspendedTypes::NONE_SUSPENDED);
1829 return NS_OK;
1830 }
1831
1832 NS_IMETHODIMP
WindowAudioCaptureChanged(bool aCapture)1833 nsNPAPIPluginInstance::WindowAudioCaptureChanged(bool aCapture)
1834 {
1835 return NS_OK;
1836 }
1837
1838 nsresult
SetMuted(bool aIsMuted)1839 nsNPAPIPluginInstance::SetMuted(bool aIsMuted)
1840 {
1841 if (RUNNING != mRunning)
1842 return NS_OK;
1843
1844 PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance informing plugin of mute state change this=%p\n",this));
1845
1846 if (!mPlugin || !mPlugin->GetLibrary())
1847 return NS_ERROR_FAILURE;
1848
1849 NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
1850
1851 if (!pluginFunctions->setvalue)
1852 return NS_ERROR_FAILURE;
1853
1854 PluginDestructionGuard guard(this);
1855
1856 NPError error;
1857 NPBool value = static_cast<NPBool>(aIsMuted);
1858 NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setvalue)(&mNPP, NPNVmuteAudioBool, &value), this,
1859 NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
1860 return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE;
1861 }
1862