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 "base/basictypes.h"
7 
8 /* This must occur *after* layers/PLayerTransaction.h to avoid typedefs conflicts. */
9 #include "mozilla/ArrayUtils.h"
10 
11 #include "pratom.h"
12 #include "prmem.h"
13 #include "prenv.h"
14 #include "prclist.h"
15 
16 #include "jsfriendapi.h"
17 
18 #include "nsPluginHost.h"
19 #include "nsNPAPIPlugin.h"
20 #include "nsNPAPIPluginInstance.h"
21 #include "nsNPAPIPluginStreamListener.h"
22 #include "nsPluginStreamListenerPeer.h"
23 #include "nsIServiceManager.h"
24 #include "nsThreadUtils.h"
25 #include "mozilla/Preferences.h"
26 #include "nsPluginInstanceOwner.h"
27 
28 #include "nsPluginsDir.h"
29 #include "nsPluginLogging.h"
30 
31 #include "nsIDOMElement.h"
32 #include "nsPIDOMWindow.h"
33 #include "nsGlobalWindow.h"
34 #include "nsIDocument.h"
35 #include "nsIContent.h"
36 #include "nsIIDNService.h"
37 #include "nsIScriptGlobalObject.h"
38 #include "nsIScriptContext.h"
39 #include "nsDOMJSUtils.h"
40 #include "nsIPrincipal.h"
41 #include "nsWildCard.h"
42 #include "nsContentUtils.h"
43 #include "mozilla/dom/ScriptSettings.h"
44 #include "nsIXULRuntime.h"
45 #include "nsIXPConnect.h"
46 
47 #include "nsIObserverService.h"
48 #include <prinrval.h>
49 
50 #ifdef MOZ_WIDGET_COCOA
51 #include <Carbon/Carbon.h>
52 #include <ApplicationServices/ApplicationServices.h>
53 #include <OpenGL/OpenGL.h>
54 #include "nsCocoaFeatures.h"
55 #include "PluginUtilsOSX.h"
56 #endif
57 
58 // needed for nppdf plugin
59 #if (MOZ_WIDGET_GTK)
60 #include <gdk/gdk.h>
61 #include <gdk/gdkx.h>
62 #if (MOZ_WIDGET_GTK == 2)
63 #include "gtk2xtbin.h"
64 #endif
65 #endif
66 
67 #include "nsJSUtils.h"
68 #include "nsJSNPRuntime.h"
69 #include "nsIHttpAuthManager.h"
70 #include "nsICookieService.h"
71 #include "nsILoadContext.h"
72 #include "nsIDocShell.h"
73 
74 #include "nsNetUtil.h"
75 #include "nsNetCID.h"
76 
77 #include "mozilla/Mutex.h"
78 #include "mozilla/PluginLibrary.h"
79 using mozilla::PluginLibrary;
80 
81 #include "mozilla/PluginPRLibrary.h"
82 using mozilla::PluginPRLibrary;
83 
84 #include "mozilla/plugins/PluginModuleParent.h"
85 using mozilla::plugins::PluginModuleChromeParent;
86 using mozilla::plugins::PluginModuleContentParent;
87 
88 #ifdef MOZ_X11
89 #include "mozilla/X11Util.h"
90 #endif
91 
92 #ifdef XP_WIN
93 #include <windows.h>
94 #include "mozilla/WindowsVersion.h"
95 #ifdef ACCESSIBILITY
96 #include "mozilla/a11y/Compatibility.h"
97 #endif
98 #endif
99 
100 #ifdef MOZ_WIDGET_ANDROID
101 #include <android/log.h>
102 #include "android_npapi.h"
103 #include "ANPBase.h"
104 #include "GeneratedJNIWrappers.h"
105 #undef LOG
106 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
107 #endif
108 
109 #include "nsIAudioChannelAgent.h"
110 #include "AudioChannelService.h"
111 
112 using namespace mozilla;
113 using namespace mozilla::plugins::parent;
114 
115 // We should make this const...
116 static NPNetscapeFuncs sBrowserFuncs = {
117   sizeof(sBrowserFuncs),
118   (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR,
119   _geturl,
120   _posturl,
121   _requestread,
122   _newstream,
123   _write,
124   _destroystream,
125   _status,
126   _useragent,
127   _memalloc,
128   _memfree,
129   _memflush,
130   _reloadplugins,
131   _getJavaEnv,
132   _getJavaPeer,
133   _geturlnotify,
134   _posturlnotify,
135   _getvalue,
136   _setvalue,
137   _invalidaterect,
138   _invalidateregion,
139   _forceredraw,
140   _getstringidentifier,
141   _getstringidentifiers,
142   _getintidentifier,
143   _identifierisstring,
144   _utf8fromidentifier,
145   _intfromidentifier,
146   _createobject,
147   _retainobject,
148   _releaseobject,
149   _invoke,
150   _invokeDefault,
151   _evaluate,
152   _getproperty,
153   _setproperty,
154   _removeproperty,
155   _hasproperty,
156   _hasmethod,
157   _releasevariantvalue,
158   _setexception,
159   _pushpopupsenabledstate,
160   _poppopupsenabledstate,
161   _enumerate,
162   _pluginthreadasynccall,
163   _construct,
164   _getvalueforurl,
165   _setvalueforurl,
166   _getauthenticationinfo,
167   _scheduletimer,
168   _unscheduletimer,
169   _popupcontextmenu,
170   _convertpoint,
171   nullptr, // handleevent, unimplemented
172   nullptr, // unfocusinstance, unimplemented
173   _urlredirectresponse,
174   _initasyncsurface,
175   _finalizeasyncsurface,
176   _setcurrentasyncsurface
177 };
178 
179 static Mutex *sPluginThreadAsyncCallLock = nullptr;
180 static PRCList sPendingAsyncCalls = PR_INIT_STATIC_CLIST(&sPendingAsyncCalls);
181 
182 // POST/GET stream type
183 enum eNPPStreamTypeInternal {
184   eNPPStreamTypeInternal_Get,
185   eNPPStreamTypeInternal_Post
186 };
187 
NS_NotifyBeginPluginCall(NSPluginCallReentry aReentryState)188 void NS_NotifyBeginPluginCall(NSPluginCallReentry aReentryState)
189 {
190   nsNPAPIPluginInstance::BeginPluginCall(aReentryState);
191 }
192 
NS_NotifyPluginCall(NSPluginCallReentry aReentryState)193 void NS_NotifyPluginCall(NSPluginCallReentry aReentryState)
194 {
195   nsNPAPIPluginInstance::EndPluginCall(aReentryState);
196 }
197 
CheckClassInitialized()198 static void CheckClassInitialized()
199 {
200   static bool initialized = false;
201 
202   if (initialized)
203     return;
204 
205   if (!sPluginThreadAsyncCallLock)
206     sPluginThreadAsyncCallLock = new Mutex("nsNPAPIPlugin.sPluginThreadAsyncCallLock");
207 
208   initialized = true;
209 
210   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,("NPN callbacks initialized\n"));
211 }
212 
nsNPAPIPlugin()213 nsNPAPIPlugin::nsNPAPIPlugin()
214 {
215   memset((void*)&mPluginFuncs, 0, sizeof(mPluginFuncs));
216   mPluginFuncs.size = sizeof(mPluginFuncs);
217   mPluginFuncs.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
218 
219   mLibrary = nullptr;
220 }
221 
~nsNPAPIPlugin()222 nsNPAPIPlugin::~nsNPAPIPlugin()
223 {
224   delete mLibrary;
225   mLibrary = nullptr;
226 }
227 
228 void
PluginCrashed(const nsAString & pluginDumpID,const nsAString & browserDumpID)229 nsNPAPIPlugin::PluginCrashed(const nsAString& pluginDumpID,
230                              const nsAString& browserDumpID)
231 {
232   RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
233   host->PluginCrashed(this, pluginDumpID, browserDumpID);
234 }
235 
236 bool
RunPluginOOP(const nsPluginTag * aPluginTag)237 nsNPAPIPlugin::RunPluginOOP(const nsPluginTag *aPluginTag)
238 {
239 #ifdef MOZ_WIDGET_ANDROID
240   return false;
241 #else
242   return true;
243 #endif
244 }
245 
246 inline PluginLibrary*
GetNewPluginLibrary(nsPluginTag * aPluginTag)247 GetNewPluginLibrary(nsPluginTag *aPluginTag)
248 {
249   PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
250 
251   if (!aPluginTag) {
252     return nullptr;
253   }
254 
255   if (XRE_IsContentProcess()) {
256     return PluginModuleContentParent::LoadModule(aPluginTag->mId, aPluginTag);
257   }
258 
259   if (nsNPAPIPlugin::RunPluginOOP(aPluginTag)) {
260     return PluginModuleChromeParent::LoadModule(aPluginTag->mFullPath.get(), aPluginTag->mId, aPluginTag);
261   }
262   return new PluginPRLibrary(aPluginTag->mFullPath.get(), aPluginTag->mLibrary);
263 }
264 
265 // Creates an nsNPAPIPlugin object. One nsNPAPIPlugin object exists per plugin (not instance).
266 nsresult
CreatePlugin(nsPluginTag * aPluginTag,nsNPAPIPlugin ** aResult)267 nsNPAPIPlugin::CreatePlugin(nsPluginTag *aPluginTag, nsNPAPIPlugin** aResult)
268 {
269   PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
270   *aResult = nullptr;
271 
272   if (!aPluginTag) {
273     return NS_ERROR_FAILURE;
274   }
275 
276   CheckClassInitialized();
277 
278   RefPtr<nsNPAPIPlugin> plugin = new nsNPAPIPlugin();
279 
280   PluginLibrary* pluginLib = GetNewPluginLibrary(aPluginTag);
281   if (!pluginLib) {
282     return NS_ERROR_FAILURE;
283   }
284 
285 #if defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID)
286   if (!pluginLib->HasRequiredFunctions()) {
287     NS_WARNING("Not all necessary functions exposed by plugin, it will not load.");
288     delete pluginLib;
289     return NS_ERROR_FAILURE;
290   }
291 #endif
292 
293   plugin->mLibrary = pluginLib;
294   pluginLib->SetPlugin(plugin);
295 
296 // Exchange NPAPI entry points.
297 #if defined(XP_WIN)
298   // NP_GetEntryPoints must be called before NP_Initialize on Windows.
299   NPError pluginCallError;
300   nsresult rv = pluginLib->NP_GetEntryPoints(&plugin->mPluginFuncs, &pluginCallError);
301   if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) {
302     return NS_ERROR_FAILURE;
303   }
304 
305   // NP_Initialize must be called after NP_GetEntryPoints on Windows.
306   rv = pluginLib->NP_Initialize(&sBrowserFuncs, &pluginCallError);
307   if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) {
308     return NS_ERROR_FAILURE;
309   }
310 #elif defined(XP_MACOSX)
311   // NP_Initialize must be called before NP_GetEntryPoints on Mac OS X.
312   // We need to match WebKit's behavior.
313   NPError pluginCallError;
314   nsresult rv = pluginLib->NP_Initialize(&sBrowserFuncs, &pluginCallError);
315   if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) {
316     return NS_ERROR_FAILURE;
317   }
318 
319   rv = pluginLib->NP_GetEntryPoints(&plugin->mPluginFuncs, &pluginCallError);
320   if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) {
321     return NS_ERROR_FAILURE;
322   }
323 #elif defined(MOZ_WIDGET_GONK)
324 #else
325   NPError pluginCallError;
326   nsresult rv = pluginLib->NP_Initialize(&sBrowserFuncs, &plugin->mPluginFuncs, &pluginCallError);
327   if (rv != NS_OK || pluginCallError != NPERR_NO_ERROR) {
328     return NS_ERROR_FAILURE;
329   }
330 #endif
331 
332   plugin.forget(aResult);
333   return NS_OK;
334 }
335 
336 PluginLibrary*
GetLibrary()337 nsNPAPIPlugin::GetLibrary()
338 {
339   return mLibrary;
340 }
341 
342 NPPluginFuncs*
PluginFuncs()343 nsNPAPIPlugin::PluginFuncs()
344 {
345   return &mPluginFuncs;
346 }
347 
348 nsresult
Shutdown()349 nsNPAPIPlugin::Shutdown()
350 {
351   NPP_PLUGIN_LOG(PLUGIN_LOG_BASIC,
352                  ("NPP Shutdown to be called: this=%p\n", this));
353 
354   NPError shutdownError;
355   mLibrary->NP_Shutdown(&shutdownError);
356 
357   return NS_OK;
358 }
359 
360 nsresult
RetainStream(NPStream * pstream,nsISupports ** aRetainedPeer)361 nsNPAPIPlugin::RetainStream(NPStream *pstream, nsISupports **aRetainedPeer)
362 {
363   if (!aRetainedPeer)
364     return NS_ERROR_NULL_POINTER;
365 
366   *aRetainedPeer = nullptr;
367 
368   if (!pstream || !pstream->ndata)
369     return NS_ERROR_NULL_POINTER;
370 
371   nsNPAPIStreamWrapper* streamWrapper = static_cast<nsNPAPIStreamWrapper*>(pstream->ndata);
372   nsNPAPIPluginStreamListener* listener = streamWrapper->GetStreamListener();
373   if (!listener) {
374     return NS_ERROR_NULL_POINTER;
375   }
376 
377   nsIStreamListener* streamListener = listener->GetStreamListenerPeer();
378   if (!streamListener) {
379     return NS_ERROR_NULL_POINTER;
380   }
381 
382   *aRetainedPeer = streamListener;
383   NS_ADDREF(*aRetainedPeer);
384   return NS_OK;
385 }
386 
387 // Create a new NPP GET or POST (given in the type argument) url
388 // stream that may have a notify callback
389 NPError
MakeNewNPAPIStreamInternal(NPP npp,const char * relativeURL,const char * target,eNPPStreamTypeInternal type,bool bDoNotify=false,void * notifyData=nullptr,uint32_t len=0,const char * buf=nullptr,NPBool file=false)390 MakeNewNPAPIStreamInternal(NPP npp, const char *relativeURL, const char *target,
391                           eNPPStreamTypeInternal type,
392                           bool bDoNotify = false,
393                           void *notifyData = nullptr, uint32_t len = 0,
394                           const char *buf = nullptr, NPBool file = false)
395 {
396   if (!npp)
397     return NPERR_INVALID_INSTANCE_ERROR;
398 
399   PluginDestructionGuard guard(npp);
400 
401   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata;
402   if (!inst || !inst->IsRunning())
403     return NPERR_INVALID_INSTANCE_ERROR;
404 
405   nsCOMPtr<nsIPluginHost> pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
406   nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
407   if (!pluginHost) {
408     return NPERR_GENERIC_ERROR;
409   }
410 
411   RefPtr<nsNPAPIPluginStreamListener> listener;
412   // Set aCallNotify here to false.  If pluginHost->GetURL or PostURL fail,
413   // the listener's destructor will do the notification while we are about to
414   // return a failure code.
415   // Call SetCallNotify(true) below after we are sure we cannot return a failure
416   // code.
417   if (!target) {
418     inst->NewStreamListener(relativeURL, notifyData,
419                             getter_AddRefs(listener));
420     if (listener) {
421       listener->SetCallNotify(false);
422     }
423   }
424 
425   switch (type) {
426   case eNPPStreamTypeInternal_Get:
427     {
428       if (NS_FAILED(pluginHost->GetURL(inst, relativeURL, target, listener,
429                                        nullptr, nullptr, false)))
430         return NPERR_GENERIC_ERROR;
431       break;
432     }
433   case eNPPStreamTypeInternal_Post:
434     {
435       if (NS_FAILED(pluginHost->PostURL(inst, relativeURL, len, buf, file,
436                                         target, listener, nullptr, nullptr,
437                                         false, 0, nullptr)))
438         return NPERR_GENERIC_ERROR;
439       break;
440     }
441   default:
442     NS_ERROR("how'd I get here");
443   }
444 
445   if (listener) {
446     // SetCallNotify(bDoNotify) here, see comment above.
447     listener->SetCallNotify(bDoNotify);
448   }
449 
450   return NPERR_NO_ERROR;
451 }
452 
453 #if defined(MOZ_MEMORY_WINDOWS)
454 extern "C" size_t malloc_usable_size(const void *ptr);
455 #endif
456 
457 namespace {
458 
459 static char *gNPPException;
460 
461 class nsPluginThreadRunnable : public Runnable,
462                                public PRCList
463 {
464 public:
465   nsPluginThreadRunnable(NPP instance, PluginThreadCallback func,
466                          void *userData);
467   virtual ~nsPluginThreadRunnable();
468 
469   NS_IMETHOD Run();
470 
IsForInstance(NPP instance)471   bool IsForInstance(NPP instance)
472   {
473     return (mInstance == instance);
474   }
475 
Invalidate()476   void Invalidate()
477   {
478     mFunc = nullptr;
479   }
480 
IsValid()481   bool IsValid()
482   {
483     return (mFunc != nullptr);
484   }
485 
486 private:
487   NPP mInstance;
488   PluginThreadCallback mFunc;
489   void *mUserData;
490 };
491 
492 static nsIDocument *
GetDocumentFromNPP(NPP npp)493 GetDocumentFromNPP(NPP npp)
494 {
495   NS_ENSURE_TRUE(npp, nullptr);
496 
497   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)npp->ndata;
498   NS_ENSURE_TRUE(inst, nullptr);
499 
500   PluginDestructionGuard guard(inst);
501 
502   RefPtr<nsPluginInstanceOwner> owner = inst->GetOwner();
503   NS_ENSURE_TRUE(owner, nullptr);
504 
505   nsCOMPtr<nsIDocument> doc;
506   owner->GetDocument(getter_AddRefs(doc));
507 
508   return doc;
509 }
510 
511 static already_AddRefed<nsIChannel>
GetChannelFromNPP(NPP npp)512 GetChannelFromNPP(NPP npp)
513 {
514   nsCOMPtr<nsIDocument> doc = GetDocumentFromNPP(npp);
515   if (!doc)
516     return nullptr;
517   nsCOMPtr<nsPIDOMWindowOuter> domwindow = doc->GetWindow();
518   nsCOMPtr<nsIChannel> channel;
519   if (domwindow) {
520     nsCOMPtr<nsIDocShell> docShell = domwindow->GetDocShell();
521     if (docShell) {
522       docShell->GetCurrentDocumentChannel(getter_AddRefs(channel));
523     }
524   }
525   return channel.forget();
526 }
527 
528 static NPIdentifier
doGetIdentifier(JSContext * cx,const NPUTF8 * name)529 doGetIdentifier(JSContext *cx, const NPUTF8* name)
530 {
531   NS_ConvertUTF8toUTF16 utf16name(name);
532 
533   JSString *str = ::JS_AtomizeAndPinUCStringN(cx, utf16name.get(), utf16name.Length());
534 
535   if (!str)
536     return nullptr;
537 
538   return StringToNPIdentifier(cx, str);
539 }
540 
541 #if defined(MOZ_MEMORY_WINDOWS)
542 BOOL
InHeap(HANDLE hHeap,LPVOID lpMem)543 InHeap(HANDLE hHeap, LPVOID lpMem)
544 {
545   BOOL success = FALSE;
546   PROCESS_HEAP_ENTRY he;
547   he.lpData = nullptr;
548   while (HeapWalk(hHeap, &he) != 0) {
549     if (he.lpData == lpMem) {
550       success = TRUE;
551       break;
552     }
553   }
554   HeapUnlock(hHeap);
555   return success;
556 }
557 #endif
558 
559 } /* anonymous namespace */
560 
NPPExceptionAutoHolder()561 NPPExceptionAutoHolder::NPPExceptionAutoHolder()
562   : mOldException(gNPPException)
563 {
564   gNPPException = nullptr;
565 }
566 
~NPPExceptionAutoHolder()567 NPPExceptionAutoHolder::~NPPExceptionAutoHolder()
568 {
569   NS_ASSERTION(!gNPPException, "NPP exception not properly cleared!");
570 
571   gNPPException = mOldException;
572 }
573 
nsPluginThreadRunnable(NPP instance,PluginThreadCallback func,void * userData)574 nsPluginThreadRunnable::nsPluginThreadRunnable(NPP instance,
575                                                PluginThreadCallback func,
576                                                void *userData)
577   : mInstance(instance), mFunc(func), mUserData(userData)
578 {
579   if (!sPluginThreadAsyncCallLock) {
580     // Failed to create lock, not much we can do here then...
581     mFunc = nullptr;
582 
583     return;
584   }
585 
586   PR_INIT_CLIST(this);
587 
588   {
589     MutexAutoLock lock(*sPluginThreadAsyncCallLock);
590 
591     nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
592     if (!inst || !inst->IsRunning()) {
593       // The plugin was stopped, ignore this async call.
594       mFunc = nullptr;
595 
596       return;
597     }
598 
599     PR_APPEND_LINK(this, &sPendingAsyncCalls);
600   }
601 }
602 
~nsPluginThreadRunnable()603 nsPluginThreadRunnable::~nsPluginThreadRunnable()
604 {
605   if (!sPluginThreadAsyncCallLock) {
606     return;
607   }
608 
609   {
610     MutexAutoLock lock(*sPluginThreadAsyncCallLock);
611 
612     PR_REMOVE_LINK(this);
613   }
614 }
615 
616 NS_IMETHODIMP
Run()617 nsPluginThreadRunnable::Run()
618 {
619   if (mFunc) {
620     PluginDestructionGuard guard(mInstance);
621 
622     NS_TRY_SAFE_CALL_VOID(mFunc(mUserData), nullptr,
623                           NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
624   }
625 
626   return NS_OK;
627 }
628 
629 void
OnPluginDestroy(NPP instance)630 OnPluginDestroy(NPP instance)
631 {
632   if (!sPluginThreadAsyncCallLock) {
633     return;
634   }
635 
636   {
637     MutexAutoLock lock(*sPluginThreadAsyncCallLock);
638 
639     if (PR_CLIST_IS_EMPTY(&sPendingAsyncCalls)) {
640       return;
641     }
642 
643     nsPluginThreadRunnable *r =
644       (nsPluginThreadRunnable *)PR_LIST_HEAD(&sPendingAsyncCalls);
645 
646     do {
647       if (r->IsForInstance(instance)) {
648         r->Invalidate();
649       }
650 
651       r = (nsPluginThreadRunnable *)PR_NEXT_LINK(r);
652     } while (r != &sPendingAsyncCalls);
653   }
654 }
655 
656 void
OnShutdown()657 OnShutdown()
658 {
659   NS_ASSERTION(PR_CLIST_IS_EMPTY(&sPendingAsyncCalls),
660                "Pending async plugin call list not cleaned up!");
661 
662   if (sPluginThreadAsyncCallLock) {
663     delete sPluginThreadAsyncCallLock;
664 
665     sPluginThreadAsyncCallLock = nullptr;
666   }
667 }
668 
AsyncCallbackAutoLock()669 AsyncCallbackAutoLock::AsyncCallbackAutoLock()
670 {
671   if (sPluginThreadAsyncCallLock) {
672     sPluginThreadAsyncCallLock->Lock();
673   }
674 }
675 
~AsyncCallbackAutoLock()676 AsyncCallbackAutoLock::~AsyncCallbackAutoLock()
677 {
678   if (sPluginThreadAsyncCallLock) {
679     sPluginThreadAsyncCallLock->Unlock();
680   }
681 }
682 
683 NPP NPPStack::sCurrentNPP = nullptr;
684 
685 const char *
PeekException()686 PeekException()
687 {
688   return gNPPException;
689 }
690 
691 void
PopException()692 PopException()
693 {
694   NS_ASSERTION(gNPPException, "Uh, no NPP exception to pop!");
695 
696   if (gNPPException) {
697     free(gNPPException);
698 
699     gNPPException = nullptr;
700   }
701 }
702 
703 //
704 // Static callbacks that get routed back through the new C++ API
705 //
706 
707 namespace mozilla {
708 namespace plugins {
709 namespace parent {
710 
711 NPError
_geturl(NPP npp,const char * relativeURL,const char * target)712 _geturl(NPP npp, const char* relativeURL, const char* target)
713 {
714   if (!NS_IsMainThread()) {
715     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_geturl called from the wrong thread\n"));
716     return NPERR_INVALID_PARAM;
717   }
718 
719   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
720   ("NPN_GetURL: npp=%p, target=%s, url=%s\n", (void *)npp, target,
721    relativeURL));
722 
723   PluginDestructionGuard guard(npp);
724 
725   // Block Adobe Acrobat from loading URLs that are not http:, https:,
726   // or ftp: URLs if the given target is null.
727   if (!target && relativeURL &&
728       (strncmp(relativeURL, "http:", 5) != 0) &&
729       (strncmp(relativeURL, "https:", 6) != 0) &&
730       (strncmp(relativeURL, "ftp:", 4) != 0)) {
731     nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata;
732 
733     const char *name = nullptr;
734     RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
735     host->GetPluginName(inst, &name);
736 
737     if (name && strstr(name, "Adobe") && strstr(name, "Acrobat")) {
738       return NPERR_NO_ERROR;
739     }
740   }
741 
742   return MakeNewNPAPIStreamInternal(npp, relativeURL, target,
743                                     eNPPStreamTypeInternal_Get);
744 }
745 
746 NPError
_geturlnotify(NPP npp,const char * relativeURL,const char * target,void * notifyData)747 _geturlnotify(NPP npp, const char* relativeURL, const char* target,
748               void* notifyData)
749 {
750   if (!NS_IsMainThread()) {
751     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_geturlnotify called from the wrong thread\n"));
752     return NPERR_INVALID_PARAM;
753   }
754 
755   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
756     ("NPN_GetURLNotify: npp=%p, target=%s, notify=%p, url=%s\n", (void*)npp,
757      target, notifyData, relativeURL));
758 
759   PluginDestructionGuard guard(npp);
760 
761   return MakeNewNPAPIStreamInternal(npp, relativeURL, target,
762                                     eNPPStreamTypeInternal_Get, true,
763                                     notifyData);
764 }
765 
766 NPError
_posturlnotify(NPP npp,const char * relativeURL,const char * target,uint32_t len,const char * buf,NPBool file,void * notifyData)767 _posturlnotify(NPP npp, const char *relativeURL, const char *target,
768                uint32_t len, const char *buf, NPBool file, void *notifyData)
769 {
770   if (!NS_IsMainThread()) {
771     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_posturlnotify called from the wrong thread\n"));
772     return NPERR_INVALID_PARAM;
773   }
774   if (!buf)
775     return NPERR_INVALID_PARAM;
776 
777   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
778                  ("NPN_PostURLNotify: npp=%p, target=%s, len=%d, file=%d, "
779                   "notify=%p, url=%s, buf=%s\n",
780                   (void*)npp, target, len, file, notifyData, relativeURL,
781                   buf));
782 
783   PluginDestructionGuard guard(npp);
784 
785   return MakeNewNPAPIStreamInternal(npp, relativeURL, target,
786                                     eNPPStreamTypeInternal_Post, true,
787                                     notifyData, len, buf, file);
788 }
789 
790 NPError
_posturl(NPP npp,const char * relativeURL,const char * target,uint32_t len,const char * buf,NPBool file)791 _posturl(NPP npp, const char *relativeURL, const char *target,
792          uint32_t len, const char *buf, NPBool file)
793 {
794   if (!NS_IsMainThread()) {
795     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_posturl called from the wrong thread\n"));
796     return NPERR_INVALID_PARAM;
797   }
798   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
799                  ("NPN_PostURL: npp=%p, target=%s, file=%d, len=%d, url=%s, "
800                   "buf=%s\n",
801                   (void*)npp, target, file, len, relativeURL, buf));
802 
803   PluginDestructionGuard guard(npp);
804 
805   return MakeNewNPAPIStreamInternal(npp, relativeURL, target,
806                                     eNPPStreamTypeInternal_Post, false, nullptr,
807                                     len, buf, file);
808 }
809 
810 NPError
_newstream(NPP npp,NPMIMEType type,const char * target,NPStream ** result)811 _newstream(NPP npp, NPMIMEType type, const char* target, NPStream* *result)
812 {
813   if (!NS_IsMainThread()) {
814     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_newstream called from the wrong thread\n"));
815     return NPERR_INVALID_PARAM;
816   }
817   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
818   ("NPN_NewStream: npp=%p, type=%s, target=%s\n", (void*)npp,
819    (const char *)type, target));
820 
821   NPError err = NPERR_INVALID_INSTANCE_ERROR;
822   if (npp && npp->ndata) {
823     nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata;
824 
825     PluginDestructionGuard guard(inst);
826 
827     nsCOMPtr<nsIOutputStream> stream;
828     if (NS_SUCCEEDED(inst->NewStreamFromPlugin((const char*) type, target,
829                                                getter_AddRefs(stream)))) {
830       nsNPAPIStreamWrapper* wrapper = new nsNPAPIStreamWrapper(stream, nullptr);
831       if (wrapper) {
832         (*result) = &wrapper->mNPStream;
833         err = NPERR_NO_ERROR;
834       } else {
835         err = NPERR_OUT_OF_MEMORY_ERROR;
836       }
837     } else {
838       err = NPERR_GENERIC_ERROR;
839     }
840   }
841   return err;
842 }
843 
844 int32_t
_write(NPP npp,NPStream * pstream,int32_t len,void * buffer)845 _write(NPP npp, NPStream *pstream, int32_t len, void *buffer)
846 {
847   if (!NS_IsMainThread()) {
848     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_write called from the wrong thread\n"));
849     return 0;
850   }
851   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
852                  ("NPN_Write: npp=%p, url=%s, len=%d, buffer=%s\n", (void*)npp,
853                   pstream->url, len, (char*)buffer));
854 
855   // negative return indicates failure to the plugin
856   if (!npp)
857     return -1;
858 
859   PluginDestructionGuard guard(npp);
860 
861   nsNPAPIStreamWrapper* wrapper = static_cast<nsNPAPIStreamWrapper*>(pstream->ndata);
862   if (!wrapper) {
863     return -1;
864   }
865 
866   nsIOutputStream* stream = wrapper->GetOutputStream();
867   if (!stream) {
868     return -1;
869   }
870 
871   uint32_t count = 0;
872   nsresult rv = stream->Write((char *)buffer, len, &count);
873 
874   if (NS_FAILED(rv)) {
875     return -1;
876   }
877 
878   return (int32_t)count;
879 }
880 
881 NPError
_destroystream(NPP npp,NPStream * pstream,NPError reason)882 _destroystream(NPP npp, NPStream *pstream, NPError reason)
883 {
884   if (!NS_IsMainThread()) {
885     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_destroystream called from the wrong thread\n"));
886     return NPERR_INVALID_PARAM;
887   }
888   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
889                  ("NPN_DestroyStream: npp=%p, url=%s, reason=%d\n", (void*)npp,
890                   pstream->url, (int)reason));
891 
892   if (!npp)
893     return NPERR_INVALID_INSTANCE_ERROR;
894 
895   PluginDestructionGuard guard(npp);
896 
897   nsNPAPIStreamWrapper *streamWrapper = static_cast<nsNPAPIStreamWrapper*>(pstream->ndata);
898   if (!streamWrapper) {
899     return NPERR_INVALID_PARAM;
900   }
901 
902   nsNPAPIPluginStreamListener *listener = streamWrapper->GetStreamListener();
903   if (listener) {
904     // This type of stream is going from the browser to the plugin. It's either the
905     // initial src/data stream or another stream resulting from NPN_GetURL* or
906     // NPN_PostURL*.
907     //
908     // Calling OnStopBinding on the listener may cause it to be deleted due to the
909     // releasing of its last references.
910     listener->OnStopBinding(nullptr, NS_BINDING_ABORTED);
911   } else {
912     // This type of stream (NPStream) was created via NPN_NewStream. The plugin holds
913     // the reference until it is to be deleted here. Deleting the wrapper will
914     // release the wrapped nsIOutputStream.
915     //
916     // The NPStream the plugin references should always be a sub-object of its own
917     // 'ndata', which is our nsNPAPIStramWrapper. See bug 548441.
918     NS_ASSERTION((char*)streamWrapper <= (char*)pstream &&
919                  ((char*)pstream) + sizeof(*pstream)
920                      <= ((char*)streamWrapper) + sizeof(*streamWrapper),
921                  "pstream is not a subobject of wrapper");
922     delete streamWrapper;
923   }
924 
925   // 'listener' and/or 'streamWrapper' may be invalid (deleted) at this point. Don't
926   // touch them again!
927 
928   return NPERR_NO_ERROR;
929 }
930 
931 void
_status(NPP npp,const char * message)932 _status(NPP npp, const char *message)
933 {
934   // NPN_Status is no longer supported.
935 }
936 
937 void
_memfree(void * ptr)938 _memfree (void *ptr)
939 {
940   if (!NS_IsMainThread()) {
941     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_memfree called from the wrong thread\n"));
942   }
943   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemFree: ptr=%p\n", ptr));
944 
945   if (ptr)
946     free(ptr);
947 }
948 
949 uint32_t
_memflush(uint32_t size)950 _memflush(uint32_t size)
951 {
952   if (!NS_IsMainThread()) {
953     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_memflush called from the wrong thread\n"));
954   }
955   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemFlush: size=%d\n", size));
956 
957   nsMemory::HeapMinimize(true);
958   return 0;
959 }
960 
961 void
_reloadplugins(NPBool reloadPages)962 _reloadplugins(NPBool reloadPages)
963 {
964   if (!NS_IsMainThread()) {
965     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_reloadplugins called from the wrong thread\n"));
966     return;
967   }
968   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
969                  ("NPN_ReloadPlugins: reloadPages=%d\n", reloadPages));
970 
971   nsCOMPtr<nsIPluginHost> pluginHost(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
972   if (!pluginHost)
973     return;
974 
975   pluginHost->ReloadPlugins();
976 }
977 
978 void
_invalidaterect(NPP npp,NPRect * invalidRect)979 _invalidaterect(NPP npp, NPRect *invalidRect)
980 {
981   if (!NS_IsMainThread()) {
982     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invalidaterect called from the wrong thread\n"));
983     return;
984   }
985   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
986                  ("NPN_InvalidateRect: npp=%p, top=%d, left=%d, bottom=%d, "
987                   "right=%d\n", (void *)npp, invalidRect->top,
988                   invalidRect->left, invalidRect->bottom, invalidRect->right));
989 
990   if (!npp || !npp->ndata) {
991     NS_WARNING("_invalidaterect: npp or npp->ndata == 0");
992     return;
993   }
994 
995   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata;
996 
997   PluginDestructionGuard guard(inst);
998 
999   inst->InvalidateRect((NPRect *)invalidRect);
1000 }
1001 
1002 void
_invalidateregion(NPP npp,NPRegion invalidRegion)1003 _invalidateregion(NPP npp, NPRegion invalidRegion)
1004 {
1005   if (!NS_IsMainThread()) {
1006     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invalidateregion called from the wrong thread\n"));
1007     return;
1008   }
1009   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
1010                  ("NPN_InvalidateRegion: npp=%p, region=%p\n", (void*)npp,
1011                   (void*)invalidRegion));
1012 
1013   if (!npp || !npp->ndata) {
1014     NS_WARNING("_invalidateregion: npp or npp->ndata == 0");
1015     return;
1016   }
1017 
1018   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata;
1019 
1020   PluginDestructionGuard guard(inst);
1021 
1022   inst->InvalidateRegion((NPRegion)invalidRegion);
1023 }
1024 
1025 void
_forceredraw(NPP npp)1026 _forceredraw(NPP npp)
1027 {
1028 }
1029 
1030 NPObject*
_getwindowobject(NPP npp)1031 _getwindowobject(NPP npp)
1032 {
1033   if (!NS_IsMainThread()) {
1034     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getwindowobject called from the wrong thread\n"));
1035     return nullptr;
1036   }
1037 
1038   // The window want to return here is the outer window, *not* the inner (since
1039   // we don't know what the plugin will do with it).
1040   nsIDocument* doc = GetDocumentFromNPP(npp);
1041   NS_ENSURE_TRUE(doc, nullptr);
1042   nsCOMPtr<nsPIDOMWindowOuter> outer = doc->GetWindow();
1043   NS_ENSURE_TRUE(outer, nullptr);
1044 
1045   JS::Rooted<JSObject*> global(dom::RootingCx(),
1046                                nsGlobalWindow::Cast(outer)->GetGlobalJSObject());
1047   return nsJSObjWrapper::GetNewOrUsed(npp, global);
1048 }
1049 
1050 NPObject*
_getpluginelement(NPP npp)1051 _getpluginelement(NPP npp)
1052 {
1053   if (!NS_IsMainThread()) {
1054     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getpluginelement called from the wrong thread\n"));
1055     return nullptr;
1056   }
1057 
1058   nsNPAPIPluginInstance* inst = static_cast<nsNPAPIPluginInstance*>(npp->ndata);
1059   if (!inst)
1060     return nullptr;
1061 
1062   nsCOMPtr<nsIDOMElement> element;
1063   inst->GetDOMElement(getter_AddRefs(element));
1064 
1065   if (!element)
1066     return nullptr;
1067 
1068   nsIDocument *doc = GetDocumentFromNPP(npp);
1069   if (NS_WARN_IF(!doc)) {
1070     return nullptr;
1071   }
1072 
1073   dom::AutoJSAPI jsapi;
1074   if (NS_WARN_IF(!jsapi.Init(doc->GetInnerWindow()))) {
1075     return nullptr;
1076   }
1077   JSContext* cx = jsapi.cx();
1078 
1079   nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID()));
1080   NS_ENSURE_TRUE(xpc, nullptr);
1081 
1082   JS::RootedObject obj(cx);
1083   xpc->WrapNative(cx, ::JS::CurrentGlobalOrNull(cx), element,
1084                   NS_GET_IID(nsIDOMElement), obj.address());
1085   NS_ENSURE_TRUE(obj, nullptr);
1086 
1087   return nsJSObjWrapper::GetNewOrUsed(npp, obj);
1088 }
1089 
1090 NPIdentifier
_getstringidentifier(const NPUTF8 * name)1091 _getstringidentifier(const NPUTF8* name)
1092 {
1093   if (!name) {
1094     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getstringidentifier: passed null name"));
1095     return nullptr;
1096   }
1097   if (!NS_IsMainThread()) {
1098     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getstringidentifier called from the wrong thread\n"));
1099   }
1100 
1101   AutoSafeJSContext cx;
1102   return doGetIdentifier(cx, name);
1103 }
1104 
1105 void
_getstringidentifiers(const NPUTF8 ** names,int32_t nameCount,NPIdentifier * identifiers)1106 _getstringidentifiers(const NPUTF8** names, int32_t nameCount,
1107                       NPIdentifier *identifiers)
1108 {
1109   if (!NS_IsMainThread()) {
1110     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getstringidentifiers called from the wrong thread\n"));
1111   }
1112 
1113   AutoSafeJSContext cx;
1114 
1115   for (int32_t i = 0; i < nameCount; ++i) {
1116     if (names[i]) {
1117       identifiers[i] = doGetIdentifier(cx, names[i]);
1118     } else {
1119       NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_getstringidentifiers: passed null name"));
1120       identifiers[i] = nullptr;
1121     }
1122   }
1123 }
1124 
1125 NPIdentifier
_getintidentifier(int32_t intid)1126 _getintidentifier(int32_t intid)
1127 {
1128   if (!NS_IsMainThread()) {
1129     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getstringidentifier called from the wrong thread\n"));
1130   }
1131   return IntToNPIdentifier(intid);
1132 }
1133 
1134 NPUTF8*
_utf8fromidentifier(NPIdentifier id)1135 _utf8fromidentifier(NPIdentifier id)
1136 {
1137   if (!NS_IsMainThread()) {
1138     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_utf8fromidentifier called from the wrong thread\n"));
1139   }
1140   if (!id)
1141     return nullptr;
1142 
1143   if (!NPIdentifierIsString(id)) {
1144     return nullptr;
1145   }
1146 
1147   JSString *str = NPIdentifierToString(id);
1148   nsAutoString autoStr;
1149   AssignJSFlatString(autoStr, JS_ASSERT_STRING_IS_FLAT(str));
1150 
1151   return ToNewUTF8String(autoStr);
1152 }
1153 
1154 int32_t
_intfromidentifier(NPIdentifier id)1155 _intfromidentifier(NPIdentifier id)
1156 {
1157   if (!NS_IsMainThread()) {
1158     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_intfromidentifier called from the wrong thread\n"));
1159   }
1160 
1161   if (!NPIdentifierIsInt(id)) {
1162     return INT32_MIN;
1163   }
1164 
1165   return NPIdentifierToInt(id);
1166 }
1167 
1168 bool
_identifierisstring(NPIdentifier id)1169 _identifierisstring(NPIdentifier id)
1170 {
1171   if (!NS_IsMainThread()) {
1172     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_identifierisstring called from the wrong thread\n"));
1173   }
1174 
1175   return NPIdentifierIsString(id);
1176 }
1177 
1178 NPObject*
_createobject(NPP npp,NPClass * aClass)1179 _createobject(NPP npp, NPClass* aClass)
1180 {
1181   if (!NS_IsMainThread()) {
1182     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_createobject called from the wrong thread\n"));
1183     return nullptr;
1184   }
1185   if (!npp) {
1186     NS_ERROR("Null npp passed to _createobject()!");
1187 
1188     return nullptr;
1189   }
1190 
1191   PluginDestructionGuard guard(npp);
1192 
1193   if (!aClass) {
1194     NS_ERROR("Null class passed to _createobject()!");
1195 
1196     return nullptr;
1197   }
1198 
1199   NPPAutoPusher nppPusher(npp);
1200 
1201   NPObject *npobj;
1202 
1203   if (aClass->allocate) {
1204     npobj = aClass->allocate(npp, aClass);
1205   } else {
1206     npobj = (NPObject *)PR_Malloc(sizeof(NPObject));
1207   }
1208 
1209   if (npobj) {
1210     npobj->_class = aClass;
1211     npobj->referenceCount = 1;
1212     NS_LOG_ADDREF(npobj, 1, "BrowserNPObject", sizeof(NPObject));
1213   }
1214 
1215   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1216                  ("Created NPObject %p, NPClass %p\n", npobj, aClass));
1217 
1218   return npobj;
1219 }
1220 
1221 NPObject*
_retainobject(NPObject * npobj)1222 _retainobject(NPObject* npobj)
1223 {
1224   if (!NS_IsMainThread()) {
1225     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_retainobject called from the wrong thread\n"));
1226   }
1227   if (npobj) {
1228 #ifdef NS_BUILD_REFCNT_LOGGING
1229     int32_t refCnt =
1230 #endif
1231       PR_ATOMIC_INCREMENT((int32_t*)&npobj->referenceCount);
1232     NS_LOG_ADDREF(npobj, refCnt, "BrowserNPObject", sizeof(NPObject));
1233   }
1234 
1235   return npobj;
1236 }
1237 
1238 void
_releaseobject(NPObject * npobj)1239 _releaseobject(NPObject* npobj)
1240 {
1241   // If nothing is passed, just return, even if we're on the wrong thread.
1242   if (!npobj) {
1243     return;
1244   }
1245 
1246   // THIS IS A KNOWN LEAK. SEE BUG 1221448.
1247   // If releaseobject is called off the main thread and we have a valid pointer,
1248   // we at least know it was created on the main thread (see _createobject
1249   // implementation). However, forwarding the deletion back to the main thread
1250   // without careful checking could cause bad memory management races. So, for
1251   // now, we leak by warning and then just returning early. But it should fix
1252   // java 7 crashes.
1253   if (!NS_IsMainThread()) {
1254     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_releaseobject called from the wrong thread\n"));
1255     return;
1256   }
1257 
1258   int32_t refCnt = PR_ATOMIC_DECREMENT((int32_t*)&npobj->referenceCount);
1259   NS_LOG_RELEASE(npobj, refCnt, "BrowserNPObject");
1260 
1261   if (refCnt == 0) {
1262     nsNPObjWrapper::OnDestroy(npobj);
1263 
1264     NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1265                    ("Deleting NPObject %p, refcount hit 0\n", npobj));
1266 
1267     if (npobj->_class && npobj->_class->deallocate) {
1268       npobj->_class->deallocate(npobj);
1269     } else {
1270       PR_Free(npobj);
1271     }
1272   }
1273 }
1274 
1275 bool
_invoke(NPP npp,NPObject * npobj,NPIdentifier method,const NPVariant * args,uint32_t argCount,NPVariant * result)1276 _invoke(NPP npp, NPObject* npobj, NPIdentifier method, const NPVariant *args,
1277         uint32_t argCount, NPVariant *result)
1278 {
1279   if (!NS_IsMainThread()) {
1280     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invoke called from the wrong thread\n"));
1281     return false;
1282   }
1283   if (!npp || !npobj || !npobj->_class || !npobj->_class->invoke)
1284     return false;
1285 
1286   PluginDestructionGuard guard(npp);
1287 
1288   NPPExceptionAutoHolder nppExceptionHolder;
1289   NPPAutoPusher nppPusher(npp);
1290 
1291   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1292                  ("NPN_Invoke(npp %p, npobj %p, method %p, args %d\n", npp,
1293                   npobj, method, argCount));
1294 
1295   return npobj->_class->invoke(npobj, method, args, argCount, result);
1296 }
1297 
1298 bool
_invokeDefault(NPP npp,NPObject * npobj,const NPVariant * args,uint32_t argCount,NPVariant * result)1299 _invokeDefault(NPP npp, NPObject* npobj, const NPVariant *args,
1300                uint32_t argCount, NPVariant *result)
1301 {
1302   if (!NS_IsMainThread()) {
1303     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_invokedefault called from the wrong thread\n"));
1304     return false;
1305   }
1306   if (!npp || !npobj || !npobj->_class || !npobj->_class->invokeDefault)
1307     return false;
1308 
1309   NPPExceptionAutoHolder nppExceptionHolder;
1310   NPPAutoPusher nppPusher(npp);
1311 
1312   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1313                  ("NPN_InvokeDefault(npp %p, npobj %p, args %d\n", npp,
1314                   npobj, argCount));
1315 
1316   return npobj->_class->invokeDefault(npobj, args, argCount, result);
1317 }
1318 
1319 bool
_evaluate(NPP npp,NPObject * npobj,NPString * script,NPVariant * result)1320 _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result)
1321 {
1322   if (!NS_IsMainThread()) {
1323     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_evaluate called from the wrong thread\n"));
1324     return false;
1325   }
1326   if (!npp)
1327     return false;
1328 
1329   NPPAutoPusher nppPusher(npp);
1330 
1331   nsIDocument *doc = GetDocumentFromNPP(npp);
1332   NS_ENSURE_TRUE(doc, false);
1333 
1334   nsGlobalWindow* win = nsGlobalWindow::Cast(doc->GetInnerWindow());
1335   if (NS_WARN_IF(!win || !win->FastGetGlobalJSObject())) {
1336     return false;
1337   }
1338 
1339   nsAutoMicroTask mt;
1340   dom::AutoEntryScript aes(win, "NPAPI NPN_evaluate");
1341   JSContext* cx = aes.cx();
1342 
1343   JS::Rooted<JSObject*> obj(cx, nsNPObjWrapper::GetNewOrUsed(npp, cx, npobj));
1344 
1345   if (!obj) {
1346     return false;
1347   }
1348 
1349   obj = js::ToWindowIfWindowProxy(obj);
1350   MOZ_ASSERT(obj, "ToWindowIfWindowProxy should never return null");
1351 
1352   if (result) {
1353     // Initialize the out param to void
1354     VOID_TO_NPVARIANT(*result);
1355   }
1356 
1357   if (!script || !script->UTF8Length || !script->UTF8Characters) {
1358     // Nothing to evaluate.
1359 
1360     return true;
1361   }
1362 
1363   NS_ConvertUTF8toUTF16 utf16script(script->UTF8Characters,
1364                                     script->UTF8Length);
1365 
1366   nsIPrincipal *principal = doc->NodePrincipal();
1367 
1368   nsAutoCString specStr;
1369   const char *spec;
1370 
1371   nsCOMPtr<nsIURI> uri;
1372   principal->GetURI(getter_AddRefs(uri));
1373 
1374   if (uri) {
1375     uri->GetSpec(specStr);
1376     spec = specStr.get();
1377   } else {
1378     // No URI in a principal means it's the system principal. If the
1379     // document URI is a chrome:// URI, pass that in as the URI of the
1380     // script, else pass in null for the filename as there's no way to
1381     // know where this document really came from. Passing in null here
1382     // also means that the script gets treated by XPConnect as if it
1383     // needs additional protection, which is what we want for unknown
1384     // chrome code anyways.
1385 
1386     uri = doc->GetDocumentURI();
1387     bool isChrome = false;
1388 
1389     if (uri && NS_SUCCEEDED(uri->SchemeIs("chrome", &isChrome)) && isChrome) {
1390       uri->GetSpec(specStr);
1391       spec = specStr.get();
1392     } else {
1393       spec = nullptr;
1394     }
1395   }
1396 
1397   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1398                  ("NPN_Evaluate(npp %p, npobj %p, script <<<%s>>>) called\n",
1399                   npp, npobj, script->UTF8Characters));
1400 
1401   JS::CompileOptions options(cx);
1402   options.setFileAndLine(spec, 0)
1403          .setVersion(JSVERSION_DEFAULT);
1404   JS::Rooted<JS::Value> rval(cx);
1405   nsJSUtils::EvaluateOptions evalOptions(cx);
1406   if (obj != js::GetGlobalForObjectCrossCompartment(obj) &&
1407       !evalOptions.scopeChain.append(obj)) {
1408     return false;
1409   }
1410   obj = js::GetGlobalForObjectCrossCompartment(obj);
1411   nsresult rv = nsJSUtils::EvaluateString(cx, utf16script, obj, options,
1412                                           evalOptions, &rval);
1413 
1414   return NS_SUCCEEDED(rv) &&
1415          (!result || JSValToNPVariant(npp, cx, rval, result));
1416 }
1417 
1418 bool
_getproperty(NPP npp,NPObject * npobj,NPIdentifier property,NPVariant * result)1419 _getproperty(NPP npp, NPObject* npobj, NPIdentifier property,
1420              NPVariant *result)
1421 {
1422   if (!NS_IsMainThread()) {
1423     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getproperty called from the wrong thread\n"));
1424     return false;
1425   }
1426   if (!npp || !npobj || !npobj->_class || !npobj->_class->getProperty)
1427     return false;
1428 
1429   NPPExceptionAutoHolder nppExceptionHolder;
1430   NPPAutoPusher nppPusher(npp);
1431 
1432   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1433                  ("NPN_GetProperty(npp %p, npobj %p, property %p) called\n",
1434                   npp, npobj, property));
1435 
1436   if (!npobj->_class->getProperty(npobj, property, result))
1437     return false;
1438 
1439   // If a Java plugin tries to get the document.URL or document.documentURI
1440   // property from us, don't pass back a value that Java won't be able to
1441   // understand -- one that will make the URL(String) constructor throw a
1442   // MalformedURL exception.  Passing such a value causes Java Plugin2 to
1443   // crash (to throw a RuntimeException in Plugin2Manager.getDocumentBase()).
1444   // Also don't pass back a value that Java is likely to mishandle.
1445 
1446   nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*) npp->ndata;
1447   if (!inst)
1448     return false;
1449   nsNPAPIPlugin* plugin = inst->GetPlugin();
1450   if (!plugin)
1451     return false;
1452   RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
1453   nsPluginTag* pluginTag = host->TagForPlugin(plugin);
1454   if (!pluginTag->mIsJavaPlugin)
1455     return true;
1456 
1457   if (!NPVARIANT_IS_STRING(*result))
1458     return true;
1459 
1460   NPUTF8* propertyName = _utf8fromidentifier(property);
1461   if (!propertyName)
1462     return true;
1463   bool notURL =
1464     (PL_strcasecmp(propertyName, "URL") &&
1465      PL_strcasecmp(propertyName, "documentURI"));
1466   _memfree(propertyName);
1467   if (notURL)
1468     return true;
1469 
1470   NPObject* window_obj = _getwindowobject(npp);
1471   if (!window_obj)
1472     return true;
1473 
1474   NPVariant doc_v;
1475   NPObject* document_obj = nullptr;
1476   NPIdentifier doc_id = _getstringidentifier("document");
1477   bool ok = npobj->_class->getProperty(window_obj, doc_id, &doc_v);
1478   _releaseobject(window_obj);
1479   if (ok) {
1480     if (NPVARIANT_IS_OBJECT(doc_v)) {
1481       document_obj = NPVARIANT_TO_OBJECT(doc_v);
1482     } else {
1483       _releasevariantvalue(&doc_v);
1484       return true;
1485     }
1486   } else {
1487     return true;
1488   }
1489   _releaseobject(document_obj);
1490   if (document_obj != npobj)
1491     return true;
1492 
1493   NPString urlnp = NPVARIANT_TO_STRING(*result);
1494   nsXPIDLCString url;
1495   url.Assign(urlnp.UTF8Characters, urlnp.UTF8Length);
1496 
1497   bool javaCompatible = false;
1498   if (NS_FAILED(NS_CheckIsJavaCompatibleURLString(url, &javaCompatible)))
1499     javaCompatible = false;
1500   if (javaCompatible)
1501     return true;
1502 
1503   // If Java won't be able to interpret the original value of document.URL or
1504   // document.documentURI, or is likely to mishandle it, pass back something
1505   // that Java will understand but won't be able to use to access the network,
1506   // and for which same-origin checks will always fail.
1507 
1508   if (inst->mFakeURL.IsVoid()) {
1509     // Abort (do an error return) if NS_MakeRandomInvalidURLString() fails.
1510     if (NS_FAILED(NS_MakeRandomInvalidURLString(inst->mFakeURL))) {
1511       _releasevariantvalue(result);
1512       return false;
1513     }
1514   }
1515 
1516   _releasevariantvalue(result);
1517   char* fakeurl = (char *) _memalloc(inst->mFakeURL.Length() + 1);
1518   strcpy(fakeurl, inst->mFakeURL);
1519   STRINGZ_TO_NPVARIANT(fakeurl, *result);
1520 
1521   return true;
1522 }
1523 
1524 bool
_setproperty(NPP npp,NPObject * npobj,NPIdentifier property,const NPVariant * value)1525 _setproperty(NPP npp, NPObject* npobj, NPIdentifier property,
1526              const NPVariant *value)
1527 {
1528   if (!NS_IsMainThread()) {
1529     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_setproperty called from the wrong thread\n"));
1530     return false;
1531   }
1532   if (!npp || !npobj || !npobj->_class || !npobj->_class->setProperty)
1533     return false;
1534 
1535   NPPExceptionAutoHolder nppExceptionHolder;
1536   NPPAutoPusher nppPusher(npp);
1537 
1538   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1539                  ("NPN_SetProperty(npp %p, npobj %p, property %p) called\n",
1540                   npp, npobj, property));
1541 
1542   return npobj->_class->setProperty(npobj, property, value);
1543 }
1544 
1545 bool
_removeproperty(NPP npp,NPObject * npobj,NPIdentifier property)1546 _removeproperty(NPP npp, NPObject* npobj, NPIdentifier property)
1547 {
1548   if (!NS_IsMainThread()) {
1549     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_removeproperty called from the wrong thread\n"));
1550     return false;
1551   }
1552   if (!npp || !npobj || !npobj->_class || !npobj->_class->removeProperty)
1553     return false;
1554 
1555   NPPExceptionAutoHolder nppExceptionHolder;
1556   NPPAutoPusher nppPusher(npp);
1557 
1558   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1559                  ("NPN_RemoveProperty(npp %p, npobj %p, property %p) called\n",
1560                   npp, npobj, property));
1561 
1562   return npobj->_class->removeProperty(npobj, property);
1563 }
1564 
1565 bool
_hasproperty(NPP npp,NPObject * npobj,NPIdentifier propertyName)1566 _hasproperty(NPP npp, NPObject* npobj, NPIdentifier propertyName)
1567 {
1568   if (!NS_IsMainThread()) {
1569     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_hasproperty called from the wrong thread\n"));
1570     return false;
1571   }
1572   if (!npp || !npobj || !npobj->_class || !npobj->_class->hasProperty)
1573     return false;
1574 
1575   NPPExceptionAutoHolder nppExceptionHolder;
1576   NPPAutoPusher nppPusher(npp);
1577 
1578   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1579                  ("NPN_HasProperty(npp %p, npobj %p, property %p) called\n",
1580                   npp, npobj, propertyName));
1581 
1582   return npobj->_class->hasProperty(npobj, propertyName);
1583 }
1584 
1585 bool
_hasmethod(NPP npp,NPObject * npobj,NPIdentifier methodName)1586 _hasmethod(NPP npp, NPObject* npobj, NPIdentifier methodName)
1587 {
1588   if (!NS_IsMainThread()) {
1589     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_hasmethod called from the wrong thread\n"));
1590     return false;
1591   }
1592   if (!npp || !npobj || !npobj->_class || !npobj->_class->hasMethod)
1593     return false;
1594 
1595   NPPExceptionAutoHolder nppExceptionHolder;
1596   NPPAutoPusher nppPusher(npp);
1597 
1598   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1599                  ("NPN_HasMethod(npp %p, npobj %p, property %p) called\n",
1600                   npp, npobj, methodName));
1601 
1602   return npobj->_class->hasMethod(npobj, methodName);
1603 }
1604 
1605 bool
_enumerate(NPP npp,NPObject * npobj,NPIdentifier ** identifier,uint32_t * count)1606 _enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier,
1607            uint32_t *count)
1608 {
1609   if (!NS_IsMainThread()) {
1610     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_enumerate called from the wrong thread\n"));
1611     return false;
1612   }
1613   if (!npp || !npobj || !npobj->_class)
1614     return false;
1615 
1616   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
1617                  ("NPN_Enumerate(npp %p, npobj %p) called\n", npp, npobj));
1618 
1619   if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(npobj->_class) ||
1620       !npobj->_class->enumerate) {
1621     *identifier = 0;
1622     *count = 0;
1623     return true;
1624   }
1625 
1626   NPPExceptionAutoHolder nppExceptionHolder;
1627   NPPAutoPusher nppPusher(npp);
1628 
1629   return npobj->_class->enumerate(npobj, identifier, count);
1630 }
1631 
1632 bool
_construct(NPP npp,NPObject * npobj,const NPVariant * args,uint32_t argCount,NPVariant * result)1633 _construct(NPP npp, NPObject* npobj, const NPVariant *args,
1634                uint32_t argCount, NPVariant *result)
1635 {
1636   if (!NS_IsMainThread()) {
1637     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_construct called from the wrong thread\n"));
1638     return false;
1639   }
1640   if (!npp || !npobj || !npobj->_class ||
1641       !NP_CLASS_STRUCT_VERSION_HAS_CTOR(npobj->_class) ||
1642       !npobj->_class->construct) {
1643     return false;
1644   }
1645 
1646   NPPExceptionAutoHolder nppExceptionHolder;
1647   NPPAutoPusher nppPusher(npp);
1648 
1649   return npobj->_class->construct(npobj, args, argCount, result);
1650 }
1651 
1652 void
_releasevariantvalue(NPVariant * variant)1653 _releasevariantvalue(NPVariant* variant)
1654 {
1655   if (!NS_IsMainThread()) {
1656     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_releasevariantvalue called from the wrong thread\n"));
1657   }
1658   switch (variant->type) {
1659   case NPVariantType_Void :
1660   case NPVariantType_Null :
1661   case NPVariantType_Bool :
1662   case NPVariantType_Int32 :
1663   case NPVariantType_Double :
1664     break;
1665   case NPVariantType_String :
1666     {
1667       const NPString *s = &NPVARIANT_TO_STRING(*variant);
1668 
1669       if (s->UTF8Characters) {
1670 #if defined(MOZ_MEMORY_WINDOWS)
1671         if (malloc_usable_size((void *)s->UTF8Characters) != 0) {
1672           PR_Free((void *)s->UTF8Characters);
1673         } else {
1674           void *p = (void *)s->UTF8Characters;
1675           DWORD nheaps = 0;
1676           AutoTArray<HANDLE, 50> heaps;
1677           nheaps = GetProcessHeaps(0, heaps.Elements());
1678           heaps.AppendElements(nheaps);
1679           GetProcessHeaps(nheaps, heaps.Elements());
1680           for (DWORD i = 0; i < nheaps; i++) {
1681             if (InHeap(heaps[i], p)) {
1682               HeapFree(heaps[i], 0, p);
1683               break;
1684             }
1685           }
1686         }
1687 #else
1688         free((void *)s->UTF8Characters);
1689 #endif
1690       }
1691       break;
1692     }
1693   case NPVariantType_Object:
1694     {
1695       NPObject *npobj = NPVARIANT_TO_OBJECT(*variant);
1696 
1697       if (npobj)
1698         _releaseobject(npobj);
1699 
1700       break;
1701     }
1702   default:
1703     NS_ERROR("Unknown NPVariant type!");
1704   }
1705 
1706   VOID_TO_NPVARIANT(*variant);
1707 }
1708 
1709 void
_setexception(NPObject * npobj,const NPUTF8 * message)1710 _setexception(NPObject* npobj, const NPUTF8 *message)
1711 {
1712   if (!NS_IsMainThread()) {
1713     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_setexception called from the wrong thread\n"));
1714     return;
1715   }
1716 
1717   if (!message) return;
1718 
1719   if (gNPPException) {
1720     // If a plugin throws multiple exceptions, we'll only report the
1721     // last one for now.
1722     free(gNPPException);
1723   }
1724 
1725   gNPPException = strdup(message);
1726 }
1727 
1728 NPError
_getvalue(NPP npp,NPNVariable variable,void * result)1729 _getvalue(NPP npp, NPNVariable variable, void *result)
1730 {
1731   if (!NS_IsMainThread()) {
1732     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getvalue called from the wrong thread\n"));
1733     return NPERR_INVALID_PARAM;
1734   }
1735   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetValue: npp=%p, var=%d\n",
1736                                      (void*)npp, (int)variable));
1737 
1738   nsresult res;
1739 
1740   PluginDestructionGuard guard(npp);
1741 
1742   // Cast NPNVariable enum to int to avoid warnings about including switch
1743   // cases for android_npapi.h's non-standard ANPInterface values.
1744   switch (static_cast<int>(variable)) {
1745 
1746 #if defined(XP_UNIX) && !defined(XP_MACOSX)
1747   case NPNVxDisplay : {
1748 #if defined(MOZ_X11)
1749     if (npp) {
1750       nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata;
1751       bool windowless = false;
1752       inst->IsWindowless(&windowless);
1753       // The documentation on the types for many variables in NP(N|P)_GetValue
1754       // is vague.  Often boolean values are NPBool (1 byte), but
1755       // https://developer.mozilla.org/en/XEmbed_Extension_for_Mozilla_Plugins
1756       // treats NPPVpluginNeedsXEmbed as PRBool (int), and
1757       // on x86/32-bit, flash stores to this using |movl 0x1,&needsXEmbed|.
1758       // thus we can't use NPBool for needsXEmbed, or the three bytes above
1759       // it on the stack would get clobbered. so protect with the larger bool.
1760       int needsXEmbed = 0;
1761       if (!windowless) {
1762         res = inst->GetValueFromPlugin(NPPVpluginNeedsXEmbed, &needsXEmbed);
1763         // If the call returned an error code make sure we still use our default value.
1764         if (NS_FAILED(res)) {
1765           needsXEmbed = 0;
1766         }
1767       }
1768       if (windowless || needsXEmbed) {
1769         (*(Display **)result) = mozilla::DefaultXDisplay();
1770         return NPERR_NO_ERROR;
1771       }
1772     }
1773 #if (MOZ_WIDGET_GTK == 2)
1774     // adobe nppdf calls XtGetApplicationNameAndClass(display,
1775     // &instance, &class) we have to init Xt toolkit before get
1776     // XtDisplay just call gtk_xtbin_new(w,0) once
1777     static GtkWidget *gtkXtBinHolder = 0;
1778     if (!gtkXtBinHolder) {
1779       gtkXtBinHolder = gtk_xtbin_new(gdk_get_default_root_window(),0);
1780       // it crashes on destroy, let it leak
1781       // gtk_widget_destroy(gtkXtBinHolder);
1782     }
1783     (*(Display **)result) =  GTK_XTBIN(gtkXtBinHolder)->xtdisplay;
1784     return NPERR_NO_ERROR;
1785 #endif
1786 #endif
1787     return NPERR_GENERIC_ERROR;
1788   }
1789 
1790   case NPNVxtAppContext:
1791     return NPERR_GENERIC_ERROR;
1792 #endif
1793 
1794 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
1795   case NPNVnetscapeWindow: {
1796     if (!npp || !npp->ndata)
1797       return NPERR_INVALID_INSTANCE_ERROR;
1798 
1799     nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata;
1800 
1801     RefPtr<nsPluginInstanceOwner> owner = inst->GetOwner();
1802     NS_ENSURE_TRUE(owner, NPERR_NO_ERROR);
1803 
1804     if (NS_SUCCEEDED(owner->GetNetscapeWindow(result))) {
1805       return NPERR_NO_ERROR;
1806     }
1807     return NPERR_GENERIC_ERROR;
1808   }
1809 #endif
1810 
1811   case NPNVjavascriptEnabledBool: {
1812     *(NPBool*)result = false;
1813     bool js = false;
1814     res = Preferences::GetBool("javascript.enabled", &js);
1815     if (NS_SUCCEEDED(res)) {
1816       *(NPBool*)result = js;
1817     }
1818     return NPERR_NO_ERROR;
1819   }
1820 
1821   case NPNVasdEnabledBool:
1822     *(NPBool*)result = false;
1823     return NPERR_NO_ERROR;
1824 
1825   case NPNVisOfflineBool: {
1826     bool offline = false;
1827     nsCOMPtr<nsIIOService> ioservice =
1828       do_GetService(NS_IOSERVICE_CONTRACTID, &res);
1829     if (NS_SUCCEEDED(res))
1830       res = ioservice->GetOffline(&offline);
1831     if (NS_FAILED(res))
1832       return NPERR_GENERIC_ERROR;
1833 
1834     *(NPBool*)result = offline;
1835     return NPERR_NO_ERROR;
1836   }
1837 
1838   case NPNVToolkit: {
1839 #ifdef MOZ_WIDGET_GTK
1840     *((NPNToolkitType*)result) = NPNVGtk2;
1841 #endif
1842 
1843     if (*(NPNToolkitType*)result)
1844         return NPERR_NO_ERROR;
1845 
1846     return NPERR_GENERIC_ERROR;
1847   }
1848 
1849   case NPNVSupportsXEmbedBool: {
1850 #ifdef MOZ_WIDGET_GTK
1851     *(NPBool*)result = true;
1852 #else
1853     *(NPBool*)result = false;
1854 #endif
1855     return NPERR_NO_ERROR;
1856   }
1857 
1858   case NPNVWindowNPObject: {
1859     *(NPObject **)result = _getwindowobject(npp);
1860 
1861     return *(NPObject **)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
1862   }
1863 
1864   case NPNVPluginElementNPObject: {
1865     *(NPObject **)result = _getpluginelement(npp);
1866 
1867     return *(NPObject **)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
1868   }
1869 
1870   case NPNVSupportsWindowless: {
1871 #if defined(XP_WIN) || defined(XP_MACOSX) || \
1872     (defined(MOZ_X11) && defined(MOZ_WIDGET_GTK))
1873     *(NPBool*)result = true;
1874 #else
1875     *(NPBool*)result = false;
1876 #endif
1877     return NPERR_NO_ERROR;
1878   }
1879 
1880   case NPNVprivateModeBool: {
1881     bool privacy;
1882     nsNPAPIPluginInstance *inst = static_cast<nsNPAPIPluginInstance*>(npp->ndata);
1883     if (!inst)
1884       return NPERR_GENERIC_ERROR;
1885 
1886     nsresult rv = inst->IsPrivateBrowsing(&privacy);
1887     if (NS_FAILED(rv))
1888       return NPERR_GENERIC_ERROR;
1889     *(NPBool*)result = (NPBool)privacy;
1890     return NPERR_NO_ERROR;
1891   }
1892 
1893   case NPNVdocumentOrigin: {
1894     nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)npp->ndata;
1895     if (!inst) {
1896       return NPERR_GENERIC_ERROR;
1897     }
1898 
1899     nsCOMPtr<nsIDOMElement> element;
1900     inst->GetDOMElement(getter_AddRefs(element));
1901     if (!element) {
1902       return NPERR_GENERIC_ERROR;
1903     }
1904 
1905     nsCOMPtr<nsIContent> content(do_QueryInterface(element));
1906     if (!content) {
1907       return NPERR_GENERIC_ERROR;
1908     }
1909 
1910     nsIPrincipal* principal = content->NodePrincipal();
1911 
1912     nsAutoString utf16Origin;
1913     res = nsContentUtils::GetUTFOrigin(principal, utf16Origin);
1914     if (NS_FAILED(res)) {
1915       return NPERR_GENERIC_ERROR;
1916     }
1917 
1918     nsCOMPtr<nsIIDNService> idnService = do_GetService(NS_IDNSERVICE_CONTRACTID);
1919     if (!idnService) {
1920       return NPERR_GENERIC_ERROR;
1921     }
1922 
1923     // This is a bit messy: we convert to UTF-8 here, but then
1924     // nsIDNService::Normalize will convert back to UTF-16 for processing,
1925     // and back to UTF-8 again to return the result.
1926     // Alternative: perhaps we should add a NormalizeUTF16 version of the API,
1927     // and just convert to UTF-8 for the final return (resulting in one
1928     // encoding form conversion instead of three).
1929     NS_ConvertUTF16toUTF8 utf8Origin(utf16Origin);
1930     nsAutoCString normalizedUTF8Origin;
1931     res = idnService->Normalize(utf8Origin, normalizedUTF8Origin);
1932     if (NS_FAILED(res)) {
1933       return NPERR_GENERIC_ERROR;
1934     }
1935 
1936     *(char**)result = ToNewCString(normalizedUTF8Origin);
1937     return *(char**)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
1938   }
1939 
1940 #ifdef XP_MACOSX
1941   case NPNVpluginDrawingModel: {
1942     if (npp) {
1943       nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata;
1944       if (inst) {
1945         NPDrawingModel drawingModel;
1946         inst->GetDrawingModel((int32_t*)&drawingModel);
1947         *(NPDrawingModel*)result = drawingModel;
1948         return NPERR_NO_ERROR;
1949       }
1950     }
1951     return NPERR_GENERIC_ERROR;
1952   }
1953 
1954 #ifndef NP_NO_QUICKDRAW
1955   case NPNVsupportsQuickDrawBool: {
1956     *(NPBool*)result = false;
1957 
1958     return NPERR_NO_ERROR;
1959   }
1960 #endif
1961 
1962   case NPNVsupportsCoreGraphicsBool: {
1963     *(NPBool*)result = true;
1964 
1965     return NPERR_NO_ERROR;
1966   }
1967 
1968   case NPNVsupportsCoreAnimationBool: {
1969     *(NPBool*)result = true;
1970 
1971     return NPERR_NO_ERROR;
1972   }
1973 
1974   case NPNVsupportsInvalidatingCoreAnimationBool: {
1975     *(NPBool*)result = true;
1976 
1977     return NPERR_NO_ERROR;
1978   }
1979 
1980   case NPNVsupportsCompositingCoreAnimationPluginsBool: {
1981     *(NPBool*)result = PR_TRUE;
1982 
1983     return NPERR_NO_ERROR;
1984   }
1985 
1986 #ifndef NP_NO_CARBON
1987   case NPNVsupportsCarbonBool: {
1988     *(NPBool*)result = false;
1989 
1990     return NPERR_NO_ERROR;
1991   }
1992 #endif
1993   case NPNVsupportsCocoaBool: {
1994     *(NPBool*)result = true;
1995 
1996     return NPERR_NO_ERROR;
1997   }
1998 
1999   case NPNVsupportsUpdatedCocoaTextInputBool: {
2000     *(NPBool*)result = true;
2001     return NPERR_NO_ERROR;
2002   }
2003 #endif
2004 
2005 #if defined(XP_MACOSX) || defined(XP_WIN)
2006   case NPNVcontentsScaleFactor: {
2007     nsNPAPIPluginInstance *inst =
2008       (nsNPAPIPluginInstance *) (npp ? npp->ndata : nullptr);
2009     double scaleFactor = inst ? inst->GetContentsScaleFactor() : 1.0;
2010     *(double*)result = scaleFactor;
2011     return NPERR_NO_ERROR;
2012   }
2013 #endif
2014 
2015   case NPNVCSSZoomFactor: {
2016     nsNPAPIPluginInstance *inst =
2017       (nsNPAPIPluginInstance *) (npp ? npp->ndata : nullptr);
2018     double scaleFactor = inst ? inst->GetCSSZoomFactor() : 1.0;
2019     *(double*)result = scaleFactor;
2020     return NPERR_NO_ERROR;
2021   }
2022 
2023 #ifdef MOZ_WIDGET_ANDROID
2024     case kLogInterfaceV0_ANPGetValue: {
2025       LOG("get log interface");
2026       ANPLogInterfaceV0 *i = (ANPLogInterfaceV0 *) result;
2027       InitLogInterface(i);
2028       return NPERR_NO_ERROR;
2029     }
2030 
2031     case kBitmapInterfaceV0_ANPGetValue: {
2032       LOG("get bitmap interface");
2033       return NPERR_GENERIC_ERROR;
2034     }
2035 
2036     case kMatrixInterfaceV0_ANPGetValue: {
2037       LOG("get matrix interface");
2038       return NPERR_GENERIC_ERROR;
2039     }
2040 
2041     case kPathInterfaceV0_ANPGetValue: {
2042       LOG("get path interface");
2043       return NPERR_GENERIC_ERROR;
2044     }
2045 
2046     case kTypefaceInterfaceV0_ANPGetValue: {
2047       LOG("get typeface interface");
2048       ANPTypefaceInterfaceV0 *i = (ANPTypefaceInterfaceV0 *) result;
2049       InitTypeFaceInterface(i);
2050       return NPERR_NO_ERROR;
2051     }
2052 
2053     case kPaintInterfaceV0_ANPGetValue: {
2054       LOG("get paint interface");
2055       ANPPaintInterfaceV0 *i = (ANPPaintInterfaceV0 *) result;
2056       InitPaintInterface(i);
2057       return NPERR_NO_ERROR;
2058     }
2059 
2060     case kCanvasInterfaceV0_ANPGetValue: {
2061       LOG("get canvas interface");
2062       ANPCanvasInterfaceV0 *i = (ANPCanvasInterfaceV0 *) result;
2063       InitCanvasInterface(i);
2064       return NPERR_NO_ERROR;
2065     }
2066 
2067     case kWindowInterfaceV0_ANPGetValue: {
2068       LOG("get window interface");
2069       ANPWindowInterfaceV0 *i = (ANPWindowInterfaceV0 *) result;
2070       InitWindowInterface(i);
2071       return NPERR_NO_ERROR;
2072     }
2073 
2074     case kAudioTrackInterfaceV0_ANPGetValue: {
2075       LOG("get audio interface");
2076       ANPAudioTrackInterfaceV0 *i = (ANPAudioTrackInterfaceV0 *) result;
2077       InitAudioTrackInterfaceV0(i);
2078       return NPERR_NO_ERROR;
2079     }
2080 
2081     case kEventInterfaceV0_ANPGetValue: {
2082       LOG("get event interface");
2083       ANPEventInterfaceV0 *i = (ANPEventInterfaceV0 *) result;
2084       InitEventInterface(i);
2085       return NPERR_NO_ERROR;
2086     }
2087 
2088     case kSystemInterfaceV0_ANPGetValue: {
2089       LOG("get system interface");
2090       return NPERR_GENERIC_ERROR;
2091     }
2092 
2093     case kSurfaceInterfaceV0_ANPGetValue: {
2094       LOG("get surface interface");
2095       ANPSurfaceInterfaceV0 *i = (ANPSurfaceInterfaceV0 *) result;
2096       InitSurfaceInterface(i);
2097       return NPERR_NO_ERROR;
2098     }
2099 
2100     case kSupportedDrawingModel_ANPGetValue: {
2101       LOG("get supported drawing model");
2102       return NPERR_GENERIC_ERROR;
2103     }
2104 
2105     case kJavaContext_ANPGetValue: {
2106       LOG("get java context");
2107       auto ret = java::GeckoAppShell::GetContext();
2108       if (!ret)
2109         return NPERR_GENERIC_ERROR;
2110 
2111       *static_cast<jobject*>(result) = ret.Forget();
2112       return NPERR_NO_ERROR;
2113     }
2114 
2115     case kAudioTrackInterfaceV1_ANPGetValue: {
2116       LOG("get audio interface v1");
2117       ANPAudioTrackInterfaceV1 *i = (ANPAudioTrackInterfaceV1 *) result;
2118       InitAudioTrackInterfaceV1(i);
2119       return NPERR_NO_ERROR;
2120     }
2121 
2122     case kNativeWindowInterfaceV0_ANPGetValue: {
2123       LOG("get native window interface v0");
2124       ANPNativeWindowInterfaceV0* i = (ANPNativeWindowInterfaceV0 *) result;
2125       InitNativeWindowInterface(i);
2126       return NPERR_NO_ERROR;
2127     }
2128 
2129     case kOpenGLInterfaceV0_ANPGetValue: {
2130       LOG("get openGL interface");
2131       return NPERR_GENERIC_ERROR;
2132     }
2133 
2134     case kWindowInterfaceV1_ANPGetValue: {
2135       LOG("get Window interface V1");
2136       return NPERR_GENERIC_ERROR;
2137     }
2138 
2139     case kWindowInterfaceV2_ANPGetValue: {
2140       LOG("get Window interface V2");
2141       ANPWindowInterfaceV2 *i = (ANPWindowInterfaceV2 *) result;
2142       InitWindowInterfaceV2(i);
2143       return NPERR_NO_ERROR;
2144     }
2145 
2146     case kVideoInterfaceV0_ANPGetValue: {
2147       LOG("get video interface V0");
2148       return NPERR_GENERIC_ERROR;
2149     }
2150 
2151     case kVideoInterfaceV1_ANPGetValue: {
2152       LOG("get video interface V1");
2153       ANPVideoInterfaceV1 *i = (ANPVideoInterfaceV1*) result;
2154       InitVideoInterfaceV1(i);
2155       return NPERR_NO_ERROR;
2156     }
2157 
2158     case kSystemInterfaceV1_ANPGetValue: {
2159       LOG("get system interface v1");
2160       ANPSystemInterfaceV1* i = reinterpret_cast<ANPSystemInterfaceV1*>(result);
2161       InitSystemInterfaceV1(i);
2162       return NPERR_NO_ERROR;
2163     }
2164 
2165     case kSystemInterfaceV2_ANPGetValue: {
2166       LOG("get system interface v2");
2167       ANPSystemInterfaceV2* i = reinterpret_cast<ANPSystemInterfaceV2*>(result);
2168       InitSystemInterfaceV2(i);
2169       return NPERR_NO_ERROR;
2170     }
2171 #endif
2172 
2173   // we no longer hand out any XPCOM objects
2174   case NPNVDOMElement:
2175   case NPNVDOMWindow:
2176   case NPNVserviceManager:
2177     // old XPCOM objects, no longer supported, but null out the out
2178     // param to avoid crashing plugins that still try to use this.
2179     *(nsISupports**)result = nullptr;
2180     MOZ_FALLTHROUGH;
2181 
2182   default:
2183     NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_getvalue unhandled get value: %d\n", variable));
2184     return NPERR_GENERIC_ERROR;
2185   }
2186 }
2187 
2188 NPError
_setvalue(NPP npp,NPPVariable variable,void * result)2189 _setvalue(NPP npp, NPPVariable variable, void *result)
2190 {
2191   if (!NS_IsMainThread()) {
2192     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_setvalue called from the wrong thread\n"));
2193     return NPERR_INVALID_PARAM;
2194   }
2195   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_SetValue: npp=%p, var=%d\n",
2196                                      (void*)npp, (int)variable));
2197 
2198   if (!npp)
2199     return NPERR_INVALID_INSTANCE_ERROR;
2200 
2201   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata;
2202 
2203   NS_ASSERTION(inst, "null instance");
2204 
2205   if (!inst)
2206     return NPERR_INVALID_INSTANCE_ERROR;
2207 
2208   PluginDestructionGuard guard(inst);
2209 
2210   // Cast NPNVariable enum to int to avoid warnings about including switch
2211   // cases for android_npapi.h's non-standard ANPInterface values.
2212   switch (static_cast<int>(variable)) {
2213 
2214     // we should keep backward compatibility with NPAPI where the
2215     // actual pointer value is checked rather than its content
2216     // when passing booleans
2217     case NPPVpluginWindowBool: {
2218 #ifdef XP_MACOSX
2219       // This setting doesn't apply to OS X (only to Windows and Unix/Linux).
2220       // See https://developer.mozilla.org/En/NPN_SetValue#section_5.  Return
2221       // NPERR_NO_ERROR here to conform to other browsers' behavior on OS X
2222       // (e.g. Safari and Opera).
2223       return NPERR_NO_ERROR;
2224 #else
2225       NPBool bWindowless = (result == nullptr);
2226       return inst->SetWindowless(bWindowless);
2227 #endif
2228     }
2229     case NPPVpluginTransparentBool: {
2230       NPBool bTransparent = (result != nullptr);
2231       return inst->SetTransparent(bTransparent);
2232     }
2233 
2234     case NPPVjavascriptPushCallerBool: {
2235       return NPERR_NO_ERROR;
2236     }
2237 
2238     case NPPVpluginKeepLibraryInMemory: {
2239       NPBool bCached = (result != nullptr);
2240       inst->SetCached(bCached);
2241       return NPERR_NO_ERROR;
2242     }
2243 
2244     case NPPVpluginUsesDOMForCursorBool: {
2245       bool useDOMForCursor = (result != nullptr);
2246       return inst->SetUsesDOMForCursor(useDOMForCursor);
2247     }
2248 
2249     case NPPVpluginIsPlayingAudio: {
2250       bool isMuted = !result;
2251 
2252       nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*) npp->ndata;
2253       MOZ_ASSERT(inst);
2254 
2255       if (isMuted && !inst->HasAudioChannelAgent()) {
2256         return NPERR_NO_ERROR;
2257       }
2258 
2259       nsCOMPtr<nsIAudioChannelAgent> agent;
2260       nsresult rv = inst->GetOrCreateAudioChannelAgent(getter_AddRefs(agent));
2261       if (NS_WARN_IF(NS_FAILED(rv))) {
2262         return NPERR_NO_ERROR;
2263       }
2264 
2265       MOZ_ASSERT(agent);
2266 
2267       if (isMuted) {
2268         rv = agent->NotifyStoppedPlaying();
2269         if (NS_WARN_IF(NS_FAILED(rv))) {
2270           return NPERR_NO_ERROR;
2271         }
2272       } else {
2273 
2274         dom::AudioPlaybackConfig config;
2275         rv = agent->NotifyStartedPlaying(&config,
2276                                          dom::AudioChannelService::AudibleState::eAudible);
2277         if (NS_WARN_IF(NS_FAILED(rv))) {
2278           return NPERR_NO_ERROR;
2279         }
2280 
2281         rv = inst->WindowVolumeChanged(config.mVolume, config.mMuted);
2282         if (NS_WARN_IF(NS_FAILED(rv))) {
2283           return NPERR_NO_ERROR;
2284         }
2285 
2286         // Since we only support for muting now, the implementation of suspend
2287         // is equal to muting. Therefore, if we have already muted the plugin,
2288         // then we don't need to call WindowSuspendChanged() again.
2289         if (config.mMuted) {
2290           return NPERR_NO_ERROR;
2291         }
2292 
2293         rv = inst->WindowSuspendChanged(config.mSuspend);
2294         if (NS_WARN_IF(NS_FAILED(rv))) {
2295           return NPERR_NO_ERROR;
2296         }
2297       }
2298 
2299       return NPERR_NO_ERROR;
2300     }
2301 
2302 #ifndef MOZ_WIDGET_ANDROID
2303     // On android, their 'drawing model' uses the same constant!
2304     case NPPVpluginDrawingModel: {
2305       if (inst) {
2306         inst->SetDrawingModel((NPDrawingModel)NS_PTR_TO_INT32(result));
2307         return NPERR_NO_ERROR;
2308       }
2309       else {
2310         return NPERR_GENERIC_ERROR;
2311       }
2312     }
2313 #endif
2314 
2315 #ifdef XP_MACOSX
2316     case NPPVpluginEventModel: {
2317       if (inst) {
2318         inst->SetEventModel((NPEventModel)NS_PTR_TO_INT32(result));
2319         return NPERR_NO_ERROR;
2320       }
2321       else {
2322         return NPERR_GENERIC_ERROR;
2323       }
2324     }
2325 #endif
2326 #ifdef MOZ_WIDGET_ANDROID
2327   case kRequestDrawingModel_ANPSetValue:
2328     if (inst)
2329       inst->SetANPDrawingModel(NS_PTR_TO_INT32(result));
2330     return NPERR_NO_ERROR;
2331   case kAcceptEvents_ANPSetValue:
2332     return NPERR_NO_ERROR;
2333 #endif
2334     default:
2335       return NPERR_GENERIC_ERROR;
2336   }
2337 }
2338 
2339 NPError
_requestread(NPStream * pstream,NPByteRange * rangeList)2340 _requestread(NPStream *pstream, NPByteRange *rangeList)
2341 {
2342   if (!NS_IsMainThread()) {
2343     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_requestread called from the wrong thread\n"));
2344     return NPERR_INVALID_PARAM;
2345   }
2346   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_RequestRead: stream=%p\n",
2347                                      (void*)pstream));
2348 
2349 #ifdef PLUGIN_LOGGING
2350   for(NPByteRange * range = rangeList; range != nullptr; range = range->next)
2351     MOZ_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY,
2352     ("%i-%i", range->offset, range->offset + range->length - 1));
2353 
2354   MOZ_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY, ("\n\n"));
2355   PR_LogFlush();
2356 #endif
2357 
2358   if (!pstream || !rangeList || !pstream->ndata)
2359     return NPERR_INVALID_PARAM;
2360 
2361   nsNPAPIStreamWrapper* streamWrapper = static_cast<nsNPAPIStreamWrapper*>(pstream->ndata);
2362   nsNPAPIPluginStreamListener* streamlistener = streamWrapper->GetStreamListener();
2363   if (!streamlistener) {
2364     return NPERR_GENERIC_ERROR;
2365   }
2366 
2367   int32_t streamtype = NP_NORMAL;
2368 
2369   streamlistener->GetStreamType(&streamtype);
2370 
2371   if (streamtype != NP_SEEK)
2372     return NPERR_STREAM_NOT_SEEKABLE;
2373 
2374   if (!streamlistener->mStreamListenerPeer)
2375     return NPERR_GENERIC_ERROR;
2376 
2377   nsresult rv = streamlistener->mStreamListenerPeer->RequestRead((NPByteRange *)rangeList);
2378   if (NS_FAILED(rv))
2379     return NPERR_GENERIC_ERROR;
2380 
2381   return NPERR_NO_ERROR;
2382 }
2383 
2384 // Deprecated, only stubbed out
2385 void* /* OJI type: JRIEnv* */
_getJavaEnv()2386 _getJavaEnv()
2387 {
2388   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaEnv\n"));
2389   return nullptr;
2390 }
2391 
2392 const char *
_useragent(NPP npp)2393 _useragent(NPP npp)
2394 {
2395   if (!NS_IsMainThread()) {
2396     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_useragent called from the wrong thread\n"));
2397     return nullptr;
2398   }
2399   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_UserAgent: npp=%p\n", (void*)npp));
2400 
2401   nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
2402   nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
2403   if (!pluginHost) {
2404     return nullptr;
2405   }
2406 
2407   const char *retstr;
2408   nsresult rv = pluginHost->UserAgent(&retstr);
2409   if (NS_FAILED(rv))
2410     return nullptr;
2411 
2412   return retstr;
2413 }
2414 
2415 void *
_memalloc(uint32_t size)2416 _memalloc (uint32_t size)
2417 {
2418   if (!NS_IsMainThread()) {
2419     NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,("NPN_memalloc called from the wrong thread\n"));
2420   }
2421   NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY, ("NPN_MemAlloc: size=%d\n", size));
2422   return moz_xmalloc(size);
2423 }
2424 
2425 // Deprecated, only stubbed out
2426 void* /* OJI type: jref */
_getJavaPeer(NPP npp)2427 _getJavaPeer(NPP npp)
2428 {
2429   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaPeer: npp=%p\n", (void*)npp));
2430   return nullptr;
2431 }
2432 
2433 void
_pushpopupsenabledstate(NPP npp,NPBool enabled)2434 _pushpopupsenabledstate(NPP npp, NPBool enabled)
2435 {
2436   if (!NS_IsMainThread()) {
2437     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_pushpopupsenabledstate called from the wrong thread\n"));
2438     return;
2439   }
2440   nsNPAPIPluginInstance *inst = npp ? (nsNPAPIPluginInstance *)npp->ndata : nullptr;
2441   if (!inst)
2442     return;
2443 
2444   inst->PushPopupsEnabledState(enabled);
2445 }
2446 
2447 void
_poppopupsenabledstate(NPP npp)2448 _poppopupsenabledstate(NPP npp)
2449 {
2450   if (!NS_IsMainThread()) {
2451     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_poppopupsenabledstate called from the wrong thread\n"));
2452     return;
2453   }
2454   nsNPAPIPluginInstance *inst = npp ? (nsNPAPIPluginInstance *)npp->ndata : nullptr;
2455   if (!inst)
2456     return;
2457 
2458   inst->PopPopupsEnabledState();
2459 }
2460 
2461 void
_pluginthreadasynccall(NPP instance,PluginThreadCallback func,void * userData)2462 _pluginthreadasynccall(NPP instance, PluginThreadCallback func, void *userData)
2463 {
2464   if (NS_IsMainThread()) {
2465     NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,("NPN_pluginthreadasynccall called from the main thread\n"));
2466   } else {
2467     NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,("NPN_pluginthreadasynccall called from a non main thread\n"));
2468   }
2469   RefPtr<nsPluginThreadRunnable> evt =
2470     new nsPluginThreadRunnable(instance, func, userData);
2471 
2472   if (evt && evt->IsValid()) {
2473     NS_DispatchToMainThread(evt);
2474   }
2475 }
2476 
2477 NPError
_getvalueforurl(NPP instance,NPNURLVariable variable,const char * url,char ** value,uint32_t * len)2478 _getvalueforurl(NPP instance, NPNURLVariable variable, const char *url,
2479                 char **value, uint32_t *len)
2480 {
2481   if (!NS_IsMainThread()) {
2482     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getvalueforurl called from the wrong thread\n"));
2483     return NPERR_GENERIC_ERROR;
2484   }
2485 
2486   if (!instance) {
2487     return NPERR_INVALID_PARAM;
2488   }
2489 
2490   if (!url || !*url || !len) {
2491     return NPERR_INVALID_URL;
2492   }
2493 
2494   *len = 0;
2495 
2496   switch (variable) {
2497   case NPNURLVProxy:
2498     {
2499       nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
2500       nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
2501       if (pluginHost && NS_SUCCEEDED(pluginHost->FindProxyForURL(url, value))) {
2502         *len = *value ? strlen(*value) : 0;
2503         return NPERR_NO_ERROR;
2504       }
2505       break;
2506     }
2507   case NPNURLVCookie:
2508     {
2509       nsCOMPtr<nsICookieService> cookieService =
2510         do_GetService(NS_COOKIESERVICE_CONTRACTID);
2511 
2512       if (!cookieService)
2513         return NPERR_GENERIC_ERROR;
2514 
2515       // Make an nsURI from the url argument
2516       nsCOMPtr<nsIURI> uri;
2517       if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), nsDependentCString(url)))) {
2518         return NPERR_GENERIC_ERROR;
2519       }
2520 
2521       nsCOMPtr<nsIChannel> channel = GetChannelFromNPP(instance);
2522 
2523       if (NS_FAILED(cookieService->GetCookieString(uri, channel, value)) ||
2524           !*value) {
2525         return NPERR_GENERIC_ERROR;
2526       }
2527 
2528       *len = strlen(*value);
2529       return NPERR_NO_ERROR;
2530     }
2531 
2532   default:
2533     // Fall through and return an error...
2534     ;
2535   }
2536 
2537   return NPERR_GENERIC_ERROR;
2538 }
2539 
2540 NPError
_setvalueforurl(NPP instance,NPNURLVariable variable,const char * url,const char * value,uint32_t len)2541 _setvalueforurl(NPP instance, NPNURLVariable variable, const char *url,
2542                 const char *value, uint32_t len)
2543 {
2544   if (!NS_IsMainThread()) {
2545     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_setvalueforurl called from the wrong thread\n"));
2546     return NPERR_GENERIC_ERROR;
2547   }
2548 
2549   if (!instance) {
2550     return NPERR_INVALID_PARAM;
2551   }
2552 
2553   if (!url || !*url) {
2554     return NPERR_INVALID_URL;
2555   }
2556 
2557   switch (variable) {
2558   case NPNURLVCookie:
2559     {
2560       if (!value || 0 == len)
2561         return NPERR_INVALID_PARAM;
2562 
2563       nsresult rv = NS_ERROR_FAILURE;
2564       nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
2565       if (NS_FAILED(rv))
2566         return NPERR_GENERIC_ERROR;
2567 
2568       nsCOMPtr<nsICookieService> cookieService = do_GetService(NS_COOKIESERVICE_CONTRACTID, &rv);
2569       if (NS_FAILED(rv))
2570         return NPERR_GENERIC_ERROR;
2571 
2572       nsCOMPtr<nsIURI> uriIn;
2573       rv = ioService->NewURI(nsDependentCString(url), nullptr, nullptr, getter_AddRefs(uriIn));
2574       if (NS_FAILED(rv))
2575         return NPERR_GENERIC_ERROR;
2576 
2577       nsCOMPtr<nsIChannel> channel = GetChannelFromNPP(instance);
2578 
2579       char *cookie = (char*)value;
2580       char c = cookie[len];
2581       cookie[len] = '\0';
2582       rv = cookieService->SetCookieString(uriIn, nullptr, cookie, channel);
2583       cookie[len] = c;
2584       if (NS_SUCCEEDED(rv))
2585         return NPERR_NO_ERROR;
2586     }
2587 
2588     break;
2589   case NPNURLVProxy:
2590     // We don't support setting proxy values, fall through...
2591   default:
2592     // Fall through and return an error...
2593     ;
2594   }
2595 
2596   return NPERR_GENERIC_ERROR;
2597 }
2598 
2599 NPError
_getauthenticationinfo(NPP instance,const char * protocol,const char * host,int32_t port,const char * scheme,const char * realm,char ** username,uint32_t * ulen,char ** password,uint32_t * plen)2600 _getauthenticationinfo(NPP instance, const char *protocol, const char *host,
2601                        int32_t port, const char *scheme, const char *realm,
2602                        char **username, uint32_t *ulen, char **password,
2603                        uint32_t *plen)
2604 {
2605   if (!NS_IsMainThread()) {
2606     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getauthenticationinfo called from the wrong thread\n"));
2607     return NPERR_GENERIC_ERROR;
2608   }
2609 
2610   if (!instance || !protocol || !host || !scheme || !realm || !username ||
2611       !ulen || !password || !plen)
2612     return NPERR_INVALID_PARAM;
2613 
2614   *username = nullptr;
2615   *password = nullptr;
2616   *ulen = 0;
2617   *plen = 0;
2618 
2619   nsDependentCString proto(protocol);
2620 
2621   if (!proto.LowerCaseEqualsLiteral("http") &&
2622       !proto.LowerCaseEqualsLiteral("https"))
2623     return NPERR_GENERIC_ERROR;
2624 
2625   nsCOMPtr<nsIHttpAuthManager> authManager =
2626     do_GetService("@mozilla.org/network/http-auth-manager;1");
2627   if (!authManager)
2628     return NPERR_GENERIC_ERROR;
2629 
2630   nsNPAPIPluginInstance *inst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
2631   if (!inst)
2632     return NPERR_GENERIC_ERROR;
2633 
2634   bool authPrivate = false;
2635   if (NS_FAILED(inst->IsPrivateBrowsing(&authPrivate)))
2636     return NPERR_GENERIC_ERROR;
2637 
2638   nsIDocument *doc = GetDocumentFromNPP(instance);
2639   NS_ENSURE_TRUE(doc, NPERR_GENERIC_ERROR);
2640   nsIPrincipal *principal = doc->NodePrincipal();
2641 
2642   nsAutoString unused, uname16, pwd16;
2643   if (NS_FAILED(authManager->GetAuthIdentity(proto, nsDependentCString(host),
2644                                              port, nsDependentCString(scheme),
2645                                              nsDependentCString(realm),
2646                                              EmptyCString(), unused, uname16,
2647                                              pwd16, authPrivate, principal))) {
2648     return NPERR_GENERIC_ERROR;
2649   }
2650 
2651   NS_ConvertUTF16toUTF8 uname8(uname16);
2652   NS_ConvertUTF16toUTF8 pwd8(pwd16);
2653 
2654   *username = ToNewCString(uname8);
2655   *ulen = *username ? uname8.Length() : 0;
2656 
2657   *password = ToNewCString(pwd8);
2658   *plen = *password ? pwd8.Length() : 0;
2659 
2660   return NPERR_NO_ERROR;
2661 }
2662 
2663 uint32_t
_scheduletimer(NPP instance,uint32_t interval,NPBool repeat,PluginTimerFunc timerFunc)2664 _scheduletimer(NPP instance, uint32_t interval, NPBool repeat, PluginTimerFunc timerFunc)
2665 {
2666   if (!NS_IsMainThread()) {
2667     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_scheduletimer called from the wrong thread\n"));
2668     return 0;
2669   }
2670 
2671   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
2672   if (!inst)
2673     return 0;
2674 
2675   return inst->ScheduleTimer(interval, repeat, timerFunc);
2676 }
2677 
2678 void
_unscheduletimer(NPP instance,uint32_t timerID)2679 _unscheduletimer(NPP instance, uint32_t timerID)
2680 {
2681   if (!NS_IsMainThread()) {
2682     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_unscheduletimer called from the wrong thread\n"));
2683     return;
2684   }
2685 
2686 #ifdef MOZ_WIDGET_ANDROID
2687   // Sometimes Flash calls this with a dead NPP instance. Ensure the one we have
2688   // here is valid and maps to a nsNPAPIPluginInstance.
2689   nsNPAPIPluginInstance *inst = nsNPAPIPluginInstance::GetFromNPP(instance);
2690 #else
2691   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
2692 #endif
2693   if (!inst)
2694     return;
2695 
2696   inst->UnscheduleTimer(timerID);
2697 }
2698 
2699 NPError
_popupcontextmenu(NPP instance,NPMenu * menu)2700 _popupcontextmenu(NPP instance, NPMenu* menu)
2701 {
2702   if (!NS_IsMainThread()) {
2703     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_popupcontextmenu called from the wrong thread\n"));
2704     return 0;
2705   }
2706 
2707 #ifdef MOZ_WIDGET_COCOA
2708   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
2709 
2710   double pluginX, pluginY;
2711   double screenX, screenY;
2712 
2713   const NPCocoaEvent* currentEvent = static_cast<NPCocoaEvent*>(inst->GetCurrentEvent());
2714   if (!currentEvent) {
2715     return NPERR_GENERIC_ERROR;
2716   }
2717 
2718   // Ensure that the events has an x/y value.
2719   if (currentEvent->type != NPCocoaEventMouseDown    &&
2720       currentEvent->type != NPCocoaEventMouseUp      &&
2721       currentEvent->type != NPCocoaEventMouseMoved   &&
2722       currentEvent->type != NPCocoaEventMouseEntered &&
2723       currentEvent->type != NPCocoaEventMouseExited  &&
2724       currentEvent->type != NPCocoaEventMouseDragged) {
2725       return NPERR_GENERIC_ERROR;
2726   }
2727 
2728   pluginX = currentEvent->data.mouse.pluginX;
2729   pluginY = currentEvent->data.mouse.pluginY;
2730 
2731   if ((pluginX < 0.0) || (pluginY < 0.0))
2732     return NPERR_GENERIC_ERROR;
2733 
2734   NPBool success = _convertpoint(instance,
2735                                  pluginX,  pluginY, NPCoordinateSpacePlugin,
2736                                  &screenX, &screenY, NPCoordinateSpaceScreen);
2737 
2738   if (success) {
2739     return mozilla::plugins::PluginUtilsOSX::ShowCocoaContextMenu(menu,
2740                                     screenX, screenY,
2741                                     nullptr,
2742                                     nullptr);
2743   } else {
2744     NS_WARNING("Convertpoint failed, could not created contextmenu.");
2745     return NPERR_GENERIC_ERROR;
2746   }
2747 #else
2748     NS_WARNING("Not supported on this platform!");
2749     return NPERR_GENERIC_ERROR;
2750 #endif
2751 }
2752 
2753 NPBool
_convertpoint(NPP instance,double sourceX,double sourceY,NPCoordinateSpace sourceSpace,double * destX,double * destY,NPCoordinateSpace destSpace)2754 _convertpoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace)
2755 {
2756   if (!NS_IsMainThread()) {
2757     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_convertpoint called from the wrong thread\n"));
2758     return 0;
2759   }
2760 
2761   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
2762   if (!inst)
2763     return false;
2764 
2765   return inst->ConvertPoint(sourceX, sourceY, sourceSpace, destX, destY, destSpace);
2766 }
2767 
2768 void
_urlredirectresponse(NPP instance,void * notifyData,NPBool allow)2769 _urlredirectresponse(NPP instance, void* notifyData, NPBool allow)
2770 {
2771   if (!NS_IsMainThread()) {
2772     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_convertpoint called from the wrong thread\n"));
2773     return;
2774   }
2775 
2776   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
2777   if (!inst) {
2778     return;
2779   }
2780 
2781   inst->URLRedirectResponse(notifyData, allow);
2782 }
2783 
2784 NPError
_initasyncsurface(NPP instance,NPSize * size,NPImageFormat format,void * initData,NPAsyncSurface * surface)2785 _initasyncsurface(NPP instance, NPSize *size, NPImageFormat format, void *initData, NPAsyncSurface *surface)
2786 {
2787   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
2788   if (!inst) {
2789     return NPERR_GENERIC_ERROR;
2790   }
2791 
2792   return inst->InitAsyncSurface(size, format, initData, surface);
2793 }
2794 
2795 NPError
_finalizeasyncsurface(NPP instance,NPAsyncSurface * surface)2796 _finalizeasyncsurface(NPP instance, NPAsyncSurface *surface)
2797 {
2798   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
2799   if (!inst) {
2800     return NPERR_GENERIC_ERROR;
2801   }
2802 
2803   return inst->FinalizeAsyncSurface(surface);
2804 }
2805 
2806 void
_setcurrentasyncsurface(NPP instance,NPAsyncSurface * surface,NPRect * changed)2807 _setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed)
2808 {
2809   nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
2810   if (!inst) {
2811     return;
2812   }
2813 
2814   inst->SetCurrentAsyncSurface(surface, changed);
2815 }
2816 
2817 } /* namespace parent */
2818 } /* namespace plugins */
2819 } /* namespace mozilla */
2820