OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/input/touch_selection_controller.h" | 5 #include "content/browser/renderer_host/input/touch_selection_controller.h" |
6 | 6 |
| 7 #include "base/auto_reset.h" |
7 #include "base/logging.h" | 8 #include "base/logging.h" |
8 #include "third_party/WebKit/public/web/WebInputEvent.h" | 9 #include "third_party/WebKit/public/web/WebInputEvent.h" |
9 | 10 |
10 namespace content { | 11 namespace content { |
11 | 12 |
12 TouchSelectionController::TouchSelectionController( | 13 TouchSelectionController::TouchSelectionController( |
13 TouchSelectionControllerClient* client) | 14 TouchSelectionControllerClient* client) |
14 : client_(client), | 15 : client_(client), |
15 last_input_event_type_(INPUT_EVENT_TYPE_NONE), | 16 response_pending_input_event_(INPUT_EVENT_TYPE_NONE), |
16 start_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED), | 17 start_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED), |
17 start_visible_(false), | 18 start_visible_(false), |
18 end_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED), | 19 end_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED), |
19 end_visible_(false), | 20 end_visible_(false), |
20 is_insertion_active_(false), | 21 is_insertion_active_(false), |
21 activate_insertion_automatically_(false), | 22 activate_insertion_automatically_(false), |
22 is_selection_active_(false), | 23 is_selection_active_(false), |
23 activate_selection_automatically_(false), | 24 activate_selection_automatically_(false), |
24 selection_empty_(false), | 25 selection_empty_(false), |
25 selection_editable_(false), | 26 selection_editable_(false), |
26 temporarily_hidden_(false) { | 27 temporarily_hidden_(false) { |
27 DCHECK(client_); | 28 DCHECK(client_); |
28 HideAndDisallowShowingAutomatically(); | 29 HideAndDisallowShowingAutomatically(); |
29 } | 30 } |
30 | 31 |
31 TouchSelectionController::~TouchSelectionController() { | 32 TouchSelectionController::~TouchSelectionController() { |
32 } | 33 } |
33 | 34 |
34 void TouchSelectionController::OnSelectionBoundsChanged( | 35 void TouchSelectionController::OnSelectionBoundsChanged( |
35 const gfx::RectF& start_rect, | 36 const gfx::RectF& start_rect, |
36 TouchHandleOrientation start_orientation, | 37 TouchHandleOrientation start_orientation, |
37 bool start_visible, | 38 bool start_visible, |
38 const gfx::RectF& end_rect, | 39 const gfx::RectF& end_rect, |
39 TouchHandleOrientation end_orientation, | 40 TouchHandleOrientation end_orientation, |
40 bool end_visible) { | 41 bool end_visible) { |
41 if (!activate_selection_automatically_ && !activate_insertion_automatically_) | 42 if (!activate_selection_automatically_ && |
| 43 !activate_insertion_automatically_) { |
| 44 DCHECK_EQ(INPUT_EVENT_TYPE_NONE, response_pending_input_event_); |
42 return; | 45 return; |
| 46 } |
43 | 47 |
44 if (start_rect_ == start_rect && end_rect_ == end_rect && | 48 if (start_rect_ == start_rect && end_rect_ == end_rect && |
45 start_orientation_ == start_orientation && | 49 start_orientation_ == start_orientation && |
46 end_orientation_ == end_orientation && start_visible_ == start_visible && | 50 end_orientation_ == end_orientation && start_visible_ == start_visible && |
47 end_visible_ == end_visible) | 51 end_visible_ == end_visible) |
48 return; | 52 return; |
49 | 53 |
50 start_rect_ = start_rect; | 54 start_rect_ = start_rect; |
51 start_orientation_ = start_orientation; | 55 start_orientation_ = start_orientation; |
52 start_visible_ = start_visible; | 56 start_visible_ = start_visible; |
53 end_rect_ = end_rect; | 57 end_rect_ = end_rect; |
54 end_orientation_ = end_orientation; | 58 end_orientation_ = end_orientation; |
55 end_visible_ = end_visible; | 59 end_visible_ = end_visible; |
56 | 60 |
| 61 // Ensure that |response_pending_input_event_| is cleared after the method |
| 62 // completes, while also making its current value available for the duration |
| 63 // of the call. |
| 64 InputEventType causal_input_event = response_pending_input_event_; |
| 65 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE; |
| 66 base::AutoReset<InputEventType> auto_reset_response_pending_input_event( |
| 67 &response_pending_input_event_, causal_input_event); |
| 68 |
57 const bool is_selection_dragging = | 69 const bool is_selection_dragging = |
58 is_selection_active_ && (start_selection_handle_->is_dragging() || | 70 is_selection_active_ && (start_selection_handle_->is_dragging() || |
59 end_selection_handle_->is_dragging()); | 71 end_selection_handle_->is_dragging()); |
60 | 72 |
61 // It's possible that the bounds temporarily overlap while a selection handle | 73 // It's possible that the bounds temporarily overlap while a selection handle |
62 // is being dragged, incorrectly reporting a CENTER orientation. | 74 // is being dragged, incorrectly reporting a CENTER orientation. |
63 // TODO(jdduke): This safeguard is racy, as it's possible the delayed response | 75 // TODO(jdduke): This safeguard is racy, as it's possible the delayed response |
64 // from handle positioning occurs *after* the handle dragging has ceased. | 76 // from handle positioning occurs *after* the handle dragging has ceased. |
65 // Instead, prevent selection -> insertion transitions without an intervening | 77 // Instead, prevent selection -> insertion transitions without an intervening |
66 // action or selection clearing of some sort, crbug.com/392696. | 78 // action or selection clearing of some sort, crbug.com/392696. |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 (event_pos - GetEndPosition()).LengthSquared()) | 122 (event_pos - GetEndPosition()).LengthSquared()) |
111 return start_selection_handle_->WillHandleTouchEvent(event); | 123 return start_selection_handle_->WillHandleTouchEvent(event); |
112 else | 124 else |
113 return end_selection_handle_->WillHandleTouchEvent(event); | 125 return end_selection_handle_->WillHandleTouchEvent(event); |
114 } | 126 } |
115 | 127 |
116 return false; | 128 return false; |
117 } | 129 } |
118 | 130 |
119 void TouchSelectionController::OnLongPressEvent() { | 131 void TouchSelectionController::OnLongPressEvent() { |
120 last_input_event_type_ = LONG_PRESS; | 132 response_pending_input_event_ = LONG_PRESS; |
121 ShowSelectionHandlesAutomatically(); | 133 ShowSelectionHandlesAutomatically(); |
122 ShowInsertionHandleAutomatically(); | 134 ShowInsertionHandleAutomatically(); |
123 ResetCachedValuesIfInactive(); | 135 ResetCachedValuesIfInactive(); |
124 } | 136 } |
125 | 137 |
126 void TouchSelectionController::OnTapEvent() { | 138 void TouchSelectionController::OnTapEvent() { |
127 last_input_event_type_ = TAP; | 139 response_pending_input_event_ = TAP; |
128 activate_selection_automatically_ = false; | 140 activate_selection_automatically_ = false; |
129 DeactivateSelection(); | 141 DeactivateSelection(); |
130 ShowInsertionHandleAutomatically(); | 142 ShowInsertionHandleAutomatically(); |
131 ResetCachedValuesIfInactive(); | 143 ResetCachedValuesIfInactive(); |
132 } | 144 } |
133 | 145 |
134 void TouchSelectionController::HideAndDisallowShowingAutomatically() { | 146 void TouchSelectionController::HideAndDisallowShowingAutomatically() { |
135 last_input_event_type_ = INPUT_EVENT_TYPE_NONE; | 147 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE; |
136 DeactivateInsertion(); | 148 DeactivateInsertion(); |
137 DeactivateSelection(); | 149 DeactivateSelection(); |
138 activate_insertion_automatically_ = false; | 150 activate_insertion_automatically_ = false; |
139 activate_selection_automatically_ = false; | 151 activate_selection_automatically_ = false; |
140 } | 152 } |
141 | 153 |
142 void TouchSelectionController::SetTemporarilyHidden(bool hidden) { | 154 void TouchSelectionController::SetTemporarilyHidden(bool hidden) { |
143 if (temporarily_hidden_ == hidden) | 155 if (temporarily_hidden_ == hidden) |
144 return; | 156 return; |
145 temporarily_hidden_ = hidden; | 157 temporarily_hidden_ = hidden; |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 void TouchSelectionController::ShowSelectionHandlesAutomatically() { | 253 void TouchSelectionController::ShowSelectionHandlesAutomatically() { |
242 if (activate_selection_automatically_) | 254 if (activate_selection_automatically_) |
243 return; | 255 return; |
244 activate_selection_automatically_ = true; | 256 activate_selection_automatically_ = true; |
245 ResetCachedValuesIfInactive(); | 257 ResetCachedValuesIfInactive(); |
246 } | 258 } |
247 | 259 |
248 void TouchSelectionController::OnInsertionChanged() { | 260 void TouchSelectionController::OnInsertionChanged() { |
249 DeactivateSelection(); | 261 DeactivateSelection(); |
250 | 262 |
251 if (last_input_event_type_ == TAP && selection_empty_) { | 263 if (response_pending_input_event_ == TAP && selection_empty_) { |
252 HideAndDisallowShowingAutomatically(); | 264 HideAndDisallowShowingAutomatically(); |
253 return; | 265 return; |
254 } | 266 } |
255 | 267 |
256 if (!activate_insertion_automatically_) | 268 if (!activate_insertion_automatically_) |
257 return; | 269 return; |
258 | 270 |
259 const bool was_active = is_insertion_active_; | 271 const bool was_active = is_insertion_active_; |
260 const gfx::PointF position = GetStartPosition(); | 272 const gfx::PointF position = GetStartPosition(); |
261 if (!is_insertion_active_) | 273 if (!is_insertion_active_) |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
317 start_selection_handle_->SetOrientation(start_orientation_); | 329 start_selection_handle_->SetOrientation(start_orientation_); |
318 } | 330 } |
319 | 331 |
320 if (!end_selection_handle_) { | 332 if (!end_selection_handle_) { |
321 end_selection_handle_.reset(new TouchHandle(this, end_orientation_)); | 333 end_selection_handle_.reset(new TouchHandle(this, end_orientation_)); |
322 } else { | 334 } else { |
323 end_selection_handle_->SetEnabled(true); | 335 end_selection_handle_->SetEnabled(true); |
324 end_selection_handle_->SetOrientation(end_orientation_); | 336 end_selection_handle_->SetOrientation(end_orientation_); |
325 } | 337 } |
326 | 338 |
327 if (!is_selection_active_) { | 339 // As a long press received while a selection is already active may trigger |
| 340 // an entirely new selection, notify the client but avoid sending an |
| 341 // intervening SELECTION_CLEARED update to avoid unnecessary state changes. |
| 342 if (!is_selection_active_ || response_pending_input_event_ == LONG_PRESS) { |
328 is_selection_active_ = true; | 343 is_selection_active_ = true; |
| 344 response_pending_input_event_ = INPUT_EVENT_TYPE_NONE; |
329 client_->OnSelectionEvent(SELECTION_SHOWN, GetStartPosition()); | 345 client_->OnSelectionEvent(SELECTION_SHOWN, GetStartPosition()); |
330 } | 346 } |
331 } | 347 } |
332 | 348 |
333 void TouchSelectionController::DeactivateSelection() { | 349 void TouchSelectionController::DeactivateSelection() { |
334 if (!is_selection_active_) | 350 if (!is_selection_active_) |
335 return; | 351 return; |
336 DCHECK(start_selection_handle_); | 352 DCHECK(start_selection_handle_); |
337 DCHECK(end_selection_handle_); | 353 DCHECK(end_selection_handle_); |
338 start_selection_handle_->SetEnabled(false); | 354 start_selection_handle_->SetEnabled(false); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 } | 393 } |
378 | 394 |
379 TouchHandle::AnimationStyle TouchSelectionController::GetAnimationStyle( | 395 TouchHandle::AnimationStyle TouchSelectionController::GetAnimationStyle( |
380 bool was_active) const { | 396 bool was_active) const { |
381 return was_active && client_->SupportsAnimation() | 397 return was_active && client_->SupportsAnimation() |
382 ? TouchHandle::ANIMATION_SMOOTH | 398 ? TouchHandle::ANIMATION_SMOOTH |
383 : TouchHandle::ANIMATION_NONE; | 399 : TouchHandle::ANIMATION_NONE; |
384 } | 400 } |
385 | 401 |
386 } // namespace content | 402 } // namespace content |
OLD | NEW |