summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-13 03:46:25 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-13 03:46:25 +0000
commit860ee64b0cabaae1acc8fd4277bf0ed81ae35425 (patch)
treeb374df21914d967f3df72bf156248c91c398b082 /content
parent76321a195e76c58a533b97794430363f82c30854 (diff)
downloadchromium_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.gypi1
-rw-r--r--content/public/renderer/context_menu_client.h34
-rw-r--r--content/public/renderer/render_view.h17
-rw-r--r--content/public/renderer/render_view_observer.h1
-rw-r--r--content/renderer/pepper/pepper_plugin_delegate_impl.cc70
-rw-r--r--content/renderer/pepper/pepper_plugin_delegate_impl.h23
-rw-r--r--content/renderer/render_view_impl.cc35
-rw-r--r--content/renderer/render_view_impl.h19
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