michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* vim: set sw=4 ts=4 et : */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef MOZ_WIDGET_QT michael@0: #include // for _exit() michael@0: #include michael@0: #include "nsQAppInstance.h" michael@0: #include "NestedLoopTimer.h" michael@0: #endif michael@0: michael@0: #include "mozilla/plugins/PluginModuleChild.h" michael@0: michael@0: /* This must occur *after* plugins/PluginModuleChild.h to avoid typedefs conflicts. */ michael@0: #include "mozilla/ArrayUtils.h" michael@0: michael@0: #include "mozilla/ipc/MessageChannel.h" michael@0: michael@0: #ifdef MOZ_WIDGET_GTK michael@0: #include michael@0: #if (MOZ_WIDGET_GTK == 3) michael@0: #include michael@0: #endif michael@0: #endif michael@0: michael@0: #include "nsIFile.h" michael@0: michael@0: #include "pratom.h" michael@0: #include "nsDebug.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsPluginsDir.h" michael@0: #include "nsXULAppAPI.h" michael@0: michael@0: #ifdef MOZ_X11 michael@0: # include "mozilla/X11Util.h" michael@0: #endif michael@0: #include "mozilla/plugins/PluginInstanceChild.h" michael@0: #include "mozilla/plugins/StreamNotifyChild.h" michael@0: #include "mozilla/plugins/BrowserStreamChild.h" michael@0: #include "mozilla/plugins/PluginStreamChild.h" michael@0: #include "PluginIdentifierChild.h" michael@0: #include "mozilla/dom/CrashReporterChild.h" michael@0: michael@0: #include "nsNPAPIPlugin.h" michael@0: michael@0: #ifdef XP_WIN michael@0: #include "COMMessageFilter.h" michael@0: #include "nsWindowsDllInterceptor.h" michael@0: #include "mozilla/widget/AudioSession.h" michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_COCOA michael@0: #include "PluginInterposeOSX.h" michael@0: #include "PluginUtilsOSX.h" michael@0: #endif michael@0: michael@0: #include "GeckoProfiler.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::plugins; michael@0: using mozilla::dom::CrashReporterChild; michael@0: using mozilla::dom::PCrashReporterChild; michael@0: michael@0: #if defined(XP_WIN) michael@0: const wchar_t * kFlashFullscreenClass = L"ShockwaveFlashFullScreen"; michael@0: const wchar_t * kMozillaWindowClass = L"MozillaWindowClass"; michael@0: #endif michael@0: michael@0: namespace { michael@0: PluginModuleChild* gInstance = nullptr; michael@0: } michael@0: michael@0: #ifdef MOZ_WIDGET_QT michael@0: typedef void (*_gtk_init_fn)(int argc, char **argv); michael@0: static _gtk_init_fn s_gtk_init = nullptr; michael@0: static PRLibrary *sGtkLib = nullptr; michael@0: #endif michael@0: michael@0: #ifdef XP_WIN michael@0: // Used with fix for flash fullscreen window loosing focus. michael@0: static bool gDelayFlashFocusReplyUntilEval = false; michael@0: // Used to fix GetWindowInfo problems with internal flash settings dialogs michael@0: static WindowsDllInterceptor sUser32Intercept; michael@0: typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi); michael@0: static GetWindowInfoPtr sGetWindowInfoPtrStub = nullptr; michael@0: static HWND sBrowserHwnd = nullptr; michael@0: #endif michael@0: michael@0: PluginModuleChild::PluginModuleChild() michael@0: : mLibrary(0) michael@0: , mPluginFilename("") michael@0: , mQuirks(QUIRKS_NOT_INITIALIZED) michael@0: , mShutdownFunc(0) michael@0: , mInitializeFunc(0) michael@0: #if defined(OS_WIN) || defined(OS_MACOSX) michael@0: , mGetEntryPointsFunc(0) michael@0: #elif defined(MOZ_WIDGET_GTK) michael@0: , mNestedLoopTimerId(0) michael@0: #elif defined(MOZ_WIDGET_QT) michael@0: , mNestedLoopTimerObject(0) michael@0: #endif michael@0: #ifdef OS_WIN michael@0: , mNestedEventHook(nullptr) michael@0: , mGlobalCallWndProcHook(nullptr) michael@0: #endif michael@0: { michael@0: NS_ASSERTION(!gInstance, "Something terribly wrong here!"); michael@0: memset(&mFunctions, 0, sizeof(mFunctions)); michael@0: memset(&mSavedData, 0, sizeof(mSavedData)); michael@0: gInstance = this; michael@0: mUserAgent.SetIsVoid(true); michael@0: #ifdef XP_MACOSX michael@0: mac_plugin_interposing::child::SetUpCocoaInterposing(); michael@0: #endif michael@0: } michael@0: michael@0: PluginModuleChild::~PluginModuleChild() michael@0: { michael@0: NS_ASSERTION(gInstance == this, "Something terribly wrong here!"); michael@0: michael@0: // We don't unload the plugin library in case it uses atexit handlers or michael@0: // other similar hooks. michael@0: michael@0: DeinitGraphics(); michael@0: michael@0: gInstance = nullptr; michael@0: } michael@0: michael@0: // static michael@0: PluginModuleChild* michael@0: PluginModuleChild::current() michael@0: { michael@0: NS_ASSERTION(gInstance, "Null instance!"); michael@0: return gInstance; michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::Init(const std::string& aPluginFilename, michael@0: base::ProcessHandle aParentProcessHandle, michael@0: MessageLoop* aIOLoop, michael@0: IPC::Channel* aChannel) michael@0: { michael@0: PLUGIN_LOG_DEBUG_METHOD; michael@0: michael@0: GetIPCChannel()->SetAbortOnError(true); michael@0: michael@0: // Request Windows message deferral behavior on our channel. This michael@0: // applies to the top level and all sub plugin protocols since they michael@0: // all share the same channel. michael@0: GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION); michael@0: michael@0: #ifdef XP_WIN michael@0: COMMessageFilter::Initialize(this); michael@0: #endif michael@0: michael@0: NS_ASSERTION(aChannel, "need a channel"); michael@0: michael@0: if (!InitGraphics()) michael@0: return false; michael@0: michael@0: mPluginFilename = aPluginFilename.c_str(); michael@0: nsCOMPtr localFile; michael@0: NS_NewLocalFile(NS_ConvertUTF8toUTF16(mPluginFilename), michael@0: true, michael@0: getter_AddRefs(localFile)); michael@0: michael@0: bool exists; michael@0: localFile->Exists(&exists); michael@0: NS_ASSERTION(exists, "plugin file ain't there"); michael@0: michael@0: nsPluginFile pluginFile(localFile); michael@0: michael@0: #if defined(MOZ_X11) || defined(OS_MACOSX) michael@0: nsPluginInfo info = nsPluginInfo(); michael@0: if (NS_FAILED(pluginFile.GetPluginInfo(info, &mLibrary))) { michael@0: return false; michael@0: } michael@0: michael@0: #if defined(MOZ_X11) michael@0: NS_NAMED_LITERAL_CSTRING(flash10Head, "Shockwave Flash 10."); michael@0: if (StringBeginsWith(nsDependentCString(info.fDescription), flash10Head)) { michael@0: AddQuirk(QUIRK_FLASH_EXPOSE_COORD_TRANSLATION); michael@0: } michael@0: #else // defined(OS_MACOSX) michael@0: mozilla::plugins::PluginUtilsOSX::SetProcessName(info.fName); michael@0: #endif michael@0: michael@0: pluginFile.FreePluginInfo(info); michael@0: michael@0: if (!mLibrary) michael@0: #endif michael@0: { michael@0: nsresult rv = pluginFile.LoadPlugin(&mLibrary); michael@0: if (NS_FAILED(rv)) michael@0: return false; michael@0: } michael@0: NS_ASSERTION(mLibrary, "couldn't open shared object"); michael@0: michael@0: if (!Open(aChannel, aParentProcessHandle, aIOLoop)) michael@0: return false; michael@0: michael@0: memset((void*) &mFunctions, 0, sizeof(mFunctions)); michael@0: mFunctions.size = sizeof(mFunctions); michael@0: mFunctions.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR; michael@0: michael@0: // TODO: use PluginPRLibrary here michael@0: michael@0: #if defined(OS_LINUX) || defined(OS_BSD) michael@0: mShutdownFunc = michael@0: (NP_PLUGINSHUTDOWN) PR_FindFunctionSymbol(mLibrary, "NP_Shutdown"); michael@0: michael@0: // create the new plugin handler michael@0: michael@0: mInitializeFunc = michael@0: (NP_PLUGINUNIXINIT) PR_FindFunctionSymbol(mLibrary, "NP_Initialize"); michael@0: NS_ASSERTION(mInitializeFunc, "couldn't find NP_Initialize()"); michael@0: michael@0: #elif defined(OS_WIN) || defined(OS_MACOSX) michael@0: mShutdownFunc = michael@0: (NP_PLUGINSHUTDOWN)PR_FindFunctionSymbol(mLibrary, "NP_Shutdown"); michael@0: michael@0: mGetEntryPointsFunc = michael@0: (NP_GETENTRYPOINTS)PR_FindSymbol(mLibrary, "NP_GetEntryPoints"); michael@0: NS_ENSURE_TRUE(mGetEntryPointsFunc, false); michael@0: michael@0: mInitializeFunc = michael@0: (NP_PLUGININIT)PR_FindFunctionSymbol(mLibrary, "NP_Initialize"); michael@0: NS_ENSURE_TRUE(mInitializeFunc, false); michael@0: #else michael@0: michael@0: # error Please copy the initialization code from nsNPAPIPlugin.cpp michael@0: michael@0: #endif michael@0: michael@0: return true; michael@0: } michael@0: michael@0: #if defined(MOZ_WIDGET_GTK) michael@0: typedef void (*GObjectDisposeFn)(GObject*); michael@0: typedef gboolean (*GtkWidgetScrollEventFn)(GtkWidget*, GdkEventScroll*); michael@0: typedef void (*GtkPlugEmbeddedFn)(GtkPlug*); michael@0: michael@0: static GObjectDisposeFn real_gtk_plug_dispose; michael@0: static GtkPlugEmbeddedFn real_gtk_plug_embedded; michael@0: michael@0: static void michael@0: undo_bogus_unref(gpointer data, GObject* object, gboolean is_last_ref) { michael@0: if (!is_last_ref) // recursion in g_object_ref michael@0: return; michael@0: michael@0: g_object_ref(object); michael@0: } michael@0: michael@0: static void michael@0: wrap_gtk_plug_dispose(GObject* object) { michael@0: // Work around Flash Player bug described in bug 538914. michael@0: // michael@0: // This function is called during gtk_widget_destroy and/or before michael@0: // the object's last reference is removed. A reference to the michael@0: // object is held during the call so the ref count should not drop michael@0: // to zero. However, Flash Player tries to destroy the GtkPlug michael@0: // using g_object_unref instead of gtk_widget_destroy. The michael@0: // reference that Flash is removing actually belongs to the michael@0: // GtkPlug. During real_gtk_plug_dispose, the GtkPlug removes its michael@0: // reference. michael@0: // michael@0: // A toggle ref is added to prevent premature deletion of the object michael@0: // caused by Flash Player's extra unref, and to detect when there are michael@0: // unexpectedly no other references. michael@0: g_object_add_toggle_ref(object, undo_bogus_unref, nullptr); michael@0: (*real_gtk_plug_dispose)(object); michael@0: g_object_remove_toggle_ref(object, undo_bogus_unref, nullptr); michael@0: } michael@0: michael@0: static gboolean michael@0: gtk_plug_scroll_event(GtkWidget *widget, GdkEventScroll *gdk_event) michael@0: { michael@0: if (!gtk_widget_is_toplevel(widget)) // in same process as its GtkSocket michael@0: return FALSE; // event not handled; propagate to GtkSocket michael@0: michael@0: GdkWindow* socket_window = gtk_plug_get_socket_window(GTK_PLUG(widget)); michael@0: if (!socket_window) michael@0: return FALSE; michael@0: michael@0: // Propagate the event to the embedder. michael@0: GdkScreen* screen = gdk_window_get_screen(socket_window); michael@0: GdkWindow* plug_window = gtk_widget_get_window(widget); michael@0: GdkWindow* event_window = gdk_event->window; michael@0: gint x = gdk_event->x; michael@0: gint y = gdk_event->y; michael@0: unsigned int button; michael@0: unsigned int button_mask = 0; michael@0: XEvent xevent; michael@0: Display* dpy = GDK_WINDOW_XDISPLAY(socket_window); michael@0: michael@0: /* Translate the event coordinates to the plug window, michael@0: * which should be aligned with the socket window. michael@0: */ michael@0: while (event_window != plug_window) michael@0: { michael@0: gint dx, dy; michael@0: michael@0: gdk_window_get_position(event_window, &dx, &dy); michael@0: x += dx; michael@0: y += dy; michael@0: michael@0: event_window = gdk_window_get_parent(event_window); michael@0: if (!event_window) michael@0: return FALSE; michael@0: } michael@0: michael@0: switch (gdk_event->direction) { michael@0: case GDK_SCROLL_UP: michael@0: button = 4; michael@0: button_mask = Button4Mask; michael@0: break; michael@0: case GDK_SCROLL_DOWN: michael@0: button = 5; michael@0: button_mask = Button5Mask; michael@0: break; michael@0: case GDK_SCROLL_LEFT: michael@0: button = 6; michael@0: break; michael@0: case GDK_SCROLL_RIGHT: michael@0: button = 7; michael@0: break; michael@0: default: michael@0: return FALSE; // unknown GdkScrollDirection michael@0: } michael@0: michael@0: memset(&xevent, 0, sizeof(xevent)); michael@0: xevent.xbutton.type = ButtonPress; michael@0: xevent.xbutton.window = gdk_x11_window_get_xid(socket_window); michael@0: xevent.xbutton.root = gdk_x11_window_get_xid(gdk_screen_get_root_window(screen)); michael@0: xevent.xbutton.subwindow = gdk_x11_window_get_xid(plug_window); michael@0: xevent.xbutton.time = gdk_event->time; michael@0: xevent.xbutton.x = x; michael@0: xevent.xbutton.y = y; michael@0: xevent.xbutton.x_root = gdk_event->x_root; michael@0: xevent.xbutton.y_root = gdk_event->y_root; michael@0: xevent.xbutton.state = gdk_event->state; michael@0: xevent.xbutton.button = button; michael@0: xevent.xbutton.same_screen = True; michael@0: michael@0: gdk_error_trap_push(); michael@0: michael@0: XSendEvent(dpy, xevent.xbutton.window, michael@0: True, ButtonPressMask, &xevent); michael@0: michael@0: xevent.xbutton.type = ButtonRelease; michael@0: xevent.xbutton.state |= button_mask; michael@0: XSendEvent(dpy, xevent.xbutton.window, michael@0: True, ButtonReleaseMask, &xevent); michael@0: michael@0: gdk_display_sync(gdk_screen_get_display(screen)); michael@0: gdk_error_trap_pop(); michael@0: michael@0: return TRUE; // event handled michael@0: } michael@0: michael@0: static void michael@0: wrap_gtk_plug_embedded(GtkPlug* plug) { michael@0: GdkWindow* socket_window = gtk_plug_get_socket_window(plug); michael@0: if (socket_window) { michael@0: if (gtk_check_version(2,18,7) != nullptr // older michael@0: && g_object_get_data(G_OBJECT(socket_window), michael@0: "moz-existed-before-set-window")) { michael@0: // Add missing reference for michael@0: // https://bugzilla.gnome.org/show_bug.cgi?id=607061 michael@0: g_object_ref(socket_window); michael@0: } michael@0: michael@0: // Ensure the window exists to make this GtkPlug behave like an michael@0: // in-process GtkPlug for Flash Player. (Bugs 561308 and 539138). michael@0: gtk_widget_realize(GTK_WIDGET(plug)); michael@0: } michael@0: michael@0: if (*real_gtk_plug_embedded) { michael@0: (*real_gtk_plug_embedded)(plug); michael@0: } michael@0: } michael@0: michael@0: // michael@0: // The next four constants are knobs that can be tuned. They trade michael@0: // off potential UI lag from delayed event processing with CPU time. michael@0: // michael@0: static const gint kNestedLoopDetectorPriority = G_PRIORITY_HIGH_IDLE; michael@0: // 90ms so that we can hopefully break livelocks before the user michael@0: // notices UI lag (100ms) michael@0: static const guint kNestedLoopDetectorIntervalMs = 90; michael@0: michael@0: static const gint kBrowserEventPriority = G_PRIORITY_HIGH_IDLE; michael@0: static const guint kBrowserEventIntervalMs = 10; michael@0: michael@0: // static michael@0: gboolean michael@0: PluginModuleChild::DetectNestedEventLoop(gpointer data) michael@0: { michael@0: PluginModuleChild* pmc = static_cast(data); michael@0: michael@0: NS_ABORT_IF_FALSE(0 != pmc->mNestedLoopTimerId, michael@0: "callback after descheduling"); michael@0: NS_ABORT_IF_FALSE(pmc->mTopLoopDepth < g_main_depth(), michael@0: "not canceled before returning to main event loop!"); michael@0: michael@0: PLUGIN_LOG_DEBUG(("Detected nested glib event loop")); michael@0: michael@0: // just detected a nested loop; start a timer that will michael@0: // periodically rpc-call back into the browser and process some michael@0: // events michael@0: pmc->mNestedLoopTimerId = michael@0: g_timeout_add_full(kBrowserEventPriority, michael@0: kBrowserEventIntervalMs, michael@0: PluginModuleChild::ProcessBrowserEvents, michael@0: data, michael@0: nullptr); michael@0: // cancel the nested-loop detection timer michael@0: return FALSE; michael@0: } michael@0: michael@0: // static michael@0: gboolean michael@0: PluginModuleChild::ProcessBrowserEvents(gpointer data) michael@0: { michael@0: PluginModuleChild* pmc = static_cast(data); michael@0: michael@0: NS_ABORT_IF_FALSE(pmc->mTopLoopDepth < g_main_depth(), michael@0: "not canceled before returning to main event loop!"); michael@0: michael@0: pmc->CallProcessSomeEvents(); michael@0: michael@0: return TRUE; michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::EnteredCxxStack() michael@0: { michael@0: NS_ABORT_IF_FALSE(0 == mNestedLoopTimerId, michael@0: "previous timer not descheduled"); michael@0: michael@0: mNestedLoopTimerId = michael@0: g_timeout_add_full(kNestedLoopDetectorPriority, michael@0: kNestedLoopDetectorIntervalMs, michael@0: PluginModuleChild::DetectNestedEventLoop, michael@0: this, michael@0: nullptr); michael@0: michael@0: #ifdef DEBUG michael@0: mTopLoopDepth = g_main_depth(); michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::ExitedCxxStack() michael@0: { michael@0: NS_ABORT_IF_FALSE(0 < mNestedLoopTimerId, michael@0: "nested loop timeout not scheduled"); michael@0: michael@0: g_source_remove(mNestedLoopTimerId); michael@0: mNestedLoopTimerId = 0; michael@0: } michael@0: #elif defined (MOZ_WIDGET_QT) michael@0: michael@0: void michael@0: PluginModuleChild::EnteredCxxStack() michael@0: { michael@0: NS_ABORT_IF_FALSE(mNestedLoopTimerObject == nullptr, michael@0: "previous timer not descheduled"); michael@0: mNestedLoopTimerObject = new NestedLoopTimer(this); michael@0: QTimer::singleShot(kNestedLoopDetectorIntervalMs, michael@0: mNestedLoopTimerObject, SLOT(timeOut())); michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::ExitedCxxStack() michael@0: { michael@0: NS_ABORT_IF_FALSE(mNestedLoopTimerObject != nullptr, michael@0: "nested loop timeout not scheduled"); michael@0: delete mNestedLoopTimerObject; michael@0: mNestedLoopTimerObject = nullptr; michael@0: } michael@0: michael@0: #endif michael@0: michael@0: bool michael@0: PluginModuleChild::RecvSetParentHangTimeout(const uint32_t& aSeconds) michael@0: { michael@0: #ifdef XP_WIN michael@0: SetReplyTimeoutMs(((aSeconds > 0) ? (1000 * aSeconds) : 0)); michael@0: #endif michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::ShouldContinueFromReplyTimeout() michael@0: { michael@0: #ifdef XP_WIN michael@0: NS_RUNTIMEABORT("terminating child process"); michael@0: #endif michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::InitGraphics() michael@0: { michael@0: #if defined(MOZ_WIDGET_GTK) michael@0: // Work around plugins that don't interact well with GDK michael@0: // client-side windows. michael@0: PR_SetEnv("GDK_NATIVE_WINDOWS=1"); michael@0: michael@0: gtk_init(0, 0); michael@0: michael@0: // GtkPlug is a static class so will leak anyway but this ref makes sure. michael@0: gpointer gtk_plug_class = g_type_class_ref(GTK_TYPE_PLUG); michael@0: michael@0: // The dispose method is a good place to hook into the destruction process michael@0: // because the reference count should be 1 the last time dispose is michael@0: // called. (Toggle references wouldn't detect if the reference count michael@0: // might be higher.) michael@0: GObjectDisposeFn* dispose = &G_OBJECT_CLASS(gtk_plug_class)->dispose; michael@0: NS_ABORT_IF_FALSE(*dispose != wrap_gtk_plug_dispose, michael@0: "InitGraphics called twice"); michael@0: real_gtk_plug_dispose = *dispose; michael@0: *dispose = wrap_gtk_plug_dispose; michael@0: michael@0: // If we ever stop setting GDK_NATIVE_WINDOWS, we'll also need to michael@0: // gtk_widget_add_events GDK_SCROLL_MASK or GDK client-side windows will michael@0: // not tell us about the scroll events that it intercepts. With native michael@0: // windows, this is called when GDK intercepts the events; if GDK doesn't michael@0: // intercept the events, then the X server will instead send them directly michael@0: // to an ancestor (embedder) window. michael@0: GtkWidgetScrollEventFn* scroll_event = michael@0: >K_WIDGET_CLASS(gtk_plug_class)->scroll_event; michael@0: if (!*scroll_event) { michael@0: *scroll_event = gtk_plug_scroll_event; michael@0: } michael@0: michael@0: GtkPlugEmbeddedFn* embedded = >K_PLUG_CLASS(gtk_plug_class)->embedded; michael@0: real_gtk_plug_embedded = *embedded; michael@0: *embedded = wrap_gtk_plug_embedded; michael@0: michael@0: #elif defined(MOZ_WIDGET_QT) michael@0: nsQAppInstance::AddRef(); michael@0: // Work around plugins that don't interact well without gtk initialized michael@0: // see bug 566845 michael@0: #if defined(MOZ_X11) michael@0: if (!sGtkLib) michael@0: sGtkLib = PR_LoadLibrary("libgtk-x11-2.0.so.0"); michael@0: #endif michael@0: if (sGtkLib) { michael@0: s_gtk_init = (_gtk_init_fn)PR_FindFunctionSymbol(sGtkLib, "gtk_init"); michael@0: if (s_gtk_init) michael@0: s_gtk_init(0, 0); michael@0: } michael@0: #else michael@0: // may not be necessary on all platforms michael@0: #endif michael@0: #ifdef MOZ_X11 michael@0: // Do this after initializing GDK, or GDK will install its own handler. michael@0: XRE_InstallX11ErrorHandler(); michael@0: #endif michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::DeinitGraphics() michael@0: { michael@0: #ifdef MOZ_WIDGET_QT michael@0: nsQAppInstance::Release(); michael@0: if (sGtkLib) { michael@0: PR_UnloadLibrary(sGtkLib); michael@0: sGtkLib = nullptr; michael@0: s_gtk_init = nullptr; michael@0: } michael@0: #endif michael@0: michael@0: #if defined(MOZ_X11) && defined(NS_FREE_PERMANENT_DATA) michael@0: // We free some data off of XDisplay close hooks, ensure they're michael@0: // run. Closing the display is pretty scary, so we only do it to michael@0: // silence leak checkers. michael@0: XCloseDisplay(DefaultXDisplay()); michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::AnswerNP_Shutdown(NPError *rv) michael@0: { michael@0: AssertPluginThread(); michael@0: michael@0: #if defined XP_WIN michael@0: mozilla::widget::StopAudioSession(); michael@0: #endif michael@0: michael@0: // the PluginModuleParent shuts down this process after this interrupt michael@0: // call pops off its stack michael@0: michael@0: *rv = mShutdownFunc ? mShutdownFunc() : NPERR_NO_ERROR; michael@0: michael@0: // weakly guard against re-entry after NP_Shutdown michael@0: memset(&mFunctions, 0, sizeof(mFunctions)); michael@0: michael@0: #ifdef OS_WIN michael@0: ResetEventHooks(); michael@0: #endif michael@0: michael@0: GetIPCChannel()->SetAbortOnError(false); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::AnswerOptionalFunctionsSupported(bool *aURLRedirectNotify, michael@0: bool *aClearSiteData, michael@0: bool *aGetSitesWithData) michael@0: { michael@0: *aURLRedirectNotify = !!mFunctions.urlredirectnotify; michael@0: *aClearSiteData = !!mFunctions.clearsitedata; michael@0: *aGetSitesWithData = !!mFunctions.getsiteswithdata; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::AnswerNPP_ClearSiteData(const nsCString& aSite, michael@0: const uint64_t& aFlags, michael@0: const uint64_t& aMaxAge, michael@0: NPError* aResult) michael@0: { michael@0: *aResult = michael@0: mFunctions.clearsitedata(NullableStringGet(aSite), aFlags, aMaxAge); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::AnswerNPP_GetSitesWithData(InfallibleTArray* aResult) michael@0: { michael@0: char** result = mFunctions.getsiteswithdata(); michael@0: if (!result) michael@0: return true; michael@0: michael@0: char** iterator = result; michael@0: while (*iterator) { michael@0: aResult->AppendElement(*iterator); michael@0: NS_Free(*iterator); michael@0: ++iterator; michael@0: } michael@0: NS_Free(result); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::RecvSetAudioSessionData(const nsID& aId, michael@0: const nsString& aDisplayName, michael@0: const nsString& aIconPath) michael@0: { michael@0: #if !defined XP_WIN michael@0: NS_RUNTIMEABORT("Not Reached!"); michael@0: return false; michael@0: #else michael@0: nsresult rv = mozilla::widget::RecvAudioSessionData(aId, aDisplayName, aIconPath); michael@0: NS_ENSURE_SUCCESS(rv, true); // Bail early if this fails michael@0: michael@0: // Ignore failures here; we can't really do anything about them michael@0: mozilla::widget::StartAudioSession(); michael@0: return true; michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::QuickExit() michael@0: { michael@0: NS_WARNING("plugin process _exit()ing"); michael@0: _exit(0); michael@0: } michael@0: michael@0: PCrashReporterChild* michael@0: PluginModuleChild::AllocPCrashReporterChild(mozilla::dom::NativeThreadId* id, michael@0: uint32_t* processType) michael@0: { michael@0: return new CrashReporterChild(); michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::DeallocPCrashReporterChild(PCrashReporterChild* actor) michael@0: { michael@0: delete actor; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::AnswerPCrashReporterConstructor( michael@0: PCrashReporterChild* actor, michael@0: mozilla::dom::NativeThreadId* id, michael@0: uint32_t* processType) michael@0: { michael@0: #ifdef MOZ_CRASHREPORTER michael@0: *id = CrashReporter::CurrentThreadId(); michael@0: *processType = XRE_GetProcessType(); michael@0: #endif michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: if (AbnormalShutdown == why) { michael@0: NS_WARNING("shutting down early because of crash!"); michael@0: QuickExit(); michael@0: } michael@0: michael@0: // doesn't matter why we're being destroyed; it's up to us to michael@0: // initiate (clean) shutdown michael@0: XRE_ShutdownChildProcess(); michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::CleanUp() michael@0: { michael@0: } michael@0: michael@0: const char* michael@0: PluginModuleChild::GetUserAgent() michael@0: { michael@0: if (mUserAgent.IsVoid() && !CallNPN_UserAgent(&mUserAgent)) michael@0: return nullptr; michael@0: michael@0: return NullableStringGet(mUserAgent); michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::RegisterActorForNPObject(NPObject* aObject, michael@0: PluginScriptableObjectChild* aActor) michael@0: { michael@0: AssertPluginThread(); michael@0: NS_ASSERTION(aObject && aActor, "Null pointer!"); michael@0: michael@0: NPObjectData* d = mObjectMap.GetEntry(aObject); michael@0: if (!d) { michael@0: NS_ERROR("NPObject not in object table"); michael@0: return false; michael@0: } michael@0: michael@0: d->actor = aActor; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::UnregisterActorForNPObject(NPObject* aObject) michael@0: { michael@0: AssertPluginThread(); michael@0: NS_ASSERTION(aObject, "Null pointer!"); michael@0: michael@0: NPObjectData* d = mObjectMap.GetEntry(aObject); michael@0: NS_ASSERTION(d, "NPObject not in object table"); michael@0: if (d) { michael@0: d->actor = nullptr; michael@0: } michael@0: } michael@0: michael@0: PluginScriptableObjectChild* michael@0: PluginModuleChild::GetActorForNPObject(NPObject* aObject) michael@0: { michael@0: AssertPluginThread(); michael@0: NS_ASSERTION(aObject, "Null pointer!"); michael@0: michael@0: NPObjectData* d = mObjectMap.GetEntry(aObject); michael@0: if (!d) { michael@0: NS_ERROR("Plugin using object not created with NPN_CreateObject?"); michael@0: return nullptr; michael@0: } michael@0: michael@0: return d->actor; michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: bool michael@0: PluginModuleChild::NPObjectIsRegistered(NPObject* aObject) michael@0: { michael@0: return !!mObjectMap.GetEntry(aObject); michael@0: } michael@0: #endif michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // FIXME/cjones: just getting this out of the way for the moment ... michael@0: michael@0: namespace mozilla { michael@0: namespace plugins { michael@0: namespace child { michael@0: michael@0: static NPError michael@0: _requestread(NPStream *pstream, NPByteRange *rangeList); michael@0: michael@0: static NPError michael@0: _geturlnotify(NPP aNPP, const char* relativeURL, const char* target, michael@0: void* notifyData); michael@0: michael@0: static NPError michael@0: _getvalue(NPP aNPP, NPNVariable variable, void *r_value); michael@0: michael@0: static NPError michael@0: _setvalue(NPP aNPP, NPPVariable variable, void *r_value); michael@0: michael@0: static NPError michael@0: _geturl(NPP aNPP, const char* relativeURL, const char* target); michael@0: michael@0: static NPError michael@0: _posturlnotify(NPP aNPP, const char* relativeURL, const char *target, michael@0: uint32_t len, const char *buf, NPBool file, void* notifyData); michael@0: michael@0: static NPError michael@0: _posturl(NPP aNPP, const char* relativeURL, const char *target, uint32_t len, michael@0: const char *buf, NPBool file); michael@0: michael@0: static NPError michael@0: _newstream(NPP aNPP, NPMIMEType type, const char* window, NPStream** pstream); michael@0: michael@0: static int32_t michael@0: _write(NPP aNPP, NPStream *pstream, int32_t len, void *buffer); michael@0: michael@0: static NPError michael@0: _destroystream(NPP aNPP, NPStream *pstream, NPError reason); michael@0: michael@0: static void michael@0: _status(NPP aNPP, const char *message); michael@0: michael@0: static void michael@0: _memfree (void *ptr); michael@0: michael@0: static uint32_t michael@0: _memflush(uint32_t size); michael@0: michael@0: static void michael@0: _reloadplugins(NPBool reloadPages); michael@0: michael@0: static void michael@0: _invalidaterect(NPP aNPP, NPRect *invalidRect); michael@0: michael@0: static void michael@0: _invalidateregion(NPP aNPP, NPRegion invalidRegion); michael@0: michael@0: static void michael@0: _forceredraw(NPP aNPP); michael@0: michael@0: static const char* michael@0: _useragent(NPP aNPP); michael@0: michael@0: static void* michael@0: _memalloc (uint32_t size); michael@0: michael@0: // Deprecated entry points for the old Java plugin. michael@0: static void* /* OJI type: JRIEnv* */ michael@0: _getjavaenv(void); michael@0: michael@0: // Deprecated entry points for the old Java plugin. michael@0: static void* /* OJI type: jref */ michael@0: _getjavapeer(NPP aNPP); michael@0: michael@0: static bool michael@0: _invoke(NPP aNPP, NPObject* npobj, NPIdentifier method, const NPVariant *args, michael@0: uint32_t argCount, NPVariant *result); michael@0: michael@0: static bool michael@0: _invokedefault(NPP aNPP, NPObject* npobj, const NPVariant *args, michael@0: uint32_t argCount, NPVariant *result); michael@0: michael@0: static bool michael@0: _evaluate(NPP aNPP, NPObject* npobj, NPString *script, NPVariant *result); michael@0: michael@0: static bool michael@0: _getproperty(NPP aNPP, NPObject* npobj, NPIdentifier property, michael@0: NPVariant *result); michael@0: michael@0: static bool michael@0: _setproperty(NPP aNPP, NPObject* npobj, NPIdentifier property, michael@0: const NPVariant *value); michael@0: michael@0: static bool michael@0: _removeproperty(NPP aNPP, NPObject* npobj, NPIdentifier property); michael@0: michael@0: static bool michael@0: _hasproperty(NPP aNPP, NPObject* npobj, NPIdentifier propertyName); michael@0: michael@0: static bool michael@0: _hasmethod(NPP aNPP, NPObject* npobj, NPIdentifier methodName); michael@0: michael@0: static bool michael@0: _enumerate(NPP aNPP, NPObject *npobj, NPIdentifier **identifier, michael@0: uint32_t *count); michael@0: michael@0: static bool michael@0: _construct(NPP aNPP, NPObject* npobj, const NPVariant *args, michael@0: uint32_t argCount, NPVariant *result); michael@0: michael@0: static void michael@0: _releasevariantvalue(NPVariant *variant); michael@0: michael@0: static void michael@0: _setexception(NPObject* npobj, const NPUTF8 *message); michael@0: michael@0: static void michael@0: _pushpopupsenabledstate(NPP aNPP, NPBool enabled); michael@0: michael@0: static void michael@0: _poppopupsenabledstate(NPP aNPP); michael@0: michael@0: static void michael@0: _pluginthreadasynccall(NPP instance, PluginThreadCallback func, michael@0: void *userData); michael@0: michael@0: static NPError michael@0: _getvalueforurl(NPP npp, NPNURLVariable variable, const char *url, michael@0: char **value, uint32_t *len); michael@0: michael@0: static NPError michael@0: _setvalueforurl(NPP npp, NPNURLVariable variable, const char *url, michael@0: const char *value, uint32_t len); michael@0: michael@0: static NPError michael@0: _getauthenticationinfo(NPP npp, const char *protocol, michael@0: const char *host, int32_t port, michael@0: const char *scheme, const char *realm, michael@0: char **username, uint32_t *ulen, michael@0: char **password, uint32_t *plen); michael@0: michael@0: static uint32_t michael@0: _scheduletimer(NPP instance, uint32_t interval, NPBool repeat, michael@0: void (*timerFunc)(NPP npp, uint32_t timerID)); michael@0: michael@0: static void michael@0: _unscheduletimer(NPP instance, uint32_t timerID); michael@0: michael@0: static NPError michael@0: _popupcontextmenu(NPP instance, NPMenu* menu); michael@0: michael@0: static NPBool michael@0: _convertpoint(NPP instance, michael@0: double sourceX, double sourceY, NPCoordinateSpace sourceSpace, michael@0: double *destX, double *destY, NPCoordinateSpace destSpace); michael@0: michael@0: static void michael@0: _urlredirectresponse(NPP instance, void* notifyData, NPBool allow); michael@0: michael@0: static NPError michael@0: _initasyncsurface(NPP instance, NPSize *size, michael@0: NPImageFormat format, void *initData, michael@0: NPAsyncSurface *surface); michael@0: michael@0: static NPError michael@0: _finalizeasyncsurface(NPP instance, NPAsyncSurface *surface); michael@0: michael@0: static void michael@0: _setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed); michael@0: michael@0: } /* namespace child */ michael@0: } /* namespace plugins */ michael@0: } /* namespace mozilla */ michael@0: michael@0: const NPNetscapeFuncs PluginModuleChild::sBrowserFuncs = { michael@0: sizeof(sBrowserFuncs), michael@0: (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR, michael@0: mozilla::plugins::child::_geturl, michael@0: mozilla::plugins::child::_posturl, michael@0: mozilla::plugins::child::_requestread, michael@0: mozilla::plugins::child::_newstream, michael@0: mozilla::plugins::child::_write, michael@0: mozilla::plugins::child::_destroystream, michael@0: mozilla::plugins::child::_status, michael@0: mozilla::plugins::child::_useragent, michael@0: mozilla::plugins::child::_memalloc, michael@0: mozilla::plugins::child::_memfree, michael@0: mozilla::plugins::child::_memflush, michael@0: mozilla::plugins::child::_reloadplugins, michael@0: mozilla::plugins::child::_getjavaenv, michael@0: mozilla::plugins::child::_getjavapeer, michael@0: mozilla::plugins::child::_geturlnotify, michael@0: mozilla::plugins::child::_posturlnotify, michael@0: mozilla::plugins::child::_getvalue, michael@0: mozilla::plugins::child::_setvalue, michael@0: mozilla::plugins::child::_invalidaterect, michael@0: mozilla::plugins::child::_invalidateregion, michael@0: mozilla::plugins::child::_forceredraw, michael@0: PluginModuleChild::NPN_GetStringIdentifier, michael@0: PluginModuleChild::NPN_GetStringIdentifiers, michael@0: PluginModuleChild::NPN_GetIntIdentifier, michael@0: PluginModuleChild::NPN_IdentifierIsString, michael@0: PluginModuleChild::NPN_UTF8FromIdentifier, michael@0: PluginModuleChild::NPN_IntFromIdentifier, michael@0: PluginModuleChild::NPN_CreateObject, michael@0: PluginModuleChild::NPN_RetainObject, michael@0: PluginModuleChild::NPN_ReleaseObject, michael@0: mozilla::plugins::child::_invoke, michael@0: mozilla::plugins::child::_invokedefault, michael@0: mozilla::plugins::child::_evaluate, michael@0: mozilla::plugins::child::_getproperty, michael@0: mozilla::plugins::child::_setproperty, michael@0: mozilla::plugins::child::_removeproperty, michael@0: mozilla::plugins::child::_hasproperty, michael@0: mozilla::plugins::child::_hasmethod, michael@0: mozilla::plugins::child::_releasevariantvalue, michael@0: mozilla::plugins::child::_setexception, michael@0: mozilla::plugins::child::_pushpopupsenabledstate, michael@0: mozilla::plugins::child::_poppopupsenabledstate, michael@0: mozilla::plugins::child::_enumerate, michael@0: mozilla::plugins::child::_pluginthreadasynccall, michael@0: mozilla::plugins::child::_construct, michael@0: mozilla::plugins::child::_getvalueforurl, michael@0: mozilla::plugins::child::_setvalueforurl, michael@0: mozilla::plugins::child::_getauthenticationinfo, michael@0: mozilla::plugins::child::_scheduletimer, michael@0: mozilla::plugins::child::_unscheduletimer, michael@0: mozilla::plugins::child::_popupcontextmenu, michael@0: mozilla::plugins::child::_convertpoint, michael@0: nullptr, // handleevent, unimplemented michael@0: nullptr, // unfocusinstance, unimplemented michael@0: mozilla::plugins::child::_urlredirectresponse, michael@0: mozilla::plugins::child::_initasyncsurface, michael@0: mozilla::plugins::child::_finalizeasyncsurface, michael@0: mozilla::plugins::child::_setcurrentasyncsurface michael@0: }; michael@0: michael@0: PluginInstanceChild* michael@0: InstCast(NPP aNPP) michael@0: { michael@0: NS_ABORT_IF_FALSE(!!(aNPP->ndata), "nil instance"); michael@0: return static_cast(aNPP->ndata); michael@0: } michael@0: michael@0: namespace mozilla { michael@0: namespace plugins { michael@0: namespace child { michael@0: michael@0: NPError michael@0: _requestread(NPStream* aStream, michael@0: NPByteRange* aRangeList) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM); michael@0: michael@0: BrowserStreamChild* bs = michael@0: static_cast(static_cast(aStream->ndata)); michael@0: bs->EnsureCorrectStream(aStream); michael@0: return bs->NPN_RequestRead(aRangeList); michael@0: } michael@0: michael@0: NPError michael@0: _geturlnotify(NPP aNPP, michael@0: const char* aRelativeURL, michael@0: const char* aTarget, michael@0: void* aNotifyData) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM); michael@0: michael@0: if (!aNPP) // nullptr check for nspluginwrapper (bug 561690) michael@0: return NPERR_INVALID_INSTANCE_ERROR; michael@0: michael@0: nsCString url = NullableString(aRelativeURL); michael@0: StreamNotifyChild* sn = new StreamNotifyChild(url); michael@0: michael@0: NPError err; michael@0: InstCast(aNPP)->CallPStreamNotifyConstructor( michael@0: sn, url, NullableString(aTarget), false, nsCString(), false, &err); michael@0: michael@0: if (NPERR_NO_ERROR == err) { michael@0: // If NPN_PostURLNotify fails, the parent will immediately send us michael@0: // a PStreamNotifyDestructor, which should not call NPP_URLNotify. michael@0: sn->SetValid(aNotifyData); michael@0: } michael@0: michael@0: return err; michael@0: } michael@0: michael@0: NPError michael@0: _getvalue(NPP aNPP, michael@0: NPNVariable aVariable, michael@0: void* aValue) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM); michael@0: michael@0: switch (aVariable) { michael@0: // Copied from nsNPAPIPlugin.cpp michael@0: case NPNVToolkit: michael@0: #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT) michael@0: *static_cast(aValue) = NPNVGtk2; michael@0: return NPERR_NO_ERROR; michael@0: #endif michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: case NPNVjavascriptEnabledBool: // Intentional fall-through michael@0: case NPNVasdEnabledBool: // Intentional fall-through michael@0: case NPNVisOfflineBool: // Intentional fall-through michael@0: case NPNVSupportsXEmbedBool: // Intentional fall-through michael@0: case NPNVSupportsWindowless: { // Intentional fall-through michael@0: NPError result; michael@0: bool value; michael@0: PluginModuleChild::current()-> michael@0: CallNPN_GetValue_WithBoolReturn(aVariable, &result, &value); michael@0: *(NPBool*)aValue = value ? true : false; michael@0: return result; michael@0: } michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: case NPNVxDisplay: { michael@0: if (aNPP) { michael@0: return InstCast(aNPP)->NPN_GetValue(aVariable, aValue); michael@0: } michael@0: else { michael@0: *(void **)aValue = xt_client_get_display(); michael@0: } michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: case NPNVxtAppContext: michael@0: return NPERR_GENERIC_ERROR; michael@0: #endif michael@0: default: { michael@0: if (aNPP) { michael@0: return InstCast(aNPP)->NPN_GetValue(aVariable, aValue); michael@0: } michael@0: michael@0: NS_WARNING("Null NPP!"); michael@0: return NPERR_INVALID_INSTANCE_ERROR; michael@0: } michael@0: } michael@0: michael@0: NS_NOTREACHED("Shouldn't get here!"); michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: NPError michael@0: _setvalue(NPP aNPP, michael@0: NPPVariable aVariable, michael@0: void* aValue) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM); michael@0: return InstCast(aNPP)->NPN_SetValue(aVariable, aValue); michael@0: } michael@0: michael@0: NPError michael@0: _geturl(NPP aNPP, michael@0: const char* aRelativeURL, michael@0: const char* aTarget) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM); michael@0: michael@0: NPError err; michael@0: InstCast(aNPP)->CallNPN_GetURL(NullableString(aRelativeURL), michael@0: NullableString(aTarget), &err); michael@0: return err; michael@0: } michael@0: michael@0: NPError michael@0: _posturlnotify(NPP aNPP, michael@0: const char* aRelativeURL, michael@0: const char* aTarget, michael@0: uint32_t aLength, michael@0: const char* aBuffer, michael@0: NPBool aIsFile, michael@0: void* aNotifyData) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM); michael@0: michael@0: if (!aBuffer) michael@0: return NPERR_INVALID_PARAM; michael@0: michael@0: nsCString url = NullableString(aRelativeURL); michael@0: StreamNotifyChild* sn = new StreamNotifyChild(url); michael@0: michael@0: NPError err; michael@0: InstCast(aNPP)->CallPStreamNotifyConstructor( michael@0: sn, url, NullableString(aTarget), true, michael@0: nsCString(aBuffer, aLength), aIsFile, &err); michael@0: michael@0: if (NPERR_NO_ERROR == err) { michael@0: // If NPN_PostURLNotify fails, the parent will immediately send us michael@0: // a PStreamNotifyDestructor, which should not call NPP_URLNotify. michael@0: sn->SetValid(aNotifyData); michael@0: } michael@0: michael@0: return err; michael@0: } michael@0: michael@0: NPError michael@0: _posturl(NPP aNPP, michael@0: const char* aRelativeURL, michael@0: const char* aTarget, michael@0: uint32_t aLength, michael@0: const char* aBuffer, michael@0: NPBool aIsFile) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM); michael@0: michael@0: NPError err; michael@0: // FIXME what should happen when |aBuffer| is null? michael@0: InstCast(aNPP)->CallNPN_PostURL(NullableString(aRelativeURL), michael@0: NullableString(aTarget), michael@0: nsDependentCString(aBuffer, aLength), michael@0: aIsFile, &err); michael@0: return err; michael@0: } michael@0: michael@0: NPError michael@0: _newstream(NPP aNPP, michael@0: NPMIMEType aMIMEType, michael@0: const char* aWindow, michael@0: NPStream** aStream) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM); michael@0: return InstCast(aNPP)->NPN_NewStream(aMIMEType, aWindow, aStream); michael@0: } michael@0: michael@0: int32_t michael@0: _write(NPP aNPP, michael@0: NPStream* aStream, michael@0: int32_t aLength, michael@0: void* aBuffer) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(0); michael@0: michael@0: PluginStreamChild* ps = michael@0: static_cast(static_cast(aStream->ndata)); michael@0: ps->EnsureCorrectInstance(InstCast(aNPP)); michael@0: ps->EnsureCorrectStream(aStream); michael@0: return ps->NPN_Write(aLength, aBuffer); michael@0: } michael@0: michael@0: NPError michael@0: _destroystream(NPP aNPP, michael@0: NPStream* aStream, michael@0: NPError aReason) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM); michael@0: michael@0: PluginInstanceChild* p = InstCast(aNPP); michael@0: AStream* s = static_cast(aStream->ndata); michael@0: if (s->IsBrowserStream()) { michael@0: BrowserStreamChild* bs = static_cast(s); michael@0: bs->EnsureCorrectInstance(p); michael@0: bs->NPN_DestroyStream(aReason); michael@0: } michael@0: else { michael@0: PluginStreamChild* ps = static_cast(s); michael@0: ps->EnsureCorrectInstance(p); michael@0: PPluginStreamChild::Call__delete__(ps, aReason, false); michael@0: } michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: void michael@0: _status(NPP aNPP, michael@0: const char* aMessage) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD_VOID(); michael@0: NS_WARNING("Not yet implemented!"); michael@0: } michael@0: michael@0: void michael@0: _memfree(void* aPtr) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: // Only assert plugin thread here for consistency with in-process plugins. michael@0: AssertPluginThread(); michael@0: NS_Free(aPtr); michael@0: } michael@0: michael@0: uint32_t michael@0: _memflush(uint32_t aSize) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: // Only assert plugin thread here for consistency with in-process plugins. michael@0: AssertPluginThread(); michael@0: return 0; michael@0: } michael@0: michael@0: void michael@0: _reloadplugins(NPBool aReloadPages) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD_VOID(); michael@0: michael@0: PluginModuleChild::current()->SendNPN_ReloadPlugins(!!aReloadPages); michael@0: } michael@0: michael@0: void michael@0: _invalidaterect(NPP aNPP, michael@0: NPRect* aInvalidRect) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD_VOID(); michael@0: // nullptr check for nspluginwrapper (bug 548434) michael@0: if (aNPP) { michael@0: InstCast(aNPP)->InvalidateRect(aInvalidRect); michael@0: } michael@0: } michael@0: michael@0: void michael@0: _invalidateregion(NPP aNPP, michael@0: NPRegion aInvalidRegion) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD_VOID(); michael@0: NS_WARNING("Not yet implemented!"); michael@0: } michael@0: michael@0: void michael@0: _forceredraw(NPP aNPP) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD_VOID(); michael@0: michael@0: // We ignore calls to NPN_ForceRedraw. Such calls should michael@0: // never be necessary. michael@0: } michael@0: michael@0: const char* michael@0: _useragent(NPP aNPP) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(nullptr); michael@0: return PluginModuleChild::current()->GetUserAgent(); michael@0: } michael@0: michael@0: void* michael@0: _memalloc(uint32_t aSize) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: // Only assert plugin thread here for consistency with in-process plugins. michael@0: AssertPluginThread(); michael@0: return NS_Alloc(aSize); michael@0: } michael@0: michael@0: // Deprecated entry points for the old Java plugin. michael@0: void* /* OJI type: JRIEnv* */ michael@0: _getjavaenv(void) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: return 0; michael@0: } michael@0: michael@0: void* /* OJI type: jref */ michael@0: _getjavapeer(NPP aNPP) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: return 0; michael@0: } michael@0: michael@0: bool michael@0: _invoke(NPP aNPP, michael@0: NPObject* aNPObj, michael@0: NPIdentifier aMethod, michael@0: const NPVariant* aArgs, michael@0: uint32_t aArgCount, michael@0: NPVariant* aResult) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(false); michael@0: michael@0: if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->invoke) michael@0: return false; michael@0: michael@0: return aNPObj->_class->invoke(aNPObj, aMethod, aArgs, aArgCount, aResult); michael@0: } michael@0: michael@0: bool michael@0: _invokedefault(NPP aNPP, michael@0: NPObject* aNPObj, michael@0: const NPVariant* aArgs, michael@0: uint32_t aArgCount, michael@0: NPVariant* aResult) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(false); michael@0: michael@0: if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->invokeDefault) michael@0: return false; michael@0: michael@0: return aNPObj->_class->invokeDefault(aNPObj, aArgs, aArgCount, aResult); michael@0: } michael@0: michael@0: bool michael@0: _evaluate(NPP aNPP, michael@0: NPObject* aObject, michael@0: NPString* aScript, michael@0: NPVariant* aResult) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(false); michael@0: michael@0: if (!(aNPP && aObject && aScript && aResult)) { michael@0: NS_ERROR("Bad arguments!"); michael@0: return false; michael@0: } michael@0: michael@0: PluginScriptableObjectChild* actor = michael@0: InstCast(aNPP)->GetActorForNPObject(aObject); michael@0: if (!actor) { michael@0: NS_ERROR("Failed to create actor?!"); michael@0: return false; michael@0: } michael@0: michael@0: #ifdef XP_WIN michael@0: if (gDelayFlashFocusReplyUntilEval) { michael@0: ReplyMessage(0); michael@0: gDelayFlashFocusReplyUntilEval = false; michael@0: } michael@0: #endif michael@0: michael@0: return actor->Evaluate(aScript, aResult); michael@0: } michael@0: michael@0: bool michael@0: _getproperty(NPP aNPP, michael@0: NPObject* aNPObj, michael@0: NPIdentifier aPropertyName, michael@0: NPVariant* aResult) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(false); michael@0: michael@0: if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->getProperty) michael@0: return false; michael@0: michael@0: return aNPObj->_class->getProperty(aNPObj, aPropertyName, aResult); michael@0: } michael@0: michael@0: bool michael@0: _setproperty(NPP aNPP, michael@0: NPObject* aNPObj, michael@0: NPIdentifier aPropertyName, michael@0: const NPVariant* aValue) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(false); michael@0: michael@0: if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->setProperty) michael@0: return false; michael@0: michael@0: return aNPObj->_class->setProperty(aNPObj, aPropertyName, aValue); michael@0: } michael@0: michael@0: bool michael@0: _removeproperty(NPP aNPP, michael@0: NPObject* aNPObj, michael@0: NPIdentifier aPropertyName) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(false); michael@0: michael@0: if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->removeProperty) michael@0: return false; michael@0: michael@0: return aNPObj->_class->removeProperty(aNPObj, aPropertyName); michael@0: } michael@0: michael@0: bool michael@0: _hasproperty(NPP aNPP, michael@0: NPObject* aNPObj, michael@0: NPIdentifier aPropertyName) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(false); michael@0: michael@0: if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->hasProperty) michael@0: return false; michael@0: michael@0: return aNPObj->_class->hasProperty(aNPObj, aPropertyName); michael@0: } michael@0: michael@0: bool michael@0: _hasmethod(NPP aNPP, michael@0: NPObject* aNPObj, michael@0: NPIdentifier aMethodName) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(false); michael@0: michael@0: if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->hasMethod) michael@0: return false; michael@0: michael@0: return aNPObj->_class->hasMethod(aNPObj, aMethodName); michael@0: } michael@0: michael@0: bool michael@0: _enumerate(NPP aNPP, michael@0: NPObject* aNPObj, michael@0: NPIdentifier** aIdentifiers, michael@0: uint32_t* aCount) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(false); michael@0: michael@0: if (!aNPP || !aNPObj || !aNPObj->_class) michael@0: return false; michael@0: michael@0: if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(aNPObj->_class) || michael@0: !aNPObj->_class->enumerate) { michael@0: *aIdentifiers = 0; michael@0: *aCount = 0; michael@0: return true; michael@0: } michael@0: michael@0: return aNPObj->_class->enumerate(aNPObj, aIdentifiers, aCount); michael@0: } michael@0: michael@0: bool michael@0: _construct(NPP aNPP, michael@0: NPObject* aNPObj, michael@0: const NPVariant* aArgs, michael@0: uint32_t aArgCount, michael@0: NPVariant* aResult) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(false); michael@0: michael@0: if (!aNPP || !aNPObj || !aNPObj->_class || michael@0: !NP_CLASS_STRUCT_VERSION_HAS_CTOR(aNPObj->_class) || michael@0: !aNPObj->_class->construct) { michael@0: return false; michael@0: } michael@0: michael@0: return aNPObj->_class->construct(aNPObj, aArgs, aArgCount, aResult); michael@0: } michael@0: michael@0: void michael@0: _releasevariantvalue(NPVariant* aVariant) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: // Only assert plugin thread here for consistency with in-process plugins. michael@0: AssertPluginThread(); michael@0: michael@0: if (NPVARIANT_IS_STRING(*aVariant)) { michael@0: NPString str = NPVARIANT_TO_STRING(*aVariant); michael@0: free(const_cast(str.UTF8Characters)); michael@0: } michael@0: else if (NPVARIANT_IS_OBJECT(*aVariant)) { michael@0: NPObject* object = NPVARIANT_TO_OBJECT(*aVariant); michael@0: if (object) { michael@0: PluginModuleChild::NPN_ReleaseObject(object); michael@0: } michael@0: } michael@0: VOID_TO_NPVARIANT(*aVariant); michael@0: } michael@0: michael@0: void michael@0: _setexception(NPObject* aNPObj, michael@0: const NPUTF8* aMessage) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD_VOID(); michael@0: michael@0: PluginModuleChild* self = PluginModuleChild::current(); michael@0: PluginScriptableObjectChild* actor = nullptr; michael@0: if (aNPObj) { michael@0: actor = self->GetActorForNPObject(aNPObj); michael@0: if (!actor) { michael@0: NS_ERROR("Failed to get actor!"); michael@0: return; michael@0: } michael@0: } michael@0: michael@0: self->SendNPN_SetException(static_cast(actor), michael@0: NullableString(aMessage)); michael@0: } michael@0: michael@0: void michael@0: _pushpopupsenabledstate(NPP aNPP, michael@0: NPBool aEnabled) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD_VOID(); michael@0: michael@0: InstCast(aNPP)->CallNPN_PushPopupsEnabledState(aEnabled ? true : false); michael@0: } michael@0: michael@0: void michael@0: _poppopupsenabledstate(NPP aNPP) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD_VOID(); michael@0: michael@0: InstCast(aNPP)->CallNPN_PopPopupsEnabledState(); michael@0: } michael@0: michael@0: void michael@0: _pluginthreadasynccall(NPP aNPP, michael@0: PluginThreadCallback aFunc, michael@0: void* aUserData) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: if (!aFunc) michael@0: return; michael@0: michael@0: InstCast(aNPP)->AsyncCall(aFunc, aUserData); michael@0: } michael@0: michael@0: NPError michael@0: _getvalueforurl(NPP npp, NPNURLVariable variable, const char *url, michael@0: char **value, uint32_t *len) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: AssertPluginThread(); michael@0: michael@0: if (!url) michael@0: return NPERR_INVALID_URL; michael@0: michael@0: if (!npp || !value || !len) michael@0: return NPERR_INVALID_PARAM; michael@0: michael@0: switch (variable) { michael@0: case NPNURLVCookie: michael@0: case NPNURLVProxy: michael@0: nsCString v; michael@0: NPError result; michael@0: InstCast(npp)-> michael@0: CallNPN_GetValueForURL(variable, nsCString(url), &v, &result); michael@0: if (NPERR_NO_ERROR == result) { michael@0: *value = ToNewCString(v); michael@0: *len = v.Length(); michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: michael@0: NPError michael@0: _setvalueforurl(NPP npp, NPNURLVariable variable, const char *url, michael@0: const char *value, uint32_t len) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: AssertPluginThread(); michael@0: michael@0: if (!value) michael@0: return NPERR_INVALID_PARAM; michael@0: michael@0: if (!url) michael@0: return NPERR_INVALID_URL; michael@0: michael@0: switch (variable) { michael@0: case NPNURLVCookie: michael@0: case NPNURLVProxy: michael@0: NPError result; michael@0: InstCast(npp)->CallNPN_SetValueForURL(variable, nsCString(url), michael@0: nsDependentCString(value, len), michael@0: &result); michael@0: return result; michael@0: } michael@0: michael@0: return NPERR_INVALID_PARAM; michael@0: } michael@0: michael@0: NPError michael@0: _getauthenticationinfo(NPP npp, const char *protocol, michael@0: const char *host, int32_t port, michael@0: const char *scheme, const char *realm, michael@0: char **username, uint32_t *ulen, michael@0: char **password, uint32_t *plen) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: AssertPluginThread(); michael@0: michael@0: if (!protocol || !host || !scheme || !realm || !username || !ulen || michael@0: !password || !plen) michael@0: return NPERR_INVALID_PARAM; michael@0: michael@0: nsCString u; michael@0: nsCString p; michael@0: NPError result; michael@0: InstCast(npp)-> michael@0: CallNPN_GetAuthenticationInfo(nsDependentCString(protocol), michael@0: nsDependentCString(host), michael@0: port, michael@0: nsDependentCString(scheme), michael@0: nsDependentCString(realm), michael@0: &u, &p, &result); michael@0: if (NPERR_NO_ERROR == result) { michael@0: *username = ToNewCString(u); michael@0: *ulen = u.Length(); michael@0: *password = ToNewCString(p); michael@0: *plen = p.Length(); michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: uint32_t michael@0: _scheduletimer(NPP npp, uint32_t interval, NPBool repeat, michael@0: void (*timerFunc)(NPP npp, uint32_t timerID)) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: AssertPluginThread(); michael@0: return InstCast(npp)->ScheduleTimer(interval, repeat, timerFunc); michael@0: } michael@0: michael@0: void michael@0: _unscheduletimer(NPP npp, uint32_t timerID) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: AssertPluginThread(); michael@0: InstCast(npp)->UnscheduleTimer(timerID); michael@0: } michael@0: michael@0: michael@0: #ifdef OS_MACOSX michael@0: static void ProcessBrowserEvents(void* pluginModule) { michael@0: PluginModuleChild* pmc = static_cast(pluginModule); michael@0: michael@0: if (!pmc) michael@0: return; michael@0: michael@0: pmc->CallProcessSomeEvents(); michael@0: } michael@0: #endif michael@0: michael@0: NPError michael@0: _popupcontextmenu(NPP instance, NPMenu* menu) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: AssertPluginThread(); michael@0: michael@0: #ifdef MOZ_WIDGET_COCOA michael@0: double pluginX, pluginY; michael@0: double screenX, screenY; michael@0: michael@0: const NPCocoaEvent* currentEvent = InstCast(instance)->getCurrentEvent(); michael@0: if (!currentEvent) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: // Ensure that the events has an x/y value. michael@0: if (currentEvent->type != NPCocoaEventMouseDown && michael@0: currentEvent->type != NPCocoaEventMouseUp && michael@0: currentEvent->type != NPCocoaEventMouseMoved && michael@0: currentEvent->type != NPCocoaEventMouseEntered && michael@0: currentEvent->type != NPCocoaEventMouseExited && michael@0: currentEvent->type != NPCocoaEventMouseDragged) { michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: pluginX = currentEvent->data.mouse.pluginX; michael@0: pluginY = currentEvent->data.mouse.pluginY; michael@0: michael@0: if ((pluginX < 0.0) || (pluginY < 0.0)) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: NPBool success = _convertpoint(instance, michael@0: pluginX, pluginY, NPCoordinateSpacePlugin, michael@0: &screenX, &screenY, NPCoordinateSpaceScreen); michael@0: michael@0: if (success) { michael@0: return mozilla::plugins::PluginUtilsOSX::ShowCocoaContextMenu(menu, michael@0: screenX, screenY, michael@0: PluginModuleChild::current(), michael@0: ProcessBrowserEvents); michael@0: } else { michael@0: NS_WARNING("Convertpoint failed, could not created contextmenu."); michael@0: return NPERR_GENERIC_ERROR; michael@0: } michael@0: michael@0: #else michael@0: NS_WARNING("Not supported on this platform!"); michael@0: return NPERR_GENERIC_ERROR; michael@0: #endif michael@0: } michael@0: michael@0: NPBool michael@0: _convertpoint(NPP instance, michael@0: double sourceX, double sourceY, NPCoordinateSpace sourceSpace, michael@0: double *destX, double *destY, NPCoordinateSpace destSpace) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: if (!IsPluginThread()) { michael@0: NS_WARNING("Not running on the plugin's main thread!"); michael@0: return false; michael@0: } michael@0: michael@0: double rDestX = 0; michael@0: bool ignoreDestX = !destX; michael@0: double rDestY = 0; michael@0: bool ignoreDestY = !destY; michael@0: bool result = false; michael@0: InstCast(instance)->CallNPN_ConvertPoint(sourceX, ignoreDestX, sourceY, ignoreDestY, sourceSpace, destSpace, michael@0: &rDestX, &rDestY, &result); michael@0: if (result) { michael@0: if (destX) michael@0: *destX = rDestX; michael@0: if (destY) michael@0: *destY = rDestY; michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: _urlredirectresponse(NPP instance, void* notifyData, NPBool allow) michael@0: { michael@0: InstCast(instance)->NPN_URLRedirectResponse(notifyData, allow); michael@0: } michael@0: michael@0: NPError michael@0: _initasyncsurface(NPP instance, NPSize *size, michael@0: NPImageFormat format, void *initData, michael@0: NPAsyncSurface *surface) michael@0: { michael@0: return InstCast(instance)->NPN_InitAsyncSurface(size, format, initData, surface); michael@0: } michael@0: michael@0: NPError michael@0: _finalizeasyncsurface(NPP instance, NPAsyncSurface *surface) michael@0: { michael@0: return InstCast(instance)->NPN_FinalizeAsyncSurface(surface); michael@0: } michael@0: michael@0: void michael@0: _setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed) michael@0: { michael@0: InstCast(instance)->NPN_SetCurrentAsyncSurface(surface, changed); michael@0: } michael@0: michael@0: } /* namespace child */ michael@0: } /* namespace plugins */ michael@0: } /* namespace mozilla */ michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: bool michael@0: PluginModuleChild::AnswerNP_GetEntryPoints(NPError* _retval) michael@0: { michael@0: PLUGIN_LOG_DEBUG_METHOD; michael@0: AssertPluginThread(); michael@0: michael@0: #if defined(OS_LINUX) || defined(OS_BSD) michael@0: return true; michael@0: #elif defined(OS_WIN) || defined(OS_MACOSX) michael@0: *_retval = mGetEntryPointsFunc(&mFunctions); michael@0: return true; michael@0: #else michael@0: # error Please implement me for your platform michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::AnswerNP_Initialize(const uint32_t& aFlags, NPError* _retval) michael@0: { michael@0: PLUGIN_LOG_DEBUG_METHOD; michael@0: AssertPluginThread(); michael@0: michael@0: mAsyncDrawingAllowed = aFlags & kAllowAsyncDrawing; michael@0: michael@0: #ifdef OS_WIN michael@0: SetEventHooks(); michael@0: #endif michael@0: michael@0: #ifdef MOZ_X11 michael@0: // Send the parent our X socket to act as a proxy reference for our X michael@0: // resources. michael@0: int xSocketFd = ConnectionNumber(DefaultXDisplay()); michael@0: SendBackUpXResources(FileDescriptor(xSocketFd)); michael@0: #endif michael@0: michael@0: #if defined(OS_LINUX) || defined(OS_BSD) michael@0: *_retval = mInitializeFunc(&sBrowserFuncs, &mFunctions); michael@0: return true; michael@0: #elif defined(OS_WIN) || defined(OS_MACOSX) michael@0: *_retval = mInitializeFunc(&sBrowserFuncs); michael@0: return true; michael@0: #else michael@0: # error Please implement me for your platform michael@0: #endif michael@0: } michael@0: michael@0: PPluginIdentifierChild* michael@0: PluginModuleChild::AllocPPluginIdentifierChild(const nsCString& aString, michael@0: const int32_t& aInt, michael@0: const bool& aTemporary) michael@0: { michael@0: // We cannot call SetPermanent within this function because Manager() isn't michael@0: // set up yet. michael@0: if (aString.IsVoid()) { michael@0: return new PluginIdentifierChildInt(aInt); michael@0: } michael@0: return new PluginIdentifierChildString(aString); michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::RecvPPluginIdentifierConstructor(PPluginIdentifierChild* actor, michael@0: const nsCString& aString, michael@0: const int32_t& aInt, michael@0: const bool& aTemporary) michael@0: { michael@0: if (!aTemporary) { michael@0: static_cast(actor)->MakePermanent(); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::DeallocPPluginIdentifierChild(PPluginIdentifierChild* aActor) michael@0: { michael@0: delete aActor; michael@0: return true; michael@0: } michael@0: michael@0: #if defined(XP_WIN) michael@0: BOOL WINAPI michael@0: PMCGetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi) michael@0: { michael@0: if (!pwi) michael@0: return FALSE; michael@0: michael@0: if (!sGetWindowInfoPtrStub) { michael@0: NS_ASSERTION(FALSE, "Something is horribly wrong in PMCGetWindowInfoHook!"); michael@0: return FALSE; michael@0: } michael@0: michael@0: if (!sBrowserHwnd) { michael@0: wchar_t szClass[20]; michael@0: if (GetClassNameW(hWnd, szClass, ArrayLength(szClass)) && michael@0: !wcscmp(szClass, kMozillaWindowClass)) { michael@0: sBrowserHwnd = hWnd; michael@0: } michael@0: } michael@0: // Oddity: flash does strange rect comparisons for mouse input destined for michael@0: // it's internal settings window. Post removing sub widgets for tabs, touch michael@0: // this up so they get the rect they expect. michael@0: // XXX potentially tie this to a specific major version? michael@0: BOOL result = sGetWindowInfoPtrStub(hWnd, pwi); michael@0: if (sBrowserHwnd && sBrowserHwnd == hWnd) michael@0: pwi->rcWindow = pwi->rcClient; michael@0: return result; michael@0: } michael@0: #endif michael@0: michael@0: PPluginInstanceChild* michael@0: PluginModuleChild::AllocPPluginInstanceChild(const nsCString& aMimeType, michael@0: const uint16_t& aMode, michael@0: const InfallibleTArray& aNames, michael@0: const InfallibleTArray& aValues, michael@0: NPError* rv) michael@0: { michael@0: PLUGIN_LOG_DEBUG_METHOD; michael@0: AssertPluginThread(); michael@0: michael@0: InitQuirksModes(aMimeType); michael@0: michael@0: #ifdef XP_WIN michael@0: if ((mQuirks & QUIRK_FLASH_HOOK_GETWINDOWINFO) && michael@0: !sGetWindowInfoPtrStub) { michael@0: sUser32Intercept.Init("user32.dll"); michael@0: sUser32Intercept.AddHook("GetWindowInfo", reinterpret_cast(PMCGetWindowInfoHook), michael@0: (void**) &sGetWindowInfoPtrStub); michael@0: } michael@0: #endif michael@0: michael@0: return new PluginInstanceChild(&mFunctions); michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::InitQuirksModes(const nsCString& aMimeType) michael@0: { michael@0: if (mQuirks != QUIRKS_NOT_INITIALIZED) michael@0: return; michael@0: mQuirks = 0; michael@0: // application/x-silverlight michael@0: // application/x-silverlight-2 michael@0: NS_NAMED_LITERAL_CSTRING(silverlight, "application/x-silverlight"); michael@0: if (FindInReadable(silverlight, aMimeType)) { michael@0: mQuirks |= QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT; michael@0: #ifdef OS_WIN michael@0: mQuirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK; michael@0: mQuirks |= QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT; michael@0: #endif michael@0: } michael@0: michael@0: #ifdef OS_WIN michael@0: // application/x-shockwave-flash michael@0: NS_NAMED_LITERAL_CSTRING(flash, "application/x-shockwave-flash"); michael@0: if (FindInReadable(flash, aMimeType)) { michael@0: mQuirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK; michael@0: mQuirks |= QUIRK_FLASH_THROTTLE_WMUSER_EVENTS; michael@0: mQuirks |= QUIRK_FLASH_HOOK_SETLONGPTR; michael@0: mQuirks |= QUIRK_FLASH_HOOK_GETWINDOWINFO; michael@0: mQuirks |= QUIRK_FLASH_FIXUP_MOUSE_CAPTURE; michael@0: } michael@0: michael@0: // QuickTime plugin usually loaded with audio/mpeg mimetype michael@0: NS_NAMED_LITERAL_CSTRING(quicktime, "npqtplugin"); michael@0: if (FindInReadable(quicktime, mPluginFilename)) { michael@0: mQuirks |= QUIRK_QUICKTIME_AVOID_SETWINDOW; michael@0: } michael@0: #endif michael@0: michael@0: #ifdef XP_MACOSX michael@0: // Whitelist Flash and Quicktime to support offline renderer michael@0: NS_NAMED_LITERAL_CSTRING(flash, "application/x-shockwave-flash"); michael@0: NS_NAMED_LITERAL_CSTRING(quicktime, "QuickTime Plugin.plugin"); michael@0: if (FindInReadable(flash, aMimeType)) { michael@0: mQuirks |= QUIRK_FLASH_AVOID_CGMODE_CRASHES; michael@0: } michael@0: if (FindInReadable(flash, aMimeType) || michael@0: FindInReadable(quicktime, mPluginFilename)) { michael@0: mQuirks |= QUIRK_ALLOW_OFFLINE_RENDERER; michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::AnswerPPluginInstanceConstructor(PPluginInstanceChild* aActor, michael@0: const nsCString& aMimeType, michael@0: const uint16_t& aMode, michael@0: const InfallibleTArray& aNames, michael@0: const InfallibleTArray& aValues, michael@0: NPError* rv) michael@0: { michael@0: PLUGIN_LOG_DEBUG_METHOD; michael@0: AssertPluginThread(); michael@0: michael@0: PluginInstanceChild* childInstance = michael@0: reinterpret_cast(aActor); michael@0: NS_ASSERTION(childInstance, "Null actor!"); michael@0: michael@0: // unpack the arguments into a C format michael@0: int argc = aNames.Length(); michael@0: NS_ASSERTION(argc == (int) aValues.Length(), michael@0: "argn.length != argv.length"); michael@0: michael@0: nsAutoArrayPtr argn(new char*[1 + argc]); michael@0: nsAutoArrayPtr argv(new char*[1 + argc]); michael@0: argn[argc] = 0; michael@0: argv[argc] = 0; michael@0: michael@0: for (int i = 0; i < argc; ++i) { michael@0: argn[i] = const_cast(NullableStringGet(aNames[i])); michael@0: argv[i] = const_cast(NullableStringGet(aValues[i])); michael@0: } michael@0: michael@0: NPP npp = childInstance->GetNPP(); michael@0: michael@0: // FIXME/cjones: use SAFE_CALL stuff michael@0: *rv = mFunctions.newp((char*)NullableStringGet(aMimeType), michael@0: npp, michael@0: aMode, michael@0: argc, michael@0: argn, michael@0: argv, michael@0: 0); michael@0: if (NPERR_NO_ERROR != *rv) { michael@0: return true; michael@0: } michael@0: michael@0: childInstance->Initialize(); michael@0: michael@0: #if defined(XP_MACOSX) && defined(__i386__) michael@0: // If an i386 Mac OS X plugin has selected the Carbon event model then michael@0: // we have to fail. We do not support putting Carbon event model plugins michael@0: // out of process. Note that Carbon is the default model so out of process michael@0: // plugins need to actively negotiate something else in order to work michael@0: // out of process. michael@0: if (childInstance->EventModel() == NPEventModelCarbon) { michael@0: // Send notification that a plugin tried to negotiate Carbon NPAPI so that michael@0: // users can be notified that restarting the browser in i386 mode may allow michael@0: // them to use the plugin. michael@0: childInstance->SendNegotiatedCarbon(); michael@0: michael@0: // Fail to instantiate. michael@0: *rv = NPERR_MODULE_LOAD_FAILED_ERROR; michael@0: } michael@0: #endif michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::DeallocPPluginInstanceChild(PPluginInstanceChild* aActor) michael@0: { michael@0: PLUGIN_LOG_DEBUG_METHOD; michael@0: AssertPluginThread(); michael@0: michael@0: delete aActor; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: NPObject* michael@0: PluginModuleChild::NPN_CreateObject(NPP aNPP, NPClass* aClass) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: ENSURE_PLUGIN_THREAD(nullptr); michael@0: michael@0: PluginInstanceChild* i = InstCast(aNPP); michael@0: if (i->mDeletingHash) { michael@0: NS_ERROR("Plugin used NPP after NPP_Destroy"); michael@0: return nullptr; michael@0: } michael@0: michael@0: NPObject* newObject; michael@0: if (aClass && aClass->allocate) { michael@0: newObject = aClass->allocate(aNPP, aClass); michael@0: } michael@0: else { michael@0: newObject = reinterpret_cast(child::_memalloc(sizeof(NPObject))); michael@0: } michael@0: michael@0: if (newObject) { michael@0: newObject->_class = aClass; michael@0: newObject->referenceCount = 1; michael@0: NS_LOG_ADDREF(newObject, 1, "NPObject", sizeof(NPObject)); michael@0: } michael@0: michael@0: NPObjectData* d = static_cast(i->Manager()) michael@0: ->mObjectMap.PutEntry(newObject); michael@0: NS_ASSERTION(!d->instance, "New NPObject already mapped?"); michael@0: d->instance = i; michael@0: michael@0: return newObject; michael@0: } michael@0: michael@0: NPObject* michael@0: PluginModuleChild::NPN_RetainObject(NPObject* aNPObj) michael@0: { michael@0: AssertPluginThread(); michael@0: michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: int32_t refCnt = michael@0: #endif michael@0: PR_ATOMIC_INCREMENT((int32_t*)&aNPObj->referenceCount); michael@0: NS_LOG_ADDREF(aNPObj, refCnt, "NPObject", sizeof(NPObject)); michael@0: michael@0: return aNPObj; michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::NPN_ReleaseObject(NPObject* aNPObj) michael@0: { michael@0: AssertPluginThread(); michael@0: michael@0: NPObjectData* d = current()->mObjectMap.GetEntry(aNPObj); michael@0: if (!d) { michael@0: NS_ERROR("Releasing object not in mObjectMap?"); michael@0: return; michael@0: } michael@0: michael@0: DeletingObjectEntry* doe = nullptr; michael@0: if (d->instance->mDeletingHash) { michael@0: doe = d->instance->mDeletingHash->GetEntry(aNPObj); michael@0: if (!doe) { michael@0: NS_ERROR("An object for a destroyed instance isn't in the instance deletion hash"); michael@0: return; michael@0: } michael@0: if (doe->mDeleted) michael@0: return; michael@0: } michael@0: michael@0: int32_t refCnt = PR_ATOMIC_DECREMENT((int32_t*)&aNPObj->referenceCount); michael@0: NS_LOG_RELEASE(aNPObj, refCnt, "NPObject"); michael@0: michael@0: if (refCnt == 0) { michael@0: DeallocNPObject(aNPObj); michael@0: if (doe) michael@0: doe->mDeleted = true; michael@0: } michael@0: return; michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::DeallocNPObject(NPObject* aNPObj) michael@0: { michael@0: if (aNPObj->_class && aNPObj->_class->deallocate) { michael@0: aNPObj->_class->deallocate(aNPObj); michael@0: } else { michael@0: child::_memfree(aNPObj); michael@0: } michael@0: michael@0: NPObjectData* d = current()->mObjectMap.GetEntry(aNPObj); michael@0: if (d->actor) michael@0: d->actor->NPObjectDestroyed(); michael@0: michael@0: current()->mObjectMap.RemoveEntry(aNPObj); michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::FindNPObjectsForInstance(PluginInstanceChild* instance) michael@0: { michael@0: NS_ASSERTION(instance->mDeletingHash, "filling null mDeletingHash?"); michael@0: mObjectMap.EnumerateEntries(CollectForInstance, instance); michael@0: } michael@0: michael@0: PLDHashOperator michael@0: PluginModuleChild::CollectForInstance(NPObjectData* d, void* userArg) michael@0: { michael@0: PluginInstanceChild* instance = static_cast(userArg); michael@0: if (d->instance == instance) { michael@0: NPObject* o = d->GetKey(); michael@0: instance->mDeletingHash->PutEntry(o); michael@0: } michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: NPIdentifier michael@0: PluginModuleChild::NPN_GetStringIdentifier(const NPUTF8* aName) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: AssertPluginThread(); michael@0: michael@0: if (!aName) michael@0: return 0; michael@0: michael@0: PluginModuleChild* self = PluginModuleChild::current(); michael@0: nsDependentCString name(aName); michael@0: michael@0: PluginIdentifierChildString* ident = self->mStringIdentifiers.Get(name); michael@0: if (!ident) { michael@0: nsCString nameCopy(name); michael@0: michael@0: ident = new PluginIdentifierChildString(nameCopy); michael@0: self->SendPPluginIdentifierConstructor(ident, nameCopy, -1, false); michael@0: } michael@0: ident->MakePermanent(); michael@0: return ident; michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::NPN_GetStringIdentifiers(const NPUTF8** aNames, michael@0: int32_t aNameCount, michael@0: NPIdentifier* aIdentifiers) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: AssertPluginThread(); michael@0: michael@0: if (!(aNames && aNameCount > 0 && aIdentifiers)) { michael@0: NS_RUNTIMEABORT("Bad input! Headed for a crash!"); michael@0: } michael@0: michael@0: PluginModuleChild* self = PluginModuleChild::current(); michael@0: michael@0: for (int32_t index = 0; index < aNameCount; ++index) { michael@0: if (!aNames[index]) { michael@0: aIdentifiers[index] = 0; michael@0: continue; michael@0: } michael@0: nsDependentCString name(aNames[index]); michael@0: PluginIdentifierChildString* ident = self->mStringIdentifiers.Get(name); michael@0: if (!ident) { michael@0: nsCString nameCopy(name); michael@0: michael@0: ident = new PluginIdentifierChildString(nameCopy); michael@0: self->SendPPluginIdentifierConstructor(ident, nameCopy, -1, false); michael@0: } michael@0: ident->MakePermanent(); michael@0: aIdentifiers[index] = ident; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: PluginModuleChild::NPN_IdentifierIsString(NPIdentifier aIdentifier) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: michael@0: PluginIdentifierChild* ident = michael@0: static_cast(aIdentifier); michael@0: return ident->IsString(); michael@0: } michael@0: michael@0: NPIdentifier michael@0: PluginModuleChild::NPN_GetIntIdentifier(int32_t aIntId) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: AssertPluginThread(); michael@0: michael@0: PluginModuleChild* self = PluginModuleChild::current(); michael@0: michael@0: PluginIdentifierChildInt* ident = self->mIntIdentifiers.Get(aIntId); michael@0: if (!ident) { michael@0: nsCString voidString; michael@0: voidString.SetIsVoid(true); michael@0: michael@0: ident = new PluginIdentifierChildInt(aIntId); michael@0: self->SendPPluginIdentifierConstructor(ident, voidString, aIntId, false); michael@0: } michael@0: ident->MakePermanent(); michael@0: return ident; michael@0: } michael@0: michael@0: NPUTF8* michael@0: PluginModuleChild::NPN_UTF8FromIdentifier(NPIdentifier aIdentifier) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: michael@0: if (static_cast(aIdentifier)->IsString()) { michael@0: return static_cast(aIdentifier)->ToString(); michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: int32_t michael@0: PluginModuleChild::NPN_IntFromIdentifier(NPIdentifier aIdentifier) michael@0: { michael@0: PLUGIN_LOG_DEBUG_FUNCTION; michael@0: michael@0: if (!static_cast(aIdentifier)->IsString()) { michael@0: return static_cast(aIdentifier)->ToInt(); michael@0: } michael@0: return INT32_MIN; michael@0: } michael@0: michael@0: #ifdef OS_WIN michael@0: void michael@0: PluginModuleChild::EnteredCall() michael@0: { michael@0: mIncallPumpingStack.AppendElement(); michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::ExitedCall() michael@0: { michael@0: NS_ASSERTION(mIncallPumpingStack.Length(), "mismatched entered/exited"); michael@0: uint32_t len = mIncallPumpingStack.Length(); michael@0: const IncallFrame& f = mIncallPumpingStack[len - 1]; michael@0: if (f._spinning) michael@0: MessageLoop::current()->SetNestableTasksAllowed(f._savedNestableTasksAllowed); michael@0: michael@0: mIncallPumpingStack.TruncateLength(len - 1); michael@0: } michael@0: michael@0: LRESULT CALLBACK michael@0: PluginModuleChild::CallWindowProcHook(int nCode, WPARAM wParam, LPARAM lParam) michael@0: { michael@0: // Trap and reply to anything we recognize as the source of a michael@0: // potential send message deadlock. michael@0: if (nCode >= 0 && michael@0: (InSendMessageEx(nullptr)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) { michael@0: CWPSTRUCT* pCwp = reinterpret_cast(lParam); michael@0: if (pCwp->message == WM_KILLFOCUS) { michael@0: // Fix for flash fullscreen window loosing focus. On single michael@0: // core systems, sync killfocus events need to be handled michael@0: // after the flash fullscreen window procedure processes this michael@0: // message, otherwise fullscreen focus will not work correctly. michael@0: wchar_t szClass[26]; michael@0: if (GetClassNameW(pCwp->hwnd, szClass, michael@0: sizeof(szClass)/sizeof(char16_t)) && michael@0: !wcscmp(szClass, kFlashFullscreenClass)) { michael@0: gDelayFlashFocusReplyUntilEval = true; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return CallNextHookEx(nullptr, nCode, wParam, lParam); michael@0: } michael@0: michael@0: LRESULT CALLBACK michael@0: PluginModuleChild::NestedInputEventHook(int nCode, WPARAM wParam, LPARAM lParam) michael@0: { michael@0: PluginModuleChild* self = current(); michael@0: uint32_t len = self->mIncallPumpingStack.Length(); michael@0: if (nCode >= 0 && len && !self->mIncallPumpingStack[len - 1]._spinning) { michael@0: MessageLoop* loop = MessageLoop::current(); michael@0: self->SendProcessNativeEventsInInterruptCall(); michael@0: IncallFrame& f = self->mIncallPumpingStack[len - 1]; michael@0: f._spinning = true; michael@0: f._savedNestableTasksAllowed = loop->NestableTasksAllowed(); michael@0: loop->SetNestableTasksAllowed(true); michael@0: loop->set_os_modal_loop(true); michael@0: } michael@0: michael@0: return CallNextHookEx(nullptr, nCode, wParam, lParam); michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::SetEventHooks() michael@0: { michael@0: NS_ASSERTION(!mNestedEventHook, michael@0: "mNestedEventHook already setup in call to SetNestedInputEventHook?"); michael@0: NS_ASSERTION(!mGlobalCallWndProcHook, michael@0: "mGlobalCallWndProcHook already setup in call to CallWindowProcHook?"); michael@0: michael@0: PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION)); michael@0: michael@0: // WH_MSGFILTER event hook for detecting modal loops in the child. michael@0: mNestedEventHook = SetWindowsHookEx(WH_MSGFILTER, michael@0: NestedInputEventHook, michael@0: nullptr, michael@0: GetCurrentThreadId()); michael@0: michael@0: // WH_CALLWNDPROC event hook for trapping sync messages sent from michael@0: // parent that can cause deadlocks. michael@0: mGlobalCallWndProcHook = SetWindowsHookEx(WH_CALLWNDPROC, michael@0: CallWindowProcHook, michael@0: nullptr, michael@0: GetCurrentThreadId()); michael@0: } michael@0: michael@0: void michael@0: PluginModuleChild::ResetEventHooks() michael@0: { michael@0: PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION)); michael@0: if (mNestedEventHook) michael@0: UnhookWindowsHookEx(mNestedEventHook); michael@0: mNestedEventHook = nullptr; michael@0: if (mGlobalCallWndProcHook) michael@0: UnhookWindowsHookEx(mGlobalCallWndProcHook); michael@0: mGlobalCallWndProcHook = nullptr; michael@0: } michael@0: #endif michael@0: michael@0: bool michael@0: PluginModuleChild::RecvProcessNativeEventsInInterruptCall() michael@0: { michael@0: PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION)); michael@0: #if defined(OS_WIN) michael@0: ProcessNativeEventsInInterruptCall(); michael@0: return true; michael@0: #else michael@0: NS_RUNTIMEABORT( michael@0: "PluginModuleChild::RecvProcessNativeEventsInInterruptCall not implemented!"); michael@0: return false; michael@0: #endif michael@0: } michael@0: michael@0: #ifdef MOZ_WIDGET_COCOA michael@0: void michael@0: PluginModuleChild::ProcessNativeEvents() { michael@0: CallProcessSomeEvents(); michael@0: } michael@0: #endif michael@0: michael@0: bool michael@0: PluginModuleChild::AnswerGeckoGetProfile(nsCString* aProfile) { michael@0: char* profile = profiler_get_profile(); michael@0: if (profile != nullptr) { michael@0: *aProfile = nsCString(profile, strlen(profile)); michael@0: free(profile); michael@0: } else { michael@0: *aProfile = nsCString("", 0); michael@0: } michael@0: return true; michael@0: } michael@0: