forked from mirrors/gecko-dev
Replace the boolean pref "security.sandbox.mac.flash.enabled" with "dom.ipc.plugins.sandbox-level.flash" to support sandbox levels and be consistent with the Windows pref name. Adds filesystem read access to the sandbox using sandbox extensions granted by the file dialog machinery (level 1). Add support for level 2 which blocks read access. Allow the sandbox to be disabled with MOZ_DISABLE_NPAPI_SANDBOX. MozReview-Commit-ID: 4rfobEoxQpF --HG-- extra : rebase_source : 05dc54b46063967e959bc3fced21c61e5463de48
2239 lines
61 KiB
C++
2239 lines
61 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* vim: set sw=4 ts=4 et : */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/plugins/PluginModuleChild.h"
|
|
|
|
/* This must occur *after* plugins/PluginModuleChild.h to avoid typedefs conflicts. */
|
|
#include "mozilla/ArrayUtils.h"
|
|
|
|
#include "mozilla/ipc/MessageChannel.h"
|
|
|
|
#ifdef MOZ_WIDGET_GTK
|
|
#include <gtk/gtk.h>
|
|
#endif
|
|
|
|
#include "nsIFile.h"
|
|
|
|
#include "pratom.h"
|
|
#include "nsDebug.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsPluginsDir.h"
|
|
#include "nsXULAppAPI.h"
|
|
|
|
#ifdef MOZ_X11
|
|
# include "nsX11ErrorHandler.h"
|
|
# include "mozilla/X11Util.h"
|
|
#endif
|
|
|
|
#include "mozilla/ipc/CrashReporterClient.h"
|
|
#include "mozilla/ipc/ProcessChild.h"
|
|
#include "mozilla/plugins/PluginInstanceChild.h"
|
|
#include "mozilla/plugins/StreamNotifyChild.h"
|
|
#include "mozilla/plugins/BrowserStreamChild.h"
|
|
#include "mozilla/Sprintf.h"
|
|
#include "mozilla/Unused.h"
|
|
|
|
#include "nsNPAPIPlugin.h"
|
|
#include "FunctionHook.h"
|
|
#include "FunctionBrokerChild.h"
|
|
|
|
#ifdef XP_WIN
|
|
#include "mozilla/widget/AudioSession.h"
|
|
#include <knownfolders.h>
|
|
#endif
|
|
|
|
#ifdef MOZ_WIDGET_COCOA
|
|
#include "PluginInterposeOSX.h"
|
|
#include "PluginUtilsOSX.h"
|
|
#endif
|
|
|
|
#ifdef MOZ_GECKO_PROFILER
|
|
#include "ChildProfilerController.h"
|
|
#endif
|
|
|
|
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
|
#include "mozilla/Sandbox.h"
|
|
#endif
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::ipc;
|
|
using namespace mozilla::plugins;
|
|
using namespace mozilla::widget;
|
|
|
|
#if defined(XP_WIN)
|
|
const wchar_t * kFlashFullscreenClass = L"ShockwaveFlashFullScreen";
|
|
#endif
|
|
|
|
namespace {
|
|
// see PluginModuleChild::GetChrome()
|
|
PluginModuleChild* gChromeInstance = nullptr;
|
|
} // namespace
|
|
|
|
#ifdef XP_WIN
|
|
// Used with fix for flash fullscreen window loosing focus.
|
|
static bool gDelayFlashFocusReplyUntilEval = false;
|
|
#endif
|
|
|
|
/* static */
|
|
bool
|
|
PluginModuleChild::CreateForContentProcess(Endpoint<PPluginModuleChild>&& aEndpoint)
|
|
{
|
|
auto* child = new PluginModuleChild(false);
|
|
return child->InitForContent(Move(aEndpoint));
|
|
}
|
|
|
|
PluginModuleChild::PluginModuleChild(bool aIsChrome)
|
|
: mLibrary(0)
|
|
, mPluginFilename("")
|
|
, mQuirks(QUIRKS_NOT_INITIALIZED)
|
|
, mIsChrome(aIsChrome)
|
|
, mHasShutdown(false)
|
|
, mShutdownFunc(0)
|
|
, mInitializeFunc(0)
|
|
#if defined(OS_WIN) || defined(OS_MACOSX)
|
|
, mGetEntryPointsFunc(0)
|
|
#elif defined(MOZ_WIDGET_GTK)
|
|
, mNestedLoopTimerId(0)
|
|
#endif
|
|
#ifdef OS_WIN
|
|
, mNestedEventHook(nullptr)
|
|
, mGlobalCallWndProcHook(nullptr)
|
|
, mAsyncRenderSupport(false)
|
|
#endif
|
|
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
|
, mFlashSandboxLevel(0)
|
|
, mEnableFlashSandboxLogging(false)
|
|
#endif
|
|
{
|
|
memset(&mFunctions, 0, sizeof(mFunctions));
|
|
if (mIsChrome) {
|
|
MOZ_ASSERT(!gChromeInstance);
|
|
gChromeInstance = this;
|
|
}
|
|
|
|
#ifdef XP_MACOSX
|
|
if (aIsChrome) {
|
|
mac_plugin_interposing::child::SetUpCocoaInterposing();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
PluginModuleChild::~PluginModuleChild()
|
|
{
|
|
if (mIsChrome) {
|
|
MOZ_ASSERT(gChromeInstance == this);
|
|
|
|
// We don't unload the plugin library in case it uses atexit handlers or
|
|
// other similar hooks.
|
|
|
|
DeinitGraphics();
|
|
PluginScriptableObjectChild::ClearIdentifiers();
|
|
|
|
gChromeInstance = nullptr;
|
|
}
|
|
}
|
|
|
|
// static
|
|
PluginModuleChild*
|
|
PluginModuleChild::GetChrome()
|
|
{
|
|
// A special PluginModuleChild instance that talks to the chrome process
|
|
// during startup and shutdown. Synchronous messages to or from this actor
|
|
// should be avoided because they may lead to hangs.
|
|
MOZ_ASSERT(gChromeInstance);
|
|
return gChromeInstance;
|
|
}
|
|
|
|
void
|
|
PluginModuleChild::CommonInit()
|
|
{
|
|
PLUGIN_LOG_DEBUG_METHOD;
|
|
|
|
// Request Windows message deferral behavior on our channel. This
|
|
// applies to the top level and all sub plugin protocols since they
|
|
// all share the same channel.
|
|
// Bug 1090573 - Don't do this for connections to content processes.
|
|
GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
|
|
|
|
memset((void*) &mFunctions, 0, sizeof(mFunctions));
|
|
mFunctions.size = sizeof(mFunctions);
|
|
mFunctions.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
|
|
}
|
|
|
|
bool
|
|
PluginModuleChild::InitForContent(Endpoint<PPluginModuleChild>&& aEndpoint)
|
|
{
|
|
CommonInit();
|
|
|
|
if (!aEndpoint.Bind(this)) {
|
|
return false;
|
|
}
|
|
|
|
mLibrary = GetChrome()->mLibrary;
|
|
mFunctions = GetChrome()->mFunctions;
|
|
|
|
return true;
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::RecvInitProfiler(Endpoint<mozilla::PProfilerChild>&& aEndpoint)
|
|
{
|
|
#ifdef MOZ_GECKO_PROFILER
|
|
mProfilerController = ChildProfilerController::Create(Move(aEndpoint));
|
|
#endif
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::RecvDisableFlashProtectedMode()
|
|
{
|
|
MOZ_ASSERT(mIsChrome);
|
|
#ifdef XP_WIN
|
|
FunctionHook::HookProtectedMode();
|
|
#else
|
|
MOZ_ASSERT(false, "Should not be called");
|
|
#endif
|
|
return IPC_OK();
|
|
}
|
|
|
|
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
|
void
|
|
PluginModuleChild::EnableFlashSandbox(int aLevel, bool aShouldEnableLogging)
|
|
{
|
|
mFlashSandboxLevel = aLevel;
|
|
mEnableFlashSandboxLogging = aShouldEnableLogging;
|
|
}
|
|
#endif
|
|
|
|
bool
|
|
PluginModuleChild::InitForChrome(const std::string& aPluginFilename,
|
|
base::ProcessId aParentPid,
|
|
MessageLoop* aIOLoop,
|
|
IPC::Channel* aChannel)
|
|
{
|
|
NS_ASSERTION(aChannel, "need a channel");
|
|
|
|
if (!InitGraphics())
|
|
return false;
|
|
|
|
mPluginFilename = aPluginFilename.c_str();
|
|
nsCOMPtr<nsIFile> localFile;
|
|
NS_NewLocalFile(NS_ConvertUTF8toUTF16(mPluginFilename),
|
|
true,
|
|
getter_AddRefs(localFile));
|
|
|
|
if (!localFile)
|
|
return false;
|
|
|
|
bool exists;
|
|
localFile->Exists(&exists);
|
|
NS_ASSERTION(exists, "plugin file ain't there");
|
|
|
|
nsPluginFile pluginFile(localFile);
|
|
|
|
nsPluginInfo info = nsPluginInfo();
|
|
if (NS_FAILED(pluginFile.GetPluginInfo(info, &mLibrary))) {
|
|
return false;
|
|
}
|
|
|
|
#if defined(XP_WIN)
|
|
// XXX quirks isn't initialized yet
|
|
mAsyncRenderSupport = info.fSupportsAsyncRender;
|
|
#endif
|
|
#if defined(MOZ_X11)
|
|
NS_NAMED_LITERAL_CSTRING(flash10Head, "Shockwave Flash 10.");
|
|
if (StringBeginsWith(nsDependentCString(info.fDescription), flash10Head)) {
|
|
AddQuirk(QUIRK_FLASH_EXPOSE_COORD_TRANSLATION);
|
|
}
|
|
#endif
|
|
#if defined(XP_MACOSX)
|
|
const char* namePrefix = "Plugin Content";
|
|
char nameBuffer[80];
|
|
SprintfLiteral(nameBuffer, "%s (%s)", namePrefix, info.fName);
|
|
mozilla::plugins::PluginUtilsOSX::SetProcessName(nameBuffer);
|
|
#endif
|
|
pluginFile.FreePluginInfo(info);
|
|
#if defined(MOZ_X11) || defined(XP_MACOSX)
|
|
if (!mLibrary)
|
|
#endif
|
|
{
|
|
nsresult rv = pluginFile.LoadPlugin(&mLibrary);
|
|
if (NS_FAILED(rv))
|
|
return false;
|
|
}
|
|
NS_ASSERTION(mLibrary, "couldn't open shared object");
|
|
|
|
CommonInit();
|
|
|
|
if (!Open(aChannel, aParentPid, aIOLoop)) {
|
|
return false;
|
|
}
|
|
|
|
GetIPCChannel()->SetAbortOnError(true);
|
|
|
|
#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
|
|
mShutdownFunc =
|
|
(NP_PLUGINSHUTDOWN) PR_FindFunctionSymbol(mLibrary, "NP_Shutdown");
|
|
|
|
// create the new plugin handler
|
|
|
|
mInitializeFunc =
|
|
(NP_PLUGINUNIXINIT) PR_FindFunctionSymbol(mLibrary, "NP_Initialize");
|
|
NS_ASSERTION(mInitializeFunc, "couldn't find NP_Initialize()");
|
|
|
|
#elif defined(OS_WIN) || defined(OS_MACOSX)
|
|
mShutdownFunc =
|
|
(NP_PLUGINSHUTDOWN)PR_FindFunctionSymbol(mLibrary, "NP_Shutdown");
|
|
|
|
mGetEntryPointsFunc =
|
|
(NP_GETENTRYPOINTS)PR_FindSymbol(mLibrary, "NP_GetEntryPoints");
|
|
NS_ENSURE_TRUE(mGetEntryPointsFunc, false);
|
|
|
|
mInitializeFunc =
|
|
(NP_PLUGININIT)PR_FindFunctionSymbol(mLibrary, "NP_Initialize");
|
|
NS_ENSURE_TRUE(mInitializeFunc, false);
|
|
#else
|
|
|
|
# error Please copy the initialization code from nsNPAPIPlugin.cpp
|
|
|
|
#endif
|
|
|
|
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
|
if (mFlashSandboxLevel > 0) {
|
|
MacSandboxInfo flashSandboxInfo;
|
|
flashSandboxInfo.type = MacSandboxType_Plugin;
|
|
flashSandboxInfo.pluginInfo.type = MacSandboxPluginType_Flash;
|
|
flashSandboxInfo.pluginInfo.pluginBinaryPath = aPluginFilename;
|
|
flashSandboxInfo.level = mFlashSandboxLevel;
|
|
flashSandboxInfo.shouldLog = mEnableFlashSandboxLogging;
|
|
|
|
std::string sbError;
|
|
if (!mozilla::StartMacSandbox(flashSandboxInfo, sbError)) {
|
|
fprintf(stderr, "Failed to start sandbox:\n%s\n", sbError.c_str());
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
#if defined(MOZ_WIDGET_GTK)
|
|
|
|
typedef void (*GObjectDisposeFn)(GObject*);
|
|
typedef gboolean (*GtkWidgetScrollEventFn)(GtkWidget*, GdkEventScroll*);
|
|
typedef void (*GtkPlugEmbeddedFn)(GtkPlug*);
|
|
|
|
static GObjectDisposeFn real_gtk_plug_dispose;
|
|
static GtkPlugEmbeddedFn real_gtk_plug_embedded;
|
|
|
|
static void
|
|
undo_bogus_unref(gpointer data, GObject* object, gboolean is_last_ref) {
|
|
if (!is_last_ref) // recursion in g_object_ref
|
|
return;
|
|
|
|
g_object_ref(object);
|
|
}
|
|
|
|
static void
|
|
wrap_gtk_plug_dispose(GObject* object) {
|
|
// Work around Flash Player bug described in bug 538914.
|
|
//
|
|
// This function is called during gtk_widget_destroy and/or before
|
|
// the object's last reference is removed. A reference to the
|
|
// object is held during the call so the ref count should not drop
|
|
// to zero. However, Flash Player tries to destroy the GtkPlug
|
|
// using g_object_unref instead of gtk_widget_destroy. The
|
|
// reference that Flash is removing actually belongs to the
|
|
// GtkPlug. During real_gtk_plug_dispose, the GtkPlug removes its
|
|
// reference.
|
|
//
|
|
// A toggle ref is added to prevent premature deletion of the object
|
|
// caused by Flash Player's extra unref, and to detect when there are
|
|
// unexpectedly no other references.
|
|
g_object_add_toggle_ref(object, undo_bogus_unref, nullptr);
|
|
(*real_gtk_plug_dispose)(object);
|
|
g_object_remove_toggle_ref(object, undo_bogus_unref, nullptr);
|
|
}
|
|
|
|
static gboolean
|
|
gtk_plug_scroll_event(GtkWidget *widget, GdkEventScroll *gdk_event)
|
|
{
|
|
if (!gtk_widget_is_toplevel(widget)) // in same process as its GtkSocket
|
|
return FALSE; // event not handled; propagate to GtkSocket
|
|
|
|
GdkWindow* socket_window = gtk_plug_get_socket_window(GTK_PLUG(widget));
|
|
if (!socket_window)
|
|
return FALSE;
|
|
|
|
// Propagate the event to the embedder.
|
|
GdkScreen* screen = gdk_window_get_screen(socket_window);
|
|
GdkWindow* plug_window = gtk_widget_get_window(widget);
|
|
GdkWindow* event_window = gdk_event->window;
|
|
gint x = gdk_event->x;
|
|
gint y = gdk_event->y;
|
|
unsigned int button;
|
|
unsigned int button_mask = 0;
|
|
XEvent xevent;
|
|
Display* dpy = GDK_WINDOW_XDISPLAY(socket_window);
|
|
|
|
/* Translate the event coordinates to the plug window,
|
|
* which should be aligned with the socket window.
|
|
*/
|
|
while (event_window != plug_window)
|
|
{
|
|
gint dx, dy;
|
|
|
|
gdk_window_get_position(event_window, &dx, &dy);
|
|
x += dx;
|
|
y += dy;
|
|
|
|
event_window = gdk_window_get_parent(event_window);
|
|
if (!event_window)
|
|
return FALSE;
|
|
}
|
|
|
|
switch (gdk_event->direction) {
|
|
case GDK_SCROLL_UP:
|
|
button = 4;
|
|
button_mask = Button4Mask;
|
|
break;
|
|
case GDK_SCROLL_DOWN:
|
|
button = 5;
|
|
button_mask = Button5Mask;
|
|
break;
|
|
case GDK_SCROLL_LEFT:
|
|
button = 6;
|
|
break;
|
|
case GDK_SCROLL_RIGHT:
|
|
button = 7;
|
|
break;
|
|
default:
|
|
return FALSE; // unknown GdkScrollDirection
|
|
}
|
|
|
|
memset(&xevent, 0, sizeof(xevent));
|
|
xevent.xbutton.type = ButtonPress;
|
|
xevent.xbutton.window = gdk_x11_window_get_xid(socket_window);
|
|
xevent.xbutton.root = gdk_x11_window_get_xid(gdk_screen_get_root_window(screen));
|
|
xevent.xbutton.subwindow = gdk_x11_window_get_xid(plug_window);
|
|
xevent.xbutton.time = gdk_event->time;
|
|
xevent.xbutton.x = x;
|
|
xevent.xbutton.y = y;
|
|
xevent.xbutton.x_root = gdk_event->x_root;
|
|
xevent.xbutton.y_root = gdk_event->y_root;
|
|
xevent.xbutton.state = gdk_event->state;
|
|
xevent.xbutton.button = button;
|
|
xevent.xbutton.same_screen = True;
|
|
|
|
gdk_error_trap_push();
|
|
|
|
XSendEvent(dpy, xevent.xbutton.window,
|
|
True, ButtonPressMask, &xevent);
|
|
|
|
xevent.xbutton.type = ButtonRelease;
|
|
xevent.xbutton.state |= button_mask;
|
|
XSendEvent(dpy, xevent.xbutton.window,
|
|
True, ButtonReleaseMask, &xevent);
|
|
|
|
gdk_display_sync(gdk_screen_get_display(screen));
|
|
gdk_error_trap_pop();
|
|
|
|
return TRUE; // event handled
|
|
}
|
|
|
|
static void
|
|
wrap_gtk_plug_embedded(GtkPlug* plug) {
|
|
GdkWindow* socket_window = gtk_plug_get_socket_window(plug);
|
|
if (socket_window) {
|
|
if (gtk_check_version(2,18,7) != nullptr // older
|
|
&& g_object_get_data(G_OBJECT(socket_window),
|
|
"moz-existed-before-set-window")) {
|
|
// Add missing reference for
|
|
// https://bugzilla.gnome.org/show_bug.cgi?id=607061
|
|
g_object_ref(socket_window);
|
|
}
|
|
|
|
// Ensure the window exists to make this GtkPlug behave like an
|
|
// in-process GtkPlug for Flash Player. (Bugs 561308 and 539138).
|
|
gtk_widget_realize(GTK_WIDGET(plug));
|
|
}
|
|
|
|
if (*real_gtk_plug_embedded) {
|
|
(*real_gtk_plug_embedded)(plug);
|
|
}
|
|
}
|
|
|
|
//
|
|
// The next four constants are knobs that can be tuned. They trade
|
|
// off potential UI lag from delayed event processing with CPU time.
|
|
//
|
|
static const gint kNestedLoopDetectorPriority = G_PRIORITY_HIGH_IDLE;
|
|
// 90ms so that we can hopefully break livelocks before the user
|
|
// notices UI lag (100ms)
|
|
static const guint kNestedLoopDetectorIntervalMs = 90;
|
|
|
|
static const gint kBrowserEventPriority = G_PRIORITY_HIGH_IDLE;
|
|
static const guint kBrowserEventIntervalMs = 10;
|
|
|
|
// static
|
|
gboolean
|
|
PluginModuleChild::DetectNestedEventLoop(gpointer data)
|
|
{
|
|
PluginModuleChild* pmc = static_cast<PluginModuleChild*>(data);
|
|
|
|
MOZ_ASSERT(0 != pmc->mNestedLoopTimerId,
|
|
"callback after descheduling");
|
|
MOZ_ASSERT(pmc->mTopLoopDepth < g_main_depth(),
|
|
"not canceled before returning to main event loop!");
|
|
|
|
PLUGIN_LOG_DEBUG(("Detected nested glib event loop"));
|
|
|
|
// just detected a nested loop; start a timer that will
|
|
// periodically rpc-call back into the browser and process some
|
|
// events
|
|
pmc->mNestedLoopTimerId =
|
|
g_timeout_add_full(kBrowserEventPriority,
|
|
kBrowserEventIntervalMs,
|
|
PluginModuleChild::ProcessBrowserEvents,
|
|
data,
|
|
nullptr);
|
|
// cancel the nested-loop detection timer
|
|
return FALSE;
|
|
}
|
|
|
|
// static
|
|
gboolean
|
|
PluginModuleChild::ProcessBrowserEvents(gpointer data)
|
|
{
|
|
PluginModuleChild* pmc = static_cast<PluginModuleChild*>(data);
|
|
|
|
MOZ_ASSERT(pmc->mTopLoopDepth < g_main_depth(),
|
|
"not canceled before returning to main event loop!");
|
|
|
|
pmc->CallProcessSomeEvents();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
PluginModuleChild::EnteredCxxStack()
|
|
{
|
|
MOZ_ASSERT(0 == mNestedLoopTimerId,
|
|
"previous timer not descheduled");
|
|
|
|
mNestedLoopTimerId =
|
|
g_timeout_add_full(kNestedLoopDetectorPriority,
|
|
kNestedLoopDetectorIntervalMs,
|
|
PluginModuleChild::DetectNestedEventLoop,
|
|
this,
|
|
nullptr);
|
|
|
|
#ifdef DEBUG
|
|
mTopLoopDepth = g_main_depth();
|
|
#endif
|
|
}
|
|
|
|
void
|
|
PluginModuleChild::ExitedCxxStack()
|
|
{
|
|
MOZ_ASSERT(0 < mNestedLoopTimerId,
|
|
"nested loop timeout not scheduled");
|
|
|
|
g_source_remove(mNestedLoopTimerId);
|
|
mNestedLoopTimerId = 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::RecvSetParentHangTimeout(const uint32_t& aSeconds)
|
|
{
|
|
#ifdef XP_WIN
|
|
SetReplyTimeoutMs(((aSeconds > 0) ? (1000 * aSeconds) : 0));
|
|
#endif
|
|
return IPC_OK();
|
|
}
|
|
|
|
bool
|
|
PluginModuleChild::ShouldContinueFromReplyTimeout()
|
|
{
|
|
#ifdef XP_WIN
|
|
MOZ_CRASH("terminating child process");
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
PluginModuleChild::InitGraphics()
|
|
{
|
|
#if defined(MOZ_WIDGET_GTK)
|
|
// Work around plugins that don't interact well with GDK
|
|
// client-side windows.
|
|
PR_SetEnv("GDK_NATIVE_WINDOWS=1");
|
|
|
|
gtk_init(0, 0);
|
|
|
|
// GtkPlug is a static class so will leak anyway but this ref makes sure.
|
|
gpointer gtk_plug_class = g_type_class_ref(GTK_TYPE_PLUG);
|
|
|
|
// The dispose method is a good place to hook into the destruction process
|
|
// because the reference count should be 1 the last time dispose is
|
|
// called. (Toggle references wouldn't detect if the reference count
|
|
// might be higher.)
|
|
GObjectDisposeFn* dispose = &G_OBJECT_CLASS(gtk_plug_class)->dispose;
|
|
MOZ_ASSERT(*dispose != wrap_gtk_plug_dispose,
|
|
"InitGraphics called twice");
|
|
real_gtk_plug_dispose = *dispose;
|
|
*dispose = wrap_gtk_plug_dispose;
|
|
|
|
// If we ever stop setting GDK_NATIVE_WINDOWS, we'll also need to
|
|
// gtk_widget_add_events GDK_SCROLL_MASK or GDK client-side windows will
|
|
// not tell us about the scroll events that it intercepts. With native
|
|
// windows, this is called when GDK intercepts the events; if GDK doesn't
|
|
// intercept the events, then the X server will instead send them directly
|
|
// to an ancestor (embedder) window.
|
|
GtkWidgetScrollEventFn* scroll_event =
|
|
>K_WIDGET_CLASS(gtk_plug_class)->scroll_event;
|
|
if (!*scroll_event) {
|
|
*scroll_event = gtk_plug_scroll_event;
|
|
}
|
|
|
|
GtkPlugEmbeddedFn* embedded = >K_PLUG_CLASS(gtk_plug_class)->embedded;
|
|
real_gtk_plug_embedded = *embedded;
|
|
*embedded = wrap_gtk_plug_embedded;
|
|
|
|
#else
|
|
// may not be necessary on all platforms
|
|
#endif
|
|
#ifdef MOZ_X11
|
|
// Do this after initializing GDK, or GDK will install its own handler.
|
|
InstallX11ErrorHandler();
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
void
|
|
PluginModuleChild::DeinitGraphics()
|
|
{
|
|
#if defined(MOZ_X11) && defined(NS_FREE_PERMANENT_DATA)
|
|
// We free some data off of XDisplay close hooks, ensure they're
|
|
// run. Closing the display is pretty scary, so we only do it to
|
|
// silence leak checkers.
|
|
XCloseDisplay(DefaultXDisplay());
|
|
#endif
|
|
}
|
|
|
|
NPError
|
|
PluginModuleChild::NP_Shutdown()
|
|
{
|
|
AssertPluginThread();
|
|
MOZ_ASSERT(mIsChrome);
|
|
|
|
if (mHasShutdown) {
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
#if defined XP_WIN
|
|
mozilla::widget::StopAudioSession();
|
|
#endif
|
|
|
|
// the PluginModuleParent shuts down this process after this interrupt
|
|
// call pops off its stack
|
|
|
|
NPError rv = mShutdownFunc ? mShutdownFunc() : NPERR_NO_ERROR;
|
|
|
|
// weakly guard against re-entry after NP_Shutdown
|
|
memset(&mFunctions, 0, sizeof(mFunctions));
|
|
|
|
#ifdef OS_WIN
|
|
ResetEventHooks();
|
|
#endif
|
|
|
|
GetIPCChannel()->SetAbortOnError(false);
|
|
|
|
mHasShutdown = true;
|
|
|
|
return rv;
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::AnswerNP_Shutdown(NPError *rv)
|
|
{
|
|
*rv = NP_Shutdown();
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::AnswerOptionalFunctionsSupported(bool *aURLRedirectNotify,
|
|
bool *aClearSiteData,
|
|
bool *aGetSitesWithData)
|
|
{
|
|
*aURLRedirectNotify = !!mFunctions.urlredirectnotify;
|
|
*aClearSiteData = !!mFunctions.clearsitedata;
|
|
*aGetSitesWithData = !!mFunctions.getsiteswithdata;
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::RecvNPP_ClearSiteData(const nsCString& aSite,
|
|
const uint64_t& aFlags,
|
|
const uint64_t& aMaxAge,
|
|
const uint64_t& aCallbackId)
|
|
{
|
|
NPError result =
|
|
mFunctions.clearsitedata(NullableStringGet(aSite), aFlags, aMaxAge);
|
|
SendReturnClearSiteData(result, aCallbackId);
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::RecvNPP_GetSitesWithData(const uint64_t& aCallbackId)
|
|
{
|
|
char** result = mFunctions.getsiteswithdata();
|
|
InfallibleTArray<nsCString> array;
|
|
if (!result) {
|
|
SendReturnSitesWithData(array, aCallbackId);
|
|
return IPC_OK();
|
|
}
|
|
char** iterator = result;
|
|
while (*iterator) {
|
|
array.AppendElement(*iterator);
|
|
free(*iterator);
|
|
++iterator;
|
|
}
|
|
SendReturnSitesWithData(array, aCallbackId);
|
|
free(result);
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::RecvSetAudioSessionData(const nsID& aId,
|
|
const nsString& aDisplayName,
|
|
const nsString& aIconPath)
|
|
{
|
|
#if !defined XP_WIN
|
|
MOZ_CRASH("Not Reached!");
|
|
#else
|
|
nsresult rv = mozilla::widget::RecvAudioSessionData(aId, aDisplayName, aIconPath);
|
|
NS_ENSURE_SUCCESS(rv, IPC_OK()); // Bail early if this fails
|
|
|
|
// Ignore failures here; we can't really do anything about them
|
|
mozilla::widget::StartAudioSession();
|
|
return IPC_OK();
|
|
#endif
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::RecvInitPluginModuleChild(Endpoint<PPluginModuleChild>&& aEndpoint)
|
|
{
|
|
if (!CreateForContentProcess(Move(aEndpoint))) {
|
|
return IPC_FAIL(this, "CreateForContentProcess failed");
|
|
}
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::RecvInitPluginFunctionBroker(Endpoint<PFunctionBrokerChild>&& aEndpoint)
|
|
{
|
|
#if defined(XP_WIN)
|
|
MOZ_ASSERT(mIsChrome);
|
|
if (!FunctionBrokerChild::Initialize(Move(aEndpoint))) {
|
|
return IPC_FAIL(this,
|
|
"InitPluginFunctionBroker failed to initialize broker child.");
|
|
}
|
|
return IPC_OK();
|
|
#else
|
|
return IPC_FAIL(this, "InitPluginFunctionBroker not supported on this platform.");
|
|
#endif
|
|
}
|
|
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::AnswerInitCrashReporter(Shmem&& aShmem, mozilla::dom::NativeThreadId* aOutId)
|
|
{
|
|
CrashReporterClient::InitSingletonWithShmem(aShmem);
|
|
*aOutId = CrashReporter::CurrentThreadId();
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
void
|
|
PluginModuleChild::ActorDestroy(ActorDestroyReason why)
|
|
{
|
|
#ifdef MOZ_GECKO_PROFILER
|
|
if (mProfilerController) {
|
|
mProfilerController->Shutdown();
|
|
mProfilerController = nullptr;
|
|
}
|
|
#endif
|
|
|
|
if (!mIsChrome) {
|
|
PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
|
|
if (chromeInstance) {
|
|
chromeInstance->SendNotifyContentModuleDestroyed();
|
|
}
|
|
|
|
// Destroy ourselves once we finish other teardown activities.
|
|
RefPtr<DeleteTask<PluginModuleChild>> task =
|
|
new DeleteTask<PluginModuleChild>(this);
|
|
MessageLoop::current()->PostTask(task.forget());
|
|
return;
|
|
}
|
|
|
|
if (AbnormalShutdown == why) {
|
|
NS_WARNING("shutting down early because of crash!");
|
|
ProcessChild::QuickExit();
|
|
}
|
|
|
|
if (!mHasShutdown) {
|
|
MOZ_ASSERT(gChromeInstance == this);
|
|
NP_Shutdown();
|
|
}
|
|
|
|
#if defined(XP_WIN)
|
|
FunctionBrokerChild::Destroy();
|
|
FunctionHook::ClearDllInterceptorCache();
|
|
#endif
|
|
|
|
// doesn't matter why we're being destroyed; it's up to us to
|
|
// initiate (clean) shutdown
|
|
CrashReporterClient::DestroySingleton();
|
|
|
|
XRE_ShutdownChildProcess();
|
|
}
|
|
|
|
void
|
|
PluginModuleChild::CleanUp()
|
|
{
|
|
}
|
|
|
|
const char*
|
|
PluginModuleChild::GetUserAgent()
|
|
{
|
|
return NullableStringGet(Settings().userAgent());
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// FIXME/cjones: just getting this out of the way for the moment ...
|
|
|
|
namespace mozilla {
|
|
namespace plugins {
|
|
namespace child {
|
|
|
|
static NPError
|
|
_requestread(NPStream *pstream, NPByteRange *rangeList);
|
|
|
|
static NPError
|
|
_geturlnotify(NPP aNPP, const char* relativeURL, const char* target,
|
|
void* notifyData);
|
|
|
|
static NPError
|
|
_getvalue(NPP aNPP, NPNVariable variable, void *r_value);
|
|
|
|
static NPError
|
|
_setvalue(NPP aNPP, NPPVariable variable, void *r_value);
|
|
|
|
static NPError
|
|
_geturl(NPP aNPP, const char* relativeURL, const char* target);
|
|
|
|
static NPError
|
|
_posturlnotify(NPP aNPP, const char* relativeURL, const char *target,
|
|
uint32_t len, const char *buf, NPBool file, void* notifyData);
|
|
|
|
static NPError
|
|
_posturl(NPP aNPP, const char* relativeURL, const char *target, uint32_t len,
|
|
const char *buf, NPBool file);
|
|
|
|
static void
|
|
_status(NPP aNPP, const char *message);
|
|
|
|
static void
|
|
_memfree (void *ptr);
|
|
|
|
static uint32_t
|
|
_memflush(uint32_t size);
|
|
|
|
static void
|
|
_reloadplugins(NPBool reloadPages);
|
|
|
|
static void
|
|
_invalidaterect(NPP aNPP, NPRect *invalidRect);
|
|
|
|
static void
|
|
_invalidateregion(NPP aNPP, NPRegion invalidRegion);
|
|
|
|
static void
|
|
_forceredraw(NPP aNPP);
|
|
|
|
static const char*
|
|
_useragent(NPP aNPP);
|
|
|
|
static void*
|
|
_memalloc (uint32_t size);
|
|
|
|
// Deprecated entry points for the old Java plugin.
|
|
static void* /* OJI type: JRIEnv* */
|
|
_getjavaenv(void);
|
|
|
|
// Deprecated entry points for the old Java plugin.
|
|
static void* /* OJI type: jref */
|
|
_getjavapeer(NPP aNPP);
|
|
|
|
static bool
|
|
_invoke(NPP aNPP, NPObject* npobj, NPIdentifier method, const NPVariant *args,
|
|
uint32_t argCount, NPVariant *result);
|
|
|
|
static bool
|
|
_invokedefault(NPP aNPP, NPObject* npobj, const NPVariant *args,
|
|
uint32_t argCount, NPVariant *result);
|
|
|
|
static bool
|
|
_evaluate(NPP aNPP, NPObject* npobj, NPString *script, NPVariant *result);
|
|
|
|
static bool
|
|
_getproperty(NPP aNPP, NPObject* npobj, NPIdentifier property,
|
|
NPVariant *result);
|
|
|
|
static bool
|
|
_setproperty(NPP aNPP, NPObject* npobj, NPIdentifier property,
|
|
const NPVariant *value);
|
|
|
|
static bool
|
|
_removeproperty(NPP aNPP, NPObject* npobj, NPIdentifier property);
|
|
|
|
static bool
|
|
_hasproperty(NPP aNPP, NPObject* npobj, NPIdentifier propertyName);
|
|
|
|
static bool
|
|
_hasmethod(NPP aNPP, NPObject* npobj, NPIdentifier methodName);
|
|
|
|
static bool
|
|
_enumerate(NPP aNPP, NPObject *npobj, NPIdentifier **identifier,
|
|
uint32_t *count);
|
|
|
|
static bool
|
|
_construct(NPP aNPP, NPObject* npobj, const NPVariant *args,
|
|
uint32_t argCount, NPVariant *result);
|
|
|
|
static void
|
|
_releasevariantvalue(NPVariant *variant);
|
|
|
|
static void
|
|
_setexception(NPObject* npobj, const NPUTF8 *message);
|
|
|
|
static void
|
|
_pushpopupsenabledstate(NPP aNPP, NPBool enabled);
|
|
|
|
static void
|
|
_poppopupsenabledstate(NPP aNPP);
|
|
|
|
static NPError
|
|
_getvalueforurl(NPP npp, NPNURLVariable variable, const char *url,
|
|
char **value, uint32_t *len);
|
|
|
|
static NPError
|
|
_setvalueforurl(NPP npp, NPNURLVariable variable, const char *url,
|
|
const char *value, uint32_t len);
|
|
|
|
static uint32_t
|
|
_scheduletimer(NPP instance, uint32_t interval, NPBool repeat,
|
|
void (*timerFunc)(NPP npp, uint32_t timerID));
|
|
|
|
static void
|
|
_unscheduletimer(NPP instance, uint32_t timerID);
|
|
|
|
static NPError
|
|
_popupcontextmenu(NPP instance, NPMenu* menu);
|
|
|
|
static NPBool
|
|
_convertpoint(NPP instance,
|
|
double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
|
|
double *destX, double *destY, NPCoordinateSpace destSpace);
|
|
|
|
static void
|
|
_urlredirectresponse(NPP instance, void* notifyData, NPBool allow);
|
|
|
|
static NPError
|
|
_initasyncsurface(NPP instance, NPSize *size,
|
|
NPImageFormat format, void *initData,
|
|
NPAsyncSurface *surface);
|
|
|
|
static NPError
|
|
_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface);
|
|
|
|
static void
|
|
_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed);
|
|
|
|
} /* namespace child */
|
|
} /* namespace plugins */
|
|
} /* namespace mozilla */
|
|
|
|
const NPNetscapeFuncs PluginModuleChild::sBrowserFuncs = {
|
|
sizeof(sBrowserFuncs),
|
|
(NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR,
|
|
mozilla::plugins::child::_geturl,
|
|
mozilla::plugins::child::_posturl,
|
|
mozilla::plugins::child::_requestread,
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
mozilla::plugins::child::_status,
|
|
mozilla::plugins::child::_useragent,
|
|
mozilla::plugins::child::_memalloc,
|
|
mozilla::plugins::child::_memfree,
|
|
mozilla::plugins::child::_memflush,
|
|
mozilla::plugins::child::_reloadplugins,
|
|
mozilla::plugins::child::_getjavaenv,
|
|
mozilla::plugins::child::_getjavapeer,
|
|
mozilla::plugins::child::_geturlnotify,
|
|
mozilla::plugins::child::_posturlnotify,
|
|
mozilla::plugins::child::_getvalue,
|
|
mozilla::plugins::child::_setvalue,
|
|
mozilla::plugins::child::_invalidaterect,
|
|
mozilla::plugins::child::_invalidateregion,
|
|
mozilla::plugins::child::_forceredraw,
|
|
PluginModuleChild::NPN_GetStringIdentifier,
|
|
PluginModuleChild::NPN_GetStringIdentifiers,
|
|
PluginModuleChild::NPN_GetIntIdentifier,
|
|
PluginModuleChild::NPN_IdentifierIsString,
|
|
PluginModuleChild::NPN_UTF8FromIdentifier,
|
|
PluginModuleChild::NPN_IntFromIdentifier,
|
|
PluginModuleChild::NPN_CreateObject,
|
|
PluginModuleChild::NPN_RetainObject,
|
|
PluginModuleChild::NPN_ReleaseObject,
|
|
mozilla::plugins::child::_invoke,
|
|
mozilla::plugins::child::_invokedefault,
|
|
mozilla::plugins::child::_evaluate,
|
|
mozilla::plugins::child::_getproperty,
|
|
mozilla::plugins::child::_setproperty,
|
|
mozilla::plugins::child::_removeproperty,
|
|
mozilla::plugins::child::_hasproperty,
|
|
mozilla::plugins::child::_hasmethod,
|
|
mozilla::plugins::child::_releasevariantvalue,
|
|
mozilla::plugins::child::_setexception,
|
|
mozilla::plugins::child::_pushpopupsenabledstate,
|
|
mozilla::plugins::child::_poppopupsenabledstate,
|
|
mozilla::plugins::child::_enumerate,
|
|
nullptr, // pluginthreadasynccall, not used
|
|
mozilla::plugins::child::_construct,
|
|
mozilla::plugins::child::_getvalueforurl,
|
|
mozilla::plugins::child::_setvalueforurl,
|
|
nullptr, //NPN GetAuthenticationInfo, not supported
|
|
mozilla::plugins::child::_scheduletimer,
|
|
mozilla::plugins::child::_unscheduletimer,
|
|
mozilla::plugins::child::_popupcontextmenu,
|
|
mozilla::plugins::child::_convertpoint,
|
|
nullptr, // handleevent, unimplemented
|
|
nullptr, // unfocusinstance, unimplemented
|
|
mozilla::plugins::child::_urlredirectresponse,
|
|
mozilla::plugins::child::_initasyncsurface,
|
|
mozilla::plugins::child::_finalizeasyncsurface,
|
|
mozilla::plugins::child::_setcurrentasyncsurface,
|
|
};
|
|
|
|
PluginInstanceChild*
|
|
InstCast(NPP aNPP)
|
|
{
|
|
MOZ_ASSERT(!!(aNPP->ndata), "nil instance");
|
|
return static_cast<PluginInstanceChild*>(aNPP->ndata);
|
|
}
|
|
|
|
namespace mozilla {
|
|
namespace plugins {
|
|
namespace child {
|
|
|
|
NPError
|
|
_requestread(NPStream* aStream,
|
|
NPByteRange* aRangeList)
|
|
{
|
|
return NPERR_STREAM_NOT_SEEKABLE;
|
|
}
|
|
|
|
NPError
|
|
_geturlnotify(NPP aNPP,
|
|
const char* aRelativeURL,
|
|
const char* aTarget,
|
|
void* aNotifyData)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
|
|
|
|
if (!aNPP) // nullptr check for nspluginwrapper (bug 561690)
|
|
return NPERR_INVALID_INSTANCE_ERROR;
|
|
|
|
nsCString url = NullableString(aRelativeURL);
|
|
auto* sn = new StreamNotifyChild(url);
|
|
|
|
NPError err;
|
|
InstCast(aNPP)->CallPStreamNotifyConstructor(
|
|
sn, url, NullableString(aTarget), false, nsCString(), false, &err);
|
|
|
|
if (NPERR_NO_ERROR == err) {
|
|
// If NPN_PostURLNotify fails, the parent will immediately send us
|
|
// a PStreamNotifyDestructor, which should not call NPP_URLNotify.
|
|
sn->SetValid(aNotifyData);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NPError
|
|
_getvalue(NPP aNPP,
|
|
NPNVariable aVariable,
|
|
void* aValue)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
|
|
|
|
switch (aVariable) {
|
|
// Copied from nsNPAPIPlugin.cpp
|
|
case NPNVToolkit:
|
|
#if defined(MOZ_WIDGET_GTK)
|
|
*static_cast<NPNToolkitType*>(aValue) = NPNVGtk2;
|
|
return NPERR_NO_ERROR;
|
|
#endif
|
|
return NPERR_GENERIC_ERROR;
|
|
|
|
case NPNVjavascriptEnabledBool:
|
|
*(NPBool*)aValue = PluginModuleChild::GetChrome()->Settings().javascriptEnabled();
|
|
return NPERR_NO_ERROR;
|
|
case NPNVasdEnabledBool:
|
|
*(NPBool*)aValue = PluginModuleChild::GetChrome()->Settings().asdEnabled();
|
|
return NPERR_NO_ERROR;
|
|
case NPNVisOfflineBool:
|
|
*(NPBool*)aValue = PluginModuleChild::GetChrome()->Settings().isOffline();
|
|
return NPERR_NO_ERROR;
|
|
case NPNVSupportsXEmbedBool:
|
|
// We don't support windowed xembed any more. But we still deliver
|
|
// events based on X/GTK, not Xt, so we continue to return true
|
|
// (and Flash requires that we return true).
|
|
*(NPBool*)aValue = true;
|
|
return NPERR_NO_ERROR;
|
|
case NPNVSupportsWindowless:
|
|
*(NPBool*)aValue = true;
|
|
return NPERR_NO_ERROR;
|
|
#if defined(MOZ_WIDGET_GTK)
|
|
case NPNVxDisplay: {
|
|
if (!aNPP) {
|
|
return NPERR_INVALID_INSTANCE_ERROR;
|
|
}
|
|
return InstCast(aNPP)->NPN_GetValue(aVariable, aValue);
|
|
}
|
|
case NPNVxtAppContext:
|
|
return NPERR_GENERIC_ERROR;
|
|
#endif
|
|
default: {
|
|
if (aNPP) {
|
|
return InstCast(aNPP)->NPN_GetValue(aVariable, aValue);
|
|
}
|
|
|
|
NS_WARNING("Null NPP!");
|
|
return NPERR_INVALID_INSTANCE_ERROR;
|
|
}
|
|
}
|
|
|
|
NS_NOTREACHED("Shouldn't get here!");
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
NPError
|
|
_setvalue(NPP aNPP,
|
|
NPPVariable aVariable,
|
|
void* aValue)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
|
|
return InstCast(aNPP)->NPN_SetValue(aVariable, aValue);
|
|
}
|
|
|
|
NPError
|
|
_geturl(NPP aNPP,
|
|
const char* aRelativeURL,
|
|
const char* aTarget)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
|
|
|
|
NPError err;
|
|
InstCast(aNPP)->CallNPN_GetURL(NullableString(aRelativeURL),
|
|
NullableString(aTarget), &err);
|
|
return err;
|
|
}
|
|
|
|
NPError
|
|
_posturlnotify(NPP aNPP,
|
|
const char* aRelativeURL,
|
|
const char* aTarget,
|
|
uint32_t aLength,
|
|
const char* aBuffer,
|
|
NPBool aIsFile,
|
|
void* aNotifyData)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
|
|
|
|
if (!aBuffer)
|
|
return NPERR_INVALID_PARAM;
|
|
|
|
if (aIsFile) {
|
|
PLUGIN_LOG_DEBUG(("NPN_PostURLNotify with file=true is no longer supported"));
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
nsCString url = NullableString(aRelativeURL);
|
|
auto* sn = new StreamNotifyChild(url);
|
|
|
|
NPError err;
|
|
InstCast(aNPP)->CallPStreamNotifyConstructor(
|
|
sn, url, NullableString(aTarget), true,
|
|
nsCString(aBuffer, aLength), aIsFile, &err);
|
|
|
|
if (NPERR_NO_ERROR == err) {
|
|
// If NPN_PostURLNotify fails, the parent will immediately send us
|
|
// a PStreamNotifyDestructor, which should not call NPP_URLNotify.
|
|
sn->SetValid(aNotifyData);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NPError
|
|
_posturl(NPP aNPP,
|
|
const char* aRelativeURL,
|
|
const char* aTarget,
|
|
uint32_t aLength,
|
|
const char* aBuffer,
|
|
NPBool aIsFile)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(NPERR_INVALID_PARAM);
|
|
|
|
if (aIsFile) {
|
|
PLUGIN_LOG_DEBUG(("NPN_PostURL with file=true is no longer supported"));
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
NPError err;
|
|
// FIXME what should happen when |aBuffer| is null?
|
|
InstCast(aNPP)->CallNPN_PostURL(NullableString(aRelativeURL),
|
|
NullableString(aTarget),
|
|
nsDependentCString(aBuffer, aLength),
|
|
aIsFile, &err);
|
|
return err;
|
|
}
|
|
|
|
|
|
void
|
|
_status(NPP aNPP,
|
|
const char* aMessage)
|
|
{
|
|
// NPN_Status is no longer supported.
|
|
}
|
|
|
|
void
|
|
_memfree(void* aPtr)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
free(aPtr);
|
|
}
|
|
|
|
uint32_t
|
|
_memflush(uint32_t aSize)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
_reloadplugins(NPBool aReloadPages)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD_VOID();
|
|
|
|
// Send the reload message to all modules. Chrome will need to reload from
|
|
// disk and content will need to request a new list of plugin tags from
|
|
// chrome.
|
|
PluginModuleChild::GetChrome()->SendNPN_ReloadPlugins(!!aReloadPages);
|
|
}
|
|
|
|
void
|
|
_invalidaterect(NPP aNPP,
|
|
NPRect* aInvalidRect)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD_VOID();
|
|
// nullptr check for nspluginwrapper (bug 548434)
|
|
if (aNPP) {
|
|
InstCast(aNPP)->InvalidateRect(aInvalidRect);
|
|
}
|
|
}
|
|
|
|
void
|
|
_invalidateregion(NPP aNPP,
|
|
NPRegion aInvalidRegion)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD_VOID();
|
|
NS_WARNING("Not yet implemented!");
|
|
}
|
|
|
|
void
|
|
_forceredraw(NPP aNPP)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD_VOID();
|
|
|
|
// We ignore calls to NPN_ForceRedraw. Such calls should
|
|
// never be necessary.
|
|
}
|
|
|
|
const char*
|
|
_useragent(NPP aNPP)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(nullptr);
|
|
return PluginModuleChild::GetChrome()->GetUserAgent();
|
|
}
|
|
|
|
void*
|
|
_memalloc(uint32_t aSize)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
return moz_xmalloc(aSize);
|
|
}
|
|
|
|
// Deprecated entry points for the old Java plugin.
|
|
void* /* OJI type: JRIEnv* */
|
|
_getjavaenv(void)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
return 0;
|
|
}
|
|
|
|
void* /* OJI type: jref */
|
|
_getjavapeer(NPP aNPP)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
_invoke(NPP aNPP,
|
|
NPObject* aNPObj,
|
|
NPIdentifier aMethod,
|
|
const NPVariant* aArgs,
|
|
uint32_t aArgCount,
|
|
NPVariant* aResult)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(false);
|
|
|
|
if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->invoke)
|
|
return false;
|
|
|
|
return aNPObj->_class->invoke(aNPObj, aMethod, aArgs, aArgCount, aResult);
|
|
}
|
|
|
|
bool
|
|
_invokedefault(NPP aNPP,
|
|
NPObject* aNPObj,
|
|
const NPVariant* aArgs,
|
|
uint32_t aArgCount,
|
|
NPVariant* aResult)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(false);
|
|
|
|
if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->invokeDefault)
|
|
return false;
|
|
|
|
return aNPObj->_class->invokeDefault(aNPObj, aArgs, aArgCount, aResult);
|
|
}
|
|
|
|
bool
|
|
_evaluate(NPP aNPP,
|
|
NPObject* aObject,
|
|
NPString* aScript,
|
|
NPVariant* aResult)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(false);
|
|
|
|
if (!(aNPP && aObject && aScript && aResult)) {
|
|
NS_ERROR("Bad arguments!");
|
|
return false;
|
|
}
|
|
|
|
PluginScriptableObjectChild* actor =
|
|
InstCast(aNPP)->GetActorForNPObject(aObject);
|
|
if (!actor) {
|
|
NS_ERROR("Failed to create actor?!");
|
|
return false;
|
|
}
|
|
|
|
#ifdef XP_WIN
|
|
if (gDelayFlashFocusReplyUntilEval) {
|
|
ReplyMessage(0);
|
|
gDelayFlashFocusReplyUntilEval = false;
|
|
}
|
|
#endif
|
|
|
|
return actor->Evaluate(aScript, aResult);
|
|
}
|
|
|
|
bool
|
|
_getproperty(NPP aNPP,
|
|
NPObject* aNPObj,
|
|
NPIdentifier aPropertyName,
|
|
NPVariant* aResult)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(false);
|
|
|
|
if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->getProperty)
|
|
return false;
|
|
|
|
return aNPObj->_class->getProperty(aNPObj, aPropertyName, aResult);
|
|
}
|
|
|
|
bool
|
|
_setproperty(NPP aNPP,
|
|
NPObject* aNPObj,
|
|
NPIdentifier aPropertyName,
|
|
const NPVariant* aValue)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(false);
|
|
|
|
if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->setProperty)
|
|
return false;
|
|
|
|
return aNPObj->_class->setProperty(aNPObj, aPropertyName, aValue);
|
|
}
|
|
|
|
bool
|
|
_removeproperty(NPP aNPP,
|
|
NPObject* aNPObj,
|
|
NPIdentifier aPropertyName)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(false);
|
|
|
|
if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->removeProperty)
|
|
return false;
|
|
|
|
return aNPObj->_class->removeProperty(aNPObj, aPropertyName);
|
|
}
|
|
|
|
bool
|
|
_hasproperty(NPP aNPP,
|
|
NPObject* aNPObj,
|
|
NPIdentifier aPropertyName)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(false);
|
|
|
|
if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->hasProperty)
|
|
return false;
|
|
|
|
return aNPObj->_class->hasProperty(aNPObj, aPropertyName);
|
|
}
|
|
|
|
bool
|
|
_hasmethod(NPP aNPP,
|
|
NPObject* aNPObj,
|
|
NPIdentifier aMethodName)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(false);
|
|
|
|
if (!aNPP || !aNPObj || !aNPObj->_class || !aNPObj->_class->hasMethod)
|
|
return false;
|
|
|
|
return aNPObj->_class->hasMethod(aNPObj, aMethodName);
|
|
}
|
|
|
|
bool
|
|
_enumerate(NPP aNPP,
|
|
NPObject* aNPObj,
|
|
NPIdentifier** aIdentifiers,
|
|
uint32_t* aCount)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(false);
|
|
|
|
if (!aNPP || !aNPObj || !aNPObj->_class)
|
|
return false;
|
|
|
|
if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(aNPObj->_class) ||
|
|
!aNPObj->_class->enumerate) {
|
|
*aIdentifiers = 0;
|
|
*aCount = 0;
|
|
return true;
|
|
}
|
|
|
|
return aNPObj->_class->enumerate(aNPObj, aIdentifiers, aCount);
|
|
}
|
|
|
|
bool
|
|
_construct(NPP aNPP,
|
|
NPObject* aNPObj,
|
|
const NPVariant* aArgs,
|
|
uint32_t aArgCount,
|
|
NPVariant* aResult)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(false);
|
|
|
|
if (!aNPP || !aNPObj || !aNPObj->_class ||
|
|
!NP_CLASS_STRUCT_VERSION_HAS_CTOR(aNPObj->_class) ||
|
|
!aNPObj->_class->construct) {
|
|
return false;
|
|
}
|
|
|
|
return aNPObj->_class->construct(aNPObj, aArgs, aArgCount, aResult);
|
|
}
|
|
|
|
void
|
|
_releasevariantvalue(NPVariant* aVariant)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
// Only assert plugin thread here for consistency with in-process plugins.
|
|
AssertPluginThread();
|
|
|
|
if (NPVARIANT_IS_STRING(*aVariant)) {
|
|
NPString str = NPVARIANT_TO_STRING(*aVariant);
|
|
free(const_cast<NPUTF8*>(str.UTF8Characters));
|
|
}
|
|
else if (NPVARIANT_IS_OBJECT(*aVariant)) {
|
|
NPObject* object = NPVARIANT_TO_OBJECT(*aVariant);
|
|
if (object) {
|
|
PluginModuleChild::NPN_ReleaseObject(object);
|
|
}
|
|
}
|
|
VOID_TO_NPVARIANT(*aVariant);
|
|
}
|
|
|
|
void
|
|
_setexception(NPObject* aNPObj,
|
|
const NPUTF8* aMessage)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD_VOID();
|
|
|
|
// Do nothing. We no longer support this API.
|
|
}
|
|
|
|
void
|
|
_pushpopupsenabledstate(NPP aNPP,
|
|
NPBool aEnabled)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD_VOID();
|
|
|
|
InstCast(aNPP)->CallNPN_PushPopupsEnabledState(aEnabled ? true : false);
|
|
}
|
|
|
|
void
|
|
_poppopupsenabledstate(NPP aNPP)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD_VOID();
|
|
|
|
InstCast(aNPP)->CallNPN_PopPopupsEnabledState();
|
|
}
|
|
|
|
NPError
|
|
_getvalueforurl(NPP npp, NPNURLVariable variable, const char *url,
|
|
char **value, uint32_t *len)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
AssertPluginThread();
|
|
|
|
if (!url)
|
|
return NPERR_INVALID_URL;
|
|
|
|
if (!npp || !value || !len)
|
|
return NPERR_INVALID_PARAM;
|
|
|
|
if (variable == NPNURLVProxy) {
|
|
nsCString v;
|
|
NPError result;
|
|
InstCast(npp)->
|
|
CallNPN_GetValueForURL(variable, nsCString(url), &v, &result);
|
|
if (NPERR_NO_ERROR == result) {
|
|
*value = ToNewCString(v);
|
|
*len = v.Length();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
return NPERR_INVALID_PARAM;
|
|
}
|
|
|
|
NPError
|
|
_setvalueforurl(NPP npp, NPNURLVariable variable, const char *url,
|
|
const char *value, uint32_t len)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
AssertPluginThread();
|
|
|
|
if (!value)
|
|
return NPERR_INVALID_PARAM;
|
|
|
|
if (!url)
|
|
return NPERR_INVALID_URL;
|
|
|
|
if (variable == NPNURLVProxy) {
|
|
NPError result;
|
|
InstCast(npp)->CallNPN_SetValueForURL(variable, nsCString(url),
|
|
nsDependentCString(value, len),
|
|
&result);
|
|
return result;
|
|
}
|
|
|
|
return NPERR_INVALID_PARAM;
|
|
}
|
|
|
|
|
|
uint32_t
|
|
_scheduletimer(NPP npp, uint32_t interval, NPBool repeat,
|
|
void (*timerFunc)(NPP npp, uint32_t timerID))
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
AssertPluginThread();
|
|
return InstCast(npp)->ScheduleTimer(interval, repeat, timerFunc);
|
|
}
|
|
|
|
void
|
|
_unscheduletimer(NPP npp, uint32_t timerID)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
AssertPluginThread();
|
|
InstCast(npp)->UnscheduleTimer(timerID);
|
|
}
|
|
|
|
|
|
#ifdef OS_MACOSX
|
|
static void ProcessBrowserEvents(void* pluginModule) {
|
|
PluginModuleChild* pmc = static_cast<PluginModuleChild*>(pluginModule);
|
|
|
|
if (!pmc)
|
|
return;
|
|
|
|
pmc->CallProcessSomeEvents();
|
|
}
|
|
#endif
|
|
|
|
NPError
|
|
_popupcontextmenu(NPP instance, NPMenu* menu)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
AssertPluginThread();
|
|
|
|
#ifdef MOZ_WIDGET_COCOA
|
|
double pluginX, pluginY;
|
|
double screenX, screenY;
|
|
|
|
const NPCocoaEvent* currentEvent = InstCast(instance)->getCurrentEvent();
|
|
if (!currentEvent) {
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
// Ensure that the events has an x/y value.
|
|
if (currentEvent->type != NPCocoaEventMouseDown &&
|
|
currentEvent->type != NPCocoaEventMouseUp &&
|
|
currentEvent->type != NPCocoaEventMouseMoved &&
|
|
currentEvent->type != NPCocoaEventMouseEntered &&
|
|
currentEvent->type != NPCocoaEventMouseExited &&
|
|
currentEvent->type != NPCocoaEventMouseDragged) {
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
pluginX = currentEvent->data.mouse.pluginX;
|
|
pluginY = currentEvent->data.mouse.pluginY;
|
|
|
|
if ((pluginX < 0.0) || (pluginY < 0.0))
|
|
return NPERR_GENERIC_ERROR;
|
|
|
|
NPBool success = _convertpoint(instance,
|
|
pluginX, pluginY, NPCoordinateSpacePlugin,
|
|
&screenX, &screenY, NPCoordinateSpaceScreen);
|
|
|
|
if (success) {
|
|
return mozilla::plugins::PluginUtilsOSX::ShowCocoaContextMenu(menu,
|
|
screenX, screenY,
|
|
InstCast(instance)->Manager(),
|
|
ProcessBrowserEvents);
|
|
} else {
|
|
NS_WARNING("Convertpoint failed, could not created contextmenu.");
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
#else
|
|
NS_WARNING("Not supported on this platform!");
|
|
return NPERR_GENERIC_ERROR;
|
|
#endif
|
|
}
|
|
|
|
NPBool
|
|
_convertpoint(NPP instance,
|
|
double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
|
|
double *destX, double *destY, NPCoordinateSpace destSpace)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
if (!IsPluginThread()) {
|
|
NS_WARNING("Not running on the plugin's main thread!");
|
|
return false;
|
|
}
|
|
|
|
double rDestX = 0;
|
|
bool ignoreDestX = !destX;
|
|
double rDestY = 0;
|
|
bool ignoreDestY = !destY;
|
|
bool result = false;
|
|
InstCast(instance)->CallNPN_ConvertPoint(sourceX, ignoreDestX, sourceY, ignoreDestY, sourceSpace, destSpace,
|
|
&rDestX, &rDestY, &result);
|
|
if (result) {
|
|
if (destX)
|
|
*destX = rDestX;
|
|
if (destY)
|
|
*destY = rDestY;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void
|
|
_urlredirectresponse(NPP instance, void* notifyData, NPBool allow)
|
|
{
|
|
InstCast(instance)->NPN_URLRedirectResponse(notifyData, allow);
|
|
}
|
|
|
|
NPError
|
|
_initasyncsurface(NPP instance, NPSize *size,
|
|
NPImageFormat format, void *initData,
|
|
NPAsyncSurface *surface)
|
|
{
|
|
return InstCast(instance)->NPN_InitAsyncSurface(size, format, initData, surface);
|
|
}
|
|
|
|
NPError
|
|
_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface)
|
|
{
|
|
return InstCast(instance)->NPN_FinalizeAsyncSurface(surface);
|
|
}
|
|
|
|
void
|
|
_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed)
|
|
{
|
|
InstCast(instance)->NPN_SetCurrentAsyncSurface(surface, changed);
|
|
}
|
|
|
|
} /* namespace child */
|
|
} /* namespace plugins */
|
|
} /* namespace mozilla */
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::RecvSettingChanged(const PluginSettings& aSettings)
|
|
{
|
|
mCachedSettings = aSettings;
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::AnswerNP_GetEntryPoints(NPError* _retval)
|
|
{
|
|
PLUGIN_LOG_DEBUG_METHOD;
|
|
AssertPluginThread();
|
|
MOZ_ASSERT(mIsChrome);
|
|
|
|
#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
|
|
return IPC_OK();
|
|
#elif defined(OS_WIN) || defined(OS_MACOSX)
|
|
*_retval = mGetEntryPointsFunc(&mFunctions);
|
|
return IPC_OK();
|
|
#else
|
|
# error Please implement me for your platform
|
|
#endif
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::AnswerNP_Initialize(const PluginSettings& aSettings, NPError* rv)
|
|
{
|
|
*rv = DoNP_Initialize(aSettings);
|
|
return IPC_OK();
|
|
}
|
|
|
|
NPError
|
|
PluginModuleChild::DoNP_Initialize(const PluginSettings& aSettings)
|
|
{
|
|
PLUGIN_LOG_DEBUG_METHOD;
|
|
AssertPluginThread();
|
|
MOZ_ASSERT(mIsChrome);
|
|
|
|
mCachedSettings = aSettings;
|
|
|
|
#ifdef OS_WIN
|
|
SetEventHooks();
|
|
#endif
|
|
|
|
#ifdef MOZ_X11
|
|
// Send the parent our X socket to act as a proxy reference for our X
|
|
// resources.
|
|
int xSocketFd = ConnectionNumber(DefaultXDisplay());
|
|
SendBackUpXResources(FileDescriptor(xSocketFd));
|
|
#endif
|
|
|
|
NPError result;
|
|
#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
|
|
result = mInitializeFunc(&sBrowserFuncs, &mFunctions);
|
|
#elif defined(OS_WIN) || defined(OS_MACOSX)
|
|
result = mInitializeFunc(&sBrowserFuncs);
|
|
#else
|
|
# error Please implement me for your platform
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
PPluginInstanceChild*
|
|
PluginModuleChild::AllocPPluginInstanceChild(const nsCString& aMimeType,
|
|
const InfallibleTArray<nsCString>& aNames,
|
|
const InfallibleTArray<nsCString>& aValues)
|
|
{
|
|
PLUGIN_LOG_DEBUG_METHOD;
|
|
AssertPluginThread();
|
|
|
|
// In e10s, gChromeInstance hands out quirks to instances, but never
|
|
// allocates an instance on its own. Make sure it gets the latest copy
|
|
// of quirks once we have them. Also note, with process-per-tab, we may
|
|
// have multiple PluginModuleChilds in the same plugin process, so only
|
|
// initialize this once in gChromeInstance, which is a singleton.
|
|
GetChrome()->InitQuirksModes(aMimeType);
|
|
mQuirks = GetChrome()->mQuirks;
|
|
|
|
#ifdef XP_WIN
|
|
FunctionHook::HookFunctions(mQuirks);
|
|
#endif
|
|
|
|
return new PluginInstanceChild(&mFunctions, aMimeType, aNames,
|
|
aValues);
|
|
}
|
|
|
|
void
|
|
PluginModuleChild::InitQuirksModes(const nsCString& aMimeType)
|
|
{
|
|
if (mQuirks != QUIRKS_NOT_INITIALIZED) {
|
|
return;
|
|
}
|
|
|
|
mQuirks = GetQuirksFromMimeTypeAndFilename(aMimeType, mPluginFilename);
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::AnswerModuleSupportsAsyncRender(bool* aResult)
|
|
{
|
|
#if defined(XP_WIN)
|
|
*aResult = gChromeInstance->mAsyncRenderSupport;
|
|
return IPC_OK();
|
|
#else
|
|
NS_NOTREACHED("Shouldn't get here!");
|
|
return IPC_FAIL_NO_REASON(this);
|
|
#endif
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::RecvPPluginInstanceConstructor(PPluginInstanceChild* aActor,
|
|
const nsCString& aMimeType,
|
|
InfallibleTArray<nsCString>&& aNames,
|
|
InfallibleTArray<nsCString>&& aValues)
|
|
{
|
|
PLUGIN_LOG_DEBUG_METHOD;
|
|
AssertPluginThread();
|
|
|
|
NS_ASSERTION(aActor, "Null actor!");
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::AnswerSyncNPP_New(PPluginInstanceChild* aActor, NPError* rv)
|
|
{
|
|
PLUGIN_LOG_DEBUG_METHOD;
|
|
PluginInstanceChild* childInstance =
|
|
reinterpret_cast<PluginInstanceChild*>(aActor);
|
|
AssertPluginThread();
|
|
*rv = childInstance->DoNPP_New();
|
|
return IPC_OK();
|
|
}
|
|
|
|
bool
|
|
PluginModuleChild::DeallocPPluginInstanceChild(PPluginInstanceChild* aActor)
|
|
{
|
|
PLUGIN_LOG_DEBUG_METHOD;
|
|
AssertPluginThread();
|
|
|
|
delete aActor;
|
|
|
|
return true;
|
|
}
|
|
|
|
NPObject*
|
|
PluginModuleChild::NPN_CreateObject(NPP aNPP, NPClass* aClass)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
ENSURE_PLUGIN_THREAD(nullptr);
|
|
|
|
PluginInstanceChild* i = InstCast(aNPP);
|
|
if (i->mDeletingHash) {
|
|
NS_ERROR("Plugin used NPP after NPP_Destroy");
|
|
return nullptr;
|
|
}
|
|
|
|
NPObject* newObject;
|
|
if (aClass && aClass->allocate) {
|
|
newObject = aClass->allocate(aNPP, aClass);
|
|
}
|
|
else {
|
|
newObject = reinterpret_cast<NPObject*>(child::_memalloc(sizeof(NPObject)));
|
|
}
|
|
|
|
if (newObject) {
|
|
newObject->_class = aClass;
|
|
newObject->referenceCount = 1;
|
|
NS_LOG_ADDREF(newObject, 1, "NPObject", sizeof(NPObject));
|
|
}
|
|
|
|
PluginScriptableObjectChild::RegisterObject(newObject, i);
|
|
|
|
return newObject;
|
|
}
|
|
|
|
NPObject*
|
|
PluginModuleChild::NPN_RetainObject(NPObject* aNPObj)
|
|
{
|
|
AssertPluginThread();
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
int32_t refCnt =
|
|
#endif
|
|
PR_ATOMIC_INCREMENT((int32_t*)&aNPObj->referenceCount);
|
|
NS_LOG_ADDREF(aNPObj, refCnt, "NPObject", sizeof(NPObject));
|
|
|
|
return aNPObj;
|
|
}
|
|
|
|
void
|
|
PluginModuleChild::NPN_ReleaseObject(NPObject* aNPObj)
|
|
{
|
|
AssertPluginThread();
|
|
|
|
PluginInstanceChild* instance = PluginScriptableObjectChild::GetInstanceForNPObject(aNPObj);
|
|
if (!instance) {
|
|
// The PluginInstanceChild was destroyed
|
|
return;
|
|
}
|
|
|
|
DeletingObjectEntry* doe = nullptr;
|
|
if (instance->mDeletingHash) {
|
|
doe = instance->mDeletingHash->GetEntry(aNPObj);
|
|
if (!doe) {
|
|
NS_ERROR("An object for a destroyed instance isn't in the instance deletion hash");
|
|
return;
|
|
}
|
|
if (doe->mDeleted)
|
|
return;
|
|
}
|
|
|
|
int32_t refCnt = PR_ATOMIC_DECREMENT((int32_t*)&aNPObj->referenceCount);
|
|
NS_LOG_RELEASE(aNPObj, refCnt, "NPObject");
|
|
|
|
if (refCnt == 0) {
|
|
DeallocNPObject(aNPObj);
|
|
if (doe)
|
|
doe->mDeleted = true;
|
|
}
|
|
}
|
|
|
|
void
|
|
PluginModuleChild::DeallocNPObject(NPObject* aNPObj)
|
|
{
|
|
if (aNPObj->_class && aNPObj->_class->deallocate) {
|
|
aNPObj->_class->deallocate(aNPObj);
|
|
} else {
|
|
child::_memfree(aNPObj);
|
|
}
|
|
|
|
PluginScriptableObjectChild* actor = PluginScriptableObjectChild::GetActorForNPObject(aNPObj);
|
|
if (actor)
|
|
actor->NPObjectDestroyed();
|
|
|
|
PluginScriptableObjectChild::UnregisterObject(aNPObj);
|
|
}
|
|
|
|
NPIdentifier
|
|
PluginModuleChild::NPN_GetStringIdentifier(const NPUTF8* aName)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
AssertPluginThread();
|
|
|
|
if (!aName)
|
|
return 0;
|
|
|
|
nsDependentCString name(aName);
|
|
PluginIdentifier ident(name);
|
|
PluginScriptableObjectChild::StackIdentifier stackID(ident);
|
|
stackID.MakePermanent();
|
|
return stackID.ToNPIdentifier();
|
|
}
|
|
|
|
void
|
|
PluginModuleChild::NPN_GetStringIdentifiers(const NPUTF8** aNames,
|
|
int32_t aNameCount,
|
|
NPIdentifier* aIdentifiers)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
AssertPluginThread();
|
|
|
|
if (!(aNames && aNameCount > 0 && aIdentifiers)) {
|
|
MOZ_CRASH("Bad input! Headed for a crash!");
|
|
}
|
|
|
|
for (int32_t index = 0; index < aNameCount; ++index) {
|
|
if (!aNames[index]) {
|
|
aIdentifiers[index] = 0;
|
|
continue;
|
|
}
|
|
nsDependentCString name(aNames[index]);
|
|
PluginIdentifier ident(name);
|
|
PluginScriptableObjectChild::StackIdentifier stackID(ident);
|
|
stackID.MakePermanent();
|
|
aIdentifiers[index] = stackID.ToNPIdentifier();
|
|
}
|
|
}
|
|
|
|
bool
|
|
PluginModuleChild::NPN_IdentifierIsString(NPIdentifier aIdentifier)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
|
|
PluginScriptableObjectChild::StackIdentifier stack(aIdentifier);
|
|
return stack.IsString();
|
|
}
|
|
|
|
NPIdentifier
|
|
PluginModuleChild::NPN_GetIntIdentifier(int32_t aIntId)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
AssertPluginThread();
|
|
|
|
PluginIdentifier ident(aIntId);
|
|
PluginScriptableObjectChild::StackIdentifier stackID(ident);
|
|
stackID.MakePermanent();
|
|
return stackID.ToNPIdentifier();
|
|
}
|
|
|
|
NPUTF8*
|
|
PluginModuleChild::NPN_UTF8FromIdentifier(NPIdentifier aIdentifier)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
|
|
PluginScriptableObjectChild::StackIdentifier stackID(aIdentifier);
|
|
if (stackID.IsString()) {
|
|
return ToNewCString(stackID.GetString());
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
int32_t
|
|
PluginModuleChild::NPN_IntFromIdentifier(NPIdentifier aIdentifier)
|
|
{
|
|
PLUGIN_LOG_DEBUG_FUNCTION;
|
|
|
|
PluginScriptableObjectChild::StackIdentifier stackID(aIdentifier);
|
|
if (!stackID.IsString()) {
|
|
return stackID.GetInt();
|
|
}
|
|
return INT32_MIN;
|
|
}
|
|
|
|
#ifdef OS_WIN
|
|
void
|
|
PluginModuleChild::EnteredCall()
|
|
{
|
|
mIncallPumpingStack.AppendElement();
|
|
}
|
|
|
|
void
|
|
PluginModuleChild::ExitedCall()
|
|
{
|
|
NS_ASSERTION(mIncallPumpingStack.Length(), "mismatched entered/exited");
|
|
uint32_t len = mIncallPumpingStack.Length();
|
|
const IncallFrame& f = mIncallPumpingStack[len - 1];
|
|
if (f._spinning)
|
|
MessageLoop::current()->SetNestableTasksAllowed(f._savedNestableTasksAllowed);
|
|
|
|
mIncallPumpingStack.TruncateLength(len - 1);
|
|
}
|
|
|
|
LRESULT CALLBACK
|
|
PluginModuleChild::CallWindowProcHook(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// Trap and reply to anything we recognize as the source of a
|
|
// potential send message deadlock.
|
|
if (nCode >= 0 &&
|
|
(InSendMessageEx(nullptr)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
|
|
CWPSTRUCT* pCwp = reinterpret_cast<CWPSTRUCT*>(lParam);
|
|
if (pCwp->message == WM_KILLFOCUS) {
|
|
// Fix for flash fullscreen window loosing focus. On single
|
|
// core systems, sync killfocus events need to be handled
|
|
// after the flash fullscreen window procedure processes this
|
|
// message, otherwise fullscreen focus will not work correctly.
|
|
wchar_t szClass[26];
|
|
if (GetClassNameW(pCwp->hwnd, szClass,
|
|
sizeof(szClass)/sizeof(char16_t)) &&
|
|
!wcscmp(szClass, kFlashFullscreenClass)) {
|
|
gDelayFlashFocusReplyUntilEval = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return CallNextHookEx(nullptr, nCode, wParam, lParam);
|
|
}
|
|
|
|
LRESULT CALLBACK
|
|
PluginModuleChild::NestedInputEventHook(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PluginModuleChild* self = GetChrome();
|
|
uint32_t len = self->mIncallPumpingStack.Length();
|
|
if (nCode >= 0 && len && !self->mIncallPumpingStack[len - 1]._spinning) {
|
|
MessageLoop* loop = MessageLoop::current();
|
|
self->SendProcessNativeEventsInInterruptCall();
|
|
IncallFrame& f = self->mIncallPumpingStack[len - 1];
|
|
f._spinning = true;
|
|
f._savedNestableTasksAllowed = loop->NestableTasksAllowed();
|
|
loop->SetNestableTasksAllowed(true);
|
|
loop->set_os_modal_loop(true);
|
|
}
|
|
|
|
return CallNextHookEx(nullptr, nCode, wParam, lParam);
|
|
}
|
|
|
|
void
|
|
PluginModuleChild::SetEventHooks()
|
|
{
|
|
NS_ASSERTION(!mNestedEventHook,
|
|
"mNestedEventHook already setup in call to SetNestedInputEventHook?");
|
|
NS_ASSERTION(!mGlobalCallWndProcHook,
|
|
"mGlobalCallWndProcHook already setup in call to CallWindowProcHook?");
|
|
|
|
PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
|
|
|
|
// WH_MSGFILTER event hook for detecting modal loops in the child.
|
|
mNestedEventHook = SetWindowsHookEx(WH_MSGFILTER,
|
|
NestedInputEventHook,
|
|
nullptr,
|
|
GetCurrentThreadId());
|
|
|
|
// WH_CALLWNDPROC event hook for trapping sync messages sent from
|
|
// parent that can cause deadlocks.
|
|
mGlobalCallWndProcHook = SetWindowsHookEx(WH_CALLWNDPROC,
|
|
CallWindowProcHook,
|
|
nullptr,
|
|
GetCurrentThreadId());
|
|
}
|
|
|
|
void
|
|
PluginModuleChild::ResetEventHooks()
|
|
{
|
|
PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
|
|
if (mNestedEventHook)
|
|
UnhookWindowsHookEx(mNestedEventHook);
|
|
mNestedEventHook = nullptr;
|
|
if (mGlobalCallWndProcHook)
|
|
UnhookWindowsHookEx(mGlobalCallWndProcHook);
|
|
mGlobalCallWndProcHook = nullptr;
|
|
}
|
|
#endif
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::RecvProcessNativeEventsInInterruptCall()
|
|
{
|
|
PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
|
|
#if defined(OS_WIN)
|
|
ProcessNativeEventsInInterruptCall();
|
|
return IPC_OK();
|
|
#else
|
|
MOZ_CRASH(
|
|
"PluginModuleChild::RecvProcessNativeEventsInInterruptCall not implemented!");
|
|
return IPC_FAIL_NO_REASON(this);
|
|
#endif
|
|
}
|
|
|
|
#ifdef MOZ_WIDGET_COCOA
|
|
void
|
|
PluginModuleChild::ProcessNativeEvents() {
|
|
CallProcessSomeEvents();
|
|
}
|
|
#endif
|
|
|
|
NPError
|
|
PluginModuleChild::PluginRequiresAudioDeviceChanges(
|
|
PluginInstanceChild* aInstance,
|
|
NPBool aShouldRegister)
|
|
{
|
|
#ifdef XP_WIN
|
|
// Maintain a set of PluginInstanceChildren that we need to tell when the
|
|
// default audio device has changed.
|
|
NPError rv = NPERR_NO_ERROR;
|
|
if (aShouldRegister) {
|
|
if (mAudioNotificationSet.IsEmpty()) {
|
|
// We are registering the first plugin. Notify the PluginModuleParent
|
|
// that it needs to start sending us audio device notifications.
|
|
if (!CallNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
|
|
aShouldRegister, &rv)) {
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
}
|
|
if (rv == NPERR_NO_ERROR) {
|
|
mAudioNotificationSet.PutEntry(aInstance);
|
|
}
|
|
}
|
|
else if (!mAudioNotificationSet.IsEmpty()) {
|
|
mAudioNotificationSet.RemoveEntry(aInstance);
|
|
if (mAudioNotificationSet.IsEmpty()) {
|
|
// We released the last plugin. Unregister from the PluginModuleParent.
|
|
if (!CallNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
|
|
aShouldRegister, &rv)) {
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
}
|
|
}
|
|
return rv;
|
|
#else
|
|
MOZ_CRASH("PluginRequiresAudioDeviceChanges is not available on this platform.");
|
|
#endif // XP_WIN
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
PluginModuleChild::RecvNPP_SetValue_NPNVaudioDeviceChangeDetails(
|
|
const NPAudioDeviceChangeDetailsIPC& detailsIPC)
|
|
{
|
|
#if defined(XP_WIN)
|
|
NPAudioDeviceChangeDetails details;
|
|
details.flow = detailsIPC.flow;
|
|
details.role = detailsIPC.role;
|
|
details.defaultDevice = detailsIPC.defaultDevice.c_str();
|
|
for (auto iter = mAudioNotificationSet.ConstIter(); !iter.Done(); iter.Next()) {
|
|
PluginInstanceChild* pluginInst = iter.Get()->GetKey();
|
|
pluginInst->DefaultAudioDeviceChanged(details);
|
|
}
|
|
return IPC_OK();
|
|
#else
|
|
MOZ_CRASH("NPP_SetValue_NPNVaudioDeviceChangeDetails is a Windows-only message");
|
|
#endif
|
|
}
|