diff options
author | mohsen <mohsen@chromium.org> | 2015-07-30 09:41:00 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-07-30 16:42:16 +0000 |
commit | 2a5e3624e4d0b78bfe5f5a3d40f5a98730291056 (patch) | |
tree | 6bc5339c5ac557877f6d5fe6f9575dc3c2e37799 | |
parent | c7a6ce3e5957485bb9128dd74483611c8bcfc029 (diff) | |
download | chromium_src-2a5e3624e4d0b78bfe5f5a3d40f5a98730291056.zip chromium_src-2a5e3624e4d0b78bfe5f5a3d40f5a98730291056.tar.gz chromium_src-2a5e3624e4d0b78bfe5f5a3d40f5a98730291056.tar.bz2 |
Implement Aura side of unified touch text selection for contents
This is the first part of unified touch text selection for Aura which
implements it using the new ui::TouchSelectionController for contents.
Selection updates are now coming from swap-compositor-frame IPC message
instead of selection-bounds-changed IPC message.
This CL also replaces TouchEditableImplAura (owned by
WebContentsViewAura) with ui::TouchSelectionController (owned by
RenderWidgetHostViewAura) for which a client implementation is provided
in TouchSelectionControllerClientAura.
Note that at the moment we are unable to remove selection-bounds-changed
IPC message completely as it is also used by IME and the new path is not
yet working properly inside <webview> (which is being worked on).
Next part would be using ui::TouchSelectionController to implement
unified touch text selection for Views textfields.
COLLABORATOR=mfomitchev
BUG=399721
Review URL: https://codereview.chromium.org/698253004
Cr-Commit-Position: refs/heads/master@{#341134}
22 files changed, 1170 insertions, 1323 deletions
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 6281b91..dac2fb1 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn @@ -417,6 +417,8 @@ source_set("browser") { "renderer_host/compositor_resize_lock_aura.h", "renderer_host/input/synthetic_gesture_target_aura.cc", "renderer_host/input/synthetic_gesture_target_aura.h", + "renderer_host/input/touch_selection_controller_client_aura.cc", + "renderer_host/input/touch_selection_controller_client_aura.h", "renderer_host/native_web_keyboard_event_aura.cc", "renderer_host/render_widget_host_view_aura.cc", "renderer_host/render_widget_host_view_aura.h", @@ -434,8 +436,6 @@ source_set("browser") { "web_contents/aura/overscroll_window_delegate.h", "web_contents/aura/shadow_layer_delegate.cc", "web_contents/aura/shadow_layer_delegate.h", - "web_contents/touch_editable_impl_aura.cc", - "web_contents/touch_editable_impl_aura.h", "web_contents/web_contents_view_aura.cc", "web_contents/web_contents_view_aura.h", ] 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_; diff --git a/content/browser/web_contents/touch_editable_impl_aura.cc b/content/browser/web_contents/touch_editable_impl_aura.cc deleted file mode 100644 index 622b490..0000000 --- a/content/browser/web_contents/touch_editable_impl_aura.cc +++ /dev/null @@ -1,385 +0,0 @@ -// 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 "content/browser/renderer_host/render_widget_host_impl.h" -#include "content/browser/renderer_host/render_widget_host_view_aura.h" -#include "content/browser/web_contents/web_contents_impl.h" -#include "content/common/view_messages.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/render_widget_host.h" -#include "ui/aura/client/screen_position_client.h" -#include "ui/aura/window.h" -#include "ui/aura/window_tree_host.h" -#include "ui/base/clipboard/clipboard.h" -#include "ui/base/touch/selection_bound.h" -#include "ui/base/ui_base_switches_util.h" -#include "ui/gfx/range/range.h" -#include "ui/strings/grit/ui_strings.h" -#include "ui/wm/public/activation_client.h" - -namespace content { - -//////////////////////////////////////////////////////////////////////////////// -// TouchEditableImplAura, public: - -TouchEditableImplAura::~TouchEditableImplAura() { - Cleanup(); -} - -// static -TouchEditableImplAura* TouchEditableImplAura::Create() { - if (switches::IsTouchEditingEnabled()) - return new TouchEditableImplAura(); - 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_ || !rwhva_->HasFocus()) - return; - - if (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE || - selection_anchor_ != selection_focus_) { - if (touch_selection_controller_) - touch_selection_controller_->SelectionChanged(); - } else { - EndTouchEditing(false); - } -} - -void TouchEditableImplAura::OverscrollStarted() { - overscroll_in_progress_ = true; -} - -void TouchEditableImplAura::OverscrollCompleted() { - overscroll_in_progress_ = false; - StartTouchEditingIfNecessary(); -} - -//////////////////////////////////////////////////////////////////////////////// -// TouchEditableImplAura, RenderWidgetHostViewAura::TouchEditingClient -// implementation: - -void TouchEditableImplAura::StartTouchEditing() { - if (!rwhva_ || !rwhva_->HasFocus()) - return; - - if (!touch_selection_controller_) { - touch_selection_controller_.reset( - ui::TouchEditingControllerDeprecated::Create(this)); - } - if (touch_selection_controller_) - touch_selection_controller_->SelectionChanged(); -} - -void TouchEditableImplAura::EndTouchEditing(bool quick) { - if (touch_selection_controller_) { - if (touch_selection_controller_->IsHandleDragInProgress()) { - touch_selection_controller_->SelectionChanged(); - } else { - selection_gesture_in_process_ = false; - touch_selection_controller_->HideHandles(quick); - touch_selection_controller_.reset(); - } - } -} - -void TouchEditableImplAura::OnSelectionOrCursorChanged( - const ui::SelectionBound& anchor, - const ui::SelectionBound& focus) { - selection_anchor_ = anchor; - selection_focus_ = focus; - - // If touch editing handles were not visible, we bring them up only if the - // current event is a gesture event, no scroll/fling/overscoll is in progress, - // and there is non-zero selection on the page - if (selection_gesture_in_process_ && !scroll_in_progress_ && - !overscroll_in_progress_ && selection_anchor_ != selection_focus_) { - StartTouchEditing(); - selection_gesture_in_process_ = false; - } - - UpdateEditingController(); -} - -void TouchEditableImplAura::OnTextInputTypeChanged(ui::TextInputType type) { - text_input_type_ = type; -} - -bool TouchEditableImplAura::HandleInputEvent(const ui::Event* event) { - DCHECK(rwhva_); - if (!event->IsGestureEvent()) { - // Ignore all non-gesture events. Non-gesture events that can deactivate - // touch editing are handled in TouchSelectionControllerImpl. - return false; - } - - const ui::GestureEvent* gesture_event = - static_cast<const ui::GestureEvent*>(event); - switch (event->type()) { - case ui::ET_GESTURE_TAP: - // When the user taps, we want to show touch editing handles if user - // tapped on selected text. - if (gesture_event->details().tap_count() == 1 && - selection_anchor_ != selection_focus_) { - gfx::Rect selection_rect = - ui::RectBetweenSelectionBounds(selection_anchor_, selection_focus_); - // When tap is on selection, show handles and mark event as handled only - // if handles are not present or text is not editable. Otherwise, do not - // set event as handles so that event is forwarded to the renderer to - // update selection/cursor. - if (selection_rect.Contains(gesture_event->location()) && - (text_input_type_ == ui::TEXT_INPUT_TYPE_NONE || - !touch_selection_controller_)) { - StartTouchEditing(); - return true; - } - } - // For single taps, not inside selected region, we want to show handles - // only when the tap is on an already focused textfield. - textfield_was_focused_on_tap_ = - gesture_event->details().tap_count() == 1 && - text_input_type_ != ui::TEXT_INPUT_TYPE_NONE; - break; - case ui::ET_GESTURE_LONG_PRESS: - selection_gesture_in_process_ = true; - break; - case ui::ET_GESTURE_SCROLL_BEGIN: - scroll_in_progress_ = true;; - // We need to hide selection handles during scroll (including fling and - // overscroll), but they should be re-activated after scrolling if: - // - an existing scroll decided that handles should be shown after - // scrolling; or - // - the gesture in progress is going to end in selection; or - // - selection handles are currently active. - handles_hidden_due_to_scroll_ = handles_hidden_due_to_scroll_ || - selection_gesture_in_process_ || - touch_selection_controller_ != NULL; - selection_gesture_in_process_ = false; - EndTouchEditing(true); - break; - case ui::ET_GESTURE_SCROLL_END: - scroll_in_progress_ = false; - StartTouchEditingIfNecessary(); - break; - default: - break; - } - return false; -} - -void TouchEditableImplAura::GestureEventAck(int gesture_event_type) { - DCHECK(rwhva_); - if (gesture_event_type == blink::WebInputEvent::GestureTap && - text_input_type_ != ui::TEXT_INPUT_TYPE_NONE && - textfield_was_focused_on_tap_) { - StartTouchEditing(); - UpdateEditingController(); - } -} - -void TouchEditableImplAura::DidStopFlinging() { - scroll_in_progress_ = false; - StartTouchEditingIfNecessary(); -} - -void TouchEditableImplAura::OnViewDestroyed() { - Cleanup(); -} - -//////////////////////////////////////////////////////////////////////////////// -// TouchEditableImplAura, ui::TouchEditable implementation: - -void TouchEditableImplAura::SelectRect(const gfx::Point& start, - const gfx::Point& end) { - RenderWidgetHost* host = rwhva_->GetRenderWidgetHost(); - RenderViewHost* rvh = RenderViewHost::From(host); - WebContentsImpl* wc = - static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(rvh)); - wc->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(ui::SelectionBound* anchor, - ui::SelectionBound* focus) { - *anchor = selection_anchor_; - *focus = selection_focus_; -} - -gfx::Rect TouchEditableImplAura::GetBounds() { - return rwhva_ ? gfx::Rect(rwhva_->GetNativeView()->bounds().size()) : - gfx::Rect(); -} - -gfx::NativeView TouchEditableImplAura::GetNativeView() const { - return rwhva_ ? rwhva_->GetNativeView()->GetToplevelWindow() : 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; - gfx::Point point = anchor; - ConvertPointFromScreen(&point); - RenderWidgetHost* host = rwhva_->GetRenderWidgetHost(); - host->Send(new ViewMsg_ShowContextMenu( - host->GetRoutingID(), ui::MENU_SOURCE_TOUCH_EDIT_MENU, point)); - EndTouchEditing(false); -} - -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; - 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(); - } - 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) { - RenderWidgetHost* host = rwhva_->GetRenderWidgetHost(); - RenderViewHost* rvh = RenderViewHost::From(host); - WebContents* wc = WebContents::FromRenderViewHost(rvh); - - switch (command_id) { - case IDS_APP_CUT: - wc->Cut(); - break; - case IDS_APP_COPY: - wc->Copy(); - break; - case IDS_APP_PASTE: - wc->Paste(); - break; - case IDS_APP_DELETE: - wc->Delete(); - break; - case IDS_APP_SELECT_ALL: - wc->SelectAll(); - break; - default: - NOTREACHED(); - break; - } - EndTouchEditing(false); -} - -void TouchEditableImplAura::DestroyTouchSelection() { - EndTouchEditing(false); -} - -//////////////////////////////////////////////////////////////////////////////// -// TouchEditableImplAura, private: - -TouchEditableImplAura::TouchEditableImplAura() - : text_input_type_(ui::TEXT_INPUT_TYPE_NONE), - rwhva_(NULL), - selection_gesture_in_process_(false), - handles_hidden_due_to_scroll_(false), - scroll_in_progress_(false), - overscroll_in_progress_(false), - textfield_was_focused_on_tap_(false) { -} - -void TouchEditableImplAura::StartTouchEditingIfNecessary() { - // If there is no scrolling left in progress, show selection handles if they - // were hidden due to scroll and there is a selection. - if (!scroll_in_progress_ && !overscroll_in_progress_ && - handles_hidden_due_to_scroll_ && - (selection_anchor_ != selection_focus_ || - text_input_type_ != ui::TEXT_INPUT_TYPE_NONE)) { - StartTouchEditing(); - UpdateEditingController(); - handles_hidden_due_to_scroll_ = false; - } -} - -void TouchEditableImplAura::Cleanup() { - if (rwhva_) { - rwhva_->set_touch_editing_client(NULL); - rwhva_ = NULL; - } - text_input_type_ = ui::TEXT_INPUT_TYPE_NONE; - EndTouchEditing(true); - selection_gesture_in_process_ = false; - handles_hidden_due_to_scroll_ = false; - scroll_in_progress_ = false; - overscroll_in_progress_ = false; -} - -} // namespace content diff --git a/content/browser/web_contents/touch_editable_impl_aura.h b/content/browser/web_contents/touch_editable_impl_aura.h deleted file mode 100644 index d7516f6..0000000 --- a/content/browser/web_contents/touch_editable_impl_aura.h +++ /dev/null @@ -1,116 +0,0 @@ -// 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 <queue> - -#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/geometry/point.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/native_widget_types.h" - -namespace ui { -class Accelerator; -} - -namespace content { -class TouchEditableImplAuraTest; - -// Aura specific implementation of ui::TouchEditable for a RenderWidgetHostView. -class CONTENT_EXPORT TouchEditableImplAura - : public ui::TouchEditable, - public NON_EXPORTED_BASE(RenderWidgetHostViewAura::TouchEditingClient) { - public: - ~TouchEditableImplAura() override; - - 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(); - - virtual void OverscrollStarted(); - virtual void OverscrollCompleted(); - - // Overridden from RenderWidgetHostViewAura::TouchEditingClient. - void StartTouchEditing() override; - void EndTouchEditing(bool quick) override; - void OnSelectionOrCursorChanged(const ui::SelectionBound& anchor, - const ui::SelectionBound& focus) override; - void OnTextInputTypeChanged(ui::TextInputType type) override; - bool HandleInputEvent(const ui::Event* event) override; - void GestureEventAck(int gesture_event_type) override; - void DidStopFlinging() override; - void OnViewDestroyed() override; - - // Overridden from ui::TouchEditable: - void SelectRect(const gfx::Point& start, const gfx::Point& end) override; - void MoveCaretTo(const gfx::Point& point) override; - void GetSelectionEndPoints(ui::SelectionBound* anchor, - ui::SelectionBound* focus) override; - gfx::Rect GetBounds() override; - gfx::NativeView GetNativeView() const override; - void ConvertPointToScreen(gfx::Point* point) override; - void ConvertPointFromScreen(gfx::Point* point) override; - bool DrawsHandles() override; - void OpenContextMenu(const gfx::Point& anchor) override; - bool IsCommandIdChecked(int command_id) const override; - bool IsCommandIdEnabled(int command_id) const override; - bool GetAcceleratorForCommandId(int command_id, - ui::Accelerator* accelerator) override; - void ExecuteCommand(int command_id, int event_flags) override; - void DestroyTouchSelection() override; - - protected: - TouchEditableImplAura(); - - private: - friend class TouchEditableImplAuraTest; - - // A convenience function that is called after scroll/fling/overscroll ends to - // re-activate touch selection if necessary. - void StartTouchEditingIfNecessary(); - - void Cleanup(); - - // Bounds for the selection. - ui::SelectionBound selection_anchor_; - ui::SelectionBound selection_focus_; - - // The current text input type. - ui::TextInputType text_input_type_; - - RenderWidgetHostViewAura* rwhva_; - scoped_ptr<ui::TouchEditingControllerDeprecated> touch_selection_controller_; - - // True if |rwhva_| is currently handling a gesture that could result in a - // change in selection (long press, double tap or triple tap). - bool selection_gesture_in_process_; - - // Set to true if handles are hidden when user is scrolling. Used to determine - // whether to re-show handles after a scrolling session. - bool handles_hidden_due_to_scroll_; - - // Keep track of scrolls/overscrolls in progress. - bool scroll_in_progress_; - bool overscroll_in_progress_; - - // Used to track if a textfield was focused when the current tap gesture - // happened. - bool textfield_was_focused_on_tap_; - - 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 deleted file mode 100644 index 9ee1bbf..0000000 --- a/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc +++ /dev/null @@ -1,638 +0,0 @@ -// 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/strings/utf_string_conversions.h" -#include "base/test/test_timeouts.h" -#include "base/values.h" -#include "content/browser/web_contents/web_contents_impl.h" -#include "content/browser/web_contents/web_contents_view_aura.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/common/content_switches.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/public/test/test_utils.h" -#include "content/shell/browser/shell.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" -#include "ui/aura/window.h" -#include "ui/aura/window_tree_host.h" -#include "ui/base/ui_base_switches.h" -#include "ui/compositor/scoped_animation_duration_scale_mode.h" -#include "ui/events/event_utils.h" -#include "ui/events/test/event_generator.h" -#include "ui/wm/core/default_screen_position_client.h" - -using blink::WebInputEvent; - -namespace content { - -class TestTouchEditableImplAura : public TouchEditableImplAura { - public: - TestTouchEditableImplAura() - : overscroll_started_callback_arrived_(false), - waiting_for_overscroll_started_callback_(false), - overscroll_completed_callback_arrived_(false), - waiting_for_overscroll_completed_callback_(false), - selection_changed_callback_arrived_(false), - waiting_for_selection_changed_callback_(false), - waiting_for_gesture_ack_type_(WebInputEvent::Undefined), - last_gesture_ack_type_(WebInputEvent::Undefined), - fling_stop_callback_arrived_(false), - waiting_for_fling_stop_callback_(false) {} - - virtual void Reset() { - overscroll_started_callback_arrived_ = false; - waiting_for_overscroll_started_callback_ = false; - overscroll_completed_callback_arrived_ = false; - waiting_for_overscroll_completed_callback_ = false; - selection_changed_callback_arrived_ = false; - waiting_for_selection_changed_callback_ = false; - waiting_for_gesture_ack_type_ = WebInputEvent::Undefined; - last_gesture_ack_type_ = WebInputEvent::Undefined; - fling_stop_callback_arrived_ = false; - waiting_for_fling_stop_callback_ = false; - } - - void OverscrollStarted() override { - overscroll_started_callback_arrived_ = true; - TouchEditableImplAura::OverscrollStarted(); - if (waiting_for_overscroll_started_callback_) - overscroll_started_wait_run_loop_->Quit(); -} - - void WaitForOverscrollStartedCallback() { - // Doesn't make sense to call more that once without resetting. - CHECK(!waiting_for_overscroll_started_callback_); - waiting_for_overscroll_started_callback_ = true; - if (overscroll_started_callback_arrived_) - return; - overscroll_started_wait_run_loop_.reset(new base::RunLoop()); - overscroll_started_wait_run_loop_->Run(); - } - - void OverscrollCompleted() override { - overscroll_completed_callback_arrived_ = true; - TouchEditableImplAura::OverscrollCompleted(); - if (waiting_for_overscroll_completed_callback_) - overscroll_completed_wait_run_loop_->Quit(); - } - - void WaitForOverscrollCompletedCallback() { - // Doesn't make sense to call more that once without resetting. - CHECK(!waiting_for_overscroll_completed_callback_); - waiting_for_overscroll_completed_callback_ = true; - if (overscroll_completed_callback_arrived_) - return; - overscroll_completed_wait_run_loop_.reset(new base::RunLoop()); - overscroll_completed_wait_run_loop_->Run(); - } - - void OnSelectionOrCursorChanged(const ui::SelectionBound& anchor, - const ui::SelectionBound& 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 { - last_gesture_ack_type_ = - static_cast<WebInputEvent::Type>(gesture_event_type); - TouchEditableImplAura::GestureEventAck(gesture_event_type); - if (waiting_for_gesture_ack_type_ == gesture_event_type) - gesture_ack_wait_run_loop_->Quit(); - } - - void DidStopFlinging() override { - fling_stop_callback_arrived_ = true; - TouchEditableImplAura::DidStopFlinging(); - if (waiting_for_fling_stop_callback_) - fling_stop_wait_run_loop_->Quit(); - } - - void WaitForSelectionChangeCallback() { - // Doesn't make sense to call more that once without resetting. - CHECK(!waiting_for_selection_changed_callback_); - waiting_for_selection_changed_callback_ = true; - if (selection_changed_callback_arrived_) - return; - selection_changed_wait_run_loop_.reset(new base::RunLoop()); - selection_changed_wait_run_loop_->Run(); - } - - void WaitForGestureAck(WebInputEvent::Type gesture_event_type) { - // Doesn't make sense to call more that once without resetting. - CHECK_EQ(waiting_for_gesture_ack_type_, WebInputEvent::Undefined); - waiting_for_gesture_ack_type_ = gesture_event_type; - if (last_gesture_ack_type_ == gesture_event_type) - return; - gesture_ack_wait_run_loop_.reset(new base::RunLoop()); - gesture_ack_wait_run_loop_->Run(); - } - - void WaitForFlingStopCallback() { - // Doesn't make sense to call more that once without resetting. - CHECK(!waiting_for_fling_stop_callback_); - waiting_for_fling_stop_callback_ = true; - if (fling_stop_callback_arrived_) - return; - fling_stop_wait_run_loop_.reset(new base::RunLoop()); - fling_stop_wait_run_loop_->Run(); - } - - protected: - ~TestTouchEditableImplAura() override {} - - private: - bool overscroll_started_callback_arrived_; - bool waiting_for_overscroll_started_callback_; - bool overscroll_completed_callback_arrived_; - bool waiting_for_overscroll_completed_callback_; - bool selection_changed_callback_arrived_; - bool waiting_for_selection_changed_callback_; - WebInputEvent::Type waiting_for_gesture_ack_type_; - WebInputEvent::Type last_gesture_ack_type_; - bool fling_stop_callback_arrived_; - bool waiting_for_fling_stop_callback_; - scoped_ptr<base::RunLoop> overscroll_started_wait_run_loop_; - scoped_ptr<base::RunLoop> overscroll_completed_wait_run_loop_; - scoped_ptr<base::RunLoop> selection_changed_wait_run_loop_; - scoped_ptr<base::RunLoop> gesture_ack_wait_run_loop_; - scoped_ptr<base::RunLoop> fling_stop_wait_run_loop_; - - DISALLOW_COPY_AND_ASSIGN(TestTouchEditableImplAura); -}; - -class TouchEditableImplAuraTest : public ContentBrowserTest { - public: - TouchEditableImplAuraTest() {} - - protected: - void SetUpOnMainThread() override { - ContentBrowserTest::SetUpOnMainThread(); - aura::client::SetScreenPositionClient(shell()->window()->GetRootWindow(), - &screen_position_client_); - } - - void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitch(switches::kEnableTouchEditing); - } - - // Executes the javascript synchronously and makes sure the returned value is - // freed properly. - void ExecuteSyncJSFunction(RenderFrameHost* rfh, const std::string& jscript) { - scoped_ptr<base::Value> value = - content::ExecuteScriptAndGetValue(rfh, 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()->GetContentNativeView(); - content->GetHost()->SetBounds(gfx::Rect(800, 600)); - } - - RenderWidgetHostViewAura* GetRenderWidgetHostViewAura( - TouchEditableImplAura* touch_editable) { - return touch_editable->rwhva_; - } - - ui::TouchEditingControllerDeprecated* GetTouchSelectionController( - TouchEditableImplAura* touch_editable) { - return touch_editable->touch_selection_controller_.get(); - } - - ui::TextInputType GetTextInputType(TouchEditableImplAura* touch_editable) { - return touch_editable->text_input_type_; - } - - private: - wm::DefaultScreenPositionClient screen_position_client_; - - DISALLOW_COPY_AND_ASSIGN(TouchEditableImplAuraTest); -}; - -IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest, - TouchSelectionOriginatingFromWebpageTest) { - ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); - WebContentsImpl* web_contents = - static_cast<WebContentsImpl*>(shell()->web_contents()); - RenderFrameHost* main_frame = web_contents->GetMainFrame(); - 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->GetContentNativeView(); - ui::test::EventGenerator generator(content->GetRootWindow(), content); - gfx::Rect bounds = content->GetBoundsInRootWindow(); - - touch_editable->Reset(); - ExecuteSyncJSFunction(main_frame, "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(GetRenderWidgetHostViewAura(touch_editable), rwhva); - - scoped_ptr<base::Value> value = - content::ExecuteScriptAndGetValue(main_frame, "get_selection()"); - std::string selection; - value->GetAsString(&selection); - - // Check if selection handles are showing. - EXPECT_TRUE(GetTouchSelectionController(touch_editable)); - EXPECT_STREQ("Some text we can select", selection.c_str()); - - // Lets move the handles a bit to modify the selection - touch_editable->Reset(); - ui::SelectionBound anchor, focus; - touch_editable->GetSelectionEndPoints(&anchor, &focus); - // The distance by which a handle image is offset from the bottom of the - // selection/text baseline. - const int kSelectionHandleVerticalVisualOffset = 2; - int handle_grab_x = bounds.x() + anchor.edge_bottom_rounded().x(); - int handle_grab_y = bounds.y() + anchor.edge_bottom_rounded().y() + - kSelectionHandleVerticalVisualOffset + 1; - generator.GestureScrollSequence( - gfx::Point(handle_grab_x, handle_grab_y), - gfx::Point(handle_grab_x + 20, handle_grab_y), - base::TimeDelta::FromMilliseconds(20), - 5); - touch_editable->WaitForSelectionChangeCallback(); - - EXPECT_TRUE(GetTouchSelectionController(touch_editable)); - value = content::ExecuteScriptAndGetValue(main_frame, "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()); -} - -IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest, - TestTouchSelectionHiddenWhenScrolling) { - ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); - WebContentsImpl* web_contents = - static_cast<WebContentsImpl*>(shell()->web_contents()); - RenderFrameHost* main_frame = web_contents->GetMainFrame(); - 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()); - EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva); - - // Long press to select word. - ui::GestureEvent long_press( - 10, - 10, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); - touch_editable->Reset(); - rwhva->OnGestureEvent(&long_press); - touch_editable->WaitForSelectionChangeCallback(); - - // Check if selection handles are showing. - EXPECT_TRUE(GetTouchSelectionController(touch_editable)); - - scoped_ptr<base::Value> value = - content::ExecuteScriptAndGetValue(main_frame, "get_selection()"); - std::string selection; - value->GetAsString(&selection); - EXPECT_STREQ("Some", selection.c_str()); - - // Start scrolling. Handles should get hidden. - ui::GestureEvent scroll_begin( - 10, - 10, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN)); - rwhva->OnGestureEvent(&scroll_begin); - EXPECT_FALSE(GetTouchSelectionController(touch_editable)); - - // Handles should come back after scroll ends. - ui::GestureEvent scroll_end( - 10, - 10, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END)); - rwhva->OnGestureEvent(&scroll_end); - EXPECT_TRUE(GetTouchSelectionController(touch_editable)); -} - -IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest, - TestTouchSelectionReshownAfterFling) { - ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); - WebContentsImpl* web_contents = - static_cast<WebContentsImpl*>(shell()->web_contents()); - RenderFrameHost* main_frame = web_contents->GetMainFrame(); - 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()); - EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva); - - // Long press to select word. - ui::GestureEvent long_press( - 10, - 10, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); - touch_editable->Reset(); - rwhva->OnGestureEvent(&long_press); - touch_editable->WaitForSelectionChangeCallback(); - - // Check if selection handles are showing. - EXPECT_TRUE(GetTouchSelectionController(touch_editable)); - - scoped_ptr<base::Value> value = - content::ExecuteScriptAndGetValue(main_frame, "get_selection()"); - std::string selection; - value->GetAsString(&selection); - EXPECT_STREQ("Some", selection.c_str()); - - // Start scrolling. Handles should get hidden. - ui::GestureEvent scroll_begin( - 10, - 10, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0)); - rwhva->OnGestureEvent(&scroll_begin); - EXPECT_FALSE(GetTouchSelectionController(touch_editable)); - - // Start a fling. Handles should come back after fling stops. - ui::GestureEvent fling_start( - 10, - 10, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_SCROLL_FLING_START, 1, 0)); - rwhva->OnGestureEvent(&fling_start); - touch_editable->WaitForFlingStopCallback(); - EXPECT_TRUE(GetTouchSelectionController(touch_editable)); -} - -IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest, - TestTouchSelectionWhenOverscrolling) { - ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); - WebContentsImpl* web_contents = - static_cast<WebContentsImpl*>(shell()->web_contents()); - RenderFrameHost* main_frame = web_contents->GetMainFrame(); - 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()); - EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva); - - // Long press to select word. - ui::GestureEvent long_press( - 10, - 10, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); - touch_editable->Reset(); - rwhva->OnGestureEvent(&long_press); - touch_editable->WaitForSelectionChangeCallback(); - - // Check if selection handles are showing. - EXPECT_TRUE(GetTouchSelectionController(touch_editable)); - - scoped_ptr<base::Value> value = - content::ExecuteScriptAndGetValue(main_frame, "get_selection()"); - std::string selection; - value->GetAsString(&selection); - EXPECT_STREQ("Some", selection.c_str()); - - ui::GestureEvent scroll_begin( - 10, - 10, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0)); - rwhva->OnGestureEvent(&scroll_begin); - EXPECT_FALSE(GetTouchSelectionController(touch_editable)); - - // Then overscroll starts. OverscrollStarted callback should be called and - // handles should remain hidden. - ui::GestureEvent scroll_update( - 210, - 10, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 200, 0)); - rwhva->OnGestureEvent(&scroll_update); - touch_editable->WaitForOverscrollStartedCallback(); - EXPECT_FALSE(GetTouchSelectionController(touch_editable)); - - // We might have multiple overscroll-starts in one overscroll session. Handles - // should still remain hidden. - touch_editable->OverscrollStarted(); - EXPECT_FALSE(GetTouchSelectionController(touch_editable)); - - // And, finally a scroll-end. An OverscrollCompleted callback should be - // called and handles should come back. - ui::GestureEvent scroll_end( - 10, - 210, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END)); - rwhva->OnGestureEvent(&scroll_end); - touch_editable->WaitForOverscrollCompletedCallback(); - EXPECT_TRUE(GetTouchSelectionController(touch_editable)); - - // Now repeat the same sequence, but abort the overscroll by scrolling back - // before ending the scroll. - touch_editable->Reset(); - scroll_begin = ui::GestureEvent( - 10, - 10, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0)); - rwhva->OnGestureEvent(&scroll_begin); - - scroll_update = ui::GestureEvent( - 210, - 10, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 200, 0)); - rwhva->OnGestureEvent(&scroll_update); - touch_editable->WaitForOverscrollStartedCallback(); - - // Scroll back. - ui::GestureEvent scroll_update2( - 10, - 10, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, -200, 0)); - rwhva->OnGestureEvent(&scroll_update2); - // Handles should remain hidden. - EXPECT_FALSE(GetTouchSelectionController(touch_editable)); - - // End the scroll - the overscroll should be cancelled, and we should still - // receive OverscrollCompleted callback - scroll_end = ui::GestureEvent( - 10, - 10, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END)); - rwhva->OnGestureEvent(&scroll_end); - touch_editable->WaitForOverscrollCompletedCallback(); - EXPECT_TRUE(GetTouchSelectionController(touch_editable)); -} - -IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest, - TouchSelectionOnLongPressTest) { - ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); - WebContentsImpl* web_contents = - static_cast<WebContentsImpl*>(shell()->web_contents()); - RenderFrameHost* main_frame = web_contents->GetMainFrame(); - 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()); - EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva); - - // Long press to select word. - ui::GestureEvent long_press( - 10, - 10, - 0, - ui::EventTimeForNow(), - ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); - touch_editable->Reset(); - rwhva->OnGestureEvent(&long_press); - touch_editable->WaitForSelectionChangeCallback(); - - // Check if selection handles are showing. - EXPECT_TRUE(GetTouchSelectionController(touch_editable)); - - scoped_ptr<base::Value> value = - content::ExecuteScriptAndGetValue(main_frame, "get_selection()"); - std::string selection; - value->GetAsString(&selection); - EXPECT_STREQ("Some", selection.c_str()); -} - -IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest, - NoTouchSelectionOnDoubleTapTest) { - ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); - WebContentsImpl* web_contents = - static_cast<WebContentsImpl*>(shell()->web_contents()); - RenderFrameHost* main_frame = web_contents->GetMainFrame(); - 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()); - EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva); - - // Double-tap to select word. - ui::GestureEventDetails details(ui::ET_GESTURE_TAP); - details.set_tap_count(2); - ui::GestureEvent double_tap(10, 10, 0, ui::EventTimeForNow(), details); - touch_editable->Reset(); - rwhva->OnGestureEvent(&double_tap); - touch_editable->WaitForSelectionChangeCallback(); - - // Make sure touch selection handles are not showing. - EXPECT_FALSE(GetTouchSelectionController(touch_editable)); - - scoped_ptr<base::Value> value = - content::ExecuteScriptAndGetValue(main_frame, "get_selection()"); - std::string selection; - value->GetAsString(&selection); - EXPECT_STREQ("Some", selection.c_str()); -} - -#if defined(OS_CHROMEOS) -// http://crbug.com/396509 -#define MAYBE_TouchCursorInTextfieldTest DISABLED_TouchCursorInTextfieldTest -#else -#define MAYBE_TouchCursorInTextfieldTest TouchCursorInTextfieldTest -#endif -IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest, - MAYBE_TouchCursorInTextfieldTest) { - ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); - WebContentsImpl* web_contents = - static_cast<WebContentsImpl*>(shell()->web_contents()); - RenderFrameHost* main_frame = web_contents->GetMainFrame(); - 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->GetContentNativeView(); - ui::test::EventGenerator generator(content->GetRootWindow(), content); - gfx::Rect bounds = content->GetBoundsInRootWindow(); - EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva); - - ExecuteSyncJSFunction(main_frame, "focus_textfield()"); - touch_editable->WaitForSelectionChangeCallback(); - - // Tap textfield - touch_editable->Reset(); - generator.GestureTapAt(gfx::Point(bounds.x() + 50, bounds.y() + 40)); - // Tap Down acks are sent synchronously, while Tap acks are asynchronous. - touch_editable->WaitForGestureAck(WebInputEvent::GestureTap); - touch_editable->WaitForSelectionChangeCallback(); - touch_editable->Reset(); - - // Check if cursor handle is showing. - EXPECT_NE(ui::TEXT_INPUT_TYPE_NONE, GetTextInputType(touch_editable)); - EXPECT_TRUE(GetTouchSelectionController(touch_editable)); - - scoped_ptr<base::Value> value = - content::ExecuteScriptAndGetValue(main_frame, "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); - touch_editable->WaitForSelectionChangeCallback(); - EXPECT_TRUE(GetTouchSelectionController(touch_editable)); - value = content::ExecuteScriptAndGetValue(main_frame, - "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); -} - -} // 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 39a2388..49618ee 100644 --- a/content/browser/web_contents/web_contents_view_aura.cc +++ b/content/browser/web_contents/web_contents_view_aura.cc @@ -13,6 +13,7 @@ #include "content/browser/frame_host/interstitial_page_impl.h" #include "content/browser/frame_host/navigation_entry_impl.h" #include "content/browser/renderer_host/dip_util.h" +#include "content/browser/renderer_host/input/touch_selection_controller_client_aura.h" #include "content/browser/renderer_host/overscroll_controller.h" #include "content/browser/renderer_host/render_view_host_factory.h" #include "content/browser/renderer_host/render_view_host_impl.h" @@ -21,7 +22,6 @@ #include "content/browser/renderer_host/web_input_event_aura.h" #include "content/browser/web_contents/aura/gesture_nav_simple.h" #include "content/browser/web_contents/aura/overscroll_navigation_overlay.h" -#include "content/browser/web_contents/touch_editable_impl_aura.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/notification_observer.h" @@ -63,6 +63,7 @@ #include "ui/gfx/image/image_png_rep.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/screen.h" +#include "ui/touch_selection/touch_selection_controller.h" #include "ui/wm/public/drag_drop_client.h" #include "ui/wm/public/drag_drop_delegate.h" @@ -530,8 +531,12 @@ class WebContentsViewAura::WindowObserver const gfx::Rect& new_bounds) override { if (window == host_window_ || window == view_->window_) { SendScreenRects(); - if (view_->touch_editable_) - view_->touch_editable_->UpdateEditingController(); + if (old_bounds.origin() != new_bounds.origin()) { + TouchSelectionControllerClientAura* selection_controller_client = + view_->GetSelectionControllerClient(); + if (selection_controller_client) + selection_controller_client->OnWindowMoved(); + } #if defined(OS_WIN) } else { UpdateConstrainedWindows(NULL); @@ -649,7 +654,6 @@ WebContentsViewAura::WebContentsViewAura(WebContentsImpl* web_contents, current_overscroll_gesture_(OVERSCROLL_NONE), completed_overscroll_gesture_(OVERSCROLL_NONE), navigation_overlay_(nullptr), - touch_editable_(TouchEditableImplAura::Create()), is_or_was_visible_(false) { } @@ -668,12 +672,6 @@ WebContentsViewAura::~WebContentsViewAura() { window_.reset(); } -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); @@ -723,16 +721,9 @@ void WebContentsViewAura::CompleteOverscrollNavigation(OverscrollMode mode) { if (!web_contents_->GetRenderWidgetHostView()) return; navigation_overlay_->relay_delegate()->OnOverscrollComplete(mode); - if (touch_editable_) - touch_editable_->OverscrollCompleted(); -} - -void WebContentsViewAura::AttachTouchEditableToRenderView() { - if (!touch_editable_) - return; - RenderWidgetHostViewAura* rwhva = ToRenderWidgetHostViewAura( - web_contents_->GetRenderWidgetHostView()); - touch_editable_->AttachToView(rwhva); + ui::TouchSelectionController* selection_controller = GetSelectionController(); + if (selection_controller) + selection_controller->HideAndDisallowShowingAutomatically(); } void WebContentsViewAura::OverscrollUpdateForWebContentsDelegate( @@ -741,6 +732,20 @@ void WebContentsViewAura::OverscrollUpdateForWebContentsDelegate( web_contents_->GetDelegate()->OverscrollUpdate(delta_y); } +ui::TouchSelectionController* WebContentsViewAura::GetSelectionController() + const { + RenderWidgetHostViewAura* view = + ToRenderWidgetHostViewAura(web_contents_->GetRenderWidgetHostView()); + return view ? view->selection_controller() : nullptr; +} + +TouchSelectionControllerClientAura* +WebContentsViewAura::GetSelectionControllerClient() const { + RenderWidgetHostViewAura* view = + ToRenderWidgetHostViewAura(web_contents_->GetRenderWidgetHostView()); + return view ? view->selection_controller_client() : nullptr; +} + //////////////////////////////////////////////////////////////////////////////// // WebContentsViewAura, WebContentsView implementation: @@ -898,7 +903,6 @@ RenderWidgetHostViewBase* WebContentsViewAura::CreateViewForWidget( InstallOverscrollControllerDelegate(view); } - AttachTouchEditableToRenderView(); return view; } @@ -915,7 +919,6 @@ void WebContentsViewAura::RenderViewCreated(RenderViewHost* host) { } void WebContentsViewAura::RenderViewSwappedIn(RenderViewHost* host) { - AttachTouchEditableToRenderView(); } void WebContentsViewAura::SetOverscrollControllerEnabled(bool enabled) { @@ -940,9 +943,9 @@ void WebContentsViewAura::SetOverscrollControllerEnabled(bool enabled) { void WebContentsViewAura::ShowContextMenu(RenderFrameHost* render_frame_host, const ContextMenuParams& params) { - if (touch_editable_) { - touch_editable_->EndTouchEditing(false); - } + ui::TouchSelectionController* selection_controller = GetSelectionController(); + if (selection_controller) + selection_controller->HideAndDisallowShowingAutomatically(); if (delegate_) { RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura( web_contents_->GetRenderWidgetHostView()); @@ -966,9 +969,9 @@ void WebContentsViewAura::StartDragging( return; } - if (touch_editable_) - touch_editable_->EndTouchEditing(false); - + ui::TouchSelectionController* selection_controller = GetSelectionController(); + if (selection_controller) + selection_controller->HideAndDisallowShowingAutomatically(); ui::OSExchangeData::Provider* provider = ui::OSExchangeData::CreateProvider(); PrepareDragData(drop_data, provider, web_contents_); @@ -1080,13 +1083,6 @@ void WebContentsViewAura::OnOverscrollModeChange(OverscrollMode old_mode, if (old_mode == OVERSCROLL_NORTH || old_mode == OVERSCROLL_SOUTH) OverscrollUpdateForWebContentsDelegate(0); - if (touch_editable_) { - if (new_mode == OVERSCROLL_NONE) - touch_editable_->OverscrollCompleted(); - else - touch_editable_->OverscrollStarted(); - } - current_overscroll_gesture_ = new_mode; navigation_overlay_->relay_delegate()->OnOverscrollModeChange(old_mode, new_mode); diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h index 4516181..0d84b5a 100644 --- a/content/browser/web_contents/web_contents_view_aura.h +++ b/content/browser/web_contents/web_contents_view_aura.h @@ -24,6 +24,7 @@ class Window; namespace ui { class DropTargetEvent; +class TouchSelectionController; } namespace content { @@ -32,7 +33,7 @@ class OverscrollNavigationOverlay; class RenderWidgetHostImpl; class RenderWidgetHostViewAura; class ShadowLayerDelegate; -class TouchEditableImplAura; +class TouchSelectionControllerClientAura; class WebContentsViewDelegate; class WebContentsImpl; class WebDragDestDelegate; @@ -48,9 +49,6 @@ class WebContentsViewAura WebContentsViewAura(WebContentsImpl* web_contents, WebContentsViewDelegate* delegate); - CONTENT_EXPORT void SetTouchEditableForTest( - TouchEditableImplAura* touch_editable); - private: class WindowObserver; @@ -71,10 +69,11 @@ class WebContentsViewAura // animates in, or the content window animates out). void CompleteOverscrollNavigation(OverscrollMode mode); - void AttachTouchEditableToRenderView(); - void OverscrollUpdateForWebContentsDelegate(float delta_y); + ui::TouchSelectionController* GetSelectionController() const; + TouchSelectionControllerClientAura* GetSelectionControllerClient() const; + // Overridden from WebContentsView: gfx::NativeView GetNativeView() const override; gfx::NativeView GetContentNativeView() const override; @@ -194,7 +193,6 @@ class WebContentsViewAura // navigation triggered by the overscroll gesture. scoped_ptr<OverscrollNavigationOverlay> navigation_overlay_; - scoped_ptr<TouchEditableImplAura> touch_editable_; scoped_ptr<GestureNavSimple> gesture_nav_simple_; // On Windows we can run into problems if resources get released within the diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 4a75f4f..2eb04a4 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc @@ -59,7 +59,6 @@ static void SetRuntimeFeatureDefaultsForPlatform() { WebRuntimeFeatures::enableOrientationEvent(true); WebRuntimeFeatures::enableFastMobileScrolling(true); WebRuntimeFeatures::enableMediaCapture(true); - WebRuntimeFeatures::enableCompositedSelectionUpdate(true); // Android won't be able to reliably support non-persistent notifications, the // intended behavior for which is in flux by itself. WebRuntimeFeatures::enableNotificationConstructor(false); @@ -67,6 +66,10 @@ static void SetRuntimeFeatureDefaultsForPlatform() { WebRuntimeFeatures::enableNavigatorContentUtils(true); #endif // defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(USE_AURA) + WebRuntimeFeatures::enableCompositedSelectionUpdate(true); +#endif + #if !(defined OS_ANDROID || defined OS_CHROMEOS || defined OS_IOS) // Only Android, ChromeOS, and IOS support NetInfo right now. WebRuntimeFeatures::enableNetworkInformation(false); diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 1d9cf9a..0c23b4f 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -1208,6 +1208,8 @@ 'browser/renderer_host/input/touch_emulator_client.h', 'browser/renderer_host/input/touch_event_queue.cc', 'browser/renderer_host/input/touch_event_queue.h', + 'browser/renderer_host/input/touch_selection_controller_client_aura.cc', + 'browser/renderer_host/input/touch_selection_controller_client_aura.h', 'browser/renderer_host/input/touchpad_tap_suppression_controller.cc', 'browser/renderer_host/input/touchpad_tap_suppression_controller.h', 'browser/renderer_host/input/touchscreen_tap_suppression_controller.cc', @@ -1521,8 +1523,6 @@ 'browser/web_contents/aura/overscroll_window_delegate.h', 'browser/web_contents/aura/shadow_layer_delegate.cc', 'browser/web_contents/aura/shadow_layer_delegate.h', - 'browser/web_contents/touch_editable_impl_aura.cc', - 'browser/web_contents/touch_editable_impl_aura.h', 'browser/web_contents/web_contents_android.cc', 'browser/web_contents/web_contents_android.h', 'browser/web_contents/web_contents_impl.cc', @@ -2063,10 +2063,10 @@ ], }, { 'sources/': [ + ['exclude', '^browser/renderer_host/input/touch_selection_controller_client_aura.cc'], + ['exclude', '^browser/renderer_host/input/touch_selection_controller_client_aura.h'], ['exclude', '^browser/renderer_host/render_widget_host_view_aura.cc'], ['exclude', '^browser/renderer_host/render_widget_host_view_aura.h'], - ['exclude', '^browser/web_contents/touch_editable_impl_aura.cc'], - ['exclude', '^browser/web_contents/touch_editable_impl_aura.h'], ['exclude', '^browser/renderer_host/ui_events_helper.cc'], ['exclude', '^browser/renderer_host/ui_events_helper.h'], ], diff --git a/content/content_tests.gypi b/content/content_tests.gypi index ed1a156..9095f33 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -232,6 +232,7 @@ 'browser/net_info_browsertest.cc', 'browser/renderer_host/input/touch_action_browsertest.cc', 'browser/renderer_host/input/touch_input_browsertest.cc', + 'browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc', 'browser/renderer_host/render_message_filter_browsertest.cc', 'browser/renderer_host/render_process_host_browsertest.cc', 'browser/renderer_host/render_view_host_browsertest.cc', @@ -246,7 +247,6 @@ 'browser/tracing/background_tracing_manager_browsertest.cc', 'browser/tracing/tracing_controller_browsertest.cc', 'browser/web_contents/opened_by_dom_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', @@ -1441,11 +1441,6 @@ ], 'sources': [ '<@(content_browsertests_sources)' ], 'conditions': [ - ['chromeos==0', { - 'sources!': [ - 'browser/web_contents/touch_editable_impl_aura_browsertest.cc', - ], - }], ['OS=="win"', { 'resource_include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)/webkit', @@ -1521,6 +1516,15 @@ 'browser/compositor/image_transport_factory_browsertest.cc', ], }], + ['use_aura==1', { + 'dependencies': [ + '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection', + '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_test_support', + ]}, { + 'sources!': [ + 'browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc', + ], + }], ['enable_webrtc==1', { 'sources': [ '<@(content_browsertests_webrtc_sources)' ], 'dependencies': [ diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index d38cdc1..73aa11e 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc @@ -2006,10 +2006,20 @@ void RenderWidget::UpdateSelectionBounds() { if (handling_ime_event_) return; +#if defined(USE_AURA) + // TODO(mohsen): For now, always send explicit selection IPC notifications for + // Aura beucause composited selection updates are not working for webview tags + // which regresses IME inside webview. Remove this when composited selection + // updates are fixed for webviews. See, http://crbug.com/510568. + bool send_ipc = true; +#else // With composited selection updates, the selection bounds will be reported // directly by the compositor, in which case explicit IPC selection // notifications should be suppressed. - if (!blink::WebRuntimeFeatures::isCompositedSelectionUpdateEnabled()) { + bool send_ipc = + !blink::WebRuntimeFeatures::isCompositedSelectionUpdateEnabled(); +#endif + if (send_ipc) { ViewHostMsg_SelectionBounds_Params params; GetSelectionBounds(¶ms.anchor_rect, ¶ms.focus_rect); if (selection_anchor_rect_ != params.anchor_rect || diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 07ee03f..d17a7dc 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn @@ -374,11 +374,6 @@ if (!is_mac) { "//third_party/mesa:osmesa", ] - if (!is_chromeos) { - sources -= - [ "../browser/web_contents/touch_editable_impl_aura_browsertest.cc" ] - } - if (is_win) { sources += rebase_path( content_tests_gypi_values.content_browsertests_win_sources, @@ -464,9 +459,16 @@ if (!is_mac) { "//content") } - if (!use_aura) { - sources -= - [ "../browser/web_contents/web_contents_view_aura_browsertest.cc" ] + if (use_aura) { + deps += [ + "//ui/touch_selection:test_support", + "//ui/touch_selection:touch_selection", + ] + } else { + sources -= [ + "../browser/renderer_host/input/touch_selection_controller_client_aura_browsertest.cc", + "../browser/web_contents/web_contents_view_aura_browsertest.cc", + ] } } } diff --git a/content/test/data/touch_selection.html b/content/test/data/touch_selection.html index 89d76831..7bf8644 100644 --- a/content/test/data/touch_selection.html +++ b/content/test/data/touch_selection.html @@ -3,33 +3,27 @@ <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(); // Focusing the textfiled selects its text. Collapse selection to a cursor. window.getSelection().collapseToStart(); } -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; +function get_point_inside(element) { + var rect = element.getBoundingClientRect(); + var point = { + x: rect.left + 8, + y: (rect.top + rect.bottom) / 2 + }; + window.domAutomationController.send(JSON.stringify(point)); +} + +function get_point_inside_text() { + get_point_inside(document.getElementById('textDiv')); +} + +function get_point_inside_textfield() { + get_point_inside(document.getElementById('textfield')); } </script> diff --git a/ui/touch_selection/BUILD.gn b/ui/touch_selection/BUILD.gn index 3f98ea0..f5f2825 100644 --- a/ui/touch_selection/BUILD.gn +++ b/ui/touch_selection/BUILD.gn @@ -53,6 +53,19 @@ component("touch_selection") { } } +static_library("test_support") { + testonly = true + + sources = [ + "touch_selection_controller_test_api.cc", + "touch_selection_controller_test_api.h", + ] + + deps = [ + ":touch_selection", + ] +} + # TODO(GYP): Delete this after we've converted everything to GN. # The _run targets exist only for compatibility w/ GYP. group("ui_touch_selection_unittests_run") { @@ -70,6 +83,7 @@ test("ui_touch_selection_unittests") { ] deps = [ + ":test_support", ":touch_selection", "//base/test:run_all_unittests", "//testing/gmock:gmock", diff --git a/ui/touch_selection/touch_selection_controller_test_api.cc b/ui/touch_selection/touch_selection_controller_test_api.cc new file mode 100644 index 0000000..abe89de --- /dev/null +++ b/ui/touch_selection/touch_selection_controller_test_api.cc @@ -0,0 +1,23 @@ +// 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 "ui/touch_selection/touch_selection_controller_test_api.h" + +namespace ui { + +TouchSelectionControllerTestApi::TouchSelectionControllerTestApi( + TouchSelectionController* controller) + : controller_(controller) {} + +TouchSelectionControllerTestApi::~TouchSelectionControllerTestApi() {} + +bool TouchSelectionControllerTestApi::GetStartVisible() const { + return controller_->GetStartVisible(); +} + +bool TouchSelectionControllerTestApi::GetEndVisible() const { + return controller_->GetEndVisible(); +} + +} // namespace ui diff --git a/ui/touch_selection/touch_selection_controller_test_api.h b/ui/touch_selection/touch_selection_controller_test_api.h new file mode 100644 index 0000000..b55b2628 --- /dev/null +++ b/ui/touch_selection/touch_selection_controller_test_api.h @@ -0,0 +1,33 @@ +// 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 UI_TOUCH_SELECTION_TOUCH_SELECTION_CONTROLLER_TEST_API_H_ +#define UI_TOUCH_SELECTION_TOUCH_SELECTION_CONTROLLER_TEST_API_H_ + +#include "ui/touch_selection/touch_selection_controller.h" + +namespace ui { + +// Test api class to access internals of |ui::TouchSelectionController| in +// tests. +class TouchSelectionControllerTestApi { + public: + explicit TouchSelectionControllerTestApi( + TouchSelectionController* controller); + ~TouchSelectionControllerTestApi(); + + bool GetStartVisible() const; + bool GetEndVisible() const; + + bool temporarily_hidden() const { return controller_->temporarily_hidden_; } + + private: + TouchSelectionController* const controller_; + + DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerTestApi); +}; + +} // namespace ui + +#endif // UI_TOUCH_SELECTION_TOUCH_SELECTION_CONTROLLER_TEST_API_H_ diff --git a/ui/touch_selection/touch_selection_controller_unittest.cc b/ui/touch_selection/touch_selection_controller_unittest.cc index adb09c7..b0f0576 100644 --- a/ui/touch_selection/touch_selection_controller_unittest.cc +++ b/ui/touch_selection/touch_selection_controller_unittest.cc @@ -9,6 +9,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/test/motion_event_test_utils.h" +#include "ui/touch_selection/touch_selection_controller_test_api.h" using testing::ElementsAre; using testing::IsEmpty; @@ -43,21 +44,6 @@ class MockTouchHandleDrawable : public TouchHandleDrawable { } // namespace -class TouchSelectionControllerTestApi { - public: - explicit TouchSelectionControllerTestApi(TouchSelectionController* controller) - : controller_(controller) {} - ~TouchSelectionControllerTestApi() {} - - bool GetStartVisible() const { return controller_->GetStartVisible(); } - bool GetEndVisible() const { return controller_->GetEndVisible(); } - - private: - TouchSelectionController* controller_; - - DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerTestApi); -}; - class TouchSelectionControllerTest : public testing::Test, public TouchSelectionControllerClient { public: diff --git a/ui/touch_selection/ui_touch_selection.gyp b/ui/touch_selection/ui_touch_selection.gyp index 6289bd0..76308e592 100644 --- a/ui/touch_selection/ui_touch_selection.gyp +++ b/ui/touch_selection/ui_touch_selection.gyp @@ -63,6 +63,17 @@ ], }, { + 'target_name': 'ui_touch_selection_test_support', + 'type': 'static_library', + 'dependencies': [ + 'ui_touch_selection', + ], + 'sources': [ + 'touch_selection_controller_test_api.cc', + 'touch_selection_controller_test_api.h', + ], + }, + { 'target_name': 'ui_touch_selection_unittests', 'type': '<(gtest_target_type)', 'dependencies': [ @@ -76,6 +87,7 @@ '../gfx/gfx.gyp:gfx', '../gfx/gfx.gyp:gfx_test_support', 'ui_touch_selection', + 'ui_touch_selection_test_support', ], 'sources': [ 'longpress_drag_selector_unittest.cc', |