Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / web_contents / touch_editable_impl_aura.cc
blob0f49038fb070018414b9af52af6bbe7d4cac530e
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.
5 #include "content/browser/web_contents/touch_editable_impl_aura.h"
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/browser/web_contents/web_contents_impl.h"
10 #include "content/common/view_messages.h"
11 #include "content/public/browser/render_view_host.h"
12 #include "content/public/browser/render_widget_host.h"
13 #include "ui/aura/client/screen_position_client.h"
14 #include "ui/aura/window.h"
15 #include "ui/aura/window_tree_host.h"
16 #include "ui/base/clipboard/clipboard.h"
17 #include "ui/base/ui_base_switches_util.h"
18 #include "ui/gfx/range/range.h"
19 #include "ui/strings/grit/ui_strings.h"
20 #include "ui/wm/public/activation_client.h"
22 namespace content {
24 ////////////////////////////////////////////////////////////////////////////////
25 // TouchEditableImplAura, public:
27 TouchEditableImplAura::~TouchEditableImplAura() {
28 Cleanup();
31 // static
32 TouchEditableImplAura* TouchEditableImplAura::Create() {
33 if (switches::IsTouchEditingEnabled())
34 return new TouchEditableImplAura();
35 return NULL;
38 void TouchEditableImplAura::AttachToView(RenderWidgetHostViewAura* view) {
39 if (rwhva_ == view)
40 return;
42 Cleanup();
43 if (!view)
44 return;
46 rwhva_ = view;
47 rwhva_->set_touch_editing_client(this);
50 void TouchEditableImplAura::UpdateEditingController() {
51 if (!rwhva_ || !rwhva_->HasFocus())
52 return;
54 if (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE ||
55 selection_anchor_rect_ != selection_focus_rect_) {
56 if (touch_selection_controller_)
57 touch_selection_controller_->SelectionChanged();
58 } else {
59 EndTouchEditing(false);
63 void TouchEditableImplAura::OverscrollStarted() {
64 overscroll_in_progress_ = true;
67 void TouchEditableImplAura::OverscrollCompleted() {
68 // We might receive multiple OverscrollStarted() and OverscrollCompleted()
69 // during the same scroll session (for example, when the scroll direction
70 // changes). We want to show the handles only when:
71 // 1. Overscroll has completed
72 // 2. Scrolling session is over, i.e. we have received ET_GESTURE_SCROLL_END.
73 // 3. If we had hidden the handles when scrolling started
74 // 4. If there is still a need to show handles (there is a non-empty selection
75 // or non-NONE |text_input_type_|)
76 if (overscroll_in_progress_ && !scroll_in_progress_ &&
77 handles_hidden_due_to_scroll_ &&
78 (selection_anchor_rect_ != selection_focus_rect_ ||
79 text_input_type_ != ui::TEXT_INPUT_TYPE_NONE)) {
80 StartTouchEditing();
81 UpdateEditingController();
83 overscroll_in_progress_ = false;
86 ////////////////////////////////////////////////////////////////////////////////
87 // TouchEditableImplAura, RenderWidgetHostViewAura::TouchEditingClient
88 // implementation:
90 void TouchEditableImplAura::StartTouchEditing() {
91 if (!rwhva_ || !rwhva_->HasFocus())
92 return;
94 if (!touch_selection_controller_) {
95 touch_selection_controller_.reset(
96 ui::TouchSelectionController::create(this));
98 if (touch_selection_controller_)
99 touch_selection_controller_->SelectionChanged();
102 void TouchEditableImplAura::EndTouchEditing(bool quick) {
103 if (touch_selection_controller_) {
104 if (touch_selection_controller_->IsHandleDragInProgress()) {
105 touch_selection_controller_->SelectionChanged();
106 } else {
107 selection_gesture_in_process_ = false;
108 touch_selection_controller_->HideHandles(quick);
109 touch_selection_controller_.reset();
114 void TouchEditableImplAura::OnSelectionOrCursorChanged(const gfx::Rect& anchor,
115 const gfx::Rect& focus) {
116 selection_anchor_rect_ = anchor;
117 selection_focus_rect_ = focus;
119 // If touch editing handles were not visible, we bring them up only if
120 // there is non-zero selection on the page. And the current event is a
121 // gesture event (we dont want to show handles if the user is selecting
122 // using mouse or keyboard).
123 if (selection_gesture_in_process_ && !scroll_in_progress_ &&
124 !overscroll_in_progress_ &&
125 selection_anchor_rect_ != selection_focus_rect_) {
126 StartTouchEditing();
127 selection_gesture_in_process_ = false;
130 UpdateEditingController();
133 void TouchEditableImplAura::OnTextInputTypeChanged(ui::TextInputType type) {
134 text_input_type_ = type;
137 bool TouchEditableImplAura::HandleInputEvent(const ui::Event* event) {
138 DCHECK(rwhva_);
139 if (!event->IsGestureEvent()) {
140 // Ignore all non-gesture events. Non-gesture events that can deactivate
141 // touch editing are handled in TouchSelectionControllerImpl.
142 return false;
145 const ui::GestureEvent* gesture_event =
146 static_cast<const ui::GestureEvent*>(event);
147 switch (event->type()) {
148 case ui::ET_GESTURE_TAP:
149 // When the user taps, we want to show touch editing handles if user
150 // tapped on selected text.
151 if (gesture_event->details().tap_count() == 1 &&
152 selection_anchor_rect_ != selection_focus_rect_) {
153 // UnionRects only works for rects with non-zero width.
154 gfx::Rect anchor(selection_anchor_rect_.origin(),
155 gfx::Size(1, selection_anchor_rect_.height()));
156 gfx::Rect focus(selection_focus_rect_.origin(),
157 gfx::Size(1, selection_focus_rect_.height()));
158 gfx::Rect selection_rect = gfx::UnionRects(anchor, focus);
159 if (selection_rect.Contains(gesture_event->location())) {
160 StartTouchEditing();
161 return true;
164 // For single taps, not inside selected region, we want to show handles
165 // only when the tap is on an already focused textfield.
166 textfield_was_focused_on_tap_ = false;
167 if (gesture_event->details().tap_count() == 1 &&
168 text_input_type_ != ui::TEXT_INPUT_TYPE_NONE)
169 textfield_was_focused_on_tap_ = true;
170 break;
171 case ui::ET_GESTURE_LONG_PRESS:
172 selection_gesture_in_process_ = true;
173 break;
174 case ui::ET_GESTURE_SCROLL_BEGIN:
175 // If selection handles are currently visible, we want to get them back up
176 // when scrolling ends. So we set |handles_hidden_due_to_scroll_| so that
177 // we can re-start touch editing on scroll end gesture.
178 scroll_in_progress_ = true;
179 handles_hidden_due_to_scroll_ = false;
180 if (touch_selection_controller_)
181 handles_hidden_due_to_scroll_ = true;
182 EndTouchEditing(true);
183 break;
184 case ui::ET_GESTURE_SCROLL_END:
185 // Scroll has ended, but we might still be in overscroll animation.
186 if (handles_hidden_due_to_scroll_ && !overscroll_in_progress_ &&
187 (selection_anchor_rect_ != selection_focus_rect_ ||
188 text_input_type_ != ui::TEXT_INPUT_TYPE_NONE)) {
189 StartTouchEditing();
190 UpdateEditingController();
192 // fall through to reset |scroll_in_progress_|.
193 case ui::ET_SCROLL_FLING_START:
194 selection_gesture_in_process_ = false;
195 scroll_in_progress_ = false;
196 break;
197 default:
198 break;
200 return false;
203 void TouchEditableImplAura::GestureEventAck(int gesture_event_type) {
204 DCHECK(rwhva_);
205 if (gesture_event_type == blink::WebInputEvent::GestureTap &&
206 text_input_type_ != ui::TEXT_INPUT_TYPE_NONE &&
207 textfield_was_focused_on_tap_) {
208 StartTouchEditing();
209 UpdateEditingController();
213 void TouchEditableImplAura::OnViewDestroyed() {
214 Cleanup();
217 ////////////////////////////////////////////////////////////////////////////////
218 // TouchEditableImplAura, ui::TouchEditable implementation:
220 void TouchEditableImplAura::SelectRect(const gfx::Point& start,
221 const gfx::Point& end) {
222 RenderWidgetHost* host = rwhva_->GetRenderWidgetHost();
223 RenderViewHost* rvh = RenderViewHost::From(host);
224 WebContentsImpl* wc =
225 static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(rvh));
226 wc->SelectRange(start, end);
229 void TouchEditableImplAura::MoveCaretTo(const gfx::Point& point) {
230 if (!rwhva_)
231 return;
233 RenderWidgetHostImpl* host = RenderWidgetHostImpl::From(
234 rwhva_->GetRenderWidgetHost());
235 host->MoveCaret(point);
238 void TouchEditableImplAura::GetSelectionEndPoints(gfx::Rect* p1,
239 gfx::Rect* p2) {
240 *p1 = selection_anchor_rect_;
241 *p2 = selection_focus_rect_;
244 gfx::Rect TouchEditableImplAura::GetBounds() {
245 return rwhva_ ? gfx::Rect(rwhva_->GetNativeView()->bounds().size()) :
246 gfx::Rect();
249 gfx::NativeView TouchEditableImplAura::GetNativeView() const {
250 return rwhva_ ? rwhva_->GetNativeView()->GetToplevelWindow() : NULL;
253 void TouchEditableImplAura::ConvertPointToScreen(gfx::Point* point) {
254 if (!rwhva_)
255 return;
256 aura::Window* window = rwhva_->GetNativeView();
257 aura::client::ScreenPositionClient* screen_position_client =
258 aura::client::GetScreenPositionClient(window->GetRootWindow());
259 if (screen_position_client)
260 screen_position_client->ConvertPointToScreen(window, point);
263 void TouchEditableImplAura::ConvertPointFromScreen(gfx::Point* point) {
264 if (!rwhva_)
265 return;
266 aura::Window* window = rwhva_->GetNativeView();
267 aura::client::ScreenPositionClient* screen_position_client =
268 aura::client::GetScreenPositionClient(window->GetRootWindow());
269 if (screen_position_client)
270 screen_position_client->ConvertPointFromScreen(window, point);
273 bool TouchEditableImplAura::DrawsHandles() {
274 return false;
277 void TouchEditableImplAura::OpenContextMenu(const gfx::Point& anchor) {
278 if (!rwhva_)
279 return;
280 gfx::Point point = anchor;
281 ConvertPointFromScreen(&point);
282 RenderWidgetHost* host = rwhva_->GetRenderWidgetHost();
283 host->Send(new ViewMsg_ShowContextMenu(
284 host->GetRoutingID(), ui::MENU_SOURCE_TOUCH_EDIT_MENU, point));
285 EndTouchEditing(false);
288 bool TouchEditableImplAura::IsCommandIdChecked(int command_id) const {
289 NOTREACHED();
290 return false;
293 bool TouchEditableImplAura::IsCommandIdEnabled(int command_id) const {
294 if (!rwhva_)
295 return false;
296 bool editable = rwhva_->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE;
297 bool readable = rwhva_->GetTextInputType() != ui::TEXT_INPUT_TYPE_PASSWORD;
298 gfx::Range selection_range;
299 rwhva_->GetSelectionRange(&selection_range);
300 bool has_selection = !selection_range.is_empty();
301 switch (command_id) {
302 case IDS_APP_CUT:
303 return editable && readable && has_selection;
304 case IDS_APP_COPY:
305 return readable && has_selection;
306 case IDS_APP_PASTE: {
307 base::string16 result;
308 ui::Clipboard::GetForCurrentThread()->ReadText(
309 ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
310 return editable && !result.empty();
312 case IDS_APP_DELETE:
313 return editable && has_selection;
314 case IDS_APP_SELECT_ALL:
315 return true;
316 default:
317 return false;
321 bool TouchEditableImplAura::GetAcceleratorForCommandId(
322 int command_id,
323 ui::Accelerator* accelerator) {
324 return false;
327 void TouchEditableImplAura::ExecuteCommand(int command_id, int event_flags) {
328 RenderWidgetHost* host = rwhva_->GetRenderWidgetHost();
329 RenderViewHost* rvh = RenderViewHost::From(host);
330 WebContents* wc = WebContents::FromRenderViewHost(rvh);
332 switch (command_id) {
333 case IDS_APP_CUT:
334 wc->Cut();
335 break;
336 case IDS_APP_COPY:
337 wc->Copy();
338 break;
339 case IDS_APP_PASTE:
340 wc->Paste();
341 break;
342 case IDS_APP_DELETE:
343 wc->Delete();
344 break;
345 case IDS_APP_SELECT_ALL:
346 wc->SelectAll();
347 break;
348 default:
349 NOTREACHED();
350 break;
352 EndTouchEditing(false);
355 void TouchEditableImplAura::DestroyTouchSelection() {
356 EndTouchEditing(false);
359 ////////////////////////////////////////////////////////////////////////////////
360 // TouchEditableImplAura, private:
362 TouchEditableImplAura::TouchEditableImplAura()
363 : text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
364 rwhva_(NULL),
365 selection_gesture_in_process_(false),
366 handles_hidden_due_to_scroll_(false),
367 scroll_in_progress_(false),
368 overscroll_in_progress_(false),
369 textfield_was_focused_on_tap_(false) {
372 void TouchEditableImplAura::Cleanup() {
373 if (rwhva_) {
374 rwhva_->set_touch_editing_client(NULL);
375 rwhva_ = NULL;
377 text_input_type_ = ui::TEXT_INPUT_TYPE_NONE;
378 EndTouchEditing(true);
379 selection_gesture_in_process_ = false;
380 handles_hidden_due_to_scroll_ = false;
381 scroll_in_progress_ = false;
382 overscroll_in_progress_ = false;
385 } // namespace content