summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorvarunjain@chromium.org <varunjain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-23 17:22:36 +0000
committervarunjain@chromium.org <varunjain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-23 17:22:36 +0000
commit47822260423f1b6195260dc06ce1a96e5daf291c (patch)
treebb5c187edda4695d2d586074a00b22bf003797ea /content
parentfad1a9fad3803f2c1e33b6df4b23383f012ee682 (diff)
downloadchromium_src-47822260423f1b6195260dc06ce1a96e5daf291c.zip
chromium_src-47822260423f1b6195260dc06ce1a96e5daf291c.tar.gz
chromium_src-47822260423f1b6195260dc06ce1a96e5daf291c.tar.bz2
Reland r195688 which was reverted due to build break.
There are two changes from the original CL: 1. In RenderWidgetHostViewAura::OnWindowFocused, update touch_editing_client_ before host->Shutdown. 2. Patched in r195696 to fix win_aura build BUG=115237 TBR=jam@chromium.org,tsepez@chromium.org Review URL: https://chromiumcodereview.appspot.com/13999010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@195823 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/DEPS1
-rw-r--r--content/browser/renderer_host/render_process_host_impl.cc1
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.cc3
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.cc41
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.h40
-rw-r--r--content/browser/renderer_host/render_widget_host_view_base.cc3
-rw-r--r--content/browser/renderer_host/render_widget_host_view_base.h1
-rw-r--r--content/browser/web_contents/touch_editable_impl_aura.cc314
-rw-r--r--content/browser/web_contents/touch_editable_impl_aura.h95
-rw-r--r--content/browser/web_contents/touch_editable_impl_aura_browsertest.cc284
-rw-r--r--content/browser/web_contents/web_contents_view_aura.cc28
-rw-r--r--content/browser/web_contents/web_contents_view_aura.h7
-rw-r--r--content/common/view_messages.h3
-rw-r--r--content/content_browser.gypi5
-rw-r--r--content/content_tests.gypi6
-rw-r--r--content/port/browser/render_widget_host_view_port.h2
-rw-r--r--content/renderer/render_view_impl.cc10
-rw-r--r--content/renderer/render_view_impl.h1
-rw-r--r--content/test/data/touch_selection.html35
19 files changed, 878 insertions, 2 deletions
diff --git a/content/DEPS b/content/DEPS
index 79b961e..71d3a15 100644
--- a/content/DEPS
+++ b/content/DEPS
@@ -20,6 +20,7 @@ include_rules = [
"+crypto",
"+grit/content_resources.h",
"+grit/ui_resources.h",
+ "+grit/ui_strings.h",
"+grit/webkit_chromium_resources.h",
"+grit/webkit_resources.h",
"+grit/webkit_strings.h",
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 7680ddb..b928052 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -870,6 +870,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kDisableCompositingForFixedPosition,
switches::kEnableAcceleratedPainting,
switches::kEnableTouchDragDrop,
+ switches::kEnableTouchEditing,
switches::kDisableThreadedCompositing,
switches::kDisableTouchAdjustment,
switches::kDefaultTileWidth,
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 395bd1b..2bb3c5d 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1982,6 +1982,9 @@ void RenderWidgetHostImpl::ProcessGestureAck(bool processed, int type) {
gesture_event_filter_->GetGestureEventAwaitingAck(), processed);
}
gesture_event_filter_->ProcessGestureAck(processed, type);
+
+ if (view_)
+ view_->GestureEventAck(type);
}
void RenderWidgetHostImpl::ProcessTouchAck(InputEventAckState ack_result) {
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 27a81b9..aaf1cac 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -629,7 +629,8 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host)
accelerated_compositing_state_changed_(false),
can_lock_compositor_(YES),
paint_observer_(NULL),
- accessible_parent_(NULL) {
+ accessible_parent_(NULL),
+ touch_editing_client_(NULL) {
host_->SetView(this);
window_observer_.reset(new WindowObserver(this));
aura::client::SetTooltipText(window_, &tooltip_);
@@ -791,6 +792,10 @@ void RenderWidgetHostViewAura::SetBounds(const gfx::Rect& rect) {
}
window_->SetBounds(rect);
host_->WasResized();
+ if (touch_editing_client_) {
+ touch_editing_client_->OnSelectionOrCursorChanged(selection_anchor_rect_,
+ selection_focus_rect_);
+ }
}
gfx::NativeView RenderWidgetHostViewAura::GetNativeView() const {
@@ -996,6 +1001,8 @@ void RenderWidgetHostViewAura::TextInputStateChanged(
can_compose_inline_ = params.can_compose_inline;
if (GetInputMethod())
GetInputMethod()->OnTextInputTypeChanged(this);
+ if (touch_editing_client_)
+ touch_editing_client_->OnTextInputTypeChanged(text_input_type_);
}
}
@@ -1111,6 +1118,11 @@ void RenderWidgetHostViewAura::SelectionBoundsChanged(
if (GetInputMethod())
GetInputMethod()->OnCaretBoundsChanged(this);
+
+ if (touch_editing_client_) {
+ touch_editing_client_->OnSelectionOrCursorChanged(selection_anchor_rect_,
+ selection_focus_rect_);
+ }
}
void RenderWidgetHostViewAura::ScrollOffsetChanged() {
@@ -1718,6 +1730,11 @@ gfx::Rect RenderWidgetHostViewAura::GetBoundsInRootWindow() {
return window_->GetToplevelWindow()->GetBoundsInScreen();
}
+void RenderWidgetHostViewAura::GestureEventAck(int gesture_event_type) {
+ if (touch_editing_client_)
+ touch_editing_client_->GestureEventAck(gesture_event_type);
+}
+
void RenderWidgetHostViewAura::ProcessAckedTouchEvent(
const WebKit::WebTouchEvent& touch_event, InputEventAckState ack_result) {
ScopedVector<ui::TouchEvent> events;
@@ -2059,6 +2076,8 @@ bool RenderWidgetHostViewAura::CanFocus() {
void RenderWidgetHostViewAura::OnCaptureLost() {
host_->LostCapture();
+ if (touch_editing_client_)
+ touch_editing_client_->EndTouchEditing();
}
void RenderWidgetHostViewAura::OnPaint(gfx::Canvas* canvas) {
@@ -2178,6 +2197,9 @@ scoped_refptr<ui::Texture> RenderWidgetHostViewAura::CopyTexture() {
void RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event) {
TRACE_EVENT0("browser", "RenderWidgetHostViewAura::OnKeyEvent");
+ if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event))
+ return;
+
if (popup_child_host_view_ && popup_child_host_view_->NeedsInputGrab()) {
popup_child_host_view_->OnKeyEvent(event);
if (event->handled())
@@ -2227,6 +2249,9 @@ void RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event) {
void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
TRACE_EVENT0("browser", "RenderWidgetHostViewAura::OnMouseEvent");
+ if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event))
+ return;
+
if (mouse_locked_) {
// Hide the cursor if someone else has shown it.
aura::client::CursorClient* cursor_client =
@@ -2331,6 +2356,9 @@ void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
void RenderWidgetHostViewAura::OnScrollEvent(ui::ScrollEvent* event) {
TRACE_EVENT0("browser", "RenderWidgetHostViewAura::OnScrollEvent");
+ if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event))
+ return;
+
if (event->type() == ui::ET_SCROLL) {
if (event->finger_count() != 2)
return;
@@ -2355,6 +2383,9 @@ void RenderWidgetHostViewAura::OnScrollEvent(ui::ScrollEvent* event) {
void RenderWidgetHostViewAura::OnTouchEvent(ui::TouchEvent* event) {
TRACE_EVENT0("browser", "RenderWidgetHostViewAura::OnTouchEvent");
+ if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event))
+ return;
+
// Update the touch event first.
WebKit::WebTouchPoint* point = UpdateWebTouchEventFromUIEvent(*event,
&touch_event_);
@@ -2385,6 +2416,9 @@ void RenderWidgetHostViewAura::OnGestureEvent(ui::GestureEvent* event) {
return;
}
+ if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event))
+ return;
+
RenderViewHostDelegate* delegate = NULL;
if (popup_type_ == WebKit::WebPopupTypeNone && !is_fullscreen_)
delegate = RenderViewHost::From(host_)->GetDelegate();
@@ -2490,6 +2524,9 @@ void RenderWidgetHostViewAura::OnWindowFocused(aura::Window* gained_focus,
DetachFromInputMethod();
host_->SetInputMethodActive(false);
+ if (touch_editing_client_)
+ touch_editing_client_->EndTouchEditing();
+
// If we lose the focus while fullscreen, close the window; Pepper Flash
// won't do it for us (unlike NPAPI Flash). However, we do not close the
// window if we lose the focus to a window on another display.
@@ -2640,6 +2677,8 @@ void RenderWidgetHostViewAura::OnLostResources() {
RenderWidgetHostViewAura::~RenderWidgetHostViewAura() {
if (paint_observer_)
paint_observer_->OnViewDestroyed();
+ if (touch_editing_client_)
+ touch_editing_client_->OnViewDestroyed();
if (!shared_surface_handle_.is_null()) {
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
factory->DestroySharedSurfaceHandle(shared_surface_handle_);
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index f8e5cc4..b3494b5 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -93,10 +93,47 @@ class RenderWidgetHostViewAura
virtual void OnViewDestroyed() = 0;
};
+ // Displays and controls touch editing elements such as selection handles.
+ class TouchEditingClient {
+ public:
+ TouchEditingClient() {}
+
+ // Tells the client to start showing touch editing handles.
+ virtual void StartTouchEditing() = 0;
+
+ // Notifies the client that touch editing is no longer needed.
+ virtual void EndTouchEditing() = 0;
+
+ // Notifies the client that the selection bounds need to be updated.
+ virtual void OnSelectionOrCursorChanged(const gfx::Rect& anchor,
+ const gfx::Rect& focus) = 0;
+
+ // Notifies the client that the current text input type as changed.
+ virtual void OnTextInputTypeChanged(ui::TextInputType type) = 0;
+
+ // Notifies the client that an input event is about to be sent to the
+ // renderer. Returns true if the client wants to stop event propagation.
+ virtual bool HandleInputEvent(const ui::Event* event) = 0;
+
+ // Notifies the client that a gesture event ack was received.
+ virtual void GestureEventAck(int gesture_event_type) = 0;
+
+ // This is called when the view is destroyed, so that the client can
+ // perform any necessary clean-up.
+ virtual void OnViewDestroyed() = 0;
+
+ protected:
+ virtual ~TouchEditingClient() {}
+ };
+
void set_paint_observer(PaintObserver* observer) {
paint_observer_ = observer;
}
+ void set_touch_editing_client(TouchEditingClient* client) {
+ touch_editing_client_ = client;
+ }
+
// RenderWidgetHostView implementation.
virtual void InitAsChild(gfx::NativeView parent_view) OVERRIDE;
virtual RenderWidgetHost* GetRenderWidgetHost() const OVERRIDE;
@@ -179,6 +216,7 @@ class RenderWidgetHostViewAura
virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) OVERRIDE;
virtual void GetScreenInfo(WebKit::WebScreenInfo* results) OVERRIDE;
virtual gfx::Rect GetBoundsInRootWindow() OVERRIDE;
+ virtual void GestureEventAck(int gesture_event_type) OVERRIDE;
virtual void ProcessAckedTouchEvent(
const WebKit::WebTouchEvent& touch,
InputEventAckState ack_result) OVERRIDE;
@@ -590,6 +628,8 @@ class RenderWidgetHostViewAura
// Subscriber that listens to frame presentation events.
scoped_ptr<RenderWidgetHostViewFrameSubscriber> frame_subscriber_;
+ TouchEditingClient* touch_editing_client_;
+
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAura);
};
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
index 0efb448..493c82f 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -422,6 +422,9 @@ InputEventAckState RenderWidgetHostViewBase::FilterInputEvent(
return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
+void RenderWidgetHostViewBase::GestureEventAck(int gesture_event_type) {
+}
+
void RenderWidgetHostViewBase::SetPopupType(WebKit::WebPopupType popup_type) {
popup_type_ = popup_type;
}
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h
index ae58a59..662dbab 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -61,6 +61,7 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
const WebKit::WebMouseWheelEvent& event) OVERRIDE;
virtual InputEventAckState FilterInputEvent(
const WebKit::WebInputEvent& input_event) OVERRIDE;
+ virtual void GestureEventAck(int gesture_event_type) OVERRIDE;
virtual void SetPopupType(WebKit::WebPopupType popup_type) OVERRIDE;
virtual WebKit::WebPopupType GetPopupType() OVERRIDE;
virtual BrowserAccessibilityManager*
diff --git a/content/browser/web_contents/touch_editable_impl_aura.cc b/content/browser/web_contents/touch_editable_impl_aura.cc
new file mode 100644
index 0000000..d6b3ed9
--- /dev/null
+++ b/content/browser/web_contents/touch_editable_impl_aura.cc
@@ -0,0 +1,314 @@
+// Copyright (c) 2013 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.
+
+#include "content/browser/web_contents/touch_editable_impl_aura.h"
+
+#include "base/command_line.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_view_aura.h"
+#include "content/common/view_messages.h"
+#include "content/public/browser/render_widget_host.h"
+#include "grit/ui_strings.h"
+#include "ui/aura/client/activation_client.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/range/range.h"
+#include "ui/base/ui_base_switches.h"
+
+namespace content {
+
+////////////////////////////////////////////////////////////////////////////////
+// TouchEditableImplAura, public:
+
+TouchEditableImplAura::~TouchEditableImplAura() {
+ Cleanup();
+}
+
+// static
+TouchEditableImplAura* TouchEditableImplAura::Create() {
+#if defined(OS_CHROMEOS)
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableTouchEditing))
+ return new TouchEditableImplAura();
+#endif
+ return NULL;
+}
+
+void TouchEditableImplAura::AttachToView(RenderWidgetHostViewAura* view) {
+ if (rwhva_ == view)
+ return;
+
+ Cleanup();
+ if (!view)
+ return;
+
+ rwhva_ = view;
+ rwhva_->set_touch_editing_client(this);
+}
+
+void TouchEditableImplAura::UpdateEditingController() {
+ if (!rwhva_)
+ return;
+
+ // If touch editing handles were not visible, we bring them up only if
+ // there is non-zero selection on the page. And the current event is a
+ // gesture event (we dont want to show handles if the user is selecting
+ // using mouse or keyboard).
+ if (selection_gesture_in_process_ &&
+ selection_anchor_rect_ != selection_focus_rect_)
+ StartTouchEditing();
+
+ if (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE ||
+ selection_anchor_rect_ != selection_focus_rect_) {
+ if (touch_selection_controller_)
+ touch_selection_controller_->SelectionChanged();
+ } else {
+ EndTouchEditing();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TouchEditableImplAura, RenderWidgetHostViewAura::TouchEditingClient
+// implementation:
+
+void TouchEditableImplAura::StartTouchEditing() {
+ if (!touch_selection_controller_) {
+ touch_selection_controller_.reset(
+ ui::TouchSelectionController::create(this));
+ }
+ if (touch_selection_controller_)
+ touch_selection_controller_->SelectionChanged();
+}
+
+void TouchEditableImplAura::EndTouchEditing() {
+ if (touch_selection_controller_) {
+ if (touch_selection_controller_->IsHandleDragInProgress())
+ touch_selection_controller_->SelectionChanged();
+ else
+ touch_selection_controller_.reset();
+ }
+}
+
+void TouchEditableImplAura::OnSelectionOrCursorChanged(const gfx::Rect& anchor,
+ const gfx::Rect& focus) {
+ selection_anchor_rect_ = anchor;
+ selection_focus_rect_ = focus;
+ UpdateEditingController();
+}
+
+void TouchEditableImplAura::OnTextInputTypeChanged(ui::TextInputType type) {
+ text_input_type_ = type;
+}
+
+bool TouchEditableImplAura::HandleInputEvent(const ui::Event* event) {
+ DCHECK(rwhva_);
+ if (event->IsTouchEvent())
+ return false;
+
+ if (!event->IsGestureEvent()) {
+ EndTouchEditing();
+ return false;
+ }
+
+ const ui::GestureEvent* gesture_event =
+ static_cast<const ui::GestureEvent*>(event);
+ switch (event->type()) {
+ case ui::ET_GESTURE_TAP:
+ if (gesture_event->details().tap_count() > 1)
+ selection_gesture_in_process_ = true;
+ // When the user taps, we want to show touch editing handles if user
+ // tapped on selected text.
+ if (selection_anchor_rect_ != selection_focus_rect_) {
+ // UnionRects only works for rects with non-zero width.
+ gfx::Rect anchor(selection_anchor_rect_.origin(),
+ gfx::Size(1, selection_anchor_rect_.height()));
+ gfx::Rect focus(selection_focus_rect_.origin(),
+ gfx::Size(1, selection_focus_rect_.height()));
+ gfx::Rect selection_rect = gfx::UnionRects(anchor, focus);
+ if (selection_rect.Contains(gesture_event->location())) {
+ StartTouchEditing();
+ return true;
+ }
+ }
+ break;
+ case ui::ET_GESTURE_LONG_PRESS:
+ selection_gesture_in_process_ = true;
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+void TouchEditableImplAura::GestureEventAck(int gesture_event_type) {
+ DCHECK(rwhva_);
+ if (gesture_event_type == WebKit::WebInputEvent::GestureTap &&
+ text_input_type_ != ui::TEXT_INPUT_TYPE_NONE) {
+ StartTouchEditing();
+ if (touch_selection_controller_)
+ touch_selection_controller_->SelectionChanged();
+ }
+
+ if (gesture_event_type == WebKit::WebInputEvent::GestureLongPress ||
+ gesture_event_type == WebKit::WebInputEvent::GestureTap)
+ selection_gesture_in_process_ = false;
+}
+
+void TouchEditableImplAura::OnViewDestroyed() {
+ Cleanup();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TouchEditableImplAura, ui::TouchEditable implementation:
+
+void TouchEditableImplAura::SelectRect(const gfx::Point& start,
+ const gfx::Point& end) {
+ if (!rwhva_)
+ return;
+
+ RenderWidgetHostImpl* host = RenderWidgetHostImpl::From(
+ rwhva_->GetRenderWidgetHost());
+ host->SelectRange(start, end);
+}
+
+void TouchEditableImplAura::MoveCaretTo(const gfx::Point& point) {
+ if (!rwhva_)
+ return;
+
+ RenderWidgetHostImpl* host = RenderWidgetHostImpl::From(
+ rwhva_->GetRenderWidgetHost());
+ host->MoveCaret(point);
+}
+
+void TouchEditableImplAura::GetSelectionEndPoints(gfx::Rect* p1,
+ gfx::Rect* p2) {
+ *p1 = selection_anchor_rect_;
+ *p2 = selection_focus_rect_;
+}
+
+gfx::Rect TouchEditableImplAura::GetBounds() {
+ return rwhva_ ? rwhva_->GetNativeView()->bounds() : gfx::Rect();
+}
+
+gfx::NativeView TouchEditableImplAura::GetNativeView() {
+ return rwhva_ ? rwhva_->GetNativeView()->GetRootWindow() : NULL;
+}
+
+void TouchEditableImplAura::ConvertPointToScreen(gfx::Point* point) {
+ if (!rwhva_)
+ return;
+ aura::Window* window = rwhva_->GetNativeView();
+ aura::client::ScreenPositionClient* screen_position_client =
+ aura::client::GetScreenPositionClient(window->GetRootWindow());
+ if (screen_position_client)
+ screen_position_client->ConvertPointToScreen(window, point);
+}
+
+void TouchEditableImplAura::ConvertPointFromScreen(gfx::Point* point) {
+ if (!rwhva_)
+ return;
+ aura::Window* window = rwhva_->GetNativeView();
+ aura::client::ScreenPositionClient* screen_position_client =
+ aura::client::GetScreenPositionClient(window->GetRootWindow());
+ if (screen_position_client)
+ screen_position_client->ConvertPointFromScreen(window, point);
+}
+
+bool TouchEditableImplAura::DrawsHandles() {
+ return false;
+}
+
+void TouchEditableImplAura::OpenContextMenu(const gfx::Point anchor) {
+ if (!rwhva_)
+ return;
+ RenderWidgetHost* host = rwhva_->GetRenderWidgetHost();
+ host->Send(new ViewMsg_ShowContextMenu(host->GetRoutingID()));
+ EndTouchEditing();
+}
+
+bool TouchEditableImplAura::IsCommandIdChecked(int command_id) const {
+ NOTREACHED();
+ return false;
+}
+
+bool TouchEditableImplAura::IsCommandIdEnabled(int command_id) const {
+ if (!rwhva_)
+ return false;
+ bool editable = rwhva_->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE;
+ ui::Range selection_range;
+ rwhva_->GetSelectionRange(&selection_range);
+ bool has_selection = !selection_range.is_empty();
+ switch (command_id) {
+ case IDS_APP_CUT:
+ return editable && has_selection;
+ case IDS_APP_COPY:
+ return has_selection;
+ case IDS_APP_PASTE: {
+ string16 result;
+ ui::Clipboard::GetForCurrentThread()->ReadText(
+ ui::Clipboard::BUFFER_STANDARD, &result);
+ return editable && !result.empty();
+ }
+ case IDS_APP_DELETE:
+ return editable && has_selection;
+ case IDS_APP_SELECT_ALL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool TouchEditableImplAura::GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) {
+ return false;
+}
+
+void TouchEditableImplAura::ExecuteCommand(int command_id, int event_flags) {
+ if (!rwhva_)
+ return;
+ RenderWidgetHost* host = rwhva_->GetRenderWidgetHost();
+ switch (command_id) {
+ case IDS_APP_CUT:
+ host->Cut();
+ break;
+ case IDS_APP_COPY:
+ host->Copy();
+ break;
+ case IDS_APP_PASTE:
+ host->Paste();
+ break;
+ case IDS_APP_DELETE:
+ host->Delete();
+ break;
+ case IDS_APP_SELECT_ALL:
+ host->SelectAll();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ EndTouchEditing();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TouchEditableImplAura, private:
+
+TouchEditableImplAura::TouchEditableImplAura()
+ : text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
+ rwhva_(NULL),
+ selection_gesture_in_process_(false) {
+}
+
+void TouchEditableImplAura::Cleanup() {
+ if (rwhva_) {
+ rwhva_->set_touch_editing_client(NULL);
+ rwhva_ = NULL;
+ }
+ touch_selection_controller_.reset();
+}
+
+} // namespace content
diff --git a/content/browser/web_contents/touch_editable_impl_aura.h b/content/browser/web_contents/touch_editable_impl_aura.h
new file mode 100644
index 0000000..f29dfd31
--- /dev/null
+++ b/content/browser/web_contents/touch_editable_impl_aura.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2013 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_BROWSER_WEB_CONTENTS_TOUCH_EDITABLE_IMPL_AURA_H_
+#define CONTENT_BROWSER_WEB_CONTENTS_TOUCH_EDITABLE_IMPL_AURA_H_
+
+#include <deque>
+#include <map>
+
+#include "content/browser/renderer_host/render_widget_host_view_aura.h"
+#include "ui/aura/window_observer.h"
+#include "ui/base/touch/touch_editing_controller.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/point.h"
+#include "ui/gfx/rect.h"
+
+namespace ui {
+class Accelerator;
+}
+
+namespace content {
+class TouchEditableImplAuraTest;
+
+// Aura specific implementation of ui::TouchEditable for a RenderWidgetHostView.
+class CONTENT_EXPORT TouchEditableImplAura
+ : public ui::TouchEditable,
+ public NON_EXPORTED_BASE(RenderWidgetHostViewAura::TouchEditingClient) {
+ public:
+ virtual ~TouchEditableImplAura();
+
+ static TouchEditableImplAura* Create();
+
+ void AttachToView(RenderWidgetHostViewAura* view);
+
+ // Updates the |touch_selection_controller_| or ends touch editing session
+ // depending on the current selection and cursor state.
+ void UpdateEditingController();
+
+ // Overridden from RenderWidgetHostViewAura::TouchEditingClient.
+ virtual void StartTouchEditing() OVERRIDE;
+ virtual void EndTouchEditing() OVERRIDE;
+ virtual void OnSelectionOrCursorChanged(const gfx::Rect& anchor,
+ const gfx::Rect& focus) OVERRIDE;
+ virtual void OnTextInputTypeChanged(ui::TextInputType type) OVERRIDE;
+ virtual bool HandleInputEvent(const ui::Event* event) OVERRIDE;
+ virtual void GestureEventAck(int gesture_event_type) OVERRIDE;
+ virtual void OnViewDestroyed() OVERRIDE;
+
+ // Overridden from ui::TouchEditable:
+ virtual void SelectRect(const gfx::Point& start,
+ const gfx::Point& end) OVERRIDE;
+ virtual void MoveCaretTo(const gfx::Point& point) OVERRIDE;
+ virtual void GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) OVERRIDE;
+ virtual gfx::Rect GetBounds() OVERRIDE;
+ virtual gfx::NativeView GetNativeView() OVERRIDE;
+ virtual void ConvertPointToScreen(gfx::Point* point) OVERRIDE;
+ virtual void ConvertPointFromScreen(gfx::Point* point) OVERRIDE;
+ virtual bool DrawsHandles() OVERRIDE;
+ virtual void OpenContextMenu(const gfx::Point anchor) OVERRIDE;
+ virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
+ virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
+ virtual bool GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) OVERRIDE;
+ virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
+
+ protected:
+ TouchEditableImplAura();
+
+ private:
+ friend class TouchEditableImplAuraTest;
+
+ void Cleanup();
+
+ // Rectangles for the selection anchor and focus.
+ gfx::Rect selection_anchor_rect_;
+ gfx::Rect selection_focus_rect_;
+
+ // The current text input type.
+ ui::TextInputType text_input_type_;
+
+ RenderWidgetHostViewAura* rwhva_;
+ scoped_ptr<ui::TouchSelectionController> touch_selection_controller_;
+
+ // True if |rwhva_| is currently handling a gesture that could result in a
+ // change in selection.
+ bool selection_gesture_in_process_;
+
+ DISALLOW_COPY_AND_ASSIGN(TouchEditableImplAura);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_WEB_CONTENTS_TOUCH_EDITABLE_IMPL_AURA_H_
diff --git a/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc b/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc
new file mode 100644
index 0000000..d309f45b
--- /dev/null
+++ b/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc
@@ -0,0 +1,284 @@
+// 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.
+
+#include "content/browser/web_contents/touch_editable_impl_aura.h"
+
+#include "base/command_line.h"
+#include "base/run_loop.h"
+#include "base/test/test_timeouts.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/browser/web_contents/web_contents_view_aura.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_utils.h"
+#include "content/shell/shell.h"
+#include "content/test/content_browser_test.h"
+#include "content/test/content_browser_test_utils.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/window.h"
+#include "ui/base/events/event_utils.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+
+namespace content {
+
+class TestTouchEditableImplAura : public TouchEditableImplAura {
+ public:
+ TestTouchEditableImplAura()
+ : selection_changed_callback_arrived_(false),
+ waiting_for_selection_changed_callback_(false),
+ gesture_ack_callback_arrived_(false),
+ waiting_for_gesture_ack_callback_(false) {}
+
+ void Reset() {
+ selection_changed_callback_arrived_ = false;
+ waiting_for_selection_changed_callback_ = false;
+ gesture_ack_callback_arrived_ = false;
+ waiting_for_gesture_ack_callback_ = false;
+ }
+
+ void OnSelectionOrCursorChanged(const gfx::Rect& anchor,
+ const gfx::Rect& focus) OVERRIDE {
+ selection_changed_callback_arrived_ = true;
+ TouchEditableImplAura::OnSelectionOrCursorChanged(anchor, focus);
+ if (waiting_for_selection_changed_callback_)
+ selection_changed_wait_run_loop_->Quit();
+ }
+
+ void GestureEventAck(int gesture_event_type) OVERRIDE {
+ gesture_ack_callback_arrived_ = true;
+ TouchEditableImplAura::GestureEventAck(gesture_event_type);
+ if (waiting_for_gesture_ack_callback_)
+ gesture_ack_wait_run_loop_->Quit();
+ }
+
+ void WaitForSelectionChangeCallback() {
+ if (selection_changed_callback_arrived_)
+ return;
+ waiting_for_selection_changed_callback_ = true;
+ selection_changed_wait_run_loop_.reset(new base::RunLoop());
+ selection_changed_wait_run_loop_->Run();
+ }
+
+ void WaitForGestureAck() {
+ if (gesture_ack_callback_arrived_)
+ return;
+ waiting_for_gesture_ack_callback_ = true;
+ gesture_ack_wait_run_loop_.reset(new base::RunLoop());
+ gesture_ack_wait_run_loop_->Run();
+ }
+
+ protected:
+ virtual ~TestTouchEditableImplAura() {}
+
+ private:
+ bool selection_changed_callback_arrived_;
+ bool waiting_for_selection_changed_callback_;
+ bool gesture_ack_callback_arrived_;
+ bool waiting_for_gesture_ack_callback_;
+ scoped_ptr<base::RunLoop> selection_changed_wait_run_loop_;
+ scoped_ptr<base::RunLoop> gesture_ack_wait_run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestTouchEditableImplAura);
+};
+
+class TouchEditableImplAuraTest : public ContentBrowserTest {
+ public:
+ TouchEditableImplAuraTest() {}
+
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ command_line->AppendSwitch(switches::kEnableTouchEditing);
+ }
+
+ // Executes the javascript synchronously and makes sure the returned value is
+ // freed properly.
+ void ExecuteSyncJSFunction(RenderViewHost* rvh, const std::string& jscript) {
+ scoped_ptr<base::Value> value =
+ content::ExecuteScriptAndGetValue(rvh, jscript);
+ }
+
+ // Starts the test server and navigates to the given url. Sets a large enough
+ // size to the root window. Returns after the navigation to the url is
+ // complete.
+ void StartTestWithPage(const std::string& url) {
+ ASSERT_TRUE(test_server()->Start());
+ GURL test_url(test_server()->GetURL(url));
+ NavigateToURL(shell(), test_url);
+ aura::Window* content =
+ shell()->web_contents()->GetView()->GetContentNativeView();
+ content->GetRootWindow()->SetHostSize(gfx::Size(800, 600));
+ }
+
+ void TestTouchSelectionOriginatingFromWebpage() {
+ ASSERT_NO_FATAL_FAILURE(
+ StartTestWithPage("files/touch_selection.html"));
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ RenderViewHostImpl* view_host = static_cast<RenderViewHostImpl*>(
+ web_contents->GetRenderViewHost());
+ WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
+ web_contents->GetView());
+ TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura;
+ view_aura->SetTouchEditableForTest(touch_editable);
+ RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+ web_contents->GetRenderWidgetHostView());
+ aura::Window* content = web_contents->GetView()->GetContentNativeView();
+ aura::test::EventGenerator generator(content->GetRootWindow(), content);
+ gfx::Rect bounds = content->GetBoundsInRootWindow();
+
+ touch_editable->Reset();
+ ExecuteSyncJSFunction(view_host, "select_all_text()");
+ touch_editable->WaitForSelectionChangeCallback();
+
+ // Tap inside selection to bring up selection handles.
+ generator.GestureTapAt(gfx::Point(bounds.x() + 10, bounds.y() + 10));
+ EXPECT_EQ(touch_editable->rwhva_, rwhva);
+
+ scoped_ptr<base::Value> value =
+ content::ExecuteScriptAndGetValue(view_host, "get_selection()");
+ std::string selection;
+ value->GetAsString(&selection);
+
+ // Check if selection handles are showing.
+ EXPECT_TRUE(touch_editable->touch_selection_controller_.get());
+ EXPECT_STREQ("Some text we can select", selection.c_str());
+
+ // Lets move the handles a bit to modify the selection
+ touch_editable->Reset();
+ generator.GestureScrollSequence(
+ gfx::Point(10, 37),
+ gfx::Point(30, 37),
+ base::TimeDelta::FromMilliseconds(20),
+ 1);
+ EXPECT_TRUE(touch_editable->touch_selection_controller_.get());
+ value = content::ExecuteScriptAndGetValue(view_host, "get_selection()");
+ value->GetAsString(&selection);
+
+ // It is hard to tell what exactly the selection would be now. But it would
+ // definitely be less than whatever was selected before.
+ EXPECT_GT(std::strlen("Some text we can select"), selection.size());
+ }
+
+ void TestTouchSelectionOnLongPress() {
+ ASSERT_NO_FATAL_FAILURE(
+ StartTestWithPage("files/touch_selection.html"));
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ RenderViewHostImpl* view_host = static_cast<RenderViewHostImpl*>(
+ web_contents->GetRenderViewHost());
+ WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
+ web_contents->GetView());
+ TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura;
+ view_aura->SetTouchEditableForTest(touch_editable);
+ RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+ web_contents->GetRenderWidgetHostView());
+ aura::Window* content = web_contents->GetView()->GetContentNativeView();
+ aura::test::EventGenerator generator(content->GetRootWindow(), content);
+ gfx::Rect bounds = content->GetBoundsInRootWindow();
+ EXPECT_EQ(touch_editable->rwhva_, rwhva);
+
+ // Long press to select word.
+ ui::GestureEvent long_press(ui::ET_GESTURE_LONG_PRESS,
+ 10,
+ 10,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(
+ ui::ET_GESTURE_LONG_PRESS, 0, 0),
+ 1);
+ touch_editable->Reset();
+ rwhva->OnGestureEvent(&long_press);
+ touch_editable->WaitForSelectionChangeCallback();
+
+ // Check if selection handles are showing.
+ ui::TouchSelectionController* controller =
+ touch_editable->touch_selection_controller_.get();
+ EXPECT_TRUE(controller);
+
+ scoped_ptr<base::Value> value =
+ content::ExecuteScriptAndGetValue(view_host, "get_selection()");
+ std::string selection;
+ value->GetAsString(&selection);
+ EXPECT_STREQ("Some", selection.c_str());
+ }
+
+ void TestTouchCursorInTextfield() {
+ ASSERT_NO_FATAL_FAILURE(
+ StartTestWithPage("files/touch_selection.html"));
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ RenderViewHostImpl* view_host = static_cast<RenderViewHostImpl*>(
+ web_contents->GetRenderViewHost());
+ WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
+ web_contents->GetView());
+ TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura;
+ view_aura->SetTouchEditableForTest(touch_editable);
+ RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+ web_contents->GetRenderWidgetHostView());
+ aura::Window* content = web_contents->GetView()->GetContentNativeView();
+ aura::test::EventGenerator generator(content->GetRootWindow(), content);
+ gfx::Rect bounds = content->GetBoundsInRootWindow();
+ EXPECT_EQ(touch_editable->rwhva_, rwhva);
+ ExecuteSyncJSFunction(view_host, "focus_textfield()");
+
+ // Tap textfield
+ touch_editable->Reset();
+ generator.GestureTapAt(gfx::Point(bounds.x() + 50, bounds.y() + 40));
+ touch_editable->WaitForGestureAck(); // Wait for Tap Down Ack
+ touch_editable->Reset();
+ touch_editable->WaitForGestureAck(); // Wait for Tap Ack.
+
+ // Check if cursor handle is showing.
+ ui::TouchSelectionController* controller =
+ touch_editable->touch_selection_controller_.get();
+ EXPECT_NE(ui::TEXT_INPUT_TYPE_NONE, touch_editable->text_input_type_);
+ EXPECT_TRUE(controller);
+
+ scoped_ptr<base::Value> value =
+ content::ExecuteScriptAndGetValue(view_host, "get_cursor_position()");
+ int cursor_pos = -1;
+ value->GetAsInteger(&cursor_pos);
+ EXPECT_NE(-1, cursor_pos);
+
+ // Move the cursor handle.
+ generator.GestureScrollSequence(
+ gfx::Point(50, 59),
+ gfx::Point(10, 59),
+ base::TimeDelta::FromMilliseconds(20),
+ 1);
+ EXPECT_TRUE(touch_editable->touch_selection_controller_.get());
+ value = content::ExecuteScriptAndGetValue(
+ view_host, "get_cursor_position()");
+ int new_cursor_pos = -1;
+ value->GetAsInteger(&new_cursor_pos);
+ EXPECT_NE(-1, new_cursor_pos);
+ // Cursor should have moved.
+ EXPECT_NE(new_cursor_pos, cursor_pos);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TouchEditableImplAuraTest);
+};
+
+IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
+ TouchSelectionOriginatingFromWebpageTest) {
+ TestTouchSelectionOriginatingFromWebpage();
+}
+
+IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
+ TouchSelectionOnLongPressTest) {
+ TestTouchSelectionOnLongPress();
+}
+
+IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
+ TouchCursorInTextfieldTest) {
+ TestTouchCursorInTextfield();
+}
+
+} // namespace content
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc
index 788dac5..bda08a0 100644
--- a/content/browser/web_contents/web_contents_view_aura.cc
+++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -15,6 +15,7 @@
#include "content/browser/renderer_host/render_widget_host_view_aura.h"
#include "content/browser/web_contents/interstitial_page_impl.h"
#include "content/browser/web_contents/navigation_entry_impl.h"
+#include "content/browser/web_contents/touch_editable_impl_aura.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
@@ -742,6 +743,8 @@ class WebContentsViewAura::WindowObserver
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) OVERRIDE {
SendScreenRects();
+ if (view_->touch_editable_)
+ view_->touch_editable_->UpdateEditingController();
}
virtual void OnWindowAddedToRootWindow(aura::Window* window) OVERRIDE {
@@ -876,7 +879,8 @@ WebContentsViewAura::WebContentsViewAura(
content_container_(NULL),
overscroll_change_brightness_(false),
current_overscroll_gesture_(OVERSCROLL_NONE),
- completed_overscroll_gesture_(OVERSCROLL_NONE) {
+ completed_overscroll_gesture_(OVERSCROLL_NONE),
+ touch_editable_(TouchEditableImplAura::Create()) {
}
////////////////////////////////////////////////////////////////////////////////
@@ -900,6 +904,12 @@ void WebContentsViewAura::SetupOverlayWindowForTesting() {
navigation_overlay_->SetupForTesting();
}
+void WebContentsViewAura::SetTouchEditableForTest(
+ TouchEditableImplAura* touch_editable) {
+ touch_editable_.reset(touch_editable);
+ AttachTouchEditableToRenderView();
+}
+
void WebContentsViewAura::SizeChangedCommon(const gfx::Size& size) {
if (web_contents_->GetInterstitialPage())
web_contents_->GetInterstitialPage()->SetSize(size);
@@ -1114,6 +1124,14 @@ void WebContentsViewAura::UpdateOverscrollWindowBrightness(float delta_x) {
window->layer()->SetLayerBrightness(brightness);
}
+void WebContentsViewAura::AttachTouchEditableToRenderView() {
+ if (!touch_editable_)
+ return;
+ RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+ web_contents_->GetRenderWidgetHostView());
+ touch_editable_->AttachToView(rwhva);
+}
+
////////////////////////////////////////////////////////////////////////////////
// WebContentsViewAura, WebContentsView implementation:
@@ -1274,6 +1292,7 @@ RenderWidgetHostView* WebContentsViewAura::CreateViewForWidget(
navigation_overlay_.reset(new OverscrollNavigationOverlay());
}
+ AttachTouchEditableToRenderView();
return view;
}
@@ -1294,6 +1313,7 @@ void WebContentsViewAura::RenderViewSwappedIn(RenderViewHost* host) {
navigation_overlay_->StartObservingView(static_cast<
RenderWidgetHostViewAura*>(host->GetView()));
}
+ AttachTouchEditableToRenderView();
}
void WebContentsViewAura::SetOverscrollControllerEnabled(bool enabled) {
@@ -1314,6 +1334,9 @@ void WebContentsViewAura::ShowContextMenu(
ContextMenuSourceType type) {
if (delegate_)
delegate_->ShowContextMenu(params, type);
+ if (touch_editable_)
+ touch_editable_->EndTouchEditing();
+
}
void WebContentsViewAura::ShowPopupMenu(const gfx::Rect& bounds,
@@ -1339,6 +1362,9 @@ void WebContentsViewAura::StartDragging(
return;
}
+ if (touch_editable_)
+ touch_editable_->EndTouchEditing();
+
ui::OSExchangeData::Provider* provider = ui::OSExchangeData::CreateProvider();
PrepareDragData(drop_data, provider);
diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h
index f619352..65c9462 100644
--- a/content/browser/web_contents/web_contents_view_aura.h
+++ b/content/browser/web_contents/web_contents_view_aura.h
@@ -28,6 +28,7 @@ class DropTargetEvent;
namespace content {
class OverscrollNavigationOverlay;
class ShadowWindow;
+class TouchEditableImplAura;
class WebContentsViewDelegate;
class WebContentsImpl;
class WebDragDestDelegate;
@@ -45,6 +46,8 @@ class CONTENT_EXPORT WebContentsViewAura
void SetupOverlayWindowForTesting();
+ void SetTouchEditableForTest(TouchEditableImplAura* touch_editable);
+
private:
class WindowObserver;
#if defined(OS_WIN)
@@ -92,6 +95,8 @@ class CONTENT_EXPORT WebContentsViewAura
// overscroll (|delta_x|, in pixels).
void UpdateOverscrollWindowBrightness(float delta_x);
+ void AttachTouchEditableToRenderView();
+
// Overridden from WebContentsView:
virtual gfx::NativeView GetNativeView() const OVERRIDE;
virtual gfx::NativeView GetContentNativeView() const OVERRIDE;
@@ -224,6 +229,8 @@ class CONTENT_EXPORT WebContentsViewAura
// navigation triggered by the overscroll gesture.
scoped_ptr<OverscrollNavigationOverlay> navigation_overlay_;
+ scoped_ptr<TouchEditableImplAura> touch_editable_;
+
DISALLOW_COPY_AND_ASSIGN(WebContentsViewAura);
};
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 7f0ff24..7b521e6 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -912,6 +912,9 @@ IPC_MESSAGE_ROUTED2(ViewMsg_CustomContextMenuAction,
IPC_MESSAGE_ROUTED1(ViewMsg_ContextMenuClosed,
content::CustomContextMenuContext /* custom_context */)
+// Sent to inform the renderer to invoke a context menu.
+IPC_MESSAGE_ROUTED0(ViewMsg_ShowContextMenu)
+
// Tells the renderer to perform the specified navigation, interrupting any
// existing navigation.
IPC_MESSAGE_ROUTED1(ViewMsg_Navigate, ViewMsg_Navigate_Params)
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 0bec54e..b7817dd 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -962,6 +962,8 @@
'browser/web_contents/navigation_entry_impl.h',
'browser/web_contents/render_view_host_manager.cc',
'browser/web_contents/render_view_host_manager.h',
+ 'browser/web_contents/touch_editable_impl_aura.cc',
+ 'browser/web_contents/touch_editable_impl_aura.h',
'browser/web_contents/web_contents_drag_win.cc',
'browser/web_contents/web_contents_drag_win.h',
'browser/web_contents/web_contents_impl.cc',
@@ -1251,6 +1253,7 @@
['use_aura==1', {
'dependencies': [
'../ui/aura/aura.gyp:aura',
+ '../ui/base/strings/ui_strings.gyp:ui_strings',
'../ui/compositor/compositor.gyp:compositor',
],
'sources/': [
@@ -1283,6 +1286,8 @@
['exclude', '^browser/renderer_host/software_output_device_x11.cc'],
['exclude', '^browser/renderer_host/software_output_device_x11.h'],
['exclude', '^browser/renderer_host/touchpad_tap_suppression_controller_aura.cc'],
+ ['exclude', '^browser/web_contents/touch_editable_impl_aura.cc'],
+ ['exclude', '^browser/web_contents/touch_editable_impl_aura.h'],
],
}],
['enable_plugins==1', {
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 9991e22..e9876a4 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -789,6 +789,7 @@
'browser/session_history_browsertest.cc',
'browser/site_per_process_browsertest.cc',
'browser/speech/speech_recognition_browsertest.cc',
+ 'browser/web_contents/touch_editable_impl_aura_browsertest.cc',
'browser/web_contents/web_contents_impl_browsertest.cc',
'browser/web_contents/web_contents_view_aura_browsertest.cc',
'browser/webkit_browsertest.cc',
@@ -836,6 +837,11 @@
'../webkit/plugins/ppapi/mock_plugin_delegate.h',
],
'conditions': [
+ ['chromeos==0', {
+ 'sources!': [
+ 'browser/web_contents/touch_editable_impl_aura_browsertest.cc',
+ ],
+ }],
['OS=="win"', {
'resource_include_dirs': [
'<(SHARED_INTERMEDIATE_DIR)/webkit',
diff --git a/content/port/browser/render_widget_host_view_port.h b/content/port/browser/render_widget_host_view_port.h
index e67f214..46a96c2 100644
--- a/content/port/browser/render_widget_host_view_port.h
+++ b/content/port/browser/render_widget_host_view_port.h
@@ -280,6 +280,8 @@ class CONTENT_EXPORT RenderWidgetHostViewPort : public RenderWidgetHostView,
virtual InputEventAckState FilterInputEvent(
const WebKit::WebInputEvent& input_event) = 0;
+ virtual void GestureEventAck(int gesture_event_type) = 0;
+
virtual void SetPopupType(WebKit::WebPopupType popup_type) = 0;
virtual WebKit::WebPopupType GetPopupType() = 0;
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index eafda6c..9559d46 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -749,6 +749,9 @@ void RenderViewImpl::Initialize(RenderViewImplParams* params) {
if (command_line.HasSwitch(switches::kEnableTouchDragDrop))
webview()->settings()->setTouchDragDropEnabled(true);
+ if (command_line.HasSwitch(switches::kEnableTouchEditing))
+ webview()->settings()->setTouchEditingEnabled(true);
+
if (!params->frame_name.empty())
webview()->mainFrame()->setName(params->frame_name);
webview()->settings()->setMinimumTimerInterval(
@@ -1089,6 +1092,7 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) {
ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks,
OnGetSerializedHtmlDataForCurrentPageWithLocalLinks)
IPC_MESSAGE_HANDLER(ViewMsg_ContextMenuClosed, OnContextMenuClosed)
+ IPC_MESSAGE_HANDLER(ViewMsg_ShowContextMenu, OnShowContextMenu)
// TODO(viettrungluu): Move to a separate message filter.
IPC_MESSAGE_HANDLER(ViewMsg_SetHistoryLengthAndPrune,
OnSetHistoryLengthAndPrune)
@@ -4672,6 +4676,7 @@ void RenderViewImpl::SyncSelectionIfRequired() {
selection_range_ = range;
Send(new ViewHostMsg_SelectionChanged(routing_id_, text, offset, range));
}
+ UpdateSelectionBounds();
}
GURL RenderViewImpl::GetAlternateErrorPageURL(const GURL& failed_url,
@@ -6367,6 +6372,11 @@ void RenderViewImpl::OnContextMenuClosed(
}
}
+void RenderViewImpl::OnShowContextMenu() {
+ if (webview())
+ webview()->showContextMenu();
+}
+
void RenderViewImpl::OnEnableViewSourceMode() {
if (!webview())
return;
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 377fcb3..1612308 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -922,6 +922,7 @@ class CONTENT_EXPORT RenderViewImpl
void OnClearFocusedNode();
void OnClosePage();
void OnContextMenuClosed(const CustomContextMenuContext& custom_context);
+ void OnShowContextMenu();
void OnCopy();
void OnCopyImageAt(int x, int y);
void OnCut();
diff --git a/content/test/data/touch_selection.html b/content/test/data/touch_selection.html
new file mode 100644
index 0000000..0c4721a
--- /dev/null
+++ b/content/test/data/touch_selection.html
@@ -0,0 +1,35 @@
+<html>
+<div id='textDiv'>Some text we can select</div>
+<input id='textfield' type="text" value="Text in a textfield">
+<script>
+
+function select_all_text() {
+ var div = document.getElementById("textDiv");
+ var range = document.createRange();
+ range.selectNodeContents(div);
+ var sel = window.getSelection();
+ sel.removeAllRanges();
+ sel.addRange(range);
+}
+
+function get_selection() {
+ return (window.getSelection() + "");
+}
+
+function focus_textfield() {
+ document.getElementById("textfield").focus();
+}
+
+function get_cursor_position() {
+ var div = document.getElementById("textfield");
+ var start = div.selectionStart;
+ var end = div.selectionEnd;
+ if (start == end)
+ return start;
+ else
+ return -1;
+}
+
+</script>
+
+</html>