diff options
19 files changed, 877 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 066478c..c58d369 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -865,6 +865,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..c734282 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(); @@ -2502,6 +2536,8 @@ void RenderWidgetHostViewAura::OnWindowFocused(aura::Window* gained_focus, in_shutdown_ = true; host_->Shutdown(); } + if (touch_editing_client_) + touch_editing_client_->EndTouchEditing(); } } @@ -2640,6 +2676,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..a88d471 --- /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 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 97f8f95..3710bfc 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -768,6 +768,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', @@ -809,6 +810,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 c6374a0..6b74353 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) @@ -4670,6 +4674,7 @@ void RenderViewImpl::SyncSelectionIfRequired() { selection_range_ = range; Send(new ViewHostMsg_SelectionChanged(routing_id_, text, offset, range)); } + UpdateSelectionBounds(); } GURL RenderViewImpl::GetAlternateErrorPageURL(const GURL& failed_url, @@ -6365,6 +6370,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> |