Chromium Code Reviews| 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..8244e3cf0b7e72e920921779b1b88a149021657e |
| --- /dev/null |
| +++ b/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc |
| @@ -0,0 +1,344 @@ |
| +// 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()); |
|
sadrul
2015/06/30 18:33:12
Sadness ... this is still pretty wrong.
mohsen
2015/07/03 18:07:23
Why?
sadrul
2015/07/15 17:00:14
Consider rotated windows.
I think this is the app
|
| +} |
| + |
| +} // namespace |
| + |
| +class TouchSelectionControllerClientAura::EnvPreTargetHandler |
| + : public ui::EventHandler { |
|
sadrul
2015/06/30 18:33:12
Document.
mohsen
2015/07/03 18:07:23
Done.
|
| + 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()); |
| + |
| + aura::client::CursorClient* cursor_client = |
| + aura::client::GetCursorClient(window_->GetRootWindow()); |
| + if (!cursor_client || cursor_client->IsMouseEventsEnabled()) |
|
sadrul
2015/06/30 18:33:12
Can you document why this check with cursor-client
mohsen
2015/07/03 18:07:23
Done.
|
| + 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::OnSelectionScrollStarted() { |
| + scroll_in_progress_ = true; |
| + rwhva_->selection_controller()->SetTemporarilyHidden(true); |
| + UpdateQuickMenu(); |
| +} |
| + |
| +void TouchSelectionControllerClientAura::OnSelectionScrollCompleted() { |
| + 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(); |
|
sadrul
2015/06/30 18:33:12
Can you remind me what coord-space this rect is in
mohsen
2015/07/03 18:07:23
This function will return bounding box of selectio
|
| + |
| + // Clip rect 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; |
|
sadrul
2015/06/30 18:33:12
Do these do the right thing for RTL?
mohsen
2015/07/03 18:07:23
Yeah, 'right' is always greater than or equal to '
|
| + 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() { |
| + // Hide quick menu if there is any. |
| + if (ui::TouchSelectionMenuRunner::GetInstance() && |
| + ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()) { |
| + ui::TouchSelectionMenuRunner::GetInstance()->CloseMenu(); |
| + } else { |
| + quick_menu_timer_.Stop(); |
| + } |
| + |
| + // Start timer to show quick menu if necessary. |
| + if (rwhva_->selection_controller()->active_status() == |
| + ui::TouchSelectionController::INACTIVE) { |
| + return; |
| + } |
| + |
| + if (!IsQuickMenuAllowed()) |
| + return; |
| + |
| + quick_menu_timer_.Reset(); |
| +} |
|
sadrul
2015/06/30 18:33:12
Can this be more like:
bool menu_should_show = a
mohsen
2015/07/03 18:07:23
We'd want to hide the menu even if menu_should_sho
|
| + |
| +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)); |
|
sadrul
2015/06/30 18:33:12
{}
mohsen
2015/07/03 18:07:23
Done.
|
| +} |
| + |
| +void TouchSelectionControllerClientAura::OnSelectionEvent( |
| + ui::SelectionEventType event) { |
| + switch (event) { |
| + case ui::SELECTION_SHOWN: |
| + case ui::INSERTION_SHOWN: |
| + UpdateQuickMenu(); |
| + env_pre_target_handler_.reset(new EnvPreTargetHandler( |
| + rwhva_->selection_controller(), rwhva_->GetNativeView())); |
| + break; |
| + case ui::SELECTION_CLEARED: |
| + case ui::INSERTION_CLEARED: |
| + env_pre_target_handler_.reset(); |
| + UpdateQuickMenu(); |
| + break; |
| + case ui::SELECTION_DRAG_STARTED: |
| + case ui::INSERTION_DRAG_STARTED: |
| + handle_drag_in_progress_ = true; |
| + UpdateQuickMenu(); |
| + break; |
| + case ui::SELECTION_DRAG_STOPPED: |
| + case ui::INSERTION_DRAG_STOPPED: |
| + handle_drag_in_progress_ = false; |
| + UpdateQuickMenu(); |
| + break; |
| + case ui::SELECTION_MOVED: |
| + case ui::INSERTION_MOVED: |
| + UpdateQuickMenu(); |
| + break; |
| + case ui::INSERTION_TAPPED: |
| + 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(); |
| + } |
| + case IDS_APP_DELETE: |
| + return editable && has_selection; |
| + case IDS_APP_SELECT_ALL: |
| + return true; |
| + 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: |
|
sadrul
2015/06/30 18:33:12
Shouldn't you also handle DELETE and SELECT_ALL? I
mohsen
2015/07/03 18:07:23
The quick menu as implemented for Views only can h
|
| + 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. |
| + rwhva_->selection_controller()->HideAndDisallowShowingAutomatically(); |
| +} |
| + |
| +} // namespace content |