0

Context menus should appear above the touch point if invoked by long press.

This CL does this for content area context menus only. I will send out another CL for same functionality on views controls.
We acheive this as follows: We remember in render_widget_host, which kind of
event is currently in process. When we get a request for showing context menu,
in render_view_host, we check if currently we are processing a gesture event,
and if so, we display the context menu appropriately.

BUG=142015
TEST=manual

Review URL: https://chromiumcodereview.appspot.com/10917102

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@155306 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
varunjain@chromium.org
2012-09-07 04:14:52 +00:00
parent e9029bbe94
commit ba16e3a2fb
39 changed files with 129 additions and 44 deletions

@ -26,7 +26,8 @@ ChromeWebContentsViewDelegateAndroid::GetDragDestDelegate() {
}
void ChromeWebContentsViewDelegateAndroid::ShowContextMenu(
const content::ContextMenuParams& params) {
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) {
// http://crbug.com/136075
NOTIMPLEMENTED();
// Still lacking some code here that depends on

@ -24,7 +24,8 @@ class ChromeWebContentsViewDelegateAndroid
// WebContentsViewDelegate:
virtual void ShowContextMenu(
const content::ContextMenuParams& params) OVERRIDE;
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) OVERRIDE;
// WebContentsViewDelegate:
virtual content::WebDragDestDelegate* GetDragDestDelegate() OVERRIDE;

@ -32,7 +32,8 @@ class ChromeWebContentsViewDelegateMac
content::RenderWidgetHost* render_widget_host) OVERRIDE;
virtual content::WebDragDestDelegate* GetDragDestDelegate() OVERRIDE;
virtual void ShowContextMenu(
const content::ContextMenuParams& params) OVERRIDE;
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) OVERRIDE;
private:
// The context menu. Callbacks are asynchronous so we need to keep it around.

