summaryrefslogtreecommitdiffstats
path: root/chrome/plugin
diff options
context:
space:
mode:
authorjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-29 02:18:30 +0000
committerjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-29 02:18:30 +0000
commit8beff076f15f979f9334ad9f962444f57050fe52 (patch)
treef504f4c35856204e385fa12e2f3c8a45c6bdc6a8 /chrome/plugin
parente67efe3af047fdf3ca4e62ed54cadf12b5bbbea2 (diff)
downloadchromium_src-8beff076f15f979f9334ad9f962444f57050fe52.zip
chromium_src-8beff076f15f979f9334ad9f962444f57050fe52.tar.gz
chromium_src-8beff076f15f979f9334ad9f962444f57050fe52.tar.bz2
Get rid of the need for cross process events in order to get plugin processes to run nested message loops when a dialog is shown. Instead use an async message that's broadcast from the renderer to all plugin processes that are connected to it, and which is dispatched on the plugin IO thread to set a process-local waitable event. This fixes showModalDialog on Linux/Mac.
BUG=15891 TEST=covered by UI tests, undef's them for POSIX Review URL: http://codereview.chromium.org/242043 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27456 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/plugin')
-rw-r--r--chrome/plugin/npobject_proxy.cc72
-rw-r--r--chrome/plugin/npobject_proxy.h12
-rw-r--r--chrome/plugin/npobject_stub.cc18
-rw-r--r--chrome/plugin/npobject_stub.h9
-rw-r--r--chrome/plugin/npobject_util.cc8
-rw-r--r--chrome/plugin/npobject_util.h8
-rw-r--r--chrome/plugin/plugin_channel.cc121
-rw-r--r--chrome/plugin/plugin_channel.h12
-rw-r--r--chrome/plugin/plugin_channel_base.cc9
-rw-r--r--chrome/plugin/plugin_channel_base.h5
-rw-r--r--chrome/plugin/webplugin_delegate_stub.cc10
-rw-r--r--chrome/plugin/webplugin_delegate_stub.h1
-rw-r--r--chrome/plugin/webplugin_proxy.cc45
-rw-r--r--chrome/plugin/webplugin_proxy.h17
14 files changed, 226 insertions, 121 deletions
diff --git a/chrome/plugin/npobject_proxy.cc b/chrome/plugin/npobject_proxy.cc
index f224cdb..492c6c8 100644
--- a/chrome/plugin/npobject_proxy.cc
+++ b/chrome/plugin/npobject_proxy.cc
@@ -4,10 +4,9 @@
#include "chrome/plugin/npobject_proxy.h"
-#include "base/waitable_event.h"
#include "chrome/common/plugin_messages.h"
#include "chrome/plugin/npobject_util.h"
-#include "chrome/plugin/plugin_channel_base.h"
+#include "chrome/plugin/plugin_channel.h"
#include "webkit/api/public/WebBindings.h"
#include "webkit/glue/webkit_glue.h"
#include "webkit/glue/plugins/plugin_instance.h"
@@ -51,12 +50,12 @@ NPObjectProxy::NPObjectProxy(
PluginChannelBase* channel,
int route_id,
intptr_t npobject_ptr,
- base::WaitableEvent* modal_dialog_event,
+ gfx::NativeViewId containing_window,
const GURL& page_url)
: channel_(channel),
route_id_(route_id),
npobject_ptr_(npobject_ptr),
- modal_dialog_event_(modal_dialog_event),
+ containing_window_(containing_window),
page_url_(page_url) {
channel_->AddRoute(route_id, this, true);
}
@@ -72,12 +71,12 @@ NPObjectProxy::~NPObjectProxy() {
NPObject* NPObjectProxy::Create(PluginChannelBase* channel,
int route_id,
intptr_t npobject_ptr,
- base::WaitableEvent* modal_dialog_event,
+ gfx::NativeViewId containing_window,
const GURL& page_url) {
NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(
WebBindings::createObject(0, &npclass_proxy_));
obj->proxy = new NPObjectProxy(
- channel, route_id, npobject_ptr, modal_dialog_event, page_url);
+ channel, route_id, npobject_ptr, containing_window, page_url);
return reinterpret_cast<NPObject*>(obj);
}
@@ -161,6 +160,7 @@ bool NPObjectProxy::NPInvokePrivate(NPP npp,
}
bool result = false;
+ gfx::NativeViewId containing_window = proxy->containing_window_;
NPIdentifier_Param name_param;
if (is_default) {
// The data won't actually get used, but set it so we don't send random
@@ -177,7 +177,7 @@ bool NPObjectProxy::NPInvokePrivate(NPP npp,
for (unsigned int i = 0; i < arg_count; ++i) {
NPVariant_Param param;
CreateNPVariantParam(
- args[i], channel_copy, &param, false, proxy->modal_dialog_event_,
+ args[i], channel_copy, &param, false, containing_window,
proxy->page_url_);
args_param.push_back(param);
}
@@ -192,9 +192,13 @@ bool NPObjectProxy::NPInvokePrivate(NPP npp,
// queue while waiting for a reply. We need to do this to simulate what
// happens when everything runs in-process (while calling MessageBox window
// messages are pumped).
- msg->set_pump_messages_event(proxy->modal_dialog_event_);
-
- base::WaitableEvent* modal_dialog_event_handle = proxy->modal_dialog_event_;
+ if (IsPluginProcess()) {
+ PluginChannel* channel = static_cast<PluginChannel*>(proxy->channel_.get());
+ if (channel) {
+ msg->set_pump_messages_event(
+ channel->GetModalDialogEvent(containing_window));
+ }
+ }
GURL page_url = proxy->page_url_;
proxy->Send(msg);
@@ -206,8 +210,7 @@ bool NPObjectProxy::NPInvokePrivate(NPP npp,
return false;
CreateNPVariant(
- param_result, channel_copy, np_result, modal_dialog_event_handle,
- page_url);
+ param_result, channel_copy, np_result, containing_window, page_url);
return true;
}
@@ -248,17 +251,17 @@ bool NPObjectProxy::NPGetProperty(NPObject *obj,
if (obj == NULL)
return false;
- bool result = false;
NPObjectProxy* proxy = GetProxy(obj);
if (!proxy) {
return obj->_class->getProperty(obj, name, np_result);
}
+ bool result = false;
+ gfx::NativeViewId containing_window = proxy->containing_window_;
NPIdentifier_Param name_param;
CreateNPIdentifierParam(name, &name_param);
NPVariant_Param param;
- base::WaitableEvent* modal_dialog_event_handle = proxy->modal_dialog_event_;
scoped_refptr<PluginChannelBase> channel(proxy->channel_);
GURL page_url = proxy->page_url_;
@@ -270,7 +273,7 @@ bool NPObjectProxy::NPGetProperty(NPObject *obj,
return false;
CreateNPVariant(
- param, channel.get(), np_result, modal_dialog_event_handle, page_url);
+ param, channel.get(), np_result, containing_window, page_url);
return true;
}
@@ -281,19 +284,20 @@ bool NPObjectProxy::NPSetProperty(NPObject *obj,
if (obj == NULL)
return false;
- bool result = false;
NPObjectProxy* proxy = GetProxy(obj);
if (!proxy) {
return obj->_class->setProperty(obj, name, value);
}
+ bool result = false;
+ gfx::NativeViewId containing_window = proxy->containing_window_;
NPIdentifier_Param name_param;
CreateNPIdentifierParam(name, &name_param);
NPVariant_Param value_param;
CreateNPVariantParam(
*value, proxy->channel(), &value_param, false,
- proxy->modal_dialog_event_, proxy->page_url_);
+ containing_window, proxy->page_url_);
proxy->Send(new NPObjectMsg_SetProperty(
proxy->route_id(), name_param, value_param, &result));
@@ -384,6 +388,7 @@ bool NPObjectProxy::NPNConstruct(NPObject *obj,
}
bool result = false;
+ gfx::NativeViewId containing_window = proxy->containing_window_;
// Note: This instance can get destroyed in the context of
// Send so addref the channel in this scope.
@@ -392,7 +397,7 @@ bool NPObjectProxy::NPNConstruct(NPObject *obj,
for (unsigned int i = 0; i < arg_count; ++i) {
NPVariant_Param param;
CreateNPVariantParam(
- args[i], channel_copy, &param, false, proxy->modal_dialog_event_,
+ args[i], channel_copy, &param, false, containing_window,
proxy->page_url_);
args_param.push_back(param);
}
@@ -402,9 +407,13 @@ bool NPObjectProxy::NPNConstruct(NPObject *obj,
proxy->route_id_, args_param, &param_result, &result);
// See comment in NPObjectProxy::NPInvokePrivate.
- msg->set_pump_messages_event(proxy->modal_dialog_event_);
-
- base::WaitableEvent* modal_dialog_event_handle = proxy->modal_dialog_event_;
+ if (IsPluginProcess()) {
+ PluginChannel* channel = static_cast<PluginChannel*>(proxy->channel_.get());
+ if (channel) {
+ msg->set_pump_messages_event(
+ channel->GetModalDialogEvent(proxy->containing_window_));
+ }
+ }
GURL page_url = proxy->page_url_;
proxy->Send(msg);
@@ -416,8 +425,7 @@ bool NPObjectProxy::NPNConstruct(NPObject *obj,
return false;
CreateNPVariant(
- param_result, channel_copy, np_result, modal_dialog_event_handle,
- page_url);
+ param_result, channel_copy, np_result, containing_window, page_url);
return true;
}
@@ -425,12 +433,13 @@ bool NPObjectProxy::NPNEvaluate(NPP npp,
NPObject *obj,
NPString *script,
NPVariant *result_var) {
- bool result = false;
NPObjectProxy* proxy = GetProxy(obj);
if (!proxy) {
return false;
}
+ bool result = false;
+ gfx::NativeViewId containing_window = proxy->containing_window_;
bool popups_allowed = false;
if (npp) {
@@ -450,11 +459,15 @@ bool NPObjectProxy::NPNEvaluate(NPP npp,
&result_param,
&result);
- // Please refer to the comments in NPObjectProxy::NPInvokePrivate for
- // the reasoning behind setting the pump messages event in the sync message.
- msg->set_pump_messages_event(proxy->modal_dialog_event_);
+ // See comment in NPObjectProxy::NPInvokePrivate.
+ if (IsPluginProcess()) {
+ PluginChannel* channel = static_cast<PluginChannel*>(proxy->channel_.get());
+ if (channel) {
+ msg->set_pump_messages_event(
+ channel->GetModalDialogEvent(proxy->containing_window_));
+ }
+ }
scoped_refptr<PluginChannelBase> channel(proxy->channel_);
- base::WaitableEvent* modal_dialog_event_handle = proxy->modal_dialog_event_;
GURL page_url = proxy->page_url_;
proxy->Send(msg);
@@ -464,8 +477,7 @@ bool NPObjectProxy::NPNEvaluate(NPP npp,
return false;
CreateNPVariant(
- result_param, channel.get(), result_var, modal_dialog_event_handle,
- page_url);
+ result_param, channel.get(), result_var, containing_window, page_url);
return true;
}
diff --git a/chrome/plugin/npobject_proxy.h b/chrome/plugin/npobject_proxy.h
index 8858a1b..08b408d 100644
--- a/chrome/plugin/npobject_proxy.h
+++ b/chrome/plugin/npobject_proxy.h
@@ -8,6 +8,7 @@
#ifndef CHROME_PLUGIN_NPOBJECT_PROXY_H_
#define CHROME_PLUGIN_NPOBJECT_PROXY_H_
+#include "base/gfx/native_widget_types.h"
#include "base/ref_counted.h"
#include "googleurl/src/gurl.h"
#include "ipc/ipc_channel.h"
@@ -16,10 +17,6 @@
class PluginChannelBase;
struct NPObject;
-namespace base {
-class WaitableEvent;
-}
-
// When running a plugin in a different process from the renderer, we need to
// proxy calls to NPObjects across process boundaries. This happens both ways,
// as a plugin can get an NPObject for the window, and a page can get an
@@ -33,11 +30,10 @@ class NPObjectProxy : public IPC::Channel::Listener,
public:
~NPObjectProxy();
- // modal_dialog_event_ is must be valid for the lifetime of the NPObjectProxy.
static NPObject* Create(PluginChannelBase* channel,
int route_id,
intptr_t npobject_ptr,
- base::WaitableEvent* modal_dialog_event,
+ gfx::NativeViewId containing_window,
const GURL& page_url);
// IPC::Message::Sender implementation:
@@ -103,7 +99,7 @@ class NPObjectProxy : public IPC::Channel::Listener,
NPObjectProxy(PluginChannelBase* channel,
int route_id,
intptr_t npobject_ptr,
- base::WaitableEvent* modal_dialog_event,
+ gfx::NativeViewId containing_window,
const GURL& page_url);
// IPC::Channel::Listener implementation:
@@ -120,7 +116,7 @@ class NPObjectProxy : public IPC::Channel::Listener,
scoped_refptr<PluginChannelBase> channel_;
int route_id_;
intptr_t npobject_ptr_;
- base::WaitableEvent* modal_dialog_event_;
+ gfx::NativeViewId containing_window_;
// The url of the main frame hosting the plugin.
GURL page_url_;
diff --git a/chrome/plugin/npobject_stub.cc b/chrome/plugin/npobject_stub.cc
index a48049d..cc59bec 100644
--- a/chrome/plugin/npobject_stub.cc
+++ b/chrome/plugin/npobject_stub.cc
@@ -21,14 +21,14 @@ NPObjectStub::NPObjectStub(
NPObject* npobject,
PluginChannelBase* channel,
int route_id,
- base::WaitableEvent* modal_dialog_event,
+ gfx::NativeViewId containing_window,
const GURL& page_url)
: npobject_(npobject),
channel_(channel),
route_id_(route_id),
valid_(true),
web_plugin_delegate_proxy_(NULL),
- modal_dialog_event_(modal_dialog_event),
+ containing_window_(containing_window),
page_url_(page_url) {
channel_->AddRoute(route_id, this, true);
@@ -127,7 +127,7 @@ void NPObjectStub::OnInvoke(bool is_default,
NPVariant* args_var = new NPVariant[arg_count];
for (int i = 0; i < arg_count; ++i) {
CreateNPVariant(
- args[i], local_channel, &(args_var[i]), modal_dialog_event_,
+ args[i], local_channel, &(args_var[i]), containing_window_,
page_url_);
}
@@ -164,7 +164,7 @@ void NPObjectStub::OnInvoke(bool is_default,
delete[] args_var;
CreateNPVariantParam(
- result_var, local_channel, &result_param, true, modal_dialog_event_,
+ result_var, local_channel, &result_param, true, containing_window_,
page_url_);
NPObjectMsg_Invoke::WriteReplyParams(reply_msg, result_param, return_value);
local_channel->Send(reply_msg);
@@ -202,7 +202,7 @@ void NPObjectStub::OnGetProperty(const NPIdentifier_Param& name,
}
CreateNPVariantParam(
- result_var, channel_, property, true, modal_dialog_event_, page_url_);
+ result_var, channel_, property, true, containing_window_, page_url_);
}
void NPObjectStub::OnSetProperty(const NPIdentifier_Param& name,
@@ -214,7 +214,7 @@ void NPObjectStub::OnSetProperty(const NPIdentifier_Param& name,
NPIdentifier id = CreateNPIdentifier(name);
NPVariant property_var;
CreateNPVariant(
- property, channel_, &property_var, modal_dialog_event_, page_url_);
+ property, channel_, &property_var, containing_window_, page_url_);
if (IsPluginProcess()) {
if (npobject_->_class->setProperty) {
@@ -313,7 +313,7 @@ void NPObjectStub::OnConstruct(const std::vector<NPVariant_Param>& args,
NPVariant* args_var = new NPVariant[arg_count];
for (int i = 0; i < arg_count; ++i) {
CreateNPVariant(
- args[i], local_channel, &(args_var[i]), modal_dialog_event_, page_url_);
+ args[i], local_channel, &(args_var[i]), containing_window_, page_url_);
}
if (IsPluginProcess()) {
@@ -334,7 +334,7 @@ void NPObjectStub::OnConstruct(const std::vector<NPVariant_Param>& args,
delete[] args_var;
CreateNPVariantParam(
- result_var, local_channel, &result_param, true, modal_dialog_event_,
+ result_var, local_channel, &result_param, true, containing_window_,
page_url_);
NPObjectMsg_Invoke::WriteReplyParams(reply_msg, result_param, return_value);
local_channel->Send(reply_msg);
@@ -364,7 +364,7 @@ void NPObjectStub::OnEvaluate(const std::string& script,
NPVariant_Param result_param;
CreateNPVariantParam(
- result_var, local_channel, &result_param, true, modal_dialog_event_,
+ result_var, local_channel, &result_param, true, containing_window_,
page_url_);
NPObjectMsg_Evaluate::WriteReplyParams(reply_msg, result_param, return_value);
local_channel->Send(reply_msg);
diff --git a/chrome/plugin/npobject_stub.h b/chrome/plugin/npobject_stub.h
index 0f59290..6017f73 100644
--- a/chrome/plugin/npobject_stub.h
+++ b/chrome/plugin/npobject_stub.h
@@ -10,14 +10,11 @@
#include <vector>
+#include "base/gfx/native_widget_types.h"
#include "base/ref_counted.h"
#include "googleurl/src/gurl.h"
#include "ipc/ipc_channel.h"
-namespace base {
-class WaitableEvent;
-}
-
class PluginChannelBase;
class WebPluginDelegateProxy;
struct NPIdentifier_Param;
@@ -33,7 +30,7 @@ class NPObjectStub : public IPC::Channel::Listener,
NPObjectStub(NPObject* npobject,
PluginChannelBase* channel,
int route_id,
- base::WaitableEvent* modal_dialog_event,
+ gfx::NativeViewId containing_window,
const GURL& page_url);
~NPObjectStub();
@@ -91,7 +88,7 @@ class NPObjectStub : public IPC::Channel::Listener,
bool valid_;
WebPluginDelegateProxy* web_plugin_delegate_proxy_;
- base::WaitableEvent* modal_dialog_event_;
+ gfx::NativeViewId containing_window_;
// The url of the main frame hosting the plugin.
GURL page_url_;
diff --git a/chrome/plugin/npobject_util.cc b/chrome/plugin/npobject_util.cc
index 3625992..71d866e 100644
--- a/chrome/plugin/npobject_util.cc
+++ b/chrome/plugin/npobject_util.cc
@@ -141,7 +141,7 @@ void CreateNPVariantParam(const NPVariant& variant,
PluginChannelBase* channel,
NPVariant_Param* param,
bool release,
- base::WaitableEvent* modal_dialog_event,
+ gfx::NativeViewId containing_window,
const GURL& page_url) {
switch (variant.type) {
case NPVariantType_Void:
@@ -187,7 +187,7 @@ void CreateNPVariantParam(const NPVariant& variant,
param->type = NPVARIANT_PARAM_OBJECT_ROUTING_ID;
int route_id = channel->GenerateRouteID();
new NPObjectStub(
- variant.value.objectValue, channel, route_id, modal_dialog_event,
+ variant.value.objectValue, channel, route_id, containing_window,
page_url);
param->npobject_routing_id = route_id;
param->npobject_pointer =
@@ -209,7 +209,7 @@ void CreateNPVariantParam(const NPVariant& variant,
void CreateNPVariant(const NPVariant_Param& param,
PluginChannelBase* channel,
NPVariant* result,
- base::WaitableEvent* modal_dialog_event,
+ gfx::NativeViewId containing_window,
const GURL& page_url) {
switch (param.type) {
case NPVARIANT_PARAM_VOID:
@@ -243,7 +243,7 @@ void CreateNPVariant(const NPVariant_Param& param,
NPObjectProxy::Create(channel,
param.npobject_routing_id,
param.npobject_pointer,
- modal_dialog_event,
+ containing_window,
page_url);
break;
case NPVARIANT_PARAM_OBJECT_POINTER:
diff --git a/chrome/plugin/npobject_util.h b/chrome/plugin/npobject_util.h
index 861d591..3fcc701 100644
--- a/chrome/plugin/npobject_util.h
+++ b/chrome/plugin/npobject_util.h
@@ -26,10 +26,6 @@ struct NPVariant_Param;
typedef _NPVariant NPVariant;
typedef void *NPIdentifier;
-namespace base {
-class WaitableEvent;
-}
-
// Needs to be called early in the plugin process lifetime, before any
// plugin instances are initialized.
void PatchNPNFunctions();
@@ -53,14 +49,14 @@ void CreateNPVariantParam(const NPVariant& variant,
PluginChannelBase* channel,
NPVariant_Param* param,
bool release,
- base::WaitableEvent* modal_dialog_event,
+ gfx::NativeViewId containing_window,
const GURL& page_url);
// Creates an NPVariant from the marshalled object.
void CreateNPVariant(const NPVariant_Param& param,
PluginChannelBase* channel,
NPVariant* result,
- base::WaitableEvent* modal_dialog_event,
+ gfx::NativeViewId containing_window,
const GURL& page_url);
#if defined(OS_WIN)
diff --git a/chrome/plugin/plugin_channel.cc b/chrome/plugin/plugin_channel.cc
index f852a21..54ed6f3 100644
--- a/chrome/plugin/plugin_channel.cc
+++ b/chrome/plugin/plugin_channel.cc
@@ -5,13 +5,17 @@
#include "chrome/plugin/plugin_channel.h"
#include "base/command_line.h"
+#include "base/lock.h"
#include "base/process_util.h"
#include "base/string_util.h"
+#include "base/waitable_event.h"
#include "build/build_config.h"
#include "chrome/common/child_process.h"
#include "chrome/common/plugin_messages.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/plugin/plugin_thread.h"
+#include "chrome/plugin/webplugin_delegate_stub.h"
+#include "chrome/plugin/webplugin_proxy.h"
#if defined(OS_POSIX)
#include "ipc/ipc_channel_posix.h"
@@ -27,6 +31,107 @@ class PluginReleaseTask : public Task {
// How long we wait before releasing the plugin process.
static const int kPluginReleaseTimeMS = 10000;
+
+// If a sync call to the renderer results in a modal dialog, we need to have a
+// way to know so that we can run a nested message loop to simulate what would
+// happen in a single process browser and avoid deadlock.
+class PluginChannel::MessageFilter : public IPC::ChannelProxy::MessageFilter {
+ public:
+ MessageFilter() : channel_(NULL) { }
+ ~MessageFilter() {
+ // Clean up in case of renderer crash.
+ for (ModalDialogEventMap::iterator i = modal_dialog_event_map_.begin();
+ i != modal_dialog_event_map_.end(); ++i) {
+ delete i->second.event;
+ }
+ }
+
+ base::WaitableEvent* GetModalDialogEvent(
+ gfx::NativeViewId containing_window) {
+ AutoLock auto_lock(modal_dialog_event_map_lock_);
+ if (!modal_dialog_event_map_.count(containing_window)) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ return modal_dialog_event_map_[containing_window].event;
+ }
+
+ // Decrement the ref count associated with the modal dialog event for the
+ // given tab.
+ void ReleaseModalDialogEvent(gfx::NativeViewId containing_window) {
+ AutoLock auto_lock(modal_dialog_event_map_lock_);
+ if (!modal_dialog_event_map_.count(containing_window)) {
+ NOTREACHED();
+ return;
+ }
+
+ if (--(modal_dialog_event_map_[containing_window].refcount))
+ return;
+
+ // Delete the event when the stack unwinds as it could be in use now.
+ MessageLoop::current()->DeleteSoon(
+ FROM_HERE, modal_dialog_event_map_[containing_window].event);
+ modal_dialog_event_map_.erase(containing_window);
+ }
+
+ bool Send(IPC::Message* message) {
+ // Need this function for the IPC_MESSAGE_HANDLER_DELAY_REPLY macro.
+ return channel_->Send(message);
+ }
+
+ private:
+ void OnFilterAdded(IPC::Channel* channel) { channel_ = channel; }
+
+ bool OnMessageReceived(const IPC::Message& message) {
+ IPC_BEGIN_MESSAGE_MAP(PluginChannel::MessageFilter, message)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_Init, OnInit)
+ IPC_MESSAGE_HANDLER(PluginMsg_SignalModalDialogEvent,
+ OnSignalModalDialogEvent)
+ IPC_MESSAGE_HANDLER(PluginMsg_ResetModalDialogEvent,
+ OnResetModalDialogEvent)
+ IPC_END_MESSAGE_MAP()
+ return message.type() == PluginMsg_SignalModalDialogEvent::ID ||
+ message.type() == PluginMsg_ResetModalDialogEvent::ID;
+ }
+
+ void OnInit(const PluginMsg_Init_Params& params, IPC::Message* reply_msg) {
+ AutoLock auto_lock(modal_dialog_event_map_lock_);
+ if (modal_dialog_event_map_.count(params.containing_window)) {
+ modal_dialog_event_map_[params.containing_window].refcount++;
+ return;
+ }
+
+ WaitableEventWrapper wrapper;
+ wrapper.event = new base::WaitableEvent(true, false);
+ wrapper.refcount = 1;
+ modal_dialog_event_map_[params.containing_window] = wrapper;
+ }
+
+ void OnSignalModalDialogEvent(gfx::NativeViewId containing_window) {
+ AutoLock auto_lock(modal_dialog_event_map_lock_);
+ if (modal_dialog_event_map_.count(containing_window))
+ modal_dialog_event_map_[containing_window].event->Signal();
+ }
+
+ void OnResetModalDialogEvent(gfx::NativeViewId containing_window) {
+ AutoLock auto_lock(modal_dialog_event_map_lock_);
+ if (modal_dialog_event_map_.count(containing_window))
+ modal_dialog_event_map_[containing_window].event->Reset();
+ }
+
+ struct WaitableEventWrapper {
+ base::WaitableEvent* event;
+ int refcount; // There could be multiple plugin instances per tab.
+ };
+ typedef std::map<gfx::NativeViewId, WaitableEventWrapper> ModalDialogEventMap;
+ ModalDialogEventMap modal_dialog_event_map_;
+ Lock modal_dialog_event_map_lock_;
+
+ IPC::Channel* channel_;
+};
+
+
PluginChannel* PluginChannel::GetPluginChannel(int renderer_id,
MessageLoop* ipc_message_loop) {
// Map renderer ID to a (single) channel to that process.
@@ -54,7 +159,8 @@ PluginChannel::PluginChannel()
renderer_fd_(-1),
#endif
in_send_(0),
- off_the_record_(false) {
+ off_the_record_(false),
+ filter_(new MessageFilter()) {
SendUnblockingOnlyDuringDispatch();
ChildProcess::current()->AddRefProcess();
const CommandLine* command_line = CommandLine::ForCurrentProcess();
@@ -116,6 +222,8 @@ void PluginChannel::OnDestroyInstance(int instance_id,
IPC::Message* reply_msg) {
for (size_t i = 0; i < plugin_stubs_.size(); ++i) {
if (plugin_stubs_[i]->instance_id() == instance_id) {
+ filter_->ReleaseModalDialogEvent(
+ plugin_stubs_[i]->webplugin()->containing_window());
plugin_stubs_.erase(plugin_stubs_.begin() + i);
RemoveRoute(instance_id);
Send(reply_msg);
@@ -135,6 +243,11 @@ int PluginChannel::GenerateRouteID() {
return ++last_id;
}
+base::WaitableEvent* PluginChannel::GetModalDialogEvent(
+ gfx::NativeViewId containing_window) {
+ return filter_->GetModalDialogEvent(containing_window);
+}
+
void PluginChannel::OnChannelConnected(int32 peer_pid) {
base::ProcessHandle handle;
if (!base::OpenProcessHandle(peer_pid, &handle)) {
@@ -177,5 +290,9 @@ bool PluginChannel::Init(MessageLoop* ipc_message_loop, bool create_pipe_now) {
IPC::SocketPair(&plugin_fd, &renderer_fd_);
IPC::AddChannelSocket(channel_name(), plugin_fd);
#endif
- return PluginChannelBase::Init(ipc_message_loop, create_pipe_now);
+ if (!PluginChannelBase::Init(ipc_message_loop, create_pipe_now))
+ return false;
+
+ channel_->AddFilter(filter_.get());
+ return true;
}
diff --git a/chrome/plugin/plugin_channel.h b/chrome/plugin/plugin_channel.h
index 5e512f3..35c0799 100644
--- a/chrome/plugin/plugin_channel.h
+++ b/chrome/plugin/plugin_channel.h
@@ -6,11 +6,16 @@
#define CHROME_PLUGIN_PLUGIN_CHANNEL_H_
#include <vector>
+#include "base/ref_counted.h"
#include "base/scoped_handle.h"
#include "build/build_config.h"
#include "chrome/plugin/plugin_channel_base.h"
#include "chrome/plugin/webplugin_delegate_stub.h"
+namespace base {
+class WaitableEvent;
+}
+
// Encapsulates an IPC channel between the plugin process and one renderer
// process. On the renderer side there's a corresponding PluginChannelHost.
class PluginChannel : public PluginChannelBase {
@@ -34,6 +39,10 @@ class PluginChannel : public PluginChannelBase {
int GenerateRouteID();
+ // Returns the event that's set when a call to the renderer causes a modal
+ // dialog to come up.
+ base::WaitableEvent* GetModalDialogEvent(gfx::NativeViewId containing_window);
+
#if defined(OS_POSIX)
// When first created, the PluginChannel gets assigned the file descriptor
// for the renderer.
@@ -62,6 +71,8 @@ class PluginChannel : public PluginChannelBase {
virtual bool Init(MessageLoop* ipc_message_loop, bool create_pipe_now);
private:
+ class MessageFilter;
+
// Called on the plugin thread
PluginChannel();
@@ -90,6 +101,7 @@ class PluginChannel : public PluginChannelBase {
int in_send_; // Tracks if we're in a Send call.
bool log_messages_; // True if we should log sent and received messages.
bool off_the_record_; // True if the renderer is in off the record mode.
+ scoped_refptr<MessageFilter> filter_; // Handles the modal dialog events.
DISALLOW_EVIL_CONSTRUCTORS(PluginChannel);
};
diff --git a/chrome/plugin/plugin_channel_base.cc b/chrome/plugin/plugin_channel_base.cc
index 73a32e6..9c7d3ca 100644
--- a/chrome/plugin/plugin_channel_base.cc
+++ b/chrome/plugin/plugin_channel_base.cc
@@ -46,6 +46,15 @@ PluginChannelBase* PluginChannelBase::GetChannel(
return channel;
}
+void PluginChannelBase::Broadcast(IPC::Message* message) {
+ for (PluginChannelMap::iterator iter = g_plugin_channels_.begin();
+ iter != g_plugin_channels_.end();
+ ++iter) {
+ iter->second->Send(new IPC::Message(*message));
+ }
+ delete message;
+}
+
PluginChannelBase::PluginChannelBase()
: plugin_count_(0),
peer_pid_(0),
diff --git a/chrome/plugin/plugin_channel_base.h b/chrome/plugin/plugin_channel_base.h
index 9c72294..f8c3396 100644
--- a/chrome/plugin/plugin_channel_base.h
+++ b/chrome/plugin/plugin_channel_base.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/basictypes.h"
+#include "base/gfx/native_widget_types.h"
#include "base/hash_tables.h"
#include "base/message_loop.h"
#include "base/ref_counted.h"
@@ -64,6 +65,9 @@ class PluginChannelBase : public IPC::Channel::Listener,
PluginChannelFactory factory, MessageLoop* ipc_message_loop,
bool create_pipe_now);
+ // Sends a message to all instances.
+ static void Broadcast(IPC::Message* message);
+
// Called on the worker thread
PluginChannelBase();
@@ -86,7 +90,6 @@ class PluginChannelBase : public IPC::Channel::Listener,
scoped_ptr<IPC::SyncChannel> channel_;
private:
-
IPC::Channel::Mode mode_;
std::string channel_name_;
int plugin_count_;
diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc
index cf2c689..ca247f7 100644
--- a/chrome/plugin/webplugin_delegate_stub.cc
+++ b/chrome/plugin/webplugin_delegate_stub.cc
@@ -148,12 +148,8 @@ void WebPluginDelegateStub::OnInit(const PluginMsg_Init_Params& params,
// params.containing_window, &parent));
#endif
- webplugin_ = new WebPluginProxy(channel_, instance_id_, page_url_);
-#if defined(OS_WIN)
- if (!webplugin_->SetModalDialogEvent(params.modal_dialog_event))
- return;
-#endif
-
+ webplugin_ = new WebPluginProxy(
+ channel_, instance_id_, page_url_, params.containing_window);
delegate_ = WebPluginDelegateImpl::Create(path, mime_type_, parent);
if (delegate_) {
webplugin_->set_delegate(delegate_);
@@ -289,7 +285,7 @@ void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id,
// The stub will delete itself when the proxy tells it that it's released, or
// otherwise when the channel is closed.
new NPObjectStub(
- object, channel_.get(), *route_id, webplugin_->modal_dialog_event(),
+ object, channel_.get(), *route_id, webplugin_->containing_window(),
page_url_);
// Release ref added by GetPluginScriptableObject (our stub holds its own).
diff --git a/chrome/plugin/webplugin_delegate_stub.h b/chrome/plugin/webplugin_delegate_stub.h
index 9ad63d20..849066f 100644
--- a/chrome/plugin/webplugin_delegate_stub.h
+++ b/chrome/plugin/webplugin_delegate_stub.h
@@ -47,6 +47,7 @@ class WebPluginDelegateStub : public IPC::Channel::Listener,
virtual bool Send(IPC::Message* msg);
int instance_id() { return instance_id_; }
+ WebPluginProxy* webplugin() { return webplugin_; }
private:
// Message handlers for the WebPluginDelegate calls that are proxied from the
diff --git a/chrome/plugin/webplugin_proxy.cc b/chrome/plugin/webplugin_proxy.cc
index 0eb570a..ad0b1cb 100644
--- a/chrome/plugin/webplugin_proxy.cc
+++ b/chrome/plugin/webplugin_proxy.cc
@@ -17,7 +17,6 @@
#include "base/scoped_handle.h"
#include "base/shared_memory.h"
#include "base/singleton.h"
-#include "base/waitable_event.h"
#include "build/build_config.h"
#include "chrome/common/child_process_logging.h"
#include "chrome/common/plugin_messages.h"
@@ -46,7 +45,8 @@ static ContextMap& GetContextMap() {
WebPluginProxy::WebPluginProxy(
PluginChannel* channel,
int route_id,
- const GURL& page_url)
+ const GURL& page_url,
+ gfx::NativeViewId containing_window)
: channel_(channel),
route_id_(route_id),
cp_browsing_context_(0),
@@ -54,9 +54,9 @@ WebPluginProxy::WebPluginProxy(
plugin_element_(NULL),
delegate_(NULL),
waiting_for_paint_(false),
+ containing_window_(containing_window),
page_url_(page_url),
- ALLOW_THIS_IN_INITIALIZER_LIST(runnable_method_factory_(this))
-{
+ ALLOW_THIS_IN_INITIALIZER_LIST(runnable_method_factory_(this)) {
}
WebPluginProxy::~WebPluginProxy() {
@@ -95,27 +95,6 @@ void WebPluginProxy::SetWindowlessPumpEvent(HANDLE pump_messages_event) {
Send(new PluginHostMsg_SetWindowlessPumpEvent(
route_id_, pump_messages_event_for_renderer));
}
-
-bool WebPluginProxy::SetModalDialogEvent(HANDLE modal_dialog_event) {
- // TODO(port): figure out how this will be set in the browser process, or
- // come up with a different mechanism.
- HANDLE event = NULL;
- BOOL result = DuplicateHandle(channel_->renderer_handle(),
- modal_dialog_event,
- GetCurrentProcess(),
- &event,
- SYNCHRONIZE,
- FALSE,
- 0);
- DCHECK(result) <<
- "Couldn't duplicate the modal dialog handle for the plugin." \
- "handle: " << channel_->renderer_handle() << ". err: " << GetLastError();
- if (!event)
- return false;
-
- modal_dialog_event_.reset(new base::WaitableEvent(event));
- return true;
-}
#endif
void WebPluginProxy::CancelResource(int id) {
@@ -180,8 +159,7 @@ NPObject* WebPluginProxy::GetWindowScriptNPObject() {
return NULL;
window_npobject_ = NPObjectProxy::Create(
- channel_, npobject_route_id, npobject_ptr, modal_dialog_event_.get(),
- page_url_);
+ channel_, npobject_route_id, npobject_ptr, containing_window_, page_url_);
return window_npobject_;
}
@@ -199,8 +177,7 @@ NPObject* WebPluginProxy::GetPluginElement() {
return NULL;
plugin_element_ = NPObjectProxy::Create(
- channel_, npobject_route_id, npobject_ptr, modal_dialog_event_.get(),
- page_url_);
+ channel_, npobject_route_id, npobject_ptr, containing_window_, page_url_);
return plugin_element_;
}
@@ -226,13 +203,9 @@ void WebPluginProxy::ShowModalHTMLDialog(const GURL& url, int width, int height,
new PluginHostMsg_ShowModalHTMLDialog(
route_id_, url, width, height, json_arguments, json_retval);
- // Create a new event and set it. This forces us to pump messages while
- // waiting for a response (which won't come until the dialog is closed). This
- // avoids a deadlock.
- scoped_ptr<base::WaitableEvent> event(
- new base::WaitableEvent(false, true));
- msg->set_pump_messages_event(event.get());
-
+ // Pump messages while waiting for a response (which won't come until the
+ // dialog is closed). This avoids a deadlock.
+ msg->EnableMessagePumping();
Send(msg);
}
diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h
index 0ff1890..8f74109 100644
--- a/chrome/plugin/webplugin_proxy.h
+++ b/chrome/plugin/webplugin_proxy.h
@@ -23,11 +23,6 @@
#include "webkit/glue/webplugin.h"
class PluginChannel;
-
-namespace base {
-class WaitableEvent;
-}
-
class WebPluginDelegateImpl;
// This is an implementation of WebPlugin that proxies all calls to the
@@ -38,7 +33,8 @@ class WebPluginProxy : public webkit_glue::WebPlugin {
// marshalled WebPlugin calls.
WebPluginProxy(PluginChannel* channel,
int route_id,
- const GURL& page_url);
+ const GURL& page_url,
+ gfx::NativeViewId containing_window);
~WebPluginProxy();
void set_delegate(WebPluginDelegateImpl* d) { delegate_ = d; }
@@ -48,9 +44,8 @@ class WebPluginProxy : public webkit_glue::WebPlugin {
void WillDestroyWindow(gfx::PluginWindowHandle window);
#if defined(OS_WIN)
void SetWindowlessPumpEvent(HANDLE pump_messages_event);
- // Returns true on success.
- bool SetModalDialogEvent(HANDLE modal_dialog_event);
#endif
+
void CancelResource(int id);
void Invalidate();
void InvalidateRect(const gfx::Rect& rect);
@@ -127,9 +122,7 @@ class WebPluginProxy : public webkit_glue::WebPlugin {
void ResourceClientDeleted(
webkit_glue::WebPluginResourceClient* resource_client);
- base::WaitableEvent* modal_dialog_event() {
- return modal_dialog_event_.get();
- }
+ gfx::NativeViewId containing_window() { return containing_window_; }
private:
bool Send(IPC::Message* msg);
@@ -166,7 +159,7 @@ class WebPluginProxy : public webkit_glue::WebPlugin {
WebPluginDelegateImpl* delegate_;
gfx::Rect damaged_rect_;
bool waiting_for_paint_;
- scoped_ptr<base::WaitableEvent> modal_dialog_event_;
+ gfx::NativeViewId containing_window_;
// The url of the main frame hosting the plugin.
GURL page_url_;