Index: content/browser/renderer_host/input/touch_selection_controller_client_aura.cc |
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 0000000000000000000000000000000000000000..ada3e9f2fc7549240bf0d1d5061a92a562044e58 |
--- /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 |