touch_editable_impl_aura.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
1// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "content/browser/web_contents/touch_editable_impl_aura.h" 6 7#include "content/browser/renderer_host/render_widget_host_impl.h" 8#include "content/browser/renderer_host/render_widget_host_view_aura.h" 9#include "content/common/view_messages.h" 10#include "content/public/browser/render_widget_host.h" 11#include "grit/ui_strings.h" 12#include "ui/aura/client/activation_client.h" 13#include "ui/aura/client/screen_position_client.h" 14#include "ui/aura/root_window.h" 15#include "ui/aura/window.h" 16#include "ui/base/clipboard/clipboard.h" 17#include "ui/base/range/range.h" 18#include "ui/base/ui_base_switches_util.h" 19 20namespace content { 21 22//////////////////////////////////////////////////////////////////////////////// 23// TouchEditableImplAura, public: 24 25TouchEditableImplAura::~TouchEditableImplAura() { 26 Cleanup(); 27} 28 29// static 30TouchEditableImplAura* TouchEditableImplAura::Create() { 31 if (switches::IsTouchEditingEnabled()) 32 return new TouchEditableImplAura(); 33 return NULL; 34} 35 36void TouchEditableImplAura::AttachToView(RenderWidgetHostViewAura* view) { 37 if (rwhva_ == view) 38 return; 39 40 Cleanup(); 41 if (!view) 42 return; 43 44 rwhva_ = view; 45 rwhva_->set_touch_editing_client(this); 46} 47 48void TouchEditableImplAura::UpdateEditingController() { 49 if (!rwhva_) 50 return; 51 52 // If touch editing handles were not visible, we bring them up only if 53 // there is non-zero selection on the page. And the current event is a 54 // gesture event (we dont want to show handles if the user is selecting 55 // using mouse or keyboard). 56 if (selection_gesture_in_process_ && 57 selection_anchor_rect_ != selection_focus_rect_) 58 StartTouchEditing(); 59 60 if (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE || 61 selection_anchor_rect_ != selection_focus_rect_) { 62 if (touch_selection_controller_) 63 touch_selection_controller_->SelectionChanged(); 64 } else { 65 EndTouchEditing(); 66 } 67} 68 69//////////////////////////////////////////////////////////////////////////////// 70// TouchEditableImplAura, RenderWidgetHostViewAura::TouchEditingClient 71// implementation: 72 73void TouchEditableImplAura::StartTouchEditing() { 74 if (!touch_selection_controller_) { 75 touch_selection_controller_.reset( 76 ui::TouchSelectionController::create(this)); 77 } 78 if (touch_selection_controller_) 79 touch_selection_controller_->SelectionChanged(); 80} 81 82void TouchEditableImplAura::EndTouchEditing() { 83 if (touch_selection_controller_) { 84 if (touch_selection_controller_->IsHandleDragInProgress()) 85 touch_selection_controller_->SelectionChanged(); 86 else 87 touch_selection_controller_.reset(); 88 } 89} 90 91void TouchEditableImplAura::OnSelectionOrCursorChanged(const gfx::Rect& anchor, 92 const gfx::Rect& focus) { 93 selection_anchor_rect_ = anchor; 94 selection_focus_rect_ = focus; 95 UpdateEditingController(); 96} 97 98void TouchEditableImplAura::OnTextInputTypeChanged(ui::TextInputType type) { 99 text_input_type_ = type; 100} 101 102bool TouchEditableImplAura::HandleInputEvent(const ui::Event* event) { 103 DCHECK(rwhva_); 104 if (event->IsTouchEvent()) 105 return false; 106 107 if (!event->IsGestureEvent()) { 108 EndTouchEditing(); 109 return false; 110 } 111 112 const ui::GestureEvent* gesture_event = 113 static_cast<const ui::GestureEvent*>(event); 114 switch (event->type()) { 115 case ui::ET_GESTURE_TAP: 116 if (gesture_event->details().tap_count() > 1) 117 selection_gesture_in_process_ = true; 118 // When the user taps, we want to show touch editing handles if user 119 // tapped on selected text. 120 if (selection_anchor_rect_ != selection_focus_rect_) { 121 // UnionRects only works for rects with non-zero width. 122 gfx::Rect anchor(selection_anchor_rect_.origin(), 123 gfx::Size(1, selection_anchor_rect_.height())); 124 gfx::Rect focus(selection_focus_rect_.origin(), 125 gfx::Size(1, selection_focus_rect_.height())); 126 gfx::Rect selection_rect = gfx::UnionRects(anchor, focus); 127 if (selection_rect.Contains(gesture_event->location())) { 128 StartTouchEditing(); 129 return true; 130 } 131 } 132 break; 133 case ui::ET_GESTURE_LONG_PRESS: 134 selection_gesture_in_process_ = true; 135 break; 136 default: 137 break; 138 } 139 return false; 140} 141 142void TouchEditableImplAura::GestureEventAck(int gesture_event_type) { 143 DCHECK(rwhva_); 144 if (gesture_event_type == WebKit::WebInputEvent::GestureTap && 145 text_input_type_ != ui::TEXT_INPUT_TYPE_NONE) { 146 StartTouchEditing(); 147 if (touch_selection_controller_) 148 touch_selection_controller_->SelectionChanged(); 149 } 150 151 if (gesture_event_type == WebKit::WebInputEvent::GestureLongPress || 152 gesture_event_type == WebKit::WebInputEvent::GestureTap) 153 selection_gesture_in_process_ = false; 154} 155 156void TouchEditableImplAura::OnViewDestroyed() { 157 Cleanup(); 158} 159 160//////////////////////////////////////////////////////////////////////////////// 161// TouchEditableImplAura, ui::TouchEditable implementation: 162 163void TouchEditableImplAura::SelectRect(const gfx::Point& start, 164 const gfx::Point& end) { 165 if (!rwhva_) 166 return; 167 168 RenderWidgetHostImpl* host = RenderWidgetHostImpl::From( 169 rwhva_->GetRenderWidgetHost()); 170 host->SelectRange(start, end); 171} 172 173void TouchEditableImplAura::MoveCaretTo(const gfx::Point& point) { 174 if (!rwhva_) 175 return; 176 177 RenderWidgetHostImpl* host = RenderWidgetHostImpl::From( 178 rwhva_->GetRenderWidgetHost()); 179 host->MoveCaret(point); 180} 181 182void TouchEditableImplAura::GetSelectionEndPoints(gfx::Rect* p1, 183 gfx::Rect* p2) { 184 *p1 = selection_anchor_rect_; 185 *p2 = selection_focus_rect_; 186} 187 188gfx::Rect TouchEditableImplAura::GetBounds() { 189 return rwhva_ ? rwhva_->GetNativeView()->bounds() : gfx::Rect(); 190} 191 192gfx::NativeView TouchEditableImplAura::GetNativeView() { 193 return rwhva_ ? rwhva_->GetNativeView()->GetRootWindow() : NULL; 194} 195 196void TouchEditableImplAura::ConvertPointToScreen(gfx::Point* point) { 197 if (!rwhva_) 198 return; 199 aura::Window* window = rwhva_->GetNativeView(); 200 aura::client::ScreenPositionClient* screen_position_client = 201 aura::client::GetScreenPositionClient(window->GetRootWindow()); 202 if (screen_position_client) 203 screen_position_client->ConvertPointToScreen(window, point); 204} 205 206void TouchEditableImplAura::ConvertPointFromScreen(gfx::Point* point) { 207 if (!rwhva_) 208 return; 209 aura::Window* window = rwhva_->GetNativeView(); 210 aura::client::ScreenPositionClient* screen_position_client = 211 aura::client::GetScreenPositionClient(window->GetRootWindow()); 212 if (screen_position_client) 213 screen_position_client->ConvertPointFromScreen(window, point); 214} 215 216bool TouchEditableImplAura::DrawsHandles() { 217 return false; 218} 219 220void TouchEditableImplAura::OpenContextMenu(const gfx::Point anchor) { 221 if (!rwhva_) 222 return; 223 RenderWidgetHost* host = rwhva_->GetRenderWidgetHost(); 224 host->Send(new ViewMsg_ShowContextMenu(host->GetRoutingID())); 225 EndTouchEditing(); 226} 227 228bool TouchEditableImplAura::IsCommandIdChecked(int command_id) const { 229 NOTREACHED(); 230 return false; 231} 232 233bool TouchEditableImplAura::IsCommandIdEnabled(int command_id) const { 234 if (!rwhva_) 235 return false; 236 bool editable = rwhva_->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE; 237 ui::Range selection_range; 238 rwhva_->GetSelectionRange(&selection_range); 239 bool has_selection = !selection_range.is_empty(); 240 switch (command_id) { 241 case IDS_APP_CUT: 242 return editable && has_selection; 243 case IDS_APP_COPY: 244 return has_selection; 245 case IDS_APP_PASTE: { 246 string16 result; 247 ui::Clipboard::GetForCurrentThread()->ReadText( 248 ui::Clipboard::BUFFER_STANDARD, &result); 249 return editable && !result.empty(); 250 } 251 case IDS_APP_DELETE: 252 return editable && has_selection; 253 case IDS_APP_SELECT_ALL: 254 return true; 255 default: 256 return false; 257 } 258} 259 260bool TouchEditableImplAura::GetAcceleratorForCommandId( 261 int command_id, 262 ui::Accelerator* accelerator) { 263 return false; 264} 265 266void TouchEditableImplAura::ExecuteCommand(int command_id, int event_flags) { 267 if (!rwhva_) 268 return; 269 RenderWidgetHost* host = rwhva_->GetRenderWidgetHost(); 270 switch (command_id) { 271 case IDS_APP_CUT: 272 host->Cut(); 273 break; 274 case IDS_APP_COPY: 275 host->Copy(); 276 break; 277 case IDS_APP_PASTE: 278 host->Paste(); 279 break; 280 case IDS_APP_DELETE: 281 host->Delete(); 282 break; 283 case IDS_APP_SELECT_ALL: 284 host->SelectAll(); 285 break; 286 default: 287 NOTREACHED(); 288 break; 289 } 290 EndTouchEditing(); 291} 292 293//////////////////////////////////////////////////////////////////////////////// 294// TouchEditableImplAura, private: 295 296TouchEditableImplAura::TouchEditableImplAura() 297 : text_input_type_(ui::TEXT_INPUT_TYPE_NONE), 298 rwhva_(NULL), 299 selection_gesture_in_process_(false) { 300} 301 302void TouchEditableImplAura::Cleanup() { 303 if (rwhva_) { 304 rwhva_->set_touch_editing_client(NULL); 305 rwhva_ = NULL; 306 } 307 touch_selection_controller_.reset(); 308} 309 310} // namespace content 311