diff options
-rw-r--r-- | chrome/browser/browser_uitest.cc | 2 | ||||
-rw-r--r-- | chrome/common/plugin_messages.h | 13 | ||||
-rw-r--r-- | chrome/common/plugin_messages_internal.h | 6 | ||||
-rw-r--r-- | chrome/plugin/npobject_proxy.cc | 72 | ||||
-rw-r--r-- | chrome/plugin/npobject_proxy.h | 12 | ||||
-rw-r--r-- | chrome/plugin/npobject_stub.cc | 18 | ||||
-rw-r--r-- | chrome/plugin/npobject_stub.h | 9 | ||||
-rw-r--r-- | chrome/plugin/npobject_util.cc | 8 | ||||
-rw-r--r-- | chrome/plugin/npobject_util.h | 8 | ||||
-rw-r--r-- | chrome/plugin/plugin_channel.cc | 121 | ||||
-rw-r--r-- | chrome/plugin/plugin_channel.h | 12 | ||||
-rw-r--r-- | chrome/plugin/plugin_channel_base.cc | 9 | ||||
-rw-r--r-- | chrome/plugin/plugin_channel_base.h | 5 | ||||
-rw-r--r-- | chrome/plugin/webplugin_delegate_stub.cc | 10 | ||||
-rw-r--r-- | chrome/plugin/webplugin_delegate_stub.h | 1 | ||||
-rw-r--r-- | chrome/plugin/webplugin_proxy.cc | 45 | ||||
-rw-r--r-- | chrome/plugin/webplugin_proxy.h | 17 | ||||
-rw-r--r-- | chrome/renderer/plugin_channel_host.h | 4 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 13 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 13 | ||||
-rw-r--r-- | chrome/renderer/webplugin_delegate_proxy.cc | 12 |
21 files changed, 245 insertions, 165 deletions
diff --git a/chrome/browser/browser_uitest.cc b/chrome/browser/browser_uitest.cc index 1ef62a1..0a3fee9 100644 --- a/chrome/browser/browser_uitest.cc +++ b/chrome/browser/browser_uitest.cc @@ -191,7 +191,6 @@ TEST_F(VisibleBrowserTest, WindowOpenClose) { } #endif -#if defined(OS_WIN) // only works on Windows for now: http:://crbug.com/15891 class ShowModalDialogTest : public UITest { public: ShowModalDialogTest() { @@ -221,7 +220,6 @@ TEST_F(ShowModalDialogTest, BasicTest) { ASSERT_TRUE(tab->GetTabTitle(&title)); ASSERT_EQ(L"SUCCESS", title); } -#endif class SecurityTest : public UITest { protected: diff --git a/chrome/common/plugin_messages.h b/chrome/common/plugin_messages.h index 142450c..d507882 100644 --- a/chrome/common/plugin_messages.h +++ b/chrome/common/plugin_messages.h @@ -37,9 +37,6 @@ struct PluginMsg_Init_Params { GURL page_url; std::vector<std::string> arg_names; std::vector<std::string> arg_values; -#if defined(OS_WIN) - HANDLE modal_dialog_event; -#endif bool load_manually; }; @@ -123,9 +120,6 @@ struct ParamTraits<PluginMsg_Init_Params> { DCHECK(p.arg_names.size() == p.arg_values.size()); WriteParam(m, p.arg_names); WriteParam(m, p.arg_values); -#if defined(OS_WIN) - WriteParam(m, p.modal_dialog_event); -#endif WriteParam(m, p.load_manually); } static bool Read(const Message* m, void** iter, param_type* p) { @@ -134,9 +128,6 @@ struct ParamTraits<PluginMsg_Init_Params> { ReadParam(m, iter, &p->page_url) && ReadParam(m, iter, &p->arg_names) && ReadParam(m, iter, &p->arg_values) && -#if defined(OS_WIN) - ReadParam(m, iter, &p->modal_dialog_event) && -#endif ReadParam(m, iter, &p->load_manually); } static void Log(const param_type& p, std::wstring* l) { @@ -151,10 +142,6 @@ struct ParamTraits<PluginMsg_Init_Params> { l->append(L", "); LogParam(p.arg_values, l); l->append(L", "); -#if defined(OS_WIN) - LogParam(p.modal_dialog_event, l); - l->append(L", "); -#endif LogParam(p.load_manually, l); l->append(L")"); } diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h index 9049fa7..f03cf97 100644 --- a/chrome/common/plugin_messages_internal.h +++ b/chrome/common/plugin_messages_internal.h @@ -227,6 +227,12 @@ IPC_BEGIN_MESSAGES(Plugin) IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_HandleURLRequestReply, PluginMsg_URLRequestReply_Params) + + IPC_MESSAGE_CONTROL1(PluginMsg_SignalModalDialogEvent, + gfx::NativeViewId /* containing_window */) + + IPC_MESSAGE_CONTROL1(PluginMsg_ResetModalDialogEvent, + gfx::NativeViewId /* containing_window */) IPC_END_MESSAGES(Plugin) 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, ¶m, false, proxy->modal_dialog_event_, + args[i], channel_copy, ¶m, 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, ¶m, false, proxy->modal_dialog_event_, + args[i], channel_copy, ¶m, 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, ¶m_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_; diff --git a/chrome/renderer/plugin_channel_host.h b/chrome/renderer/plugin_channel_host.h index 8d27f9a..f3d066b 100644 --- a/chrome/renderer/plugin_channel_host.h +++ b/chrome/renderer/plugin_channel_host.h @@ -33,6 +33,10 @@ class PluginChannelHost : public PluginChannelBase { static bool IsListening(); + static void Broadcast(IPC::Message* message) { + PluginChannelBase::Broadcast(message); + } + private: // Called on the render thread PluginChannelHost(); diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 231cfa7..66ac3bf 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -29,6 +29,7 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/jstemplate_builder.h" #include "chrome/common/page_zoom.h" +#include "chrome/common/plugin_messages.h" #include "chrome/common/render_messages.h" #include "chrome/common/renderer_preferences.h" #include "chrome/common/thumbnail_score.h" @@ -44,6 +45,7 @@ #include "chrome/renderer/localized_error.h" #include "chrome/renderer/media/audio_renderer_impl.h" #include "chrome/renderer/navigation_state.h" +#include "chrome/renderer/plugin_channel_host.h" #include "chrome/renderer/print_web_view_helper.h" #include "chrome/renderer/render_process.h" #include "chrome/renderer/user_script_slave.h" @@ -208,7 +210,6 @@ RenderView::RenderView(RenderThreadBase* render_thread, last_indexed_page_id_(-1), opened_by_user_gesture_(true), ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), - modal_dialog_count_(0), devtools_agent_(NULL), devtools_client_(NULL), history_back_list_count_(0), @@ -230,8 +231,6 @@ RenderView::RenderView(RenderThreadBase* render_thread, document_tag_(0), webkit_preferences_(webkit_preferences) { Singleton<RenderViewSet>()->render_view_set_.insert(this); - - modal_dialog_event_.reset(new base::WaitableEvent(true, false)); } RenderView::~RenderView() { @@ -3573,14 +3572,14 @@ void RenderView::EnsureDocumentTag() { } bool RenderView::SendAndRunNestedMessageLoop(IPC::SyncMessage* message) { - if (modal_dialog_count_++ == 0) - modal_dialog_event_->Signal(); + PluginChannelHost::Broadcast( + new PluginMsg_SignalModalDialogEvent(host_window_)); message->EnableMessagePumping(); // Runs a nested message loop. bool rv = Send(message); - if (--modal_dialog_count_ == 0) - modal_dialog_event_->Reset(); + PluginChannelHost::Broadcast( + new PluginMsg_ResetModalDialogEvent(host_window_)); return rv; } diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index fd8c981..decad59 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -140,10 +140,6 @@ class RenderView : public RenderWidget, return host_window_; } - base::WaitableEvent* modal_dialog_event() { - return modal_dialog_event_.get(); - } - int browser_window_id() { return browser_window_id_; } @@ -819,15 +815,6 @@ class RenderView : public RenderWidget, // recent message if new ones come in). scoped_ptr<IPC::Message> queued_find_reply_message_; - // Handle to an event that's set when the page is showing a modal dialog (or - // equivalent constrained window). The renderer and any plugin processes - // check this to know if they should pump messages/tasks then. - scoped_ptr<base::WaitableEvent> modal_dialog_event_; - - // Multiple dialog boxes can be shown before the first one is finished, - // so we keep a counter to know when we can reset the modal dialog event. - int modal_dialog_count_; - // Provides access to this renderer from the remote Inspector UI. scoped_ptr<DevToolsAgent> devtools_agent_; diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc index 4c5e54e..cdf5720 100644 --- a/chrome/renderer/webplugin_delegate_proxy.cc +++ b/chrome/renderer/webplugin_delegate_proxy.cc @@ -271,9 +271,6 @@ bool WebPluginDelegateProxy::Initialize(const GURL& url, } } params.load_manually = load_manually; -#if defined(OS_WIN) - params.modal_dialog_event = render_view_->modal_dialog_event()->handle(); -#endif plugin_ = plugin; @@ -746,8 +743,7 @@ NPObject* WebPluginDelegateProxy::GetPluginScriptableObject() { return NULL; npobject_ = NPObjectProxy::Create( - channel_host_.get(), route_id, npobject_ptr, - render_view_->modal_dialog_event(), page_url_); + channel_host_.get(), route_id, npobject_ptr, 0, page_url_); return WebBindings::retainObject(npobject_); } @@ -833,8 +829,7 @@ void WebPluginDelegateProxy::OnGetWindowScriptNPObject( // The stub will delete itself when the proxy tells it that it's released, or // otherwise when the channel is closed. NPObjectStub* stub = new NPObjectStub( - npobject, channel_host_.get(), route_id, - render_view_->modal_dialog_event(), page_url_); + npobject, channel_host_.get(), route_id, 0, page_url_); window_script_object_ = stub; window_script_object_->set_proxy(this); *success = true; @@ -853,8 +848,7 @@ void WebPluginDelegateProxy::OnGetPluginElement( // The stub will delete itself when the proxy tells it that it's released, or // otherwise when the channel is closed. new NPObjectStub( - npobject, channel_host_.get(), route_id, - render_view_->modal_dialog_event(), page_url_); + npobject, channel_host_.get(), route_id, 0, page_url_); *success = true; *npobject_ptr = reinterpret_cast<intptr_t>(npobject); } |