diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-13 03:46:25 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-13 03:46:25 +0000 |
commit | 860ee64b0cabaae1acc8fd4277bf0ed81ae35425 (patch) | |
tree | b374df21914d967f3df72bf156248c91c398b082 /content | |
parent | 76321a195e76c58a533b97794430363f82c30854 (diff) | |
download | chromium_src-860ee64b0cabaae1acc8fd4277bf0ed81ae35425.zip chromium_src-860ee64b0cabaae1acc8fd4277bf0ed81ae35425.tar.gz chromium_src-860ee64b0cabaae1acc8fd4277bf0ed81ae35425.tar.bz2 |
Allow custom context menus to be requested.
This allows external users to request that a render view show a context menu. This mostly exposes is a reaonsable interface the existing functionality, and removes the pepper-plugin-delegate-specific hacks.
Review URL: https://codereview.chromium.org/11083002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@161703 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r-- | content/content_renderer.gypi | 1 | ||||
-rw-r--r-- | content/public/renderer/context_menu_client.h | 34 | ||||
-rw-r--r-- | content/public/renderer/render_view.h | 17 | ||||
-rw-r--r-- | content/public/renderer/render_view_observer.h | 1 | ||||
-rw-r--r-- | content/renderer/pepper/pepper_plugin_delegate_impl.cc | 70 | ||||
-rw-r--r-- | content/renderer/pepper/pepper_plugin_delegate_impl.h | 23 | ||||
-rw-r--r-- | content/renderer/render_view_impl.cc | 35 | ||||
-rw-r--r-- | content/renderer/render_view_impl.h | 19 |
8 files changed, 128 insertions, 72 deletions
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 5e482da..5fe6368 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -29,6 +29,7 @@ 'sources': [ 'public/renderer/content_renderer_client.cc', 'public/renderer/content_renderer_client.h', + 'public/renderer/context_menu_client.h', 'public/renderer/document_state.cc', 'public/renderer/document_state.h', 'public/renderer/navigation_state.cc', diff --git a/content/public/renderer/context_menu_client.h b/content/public/renderer/context_menu_client.h new file mode 100644 index 0000000..ceb10a0 --- /dev/null +++ b/content/public/renderer/context_menu_client.h @@ -0,0 +1,34 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_RENDERER_CONTEXT_MENU_CLIENT_H_ +#define CONTENT_PUBLIC_RENDERER_CONTEXT_MENU_CLIENT_H_ + +#include "base/basictypes.h" +#include "content/common/content_export.h" + +namespace content { + +// This mirrors the WebKit API in that the "action selected" and "menu closed" +// events are separate. When the user selects and item you'll get both events. +// If the user clicks somewhere else and cancels the menu, you'll just get the +// "closed" event. +class CONTENT_EXPORT ContextMenuClient { + public: + // Called when the user selects a context menu item. The request ID will be + // the value returned by RenderView.ShowCustomContextMenu. This will be + // followed by a call to OnCustomContextMenuClosed. + virtual void OnMenuAction(int request_id, unsigned action) = 0; + + // Called when the context menu is closed. The request ID will be the value + // returned by RenderView.ShowCustomContextMenu. + virtual void OnMenuClosed(int request_id) = 0; + + protected: + virtual ~ContextMenuClient() {} +}; + +} // namespace content + +#endif // CONTENT_PUBLIC_RENDERER_CONTEXT_MENU_CLIENT_H_ diff --git a/content/public/renderer/render_view.h b/content/public/renderer/render_view.h index 164acee..222119f 100644 --- a/content/public/renderer/render_view.h +++ b/content/public/renderer/render_view.h @@ -38,7 +38,9 @@ struct WebPluginInfo; namespace content { +class ContextMenuClient; class RenderViewVisitor; +struct ContextMenuParams; class CONTENT_EXPORT RenderView : public IPC::Sender { public: @@ -108,10 +110,17 @@ class CONTENT_EXPORT RenderView : public IPC::Sender { // Filtered time per frame based on UpdateRect messages. virtual float GetFilteredTimePerFrame() const = 0; - // Shows a context menu with commands relevant to a specific element on - // the given frame. Additional context data is supplied. - virtual void ShowContextMenu(WebKit::WebFrame* frame, - const WebKit::WebContextMenuData& data) = 0; + // Shows a context menu with the given information. The given client will + // be called with the result. The client pointer is owned by the caller and + // must remain valid as long as the RenderView is alive. + // + // The request ID will be returned by this function. This is passed to the + // client functions for identification. + // + // Note: if you end up having clients outliving the RenderView, we should add + // a CancelContextMenuCallback function that takes a request id. + virtual int ShowContextMenu(ContextMenuClient* client, + const ContextMenuParams& params) = 0; // Returns the current visibility of the WebView. virtual WebKit::WebPageVisibilityState GetVisibilityState() const = 0; diff --git a/content/public/renderer/render_view_observer.h b/content/public/renderer/render_view_observer.h index 84edd39..fd5ea95 100644 --- a/content/public/renderer/render_view_observer.h +++ b/content/public/renderer/render_view_observer.h @@ -90,7 +90,6 @@ class CONTENT_EXPORT RenderViewObserver : public IPC::Listener, virtual void DidCreatePepperPlugin(RendererPpapiHost* host) {} // These match incoming IPCs. - virtual void ContextMenuAction(unsigned id) {} virtual void Navigate(const GURL& url) {} virtual void ClosePage() {} diff --git a/content/renderer/pepper/pepper_plugin_delegate_impl.cc b/content/renderer/pepper/pepper_plugin_delegate_impl.cc index 694eefd..eddbf27 100644 --- a/content/renderer/pepper/pepper_plugin_delegate_impl.cc +++ b/content/renderer/pepper/pepper_plugin_delegate_impl.cc @@ -480,6 +480,31 @@ scoped_refptr<PepperBrokerImpl> PepperPluginDelegateImpl::CreateBroker( return broker; } +void PepperPluginDelegateImpl::OnMenuAction(int request_id, unsigned action) { + // Just save the action. + DCHECK(!has_saved_context_menu_action_); + has_saved_context_menu_action_ = true; + saved_context_menu_action_ = action; +} + +void PepperPluginDelegateImpl::OnMenuClosed(int request_id) { + PendingContextMenuMap::iterator found = + pending_context_menus_.find(request_id); + if (found == pending_context_menus_.end()) { + NOTREACHED() << "OnContextMenuClosed() called twice for the same menu."; + return; + } + + if (has_saved_context_menu_action_) { + found->second->CompleteShow(PP_OK, saved_context_menu_action_); + has_saved_context_menu_action_ = false; + saved_context_menu_action_ = 0; + } else { + found->second->CompleteShow(PP_ERROR_USERCANCEL, 0); + } + pending_context_menus_.erase(found); +} + void PepperPluginDelegateImpl::OnPpapiBrokerChannelCreated( int request_id, const IPC::ChannelHandle& handle) { @@ -1373,14 +1398,10 @@ int32_t PepperPluginDelegateImpl::ShowContextMenu( static_cast<RenderWidgetFullscreenPepper*>(container)->routing_id(); } - int request_id = pending_context_menus_.Add( - new scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl>(menu)); - ContextMenuParams params; params.x = position.x(); params.y = position.y(); params.custom_context.is_pepper_menu = true; - params.custom_context.request_id = request_id; params.custom_context.render_widget_id = render_widget_id; params.custom_items = menu->menu_data(); @@ -1395,47 +1416,12 @@ int32_t PepperPluginDelegateImpl::ShowContextMenu( params.y += instance->view_data().rect.point.y; } - IPC::Message* msg = new ViewHostMsg_ContextMenu(render_view_->routing_id(), - params); - if (!render_view_->Send(msg)) { - pending_context_menus_.Remove(request_id); - return PP_ERROR_FAILED; - } - + int request_id = render_view_->ShowContextMenu(this, params); + pending_context_menus_[request_id] = + scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl>(menu); return PP_OK_COMPLETIONPENDING; } -void PepperPluginDelegateImpl::OnContextMenuClosed( - const CustomContextMenuContext& custom_context) { - int request_id = custom_context.request_id; - scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl>* menu_ptr = - pending_context_menus_.Lookup(request_id); - if (!menu_ptr) { - NOTREACHED() << "CompleteShowContextMenu() called twice for the same menu."; - return; - } - scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl> menu = *menu_ptr; - DCHECK(menu.get()); - pending_context_menus_.Remove(request_id); - - if (has_saved_context_menu_action_) { - menu->CompleteShow(PP_OK, saved_context_menu_action_); - has_saved_context_menu_action_ = false; - saved_context_menu_action_ = 0; - } else { - menu->CompleteShow(PP_ERROR_USERCANCEL, 0); - } -} - -void PepperPluginDelegateImpl::OnCustomContextMenuAction( - const CustomContextMenuContext& custom_context, - unsigned action) { - // Just save the action. - DCHECK(!has_saved_context_menu_action_); - has_saved_context_menu_action_ = true; - saved_context_menu_action_ = action; -} - webkit::ppapi::FullscreenContainer* PepperPluginDelegateImpl::CreateFullscreenContainer( webkit::ppapi::PluginInstance* instance) { diff --git a/content/renderer/pepper/pepper_plugin_delegate_impl.h b/content/renderer/pepper/pepper_plugin_delegate_impl.h index c21ef21..653de6b 100644 --- a/content/renderer/pepper/pepper_plugin_delegate_impl.h +++ b/content/renderer/pepper/pepper_plugin_delegate_impl.h @@ -17,6 +17,7 @@ #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "content/common/content_export.h" +#include "content/public/renderer/context_menu_client.h" #include "content/public/renderer/render_view_observer.h" #include "content/renderer/mouse_lock_dispatcher.h" #include "content/renderer/pepper/pepper_parent_context_provider.h" @@ -66,7 +67,6 @@ struct WebCompositionUnderline; namespace content { -struct CustomContextMenuContext; class GamepadSharedMemoryReader; class PepperBrokerImpl; class PepperDeviceEnumerationEventHandler; @@ -76,7 +76,8 @@ class PepperPluginDelegateImpl : public webkit::ppapi::PluginDelegate, public base::SupportsWeakPtr<PepperPluginDelegateImpl>, public PepperParentContextProvider, - public RenderViewObserver { + public RenderViewObserver, + public ContextMenuClient { public: explicit PepperPluginDelegateImpl(RenderViewImpl* render_view); virtual ~PepperPluginDelegateImpl(); @@ -353,14 +354,6 @@ class PepperPluginDelegateImpl webkit::ppapi::PluginInstance* instance, webkit::ppapi::PPB_Flash_Menu_Impl* menu, const gfx::Point& position) OVERRIDE; - void OnContextMenuClosed( - const CustomContextMenuContext& custom_context); - void OnCustomContextMenuAction( - const CustomContextMenuContext& custom_context, - unsigned action); - void CompleteShowContextMenu(int request_id, - bool did_select, - unsigned action); virtual webkit::ppapi::FullscreenContainer* CreateFullscreenContainer( webkit::ppapi::PluginInstance* instance) OVERRIDE; @@ -471,6 +464,10 @@ class PepperPluginDelegateImpl scoped_refptr<PepperBrokerImpl> CreateBroker( webkit::ppapi::PluginModule* plugin_module); + // ContextMenuClient implementation. + virtual void OnMenuAction(int request_id, unsigned action) OVERRIDE; + virtual void OnMenuClosed(int request_id) OVERRIDE; + // Implementation of PepperParentContextProvider. virtual WebGraphicsContext3DCommandBufferImpl* GetParentContextForPlatformContext3D() OVERRIDE; @@ -504,8 +501,10 @@ class PepperPluginDelegateImpl IDMap<ppapi::PPB_HostResolver_Shared> host_resolvers_; - IDMap<scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl>, - IDMapOwnPointer> pending_context_menus_; + // Maps context menu request IDs to the menu resource to receive the result. + typedef std::map<int, scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl> > + PendingContextMenuMap; + PendingContextMenuMap pending_context_menus_; typedef IDMap<scoped_refptr<PepperBrokerImpl>, IDMapOwnPointer> BrokerMap; BrokerMap pending_connect_broker_; diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 906076e..b2eb191 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc @@ -4421,9 +4421,13 @@ float RenderViewImpl::GetFilteredTimePerFrame() const { return filtered_time_per_frame(); } -void RenderViewImpl::ShowContextMenu(WebKit::WebFrame* frame, - const WebKit::WebContextMenuData& data) { - showContextMenu(frame, data); +int RenderViewImpl::ShowContextMenu(content::ContextMenuClient* client, + const content::ContextMenuParams& params) { + DCHECK(client); // A null client means "internal" when we issue callbacks. + content::ContextMenuParams our_params(params); + our_params.custom_context.request_id = pending_context_menus_.Add(client); + Send(new ViewHostMsg_ContextMenu(routing_id_, our_params)); + return our_params.custom_context.request_id; } WebKit::WebPageVisibilityState RenderViewImpl::GetVisibilityState() const { @@ -5154,12 +5158,15 @@ void RenderViewImpl::OnSetAltErrorPageURL(const GURL& url) { void RenderViewImpl::OnCustomContextMenuAction( const content::CustomContextMenuContext& custom_context, unsigned action) { - if (custom_context.is_pepper_menu) - pepper_delegate_.OnCustomContextMenuAction(custom_context, action); - else + if (custom_context.request_id) { + // External context menu request, look in our map. + content::ContextMenuClient* client = + pending_context_menus_.Lookup(custom_context.request_id); + client->OnMenuAction(custom_context.request_id, action); + } else { + // Internal request, forward to WebKit. webview()->performCustomContextMenuAction(action); - FOR_EACH_OBSERVER(RenderViewObserver, observers_, - ContextMenuAction(action)); + } } void RenderViewImpl::OnEnumerateDirectoryResponse( @@ -6293,10 +6300,16 @@ void RenderViewImpl::OnSelectPopupMenuItems( void RenderViewImpl::OnContextMenuClosed( const content::CustomContextMenuContext& custom_context) { - if (custom_context.is_pepper_menu) - pepper_delegate_.OnContextMenuClosed(custom_context); - else + if (custom_context.request_id) { + // External request, should be in our map. + content::ContextMenuClient* client = + pending_context_menus_.Lookup(custom_context.request_id); + client->OnMenuClosed(custom_context.request_id); + pending_context_menus_.Remove(custom_context.request_id); + } else { + // Internal request, forward to WebKit. context_menu_node_.reset(); + } } void RenderViewImpl::OnEnableViewSourceMode() { diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index 1472670..2219c97 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h @@ -715,8 +715,9 @@ class RenderViewImpl : public RenderWidget, virtual int GetEnabledBindings() const OVERRIDE; virtual bool GetContentStateImmediately() const OVERRIDE; virtual float GetFilteredTimePerFrame() const OVERRIDE; - virtual void ShowContextMenu(WebKit::WebFrame* frame, - const WebKit::WebContextMenuData& data) OVERRIDE; + virtual int ShowContextMenu( + content::ContextMenuClient* client, + const content::ContextMenuParams& params) OVERRIDE; virtual WebKit::WebPageVisibilityState GetVisibilityState() const OVERRIDE; virtual void RunModalAlertDialog(WebKit::WebFrame* frame, const WebKit::WebString& message) OVERRIDE; @@ -1340,6 +1341,20 @@ class RenderViewImpl : public RenderWidget, size_t selection_text_offset_; ui::Range selection_range_; + // External context menu requests we're waiting for. "Internal" + // (WebKit-originated) context menu events will have an ID of 0 and will not + // be in this map. + // + // We don't want to add internal ones since some of the "special" page + // handlers in the browser process just ignore the context menu requests so + // avoid showing context menus, and so this will cause right clicks to leak + // entries in this map. Most users of the custom context menu (e.g. Pepper + // plugins) are normally only on "regular" pages and the regular pages will + // always respond properly to the request, so we don't have to worry so + // much about leaks. + IDMap<content::ContextMenuClient, IDMapExternalPointer> + pending_context_menus_; + // View ---------------------------------------------------------------------- // Cache the preferred size of the page in order to prevent sending the IPC |