@ -33,7 +33,8 @@ content::WebDragDestDelegate*
}
void ChromeWebContentsViewDelegateMac::ShowContextMenu(
const content::ContextMenuParams& params) {
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) {
// The renderer may send the "show context menu" message multiple times, one
// for each right click mouse event it receives. Normally, this doesn't happen
// because mouse events are not forwarded once the context menu is showing.

@ -116,7 +116,8 @@ gboolean ChromeWebContentsViewDelegateGtk::OnNativeViewFocusEvent(
}
void ChromeWebContentsViewDelegateGtk::ShowContextMenu(
const content::ContextMenuParams& params) {
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) {
// Find out the RenderWidgetHostView that corresponds to the render widget on
// which this context menu is showed, so that we can retrieve the last mouse
// down event on the render widget and use it as the timestamp of the

@ -40,7 +40,8 @@ class ChromeWebContentsViewDelegateGtk
// Overridden from WebContentsViewDelegate:
virtual void ShowContextMenu(
const content::ContextMenuParams& params) OVERRIDE;
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) OVERRIDE;
virtual content::WebDragDestDelegate* GetDragDestDelegate() OVERRIDE;
virtual void Initialize(GtkWidget* expanded_container,
ui::FocusStoreGtk* focus_store) OVERRIDE;

@ -123,7 +123,8 @@ void ChromeWebContentsViewDelegateViews::RestoreFocus() {
}
void ChromeWebContentsViewDelegateViews::ShowContextMenu(
const content::ContextMenuParams& params) {
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) {
context_menu_.reset(
RenderViewContextMenuViews::Create(web_contents_, params));
context_menu_->Init();
@ -152,7 +153,7 @@ void ChromeWebContentsViewDelegateViews::ShowContextMenu(
// Enable recursive tasks on the message loop so we can get updates while
// the context menu is being displayed.
MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
context_menu_->RunMenuAt(GetTopLevelWidget(), screen_point);
context_menu_->RunMenuAt(GetTopLevelWidget(), screen_point, type);
}
void ChromeWebContentsViewDelegateViews::SizeChanged(const gfx::Size& size) {

@ -39,7 +39,8 @@ class ChromeWebContentsViewDelegateViews
virtual bool Focus() OVERRIDE;
virtual void TakeFocus(bool reverse) OVERRIDE;
virtual void ShowContextMenu(
const content::ContextMenuParams& params) OVERRIDE;
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) OVERRIDE;
virtual void SizeChanged(const gfx::Size& size) OVERRIDE;
private:

@ -42,10 +42,15 @@ RenderViewContextMenuViews* RenderViewContextMenuViews::Create(
}
#endif // OS_WIN
void RenderViewContextMenuViews::RunMenuAt(views::Widget* parent,
const gfx::Point& point) {
void RenderViewContextMenuViews::RunMenuAt(
views::Widget* parent,
const gfx::Point& point,
const content::ContextMenuSourceType& type) {
views::MenuItemView::AnchorPosition anchor_position =
type == content::CONTEXT_MENU_SOURCE_TOUCH ?
views::MenuItemView::BOTTOMCENTER : views::MenuItemView::TOPLEFT;
if (menu_runner_->RunMenuAt(parent, NULL, gfx::Rect(point, gfx::Size()),
views::MenuItemView::TOPLEFT, views::MenuRunner::HAS_MNEMONICS |
anchor_position, views::MenuRunner::HAS_MNEMONICS |
views::MenuRunner::CONTEXT_MENU) ==
views::MenuRunner::MENU_DELETED)
return;

@ -9,6 +9,7 @@
#include "base/memory/scoped_vector.h"
#include "base/string16.h"
#include "chrome/browser/tab_contents/render_view_context_menu.h"
#include "content/public/common/context_menu_source_type.h"
namespace gfx {
class Point;
@ -30,7 +31,9 @@ class RenderViewContextMenuViews : public RenderViewContextMenu {
content::WebContents* tab_contents,
const content::ContextMenuParams& params);
void RunMenuAt(views::Widget* parent, const gfx::Point& point);
void RunMenuAt(views::Widget* parent,
const gfx::Point& point,
const content::ContextMenuSourceType& type);
void UpdateMenuItemStates();

@ -13,6 +13,7 @@
#include "base/process_util.h"
#include "base/string16.h"
#include "content/common/content_export.h"
#include "content/public/common/context_menu_source_type.h"
#include "content/public/common/javascript_message_type.h"
#include "content/public/common/media_stream_request.h"
#include "net/base/load_states.h"
@ -404,7 +405,8 @@ class CONTENT_EXPORT RenderViewHostDelegate {
// A context menu should be shown, to be built using the context information
// provided in the supplied params.
virtual void ShowContextMenu(const ContextMenuParams& params) {}
virtual void ShowContextMenu(const ContextMenuParams& params,
const ContextMenuSourceType& type) {}
// The render view has requested access to media devices listed in
// |request|, and the client should grant or deny that permission by

@ -53,6 +53,7 @@
#include "content/public/common/content_constants.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/context_menu_params.h"
#include "content/public/common/context_menu_source_type.h"
#include "content/public/common/result_codes.h"
#include "content/public/common/url_constants.h"
#include "net/base/net_util.h"
@ -1253,7 +1254,15 @@ void RenderViewHostImpl::OnMsgContextMenu(
FilterURL(policy, renderer_id, false, &validated_params.page_url);
FilterURL(policy, renderer_id, true, &validated_params.frame_url);
delegate_->ShowContextMenu(validated_params);
content::ContextMenuSourceType type = content::CONTEXT_MENU_SOURCE_MOUSE;
if (!in_process_event_types_.empty()) {
WebKit::WebInputEvent::Type event_type = in_process_event_types_.front();
if (WebKit::WebInputEvent::isGestureEventType(event_type))
type = content::CONTEXT_MENU_SOURCE_TOUCH;
else if (WebKit::WebInputEvent::isKeyboardEventType(event_type))
type = content::CONTEXT_MENU_SOURCE_KEYBOARD;
}
delegate_->ShowContextMenu(validated_params, type);
}
void RenderViewHostImpl::OnMsgToggleFullscreen(bool enter_fullscreen) {

@ -83,7 +83,8 @@ class MockDraggingRenderViewHostDelegateView
public:
virtual ~MockDraggingRenderViewHostDelegateView() {}
virtual void ShowContextMenu(
const content::ContextMenuParams& params) OVERRIDE {}
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) OVERRIDE {}
virtual void ShowPopupMenu(const gfx::Rect& bounds,
int item_height,
double item_font_size,

@ -1016,6 +1016,8 @@ void RenderWidgetHostImpl::ForwardInputEvent(const WebInputEvent& input_event,
DCHECK(!process_->IgnoreInputEvents());
in_process_event_types_.push(input_event.type);
IPC::Message* message = new ViewMsg_HandleInputEvent(routing_id_);
message->WriteData(
reinterpret_cast<const char*>(&input_event), event_size);
@ -1534,6 +1536,9 @@ void RenderWidgetHostImpl::DidUpdateBackingStore(
void RenderWidgetHostImpl::OnMsgInputEventAck(WebInputEvent::Type event_type,
bool processed) {
TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::OnMsgInputEventAck");
if (!in_process_event_types_.empty() &&
in_process_event_types_.front() == event_type)
in_process_event_types_.pop();
// Log the time delta for processing an input event.
TimeDelta delta = TimeTicks::Now() - input_event_start_time_;

@ -7,6 +7,7 @@
#include <deque>
#include <map>
#include <queue>
#include <string>
#include <vector>
@ -490,6 +491,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost,
// This value indicates how long to wait before we consider a renderer hung.
int hung_renderer_delay_ms_;
std::queue<WebKit::WebInputEvent::Type> in_process_event_types_;
private:
friend class ::MockRenderWidgetHost;

@ -675,7 +675,8 @@ void InterstitialPageImpl::ShowCreatedFullscreenWidget(int route_id) {
}
void InterstitialPageImpl::ShowContextMenu(
const content::ContextMenuParams& params) {
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) {
}
void InterstitialPageImpl::Disable() {

@ -113,7 +113,8 @@ class CONTENT_EXPORT InterstitialPageImpl
const gfx::Rect& initial_pos) OVERRIDE;
virtual void ShowCreatedFullscreenWidget(int route_id) OVERRIDE;
virtual void ShowContextMenu(
const content::ContextMenuParams& params) OVERRIDE;
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) OVERRIDE;
// RenderWidgetHostDelegate implementation:
virtual bool PreHandleKeyboardEvent(

@ -1425,12 +1425,13 @@ RenderWidgetHostView* WebContentsImpl::GetCreatedWidget(int route_id) {
}
void WebContentsImpl::ShowContextMenu(
const content::ContextMenuParams& params) {
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) {
// Allow WebContentsDelegates to handle the context menu operation first.
if (delegate_ && delegate_->HandleContextMenu(params))
return;
render_view_host_delegate_view_->ShowContextMenu(params);
render_view_host_delegate_view_->ShowContextMenu(params, type);
}
void WebContentsImpl::RequestMediaAccessPermission(

@ -406,7 +406,8 @@ class CONTENT_EXPORT WebContentsImpl
const gfx::Rect& initial_pos) OVERRIDE;
virtual void ShowCreatedFullscreenWidget(int route_id) OVERRIDE;
virtual void ShowContextMenu(
const content::ContextMenuParams& params) OVERRIDE;
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) OVERRIDE;
virtual void RequestMediaAccessPermission(
const content::MediaStreamRequest* request,
const content::MediaResponseCallback& callback) OVERRIDE;

@ -158,9 +158,11 @@ gfx::Rect WebContentsViewAndroid::GetViewBounds() const {
return gfx::Rect();
}
void WebContentsViewAndroid::ShowContextMenu(const ContextMenuParams& params) {
void WebContentsViewAndroid::ShowContextMenu(
const ContextMenuParams& params,
const content::ContextMenuSourceType& type) {
if (delegate_.get())
delegate_->ShowContextMenu(params);
delegate_->ShowContextMenu(params, type);
}
void WebContentsViewAndroid::ShowPopupMenu(

@ -54,7 +54,9 @@ class WebContentsViewAndroid : public WebContentsView,
virtual gfx::Rect GetViewBounds() const OVERRIDE;
// Backend implementation of RenderViewHostDelegateView.
virtual void ShowContextMenu(const ContextMenuParams& params) OVERRIDE;
virtual void ShowContextMenu(
const ContextMenuParams& params,
const content::ContextMenuSourceType& type) OVERRIDE;
virtual void ShowPopupMenu(const gfx::Rect& bounds,
int item_height,
double item_font_size,

@ -405,9 +405,10 @@ gfx::Rect WebContentsViewAura::GetViewBounds() const {
// WebContentsViewAura, RenderViewHostDelegateView implementation:
void WebContentsViewAura::ShowContextMenu(
const content::ContextMenuParams& params) {
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) {
if (delegate_.get())
delegate_->ShowContextMenu(params);
delegate_->ShowContextMenu(params, type);
}
void WebContentsViewAura::ShowPopupMenu(const gfx::Rect& bounds,

@ -72,7 +72,8 @@ class CONTENT_EXPORT WebContentsViewAura
// Overridden from RenderViewHostDelegateView:
virtual void ShowContextMenu(
const content::ContextMenuParams& params) OVERRIDE;
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) OVERRIDE;
virtual void ShowPopupMenu(const gfx::Rect& bounds,
int item_height,
double item_font_size,

@ -328,9 +328,10 @@ gboolean WebContentsViewGtk::OnFocus(GtkWidget* widget,
}
void WebContentsViewGtk::ShowContextMenu(
const content::ContextMenuParams& params) {
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) {
if (delegate_.get())
delegate_->ShowContextMenu(params);
delegate_->ShowContextMenu(params, type);
else
DLOG(ERROR) << "Cannot show context menus without a delegate.";
}

@ -71,7 +71,8 @@ class CONTENT_EXPORT WebContentsViewGtk
// Backend implementation of RenderViewHostDelegateView.
virtual void ShowContextMenu(
const content::ContextMenuParams& params) OVERRIDE;
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) OVERRIDE;
virtual void ShowPopupMenu(const gfx::Rect& bounds,
int item_height,
double item_font_size,

@ -87,7 +87,8 @@ class WebContentsViewMac
// Backend implementation of RenderViewHostDelegateView.
virtual void ShowContextMenu(
const content::ContextMenuParams& params) OVERRIDE;
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) OVERRIDE;
virtual void ShowPopupMenu(const gfx::Rect& bounds,
int item_height,
double item_font_size,

@ -281,7 +281,8 @@ void WebContentsViewMac::TakeFocus(bool reverse) {
}
void WebContentsViewMac::ShowContextMenu(
const content::ContextMenuParams& params) {
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) {
// Allow delegates to handle the context menu operation first.
if (web_contents_->GetDelegate() &&
web_contents_->GetDelegate()->HandleContextMenu(params)) {
@ -289,7 +290,7 @@ void WebContentsViewMac::ShowContextMenu(
}
if (delegate())
delegate()->ShowContextMenu(params);
delegate()->ShowContextMenu(params, type);
else
DLOG(ERROR) << "Cannot show context menus without a delegate.";
}

@ -264,9 +264,10 @@ gfx::Rect WebContentsViewWin::GetViewBounds() const {
}
void WebContentsViewWin::ShowContextMenu(
const content::ContextMenuParams& params) {
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) {
if (delegate_.get())
delegate_->ShowContextMenu(params);
delegate_->ShowContextMenu(params, type);
}
void WebContentsViewWin::ShowPopupMenu(const gfx::Rect& bounds,

@ -80,7 +80,8 @@ class CONTENT_EXPORT WebContentsViewWin
// Implementation of RenderViewHostDelegateView.
virtual void ShowContextMenu(
const content::ContextMenuParams& params) OVERRIDE;
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) OVERRIDE;
virtual void ShowPopupMenu(const gfx::Rect& bounds,
int item_height,
double item_font_size,

@ -47,6 +47,7 @@
'public/common/content_switches.h',
'public/common/context_menu_params.cc',
'public/common/context_menu_params.h',
'public/common/context_menu_source_type.h',
'public/common/console_message_level.h',
'public/common/dx_diag_node.cc',
'public/common/dx_diag_node.h',

@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "content/common/content_export.h"
#include "content/public/common/context_menu_source_type.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragOperation.h"
class SkBitmap;
@ -32,7 +33,8 @@ class CONTENT_EXPORT RenderViewHostDelegateView {
public:
// A context menu should be shown, to be built using the context information
// provided in the supplied params.
virtual void ShowContextMenu(const ContextMenuParams& params) {}
virtual void ShowContextMenu(const ContextMenuParams& params,
const ContextMenuSourceType& type) {}
// Shows a popup menu with the specified items.
// This method should call RenderViewHost::DidSelectPopupMenuItem[s]() or

@ -12,6 +12,7 @@
#endif
#include "content/common/content_export.h"
#include "content/public/common/context_menu_source_type.h"
#include "ui/gfx/native_widget_types.h"
#if defined(OS_MACOSX)
@ -42,7 +43,9 @@ class CONTENT_EXPORT WebContentsViewDelegate {
virtual WebDragDestDelegate* GetDragDestDelegate() = 0;
// Shows a context menu.
virtual void ShowContextMenu(const content::ContextMenuParams& params) = 0;
virtual void ShowContextMenu(
const content::ContextMenuParams& params,
const content::ContextMenuSourceType& type) = 0;
#if defined(OS_WIN) || defined(USE_AURA)
// These methods allow the embedder to intercept WebContentsViewWin's

@ -0,0 +1,18 @@
// 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_COMMON_CONTEXT_MENU_SOURCE_TYPE_H_
#define CONTENT_PUBLIC_COMMON_CONTEXT_MENU_SOURCE_TYPE_H_
namespace content {
enum ContextMenuSourceType {
CONTEXT_MENU_SOURCE_MOUSE,
CONTEXT_MENU_SOURCE_KEYBOARD,
CONTEXT_MENU_SOURCE_TOUCH,
};
} // namespace content
#endif // CONTENT_PUBLIC_COMMON_CONTEXT_MENU_SOURCE_TYPE_H_

@ -8,6 +8,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view_delegate.h"
#include "content/public/common/context_menu_params.h"
#include "content/public/common/context_menu_source_type.h"
#if defined(TOOLKIT_GTK)
#include "ui/base/gtk/gtk_signal.h"
@ -22,8 +23,8 @@ class ShellWebContentsViewDelegate : public WebContentsViewDelegate {
virtual ~ShellWebContentsViewDelegate();
// Overridden from WebContentsViewDelegate:
virtual void ShowContextMenu(
const ContextMenuParams& params) OVERRIDE;
virtual void ShowContextMenu(const ContextMenuParams& params,
const ContextMenuSourceType& type) OVERRIDE;
virtual WebDragDestDelegate* GetDragDestDelegate() OVERRIDE;
#if defined(TOOLKIT_GTK)

@ -41,7 +41,8 @@ ShellWebContentsViewDelegate::~ShellWebContentsViewDelegate() {
}
void ShellWebContentsViewDelegate::ShowContextMenu(
const ContextMenuParams& params) {
const ContextMenuParams& params,
const ContextMenuSourceType& type) {
GtkWidget* menu = gtk_menu_new();
params_ = params;

@ -13,7 +13,8 @@ TestWebContentsView::~TestWebContentsView() {
}
void TestWebContentsView::ShowContextMenu(
const ContextMenuParams& params) {
const ContextMenuParams& params,
const content::ContextMenuSourceType& type) {
}
void TestWebContentsView::ShowPopupMenu(const gfx::Rect& bounds,

@ -18,7 +18,9 @@ class TestWebContentsView : public WebContentsView,
virtual ~TestWebContentsView();
// RenderViewHostDelegateView:
virtual void ShowContextMenu(const ContextMenuParams& params) OVERRIDE;
virtual void ShowContextMenu(
const ContextMenuParams& params,
const content::ContextMenuSourceType& type) OVERRIDE;
virtual void ShowPopupMenu(const gfx::Rect& bounds,
int item_height,
double item_font_size,

@ -1564,6 +1564,9 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
x = x + state_.initial_bounds.width() - pref.width();
if (MenuConfig::instance().offset_context_menus && state_.context_menu)
x -= 1;
} else if (state_.anchor == MenuItemView::BOTTOMCENTER) {
x = x - (pref.width() - state_.initial_bounds.width()) / 2;
y = std::max(0, state_.initial_bounds.y() - pref.height());
}
if (!state_.monitor_bounds.IsEmpty() &&

@ -91,7 +91,8 @@ class VIEWS_EXPORT MenuItemView : public View {
// opposite position will be used if base::i18n:IsRTL() is true.
enum AnchorPosition {
TOPLEFT,
TOPRIGHT
TOPRIGHT,
BOTTOMCENTER
};
// Where the menu should be drawn, above or below the bounds (when