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 >K_WIDGET_CLASS(gtk_plug_class)->scroll_event;
599 if (!*scroll_event) {
600 *scroll_event = gtk_plug_scroll_event;
601 }
602
603 GtkPlugEmbeddedFn* embedded = >K_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