summaryrefslogtreecommitdiffstats
path: root/content/browser/renderer_host
diff options
context:
space:
mode:
Diffstat (limited to 'content/browser/renderer_host')
-rw-r--r--content/browser/renderer_host/input/touch_selection_controller_client_aura.cc353
-rw-r--r--content/browser/renderer_host/input/touch_selection_controller_client_aura.h80
-rw-r--r--content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc441
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.cc129
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.h76
5 files changed, 995 insertions, 84 deletions
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc b/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc
new file mode 100644
index 0000000..ada3e9f
--- /dev/null
+++ b/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc
@@ -0,0 +1,353 @@
+// Copyright 2015 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/renderer_host/input/touch_selection_controller_client_aura.h"
+
+#include "content/browser/renderer_host/render_widget_host_delegate.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_view_host.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/base/clipboard/clipboard.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
+#include "ui/strings/grit/ui_strings.h"
+#include "ui/touch_selection/touch_handle_drawable_aura.h"
+#include "ui/touch_selection/touch_selection_menu_runner.h"
+
+namespace content {
+namespace {
+
+// Delay before showing the quick menu, in milliseconds.
+const int kQuickMenuDelayInMs = 100;
+
+gfx::Rect ConvertRectToScreen(aura::Window* window, const gfx::RectF& rect) {
+ gfx::Point origin = gfx::ToRoundedPoint(rect.origin());
+ gfx::Point bottom_right = gfx::ToRoundedPoint(rect.bottom_right());
+
+ aura::Window* root_window = window->GetRootWindow();
+ if (root_window) {
+ aura::client::ScreenPositionClient* screen_position_client =
+ aura::client::GetScreenPositionClient(root_window);
+ if (screen_position_client) {
+ screen_position_client->ConvertPointToScreen(window, &origin);
+ screen_position_client->ConvertPointToScreen(window, &bottom_right);
+ }
+ }
+ return gfx::Rect(origin.x(), origin.y(), bottom_right.x() - origin.x(),
+ bottom_right.y() - origin.y());
+}
+
+} // namespace
+
+// A pre-target event handler for aura::Env which deactivates touch selection on
+// mouse and keyboard events.
+class TouchSelectionControllerClientAura::EnvPreTargetHandler
+ : public ui::EventHandler {
+ public:
+ EnvPreTargetHandler(ui::TouchSelectionController* selection_controller,
+ aura::Window* window);
+ ~EnvPreTargetHandler() override;
+
+ private:
+ // EventHandler:
+ void OnKeyEvent(ui::KeyEvent* event) override;
+ void OnMouseEvent(ui::MouseEvent* event) override;
+ void OnScrollEvent(ui::ScrollEvent* event) override;
+
+ ui::TouchSelectionController* selection_controller_;
+ aura::Window* window_;
+
+ DISALLOW_COPY_AND_ASSIGN(EnvPreTargetHandler);
+};
+
+TouchSelectionControllerClientAura::EnvPreTargetHandler::EnvPreTargetHandler(
+ ui::TouchSelectionController* selection_controller,
+ aura::Window* window)
+ : selection_controller_(selection_controller), window_(window) {
+ aura::Env::GetInstance()->AddPreTargetHandler(this);
+}
+
+TouchSelectionControllerClientAura::EnvPreTargetHandler::
+ ~EnvPreTargetHandler() {
+ aura::Env::GetInstance()->RemovePreTargetHandler(this);
+}
+
+void TouchSelectionControllerClientAura::EnvPreTargetHandler::OnKeyEvent(
+ ui::KeyEvent* event) {
+ DCHECK_NE(ui::TouchSelectionController::INACTIVE,
+ selection_controller_->active_status());
+
+ selection_controller_->HideAndDisallowShowingAutomatically();
+}
+
+void TouchSelectionControllerClientAura::EnvPreTargetHandler::OnMouseEvent(
+ ui::MouseEvent* event) {
+ DCHECK_NE(ui::TouchSelectionController::INACTIVE,
+ selection_controller_->active_status());
+
+ // If mouse events are not enabled, this mouse event is synthesized from a
+ // touch event in which case we don't want to deactivate touch selection.
+ aura::client::CursorClient* cursor_client =
+ aura::client::GetCursorClient(window_->GetRootWindow());
+ if (!cursor_client || cursor_client->IsMouseEventsEnabled())
+ selection_controller_->HideAndDisallowShowingAutomatically();
+}
+
+void TouchSelectionControllerClientAura::EnvPreTargetHandler::OnScrollEvent(
+ ui::ScrollEvent* event) {
+ DCHECK_NE(ui::TouchSelectionController::INACTIVE,
+ selection_controller_->active_status());
+
+ selection_controller_->HideAndDisallowShowingAutomatically();
+}
+
+TouchSelectionControllerClientAura::TouchSelectionControllerClientAura(
+ RenderWidgetHostViewAura* rwhva)
+ : rwhva_(rwhva),
+ quick_menu_timer_(
+ FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kQuickMenuDelayInMs),
+ base::Bind(&TouchSelectionControllerClientAura::ShowQuickMenu,
+ base::Unretained(this)),
+ false),
+ touch_down_(false),
+ scroll_in_progress_(false),
+ handle_drag_in_progress_(false) {
+ DCHECK(rwhva_);
+}
+
+TouchSelectionControllerClientAura::~TouchSelectionControllerClientAura() {
+}
+
+void TouchSelectionControllerClientAura::OnWindowMoved() {
+ UpdateQuickMenu();
+}
+
+void TouchSelectionControllerClientAura::OnTouchDown() {
+ touch_down_ = true;
+ UpdateQuickMenu();
+}
+
+void TouchSelectionControllerClientAura::OnTouchUp() {
+ touch_down_ = false;
+ UpdateQuickMenu();
+}
+
+void TouchSelectionControllerClientAura::OnScrollStarted() {
+ scroll_in_progress_ = true;
+ rwhva_->selection_controller()->SetTemporarilyHidden(true);
+ UpdateQuickMenu();
+}
+
+void TouchSelectionControllerClientAura::OnScrollCompleted() {
+ scroll_in_progress_ = false;
+ rwhva_->selection_controller()->SetTemporarilyHidden(false);
+ UpdateQuickMenu();
+}
+
+bool TouchSelectionControllerClientAura::IsQuickMenuAllowed() const {
+ return !touch_down_ && !scroll_in_progress_ && !handle_drag_in_progress_;
+}
+
+void TouchSelectionControllerClientAura::ShowQuickMenu() {
+ if (!ui::TouchSelectionMenuRunner::GetInstance())
+ return;
+
+ gfx::RectF rect = rwhva_->selection_controller()->GetRectBetweenBounds();
+
+ // Clip rect, which is in |rwhva_|'s window's coordinate space, to client
+ // bounds.
+ gfx::PointF origin = rect.origin();
+ gfx::PointF bottom_right = rect.bottom_right();
+ gfx::Rect client_bounds = rwhva_->GetNativeView()->bounds();
+ origin.SetToMax(client_bounds.origin());
+ bottom_right.SetToMin(client_bounds.bottom_right());
+ if (origin.x() > bottom_right.x() || origin.y() > bottom_right.y())
+ return;
+
+ gfx::Vector2dF diagonal = bottom_right - origin;
+ gfx::SizeF size(diagonal.x(), diagonal.y());
+ gfx::RectF anchor_rect(origin, size);
+
+ // Calculate maximum handle image size;
+ gfx::SizeF max_handle_size =
+ rwhva_->selection_controller()->GetStartHandleRect().size();
+ max_handle_size.SetToMax(
+ rwhva_->selection_controller()->GetEndHandleRect().size());
+
+ aura::Window* parent = rwhva_->GetNativeView();
+ ui::TouchSelectionMenuRunner::GetInstance()->OpenMenu(
+ this, ConvertRectToScreen(parent, anchor_rect),
+ gfx::ToRoundedSize(max_handle_size), parent->GetToplevelWindow());
+}
+
+void TouchSelectionControllerClientAura::UpdateQuickMenu() {
+ bool menu_is_showing =
+ ui::TouchSelectionMenuRunner::GetInstance() &&
+ ui::TouchSelectionMenuRunner::GetInstance()->IsRunning();
+ bool menu_should_show = rwhva_->selection_controller()->active_status() !=
+ ui::TouchSelectionController::INACTIVE &&
+ IsQuickMenuAllowed();
+
+ // Hide the quick menu if there is any. This should happen even if the menu
+ // should be shown again, in order to update its location or content.
+ if (menu_is_showing)
+ ui::TouchSelectionMenuRunner::GetInstance()->CloseMenu();
+ else
+ quick_menu_timer_.Stop();
+
+ // Start timer to show quick menu if necessary.
+ if (menu_should_show) {
+ if (show_quick_menu_immediately_for_test_)
+ ShowQuickMenu();
+ else
+ quick_menu_timer_.Reset();
+ }
+}
+
+bool TouchSelectionControllerClientAura::SupportsAnimation() const {
+ return false;
+}
+
+void TouchSelectionControllerClientAura::SetNeedsAnimate() {
+ NOTREACHED();
+}
+
+void TouchSelectionControllerClientAura::MoveCaret(
+ const gfx::PointF& position) {
+ RenderWidgetHostImpl* host =
+ RenderWidgetHostImpl::From(rwhva_->GetRenderWidgetHost());
+ host->MoveCaret(gfx::ToRoundedPoint(position));
+}
+
+void TouchSelectionControllerClientAura::MoveRangeSelectionExtent(
+ const gfx::PointF& extent) {
+ RenderWidgetHostDelegate* host_delegate =
+ RenderWidgetHostImpl::From(rwhva_->GetRenderWidgetHost())->delegate();
+ if (host_delegate)
+ host_delegate->MoveRangeSelectionExtent(gfx::ToRoundedPoint(extent));
+}
+
+void TouchSelectionControllerClientAura::SelectBetweenCoordinates(
+ const gfx::PointF& base,
+ const gfx::PointF& extent) {
+ RenderWidgetHostDelegate* host_delegate =
+ RenderWidgetHostImpl::From(rwhva_->GetRenderWidgetHost())->delegate();
+ if (host_delegate) {
+ host_delegate->SelectRange(gfx::ToRoundedPoint(base),
+ gfx::ToRoundedPoint(extent));
+ }
+}
+
+void TouchSelectionControllerClientAura::OnSelectionEvent(
+ ui::SelectionEventType event) {
+ switch (event) {
+ case ui::SELECTION_HANDLES_SHOWN:
+ case ui::INSERTION_HANDLE_SHOWN:
+ UpdateQuickMenu();
+ env_pre_target_handler_.reset(new EnvPreTargetHandler(
+ rwhva_->selection_controller(), rwhva_->GetNativeView()));
+ break;
+ case ui::SELECTION_HANDLES_CLEARED:
+ case ui::INSERTION_HANDLE_CLEARED:
+ env_pre_target_handler_.reset();
+ UpdateQuickMenu();
+ break;
+ case ui::SELECTION_HANDLE_DRAG_STARTED:
+ case ui::INSERTION_HANDLE_DRAG_STARTED:
+ handle_drag_in_progress_ = true;
+ UpdateQuickMenu();
+ break;
+ case ui::SELECTION_HANDLE_DRAG_STOPPED:
+ case ui::INSERTION_HANDLE_DRAG_STOPPED:
+ handle_drag_in_progress_ = false;
+ UpdateQuickMenu();
+ break;
+ case ui::SELECTION_HANDLES_MOVED:
+ case ui::INSERTION_HANDLE_MOVED:
+ UpdateQuickMenu();
+ break;
+ case ui::INSERTION_HANDLE_TAPPED:
+ case ui::SELECTION_ESTABLISHED:
+ case ui::SELECTION_DISSOLVED:
+ break;
+ };
+}
+
+scoped_ptr<ui::TouchHandleDrawable>
+TouchSelectionControllerClientAura::CreateDrawable() {
+ return scoped_ptr<ui::TouchHandleDrawable>(
+ new ui::TouchHandleDrawableAura(rwhva_->GetNativeView()));
+}
+
+bool TouchSelectionControllerClientAura::IsCommandIdEnabled(
+ int command_id) const {
+ bool editable = rwhva_->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE;
+ bool readable = rwhva_->GetTextInputType() != ui::TEXT_INPUT_TYPE_PASSWORD;
+ gfx::Range selection_range;
+ rwhva_->GetSelectionRange(&selection_range);
+ bool has_selection = !selection_range.is_empty();
+ switch (command_id) {
+ case IDS_APP_CUT:
+ return editable && readable && has_selection;
+ case IDS_APP_COPY:
+ return readable && has_selection;
+ case IDS_APP_PASTE: {
+ base::string16 result;
+ ui::Clipboard::GetForCurrentThread()->ReadText(
+ ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
+ return editable && !result.empty();
+ }
+ default:
+ return false;
+ }
+}
+
+void TouchSelectionControllerClientAura::ExecuteCommand(int command_id,
+ int event_flags) {
+ rwhva_->selection_controller()->HideAndDisallowShowingAutomatically();
+ RenderWidgetHostDelegate* host_delegate =
+ RenderWidgetHostImpl::From(rwhva_->GetRenderWidgetHost())->delegate();
+ if (!host_delegate)
+ return;
+
+ switch (command_id) {
+ case IDS_APP_CUT:
+ host_delegate->Cut();
+ break;
+ case IDS_APP_COPY:
+ host_delegate->Copy();
+ break;
+ case IDS_APP_PASTE:
+ host_delegate->Paste();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+void TouchSelectionControllerClientAura::RunContextMenu() {
+ gfx::RectF anchor_rect =
+ rwhva_->selection_controller()->GetRectBetweenBounds();
+ gfx::PointF anchor_point =
+ gfx::PointF(anchor_rect.CenterPoint().x(), anchor_rect.y());
+ RenderWidgetHostImpl* host =
+ RenderWidgetHostImpl::From(rwhva_->GetRenderWidgetHost());
+ host->Send(new ViewMsg_ShowContextMenu(host->GetRoutingID(),
+ ui::MENU_SOURCE_TOUCH_EDIT_MENU,
+ gfx::ToRoundedPoint(anchor_point)));
+
+ // Hide selection handles after getting rect-between-bounds from touch
+ // selection controller; otherwise, rect would be empty and the above
+ // calculations would be invalid.
+ rwhva_->selection_controller()->HideAndDisallowShowingAutomatically();
+}
+
+} // namespace content
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_aura.h b/content/browser/renderer_host/input/touch_selection_controller_client_aura.h
new file mode 100644
index 0000000..bb9dd66
--- /dev/null
+++ b/content/browser/renderer_host/input/touch_selection_controller_client_aura.h
@@ -0,0 +1,80 @@
+// Copyright 2015 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_RENDERER_HOST_INPUT_TOUCH_SELECTION_CONTROLLER_CLIENT_AURA_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_SELECTION_CONTROLLER_CLIENT_AURA_H_
+
+#include "base/timer/timer.h"
+#include "content/common/content_export.h"
+#include "ui/touch_selection/touch_selection_controller.h"
+#include "ui/touch_selection/touch_selection_menu_runner.h"
+
+namespace content {
+class RenderWidgetHostViewAura;
+
+// An implementation of |TouchSelectionControllerClient| to be used in Aura's
+// implementation of touch selection for contents.
+class CONTENT_EXPORT TouchSelectionControllerClientAura
+ : public ui::TouchSelectionControllerClient,
+ public ui::TouchSelectionMenuClient {
+ public:
+ explicit TouchSelectionControllerClientAura(RenderWidgetHostViewAura* rwhva);
+ ~TouchSelectionControllerClientAura() override;
+
+ // Called when |rwhva_|'s window is moved, to update the quick menu's
+ // position.
+ void OnWindowMoved();
+
+ // Called on first touch down/last touch up to hide/show the quick menu.
+ void OnTouchDown();
+ void OnTouchUp();
+
+ // Called when touch scroll starts/completes to hide/show touch handles and
+ // the quick menu.
+ void OnScrollStarted();
+ void OnScrollCompleted();
+
+ private:
+ friend class TestTouchSelectionControllerClientAura;
+ class EnvPreTargetHandler;
+
+ bool IsQuickMenuAllowed() const;
+ void ShowQuickMenu();
+ void UpdateQuickMenu();
+
+ // ui::TouchSelectionControllerClient:
+ bool SupportsAnimation() const override;
+ void SetNeedsAnimate() override;
+ void MoveCaret(const gfx::PointF& position) override;
+ void MoveRangeSelectionExtent(const gfx::PointF& extent) override;
+ void SelectBetweenCoordinates(const gfx::PointF& base,
+ const gfx::PointF& extent) override;
+ void OnSelectionEvent(ui::SelectionEventType event) override;
+ scoped_ptr<ui::TouchHandleDrawable> CreateDrawable() override;
+
+ // ui::TouchSelectionMenuClient:
+ bool IsCommandIdEnabled(int command_id) const override;
+ void ExecuteCommand(int command_id, int event_flags) override;
+ void RunContextMenu() override;
+
+ // Not owned, non-null for the lifetime of this object.
+ RenderWidgetHostViewAura* rwhva_;
+
+ base::Timer quick_menu_timer_;
+ bool touch_down_;
+ bool scroll_in_progress_;
+ bool handle_drag_in_progress_;
+
+ bool show_quick_menu_immediately_for_test_;
+
+ // A pre-target event handler for aura::Env which deactivates touch selection
+ // on mouse and keyboard events.
+ scoped_ptr<EnvPreTargetHandler> env_pre_target_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerClientAura);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_SELECTION_CONTROLLER_CLIENT_AURA_H_
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc b/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
new file mode 100644
index 0000000..999b1cd
--- /dev/null
+++ b/content/browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc
@@ -0,0 +1,441 @@
+// Copyright 2015 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/renderer_host/input/touch_selection_controller_client_aura.h"
+
+#include "base/json/json_reader.h"
+#include "base/run_loop.h"
+#include "content/browser/renderer_host/render_widget_host_view_aura.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/touch_selection/touch_selection_controller_test_api.h"
+
+namespace content {
+namespace {
+
+bool JSONToPoint(const std::string& str, gfx::PointF* point) {
+ scoped_ptr<base::Value> value = base::JSONReader::Read(str);
+ if (!value)
+ return false;
+ base::DictionaryValue* root;
+ if (!value->GetAsDictionary(&root))
+ return false;
+ double x, y;
+ if (!root->GetDouble("x", &x))
+ return false;
+ if (!root->GetDouble("y", &y))
+ return false;
+ point->set_x(x);
+ point->set_y(y);
+ return true;
+}
+
+// A mock touch selection menu runner to use whenever a default one is not
+// installed.
+class TestTouchSelectionMenuRunner : public ui::TouchSelectionMenuRunner {
+ public:
+ TestTouchSelectionMenuRunner() : menu_opened_(false) {}
+ ~TestTouchSelectionMenuRunner() override {}
+
+ private:
+ void OpenMenu(ui::TouchSelectionMenuClient* client,
+ const gfx::Rect& anchor_rect,
+ const gfx::Size& handle_image_size,
+ aura::Window* context) override {
+ menu_opened_ = true;
+ }
+
+ void CloseMenu() override { menu_opened_ = false; }
+
+ bool IsRunning() const override { return menu_opened_; }
+
+ bool menu_opened_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestTouchSelectionMenuRunner);
+};
+
+} // namespace
+
+class TestTouchSelectionControllerClientAura
+ : public TouchSelectionControllerClientAura {
+ public:
+ explicit TestTouchSelectionControllerClientAura(
+ RenderWidgetHostViewAura* rwhva)
+ : TouchSelectionControllerClientAura(rwhva),
+ expected_event_(ui::SELECTION_HANDLES_SHOWN) {
+ show_quick_menu_immediately_for_test_ = true;
+ }
+
+ ~TestTouchSelectionControllerClientAura() override {}
+
+ void InitWaitForSelectionEvent(ui::SelectionEventType expected_event) {
+ DCHECK(!run_loop_);
+ expected_event_ = expected_event;
+ run_loop_.reset(new base::RunLoop());
+ }
+
+ void Wait() {
+ DCHECK(run_loop_);
+ run_loop_->Run();
+ run_loop_.reset();
+ }
+
+ private:
+ // TouchSelectionControllerClientAura:
+ void OnSelectionEvent(ui::SelectionEventType event) override {
+ TouchSelectionControllerClientAura::OnSelectionEvent(event);
+ if (run_loop_ && event == expected_event_)
+ run_loop_->Quit();
+ }
+
+ bool IsCommandIdEnabled(int command_id) const override {
+ // Return true so that quick menu has something to show.
+ return true;
+ }
+
+ ui::SelectionEventType expected_event_;
+ scoped_ptr<base::RunLoop> run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestTouchSelectionControllerClientAura);
+};
+
+class TouchSelectionControllerClientAuraTest : public ContentBrowserTest {
+ public:
+ TouchSelectionControllerClientAuraTest() {}
+ ~TouchSelectionControllerClientAuraTest() override {}
+
+ protected:
+ // 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()->GetContentNativeView();
+ content->GetHost()->SetBounds(gfx::Rect(800, 600));
+ }
+
+ bool GetPointInsideText(gfx::PointF* point) {
+ std::string str;
+ if (ExecuteScriptAndExtractString(shell()->web_contents()->GetMainFrame(),
+ "get_point_inside_text()", &str)) {
+ return JSONToPoint(str, point);
+ }
+ return false;
+ }
+
+ bool GetPointInsideTextfield(gfx::PointF* point) {
+ std::string str;
+ if (ExecuteScriptAndExtractString(shell()->web_contents()->GetMainFrame(),
+ "get_point_inside_textfield()", &str)) {
+ return JSONToPoint(str, point);
+ }
+ return false;
+ }
+
+ private:
+ void SetUpOnMainThread() override {
+ ContentBrowserTest::SetUpOnMainThread();
+ if (!ui::TouchSelectionMenuRunner::GetInstance())
+ menu_runner_.reset(new TestTouchSelectionMenuRunner);
+ }
+
+ void TearDownOnMainThread() override {
+ menu_runner_ = nullptr;
+ ContentBrowserTest::TearDownOnMainThread();
+ }
+
+ scoped_ptr<TestTouchSelectionMenuRunner> menu_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerClientAuraTest);
+};
+
+// Tests if long-pressing on a text brings up selection handles and the quick
+// menu properly.
+IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, BasicSelection) {
+ // Set the test page up.
+ ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
+ WebContents* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+ web_contents->GetRenderWidgetHostView());
+ TestTouchSelectionControllerClientAura* selection_controller_client =
+ new TestTouchSelectionControllerClientAura(rwhva);
+ rwhva->SetSelectionControllerClientForTest(
+ make_scoped_ptr(selection_controller_client));
+
+ EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+
+ // Long-press on the text and wait for handles to appear.
+ selection_controller_client->InitWaitForSelectionEvent(
+ ui::SELECTION_HANDLES_SHOWN);
+
+ gfx::PointF point;
+ ASSERT_TRUE(GetPointInsideText(&point));
+ ui::GestureEvent long_press(
+ point.x(), point.y(), 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
+ rwhva->OnGestureEvent(&long_press);
+
+ selection_controller_client->Wait();
+
+ // Check if selection is active and the quick menu is showing.
+ EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+}
+
+// Tests if tapping in a textfield brings up the insertion handle and the quick
+// menu properly.
+IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, BasicInsertion) {
+ // Set the test page up.
+ ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
+ WebContents* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+ web_contents->GetRenderWidgetHostView());
+ TestTouchSelectionControllerClientAura* selection_controller_client =
+ new TestTouchSelectionControllerClientAura(rwhva);
+ rwhva->SetSelectionControllerClientForTest(
+ make_scoped_ptr(selection_controller_client));
+
+ EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+
+ // Tap inside the textfield and wait for the insertion handle to appear.
+ selection_controller_client->InitWaitForSelectionEvent(
+ ui::INSERTION_HANDLE_SHOWN);
+
+ gfx::PointF point;
+ ASSERT_TRUE(GetPointInsideTextfield(&point));
+ ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP);
+ tap_details.set_tap_count(1);
+ ui::GestureEvent tap(point.x(), point.y(), 0, ui::EventTimeForNow(),
+ tap_details);
+ rwhva->OnGestureEvent(&tap);
+
+ selection_controller_client->Wait();
+
+ // Check if insertion is active and the quick menu is showing.
+ EXPECT_EQ(ui::TouchSelectionController::INSERTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+}
+
+// Tests if the quick menu is hidden whenever a touch point is active.
+IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
+ QuickMenuHiddenOnTouch) {
+ // Set the test page up.
+ ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
+ WebContents* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+ web_contents->GetRenderWidgetHostView());
+ TestTouchSelectionControllerClientAura* selection_controller_client =
+ new TestTouchSelectionControllerClientAura(rwhva);
+ rwhva->SetSelectionControllerClientForTest(
+ make_scoped_ptr(selection_controller_client));
+
+ EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+
+ // Long-press on the text and wait for selection handles to appear.
+ selection_controller_client->InitWaitForSelectionEvent(
+ ui::SELECTION_HANDLES_SHOWN);
+
+ gfx::PointF point;
+ ASSERT_TRUE(GetPointInsideText(&point));
+ ui::GestureEvent long_press(
+ point.x(), point.y(), 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
+ rwhva->OnGestureEvent(&long_press);
+
+ selection_controller_client->Wait();
+
+ EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+
+ ui::test::EventGenerator generator(
+ web_contents->GetContentNativeView()->GetRootWindow(),
+ web_contents->GetContentNativeView());
+
+ // Put the first finger down: the quick menu should get hidden.
+ generator.PressTouchId(0);
+ EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+
+ // Put a second finger down: the quick menu should remain hidden.
+ generator.PressTouchId(1);
+ EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+
+ // Lift the first finger up: the quick menu should still remain hidden.
+ generator.ReleaseTouchId(0);
+ EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+
+ // Lift the second finger up: the quick menu should re-appear.
+ generator.ReleaseTouchId(1);
+ EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+}
+
+// Tests if the quick menu and touch handles are hidden during an scroll.
+IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, HiddenOnScroll) {
+ // Set the test page up.
+ ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
+ WebContents* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+ web_contents->GetRenderWidgetHostView());
+ TestTouchSelectionControllerClientAura* selection_controller_client =
+ new TestTouchSelectionControllerClientAura(rwhva);
+ rwhva->SetSelectionControllerClientForTest(
+ make_scoped_ptr(selection_controller_client));
+ ui::TouchSelectionControllerTestApi selection_controller_test_api(
+ rwhva->selection_controller());
+
+ EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+
+ // Long-press on the text and wait for selection handles to appear.
+ selection_controller_client->InitWaitForSelectionEvent(
+ ui::SELECTION_HANDLES_SHOWN);
+
+ gfx::PointF point;
+ ASSERT_TRUE(GetPointInsideText(&point));
+ ui::GestureEvent long_press(
+ point.x(), point.y(), 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
+ rwhva->OnGestureEvent(&long_press);
+
+ selection_controller_client->Wait();
+
+ EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_FALSE(selection_controller_test_api.temporarily_hidden());
+ EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+
+ // Put a finger down: the quick menu should go away, while touch handles stay
+ // there.
+ ui::TouchEvent touch_down(ui::ET_TOUCH_PRESSED, gfx::PointF(10, 10), 0,
+ ui::EventTimeForNow());
+ rwhva->OnTouchEvent(&touch_down);
+ EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_FALSE(selection_controller_test_api.temporarily_hidden());
+ EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+
+ // Start scrolling: touch handles should get hidden, while touch selection is
+ // still active.
+ ui::GestureEvent scroll_begin(
+ 10, 10, 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
+ rwhva->OnGestureEvent(&scroll_begin);
+ EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_TRUE(selection_controller_test_api.temporarily_hidden());
+ EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+
+ // End scrolling: touch handles should re-appear.
+ ui::GestureEvent scroll_end(
+ 10, 10, 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
+ rwhva->OnGestureEvent(&scroll_end);
+ EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_FALSE(selection_controller_test_api.temporarily_hidden());
+ EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+
+ // Lift the finger up: the quick menu should re-appear.
+ ui::TouchEvent touch_up(ui::ET_TOUCH_RELEASED, gfx::PointF(10, 10), 0,
+ ui::EventTimeForNow());
+ rwhva->OnTouchEvent(&touch_up);
+ EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_FALSE(selection_controller_test_api.temporarily_hidden());
+ EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+}
+
+// Tests if touch selection gets deactivated after an overscroll completes.
+IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest,
+ HiddenAfterOverscroll) {
+ // Set the page up.
+ ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
+ WebContents* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+ web_contents->GetRenderWidgetHostView());
+ TestTouchSelectionControllerClientAura* selection_controller_client =
+ new TestTouchSelectionControllerClientAura(rwhva);
+ rwhva->SetSelectionControllerClientForTest(
+ make_scoped_ptr(selection_controller_client));
+
+ EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+
+ // Long-press on the text and wait for touch handles to appear.
+ selection_controller_client->InitWaitForSelectionEvent(
+ ui::SELECTION_HANDLES_SHOWN);
+
+ gfx::PointF point;
+ ASSERT_TRUE(GetPointInsideText(&point));
+ ui::GestureEvent long_press(
+ point.x(), point.y(), 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
+ rwhva->OnGestureEvent(&long_press);
+
+ selection_controller_client->Wait();
+
+ EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+
+ // Scroll such that an overscroll is initiated and wait for it to complete:
+ // touch selection should not be active at the end.
+ selection_controller_client->InitWaitForSelectionEvent(
+ ui::SELECTION_HANDLES_CLEARED);
+
+ ui::GestureEvent scroll_begin(
+ 10, 10, 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
+ rwhva->OnGestureEvent(&scroll_begin);
+
+ ui::GestureEvent scroll_update(
+ 210, 10, 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 200, 0));
+ rwhva->OnGestureEvent(&scroll_update);
+
+ ui::GestureEvent scroll_end(
+ 210, 10, 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
+ rwhva->OnGestureEvent(&scroll_end);
+
+ selection_controller_client->Wait();
+
+ EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
+ rwhva->selection_controller()->active_status());
+ EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+}
+
+} // namespace content
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 3947821..2edeacf 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -30,6 +30,8 @@
#include "content/browser/renderer_host/compositor_resize_lock_aura.h"
#include "content/browser/renderer_host/dip_util.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target_aura.h"
+#include "content/browser/renderer_host/input/touch_selection_controller_client_aura.h"
+#include "content/browser/renderer_host/input/ui_touch_selection_helper.h"
#include "content/browser/renderer_host/input/web_input_event_util.h"
#include "content/browser/renderer_host/overscroll_controller.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
@@ -71,6 +73,7 @@
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
+#include "ui/events/gesture_detection/gesture_configuration.h"
#include "ui/events/gestures/gesture_recognizer.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/display.h"
@@ -78,6 +81,7 @@
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/skia_util.h"
+#include "ui/touch_selection/touch_selection_controller.h"
#include "ui/wm/public/activation_client.h"
#include "ui/wm/public/scoped_tooltip_disabler.h"
#include "ui/wm/public/tooltip_client.h"
@@ -462,7 +466,6 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host,
showing_context_menu_(false),
#endif
has_snapped_to_boundary_(false),
- touch_editing_client_(NULL),
is_guest_view_hack_(is_guest_view_hack),
begin_frame_observer_proxy_(this),
weak_ptr_factory_(this) {
@@ -480,6 +483,10 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host,
bool overscroll_enabled = base::CommandLine::ForCurrentProcess()->
GetSwitchValueASCII(switches::kOverscrollHistoryNavigation) != "0";
SetOverscrollControllerEnabled(overscroll_enabled);
+
+ selection_controller_client_.reset(
+ new TouchSelectionControllerClientAura(this));
+ CreateSelectionController();
}
////////////////////////////////////////////////////////////////////////////////
@@ -965,8 +972,6 @@ void RenderWidgetHostViewAura::TextInputTypeChanged(
text_input_flags_ = flags;
if (GetInputMethod())
GetInputMethod()->OnTextInputTypeChanged(this);
- if (touch_editing_client_)
- touch_editing_client_->OnTextInputTypeChanged(text_input_type_);
}
}
@@ -1083,11 +1088,6 @@ void RenderWidgetHostViewAura::SelectionBoundsChanged(
selection_focus_ = focus_bound;
if (GetInputMethod())
GetInputMethod()->OnCaretBoundsChanged(this);
-
- if (touch_editing_client_) {
- touch_editing_client_->OnSelectionOrCursorChanged(
- anchor_bound, focus_bound);
- }
}
void RenderWidgetHostViewAura::CopyFromCompositingSurface(
@@ -1178,6 +1178,10 @@ void RenderWidgetHostViewAura::OnSwapCompositorFrame(
frame->metadata.device_scale_factor,
frame->metadata.latency_info,
&frame->metadata.satisfies_sequences);
+ SelectionUpdated(frame->metadata.selection.is_editable,
+ frame->metadata.selection.is_empty_text_form_control,
+ ConvertSelectionBound(frame->metadata.selection.start),
+ ConvertSelectionBound(frame->metadata.selection.end));
return;
}
@@ -1190,8 +1194,7 @@ void RenderWidgetHostViewAura::OnSwapCompositorFrame(
}
void RenderWidgetHostViewAura::DidStopFlinging() {
- if (touch_editing_client_)
- touch_editing_client_->DidStopFlinging();
+ selection_controller_client_->OnScrollCompleted();
}
#if defined(OS_WIN)
@@ -1271,9 +1274,6 @@ void RenderWidgetHostViewAura::WheelEventAck(
void RenderWidgetHostViewAura::GestureEventAck(
const blink::WebGestureEvent& event,
InputEventAckState ack_result) {
- if (touch_editing_client_)
- touch_editing_client_->GestureEventAck(event.type);
-
if (overscroll_controller_) {
overscroll_controller_->ReceivedEventACK(
event, (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result));
@@ -1675,9 +1675,8 @@ gfx::Rect RenderWidgetHostViewAura::ConvertRectFromScreen(
}
gfx::Rect RenderWidgetHostViewAura::GetCaretBounds() const {
- gfx::Rect rect =
- ui::RectBetweenSelectionBounds(selection_anchor_, selection_focus_);
- return ConvertRectToScreen(rect);
+ return ConvertRectToScreen(
+ ui::RectBetweenSelectionBounds(selection_anchor_, selection_focus_));
}
bool RenderWidgetHostViewAura::GetCompositionCharacterBounds(
@@ -1861,8 +1860,6 @@ bool RenderWidgetHostViewAura::CanFocus() {
void RenderWidgetHostViewAura::OnCaptureLost() {
host_->LostCapture();
- if (touch_editing_client_)
- touch_editing_client_->EndTouchEditing(false);
}
void RenderWidgetHostViewAura::OnPaint(const ui::PaintContext& context) {
@@ -1945,8 +1942,6 @@ void RenderWidgetHostViewAura::GetHitTestMask(gfx::Path* mask) const {
void RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event) {
TRACE_EVENT0("input", "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);
@@ -1993,9 +1988,6 @@ void RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event) {
void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnMouseEvent");
- if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event))
- return;
-
if (mouse_locked_) {
aura::client::CursorClient* cursor_client =
aura::client::GetCursorClient(window_->GetRootWindow());
@@ -2159,8 +2151,6 @@ void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
void RenderWidgetHostViewAura::OnScrollEvent(ui::ScrollEvent* event) {
TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnScrollEvent");
- if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event))
- return;
if (event->type() == ui::ET_SCROLL) {
#if !defined(OS_WIN)
@@ -2189,8 +2179,8 @@ void RenderWidgetHostViewAura::OnScrollEvent(ui::ScrollEvent* event) {
void RenderWidgetHostViewAura::OnTouchEvent(ui::TouchEvent* event) {
TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnTouchEvent");
- if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event))
- return;
+
+ bool had_no_pointer = !pointer_state_.GetPointerCount();
// Update the touch event first.
if (!pointer_state_.OnTouch(*event)) {
@@ -2198,10 +2188,24 @@ void RenderWidgetHostViewAura::OnTouchEvent(ui::TouchEvent* event) {
return;
}
- blink::WebTouchEvent touch_event = ui::CreateWebTouchEventFromMotionEvent(
- pointer_state_, event->may_cause_scrolling());
+ blink::WebTouchEvent touch_event;
+ bool handled = selection_controller_->WillHandleTouchEvent(pointer_state_);
+ if (handled) {
+ event->SetHandled();
+ } else {
+ touch_event = ui::CreateWebTouchEventFromMotionEvent(
+ pointer_state_, event->may_cause_scrolling());
+ }
pointer_state_.CleanupRemovedTouchPoints(*event);
+ if (handled)
+ return;
+
+ if (had_no_pointer)
+ selection_controller_client_->OnTouchDown();
+ if (!pointer_state_.GetPointerCount())
+ selection_controller_client_->OnTouchUp();
+
// It is important to always mark events as being handled asynchronously when
// they are forwarded. This ensures that the current event does not get
// processed by the gesture recognizer before events currently awaiting
@@ -2216,6 +2220,7 @@ void RenderWidgetHostViewAura::OnTouchEvent(ui::TouchEvent* event) {
void RenderWidgetHostViewAura::OnGestureEvent(ui::GestureEvent* event) {
TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnGestureEvent");
+
if ((event->type() == ui::ET_GESTURE_PINCH_BEGIN ||
event->type() == ui::ET_GESTURE_PINCH_UPDATE ||
event->type() == ui::ET_GESTURE_PINCH_END) && !pinch_zoom_enabled_) {
@@ -2223,7 +2228,8 @@ void RenderWidgetHostViewAura::OnGestureEvent(ui::GestureEvent* event) {
return;
}
- if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event))
+ HandleGestureForTouchSelection(event);
+ if (event->handled())
return;
// Confirm existing composition text on TAP gesture, to make sure the input
@@ -2316,8 +2322,7 @@ void RenderWidgetHostViewAura::OnWindowFocused(aura::Window* gained_focus,
DetachFromInputMethod();
- if (touch_editing_client_)
- touch_editing_client_->EndTouchEditing(false);
+ selection_controller_->HideAndDisallowShowingAutomatically();
if (overscroll_controller_)
overscroll_controller_->Cancel();
@@ -2374,9 +2379,8 @@ void RenderWidgetHostViewAura::OnHostMoved(const aura::WindowTreeHost* host,
// RenderWidgetHostViewAura, private:
RenderWidgetHostViewAura::~RenderWidgetHostViewAura() {
- if (touch_editing_client_)
- touch_editing_client_->OnViewDestroyed();
-
+ selection_controller_.reset();
+ selection_controller_client_.reset();
delegated_frame_host_.reset();
window_observer_.reset();
if (window_->GetHost())
@@ -2553,6 +2557,12 @@ void RenderWidgetHostViewAura::OnShowContextMenu() {
#endif
}
+void RenderWidgetHostViewAura::SetSelectionControllerClientForTest(
+ scoped_ptr<TouchSelectionControllerClientAura> client) {
+ selection_controller_client_.swap(client);
+ CreateSelectionController();
+}
+
void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect) {
SnapToPhysicalPixelBoundary();
// Don't recursively call SetBounds if this bounds update is the result of
@@ -2561,10 +2571,6 @@ void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect) {
window_->SetBounds(rect);
host_->WasResized();
delegated_frame_host_->WasResized();
- if (touch_editing_client_) {
- touch_editing_client_->OnSelectionOrCursorChanged(selection_anchor_,
- selection_focus_);
- }
#if defined(OS_WIN)
// Create the legacy dummy window which corresponds to the bounds of the
// webcontents. This will be passed as the container window for windowless
@@ -2707,6 +2713,51 @@ void RenderWidgetHostViewAura::ForwardKeyboardEvent(
host_->ForwardKeyboardEvent(event);
}
+void RenderWidgetHostViewAura::SelectionUpdated(bool is_editable,
+ bool is_empty_text_form_control,
+ const ui::SelectionBound& start,
+ const ui::SelectionBound& end) {
+ selection_controller_->OnSelectionEditable(is_editable);
+ selection_controller_->OnSelectionEmpty(is_empty_text_form_control);
+ selection_controller_->OnSelectionBoundsChanged(start, end);
+}
+
+void RenderWidgetHostViewAura::CreateSelectionController() {
+ ui::TouchSelectionController::Config tsc_config;
+ tsc_config.tap_timeout = base::TimeDelta::FromMilliseconds(
+ ui::GestureConfiguration::GetInstance()->show_press_delay_in_ms());
+ tsc_config.tap_slop = ui::GestureConfiguration::GetInstance()
+ ->max_touch_move_in_pixels_for_click();
+ tsc_config.show_on_tap_for_empty_editable = true;
+ tsc_config.enable_longpress_drag_selection = false;
+ selection_controller_.reset(new ui::TouchSelectionController(
+ selection_controller_client_.get(), tsc_config));
+}
+
+void RenderWidgetHostViewAura::HandleGestureForTouchSelection(
+ ui::GestureEvent* event) {
+ switch (event->type()) {
+ case ui::ET_GESTURE_LONG_PRESS:
+ if (selection_controller_->WillHandleLongPressEvent(
+ base::TimeTicks() + event->time_stamp(), event->location_f())) {
+ event->SetHandled();
+ }
+ break;
+ case ui::ET_GESTURE_TAP:
+ if (selection_controller_->WillHandleTapEvent(event->location_f()))
+ event->SetHandled();
+ break;
+ case ui::ET_GESTURE_SCROLL_BEGIN:
+ selection_controller_client_->OnScrollStarted();
+ break;
+ case ui::ET_GESTURE_SCROLL_END:
+ selection_controller_client_->OnScrollCompleted();
+ break;
+ default:
+ break;
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// DelegatedFrameHost, public:
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 e0f76f1..b3d913f 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -31,7 +31,6 @@
#include "ui/aura/window_tree_host_observer.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/touch/selection_bound.h"
-#include "ui/base/touch/touch_editing_controller.h"
#include "ui/events/gestures/motion_event_aura.h"
#include "ui/gfx/display_observer.h"
#include "ui/gfx/geometry/insets.h"
@@ -65,6 +64,7 @@ class CompositorLock;
class InputMethod;
class LocatedEvent;
class Texture;
+class TouchSelectionController;
}
namespace content {
@@ -76,6 +76,7 @@ class OverscrollController;
class RenderFrameHostImpl;
class RenderWidgetHostImpl;
class RenderWidgetHostView;
+class TouchSelectionControllerClientAura;
// RenderWidgetHostView class hierarchy described in render_widget_host_view.h.
class CONTENT_EXPORT RenderWidgetHostViewAura
@@ -90,49 +91,6 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
public aura::client::FocusChangeObserver,
public aura::client::CursorClientObserver {
public:
- // 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. |quick|
- // determines whether the handles should fade out quickly or slowly.
- virtual void EndTouchEditing(bool quick) = 0;
-
- // Notifies the client that the selection bounds need to be updated.
- virtual void OnSelectionOrCursorChanged(
- const ui::SelectionBound& anchor,
- const ui::SelectionBound& 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;
-
- // Notifies the client that the fling has ended, so it can activate touch
- // editing if needed.
- virtual void DidStopFlinging() = 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_touch_editing_client(TouchEditingClient* client) {
- touch_editing_client_ = client;
- }
-
// When |is_guest_view_hack| is true, this view isn't really the view for
// the |widget|, a RenderWidgetHostViewGuest is.
//
@@ -344,6 +302,14 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
void SnapToPhysicalPixelBoundary();
+ ui::TouchSelectionController* selection_controller() const {
+ return selection_controller_.get();
+ }
+
+ TouchSelectionControllerClientAura* selection_controller_client() const {
+ return selection_controller_client_.get();
+ }
+
OverscrollController* overscroll_controller() const {
return overscroll_controller_.get();
}
@@ -351,6 +317,11 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// Called when the context menu is about to be displayed.
void OnShowContextMenu();
+ // Used in tests to set a mock client for touch selection controller. It will
+ // create a new touch selection controller for the new client.
+ void SetSelectionControllerClientForTest(
+ scoped_ptr<TouchSelectionControllerClientAura> client);
+
protected:
~RenderWidgetHostViewAura() override;
@@ -510,6 +481,20 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// Called when the parent window hierarchy for our window changes.
void ParentHierarchyChanged();
+ // Helper function to be called whenever new selection information is
+ // received. It will update selection controller.
+ void SelectionUpdated(bool is_editable,
+ bool is_empty_text_form_control,
+ const ui::SelectionBound& start,
+ const ui::SelectionBound& end);
+
+ // Helper function to create a selection controller.
+ void CreateSelectionController();
+
+ // Performs gesture handling needed for touch text selection. Sets event as
+ // handled if it should not be further processed.
+ void HandleGestureForTouchSelection(ui::GestureEvent* event);
+
// The model object.
RenderWidgetHostImpl* host_;
@@ -647,7 +632,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
bool has_snapped_to_boundary_;
- TouchEditingClient* touch_editing_client_;
+ scoped_ptr<TouchSelectionControllerClientAura> selection_controller_client_;
+ scoped_ptr<ui::TouchSelectionController> selection_controller_;
scoped_ptr<OverscrollController> overscroll_controller_;