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