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 #include "mozilla/Logging.h"
9 #include "nscore.h"
10 #include "prenv.h"
11 
12 #include "nsNPAPIPluginInstance.h"
13 #include "nsNPAPIPlugin.h"
14 #include "nsNPAPIPluginStreamListener.h"
15 #include "nsPluginHost.h"
16 #include "nsPluginLogging.h"
17 #include "nsContentUtils.h"
18 #include "nsPluginInstanceOwner.h"
19 
20 #include "nsThreadUtils.h"
21 #include "mozilla/dom/Document.h"
22 #include "nsIDocShell.h"
23 #include "nsIScriptGlobalObject.h"
24 #include "nsIScriptContext.h"
25 #include "nsDirectoryServiceDefs.h"
26 #include "nsJSNPRuntime.h"
27 #include "nsPluginStreamListenerPeer.h"
28 #include "nsSize.h"
29 #include "nsNetCID.h"
30 #include "nsIContent.h"
31 #include "nsVersionComparator.h"
32 #include "mozilla/Preferences.h"
33 #include "mozilla/Unused.h"
34 #include "nsILoadContext.h"
35 #include "mozilla/dom/Element.h"
36 #include "mozilla/dom/HTMLObjectElementBinding.h"
37 #include "AudioChannelService.h"
38 
39 using namespace mozilla;
40 using namespace mozilla::dom;
41 
42 using namespace mozilla;
43 using namespace mozilla::plugins::parent;
44 using namespace mozilla::layers;
45 
NS_IMPL_ISUPPORTS(nsNPAPIPluginInstance,nsIAudioChannelAgentCallback)46 NS_IMPL_ISUPPORTS(nsNPAPIPluginInstance, nsIAudioChannelAgentCallback)
47 
48 nsNPAPIPluginInstance::nsNPAPIPluginInstance()
49     : mDrawingModel(kDefaultDrawingModel),
50       mRunning(NOT_STARTED),
51       mWindowless(false),
52       mTransparent(false),
53       mCached(false),
54       mUsesDOMForCursor(false),
55       mInPluginInitCall(false),
56       mPlugin(nullptr),
57       mMIMEType(nullptr),
58       mOwner(nullptr)
59 #ifdef XP_MACOSX
60       ,
61       mCurrentPluginEvent(nullptr)
62 #endif
63       ,
64       mCachedParamLength(0),
65       mCachedParamNames(nullptr),
66       mCachedParamValues(nullptr) {
67   mNPP.pdata = nullptr;
68   mNPP.ndata = this;
69 
70   PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n", this));
71 }
72 
~nsNPAPIPluginInstance()73 nsNPAPIPluginInstance::~nsNPAPIPluginInstance() {
74   PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance dtor: this=%p\n", this));
75 
76   if (mMIMEType) {
77     free(mMIMEType);
78     mMIMEType = nullptr;
79   }
80 
81   if (!mCachedParamValues || !mCachedParamNames) {
82     return;
83   }
84   MOZ_ASSERT(mCachedParamValues && mCachedParamNames);
85 
86   for (uint32_t i = 0; i < mCachedParamLength; i++) {
87     if (mCachedParamNames[i]) {
88       free(mCachedParamNames[i]);
89       mCachedParamNames[i] = nullptr;
90     }
91     if (mCachedParamValues[i]) {
92       free(mCachedParamValues[i]);
93       mCachedParamValues[i] = nullptr;
94     }
95   }
96 
97   free(mCachedParamNames);
98   mCachedParamNames = nullptr;
99 
100   free(mCachedParamValues);
101   mCachedParamValues = nullptr;
102 }
103 
104 uint32_t nsNPAPIPluginInstance::gInUnsafePluginCalls = 0;
105 
Destroy()106 void nsNPAPIPluginInstance::Destroy() {
107   Stop();
108   mPlugin = nullptr;
109   mAudioChannelAgent = nullptr;
110 }
111 
StopTime()112 TimeStamp nsNPAPIPluginInstance::StopTime() { return mStopTime; }
113 
Initialize(nsNPAPIPlugin * aPlugin,nsPluginInstanceOwner * aOwner,const nsACString & aMIMEType)114 nsresult nsNPAPIPluginInstance::Initialize(nsNPAPIPlugin* aPlugin,
115                                            nsPluginInstanceOwner* aOwner,
116                                            const nsACString& aMIMEType) {
117   AUTO_PROFILER_LABEL("nsNPAPIPlugin::Initialize", OTHER);
118   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
119              ("nsNPAPIPluginInstance::Initialize this=%p\n", this));
120 
121   NS_ENSURE_ARG_POINTER(aPlugin);
122   NS_ENSURE_ARG_POINTER(aOwner);
123 
124   mPlugin = aPlugin;
125   mOwner = aOwner;
126 
127   if (!aMIMEType.IsEmpty()) {
128     mMIMEType = ToNewCString(aMIMEType);
129   }
130 
131   return Start();
132 }
133 
Stop()134 nsresult nsNPAPIPluginInstance::Stop() {
135   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
136              ("nsNPAPIPluginInstance::Stop this=%p\n", this));
137 
138   // Make sure the plugin didn't leave popups enabled.
139   if (mPopupStates.Length() > 0) {
140     PopupBlocker::PopPopupControlState(PopupBlocker::openAbused);
141   }
142 
143   if (RUNNING != mRunning) {
144     return NS_OK;
145   }
146 
147   // clean up all outstanding timers
148   for (uint32_t i = mTimers.Length(); i > 0; i--)
149     UnscheduleTimer(mTimers[i - 1]->id);
150 
151   // If there's code from this plugin instance on the stack, delay the
152   // destroy.
153   if (PluginDestructionGuard::DelayDestroy(this)) {
154     return NS_OK;
155   }
156 
157   mRunning = DESTROYING;
158   mStopTime = TimeStamp::Now();
159 
160   // clean up open streams
161   while (mStreamListeners.Length() > 0) {
162     RefPtr<nsNPAPIPluginStreamListener> currentListener(mStreamListeners[0]);
163     currentListener->CleanUpStream(NPRES_USER_BREAK);
164     mStreamListeners.RemoveElement(currentListener);
165   }
166 
167   if (!mPlugin || !mPlugin->GetLibrary()) return NS_ERROR_FAILURE;
168 
169   NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
170 
171   NPError error = NPERR_GENERIC_ERROR;
172   if (pluginFunctions->destroy) {
173     NPSavedData* sdata = 0;
174 
175     NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->destroy)(&mNPP, &sdata),
176                             this, NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
177 
178     NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
179                    ("NPP Destroy called: this=%p, npp=%p, return=%d\n", this,
180                     &mNPP, error));
181   }
182   mRunning = DESTROYED;
183 
184   nsJSNPRuntime::OnPluginDestroy(&mNPP);
185 
186   if (error != NPERR_NO_ERROR)
187     return NS_ERROR_FAILURE;
188   else
189     return NS_OK;
190 }
191 
GetDOMWindow()192 already_AddRefed<nsPIDOMWindowOuter> nsNPAPIPluginInstance::GetDOMWindow() {
193   if (!mOwner) return nullptr;
194 
195   RefPtr<nsPluginInstanceOwner> kungFuDeathGrip(mOwner);
196 
197   nsCOMPtr<Document> doc;
198   kungFuDeathGrip->GetDocument(getter_AddRefs(doc));
199   if (!doc) return nullptr;
200 
201   RefPtr<nsPIDOMWindowOuter> window = doc->GetWindow();
202 
203   return window.forget();
204 }
205 
GetTagType(nsPluginTagType * result)206 nsresult nsNPAPIPluginInstance::GetTagType(nsPluginTagType* result) {
207   if (!mOwner) {
208     return NS_ERROR_FAILURE;
209   }
210 
211   return mOwner->GetTagType(result);
212 }
213 
214 nsTArray<nsNPAPIPluginStreamListener*>*
StreamListeners()215 nsNPAPIPluginInstance::StreamListeners() {
216   return &mStreamListeners;
217 }
218 
219 nsTArray<nsPluginStreamListenerPeer*>*
FileCachedStreamListeners()220 nsNPAPIPluginInstance::FileCachedStreamListeners() {
221   return &mFileCachedStreamListeners;
222 }
223 
Start()224 nsresult nsNPAPIPluginInstance::Start() {
225   if (mRunning == RUNNING) {
226     return NS_OK;
227   }
228 
229   if (!mOwner) {
230     MOZ_ASSERT(false, "Should not be calling Start() on unowned plugin.");
231     return NS_ERROR_FAILURE;
232   }
233 
234   PluginDestructionGuard guard(this);
235 
236   nsTArray<MozPluginParameter> attributes;
237   nsTArray<MozPluginParameter> params;
238 
239   nsPluginTagType tagtype;
240   nsresult rv = GetTagType(&tagtype);
241   if (NS_SUCCEEDED(rv)) {
242     mOwner->GetAttributes(attributes);
243     mOwner->GetParameters(params);
244   } else {
245     MOZ_ASSERT(false, "Failed to get tag type.");
246   }
247 
248   mCachedParamLength = attributes.Length() + 1 + params.Length();
249 
250   // We add an extra entry "PARAM" as a separator between the attribute
251   // and param values, but we don't count it if there are no <param> entries.
252   // Legacy behavior quirk.
253   uint32_t quirkParamLength =
254       params.Length() ? mCachedParamLength : attributes.Length();
255 
256   mCachedParamNames = (char**)moz_xmalloc(sizeof(char*) * mCachedParamLength);
257   mCachedParamValues = (char**)moz_xmalloc(sizeof(char*) * mCachedParamLength);
258 
259   for (uint32_t i = 0; i < attributes.Length(); i++) {
260     mCachedParamNames[i] = ToNewUTF8String(attributes[i].mName);
261     mCachedParamValues[i] = ToNewUTF8String(attributes[i].mValue);
262   }
263 
264   mCachedParamNames[attributes.Length()] =
265       ToNewUTF8String(NS_LITERAL_STRING("PARAM"));
266   mCachedParamValues[attributes.Length()] = nullptr;
267 
268   for (uint32_t i = 0, pos = attributes.Length() + 1; i < params.Length();
269        i++) {
270     mCachedParamNames[pos] = ToNewUTF8String(params[i].mName);
271     mCachedParamValues[pos] = ToNewUTF8String(params[i].mValue);
272     pos++;
273   }
274 
275   const char* mimetype;
276   NPError error = NPERR_GENERIC_ERROR;
277 
278   GetMIMEType(&mimetype);
279 
280   bool oldVal = mInPluginInitCall;
281   mInPluginInitCall = true;
282 
283   // Need this on the stack before calling NPP_New otherwise some callbacks that
284   // the plugin may make could fail (NPN_HasProperty, for example).
285   NPPAutoPusher autopush(&mNPP);
286 
287   if (!mPlugin) return NS_ERROR_FAILURE;
288 
289   PluginLibrary* library = mPlugin->GetLibrary();
290   if (!library) return NS_ERROR_FAILURE;
291 
292   // Mark this instance as running before calling NPP_New because the plugin may
293   // call other NPAPI functions, like NPN_GetURLNotify, that assume this is set
294   // before returning. If the plugin returns failure, we'll clear it out below.
295   mRunning = RUNNING;
296 
297   nsresult newResult =
298       library->NPP_New((char*)mimetype, &mNPP, quirkParamLength,
299                        mCachedParamNames, mCachedParamValues, nullptr, &error);
300   mInPluginInitCall = oldVal;
301 
302   NPP_PLUGIN_LOG(
303       PLUGIN_LOG_NORMAL,
304       ("NPP New called: this=%p, npp=%p, mime=%s, argc=%d, return=%d\n", this,
305        &mNPP, mimetype, quirkParamLength, error));
306 
307   if (NS_FAILED(newResult) || error != NPERR_NO_ERROR) {
308     mRunning = DESTROYED;
309     nsJSNPRuntime::OnPluginDestroy(&mNPP);
310     return NS_ERROR_FAILURE;
311   }
312 
313   return newResult;
314 }
315 
SetWindow(NPWindow * window)316 nsresult nsNPAPIPluginInstance::SetWindow(NPWindow* window) {
317   // NPAPI plugins don't want a SetWindow(nullptr).
318   if (!window || RUNNING != mRunning) return NS_OK;
319 
320 #if MOZ_WIDGET_GTK
321   // bug 108347, flash plugin on linux doesn't like window->width <= 0
322   return NS_OK;
323 #endif
324 
325   if (!mPlugin || !mPlugin->GetLibrary()) return NS_ERROR_FAILURE;
326 
327   NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
328 
329   if (pluginFunctions->setwindow) {
330     PluginDestructionGuard guard(this);
331 
332     // XXX Turns out that NPPluginWindow and NPWindow are structurally
333     // identical (on purpose!), so there's no need to make a copy.
334 
335     PLUGIN_LOG(PLUGIN_LOG_NORMAL,
336                ("nsNPAPIPluginInstance::SetWindow (about to call it) this=%p\n",
337                 this));
338 
339     bool oldVal = mInPluginInitCall;
340     mInPluginInitCall = true;
341 
342     NPPAutoPusher nppPusher(&mNPP);
343 
344     NPError error;
345     NS_TRY_SAFE_CALL_RETURN(
346         error, (*pluginFunctions->setwindow)(&mNPP, (NPWindow*)window), this,
347         NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
348     // 'error' is only used if this is a logging-enabled build.
349     // That is somewhat complex to check, so we just use "unused"
350     // to suppress any compiler warnings in build configurations
351     // where the logging is a no-op.
352     mozilla::Unused << error;
353 
354     mInPluginInitCall = oldVal;
355 
356     NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
357                    ("NPP SetWindow called: this=%p, [x=%d,y=%d,w=%d,h=%d], "
358                     "clip[t=%d,b=%d,l=%d,r=%d], return=%d\n",
359                     this, window->x, window->y, window->width, window->height,
360                     window->clipRect.top, window->clipRect.bottom,
361                     window->clipRect.left, window->clipRect.right, error));
362   }
363   return NS_OK;
364 }
365 
NewStreamListener(const char * aURL,void * notifyData,nsNPAPIPluginStreamListener ** listener)366 nsresult nsNPAPIPluginInstance::NewStreamListener(
367     const char* aURL, void* notifyData,
368     nsNPAPIPluginStreamListener** listener) {
369   RefPtr<nsNPAPIPluginStreamListener> sl =
370       new nsNPAPIPluginStreamListener(this, notifyData, aURL);
371 
372   mStreamListeners.AppendElement(sl);
373 
374   sl.forget(listener);
375 
376   return NS_OK;
377 }
378 
Print(NPPrint * platformPrint)379 nsresult nsNPAPIPluginInstance::Print(NPPrint* platformPrint) {
380   NS_ENSURE_TRUE(platformPrint, NS_ERROR_NULL_POINTER);
381 
382   PluginDestructionGuard guard(this);
383 
384   if (!mPlugin || !mPlugin->GetLibrary()) return NS_ERROR_FAILURE;
385 
386   NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
387 
388   NPPrint* thePrint = (NPPrint*)platformPrint;
389 
390   // to be compatible with the older SDK versions and to match what
391   // NPAPI and other browsers do, overwrite |window.type| field with one
392   // more copy of |platformPrint|. See bug 113264
393   uint16_t sdkmajorversion = (pluginFunctions->version & 0xff00) >> 8;
394   uint16_t sdkminorversion = pluginFunctions->version & 0x00ff;
395   if ((sdkmajorversion == 0) && (sdkminorversion < 11)) {
396     // Let's copy platformPrint bytes over to where it was supposed to be
397     // in older versions -- four bytes towards the beginning of the struct
398     // but we should be careful about possible misalignments
399     if (sizeof(NPWindowType) >= sizeof(void*)) {
400       void* source = thePrint->print.embedPrint.platformPrint;
401       void** destination = (void**)&(thePrint->print.embedPrint.window.type);
402       *destination = source;
403     } else {
404       NS_ERROR("Incompatible OS for assignment");
405     }
406   }
407 
408   if (pluginFunctions->print)
409     NS_TRY_SAFE_CALL_VOID((*pluginFunctions->print)(&mNPP, thePrint), this,
410                           NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
411 
412   NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
413                  ("NPP PrintProc called: this=%p, pDC=%p, "
414                   "[x=%d,y=%d,w=%d,h=%d], clip[t=%d,b=%d,l=%d,r=%d]\n",
415                   this, platformPrint->print.embedPrint.platformPrint,
416                   platformPrint->print.embedPrint.window.x,
417                   platformPrint->print.embedPrint.window.y,
418                   platformPrint->print.embedPrint.window.width,
419                   platformPrint->print.embedPrint.window.height,
420                   platformPrint->print.embedPrint.window.clipRect.top,
421                   platformPrint->print.embedPrint.window.clipRect.bottom,
422                   platformPrint->print.embedPrint.window.clipRect.left,
423                   platformPrint->print.embedPrint.window.clipRect.right));
424 
425   return NS_OK;
426 }
427 
HandleEvent(void * event,int16_t * result,NSPluginCallReentry aSafeToReenterGecko)428 nsresult nsNPAPIPluginInstance::HandleEvent(
429     void* event, int16_t* result, NSPluginCallReentry aSafeToReenterGecko) {
430   if (RUNNING != mRunning) return NS_OK;
431 
432   AUTO_PROFILER_LABEL("nsNPAPIPluginInstance::HandleEvent", OTHER);
433 
434   if (!event) return NS_ERROR_FAILURE;
435 
436   PluginDestructionGuard guard(this);
437 
438   if (!mPlugin || !mPlugin->GetLibrary()) return NS_ERROR_FAILURE;
439 
440   NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
441 
442   int16_t tmpResult = kNPEventNotHandled;
443 
444   if (pluginFunctions->event) {
445 #ifdef XP_MACOSX
446     mCurrentPluginEvent = event;
447 #endif
448 #if defined(XP_WIN)
449     NS_TRY_SAFE_CALL_RETURN(tmpResult, (*pluginFunctions->event)(&mNPP, event),
450                             this, aSafeToReenterGecko);
451 #else
452     tmpResult = (*pluginFunctions->event)(&mNPP, event);
453 #endif
454     NPP_PLUGIN_LOG(
455         PLUGIN_LOG_NOISY,
456         ("NPP HandleEvent called: this=%p, npp=%p, event=%p, return=%d\n", this,
457          &mNPP, event, tmpResult));
458 
459     if (result) *result = tmpResult;
460 #ifdef XP_MACOSX
461     mCurrentPluginEvent = nullptr;
462 #endif
463   }
464 
465   return NS_OK;
466 }
467 
GetValueFromPlugin(NPPVariable variable,void * value)468 nsresult nsNPAPIPluginInstance::GetValueFromPlugin(NPPVariable variable,
469                                                    void* value) {
470   if (!mPlugin || !mPlugin->GetLibrary()) return NS_ERROR_FAILURE;
471 
472   NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
473 
474   nsresult rv = NS_ERROR_FAILURE;
475 
476   if (pluginFunctions->getvalue && RUNNING == mRunning) {
477     PluginDestructionGuard guard(this);
478 
479     NPError pluginError = NPERR_GENERIC_ERROR;
480     NS_TRY_SAFE_CALL_RETURN(
481         pluginError, (*pluginFunctions->getvalue)(&mNPP, variable, value), this,
482         NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
483     NPP_PLUGIN_LOG(
484         PLUGIN_LOG_NORMAL,
485         ("NPP GetValue called: this=%p, npp=%p, var=%d, value=%p, return=%d\n",
486          this, &mNPP, variable, value, pluginError));
487 
488     if (pluginError == NPERR_NO_ERROR) {
489       rv = NS_OK;
490     }
491   }
492 
493   return rv;
494 }
495 
GetPlugin()496 nsNPAPIPlugin* nsNPAPIPluginInstance::GetPlugin() { return mPlugin; }
497 
GetNPP(NPP * aNPP)498 nsresult nsNPAPIPluginInstance::GetNPP(NPP* aNPP) {
499   if (aNPP)
500     *aNPP = &mNPP;
501   else
502     return NS_ERROR_NULL_POINTER;
503 
504   return NS_OK;
505 }
506 
SetWindowless(bool aWindowless)507 NPError nsNPAPIPluginInstance::SetWindowless(bool aWindowless) {
508   mWindowless = aWindowless;
509   return NPERR_NO_ERROR;
510 }
511 
SetTransparent(bool aTransparent)512 NPError nsNPAPIPluginInstance::SetTransparent(bool aTransparent) {
513   mTransparent = aTransparent;
514   return NPERR_NO_ERROR;
515 }
516 
SetUsesDOMForCursor(bool aUsesDOMForCursor)517 NPError nsNPAPIPluginInstance::SetUsesDOMForCursor(bool aUsesDOMForCursor) {
518   mUsesDOMForCursor = aUsesDOMForCursor;
519   return NPERR_NO_ERROR;
520 }
521 
UsesDOMForCursor()522 bool nsNPAPIPluginInstance::UsesDOMForCursor() { return mUsesDOMForCursor; }
523 
SetDrawingModel(NPDrawingModel aModel)524 void nsNPAPIPluginInstance::SetDrawingModel(NPDrawingModel aModel) {
525   mDrawingModel = aModel;
526 }
527 
RedrawPlugin()528 void nsNPAPIPluginInstance::RedrawPlugin() { mOwner->RedrawPlugin(); }
529 
530 #if defined(XP_MACOSX)
SetEventModel(NPEventModel aModel)531 void nsNPAPIPluginInstance::SetEventModel(NPEventModel aModel) {
532   // the event model needs to be set for the object frame immediately
533   if (!mOwner) {
534     NS_WARNING("Trying to set event model without a plugin instance owner!");
535     return;
536   }
537 
538   mOwner->SetEventModel(aModel);
539 }
540 #endif
541 
GetDrawingModel(int32_t * aModel)542 nsresult nsNPAPIPluginInstance::GetDrawingModel(int32_t* aModel) {
543   *aModel = (int32_t)mDrawingModel;
544   return NS_OK;
545 }
546 
IsRemoteDrawingCoreAnimation(bool * aDrawing)547 nsresult nsNPAPIPluginInstance::IsRemoteDrawingCoreAnimation(bool* aDrawing) {
548 #ifdef XP_MACOSX
549   if (!mPlugin) return NS_ERROR_FAILURE;
550 
551   PluginLibrary* library = mPlugin->GetLibrary();
552   if (!library) return NS_ERROR_FAILURE;
553 
554   return library->IsRemoteDrawingCoreAnimation(&mNPP, aDrawing);
555 #else
556   return NS_ERROR_FAILURE;
557 #endif
558 }
559 
ContentsScaleFactorChanged(double aContentsScaleFactor)560 nsresult nsNPAPIPluginInstance::ContentsScaleFactorChanged(
561     double aContentsScaleFactor) {
562 #if defined(XP_MACOSX) || defined(XP_WIN)
563   if (!mPlugin) return NS_ERROR_FAILURE;
564 
565   PluginLibrary* library = mPlugin->GetLibrary();
566   if (!library) return NS_ERROR_FAILURE;
567 
568   // We only need to call this if the plugin is running OOP.
569   if (!library->IsOOP()) return NS_OK;
570 
571   return library->ContentsScaleFactorChanged(&mNPP, aContentsScaleFactor);
572 #else
573   return NS_ERROR_FAILURE;
574 #endif
575 }
576 
CSSZoomFactorChanged(float aCSSZoomFactor)577 nsresult nsNPAPIPluginInstance::CSSZoomFactorChanged(float aCSSZoomFactor) {
578   if (RUNNING != mRunning) return NS_OK;
579 
580   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance informing plugin of "
581                                  "CSS Zoom Factor change this=%p\n",
582                                  this));
583 
584   if (!mPlugin || !mPlugin->GetLibrary()) return NS_ERROR_FAILURE;
585 
586   NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
587 
588   if (!pluginFunctions->setvalue) return NS_ERROR_FAILURE;
589 
590   PluginDestructionGuard guard(this);
591 
592   NPError error;
593   double value = static_cast<double>(aCSSZoomFactor);
594   NS_TRY_SAFE_CALL_RETURN(
595       error, (*pluginFunctions->setvalue)(&mNPP, NPNVCSSZoomFactor, &value),
596       this, NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
597   return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE;
598 }
599 
GetJSObject(JSContext * cx,JSObject ** outObject)600 nsresult nsNPAPIPluginInstance::GetJSObject(JSContext* cx,
601                                             JSObject** outObject) {
602   NPObject* npobj = nullptr;
603   nsresult rv = GetValueFromPlugin(NPPVpluginScriptableNPObject, &npobj);
604   if (NS_FAILED(rv) || !npobj) return NS_ERROR_FAILURE;
605 
606   *outObject = nsNPObjWrapper::GetNewOrUsed(&mNPP, cx, npobj);
607 
608   _releaseobject(npobj);
609 
610   return NS_OK;
611 }
612 
SetCached(bool aCache)613 void nsNPAPIPluginInstance::SetCached(bool aCache) { mCached = aCache; }
614 
ShouldCache()615 bool nsNPAPIPluginInstance::ShouldCache() { return mCached; }
616 
IsWindowless(bool * isWindowless)617 nsresult nsNPAPIPluginInstance::IsWindowless(bool* isWindowless) {
618 #if defined(XP_MACOSX)
619   // All OS X plugins are windowless.
620   *isWindowless = true;
621 #else
622   *isWindowless = mWindowless;
623 #endif
624   return NS_OK;
625 }
626 
627 class MOZ_STACK_CLASS AutoPluginLibraryCall {
628  public:
AutoPluginLibraryCall(nsNPAPIPluginInstance * aThis)629   explicit AutoPluginLibraryCall(nsNPAPIPluginInstance* aThis)
630       : mThis(aThis), mGuard(aThis), mLibrary(nullptr) {
631     nsNPAPIPlugin* plugin = mThis->GetPlugin();
632     if (plugin) mLibrary = plugin->GetLibrary();
633   }
operator bool()634   explicit operator bool() { return !!mLibrary; }
operator ->()635   PluginLibrary* operator->() { return mLibrary; }
636 
637  private:
638   nsNPAPIPluginInstance* mThis;
639   PluginDestructionGuard mGuard;
640   PluginLibrary* mLibrary;
641 };
642 
AsyncSetWindow(NPWindow * window)643 nsresult nsNPAPIPluginInstance::AsyncSetWindow(NPWindow* window) {
644   if (RUNNING != mRunning) return NS_OK;
645 
646   AutoPluginLibraryCall library(this);
647   if (!library) return NS_ERROR_FAILURE;
648 
649   return library->AsyncSetWindow(&mNPP, window);
650 }
651 
GetImageContainer(ImageContainer ** aContainer)652 nsresult nsNPAPIPluginInstance::GetImageContainer(ImageContainer** aContainer) {
653   *aContainer = nullptr;
654 
655   if (RUNNING != mRunning) return NS_OK;
656 
657   AutoPluginLibraryCall library(this);
658   return !library ? NS_ERROR_FAILURE
659                   : library->GetImageContainer(&mNPP, aContainer);
660 }
661 
GetImageSize(nsIntSize * aSize)662 nsresult nsNPAPIPluginInstance::GetImageSize(nsIntSize* aSize) {
663   *aSize = nsIntSize(0, 0);
664 
665   if (RUNNING != mRunning) return NS_OK;
666 
667   AutoPluginLibraryCall library(this);
668   return !library ? NS_ERROR_FAILURE : library->GetImageSize(&mNPP, aSize);
669 }
670 
671 #if defined(XP_WIN)
GetScrollCaptureContainer(ImageContainer ** aContainer)672 nsresult nsNPAPIPluginInstance::GetScrollCaptureContainer(
673     ImageContainer** aContainer) {
674   *aContainer = nullptr;
675 
676   if (RUNNING != mRunning) return NS_OK;
677 
678   AutoPluginLibraryCall library(this);
679   return !library ? NS_ERROR_FAILURE
680                   : library->GetScrollCaptureContainer(&mNPP, aContainer);
681 }
682 #endif
683 
HandledWindowedPluginKeyEvent(const NativeEventData & aKeyEventData,bool aIsConsumed)684 nsresult nsNPAPIPluginInstance::HandledWindowedPluginKeyEvent(
685     const NativeEventData& aKeyEventData, bool aIsConsumed) {
686   if (NS_WARN_IF(!mPlugin)) {
687     return NS_ERROR_FAILURE;
688   }
689 
690   PluginLibrary* library = mPlugin->GetLibrary();
691   if (NS_WARN_IF(!library)) {
692     return NS_ERROR_FAILURE;
693   }
694   return library->HandledWindowedPluginKeyEvent(&mNPP, aKeyEventData,
695                                                 aIsConsumed);
696 }
697 
DidComposite()698 void nsNPAPIPluginInstance::DidComposite() {
699   if (RUNNING != mRunning) return;
700 
701   AutoPluginLibraryCall library(this);
702   library->DidComposite(&mNPP);
703 }
704 
NotifyPainted(void)705 nsresult nsNPAPIPluginInstance::NotifyPainted(void) {
706   MOZ_ASSERT_UNREACHABLE("Dead code, shouldn't be called.");
707   return NS_ERROR_NOT_IMPLEMENTED;
708 }
709 
GetIsOOP(bool * aIsAsync)710 nsresult nsNPAPIPluginInstance::GetIsOOP(bool* aIsAsync) {
711   AutoPluginLibraryCall library(this);
712   if (!library) return NS_ERROR_FAILURE;
713 
714   *aIsAsync = library->IsOOP();
715   return NS_OK;
716 }
717 
SetBackgroundUnknown()718 nsresult nsNPAPIPluginInstance::SetBackgroundUnknown() {
719   if (RUNNING != mRunning) return NS_OK;
720 
721   AutoPluginLibraryCall library(this);
722   if (!library) return NS_ERROR_FAILURE;
723 
724   return library->SetBackgroundUnknown(&mNPP);
725 }
726 
BeginUpdateBackground(nsIntRect * aRect,DrawTarget ** aDrawTarget)727 nsresult nsNPAPIPluginInstance::BeginUpdateBackground(
728     nsIntRect* aRect, DrawTarget** aDrawTarget) {
729   if (RUNNING != mRunning) return NS_OK;
730 
731   AutoPluginLibraryCall library(this);
732   if (!library) return NS_ERROR_FAILURE;
733 
734   return library->BeginUpdateBackground(&mNPP, *aRect, aDrawTarget);
735 }
736 
EndUpdateBackground(nsIntRect * aRect)737 nsresult nsNPAPIPluginInstance::EndUpdateBackground(nsIntRect* aRect) {
738   if (RUNNING != mRunning) return NS_OK;
739 
740   AutoPluginLibraryCall library(this);
741   if (!library) return NS_ERROR_FAILURE;
742 
743   return library->EndUpdateBackground(&mNPP, *aRect);
744 }
745 
IsTransparent(bool * isTransparent)746 nsresult nsNPAPIPluginInstance::IsTransparent(bool* isTransparent) {
747   *isTransparent = mTransparent;
748   return NS_OK;
749 }
750 
GetFormValue(nsAString & aValue)751 nsresult nsNPAPIPluginInstance::GetFormValue(nsAString& aValue) {
752   aValue.Truncate();
753 
754   char* value = nullptr;
755   nsresult rv = GetValueFromPlugin(NPPVformValue, &value);
756   if (NS_FAILED(rv) || !value) return NS_ERROR_FAILURE;
757 
758   CopyUTF8toUTF16(MakeStringSpan(value), aValue);
759 
760   // NPPVformValue allocates with NPN_MemAlloc(), which uses
761   // nsMemory.
762   free(value);
763 
764   return NS_OK;
765 }
766 
PushPopupsEnabledState(bool aEnabled)767 nsresult nsNPAPIPluginInstance::PushPopupsEnabledState(bool aEnabled) {
768   nsCOMPtr<nsPIDOMWindowOuter> window = GetDOMWindow();
769   if (!window) return NS_ERROR_FAILURE;
770 
771   PopupBlocker::PopupControlState oldState =
772       PopupBlocker::PushPopupControlState(
773           aEnabled ? PopupBlocker::openAllowed : PopupBlocker::openAbused,
774           true);
775 
776   // XXX(Bug 1631371) Check if this should use a fallible operation as it
777   // pretended earlier.
778   mPopupStates.AppendElement(oldState);
779 
780   return NS_OK;
781 }
782 
PopPopupsEnabledState()783 nsresult nsNPAPIPluginInstance::PopPopupsEnabledState() {
784   int32_t last = mPopupStates.Length() - 1;
785 
786   if (last < 0) {
787     // Nothing to pop.
788     return NS_OK;
789   }
790 
791   nsCOMPtr<nsPIDOMWindowOuter> window = GetDOMWindow();
792   if (!window) return NS_ERROR_FAILURE;
793 
794   PopupBlocker::PopupControlState& oldState = mPopupStates[last];
795 
796   PopupBlocker::PopPopupControlState(oldState);
797 
798   mPopupStates.RemoveElementAt(last);
799 
800   return NS_OK;
801 }
802 
GetPluginAPIVersion(uint16_t * version)803 nsresult nsNPAPIPluginInstance::GetPluginAPIVersion(uint16_t* version) {
804   NS_ENSURE_ARG_POINTER(version);
805 
806   if (!mPlugin) return NS_ERROR_FAILURE;
807 
808   if (!mPlugin->GetLibrary()) return NS_ERROR_FAILURE;
809 
810   NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
811 
812   *version = pluginFunctions->version;
813 
814   return NS_OK;
815 }
816 
PrivateModeStateChanged(bool enabled)817 nsresult nsNPAPIPluginInstance::PrivateModeStateChanged(bool enabled) {
818   if (RUNNING != mRunning) return NS_OK;
819 
820   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance informing plugin of "
821                                  "private mode state change this=%p\n",
822                                  this));
823 
824   if (!mPlugin || !mPlugin->GetLibrary()) return NS_ERROR_FAILURE;
825 
826   NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
827 
828   if (!pluginFunctions->setvalue) return NS_ERROR_FAILURE;
829 
830   PluginDestructionGuard guard(this);
831 
832   NPError error;
833   NPBool value = static_cast<NPBool>(enabled);
834   NS_TRY_SAFE_CALL_RETURN(
835       error, (*pluginFunctions->setvalue)(&mNPP, NPNVprivateModeBool, &value),
836       this, NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
837   return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE;
838 }
839 
IsPrivateBrowsing(bool * aEnabled)840 nsresult nsNPAPIPluginInstance::IsPrivateBrowsing(bool* aEnabled) {
841   if (!mOwner) return NS_ERROR_FAILURE;
842 
843   nsCOMPtr<Document> doc;
844   mOwner->GetDocument(getter_AddRefs(doc));
845   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
846 
847   nsCOMPtr<nsPIDOMWindowOuter> domwindow = doc->GetWindow();
848   NS_ENSURE_TRUE(domwindow, NS_ERROR_FAILURE);
849 
850   nsCOMPtr<nsIDocShell> docShell = domwindow->GetDocShell();
851   nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
852   *aEnabled = (loadContext && loadContext->UsePrivateBrowsing());
853   return NS_OK;
854 }
855 
PluginTimerCallback(nsITimer * aTimer,void * aClosure)856 static void PluginTimerCallback(nsITimer* aTimer, void* aClosure) {
857   nsNPAPITimer* t = (nsNPAPITimer*)aClosure;
858   NPP npp = t->npp;
859   uint32_t id = t->id;
860 
861   PLUGIN_LOG(PLUGIN_LOG_NOISY,
862              ("nsNPAPIPluginInstance running plugin timer callback this=%p\n",
863               npp->ndata));
864 
865   // Some plugins (Flash on Android) calls unscheduletimer
866   // from this callback.
867   t->inCallback = true;
868   (*(t->callback))(npp, id);
869   t->inCallback = false;
870 
871   // Make sure we still have an instance and the timer is still alive
872   // after the callback.
873   nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)npp->ndata;
874   if (!inst || !inst->TimerWithID(id, nullptr)) return;
875 
876   // use UnscheduleTimer to clean up if this is a one-shot timer
877   uint32_t timerType;
878   t->timer->GetType(&timerType);
879   if (t->needUnschedule || timerType == nsITimer::TYPE_ONE_SHOT)
880     inst->UnscheduleTimer(id);
881 }
882 
TimerWithID(uint32_t id,uint32_t * index)883 nsNPAPITimer* nsNPAPIPluginInstance::TimerWithID(uint32_t id, uint32_t* index) {
884   uint32_t len = mTimers.Length();
885   for (uint32_t i = 0; i < len; i++) {
886     if (mTimers[i]->id == id) {
887       if (index) *index = i;
888       return mTimers[i];
889     }
890   }
891   return nullptr;
892 }
893 
ScheduleTimer(uint32_t interval,NPBool repeat,void (* timerFunc)(NPP npp,uint32_t timerID))894 uint32_t nsNPAPIPluginInstance::ScheduleTimer(
895     uint32_t interval, NPBool repeat,
896     void (*timerFunc)(NPP npp, uint32_t timerID)) {
897   if (RUNNING != mRunning) return 0;
898 
899   nsNPAPITimer* newTimer = new nsNPAPITimer();
900 
901   newTimer->inCallback = newTimer->needUnschedule = false;
902   newTimer->npp = &mNPP;
903 
904   // generate ID that is unique to this instance
905   uint32_t uniqueID = mTimers.Length();
906   while ((uniqueID == 0) || TimerWithID(uniqueID, nullptr)) uniqueID++;
907   newTimer->id = uniqueID;
908 
909   // create new xpcom timer, scheduled correctly
910   nsresult rv;
911   const short timerType = (repeat ? (short)nsITimer::TYPE_REPEATING_SLACK
912                                   : (short)nsITimer::TYPE_ONE_SHOT);
913   rv = NS_NewTimerWithFuncCallback(
914       getter_AddRefs(newTimer->timer), PluginTimerCallback, newTimer, interval,
915       timerType, "nsNPAPIPluginInstance::ScheduleTimer");
916   if (NS_FAILED(rv)) {
917     delete newTimer;
918     return 0;
919   }
920 
921   // save callback function
922   newTimer->callback = timerFunc;
923 
924   // add timer to timers array
925   mTimers.AppendElement(newTimer);
926 
927   return newTimer->id;
928 }
929 
UnscheduleTimer(uint32_t timerID)930 void nsNPAPIPluginInstance::UnscheduleTimer(uint32_t timerID) {
931   // find the timer struct by ID
932   uint32_t index;
933   nsNPAPITimer* t = TimerWithID(timerID, &index);
934   if (!t) return;
935 
936   if (t->inCallback) {
937     t->needUnschedule = true;
938     return;
939   }
940 
941   // cancel the timer
942   t->timer->Cancel();
943 
944   // remove timer struct from array
945   mTimers.RemoveElementAt(index);
946 
947   // delete timer
948   delete t;
949 }
950 
ConvertPoint(double sourceX,double sourceY,NPCoordinateSpace sourceSpace,double * destX,double * destY,NPCoordinateSpace destSpace)951 NPBool nsNPAPIPluginInstance::ConvertPoint(double sourceX, double sourceY,
952                                            NPCoordinateSpace sourceSpace,
953                                            double* destX, double* destY,
954                                            NPCoordinateSpace destSpace) {
955   if (mOwner) {
956     return mOwner->ConvertPoint(sourceX, sourceY, sourceSpace, destX, destY,
957                                 destSpace);
958   }
959 
960   return false;
961 }
962 
GetDOMElement(Element ** result)963 nsresult nsNPAPIPluginInstance::GetDOMElement(Element** result) {
964   if (!mOwner) {
965     *result = nullptr;
966     return NS_ERROR_FAILURE;
967   }
968 
969   return mOwner->GetDOMElement(result);
970 }
971 
InvalidateRect(NPRect * invalidRect)972 nsresult nsNPAPIPluginInstance::InvalidateRect(NPRect* invalidRect) {
973   if (RUNNING != mRunning) return NS_OK;
974 
975   if (!mOwner) return NS_ERROR_FAILURE;
976 
977   return mOwner->InvalidateRect(invalidRect);
978 }
979 
InvalidateRegion(NPRegion invalidRegion)980 nsresult nsNPAPIPluginInstance::InvalidateRegion(NPRegion invalidRegion) {
981   if (RUNNING != mRunning) return NS_OK;
982 
983   if (!mOwner) return NS_ERROR_FAILURE;
984 
985   return mOwner->InvalidateRegion(invalidRegion);
986 }
987 
GetMIMEType(const char ** result)988 nsresult nsNPAPIPluginInstance::GetMIMEType(const char** result) {
989   if (!mMIMEType)
990     *result = "";
991   else
992     *result = mMIMEType;
993 
994   return NS_OK;
995 }
996 
GetOwner()997 nsPluginInstanceOwner* nsNPAPIPluginInstance::GetOwner() { return mOwner; }
998 
SetOwner(nsPluginInstanceOwner * aOwner)999 void nsNPAPIPluginInstance::SetOwner(nsPluginInstanceOwner* aOwner) {
1000   mOwner = aOwner;
1001 }
1002 
AsyncSetWindow(NPWindow & window)1003 nsresult nsNPAPIPluginInstance::AsyncSetWindow(NPWindow& window) {
1004   return NS_ERROR_NOT_IMPLEMENTED;
1005 }
1006 
URLRedirectResponse(void * notifyData,NPBool allow)1007 void nsNPAPIPluginInstance::URLRedirectResponse(void* notifyData,
1008                                                 NPBool allow) {
1009   if (!notifyData) {
1010     return;
1011   }
1012 
1013   uint32_t listenerCount = mStreamListeners.Length();
1014   for (uint32_t i = 0; i < listenerCount; i++) {
1015     nsNPAPIPluginStreamListener* currentListener = mStreamListeners[i];
1016     if (currentListener->GetNotifyData() == notifyData) {
1017       currentListener->URLRedirectResponse(allow);
1018     }
1019   }
1020 }
1021 
InitAsyncSurface(NPSize * size,NPImageFormat format,void * initData,NPAsyncSurface * surface)1022 NPError nsNPAPIPluginInstance::InitAsyncSurface(NPSize* size,
1023                                                 NPImageFormat format,
1024                                                 void* initData,
1025                                                 NPAsyncSurface* surface) {
1026   if (mOwner) {
1027     return mOwner->InitAsyncSurface(size, format, initData, surface);
1028   }
1029 
1030   return NPERR_GENERIC_ERROR;
1031 }
1032 
FinalizeAsyncSurface(NPAsyncSurface * surface)1033 NPError nsNPAPIPluginInstance::FinalizeAsyncSurface(NPAsyncSurface* surface) {
1034   if (mOwner) {
1035     return mOwner->FinalizeAsyncSurface(surface);
1036   }
1037 
1038   return NPERR_GENERIC_ERROR;
1039 }
1040 
SetCurrentAsyncSurface(NPAsyncSurface * surface,NPRect * changed)1041 void nsNPAPIPluginInstance::SetCurrentAsyncSurface(NPAsyncSurface* surface,
1042                                                    NPRect* changed) {
1043   if (mOwner) {
1044     mOwner->SetCurrentAsyncSurface(surface, changed);
1045   }
1046 }
1047 
GetContentsScaleFactor()1048 double nsNPAPIPluginInstance::GetContentsScaleFactor() {
1049   double scaleFactor = 1.0;
1050   if (mOwner) {
1051     mOwner->GetContentsScaleFactor(&scaleFactor);
1052   }
1053   return scaleFactor;
1054 }
1055 
GetCSSZoomFactor()1056 float nsNPAPIPluginInstance::GetCSSZoomFactor() {
1057   float zoomFactor = 1.0;
1058   if (mOwner) {
1059     mOwner->GetCSSZoomFactor(&zoomFactor);
1060   }
1061   return zoomFactor;
1062 }
1063 
GetRunID(uint32_t * aRunID)1064 nsresult nsNPAPIPluginInstance::GetRunID(uint32_t* aRunID) {
1065   if (NS_WARN_IF(!aRunID)) {
1066     return NS_ERROR_INVALID_POINTER;
1067   }
1068 
1069   if (NS_WARN_IF(!mPlugin)) {
1070     return NS_ERROR_FAILURE;
1071   }
1072 
1073   PluginLibrary* library = mPlugin->GetLibrary();
1074   if (!library) {
1075     return NS_ERROR_FAILURE;
1076   }
1077 
1078   return library->GetRunID(aRunID);
1079 }
1080 
CreateAudioChannelAgentIfNeeded()1081 nsresult nsNPAPIPluginInstance::CreateAudioChannelAgentIfNeeded() {
1082   if (mAudioChannelAgent) {
1083     return NS_OK;
1084   }
1085 
1086   mAudioChannelAgent = new AudioChannelAgent();
1087 
1088   nsCOMPtr<nsPIDOMWindowOuter> window = GetDOMWindow();
1089   if (NS_WARN_IF(!window)) {
1090     return NS_ERROR_FAILURE;
1091   }
1092 
1093   nsresult rv = mAudioChannelAgent->Init(window->GetCurrentInnerWindow(), this);
1094   if (NS_WARN_IF(NS_FAILED(rv))) {
1095     return rv;
1096   }
1097   return NS_OK;
1098 }
1099 
NotifyStartedPlaying()1100 void nsNPAPIPluginInstance::NotifyStartedPlaying() {
1101   nsresult rv = CreateAudioChannelAgentIfNeeded();
1102   if (NS_WARN_IF(NS_FAILED(rv))) {
1103     return;
1104   }
1105 
1106   MOZ_ASSERT(mAudioChannelAgent);
1107   rv = mAudioChannelAgent->NotifyStartedPlaying(
1108       mIsMuted ? AudioChannelService::AudibleState::eNotAudible
1109                : AudioChannelService::AudibleState::eAudible);
1110   if (NS_WARN_IF(NS_FAILED(rv))) {
1111     return;
1112   }
1113 
1114   mAudioChannelAgent->PullInitialUpdate();
1115 }
1116 
NotifyStoppedPlaying()1117 void nsNPAPIPluginInstance::NotifyStoppedPlaying() {
1118   MOZ_ASSERT(mAudioChannelAgent);
1119   nsresult rv = mAudioChannelAgent->NotifyStoppedPlaying();
1120   if (NS_WARN_IF(NS_FAILED(rv))) {
1121     return;
1122   }
1123 }
1124 
1125 NS_IMETHODIMP
WindowVolumeChanged(float aVolume,bool aMuted)1126 nsNPAPIPluginInstance::WindowVolumeChanged(float aVolume, bool aMuted) {
1127   MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
1128           ("nsNPAPIPluginInstance, WindowVolumeChanged, "
1129            "this = %p, aVolume = %f, aMuted = %s\n",
1130            this, aVolume, aMuted ? "true" : "false"));
1131   // We just support mute/unmute
1132   if (mWindowMuted != aMuted) {
1133     mWindowMuted = aMuted;
1134     return UpdateMutedIfNeeded();
1135   }
1136   return NS_OK;
1137 }
1138 
1139 NS_IMETHODIMP
WindowSuspendChanged(nsSuspendedTypes aSuspend)1140 nsNPAPIPluginInstance::WindowSuspendChanged(nsSuspendedTypes aSuspend) {
1141   MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
1142           ("nsNPAPIPluginInstance, WindowSuspendChanged, "
1143            "this = %p, aSuspend = %s\n",
1144            this, SuspendTypeToStr(aSuspend)));
1145   const bool isSuspended = aSuspend != nsISuspendedTypes::NONE_SUSPENDED;
1146   if (mWindowSuspended != isSuspended) {
1147     mWindowSuspended = isSuspended;
1148     // It doesn't support suspending, so we just do something like mute/unmute.
1149     return UpdateMutedIfNeeded();
1150   }
1151   return NS_OK;
1152 }
1153 
1154 NS_IMETHODIMP
WindowAudioCaptureChanged(bool aCapture)1155 nsNPAPIPluginInstance::WindowAudioCaptureChanged(bool aCapture) {
1156   return NS_OK;
1157 }
1158 
NotifyAudibleStateChanged() const1159 void nsNPAPIPluginInstance::NotifyAudibleStateChanged() const {
1160   // This happens when global window destroyed, we would notify agent's callback
1161   // to mute its volume, but the nsNSNPAPI had released the agent before that.
1162   if (!mAudioChannelAgent) {
1163     return;
1164   }
1165   AudioChannelService::AudibleState audibleState =
1166       mIsMuted ? AudioChannelService::AudibleState::eNotAudible
1167                : AudioChannelService::AudibleState::eAudible;
1168   // Because we don't really support suspending nsNPAPI, so all audible changes
1169   // come from changing its volume.
1170   mAudioChannelAgent->NotifyStartedAudible(
1171       audibleState, AudioChannelService::AudibleChangedReasons::eVolumeChanged);
1172 }
1173 
UpdateMutedIfNeeded()1174 nsresult nsNPAPIPluginInstance::UpdateMutedIfNeeded() {
1175   const bool shouldMute = mWindowSuspended || mWindowMuted;
1176   if (mIsMuted == shouldMute) {
1177     return NS_OK;
1178   }
1179 
1180   mIsMuted = shouldMute;
1181   NotifyAudibleStateChanged();
1182   nsresult rv = SetMuted(mIsMuted);
1183   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetMuted failed");
1184   return rv;
1185 }
1186 
SetMuted(bool aIsMuted)1187 nsresult nsNPAPIPluginInstance::SetMuted(bool aIsMuted) {
1188   if (RUNNING != mRunning) return NS_OK;
1189 
1190   PLUGIN_LOG(
1191       PLUGIN_LOG_NORMAL,
1192       ("nsNPAPIPluginInstance informing plugin of mute state change this=%p\n",
1193        this));
1194 
1195   if (!mPlugin || !mPlugin->GetLibrary()) return NS_ERROR_FAILURE;
1196 
1197   NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
1198 
1199   if (!pluginFunctions->setvalue) return NS_ERROR_FAILURE;
1200 
1201   PluginDestructionGuard guard(this);
1202 
1203   NPError error;
1204   NPBool value = static_cast<NPBool>(aIsMuted);
1205   NS_TRY_SAFE_CALL_RETURN(
1206       error, (*pluginFunctions->setvalue)(&mNPP, NPNVmuteAudioBool, &value),
1207       this, NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
1208   return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE;
1209 }
1210