1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set sw=4 ts=4 et : */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "mozilla/plugins/PluginModuleChild.h"
8 
9 /* This must occur *after* plugins/PluginModuleChild.h to avoid typedefs conflicts. */
10 #include "mozilla/ArrayUtils.h"
11 
12 #include "mozilla/ipc/MessageChannel.h"
13 
14 #ifdef MOZ_WIDGET_GTK
15 #include <gtk/gtk.h>
16 #endif
17 
18 #include "nsIFile.h"
19 
20 #include "pratom.h"
21 #include "nsDebug.h"
22 #include "nsCOMPtr.h"
23 #include "nsPluginsDir.h"
24 #include "nsXULAppAPI.h"
25 
26 #ifdef MOZ_X11
27 # include "nsX11ErrorHandler.h"
28 # include "mozilla/X11Util.h"
29 #endif
30 #include "mozilla/ipc/ProcessChild.h"
31 #include "mozilla/plugins/PluginInstanceChild.h"
32 #include "mozilla/plugins/StreamNotifyChild.h"
33 #include "mozilla/plugins/BrowserStreamChild.h"
34 #include "mozilla/plugins/PluginStreamChild.h"
35 #include "mozilla/dom/CrashReporterChild.h"
36 #include "mozilla/Sprintf.h"
37 #include "mozilla/Unused.h"
38 
39 #include "nsNPAPIPlugin.h"
40 
41 #ifdef XP_WIN
42 #include "nsWindowsDllInterceptor.h"
43 #include "mozilla/widget/AudioSession.h"
44 #include "WinUtils.h"
45 #include <knownfolders.h>
46 #endif
47 
48 #ifdef MOZ_WIDGET_COCOA
49 #include "PluginInterposeOSX.h"
50 #include "PluginUtilsOSX.h"
51 #endif
52 
53 #include "GeckoProfiler.h"
54 
55 using namespace mozilla;
56 using namespace mozilla::ipc;
57 using namespace mozilla::plugins;
58 using namespace mozilla::widget;
59 using mozilla::dom::CrashReporterChild;
60 using mozilla::dom::PCrashReporterChild;
61 
62 #if defined(XP_WIN)
63 const wchar_t * kFlashFullscreenClass = L"ShockwaveFlashFullScreen";
64 const wchar_t * kMozillaWindowClass = L"MozillaWindowClass";
65 #endif
66 
67 namespace {
68 // see PluginModuleChild::GetChrome()
69 PluginModuleChild* gChromeInstance = nullptr;
70 } // namespace
71 
72 #ifdef XP_WIN
73 // Hooking CreateFileW for protected-mode magic
74 static WindowsDllInterceptor sKernel32Intercept;
75 typedef HANDLE (WINAPI *CreateFileWPtr)(LPCWSTR fname, DWORD access,
76                                         DWORD share,
77                                         LPSECURITY_ATTRIBUTES security,
78                                         DWORD creation, DWORD flags,
79                                         HANDLE ftemplate);
80 static CreateFileWPtr sCreateFileWStub = nullptr;
81 typedef HANDLE (WINAPI *CreateFileAPtr)(LPCSTR fname, DWORD access,
82                                         DWORD share,
83                                         LPSECURITY_ATTRIBUTES security,
84                                         DWORD creation, DWORD flags,
85                                         HANDLE ftemplate);
86 static CreateFileAPtr sCreateFileAStub = nullptr;
87 
88 // Used with fix for flash fullscreen window loosing focus.
89 static bool gDelayFlashFocusReplyUntilEval = false;
90 // Used to fix GetWindowInfo problems with internal flash settings dialogs
91 static WindowsDllInterceptor sUser32Intercept;
92 typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi);
93 static GetWindowInfoPtr sGetWindowInfoPtrStub = nullptr;
94 static HWND sBrowserHwnd = nullptr;
95 // sandbox process doesn't get current key states.  So we need get it on chrome.
96 typedef SHORT (WINAPI *GetKeyStatePtr)(int);
97 static GetKeyStatePtr sGetKeyStatePtrStub = nullptr;
98 #endif
99 
100 /* static */
101 PluginModuleChild*
CreateForContentProcess(mozilla::ipc::Transport * aTransport,base::ProcessId aOtherPid)102 PluginModuleChild::CreateForContentProcess(mozilla::ipc::Transport* aTransport,
103                                            base::ProcessId aOtherPid)
104 {
105     PluginModuleChild* child = new PluginModuleChild(false);
106 
107     if (!child->InitForContent(aOtherPid, XRE_GetIOMessageLoop(), aTransport)) {
108         return nullptr;
109     }
110 
111     return child;
112 }
113 
PluginModuleChild(bool aIsChrome)114 PluginModuleChild::PluginModuleChild(bool aIsChrome)
115   : mLibrary(0)
116   , mPluginFilename("")
117   , mQuirks(QUIRKS_NOT_INITIALIZED)
118   , mIsChrome(aIsChrome)
119   , mHasShutdown(false)
120   , mTransport(nullptr)
121   , mShutdownFunc(0)
122   , mInitializeFunc(0)
123 #if defined(OS_WIN) || defined(OS_MACOSX)
124   , mGetEntryPointsFunc(0)
125 #elif defined(MOZ_WIDGET_GTK)
126   , mNestedLoopTimerId(0)
127 #endif
128 #ifdef OS_WIN
129   , mNestedEventHook(nullptr)
130   , mGlobalCallWndProcHook(nullptr)
131   , mAsyncRenderSupport(false)
132 #endif
133 {
134     memset(&mFunctions, 0, sizeof(mFunctions));
135     if (mIsChrome) {
136         MOZ_ASSERT(!gChromeInstance);
137         gChromeInstance = this;
138     }
139 
140 #ifdef XP_MACOSX
141     if (aIsChrome) {
142       mac_plugin_interposing::child::SetUpCocoaInterposing();
143     }
144 #endif
145 }
146 
~PluginModuleChild()147 PluginModuleChild::~PluginModuleChild()
148 {
149     if (mIsChrome) {
150         MOZ_ASSERT(gChromeInstance == this);
151 
152         // We don't unload the plugin library in case it uses atexit handlers or
153         // other similar hooks.
154 
155         DeinitGraphics();
156         PluginScriptableObjectChild::ClearIdentifiers();
157 
158         gChromeInstance = nullptr;
159     }
160 }
161 
162 // static
163 PluginModuleChild*
GetChrome()164 PluginModuleChild::GetChrome()
165 {
166     // A special PluginModuleChild instance that talks to the chrome process
167     // during startup and shutdown. Synchronous messages to or from this actor
168     // should be avoided because they may lead to hangs.
169     MOZ_ASSERT(gChromeInstance);
170     return gChromeInstance;
171 }
172 
173 bool
CommonInit(base::ProcessId aParentPid,MessageLoop * aIOLoop,IPC::Channel * aChannel)174 PluginModuleChild::CommonInit(base::ProcessId aParentPid,
175                               MessageLoop* aIOLoop,
176                               IPC::Channel* aChannel)
177 {
178     PLUGIN_LOG_DEBUG_METHOD;
179 
180     // Request Windows message deferral behavior on our channel. This
181     // applies to the top level and all sub plugin protocols since they
182     // all share the same channel.
183     // Bug 1090573 - Don't do this for connections to content processes.
184     GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
185 
186     if (!Open(aChannel, aParentPid, aIOLoop)) {
187         return false;
188     }
189 
190     memset((void*) &mFunctions, 0, sizeof(mFunctions));
191     mFunctions.size = sizeof(mFunctions);
192     mFunctions.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
193 
194     return true;
195 }
196 
197 bool
InitForContent(base::ProcessId aParentPid,MessageLoop * aIOLoop,IPC::Channel * aChannel)198 PluginModuleChild::InitForContent(base::ProcessId aParentPid,
199                                   MessageLoop* aIOLoop,
200                                   IPC::Channel* aChannel)
201 {
202     if (!CommonInit(aParentPid, aIOLoop, aChannel)) {
203         return false;
204     }
205 
206     mTransport = aChannel;
207 
208     mLibrary = GetChrome()->mLibrary;
209     mFunctions = GetChrome()->mFunctions;
210 
211     return true;
212 }
213 
214 bool
RecvDisableFlashProtectedMode()215 PluginModuleChild::RecvDisableFlashProtectedMode()
216 {
217     MOZ_ASSERT(mIsChrome);
218 #ifdef XP_WIN
219     HookProtectedMode();
220 #else
221     MOZ_ASSERT(false, "Should not be called");
222 #endif
223     return true;
224 }
225 
226 bool
InitForChrome(const std::string & aPluginFilename,base::ProcessId aParentPid,MessageLoop * aIOLoop,IPC::Channel * aChannel)227 PluginModuleChild::InitForChrome(const std::string& aPluginFilename,
228                                  base::ProcessId aParentPid,
229                                  MessageLoop* aIOLoop,
230                                  IPC::Channel* aChannel)
231 {
232     NS_ASSERTION(aChannel, "need a channel");
233 
234     if (!InitGraphics())
235         return false;
236 
237     mPluginFilename = aPluginFilename.c_str();
238     nsCOMPtr<nsIFile> localFile;
239     NS_NewLocalFile(NS_ConvertUTF8toUTF16(mPluginFilename),
240                     true,
241                     getter_AddRefs(localFile));
242 
243     if (!localFile)
244         return false;
245 
246     bool exists;
247     localFile->Exists(&exists);
248     NS_ASSERTION(exists, "plugin file ain't there");
249 
250     nsPluginFile pluginFile(localFile);
251 
252     nsPluginInfo info = nsPluginInfo();
253     if (NS_FAILED(pluginFile.GetPluginInfo(info, &mLibrary))) {
254         return false;
255     }
256 
257 #if defined(XP_WIN)
258     // XXX quirks isn't initialized yet
259     mAsyncRenderSupport = info.fSupportsAsyncRender;
260 #endif
261 #if defined(MOZ_X11)
262     NS_NAMED_LITERAL_CSTRING(flash10Head, "Shockwave Flash 10.");
263     if (StringBeginsWith(nsDependentCString(info.fDescription), flash10Head)) {
264         AddQuirk(QUIRK_FLASH_EXPOSE_COORD_TRANSLATION);
265     }
266 #endif
267 #if defined(XP_MACOSX)
268     const char* namePrefix = "Plugin Content";
269     char nameBuffer[80];
270     SprintfLiteral(nameBuffer, "%s (%s)", namePrefix, info.fName);
271     mozilla::plugins::PluginUtilsOSX::SetProcessName(nameBuffer);
272 #endif
273     pluginFile.FreePluginInfo(info);
274 #if defined(MOZ_X11) || defined(XP_MACOSX)
275     if (!mLibrary)
276 #endif
277     {
278         nsresult rv = pluginFile.LoadPlugin(&mLibrary);
279         if (NS_FAILED(rv))
280             return false;
281     }
282     NS_ASSERTION(mLibrary, "couldn't open shared object");
283 
284     if (!CommonInit(aParentPid, aIOLoop, aChannel)) {
285         return false;
286     }
287 
288     GetIPCChannel()->SetAbortOnError(true);
289 
290     // TODO: use PluginPRLibrary here
291 
292 #if defined(OS_LINUX) || defined(OS_BSD)
293     mShutdownFunc =
294         (NP_PLUGINSHUTDOWN) PR_FindFunctionSymbol(mLibrary, "NP_Shutdown");
295 
296     // create the new plugin handler
297 
298     mInitializeFunc =
299         (NP_PLUGINUNIXINIT) PR_FindFunctionSymbol(mLibrary, "NP_Initialize");
300     NS_ASSERTION(mInitializeFunc, "couldn't find NP_Initialize()");
301 
302 #elif defined(OS_WIN) || defined(OS_MACOSX)
303     mShutdownFunc =
304         (NP_PLUGINSHUTDOWN)PR_FindFunctionSymbol(mLibrary, "NP_Shutdown");
305 
306     mGetEntryPointsFunc =
307         (NP_GETENTRYPOINTS)PR_FindSymbol(mLibrary, "NP_GetEntryPoints");
308     NS_ENSURE_TRUE(mGetEntryPointsFunc, false);
309 
310     mInitializeFunc =
311         (NP_PLUGININIT)PR_FindFunctionSymbol(mLibrary, "NP_Initialize");
312     NS_ENSURE_TRUE(mInitializeFunc, false);
313 #else
314 
315 #  error Please copy the initialization code from nsNPAPIPlugin.cpp
316 
317 #endif
318 
319     return true;
320 }
321 
322 #if defined(MOZ_WIDGET_GTK)
323 
324 typedef void (*GObjectDisposeFn)(GObject*);
325 typedef gboolean (*GtkWidgetScrollEventFn)(GtkWidget*, GdkEventScroll*);
326 typedef void (*GtkPlugEmbeddedFn)(GtkPlug*);
327 
328 static GObjectDisposeFn real_gtk_plug_dispose;
329 static GtkPlugEmbeddedFn real_gtk_plug_embedded;
330 
331 static void
undo_bogus_unref(gpointer data,GObject * object,gboolean is_last_ref)332 undo_bogus_unref(gpointer data, GObject* object, gboolean is_last_ref) {
333     if (!is_last_ref) // recursion in g_object_ref
334         return;
335 
336     g_object_ref(object);
337 }
338 
339 static void
wrap_gtk_plug_dispose(GObject * object)340 wrap_gtk_plug_dispose(GObject* object) {
341     // Work around Flash Player bug described in bug 538914.
342     //
343     // This function is called during gtk_widget_destroy and/or before
344     // the object's last reference is removed.  A reference to the
345     // object is held during the call so the ref count should not drop
346     // to zero.  However, Flash Player tries to destroy the GtkPlug
347     // using g_object_unref instead of gtk_widget_destroy.  The
348     // reference that Flash is removing actually belongs to the
349     // GtkPlug.  During real_gtk_plug_dispose, the GtkPlug removes its
350     // reference.
351     //
352     // A toggle ref is added to prevent premature deletion of the object
353     // caused by Flash Player's extra unref, and to detect when there are
354     // unexpectedly no other references.
355     g_object_add_toggle_ref(object, undo_bogus_unref, nullptr);
356     (*real_gtk_plug_dispose)(object);
357     g_object_remove_toggle_ref(object, undo_bogus_unref, nullptr);
358 }
359 
360 static gboolean
gtk_plug_scroll_event(GtkWidget * widget,GdkEventScroll * gdk_event)361 gtk_plug_scroll_event(GtkWidget *widget, GdkEventScroll *gdk_event)
362 {
363     if (!gtk_widget_is_toplevel(widget)) // in same process as its GtkSocket
364         return FALSE; // event not handled; propagate to GtkSocket
365 
366     GdkWindow* socket_window = gtk_plug_get_socket_window(GTK_PLUG(widget));
367     if (!socket_window)
368         return FALSE;
369 
370     // Propagate the event to the embedder.
371     GdkScreen* screen = gdk_window_get_screen(socket_window);
372     GdkWindow* plug_window = gtk_widget_get_window(widget);
373     GdkWindow* event_window = gdk_event->window;
374     gint x = gdk_event->x;
375     gint y = gdk_event->y;
376     unsigned int button;
377     unsigned int button_mask = 0;
378     XEvent xevent;
379     Display* dpy = GDK_WINDOW_XDISPLAY(socket_window);
380 
381     /* Translate the event coordinates to the plug window,
382      * which should be aligned with the socket window.
383      */
384     while (event_window != plug_window)
385     {
386         gint dx, dy;
387 
388         gdk_window_get_position(event_window, &dx, &dy);
389         x += dx;
390         y += dy;
391 
392         event_window = gdk_window_get_parent(event_window);
393         if (!event_window)
394             return FALSE;
395     }
396 
397     switch (gdk_event->direction) {
398     case GDK_SCROLL_UP:
399         button = 4;
400         button_mask = Button4Mask;
401         break;
402     case GDK_SCROLL_DOWN:
403         button = 5;
404         button_mask = Button5Mask;
405         break;
406     case GDK_SCROLL_LEFT:
407         button = 6;
408         break;
409     case GDK_SCROLL_RIGHT:
410         button = 7;
411         break;
412     default:
413         return FALSE; // unknown GdkScrollDirection
414     }
415 
416     memset(&xevent, 0, sizeof(xevent));
417     xevent.xbutton.type = ButtonPress;
418     xevent.xbutton.window = gdk_x11_window_get_xid(socket_window);
419     xevent.xbutton.root = gdk_x11_window_get_xid(gdk_screen_get_root_window(screen));
420     xevent.xbutton.subwindow = gdk_x11_window_get_xid(plug_window);
421     xevent.xbutton.time = gdk_event->time;
422     xevent.xbutton.x = x;
423     xevent.xbutton.y = y;
424     xevent.xbutton.x_root = gdk_event->x_root;
425     xevent.xbutton.y_root = gdk_event->y_root;
426     xevent.xbutton.state = gdk_event->state;
427     xevent.xbutton.button = button;
428     xevent.xbutton.same_screen = True;
429 
430     gdk_error_trap_push();
431 
432     XSendEvent(dpy, xevent.xbutton.window,
433                True, ButtonPressMask, &xevent);
434 
435     xevent.xbutton.type = ButtonRelease;
436     xevent.xbutton.state |= button_mask;
437     XSendEvent(dpy, xevent.xbutton.window,
438                True, ButtonReleaseMask, &xevent);
439 
440     gdk_display_sync(gdk_screen_get_display(screen));
441     gdk_error_trap_pop();
442 
443     return TRUE; // event handled
444 }
445 
446 static void
wrap_gtk_plug_embedded(GtkPlug * plug)447 wrap_gtk_plug_embedded(GtkPlug* plug) {
448     GdkWindow* socket_window = gtk_plug_get_socket_window(plug);
449     if (socket_window) {
450         if (gtk_check_version(2,18,7) != nullptr // older
451             && g_object_get_data(G_OBJECT(socket_window),
452                                  "moz-existed-before-set-window")) {
453             // Add missing reference for
454             // https://bugzilla.gnome.org/show_bug.cgi?id=607061
455             g_object_ref(socket_window);
456         }
457 
458         // Ensure the window exists to make this GtkPlug behave like an
459         // in-process GtkPlug for Flash Player.  (Bugs 561308 and 539138).
460         gtk_widget_realize(GTK_WIDGET(plug));
461     }
462 
463     if (*real_gtk_plug_embedded) {
464         (*real_gtk_plug_embedded)(plug);
465     }
466 }
467 
468 //
469 // The next four constants are knobs that can be tuned.  They trade
470 // off potential UI lag from delayed event processing with CPU time.
471 //
472 static const gint kNestedLoopDetectorPriority = G_PRIORITY_HIGH_IDLE;
473 // 90ms so that we can hopefully break livelocks before the user
474 // notices UI lag (100ms)
475 static const guint kNestedLoopDetectorIntervalMs = 90;
476 
477 static const gint kBrowserEventPriority = G_PRIORITY_HIGH_IDLE;
478 static const guint kBrowserEventIntervalMs = 10;
479 
480 // static
481 gboolean
DetectNestedEventLoop(gpointer data)482 PluginModuleChild::DetectNestedEventLoop(gpointer data)
483 {
484     PluginModuleChild* pmc = static_cast<PluginModuleChild*>(data);
485 
486     MOZ_ASSERT(0 != pmc->mNestedLoopTimerId,
487                "callback after descheduling");
488     MOZ_ASSERT(pmc->mTopLoopDepth < g_main_depth(),
489                "not canceled before returning to main event loop!");
490 
491     PLUGIN_LOG_DEBUG(("Detected nested glib event loop"));
492 
493     // just detected a nested loop; start a timer that will
494     // periodically rpc-call back into the browser and process some
495     // events
496     pmc->mNestedLoopTimerId =
497         g_timeout_add_full(kBrowserEventPriority,
498                            kBrowserEventIntervalMs,
499                            PluginModuleChild::ProcessBrowserEvents,
500                            data,
501                            nullptr);
502     // cancel the nested-loop detection timer
503     return FALSE;
504 }
505 
506 // static
507 gboolean
ProcessBrowserEvents(gpointer data)508 PluginModuleChild::ProcessBrowserEvents(gpointer data)
509 {
510     PluginModuleChild* pmc = static_cast<PluginModuleChild*>(data);
511 
512     MOZ_ASSERT(pmc->mTopLoopDepth < g_main_depth(),
513                "not canceled before returning to main event loop!");
514 
515     pmc->CallProcessSomeEvents();
516 
517     return TRUE;
518 }
519 
520 void
EnteredCxxStack()521 PluginModuleChild::EnteredCxxStack()
522 {
523     MOZ_ASSERT(0 == mNestedLoopTimerId,
524                "previous timer not descheduled");
525 
526     mNestedLoopTimerId =
527         g_timeout_add_full(kNestedLoopDetectorPriority,
528                            kNestedLoopDetectorIntervalMs,
529                            PluginModuleChild::DetectNestedEventLoop,
530                            this,
531                            nullptr);
532 
533 #ifdef DEBUG
534     mTopLoopDepth = g_main_depth();
535 #endif
536 }
537 
538 void
ExitedCxxStack()539 PluginModuleChild::ExitedCxxStack()
540 {
541     MOZ_ASSERT(0 < mNestedLoopTimerId,
542                "nested loop timeout not scheduled");
543 
544     g_source_remove(mNestedLoopTimerId);
545     mNestedLoopTimerId = 0;
546 }
547 
548 #endif
549 
550 bool
RecvSetParentHangTimeout(const uint32_t & aSeconds)551 PluginModuleChild::RecvSetParentHangTimeout(const uint32_t& aSeconds)
552 {
553 #ifdef XP_WIN
554     SetReplyTimeoutMs(((aSeconds > 0) ? (1000 * aSeconds) : 0));
555 #endif
556     return true;
557 }
558 
559 bool
ShouldContinueFromReplyTimeout()560 PluginModuleChild::ShouldContinueFromReplyTimeout()
561 {
562 #ifdef XP_WIN
563     NS_RUNTIMEABORT("terminating child process");
564 #endif
565     return true;
566 }
567 
568 bool
InitGraphics()569 PluginModuleChild::InitGraphics()
570 {
571 #if defined(MOZ_WIDGET_GTK)
572     // Work around plugins that don't interact well with GDK
573     // client-side windows.
574     PR_SetEnv("GDK_NATIVE_WINDOWS=1");
575 
576     gtk_init(0, 0);
577 
578     // GtkPlug is a static class so will leak anyway but this ref makes sure.
579     gpointer gtk_plug_class = g_type_class_ref(GTK_TYPE_PLUG);
580 
581     // The dispose method is a good place to hook into the destruction process
582     // because the reference count should be 1 the last time dispose is
583     // called.  (Toggle references wouldn't detect if the reference count
584     // might be higher.)
585     GObjectDisposeFn* dispose = &G_OBJECT_CLASS(gtk_plug_class)->dispose;
586     MOZ_ASSERT(*dispose != wrap_gtk_plug_dispose,
587                "InitGraphics called twice");
588     real_gtk_plug_dispose = *dispose;
589     *dispose = wrap_gtk_plug_dispose;
590 
591     // If we ever stop setting GDK_NATIVE_WINDOWS, we'll also need to
592     // gtk_widget_add_events GDK_SCROLL_MASK or GDK client-side windows will
593     // not tell us about the scroll events that it intercepts.  With native
594     // windows, this is called when GDK intercepts the events; if GDK doesn't
595     // intercept the events, then the X server will instead send them directly
596     // to an ancestor (embedder) window.
597     GtkWidgetScrollEventFn* scroll_event =
598         &GTK_WIDGET_CLASS(gtk_plug_class)->scroll_event;
599     if (!*scroll_event) {
600         *scroll_event = gtk_plug_scroll_event;
601     }
602 
603     GtkPlugEmbeddedFn* embedded = &GTK_PLUG_CLASS(gtk_plug_class)->embedded;
604     real_gtk_plug_embedded = *embedded;
605     *embedded = wrap_gtk_plug_embedded;
606 
607 #else
608     // may not be necessary on all platforms
609 #endif
610 #ifdef MOZ_X11
611     // Do this after initializing GDK, or GDK will install its own handler.
612     InstallX11ErrorHandler();
613 #endif
614     return true;
615 }
616 
617 void
DeinitGraphics()618 PluginModuleChild::DeinitGraphics()
619 {
620 #if defined(MOZ_X11) && defined(NS_FREE_PERMANENT_DATA)
621     // We free some data off of XDisplay close hooks, ensure they're
622     // run.  Closing the display is pretty scary, so we only do it to
623     // silence leak checkers.
624     XCloseDisplay(DefaultXDisplay());
625 #endif
626 }
627 
628 NPError
NP_Shutdown()629 PluginModuleChild::NP_Shutdown()
630 {
631     AssertPluginThread();
632     MOZ_ASSERT(mIsChrome);
633 
634     if (mHasShutdown) {
635         return NPERR_NO_ERROR;
636     }
637 
638 #if defined XP_WIN
639     mozilla::widget::StopAudioSession();
640 #endif
641 
642     // the PluginModuleParent shuts down this process after this interrupt
643     // call pops off its stack
644 
645     NPError rv = mShutdownFunc ? mShutdownFunc() : NPERR_NO_ERROR;
646 
647     // weakly guard against re-entry after NP_Shutdown
648     memset(&mFunctions, 0, sizeof(mFunctions));
649 
650 #ifdef OS_WIN
651     ResetEventHooks();
652 #endif
653 
654     GetIPCChannel()->SetAbortOnError(false);
655 
656     mHasShutdown = true;
657 
658     return rv;
659 }
660 
661 bool
AnswerNP_Shutdown(NPError * rv)662 PluginModuleChild::AnswerNP_Shutdown(NPError *rv)
663 {
664     *rv = NP_Shutdown();
665     return true;
666 }
667 
668 bool
AnswerOptionalFunctionsSupported(bool * aURLRedirectNotify,bool * aClearSiteData,bool * aGetSitesWithData)669 PluginModuleChild::AnswerOptionalFunctionsSupported(bool *aURLRedirectNotify,
670                                                     bool *aClearSiteData,
671                                                     bool *aGetSitesWithData)
672 {
673     *aURLRedirectNotify = !!mFunctions.urlredirectnotify;
674     *aClearSiteData = !!mFunctions.clearsitedata;
675     *aGetSitesWithData = !!mFunctions.getsiteswithdata;
676     return true;
677 }
678 
679 bool
RecvNPP_ClearSiteData(const nsCString & aSite,const uint64_t & aFlags,const uint64_t & aMaxAge,const uint64_t & aCallbackId)680 PluginModuleChild::RecvNPP_ClearSiteData(const nsCString& aSite,
681                                            const uint64_t& aFlags,
682                                            const uint64_t& aMaxAge,
683                                            const uint64_t& aCallbackId)
684 {
685     NPError result =
686         mFunctions.clearsitedata(NullableStringGet(aSite), aFlags, aMaxAge);
687     SendReturnClearSiteData(result, aCallbackId);
688     return true;
689 }
690 
691 bool
RecvNPP_GetSitesWithData(const uint64_t & aCallbackId)692 PluginModuleChild::RecvNPP_GetSitesWithData(const uint64_t& aCallbackId)
693 {
694     char** result = mFunctions.getsiteswithdata();
695     InfallibleTArray<nsCString> array;
696     if (!result) {
697         SendReturnSitesWithData(array, aCallbackId);
698         return true;
699     }
700     char** iterator = result;
701     while (*iterator) {
702         array.AppendElement(*iterator);
703         free(*iterator);
704         ++iterator;
705     }
706     SendReturnSitesWithData(array, aCallbackId);
707     free(result);
708     return true;
709 }
710 
711 bool
RecvSetAudioSessionData(const nsID & aId,const nsString & aDisplayName,const nsString & aIconPath)712 PluginModuleChild::RecvSetAudioSessionData(const nsID& aId,
713                                            const nsString& aDisplayName,
714                                            const nsString& aIconPath)
715 {
716 #if !defined XP_WIN
717     NS_RUNTIMEABORT("Not Reached!");
718     return false;
719 #else
720     nsresult rv = mozilla::widget::RecvAudioSessionData(aId, aDisplayName, aIconPath);
721     NS_ENSURE_SUCCESS(rv, true); // Bail early if this fails
722 
723     // Ignore failures here; we can't really do anything about them
724     mozilla::widget::StartAudioSession();
725     return true;
726 #endif
727 }
728 
729 PPluginModuleChild*
AllocPPluginModuleChild(mozilla::ipc::Transport * aTransport,base::ProcessId aOtherPid)730 PluginModuleChild::AllocPPluginModuleChild(mozilla::ipc::Transport* aTransport,
731                                            base::ProcessId aOtherPid)
732 {
733     return PluginModuleChild::CreateForContentProcess(aTransport, aOtherPid);
734 }
735 
736 PCrashReporterChild*
AllocPCrashReporterChild(mozilla::dom::NativeThreadId * id,uint32_t * processType)737 PluginModuleChild::AllocPCrashReporterChild(mozilla::dom::NativeThreadId* id,
738                                             uint32_t* processType)
739 {
740     return new CrashReporterChild();
741 }
742 
743 bool
DeallocPCrashReporterChild(PCrashReporterChild * actor)744 PluginModuleChild::DeallocPCrashReporterChild(PCrashReporterChild* actor)
745 {
746     delete actor;
747     return true;
748 }
749 
750 bool
AnswerPCrashReporterConstructor(PCrashReporterChild * actor,mozilla::dom::NativeThreadId * id,uint32_t * processType)751 PluginModuleChild::AnswerPCrashReporterConstructor(
752         PCrashReporterChild* actor,
753         mozilla::dom::NativeThreadId* id,
754         uint32_t* processType)
755 {
756 #ifdef MOZ_CRASHREPORTER
757     *id = CrashReporter::CurrentThreadId();
758     *processType = XRE_GetProcessType();
759 #endif
760     return true;
761 }
762 
763 void
ActorDestroy(ActorDestroyReason why)764 PluginModuleChild::ActorDestroy(ActorDestroyReason why)
765 {
766     if (!mIsChrome) {
767         PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
768         if (chromeInstance) {
769             chromeInstance->SendNotifyContentModuleDestroyed();
770         }
771 
772         // Destroy ourselves once we finish other teardown activities.
773         RefPtr<DeleteTask<PluginModuleChild>> task =
774             new DeleteTask<PluginModuleChild>(this);
775         MessageLoop::current()->PostTask(task.forget());
776         return;
777     }
778 
779     if (AbnormalShutdown == why) {
780         NS_WARNING("shutting down early because of crash!");
781         ProcessChild::QuickExit();
782     }
783 
784     if (!mHasShutdown) {
785         MOZ_ASSERT(gChromeInstance == this);
786         NP_Shutdown();
787     }
788 
789     // doesn't matter why we're being destroyed; it's up to us to
790     // initiate (clean) shutdown
791     XRE_ShutdownChildProcess();
792 }
793 
794 void
CleanUp()795 PluginModuleChild::CleanUp()
796 {
797 }
798 
799 const char*
GetUserAgent()800 PluginModuleChild::GetUserAgent()
801 {
802     return NullableStringGet(Settings().userAgent());
803 }
804 
805 //-----------------------------------------------------------------------------
806 // FIXME/cjones: just getting this out of the way for the moment ...
807 
808 namespace mozilla {
809 namespace plugins {
810 namespace child {
811 
812 static NPError
813 _requestread(NPStream *pstream, NPByteRange *rangeList);
814 
815 static NPError
816 _geturlnotify(NPP aNPP, const char* relativeURL, const char* target,
817               void* notifyData);
818 
819 static NPError
820 _getvalue(NPP aNPP, NPNVariable variable, void *r_value);
821 
822 static NPError
823 _setvalue(NPP aNPP, NPPVariable variable, void *r_value);
824 
825 static NPError
826 _geturl(NPP aNPP, const char* relativeURL, const char* target);
827 
828 static NPError
829 _posturlnotify(NPP aNPP, const char* relativeURL, const char *target,
830                uint32_t len, const char *buf, NPBool file, void* notifyData);
831 
832 static NPError
833 _posturl(NPP aNPP, const char* relativeURL, const char *target, uint32_t len,
834          const char *buf, NPBool file);
835 
836 static NPError
837 _newstream(NPP aNPP, NPMIMEType type, const char* window, NPStream** pstream);
838 
839 static int32_t
840 _write(NPP aNPP, NPStream *pstream, int32_t len, void *buffer);
841 
842 static NPError
843 _destroystream(NPP aNPP, NPStream *pstream, NPError reason);
844 
845 static void
846 _status(NPP aNPP, const char *message);
847 
848 static void
849 _memfree (void *ptr);
850 
851 static uint32_t
852 _memflush(uint32_t size);
853 
854 static void
855 _reloadplugins(NPBool reloadPages);
856 
857 static void
858 _invalidaterect(NPP aNPP, NPRect *invalidRect);
859 
860 static void
861 _invalidateregion(NPP aNPP, NPRegion invalidRegion);
862 
863 static void
864 _forceredraw(NPP aNPP);
865 
866 static const char*
867 _useragent(NPP aNPP);
868 
869 static void*
870 _memalloc (uint32_t size);
871 
872 // Deprecated entry points for the old Java plugin.
873 static void* /* OJI type: JRIEnv* */
874 _getjavaenv(void);
875 
876 // Deprecated entry points for the old Java plugin.
877 static void* /* OJI type: jref */
878 _getjavapeer(NPP aNPP);
879 
880 static bool
881 _invoke(NPP aNPP, NPObject* npobj, NPIdentifier method, const NPVariant *args,
882         uint32_t argCount, NPVariant *result);
883 
884 static bool
885 _invokedefault(NPP aNPP, NPObject* npobj, const NPVariant *args,
886                uint32_t argCount, NPVariant *result);
887 
888 static bool
889 _evaluate(NPP aNPP, NPObject* npobj, NPString *script, NPVariant *result);
890 
891 static bool
892 _getproperty(NPP aNPP, NPObject* npobj, NPIdentifier property,
893              NPVariant *result);
894 
895 static bool
896 _setproperty(NPP aNPP, NPObject* npobj, NPIdentifier property,
897              const NPVariant *value);
898 
899 static bool
900 _removeproperty(NPP aNPP, NPObject* npobj, NPIdentifier property);
901 
902 static bool
903 _hasproperty(NPP aNPP, NPObject* npobj, NPIdentifier propertyName);
904 
905 static bool
906 _hasmethod(NPP aNPP, NPObject* npobj, NPIdentifier methodName);
907 
908 static bool
909 _enumerate(NPP aNPP, NPObject *npobj, NPIdentifier **identifier,
910            uint32_t *count);
911 
912 static bool
913 _construct(NPP aNPP, NPObject* npobj, const NPVariant *args,
914            uint32_t argCount, NPVariant *result);
915 
916 static void
917 _releasevariantvalue(NPVariant *variant);
918 
919 static void
920 _setexception(NPObject* npobj, const NPUTF8 *message);
921 
922 static void
923 _pushpopupsenabledstate(NPP aNPP, NPBool enabled);
924 
925 static void
926 _poppopupsenabledstate(NPP aNPP);
927 
928 static void
929 _pluginthreadasynccall(NPP instance, PluginThreadCallback func,
930                        void *userData);
931 
932 static NPError
933 _getvalueforurl(NPP npp, NPNURLVariable variable, const char *url,
934                 char **value, uint32_t *len);
935 
936 static NPError
937 _setvalueforurl(NPP npp, NPNURLVariable variable, const char *url,
938                 const char *value, uint32_t len);
939 
940 static NPError
941 _getauthenticationinfo(NPP npp, const char *protocol,
942                        const char *host, int32_t port,
943                        const char *scheme, const char *realm,
944                        char **username, uint32_t *ulen,
945                        char **password, uint32_t *plen);
946 
947 static uint32_t
948 _scheduletimer(NPP instance, uint32_t interval, NPBool repeat,
949                void (*timerFunc)(NPP npp, uint32_t timerID));
950 
951 static void
952 _unscheduletimer(NPP instance, uint32_t timerID);
953 
954 static NPError
955 _popupcontextmenu(NPP instance, NPMenu* menu);
956 
957 static NPBool
958 _convertpoint(NPP instance,
959               double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
960               double *destX, double *destY, NPCoordinateSpace destSpace);
961 
962 static void
963 _urlredirectresponse(NPP instance, void* notifyData, NPBool allow);
964 
965 static NPError
966 _initasyncsurface(NPP instance, NPSize *size,
967                   NPImageFormat format, void *initData,
968                   NPAsyncSurface *surface);
969 
970 static NPError
971 _finalizeasyncsurface(NPP instance, NPAsyncSurface *surface);
972 
973 static void
974 _setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed);
975 
976 } /* namespace child */
977 } /* namespace plugins */
978 } /* namespace mozilla */
979 
980 const NPNetscapeFuncs PluginModuleChild::sBrowserFuncs = {
981     sizeof(sBrowserFuncs),
982     (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR,
983     mozilla::plugins::child::_geturl,
984     mozilla::plugins::child::_posturl,
985     mozilla::plugins::child::_requestread,
986     mozilla::plugins::child::_newstream,
987     mozilla::plugins::child::_write,
988     mozilla::plugins::child::_destroystream,
989     mozilla::plugins::child::_status,
990     mozilla::plugins::child::_useragent,
991     mozilla::plugins::child::_memalloc,
992     mozilla::plugins::child::_memfree,
993     mozilla::plugins::child::_memflush,
994     mozilla::plugins::child::_reloadplugins,
995     mozilla::plugins::child::_getjavaenv,
996     mozilla::plugins::child::_getjavapeer,
997     mozilla::plugins::child::_geturlnotify,
998     mozilla::plugins::child::_posturlnotify,
999     mozilla::plugins::child::_getvalue,
1000     mozilla::plugins::child::_setvalue,
1001     mozilla::plugins::child::_invalidaterect,
1002     mozilla::plugins::child::_invalidateregion,
1003     mozilla::plugins::child::_forceredraw,
1004     PluginModuleChild::NPN_GetStringIdentifier,
1005     PluginModuleChild::NPN_GetStringIdentifiers,
1006     PluginModuleChild::NPN_GetIntIdentifier,
1007     PluginModuleChild::NPN_IdentifierIsString,
1008     PluginModuleChild::NPN_UTF8FromIdentifier,
1009     PluginModuleChild::NPN_IntFromIdentifier,
1010     PluginModuleChild::NPN_CreateObject,
1011     PluginModuleChild::NPN_RetainObject,
1012     PluginModuleChild::NPN_ReleaseObject,
1013     mozilla::plugins::child::_invoke,
1014     mozilla::plugins::child::_invokedefault,
1015     mozilla::plugins::child::_evaluate,
1016     mozilla::plugins::child::_getproperty,
1017     mozilla::plugins::child::_setproperty,
1018     mozilla::plugins::child::_removeproperty,
1019     mozilla::plugins::child::_hasproperty,
1020     mozilla::plugins::child::_hasmethod,
1021     mozilla::plugins::child::_releasevariantvalue,
1022     mozilla::plugins::child::_setexception,
1023     mozilla::plugins::child::_pushpopupsenabledstate,
1024     mozilla::plugins::child::_poppopupsenabledstate,
1025     mozilla::plugins::child::_enumerate,
1026     mozilla::plugins::child::_pluginthreadasynccall,
1027     mozilla::plugins::child::_construct,
1028     mozilla::plugins::child::_getvalueforurl,
1029     mozilla::plugins::child::_setvalueforurl,
1030     mozilla::plugins::child::_getauthenticationinfo,
1031     mozilla::plugins::child::_scheduletimer,
1032     mozilla::plugins::child::_unscheduletimer,
1033     mozilla::plugins::child::_popupcontextmenu,
1034     mozilla::plugins::child::_convertpoint,
1035     nullptr, // handleevent, unimplemented
1036     nullptr, // unfocusinstance, unimplemented
1037     mozilla::plugins::child::_urlredirectresponse,
1038     mozilla::plugins::child::_initasyncsurface,
1039     mozilla::plugins::child::_finalizeasyncsurface,
1040     mozilla::plugins::child::_setcurrentasyncsurface,
1041 };
1042 
1043 PluginInstanceChild*
InstCast(NPP aNPP)1044 InstCast(NPP aNPP)
1045 {
1046     MOZ_ASSERT(!!(aNPP->ndata), "nil instance");
1047     return static_cast<PluginInstanceChild*>(aNPP->ndata);
1048 }
1049 
1050 namespace mozilla {
1051 namespace plugins {
1052 namespace child {
1053 
1054 NPError
_requestread(NPStream * aStream,NPByteRange * aRangeList)1055 _requestread(NPStream* aStream,
1056              NPByteRange* aRangeList)
1057 {
1058     PLUGIN_LOG_DEBUG_FUNCTION;
1059     ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
1060 
1061     BrowserStreamChild* bs =
1062         static_cast<BrowserStreamChild*>(static_cast<AStream*>(aStream->ndata));
1063     bs->EnsureCorrectStream(aStream);
1064     return bs->NPN_RequestRead(aRangeList);
1065 }
1066 
1067 NPError
_geturlnotify(NPP aNPP,const char * aRelativeURL,const char * aTarget,void * aNotifyData)1068 _geturlnotify(NPP aNPP,
1069               const char* aRelativeURL,
1070               const char* aTarget,
1071               void* aNotifyData)
1072 {
1073     PLUGIN_LOG_DEBUG_FUNCTION;
1074     ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
1075 
1076     if (!aNPP) // nullptr check for nspluginwrapper (bug 561690)
1077         return NPERR_INVALID_INSTANCE_ERROR;
1078 
1079     nsCString url = NullableString(aRelativeURL);
1080     StreamNotifyChild* sn = new StreamNotifyChild(url);
1081 
1082     NPError err;
1083     InstCast(aNPP)->CallPStreamNotifyConstructor(
1084         sn, url, NullableString(aTarget), false, nsCString(), false, &err);
1085 
1086     if (NPERR_NO_ERROR == err) {
1087         // If NPN_PostURLNotify fails, the parent will immediately send us
1088         // a PStreamNotifyDestructor, which should not call NPP_URLNotify.
1089         sn->SetValid(aNotifyData);
1090     }
1091 
1092     return err;
1093 }
1094 
1095 NPError
_getvalue(NPP aNPP,NPNVariable aVariable,void * aValue)1096 _getvalue(NPP aNPP,
1097           NPNVariable aVariable,
1098           void* aValue)
1099 {
1100     PLUGIN_LOG_DEBUG_FUNCTION;
1101     ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
1102 
1103     switch (aVariable) {
1104         // Copied from nsNPAPIPlugin.cpp
1105         case NPNVToolkit:
1106 #if defined(MOZ_WIDGET_GTK)
1107             *static_cast<NPNToolkitType*>(aValue) = NPNVGtk2;
1108             return NPERR_NO_ERROR;
1109 #endif
1110             return NPERR_GENERIC_ERROR;
1111 
1112         case NPNVjavascriptEnabledBool:
1113             *(NPBool*)aValue = PluginModuleChild::GetChrome()->Settings().javascriptEnabled();
1114             return NPERR_NO_ERROR;
1115         case NPNVasdEnabledBool:
1116             *(NPBool*)aValue = PluginModuleChild::GetChrome()->Settings().asdEnabled();
1117             return NPERR_NO_ERROR;
1118         case NPNVisOfflineBool:
1119             *(NPBool*)aValue = PluginModuleChild::GetChrome()->Settings().isOffline();
1120             return NPERR_NO_ERROR;
1121         case NPNVSupportsXEmbedBool:
1122             *(NPBool*)aValue = PluginModuleChild::GetChrome()->Settings().supportsXembed();
1123             return NPERR_NO_ERROR;
1124         case NPNVSupportsWindowless:
1125             *(NPBool*)aValue = PluginModuleChild::GetChrome()->Settings().supportsWindowless();
1126             return NPERR_NO_ERROR;
1127 #if defined(MOZ_WIDGET_GTK)
1128         case NPNVxDisplay: {
1129             if (aNPP) {
1130                 return InstCast(aNPP)->NPN_GetValue(aVariable, aValue);
1131             }
1132             else {
1133                 *(void **)aValue = xt_client_get_display();
1134             }
1135             return NPERR_NO_ERROR;
1136         }
1137         case NPNVxtAppContext:
1138             return NPERR_GENERIC_ERROR;
1139 #endif
1140         default: {
1141             if (aNPP) {
1142                 return InstCast(aNPP)->NPN_GetValue(aVariable, aValue);
1143             }
1144 
1145             NS_WARNING("Null NPP!");
1146             return NPERR_INVALID_INSTANCE_ERROR;
1147         }
1148     }
1149 
1150     NS_NOTREACHED("Shouldn't get here!");
1151     return NPERR_GENERIC_ERROR;
1152 }
1153 
1154 NPError
_setvalue(NPP aNPP,NPPVariable aVariable,void * aValue)1155 _setvalue(NPP aNPP,
1156           NPPVariable aVariable,
1157           void* aValue)
1158 {
1159     PLUGIN_LOG_DEBUG_FUNCTION;
1160     ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
1161     return InstCast(aNPP)->NPN_SetValue(aVariable, aValue);
1162 }
1163 
1164 NPError
_geturl(NPP aNPP,const char * aRelativeURL,const char * aTarget)1165 _geturl(NPP aNPP,
1166         const char* aRelativeURL,
1167         const char* aTarget)
1168 {
1169     PLUGIN_LOG_DEBUG_FUNCTION;
1170     ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
1171 
1172     NPError err;
1173     InstCast(aNPP)->CallNPN_GetURL(NullableString(aRelativeURL),
1174                                    NullableString(aTarget), &err);
1175     return err;
1176 }
1177 
1178 NPError
_posturlnotify(NPP aNPP,const char * aRelativeURL,const char * aTarget,uint32_t aLength,const char * aBuffer,NPBool aIsFile,void * aNotifyData)1179 _posturlnotify(NPP aNPP,
1180                const char* aRelativeURL,
1181                const char* aTarget,
1182                uint32_t aLength,
1183                const char* aBuffer,
1184                NPBool aIsFile,
1185                void* aNotifyData)
1186 {
1187     PLUGIN_LOG_DEBUG_FUNCTION;
1188     ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
1189 
1190     if (!aBuffer)
1191         return NPERR_INVALID_PARAM;
1192 
1193     nsCString url = NullableString(aRelativeURL);
1194     StreamNotifyChild* sn = new StreamNotifyChild(url);
1195 
1196     NPError err;
1197     InstCast(aNPP)->CallPStreamNotifyConstructor(
1198         sn, url, NullableString(aTarget), true,
1199         nsCString(aBuffer, aLength), aIsFile, &err);
1200 
1201     if (NPERR_NO_ERROR == err) {
1202         // If NPN_PostURLNotify fails, the parent will immediately send us
1203         // a PStreamNotifyDestructor, which should not call NPP_URLNotify.
1204         sn->SetValid(aNotifyData);
1205     }
1206 
1207     return err;
1208 }
1209 
1210 NPError
_posturl(NPP aNPP,const char * aRelativeURL,const char * aTarget,uint32_t aLength,const char * aBuffer,NPBool aIsFile)1211 _posturl(NPP aNPP,
1212          const char* aRelativeURL,
1213          const char* aTarget,
1214          uint32_t aLength,
1215          const char* aBuffer,
1216          NPBool aIsFile)
1217 {
1218     PLUGIN_LOG_DEBUG_FUNCTION;
1219     ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
1220 
1221     NPError err;
1222     // FIXME what should happen when |aBuffer| is null?
1223     InstCast(aNPP)->CallNPN_PostURL(NullableString(aRelativeURL),
1224                                     NullableString(aTarget),
1225                                     nsDependentCString(aBuffer, aLength),
1226                                     aIsFile, &err);
1227     return err;
1228 }
1229 
1230 NPError
_newstream(NPP aNPP,NPMIMEType aMIMEType,const char * aWindow,NPStream ** aStream)1231 _newstream(NPP aNPP,
1232            NPMIMEType aMIMEType,
1233            const char* aWindow,
1234            NPStream** aStream)
1235 {
1236     PLUGIN_LOG_DEBUG_FUNCTION;
1237     ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
1238     return InstCast(aNPP)->NPN_NewStream(aMIMEType, aWindow, aStream);
1239 }
1240 
1241 int32_t
_write(NPP aNPP,NPStream * aStream,int32_t aLength,void * aBuffer)1242 _write(NPP aNPP,
1243        NPStream* aStream,
1244        int32_t aLength,
1245        void* aBuffer)
1246 {
1247     PLUGIN_LOG_DEBUG_FUNCTION;
1248     ENSURE_PLUGIN_THREAD(0);
1249 
1250     PluginStreamChild* ps =
1251         static_cast<PluginStreamChild*>(static_cast<AStream*>(aStream->ndata));
1252     ps->EnsureCorrectInstance(InstCast(aNPP));
1253     ps->EnsureCorrectStream(aStream);
1254     return ps->NPN_Write(aLength, aBuffer);
1255 }
1256 
1257 NPError
_destroystream(NPP aNPP,NPStream * aStream,NPError aReason)1258 _destroystream(NPP aNPP,
1259                NPStream* aStream,
1260                NPError aReason)
1261 {
1262     PLUGIN_LOG_DEBUG_FUNCTION;
1263     ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
1264 
1265     PluginInstanceChild* p = InstCast(aNPP);
1266     AStream* s = static_cast<AStream*>(aStream->ndata);
1267     if (s->IsBrowserStream()) {
1268         BrowserStreamChild* bs = static_cast<BrowserStreamChild*>(s);
1269         bs->EnsureCorrectInstance(p);
1270         bs->NPN_DestroyStream(aReason);
1271     }
1272     else {
1273         PluginStreamChild* ps = static_cast<PluginStreamChild*>(s);
1274         ps->EnsureCorrectInstance(p);
1275         PPluginStreamChild::Call__delete__(ps, aReason, false);
1276     }
1277     return NPERR_NO_ERROR;
1278 }
1279 
1280 void
_status(NPP aNPP,const char * aMessage)1281 _status(NPP aNPP,
1282         const char* aMessage)
1283 {
1284     // NPN_Status is no longer supported.
1285 }
1286 
1287 void
_memfree(void * aPtr)1288 _memfree(void* aPtr)
1289 {
1290     PLUGIN_LOG_DEBUG_FUNCTION;
1291     free(aPtr);
1292 }
1293 
1294 uint32_t
_memflush(uint32_t aSize)1295 _memflush(uint32_t aSize)
1296 {
1297     return 0;
1298 }
1299 
1300 void
_reloadplugins(NPBool aReloadPages)1301 _reloadplugins(NPBool aReloadPages)
1302 {
1303     PLUGIN_LOG_DEBUG_FUNCTION;
1304     ENSURE_PLUGIN_THREAD_VOID();
1305 
1306     // Send the reload message to all modules. Chrome will need to reload from
1307     // disk and content will need to request a new list of plugin tags from
1308     // chrome.
1309     PluginModuleChild::GetChrome()->SendNPN_ReloadPlugins(!!aReloadPages);
1310 }
1311 
1312 void
_invalidaterect(NPP aNPP,NPRect * aInvalidRect)1313 _invalidaterect(NPP aNPP,
1314                 NPRect* aInvalidRect)
1315 {
1316     PLUGIN_LOG_DEBUG_FUNCTION;
1317     ENSURE_PLUGIN_THREAD_VOID();
1318     // nullptr check for nspluginwrapper (bug 548434)
1319     if (aNPP) {
1320         InstCast(aNPP)->InvalidateRect(aInvalidRect);
1321     }
1322 }
1323 
1324 void
_invalidateregion(NPP aNPP,NPRegion aInvalidRegion)1325 _invalidateregion(NPP aNPP,
1326                   NPRegion aInvalidRegion)
1327 {
1328     PLUGIN_LOG_DEBUG_FUNCTION;
1329     ENSURE_PLUGIN_THREAD_VOID();
1330     NS_WARNING("Not yet implemented!");
1331 }
1332 
1333 void
_forceredraw(NPP aNPP)1334 _forceredraw(NPP aNPP)
1335 {
1336     PLUGIN_LOG_DEBUG_FUNCTION;
1337     ENSURE_PLUGIN_THREAD_VOID();
1338 
1339     // We ignore calls to NPN_ForceRedraw. Such calls should
1340     // never be necessary.
1341 }
1342 
1343 const char*
_useragent(NPP aNPP)1344 _useragent(NPP aNPP)
1345 {
1346     PLUGIN_LOG_DEBUG_FUNCTION;
1347     ENSURE_PLUGIN_THREAD(nullptr);
1348     return PluginModuleChild::GetChrome()->GetUserAgent();
1349 }
1350 
1351 void*
_memalloc(uint32_t aSize)1352 _memalloc(uint32_t aSize)
1353 {
1354     PLUGIN_LOG_DEBUG_FUNCTION;
1355     return moz_xmalloc(aSize);
1356 }
1357 
1358 // Deprecated entry points for the old Java plugin.
1359 void* /* OJI type: JRIEnv* */
_getjavaenv(void)1360 _getjavaenv(void)
1361 {
1362     PLUGIN_LOG_DEBUG_FUNCTION;
1363     return 0;
1364 }
1365 
1366 void* /* OJI type: jref */
_getjavapeer(NPP aNPP)1367 _getjavapeer(NPP aNPP)
1368 {
1369     PLUGIN_LOG_DEBUG_FUNCTION;
1370     return 0;
1371 }
1372 
1373 bool
_invoke(NPP aNPP,NPObject * aNPObj,NPIdentifier aMethod,const NPVariant * aArgs,uint32_t aArgCount,NPVariant * aResult)1374 _invoke(NPP aNPP,
1375         NPObject* aNPObj,
1376         NPIdentifier aMethod,
1377         const NPVariant* aArgs,
1378         uint32_t aArgCount,
1379         NPVariant* aResult)
1380 {
1381     PLUGIN_LOG_DEBUG_FUNCTION;
1382     ENSURE_PLUGIN_THREAD(false);
1383 
1384     if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->invoke)
1385         return false;
1386 
1387     return aNPObj->_class->invoke(aNPObj, aMethod, aArgs, aArgCount, aResult);
1388 }
1389 
1390 bool
_invokedefault(NPP aNPP,NPObject * aNPObj,const NPVariant * aArgs,uint32_t aArgCount,NPVariant * aResult)1391 _invokedefault(NPP aNPP,
1392                NPObject* aNPObj,
1393                const NPVariant* aArgs,
1394                uint32_t aArgCount,
1395                NPVariant* aResult)
1396 {
1397     PLUGIN_LOG_DEBUG_FUNCTION;
1398     ENSURE_PLUGIN_THREAD(false);
1399 
1400     if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->invokeDefault)
1401         return false;
1402 
1403     return aNPObj->_class->invokeDefault(aNPObj, aArgs, aArgCount, aResult);
1404 }
1405 
1406 bool
_evaluate(NPP aNPP,NPObject * aObject,NPString * aScript,NPVariant * aResult)1407 _evaluate(NPP aNPP,
1408           NPObject* aObject,
1409           NPString* aScript,
1410           NPVariant* aResult)
1411 {
1412     PLUGIN_LOG_DEBUG_FUNCTION;
1413     ENSURE_PLUGIN_THREAD(false);
1414 
1415     if (!(aNPP && aObject && aScript && aResult)) {
1416         NS_ERROR("Bad arguments!");
1417         return false;
1418     }
1419 
1420     PluginScriptableObjectChild* actor =
1421       InstCast(aNPP)->GetActorForNPObject(aObject);
1422     if (!actor) {
1423         NS_ERROR("Failed to create actor?!");
1424         return false;
1425     }
1426 
1427 #ifdef XP_WIN
1428     if (gDelayFlashFocusReplyUntilEval) {
1429         ReplyMessage(0);
1430         gDelayFlashFocusReplyUntilEval = false;
1431     }
1432 #endif
1433 
1434     return actor->Evaluate(aScript, aResult);
1435 }
1436 
1437 bool
_getproperty(NPP aNPP,NPObject * aNPObj,NPIdentifier aPropertyName,NPVariant * aResult)1438 _getproperty(NPP aNPP,
1439              NPObject* aNPObj,
1440              NPIdentifier aPropertyName,
1441              NPVariant* aResult)
1442 {
1443     PLUGIN_LOG_DEBUG_FUNCTION;
1444     ENSURE_PLUGIN_THREAD(false);
1445 
1446     if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->getProperty)
1447         return false;
1448 
1449     return aNPObj->_class->getProperty(aNPObj, aPropertyName, aResult);
1450 }
1451 
1452 bool
_setproperty(NPP aNPP,NPObject * aNPObj,NPIdentifier aPropertyName,const NPVariant * aValue)1453 _setproperty(NPP aNPP,
1454              NPObject* aNPObj,
1455              NPIdentifier aPropertyName,
1456              const NPVariant* aValue)
1457 {
1458     PLUGIN_LOG_DEBUG_FUNCTION;
1459     ENSURE_PLUGIN_THREAD(false);
1460 
1461     if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->setProperty)
1462         return false;
1463 
1464     return aNPObj->_class->setProperty(aNPObj, aPropertyName, aValue);
1465 }
1466 
1467 bool
_removeproperty(NPP aNPP,NPObject * aNPObj,NPIdentifier aPropertyName)1468 _removeproperty(NPP aNPP,
1469                 NPObject* aNPObj,
1470                 NPIdentifier aPropertyName)
1471 {
1472     PLUGIN_LOG_DEBUG_FUNCTION;
1473     ENSURE_PLUGIN_THREAD(false);
1474 
1475     if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->removeProperty)
1476         return false;
1477 
1478     return aNPObj->_class->removeProperty(aNPObj, aPropertyName);
1479 }
1480 
1481 bool
_hasproperty(NPP aNPP,NPObject * aNPObj,NPIdentifier aPropertyName)1482 _hasproperty(NPP aNPP,
1483              NPObject* aNPObj,
1484              NPIdentifier aPropertyName)
1485 {
1486     PLUGIN_LOG_DEBUG_FUNCTION;
1487     ENSURE_PLUGIN_THREAD(false);
1488 
1489     if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->hasProperty)
1490         return false;
1491 
1492     return aNPObj->_class->hasProperty(aNPObj, aPropertyName);
1493 }
1494 
1495 bool
_hasmethod(NPP aNPP,NPObject * aNPObj,NPIdentifier aMethodName)1496 _hasmethod(NPP aNPP,
1497            NPObject* aNPObj,
1498            NPIdentifier aMethodName)
1499 {
1500     PLUGIN_LOG_DEBUG_FUNCTION;
1501     ENSURE_PLUGIN_THREAD(false);
1502 
1503     if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->hasMethod)
1504         return false;
1505 
1506     return aNPObj->_class->hasMethod(aNPObj, aMethodName);
1507 }
1508 
1509 bool
_enumerate(NPP aNPP,NPObject * aNPObj,NPIdentifier ** aIdentifiers,uint32_t * aCount)1510 _enumerate(NPP aNPP,
1511            NPObject* aNPObj,
1512            NPIdentifier** aIdentifiers,
1513            uint32_t* aCount)
1514 {
1515     PLUGIN_LOG_DEBUG_FUNCTION;
1516     ENSURE_PLUGIN_THREAD(false);
1517 
1518     if (!aNPP || !aNPObj || !aNPObj->_class)
1519         return false;
1520 
1521     if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(aNPObj->_class) ||
1522         !aNPObj->_class->enumerate) {
1523         *aIdentifiers = 0;
1524         *aCount = 0;
1525         return true;
1526     }
1527 
1528     return aNPObj->_class->enumerate(aNPObj, aIdentifiers, aCount);
1529 }
1530 
1531 bool
_construct(NPP aNPP,NPObject * aNPObj,const NPVariant * aArgs,uint32_t aArgCount,NPVariant * aResult)1532 _construct(NPP aNPP,
1533            NPObject* aNPObj,
1534            const NPVariant* aArgs,
1535            uint32_t aArgCount,
1536            NPVariant* aResult)
1537 {
1538     PLUGIN_LOG_DEBUG_FUNCTION;
1539     ENSURE_PLUGIN_THREAD(false);
1540 
1541     if (!aNPP || !aNPObj || !aNPObj->_class ||
1542         !NP_CLASS_STRUCT_VERSION_HAS_CTOR(aNPObj->_class) ||
1543         !aNPObj->_class->construct) {
1544         return false;
1545     }
1546 
1547     return aNPObj->_class->construct(aNPObj, aArgs, aArgCount, aResult);
1548 }
1549 
1550 void
_releasevariantvalue(NPVariant * aVariant)1551 _releasevariantvalue(NPVariant* aVariant)
1552 {
1553     PLUGIN_LOG_DEBUG_FUNCTION;
1554     // Only assert plugin thread here for consistency with in-process plugins.
1555     AssertPluginThread();
1556 
1557     if (NPVARIANT_IS_STRING(*aVariant)) {
1558         NPString str = NPVARIANT_TO_STRING(*aVariant);
1559         free(const_cast<NPUTF8*>(str.UTF8Characters));
1560     }
1561     else if (NPVARIANT_IS_OBJECT(*aVariant)) {
1562         NPObject* object = NPVARIANT_TO_OBJECT(*aVariant);
1563         if (object) {
1564             PluginModuleChild::NPN_ReleaseObject(object);
1565         }
1566     }
1567     VOID_TO_NPVARIANT(*aVariant);
1568 }
1569 
1570 void
_setexception(NPObject * aNPObj,const NPUTF8 * aMessage)1571 _setexception(NPObject* aNPObj,
1572               const NPUTF8* aMessage)
1573 {
1574     PLUGIN_LOG_DEBUG_FUNCTION;
1575     ENSURE_PLUGIN_THREAD_VOID();
1576 
1577     // Do nothing. We no longer support this API.
1578 }
1579 
1580 void
_pushpopupsenabledstate(NPP aNPP,NPBool aEnabled)1581 _pushpopupsenabledstate(NPP aNPP,
1582                         NPBool aEnabled)
1583 {
1584     PLUGIN_LOG_DEBUG_FUNCTION;
1585     ENSURE_PLUGIN_THREAD_VOID();
1586 
1587     InstCast(aNPP)->CallNPN_PushPopupsEnabledState(aEnabled ? true : false);
1588 }
1589 
1590 void
_poppopupsenabledstate(NPP aNPP)1591 _poppopupsenabledstate(NPP aNPP)
1592 {
1593     PLUGIN_LOG_DEBUG_FUNCTION;
1594     ENSURE_PLUGIN_THREAD_VOID();
1595 
1596     InstCast(aNPP)->CallNPN_PopPopupsEnabledState();
1597 }
1598 
1599 void
_pluginthreadasynccall(NPP aNPP,PluginThreadCallback aFunc,void * aUserData)1600 _pluginthreadasynccall(NPP aNPP,
1601                        PluginThreadCallback aFunc,
1602                        void* aUserData)
1603 {
1604     PLUGIN_LOG_DEBUG_FUNCTION;
1605     if (!aFunc)
1606         return;
1607 
1608     InstCast(aNPP)->AsyncCall(aFunc, aUserData);
1609 }
1610 
1611 NPError
_getvalueforurl(NPP npp,NPNURLVariable variable,const char * url,char ** value,uint32_t * len)1612 _getvalueforurl(NPP npp, NPNURLVariable variable, const char *url,
1613                 char **value, uint32_t *len)
1614 {
1615     PLUGIN_LOG_DEBUG_FUNCTION;
1616     AssertPluginThread();
1617 
1618     if (!url)
1619         return NPERR_INVALID_URL;
1620 
1621     if (!npp || !value || !len)
1622         return NPERR_INVALID_PARAM;
1623 
1624     switch (variable) {
1625     case NPNURLVCookie:
1626     case NPNURLVProxy:
1627         nsCString v;
1628         NPError result;
1629         InstCast(npp)->
1630             CallNPN_GetValueForURL(variable, nsCString(url), &v, &result);
1631         if (NPERR_NO_ERROR == result) {
1632             *value = ToNewCString(v);
1633             *len = v.Length();
1634         }
1635         return result;
1636     }
1637 
1638     return NPERR_INVALID_PARAM;
1639 }
1640 
1641 NPError
_setvalueforurl(NPP npp,NPNURLVariable variable,const char * url,const char * value,uint32_t len)1642 _setvalueforurl(NPP npp, NPNURLVariable variable, const char *url,
1643                 const char *value, uint32_t len)
1644 {
1645     PLUGIN_LOG_DEBUG_FUNCTION;
1646     AssertPluginThread();
1647 
1648     if (!value)
1649         return NPERR_INVALID_PARAM;
1650 
1651     if (!url)
1652         return NPERR_INVALID_URL;
1653 
1654     switch (variable) {
1655     case NPNURLVCookie:
1656     case NPNURLVProxy:
1657         NPError result;
1658         InstCast(npp)->CallNPN_SetValueForURL(variable, nsCString(url),
1659                                               nsDependentCString(value, len),
1660                                               &result);
1661         return result;
1662     }
1663 
1664     return NPERR_INVALID_PARAM;
1665 }
1666 
1667 NPError
_getauthenticationinfo(NPP npp,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)1668 _getauthenticationinfo(NPP npp, const char *protocol,
1669                        const char *host, int32_t port,
1670                        const char *scheme, const char *realm,
1671                        char **username, uint32_t *ulen,
1672                        char **password, uint32_t *plen)
1673 {
1674     PLUGIN_LOG_DEBUG_FUNCTION;
1675     AssertPluginThread();
1676 
1677     if (!protocol || !host || !scheme || !realm || !username || !ulen ||
1678         !password || !plen)
1679         return NPERR_INVALID_PARAM;
1680 
1681     nsCString u;
1682     nsCString p;
1683     NPError result;
1684     InstCast(npp)->
1685         CallNPN_GetAuthenticationInfo(nsDependentCString(protocol),
1686                                       nsDependentCString(host),
1687                                       port,
1688                                       nsDependentCString(scheme),
1689                                       nsDependentCString(realm),
1690                                       &u, &p, &result);
1691     if (NPERR_NO_ERROR == result) {
1692         *username = ToNewCString(u);
1693         *ulen = u.Length();
1694         *password = ToNewCString(p);
1695         *plen = p.Length();
1696     }
1697     return result;
1698 }
1699 
1700 uint32_t
_scheduletimer(NPP npp,uint32_t interval,NPBool repeat,void (* timerFunc)(NPP npp,uint32_t timerID))1701 _scheduletimer(NPP npp, uint32_t interval, NPBool repeat,
1702                void (*timerFunc)(NPP npp, uint32_t timerID))
1703 {
1704     PLUGIN_LOG_DEBUG_FUNCTION;
1705     AssertPluginThread();
1706     return InstCast(npp)->ScheduleTimer(interval, repeat, timerFunc);
1707 }
1708 
1709 void
_unscheduletimer(NPP npp,uint32_t timerID)1710 _unscheduletimer(NPP npp, uint32_t timerID)
1711 {
1712     PLUGIN_LOG_DEBUG_FUNCTION;
1713     AssertPluginThread();
1714     InstCast(npp)->UnscheduleTimer(timerID);
1715 }
1716 
1717 
1718 #ifdef OS_MACOSX
ProcessBrowserEvents(void * pluginModule)1719 static void ProcessBrowserEvents(void* pluginModule) {
1720     PluginModuleChild* pmc = static_cast<PluginModuleChild*>(pluginModule);
1721 
1722     if (!pmc)
1723         return;
1724 
1725     pmc->CallProcessSomeEvents();
1726 }
1727 #endif
1728 
1729 NPError
_popupcontextmenu(NPP instance,NPMenu * menu)1730 _popupcontextmenu(NPP instance, NPMenu* menu)
1731 {
1732     PLUGIN_LOG_DEBUG_FUNCTION;
1733     AssertPluginThread();
1734 
1735 #ifdef MOZ_WIDGET_COCOA
1736     double pluginX, pluginY;
1737     double screenX, screenY;
1738 
1739     const NPCocoaEvent* currentEvent = InstCast(instance)->getCurrentEvent();
1740     if (!currentEvent) {
1741         return NPERR_GENERIC_ERROR;
1742     }
1743 
1744     // Ensure that the events has an x/y value.
1745     if (currentEvent->type != NPCocoaEventMouseDown    &&
1746         currentEvent->type != NPCocoaEventMouseUp      &&
1747         currentEvent->type != NPCocoaEventMouseMoved   &&
1748         currentEvent->type != NPCocoaEventMouseEntered &&
1749         currentEvent->type != NPCocoaEventMouseExited  &&
1750         currentEvent->type != NPCocoaEventMouseDragged) {
1751         return NPERR_GENERIC_ERROR;
1752     }
1753 
1754     pluginX = currentEvent->data.mouse.pluginX;
1755     pluginY = currentEvent->data.mouse.pluginY;
1756 
1757     if ((pluginX < 0.0) || (pluginY < 0.0))
1758         return NPERR_GENERIC_ERROR;
1759 
1760     NPBool success = _convertpoint(instance,
1761                                   pluginX,  pluginY, NPCoordinateSpacePlugin,
1762                                  &screenX, &screenY, NPCoordinateSpaceScreen);
1763 
1764     if (success) {
1765         return mozilla::plugins::PluginUtilsOSX::ShowCocoaContextMenu(menu,
1766                                     screenX, screenY,
1767                                     InstCast(instance)->Manager(),
1768                                     ProcessBrowserEvents);
1769     } else {
1770         NS_WARNING("Convertpoint failed, could not created contextmenu.");
1771         return NPERR_GENERIC_ERROR;
1772     }
1773 
1774 #else
1775     NS_WARNING("Not supported on this platform!");
1776     return NPERR_GENERIC_ERROR;
1777 #endif
1778 }
1779 
1780 NPBool
_convertpoint(NPP instance,double sourceX,double sourceY,NPCoordinateSpace sourceSpace,double * destX,double * destY,NPCoordinateSpace destSpace)1781 _convertpoint(NPP instance,
1782               double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
1783               double *destX, double *destY, NPCoordinateSpace destSpace)
1784 {
1785     PLUGIN_LOG_DEBUG_FUNCTION;
1786     if (!IsPluginThread()) {
1787         NS_WARNING("Not running on the plugin's main thread!");
1788         return false;
1789     }
1790 
1791     double rDestX = 0;
1792     bool ignoreDestX = !destX;
1793     double rDestY = 0;
1794     bool ignoreDestY = !destY;
1795     bool result = false;
1796     InstCast(instance)->CallNPN_ConvertPoint(sourceX, ignoreDestX, sourceY, ignoreDestY, sourceSpace, destSpace,
1797                                              &rDestX,  &rDestY, &result);
1798     if (result) {
1799         if (destX)
1800             *destX = rDestX;
1801         if (destY)
1802             *destY = rDestY;
1803     }
1804 
1805     return result;
1806 }
1807 
1808 void
_urlredirectresponse(NPP instance,void * notifyData,NPBool allow)1809 _urlredirectresponse(NPP instance, void* notifyData, NPBool allow)
1810 {
1811     InstCast(instance)->NPN_URLRedirectResponse(notifyData, allow);
1812 }
1813 
1814 NPError
_initasyncsurface(NPP instance,NPSize * size,NPImageFormat format,void * initData,NPAsyncSurface * surface)1815 _initasyncsurface(NPP instance, NPSize *size,
1816                   NPImageFormat format, void *initData,
1817                   NPAsyncSurface *surface)
1818 {
1819     return InstCast(instance)->NPN_InitAsyncSurface(size, format, initData, surface);
1820 }
1821 
1822 NPError
_finalizeasyncsurface(NPP instance,NPAsyncSurface * surface)1823 _finalizeasyncsurface(NPP instance, NPAsyncSurface *surface)
1824 {
1825     return InstCast(instance)->NPN_FinalizeAsyncSurface(surface);
1826 }
1827 
1828 void
_setcurrentasyncsurface(NPP instance,NPAsyncSurface * surface,NPRect * changed)1829 _setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed)
1830 {
1831     InstCast(instance)->NPN_SetCurrentAsyncSurface(surface, changed);
1832 }
1833 
1834 } /* namespace child */
1835 } /* namespace plugins */
1836 } /* namespace mozilla */
1837 
1838 //-----------------------------------------------------------------------------
1839 
1840 bool
RecvSettingChanged(const PluginSettings & aSettings)1841 PluginModuleChild::RecvSettingChanged(const PluginSettings& aSettings)
1842 {
1843     mCachedSettings = aSettings;
1844     return true;
1845 }
1846 
1847 bool
AnswerNP_GetEntryPoints(NPError * _retval)1848 PluginModuleChild::AnswerNP_GetEntryPoints(NPError* _retval)
1849 {
1850     PLUGIN_LOG_DEBUG_METHOD;
1851     AssertPluginThread();
1852     MOZ_ASSERT(mIsChrome);
1853 
1854 #if defined(OS_LINUX) || defined(OS_BSD)
1855     return true;
1856 #elif defined(OS_WIN) || defined(OS_MACOSX)
1857     *_retval = mGetEntryPointsFunc(&mFunctions);
1858     return true;
1859 #else
1860 #  error Please implement me for your platform
1861 #endif
1862 }
1863 
1864 bool
AnswerNP_Initialize(const PluginSettings & aSettings,NPError * rv)1865 PluginModuleChild::AnswerNP_Initialize(const PluginSettings& aSettings, NPError* rv)
1866 {
1867     *rv = DoNP_Initialize(aSettings);
1868     return true;
1869 }
1870 
1871 bool
RecvAsyncNP_Initialize(const PluginSettings & aSettings)1872 PluginModuleChild::RecvAsyncNP_Initialize(const PluginSettings& aSettings)
1873 {
1874     NPError error = DoNP_Initialize(aSettings);
1875     return SendNP_InitializeResult(error);
1876 }
1877 
1878 NPError
DoNP_Initialize(const PluginSettings & aSettings)1879 PluginModuleChild::DoNP_Initialize(const PluginSettings& aSettings)
1880 {
1881     PLUGIN_LOG_DEBUG_METHOD;
1882     AssertPluginThread();
1883     MOZ_ASSERT(mIsChrome);
1884 
1885     mCachedSettings = aSettings;
1886 
1887 #ifdef OS_WIN
1888     SetEventHooks();
1889 #endif
1890 
1891 #ifdef MOZ_X11
1892     // Send the parent our X socket to act as a proxy reference for our X
1893     // resources.
1894     int xSocketFd = ConnectionNumber(DefaultXDisplay());
1895     SendBackUpXResources(FileDescriptor(xSocketFd));
1896 #endif
1897 
1898     NPError result;
1899 #if defined(OS_LINUX) || defined(OS_BSD)
1900     result = mInitializeFunc(&sBrowserFuncs, &mFunctions);
1901 #elif defined(OS_WIN) || defined(OS_MACOSX)
1902     result = mInitializeFunc(&sBrowserFuncs);
1903 #else
1904 #  error Please implement me for your platform
1905 #endif
1906 
1907     return result;
1908 }
1909 
1910 #if defined(XP_WIN)
1911 
1912 // Windows 8 RTM (kernelbase's version is 6.2.9200.16384) doesn't call
1913 // CreateFileW from CreateFileA.
1914 // So we hook CreateFileA too to use CreateFileW hook.
1915 
1916 static HANDLE WINAPI
CreateFileAHookFn(LPCSTR fname,DWORD access,DWORD share,LPSECURITY_ATTRIBUTES security,DWORD creation,DWORD flags,HANDLE ftemplate)1917 CreateFileAHookFn(LPCSTR fname, DWORD access, DWORD share,
1918                   LPSECURITY_ATTRIBUTES security, DWORD creation, DWORD flags,
1919                   HANDLE ftemplate)
1920 {
1921     while (true) { // goto out
1922         // Our hook is for mms.cfg into \Windows\System32\Macromed\Flash
1923         // We don't requrie supporting too long path.
1924         WCHAR unicodeName[MAX_PATH];
1925         size_t len = strlen(fname);
1926 
1927         if (len >= MAX_PATH) {
1928             break;
1929         }
1930 
1931         // We call to CreateFileW for workaround of Windows 8 RTM
1932         int newLen = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, fname,
1933                                          len, unicodeName, MAX_PATH);
1934         if (newLen == 0 || newLen >= MAX_PATH) {
1935             break;
1936         }
1937         unicodeName[newLen] = '\0';
1938 
1939         return CreateFileW(unicodeName, access, share, security, creation, flags, ftemplate);
1940     }
1941 
1942     return sCreateFileAStub(fname, access, share, security, creation, flags,
1943                             ftemplate);
1944 }
1945 
1946 static bool
GetLocalLowTempPath(size_t aLen,LPWSTR aPath)1947 GetLocalLowTempPath(size_t aLen, LPWSTR aPath)
1948 {
1949     NS_NAMED_LITERAL_STRING(tempname, "\\Temp");
1950     LPWSTR path;
1951     if (SUCCEEDED(WinUtils::SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0,
1952                                                  nullptr, &path))) {
1953         if (wcslen(path) + tempname.Length() < aLen) {
1954             wcscpy(aPath, path);
1955             wcscat(aPath, tempname.get());
1956             ::CoTaskMemFree(path);
1957             return true;
1958         }
1959         ::CoTaskMemFree(path);
1960     }
1961 
1962     // XP doesn't support SHGetKnownFolderPath and LocalLow
1963     if (!GetTempPathW(aLen, aPath)) {
1964         return false;
1965     }
1966     return true;
1967 }
1968 
1969 HANDLE WINAPI
CreateFileWHookFn(LPCWSTR fname,DWORD access,DWORD share,LPSECURITY_ATTRIBUTES security,DWORD creation,DWORD flags,HANDLE ftemplate)1970 CreateFileWHookFn(LPCWSTR fname, DWORD access, DWORD share,
1971                   LPSECURITY_ATTRIBUTES security, DWORD creation, DWORD flags,
1972                   HANDLE ftemplate)
1973 {
1974     static const WCHAR kConfigFile[] = L"mms.cfg";
1975     static const size_t kConfigLength = ArrayLength(kConfigFile) - 1;
1976 
1977     while (true) { // goto out, in sheep's clothing
1978         size_t len = wcslen(fname);
1979         if (len < kConfigLength) {
1980             break;
1981         }
1982         if (wcscmp(fname + len - kConfigLength, kConfigFile) != 0) {
1983             break;
1984         }
1985 
1986         // This is the config file we want to rewrite
1987         WCHAR tempPath[MAX_PATH+1];
1988         if (GetLocalLowTempPath(MAX_PATH, tempPath) == 0) {
1989             break;
1990         }
1991         WCHAR tempFile[MAX_PATH+1];
1992         if (GetTempFileNameW(tempPath, L"fx", 0, tempFile) == 0) {
1993             break;
1994         }
1995         HANDLE replacement =
1996             sCreateFileWStub(tempFile, GENERIC_READ | GENERIC_WRITE, share,
1997                              security, TRUNCATE_EXISTING,
1998                              FILE_ATTRIBUTE_TEMPORARY |
1999                                FILE_FLAG_DELETE_ON_CLOSE,
2000                              NULL);
2001         if (replacement == INVALID_HANDLE_VALUE) {
2002             break;
2003         }
2004 
2005         HANDLE original = sCreateFileWStub(fname, access, share, security,
2006                                            creation, flags, ftemplate);
2007         if (original != INVALID_HANDLE_VALUE) {
2008             // copy original to replacement
2009             static const size_t kBufferSize = 1024;
2010             char buffer[kBufferSize];
2011             DWORD bytes;
2012             while (ReadFile(original, buffer, kBufferSize, &bytes, NULL)) {
2013                 if (bytes == 0) {
2014                     break;
2015                 }
2016                 DWORD wbytes;
2017                 WriteFile(replacement, buffer, bytes, &wbytes, NULL);
2018                 if (bytes < kBufferSize) {
2019                     break;
2020                 }
2021             }
2022             CloseHandle(original);
2023         }
2024         static const char kSettingString[] = "\nProtectedMode=0\n";
2025         DWORD wbytes;
2026         WriteFile(replacement, static_cast<const void*>(kSettingString),
2027                   sizeof(kSettingString) - 1, &wbytes, NULL);
2028         SetFilePointer(replacement, 0, NULL, FILE_BEGIN);
2029         return replacement;
2030     }
2031     return sCreateFileWStub(fname, access, share, security, creation, flags,
2032                             ftemplate);
2033 }
2034 
2035 void
HookProtectedMode()2036 PluginModuleChild::HookProtectedMode()
2037 {
2038     sKernel32Intercept.Init("kernel32.dll");
2039     sKernel32Intercept.AddHook("CreateFileW",
2040                                reinterpret_cast<intptr_t>(CreateFileWHookFn),
2041                                (void**) &sCreateFileWStub);
2042     sKernel32Intercept.AddHook("CreateFileA",
2043                                reinterpret_cast<intptr_t>(CreateFileAHookFn),
2044                                (void**) &sCreateFileAStub);
2045 }
2046 
2047 BOOL WINAPI
PMCGetWindowInfoHook(HWND hWnd,PWINDOWINFO pwi)2048 PMCGetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi)
2049 {
2050   if (!pwi)
2051       return FALSE;
2052 
2053   if (!sGetWindowInfoPtrStub) {
2054      NS_ASSERTION(FALSE, "Something is horribly wrong in PMCGetWindowInfoHook!");
2055      return FALSE;
2056   }
2057 
2058   if (!sBrowserHwnd) {
2059       wchar_t szClass[20];
2060       if (GetClassNameW(hWnd, szClass, ArrayLength(szClass)) &&
2061           !wcscmp(szClass, kMozillaWindowClass)) {
2062           sBrowserHwnd = hWnd;
2063       }
2064   }
2065   // Oddity: flash does strange rect comparisons for mouse input destined for
2066   // it's internal settings window. Post removing sub widgets for tabs, touch
2067   // this up so they get the rect they expect.
2068   // XXX potentially tie this to a specific major version?
2069   BOOL result = sGetWindowInfoPtrStub(hWnd, pwi);
2070   if (sBrowserHwnd && sBrowserHwnd == hWnd)
2071       pwi->rcWindow = pwi->rcClient;
2072   return result;
2073 }
2074 
2075 SHORT WINAPI PMCGetKeyState(int aVirtKey);
2076 
2077 // Runnable that performs GetKeyState on the main thread so that it can be
2078 // synchronously run on the PluginModuleParent via IPC.
2079 // The task alerts the given semaphore when it is finished.
2080 class GetKeyStateTask : public Runnable
2081 {
2082     SHORT* mKeyState;
2083     int mVirtKey;
2084     HANDLE mSemaphore;
2085 
2086 public:
GetKeyStateTask(int aVirtKey,HANDLE aSemaphore,SHORT * aKeyState)2087     explicit GetKeyStateTask(int aVirtKey, HANDLE aSemaphore, SHORT* aKeyState) :
2088         mVirtKey(aVirtKey), mSemaphore(aSemaphore), mKeyState(aKeyState)
2089     {}
2090 
Run()2091     NS_IMETHOD Run() override
2092     {
2093         PLUGIN_LOG_DEBUG_METHOD;
2094         AssertPluginThread();
2095         *mKeyState = PMCGetKeyState(mVirtKey);
2096         if (!ReleaseSemaphore(mSemaphore, 1, nullptr)) {
2097             return NS_ERROR_FAILURE;
2098         }
2099         return NS_OK;
2100     }
2101 };
2102 
2103 // static
2104 SHORT WINAPI
PMCGetKeyState(int aVirtKey)2105 PMCGetKeyState(int aVirtKey)
2106 {
2107     if (!IsPluginThread()) {
2108         // synchronously request the key state from the main thread
2109 
2110         // Start a semaphore at 0.  We Release the semaphore (bringing its count to 1)
2111         // when the synchronous call is done.
2112         HANDLE semaphore = CreateSemaphore(NULL, 0, 1, NULL);
2113         if (semaphore == nullptr) {
2114             MOZ_ASSERT(semaphore != nullptr);
2115             return 0;
2116         }
2117 
2118         SHORT keyState;
2119         RefPtr<GetKeyStateTask> task = new GetKeyStateTask(aVirtKey, semaphore, &keyState);
2120         ProcessChild::message_loop()->PostTask(task.forget());
2121         DWORD err = WaitForSingleObject(semaphore, INFINITE);
2122         if (err != WAIT_FAILED) {
2123             CloseHandle(semaphore);
2124             return keyState;
2125         }
2126         PLUGIN_LOG_DEBUG(("Error while waiting for GetKeyState semaphore: %d",
2127                           GetLastError()));
2128         MOZ_ASSERT(err != WAIT_FAILED);
2129         CloseHandle(semaphore);
2130         return 0;
2131     }
2132     PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
2133     if (chromeInstance) {
2134         int16_t ret = 0;
2135         if (chromeInstance->CallGetKeyState(aVirtKey, &ret)) {
2136           return ret;
2137         }
2138     }
2139     return sGetKeyStatePtrStub(aVirtKey);
2140 }
2141 #endif
2142 
2143 PPluginInstanceChild*
AllocPPluginInstanceChild(const nsCString & aMimeType,const uint16_t & aMode,const InfallibleTArray<nsCString> & aNames,const InfallibleTArray<nsCString> & aValues)2144 PluginModuleChild::AllocPPluginInstanceChild(const nsCString& aMimeType,
2145                                              const uint16_t& aMode,
2146                                              const InfallibleTArray<nsCString>& aNames,
2147                                              const InfallibleTArray<nsCString>& aValues)
2148 {
2149     PLUGIN_LOG_DEBUG_METHOD;
2150     AssertPluginThread();
2151 
2152     // In e10s, gChromeInstance hands out quirks to instances, but never
2153     // allocates an instance on its own. Make sure it gets the latest copy
2154     // of quirks once we have them. Also note, with process-per-tab, we may
2155     // have multiple PluginModuleChilds in the same plugin process, so only
2156     // initialize this once in gChromeInstance, which is a singleton.
2157     GetChrome()->InitQuirksModes(aMimeType);
2158     mQuirks = GetChrome()->mQuirks;
2159 
2160 #ifdef XP_WIN
2161     sUser32Intercept.Init("user32.dll");
2162     if ((mQuirks & QUIRK_FLASH_HOOK_GETWINDOWINFO) &&
2163         !sGetWindowInfoPtrStub) {
2164         sUser32Intercept.AddHook("GetWindowInfo", reinterpret_cast<intptr_t>(PMCGetWindowInfoHook),
2165                                  (void**) &sGetWindowInfoPtrStub);
2166     }
2167 
2168     if ((mQuirks & QUIRK_FLASH_HOOK_GETKEYSTATE) &&
2169         !sGetKeyStatePtrStub) {
2170         sUser32Intercept.AddHook("GetKeyState", reinterpret_cast<intptr_t>(PMCGetKeyState),
2171                                  (void**) &sGetKeyStatePtrStub);
2172     }
2173 #endif
2174 
2175     return new PluginInstanceChild(&mFunctions, aMimeType, aMode, aNames,
2176                                    aValues);
2177 }
2178 
2179 void
InitQuirksModes(const nsCString & aMimeType)2180 PluginModuleChild::InitQuirksModes(const nsCString& aMimeType)
2181 {
2182     if (mQuirks != QUIRKS_NOT_INITIALIZED) {
2183       return;
2184     }
2185 
2186     mQuirks = GetQuirksFromMimeTypeAndFilename(aMimeType, mPluginFilename);
2187 }
2188 
2189 bool
AnswerModuleSupportsAsyncRender(bool * aResult)2190 PluginModuleChild::AnswerModuleSupportsAsyncRender(bool* aResult)
2191 {
2192 #if defined(XP_WIN)
2193     *aResult = gChromeInstance->mAsyncRenderSupport;
2194     return true;
2195 #else
2196     NS_NOTREACHED("Shouldn't get here!");
2197     return false;
2198 #endif
2199 }
2200 
2201 bool
RecvPPluginInstanceConstructor(PPluginInstanceChild * aActor,const nsCString & aMimeType,const uint16_t & aMode,InfallibleTArray<nsCString> && aNames,InfallibleTArray<nsCString> && aValues)2202 PluginModuleChild::RecvPPluginInstanceConstructor(PPluginInstanceChild* aActor,
2203                                                   const nsCString& aMimeType,
2204                                                   const uint16_t& aMode,
2205                                                   InfallibleTArray<nsCString>&& aNames,
2206                                                   InfallibleTArray<nsCString>&& aValues)
2207 {
2208     PLUGIN_LOG_DEBUG_METHOD;
2209     AssertPluginThread();
2210 
2211     NS_ASSERTION(aActor, "Null actor!");
2212     return true;
2213 }
2214 
2215 bool
AnswerSyncNPP_New(PPluginInstanceChild * aActor,NPError * rv)2216 PluginModuleChild::AnswerSyncNPP_New(PPluginInstanceChild* aActor, NPError* rv)
2217 {
2218     PLUGIN_LOG_DEBUG_METHOD;
2219     PluginInstanceChild* childInstance =
2220         reinterpret_cast<PluginInstanceChild*>(aActor);
2221     AssertPluginThread();
2222     *rv = childInstance->DoNPP_New();
2223     return true;
2224 }
2225 
2226 class AsyncNewResultSender : public ChildAsyncCall
2227 {
2228 public:
AsyncNewResultSender(PluginInstanceChild * aInstance,NPError aResult)2229     AsyncNewResultSender(PluginInstanceChild* aInstance, NPError aResult)
2230         : ChildAsyncCall(aInstance, nullptr, nullptr)
2231         , mResult(aResult)
2232     {
2233     }
2234 
Run()2235     NS_IMETHOD Run() override
2236     {
2237         RemoveFromAsyncList();
2238         DebugOnly<bool> sendOk = mInstance->SendAsyncNPP_NewResult(mResult);
2239         MOZ_ASSERT(sendOk);
2240         return NS_OK;
2241     }
2242 
2243 private:
2244     NPError  mResult;
2245 };
2246 
2247 static void
RunAsyncNPP_New(void * aChildInstance)2248 RunAsyncNPP_New(void* aChildInstance)
2249 {
2250     MOZ_ASSERT(aChildInstance);
2251     PluginInstanceChild* childInstance =
2252         static_cast<PluginInstanceChild*>(aChildInstance);
2253     NPError rv = childInstance->DoNPP_New();
2254     RefPtr<AsyncNewResultSender> task =
2255         new AsyncNewResultSender(childInstance, rv);
2256     childInstance->PostChildAsyncCall(task.forget());
2257 }
2258 
2259 bool
RecvAsyncNPP_New(PPluginInstanceChild * aActor)2260 PluginModuleChild::RecvAsyncNPP_New(PPluginInstanceChild* aActor)
2261 {
2262     PLUGIN_LOG_DEBUG_METHOD;
2263     PluginInstanceChild* childInstance =
2264         reinterpret_cast<PluginInstanceChild*>(aActor);
2265     AssertPluginThread();
2266     // We don't want to run NPP_New async from within nested calls
2267     childInstance->AsyncCall(&RunAsyncNPP_New, childInstance);
2268     return true;
2269 }
2270 
2271 bool
DeallocPPluginInstanceChild(PPluginInstanceChild * aActor)2272 PluginModuleChild::DeallocPPluginInstanceChild(PPluginInstanceChild* aActor)
2273 {
2274     PLUGIN_LOG_DEBUG_METHOD;
2275     AssertPluginThread();
2276 
2277     delete aActor;
2278 
2279     return true;
2280 }
2281 
2282 NPObject*
NPN_CreateObject(NPP aNPP,NPClass * aClass)2283 PluginModuleChild::NPN_CreateObject(NPP aNPP, NPClass* aClass)
2284 {
2285     PLUGIN_LOG_DEBUG_FUNCTION;
2286     ENSURE_PLUGIN_THREAD(nullptr);
2287 
2288     PluginInstanceChild* i = InstCast(aNPP);
2289     if (i->mDeletingHash) {
2290         NS_ERROR("Plugin used NPP after NPP_Destroy");
2291         return nullptr;
2292     }
2293 
2294     NPObject* newObject;
2295     if (aClass && aClass->allocate) {
2296         newObject = aClass->allocate(aNPP, aClass);
2297     }
2298     else {
2299         newObject = reinterpret_cast<NPObject*>(child::_memalloc(sizeof(NPObject)));
2300     }
2301 
2302     if (newObject) {
2303         newObject->_class = aClass;
2304         newObject->referenceCount = 1;
2305         NS_LOG_ADDREF(newObject, 1, "NPObject", sizeof(NPObject));
2306     }
2307 
2308     PluginScriptableObjectChild::RegisterObject(newObject, i);
2309 
2310     return newObject;
2311 }
2312 
2313 NPObject*
NPN_RetainObject(NPObject * aNPObj)2314 PluginModuleChild::NPN_RetainObject(NPObject* aNPObj)
2315 {
2316     AssertPluginThread();
2317 
2318 #ifdef NS_BUILD_REFCNT_LOGGING
2319     int32_t refCnt =
2320 #endif
2321     PR_ATOMIC_INCREMENT((int32_t*)&aNPObj->referenceCount);
2322     NS_LOG_ADDREF(aNPObj, refCnt, "NPObject", sizeof(NPObject));
2323 
2324     return aNPObj;
2325 }
2326 
2327 void
NPN_ReleaseObject(NPObject * aNPObj)2328 PluginModuleChild::NPN_ReleaseObject(NPObject* aNPObj)
2329 {
2330     AssertPluginThread();
2331 
2332     PluginInstanceChild* instance = PluginScriptableObjectChild::GetInstanceForNPObject(aNPObj);
2333     if (!instance) {
2334         NS_ERROR("Releasing object not in mObjectMap?");
2335         return;
2336     }
2337 
2338     DeletingObjectEntry* doe = nullptr;
2339     if (instance->mDeletingHash) {
2340         doe = instance->mDeletingHash->GetEntry(aNPObj);
2341         if (!doe) {
2342             NS_ERROR("An object for a destroyed instance isn't in the instance deletion hash");
2343             return;
2344         }
2345         if (doe->mDeleted)
2346             return;
2347     }
2348 
2349     int32_t refCnt = PR_ATOMIC_DECREMENT((int32_t*)&aNPObj->referenceCount);
2350     NS_LOG_RELEASE(aNPObj, refCnt, "NPObject");
2351 
2352     if (refCnt == 0) {
2353         DeallocNPObject(aNPObj);
2354         if (doe)
2355             doe->mDeleted = true;
2356     }
2357     return;
2358 }
2359 
2360 void
DeallocNPObject(NPObject * aNPObj)2361 PluginModuleChild::DeallocNPObject(NPObject* aNPObj)
2362 {
2363     if (aNPObj->_class && aNPObj->_class->deallocate) {
2364         aNPObj->_class->deallocate(aNPObj);
2365     } else {
2366         child::_memfree(aNPObj);
2367     }
2368 
2369     PluginScriptableObjectChild* actor = PluginScriptableObjectChild::GetActorForNPObject(aNPObj);
2370     if (actor)
2371         actor->NPObjectDestroyed();
2372 
2373     PluginScriptableObjectChild::UnregisterObject(aNPObj);
2374 }
2375 
2376 NPIdentifier
NPN_GetStringIdentifier(const NPUTF8 * aName)2377 PluginModuleChild::NPN_GetStringIdentifier(const NPUTF8* aName)
2378 {
2379     PLUGIN_LOG_DEBUG_FUNCTION;
2380     AssertPluginThread();
2381 
2382     if (!aName)
2383         return 0;
2384 
2385     nsDependentCString name(aName);
2386     PluginIdentifier ident(name);
2387     PluginScriptableObjectChild::StackIdentifier stackID(ident);
2388     stackID.MakePermanent();
2389     return stackID.ToNPIdentifier();
2390 }
2391 
2392 void
NPN_GetStringIdentifiers(const NPUTF8 ** aNames,int32_t aNameCount,NPIdentifier * aIdentifiers)2393 PluginModuleChild::NPN_GetStringIdentifiers(const NPUTF8** aNames,
2394                                             int32_t aNameCount,
2395                                             NPIdentifier* aIdentifiers)
2396 {
2397     PLUGIN_LOG_DEBUG_FUNCTION;
2398     AssertPluginThread();
2399 
2400     if (!(aNames && aNameCount > 0 && aIdentifiers)) {
2401         NS_RUNTIMEABORT("Bad input! Headed for a crash!");
2402     }
2403 
2404     for (int32_t index = 0; index < aNameCount; ++index) {
2405         if (!aNames[index]) {
2406             aIdentifiers[index] = 0;
2407             continue;
2408         }
2409         nsDependentCString name(aNames[index]);
2410         PluginIdentifier ident(name);
2411         PluginScriptableObjectChild::StackIdentifier stackID(ident);
2412         stackID.MakePermanent();
2413         aIdentifiers[index] = stackID.ToNPIdentifier();
2414     }
2415 }
2416 
2417 bool
NPN_IdentifierIsString(NPIdentifier aIdentifier)2418 PluginModuleChild::NPN_IdentifierIsString(NPIdentifier aIdentifier)
2419 {
2420     PLUGIN_LOG_DEBUG_FUNCTION;
2421 
2422     PluginScriptableObjectChild::StackIdentifier stack(aIdentifier);
2423     return stack.IsString();
2424 }
2425 
2426 NPIdentifier
NPN_GetIntIdentifier(int32_t aIntId)2427 PluginModuleChild::NPN_GetIntIdentifier(int32_t aIntId)
2428 {
2429     PLUGIN_LOG_DEBUG_FUNCTION;
2430     AssertPluginThread();
2431 
2432     PluginIdentifier ident(aIntId);
2433     PluginScriptableObjectChild::StackIdentifier stackID(ident);
2434     stackID.MakePermanent();
2435     return stackID.ToNPIdentifier();
2436 }
2437 
2438 NPUTF8*
NPN_UTF8FromIdentifier(NPIdentifier aIdentifier)2439 PluginModuleChild::NPN_UTF8FromIdentifier(NPIdentifier aIdentifier)
2440 {
2441     PLUGIN_LOG_DEBUG_FUNCTION;
2442 
2443     PluginScriptableObjectChild::StackIdentifier stackID(aIdentifier);
2444     if (stackID.IsString()) {
2445         return ToNewCString(stackID.GetString());
2446     }
2447     return nullptr;
2448 }
2449 
2450 int32_t
NPN_IntFromIdentifier(NPIdentifier aIdentifier)2451 PluginModuleChild::NPN_IntFromIdentifier(NPIdentifier aIdentifier)
2452 {
2453     PLUGIN_LOG_DEBUG_FUNCTION;
2454 
2455     PluginScriptableObjectChild::StackIdentifier stackID(aIdentifier);
2456     if (!stackID.IsString()) {
2457         return stackID.GetInt();
2458     }
2459     return INT32_MIN;
2460 }
2461 
2462 #ifdef OS_WIN
2463 void
EnteredCall()2464 PluginModuleChild::EnteredCall()
2465 {
2466     mIncallPumpingStack.AppendElement();
2467 }
2468 
2469 void
ExitedCall()2470 PluginModuleChild::ExitedCall()
2471 {
2472     NS_ASSERTION(mIncallPumpingStack.Length(), "mismatched entered/exited");
2473     uint32_t len = mIncallPumpingStack.Length();
2474     const IncallFrame& f = mIncallPumpingStack[len - 1];
2475     if (f._spinning)
2476         MessageLoop::current()->SetNestableTasksAllowed(f._savedNestableTasksAllowed);
2477 
2478     mIncallPumpingStack.TruncateLength(len - 1);
2479 }
2480 
2481 LRESULT CALLBACK
CallWindowProcHook(int nCode,WPARAM wParam,LPARAM lParam)2482 PluginModuleChild::CallWindowProcHook(int nCode, WPARAM wParam, LPARAM lParam)
2483 {
2484     // Trap and reply to anything we recognize as the source of a
2485     // potential send message deadlock.
2486     if (nCode >= 0 &&
2487         (InSendMessageEx(nullptr)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
2488         CWPSTRUCT* pCwp = reinterpret_cast<CWPSTRUCT*>(lParam);
2489         if (pCwp->message == WM_KILLFOCUS) {
2490             // Fix for flash fullscreen window loosing focus. On single
2491             // core systems, sync killfocus events need to be handled
2492             // after the flash fullscreen window procedure processes this
2493             // message, otherwise fullscreen focus will not work correctly.
2494             wchar_t szClass[26];
2495             if (GetClassNameW(pCwp->hwnd, szClass,
2496                               sizeof(szClass)/sizeof(char16_t)) &&
2497                 !wcscmp(szClass, kFlashFullscreenClass)) {
2498                 gDelayFlashFocusReplyUntilEval = true;
2499             }
2500         }
2501     }
2502 
2503     return CallNextHookEx(nullptr, nCode, wParam, lParam);
2504 }
2505 
2506 LRESULT CALLBACK
NestedInputEventHook(int nCode,WPARAM wParam,LPARAM lParam)2507 PluginModuleChild::NestedInputEventHook(int nCode, WPARAM wParam, LPARAM lParam)
2508 {
2509     PluginModuleChild* self = GetChrome();
2510     uint32_t len = self->mIncallPumpingStack.Length();
2511     if (nCode >= 0 && len && !self->mIncallPumpingStack[len - 1]._spinning) {
2512         MessageLoop* loop = MessageLoop::current();
2513         self->SendProcessNativeEventsInInterruptCall();
2514         IncallFrame& f = self->mIncallPumpingStack[len - 1];
2515         f._spinning = true;
2516         f._savedNestableTasksAllowed = loop->NestableTasksAllowed();
2517         loop->SetNestableTasksAllowed(true);
2518         loop->set_os_modal_loop(true);
2519     }
2520 
2521     return CallNextHookEx(nullptr, nCode, wParam, lParam);
2522 }
2523 
2524 void
SetEventHooks()2525 PluginModuleChild::SetEventHooks()
2526 {
2527     NS_ASSERTION(!mNestedEventHook,
2528         "mNestedEventHook already setup in call to SetNestedInputEventHook?");
2529     NS_ASSERTION(!mGlobalCallWndProcHook,
2530         "mGlobalCallWndProcHook already setup in call to CallWindowProcHook?");
2531 
2532     PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2533 
2534     // WH_MSGFILTER event hook for detecting modal loops in the child.
2535     mNestedEventHook = SetWindowsHookEx(WH_MSGFILTER,
2536                                         NestedInputEventHook,
2537                                         nullptr,
2538                                         GetCurrentThreadId());
2539 
2540     // WH_CALLWNDPROC event hook for trapping sync messages sent from
2541     // parent that can cause deadlocks.
2542     mGlobalCallWndProcHook = SetWindowsHookEx(WH_CALLWNDPROC,
2543                                               CallWindowProcHook,
2544                                               nullptr,
2545                                               GetCurrentThreadId());
2546 }
2547 
2548 void
ResetEventHooks()2549 PluginModuleChild::ResetEventHooks()
2550 {
2551     PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2552     if (mNestedEventHook)
2553         UnhookWindowsHookEx(mNestedEventHook);
2554     mNestedEventHook = nullptr;
2555     if (mGlobalCallWndProcHook)
2556         UnhookWindowsHookEx(mGlobalCallWndProcHook);
2557     mGlobalCallWndProcHook = nullptr;
2558 }
2559 #endif
2560 
2561 bool
RecvProcessNativeEventsInInterruptCall()2562 PluginModuleChild::RecvProcessNativeEventsInInterruptCall()
2563 {
2564     PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
2565 #if defined(OS_WIN)
2566     ProcessNativeEventsInInterruptCall();
2567     return true;
2568 #else
2569     NS_RUNTIMEABORT(
2570         "PluginModuleChild::RecvProcessNativeEventsInInterruptCall not implemented!");
2571     return false;
2572 #endif
2573 }
2574 
2575 #ifdef MOZ_WIDGET_COCOA
2576 void
ProcessNativeEvents()2577 PluginModuleChild::ProcessNativeEvents() {
2578     CallProcessSomeEvents();
2579 }
2580 #endif
2581 
2582 bool
RecvStartProfiler(const ProfilerInitParams & params)2583 PluginModuleChild::RecvStartProfiler(const ProfilerInitParams& params)
2584 {
2585     nsTArray<const char*> featureArray;
2586     for (size_t i = 0; i < params.features().Length(); ++i) {
2587         featureArray.AppendElement(params.features()[i].get());
2588     }
2589 
2590     nsTArray<const char*> threadNameFilterArray;
2591     for (size_t i = 0; i < params.threadFilters().Length(); ++i) {
2592         threadNameFilterArray.AppendElement(params.threadFilters()[i].get());
2593     }
2594 
2595     profiler_start(params.entries(), params.interval(),
2596                    featureArray.Elements(), featureArray.Length(),
2597                    threadNameFilterArray.Elements(), threadNameFilterArray.Length());
2598 
2599     return true;
2600 }
2601 
2602 bool
RecvStopProfiler()2603 PluginModuleChild::RecvStopProfiler()
2604 {
2605     profiler_stop();
2606     return true;
2607 }
2608 
2609 bool
RecvGatherProfile()2610 PluginModuleChild::RecvGatherProfile()
2611 {
2612     nsCString profileCString;
2613     UniquePtr<char[]> profile = profiler_get_profile();
2614     if (profile != nullptr) {
2615         profileCString = nsCString(profile.get(), strlen(profile.get()));
2616     } else {
2617         profileCString = nsCString("", 0);
2618     }
2619 
2620     Unused << SendProfile(profileCString);
2621     return true;
2622 }
2623 
2624 NPError
PluginRequiresAudioDeviceChanges(PluginInstanceChild * aInstance,NPBool aShouldRegister)2625 PluginModuleChild::PluginRequiresAudioDeviceChanges(
2626                           PluginInstanceChild* aInstance,
2627                           NPBool aShouldRegister)
2628 {
2629 #ifdef XP_WIN
2630     // Maintain a set of PluginInstanceChildren that we need to tell when the
2631     // default audio device has changed.
2632     NPError rv = NPERR_NO_ERROR;
2633     if (aShouldRegister) {
2634         if (mAudioNotificationSet.IsEmpty()) {
2635             // We are registering the first plugin.  Notify the PluginModuleParent
2636             // that it needs to start sending us audio device notifications.
2637             if (!CallNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
2638                                                       aShouldRegister, &rv)) {
2639                 return NPERR_GENERIC_ERROR;
2640             }
2641         }
2642         if (rv == NPERR_NO_ERROR) {
2643             mAudioNotificationSet.PutEntry(aInstance);
2644         }
2645     }
2646     else if (!mAudioNotificationSet.IsEmpty()) {
2647         mAudioNotificationSet.RemoveEntry(aInstance);
2648         if (mAudioNotificationSet.IsEmpty()) {
2649             // We released the last plugin.  Unregister from the PluginModuleParent.
2650             if (!CallNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
2651     	      	                                        aShouldRegister, &rv)) {
2652                 return NPERR_GENERIC_ERROR;
2653             }
2654         }
2655     }
2656     return rv;
2657 #else
2658     NS_RUNTIMEABORT("PluginRequiresAudioDeviceChanges is not available on this platform.");
2659     return NPERR_GENERIC_ERROR;
2660 #endif // XP_WIN
2661 }
2662 
2663 bool
RecvNPP_SetValue_NPNVaudioDeviceChangeDetails(const NPAudioDeviceChangeDetailsIPC & detailsIPC)2664 PluginModuleChild::RecvNPP_SetValue_NPNVaudioDeviceChangeDetails(
2665                               const NPAudioDeviceChangeDetailsIPC& detailsIPC)
2666 {
2667 #if defined(XP_WIN)
2668     NPAudioDeviceChangeDetails details;
2669     details.flow = detailsIPC.flow;
2670     details.role = detailsIPC.role;
2671     details.defaultDevice = detailsIPC.defaultDevice.c_str();
2672     for (auto iter = mAudioNotificationSet.ConstIter(); !iter.Done(); iter.Next()) {
2673       PluginInstanceChild* pluginInst = iter.Get()->GetKey();
2674       pluginInst->DefaultAudioDeviceChanged(details);
2675     }
2676     return true;
2677 #else
2678     NS_RUNTIMEABORT("NPP_SetValue_NPNVaudioDeviceChangeDetails is a Windows-only message");
2679     return false;
2680 #endif
2681 }
2682