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 "ui/events/gesture_detection/gesture_provider.h" | 5 #include "ui/events/gesture_detection/gesture_provider.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 | 8 |
9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
(...skipping 25 matching lines...) Expand all Loading... |
36 float y, | 36 float y, |
37 const GestureEventDetails& details) { | 37 const GestureEventDetails& details) { |
38 return GestureEventData(type, time, x, y, details); | 38 return GestureEventData(type, time, x, y, details); |
39 } | 39 } |
40 | 40 |
41 GestureEventData CreateGesture(EventType type, | 41 GestureEventData CreateGesture(EventType type, |
42 base::TimeTicks time, | 42 base::TimeTicks time, |
43 float x, | 43 float x, |
44 float y) { | 44 float y) { |
45 return GestureEventData(type, time, x, y); | 45 return GestureEventData(type, time, x, y); |
46 } | 46 } |
47 | 47 |
48 GestureEventData CreateGesture(EventType type, | 48 GestureEventData CreateGesture(EventType type, |
49 const MotionEvent& event, | 49 const MotionEvent& event, |
50 const GestureEventDetails& details) { | 50 const GestureEventDetails& details) { |
51 return CreateGesture( | 51 return CreateGesture( |
52 type, event.GetEventTime(), event.GetX(), event.GetY(), details); | 52 type, event.GetEventTime(), event.GetX(), event.GetY(), details); |
53 } | 53 } |
54 | 54 |
55 GestureEventData CreateGesture(EventType type, | 55 GestureEventData CreateGesture(EventType type, |
56 const MotionEvent& event) { | 56 const MotionEvent& event) { |
57 return CreateGesture(type, event.GetEventTime(), event.GetX(), event.GetY()); | 57 return CreateGesture(type, event.GetEventTime(), event.GetX(), event.GetY()); |
58 } | 58 } |
59 | 59 |
60 float Round(float f) { | |
61 return (f > 0.f) ? std::floor(f + 0.5f) : std::ceil(f - 0.5f); | |
62 } | |
63 | |
64 GestureEventDetails CreateTapGestureDetails(EventType type, | 60 GestureEventDetails CreateTapGestureDetails(EventType type, |
65 const MotionEvent& event) { | 61 const MotionEvent& event) { |
66 // Set the tap count to 1 even for ET_GESTURE_DOUBLE_TAP, in order to be | 62 // Set the tap count to 1 even for ET_GESTURE_DOUBLE_TAP, in order to be |
67 // consistent with double tap behavior on a mobile viewport. See | 63 // consistent with double tap behavior on a mobile viewport. See |
68 // crbug.com/234986 for context. | 64 // crbug.com/234986 for context. |
69 GestureEventDetails tap_details(type, 1, 0); | 65 GestureEventDetails tap_details(type, 1, 0); |
70 tap_details.set_bounding_box( | 66 tap_details.set_bounding_box( |
71 gfx::RectF(event.GetTouchMajor(), event.GetTouchMajor())); | 67 gfx::RectF(event.GetTouchMajor(), event.GetTouchMajor())); |
72 return tap_details; | 68 return tap_details; |
73 } | 69 } |
74 | 70 |
75 } // namespace | 71 } // namespace |
76 | 72 |
77 // GestureProvider:::Config | 73 // GestureProvider:::Config |
78 | 74 |
79 GestureProvider::Config::Config() : disable_click_delay(false) {} | 75 GestureProvider::Config::Config() : disable_click_delay(false) {} |
80 | 76 |
81 GestureProvider::Config::~Config() {} | 77 GestureProvider::Config::~Config() {} |
82 | 78 |
83 // GestureProvider::ScaleGestureListener | 79 // GestureProvider::ScaleGestureListener |
84 | 80 |
85 class GestureProvider::ScaleGestureListenerImpl | 81 class GestureProvider::ScaleGestureListenerImpl |
86 : public ScaleGestureDetector::ScaleGestureListener { | 82 : public ScaleGestureDetector::ScaleGestureListener { |
87 public: | 83 public: |
88 ScaleGestureListenerImpl(const ScaleGestureDetector::Config& config, | 84 ScaleGestureListenerImpl(const ScaleGestureDetector::Config& config, |
| 85 float device_scale_factor, |
89 GestureProvider* provider) | 86 GestureProvider* provider) |
90 : scale_gesture_detector_(config, this), | 87 : scale_gesture_detector_(config, this), |
91 provider_(provider), | 88 provider_(provider), |
92 ignore_detector_events_(false), | 89 px_to_dp_(1.0f / device_scale_factor), |
| 90 ignore_multitouch_events_(false), |
93 pinch_event_sent_(false) {} | 91 pinch_event_sent_(false) {} |
94 | 92 |
95 bool OnTouchEvent(const MotionEvent& event) { | 93 bool OnTouchEvent(const MotionEvent& event) { |
96 // TODO: Need to deal with multi-touch transition. | 94 // TODO: Need to deal with multi-touch transition. |
97 const bool in_scale_gesture = IsScaleGestureDetectionInProgress(); | 95 const bool in_scale_gesture = IsScaleGestureDetectionInProgress(); |
98 bool handled = scale_gesture_detector_.OnTouchEvent(event); | 96 bool handled = scale_gesture_detector_.OnTouchEvent(event); |
99 if (!in_scale_gesture && | 97 if (!in_scale_gesture && |
100 (event.GetAction() == MotionEvent::ACTION_UP || | 98 (event.GetAction() == MotionEvent::ACTION_UP || |
101 event.GetAction() == MotionEvent::ACTION_CANCEL)) { | 99 event.GetAction() == MotionEvent::ACTION_CANCEL)) { |
102 return false; | 100 return false; |
103 } | 101 } |
104 return handled; | 102 return handled; |
105 } | 103 } |
106 | 104 |
107 // ScaleGestureDetector::ScaleGestureListener implementation. | 105 // ScaleGestureDetector::ScaleGestureListener implementation. |
108 virtual bool OnScaleBegin(const ScaleGestureDetector& detector) OVERRIDE { | 106 virtual bool OnScaleBegin(const ScaleGestureDetector& detector) OVERRIDE { |
109 if (ignore_detector_events_) | 107 if (ignore_multitouch_events_ && !detector.InDoubleTapMode()) |
110 return false; | 108 return false; |
111 pinch_event_sent_ = false; | 109 pinch_event_sent_ = false; |
112 return true; | 110 return true; |
113 } | 111 } |
114 | 112 |
115 virtual void OnScaleEnd(const ScaleGestureDetector& detector) OVERRIDE { | 113 virtual void OnScaleEnd(const ScaleGestureDetector& detector) OVERRIDE { |
116 if (!pinch_event_sent_) | 114 if (!pinch_event_sent_) |
117 return; | 115 return; |
118 provider_->Send( | 116 provider_->Send( |
119 CreateGesture(ET_GESTURE_PINCH_END, detector.GetEventTime(), 0, 0)); | 117 CreateGesture(ET_GESTURE_PINCH_END, detector.GetEventTime(), 0, 0)); |
120 pinch_event_sent_ = false; | 118 pinch_event_sent_ = false; |
121 } | 119 } |
122 | 120 |
123 virtual bool OnScale(const ScaleGestureDetector& detector) OVERRIDE { | 121 virtual bool OnScale(const ScaleGestureDetector& detector) OVERRIDE { |
124 if (ignore_detector_events_) | 122 if (ignore_multitouch_events_ && !detector.InDoubleTapMode()) |
125 return false; | 123 return false; |
126 if (!pinch_event_sent_) { | 124 if (!pinch_event_sent_) { |
127 pinch_event_sent_ = true; | 125 pinch_event_sent_ = true; |
128 provider_->Send(CreateGesture(ET_GESTURE_PINCH_BEGIN, | 126 provider_->Send(CreateGesture(ET_GESTURE_PINCH_BEGIN, |
129 detector.GetEventTime(), | 127 detector.GetEventTime(), |
130 detector.GetFocusX(), | 128 detector.GetFocusX(), |
131 detector.GetFocusY())); | 129 detector.GetFocusY())); |
132 } | 130 } |
133 GestureEventDetails pinch_details( | 131 |
134 ET_GESTURE_PINCH_UPDATE, detector.GetScaleFactor(), 0); | 132 float scale = detector.GetScaleFactor(); |
| 133 if (scale == 1) |
| 134 return true; |
| 135 |
| 136 if (detector.InDoubleTapMode()) { |
| 137 // Relative changes in the double-tap scale factor computed by |detector| |
| 138 // diminish as the touch moves away from the original double-tap focus. |
| 139 // For historical reasons, Chrome has instead adopted a scale factor |
| 140 // computation that is invariant to the focal distance, where |
| 141 // the scale delta remains constant if the touch velocity is constant. |
| 142 float dy = |
| 143 (detector.GetCurrentSpanY() - detector.GetPreviousSpanY()) * 0.5f; |
| 144 scale = std::pow(scale > 1 ? 1.0f + kDoubleTapDragZoomSpeed |
| 145 : 1.0f - kDoubleTapDragZoomSpeed, |
| 146 std::abs(dy * px_to_dp_)); |
| 147 } |
| 148 GestureEventDetails pinch_details(ET_GESTURE_PINCH_UPDATE, scale, 0); |
135 provider_->Send(CreateGesture(ET_GESTURE_PINCH_UPDATE, | 149 provider_->Send(CreateGesture(ET_GESTURE_PINCH_UPDATE, |
136 detector.GetEventTime(), | 150 detector.GetEventTime(), |
137 detector.GetFocusX(), | 151 detector.GetFocusX(), |
138 detector.GetFocusY(), | 152 detector.GetFocusY(), |
139 pinch_details)); | 153 pinch_details)); |
140 return true; | 154 return true; |
141 } | 155 } |
142 | 156 |
143 bool IsScaleGestureDetectionInProgress() const { | 157 void SetDoubleTapEnabled(bool enabled) { |
144 return !ignore_detector_events_ && scale_gesture_detector_.IsInProgress(); | 158 DCHECK(!IsDoubleTapInProgress()); |
| 159 scale_gesture_detector_.SetQuickScaleEnabled(enabled); |
145 } | 160 } |
146 | 161 |
147 void set_ignore_detector_events(bool value) { | 162 void SetMultiTouchEnabled(bool value) { |
148 // Note that returning false from OnScaleBegin / OnScale makes the | 163 // Note that returning false from OnScaleBegin / OnScale makes the |
149 // gesture detector not to emit further scaling notifications | 164 // gesture detector not to emit further scaling notifications |
150 // related to this gesture. Thus, if detector events are enabled in | 165 // related to this gesture. Thus, if detector events are enabled in |
151 // the middle of the gesture, we don't need to do anything. | 166 // the middle of the gesture, we don't need to do anything. |
152 ignore_detector_events_ = value; | 167 ignore_multitouch_events_ = value; |
| 168 } |
| 169 |
| 170 bool IsDoubleTapInProgress() const { |
| 171 return IsScaleGestureDetectionInProgress() && InDoubleTapMode(); |
| 172 } |
| 173 |
| 174 bool IsScaleGestureDetectionInProgress() const { |
| 175 return scale_gesture_detector_.IsInProgress(); |
153 } | 176 } |
154 | 177 |
155 private: | 178 private: |
| 179 bool InDoubleTapMode() const { |
| 180 return scale_gesture_detector_.InDoubleTapMode(); |
| 181 } |
| 182 |
156 ScaleGestureDetector scale_gesture_detector_; | 183 ScaleGestureDetector scale_gesture_detector_; |
157 | 184 |
158 GestureProvider* const provider_; | 185 GestureProvider* const provider_; |
159 | 186 |
160 // Completely silence scaling events. Used in WebView when zoom support | 187 // TODO(jdduke): Remove this when all MotionEvent's use DIPs. |
161 // is turned off. | 188 const float px_to_dp_; |
162 bool ignore_detector_events_; | 189 |
| 190 // Completely silence multi-touch (pinch) scaling events. Used in WebView when |
| 191 // zoom support is turned off. |
| 192 bool ignore_multitouch_events_; |
163 | 193 |
164 // Whether any pinch zoom event has been sent to native. | 194 // Whether any pinch zoom event has been sent to native. |
165 bool pinch_event_sent_; | 195 bool pinch_event_sent_; |
166 | 196 |
167 DISALLOW_COPY_AND_ASSIGN(ScaleGestureListenerImpl); | 197 DISALLOW_COPY_AND_ASSIGN(ScaleGestureListenerImpl); |
168 }; | 198 }; |
169 | 199 |
170 // GestureProvider::GestureListener | 200 // GestureProvider::GestureListener |
171 | 201 |
172 class GestureProvider::GestureListenerImpl | 202 class GestureProvider::GestureListenerImpl |
173 : public GestureDetector::GestureListener, | 203 : public GestureDetector::GestureListener, |
174 public GestureDetector::DoubleTapListener { | 204 public GestureDetector::DoubleTapListener { |
175 public: | 205 public: |
176 GestureListenerImpl( | 206 GestureListenerImpl( |
177 const GestureDetector::Config& gesture_detector_config, | 207 const GestureDetector::Config& gesture_detector_config, |
178 const SnapScrollController::Config& snap_scroll_controller_config, | 208 const SnapScrollController::Config& snap_scroll_controller_config, |
179 bool disable_click_delay, | 209 bool disable_click_delay, |
180 GestureProvider* provider) | 210 GestureProvider* provider) |
181 : gesture_detector_(gesture_detector_config, this, this), | 211 : gesture_detector_(gesture_detector_config, this, this), |
182 snap_scroll_controller_(snap_scroll_controller_config), | 212 snap_scroll_controller_(snap_scroll_controller_config), |
183 provider_(provider), | 213 provider_(provider), |
184 px_to_dp_(1.0f / snap_scroll_controller_config.device_scale_factor), | |
185 disable_click_delay_(disable_click_delay), | 214 disable_click_delay_(disable_click_delay), |
186 scaled_touch_slop_(gesture_detector_config.scaled_touch_slop), | 215 scaled_touch_slop_(gesture_detector_config.scaled_touch_slop), |
187 scaled_touch_slop_square_(scaled_touch_slop_ * scaled_touch_slop_), | 216 scaled_touch_slop_square_(scaled_touch_slop_ * scaled_touch_slop_), |
188 double_tap_timeout_(gesture_detector_config.double_tap_timeout), | 217 double_tap_timeout_(gesture_detector_config.double_tap_timeout), |
189 ignore_single_tap_(false), | 218 ignore_single_tap_(false), |
190 seen_first_scroll_event_(false), | 219 seen_first_scroll_event_(false), |
191 double_tap_mode_(DOUBLE_TAP_MODE_NONE), | |
192 double_tap_y_(0), | |
193 double_tap_support_enabled_(true), | |
194 double_tap_drag_zoom_anchor_x_(0), | |
195 double_tap_drag_zoom_anchor_y_(0), | |
196 last_raw_x_(0), | 220 last_raw_x_(0), |
197 last_raw_y_(0), | 221 last_raw_y_(0), |
198 accumulated_scroll_error_x_(0), | 222 accumulated_scroll_error_x_(0), |
199 accumulated_scroll_error_y_(0) { | 223 accumulated_scroll_error_y_(0) {} |
200 UpdateDoubleTapListener(); | |
201 } | |
202 | 224 |
203 virtual ~GestureListenerImpl() {} | 225 virtual ~GestureListenerImpl() {} |
204 | 226 |
205 bool OnTouchEvent(const MotionEvent& e, | 227 bool OnTouchEvent(const MotionEvent& e, |
206 bool is_scale_gesture_detection_in_progress) { | 228 bool is_scale_gesture_detection_in_progress) { |
207 snap_scroll_controller_.SetSnapScrollingMode( | 229 snap_scroll_controller_.SetSnapScrollingMode( |
208 e, is_scale_gesture_detection_in_progress); | 230 e, is_scale_gesture_detection_in_progress); |
209 | 231 |
210 if (is_scale_gesture_detection_in_progress) | 232 if (is_scale_gesture_detection_in_progress) |
211 SetIgnoreSingleTap(true); | 233 SetIgnoreSingleTap(true); |
212 | 234 |
213 if (e.GetAction() == MotionEvent::ACTION_POINTER_DOWN || | 235 if (e.GetAction() == MotionEvent::ACTION_DOWN) |
214 e.GetAction() == MotionEvent::ACTION_CANCEL) { | |
215 EndDoubleTapDragIfNecessary(e); | |
216 } else if (e.GetAction() == MotionEvent::ACTION_DOWN) { | |
217 gesture_detector_.set_is_longpress_enabled(true); | 236 gesture_detector_.set_is_longpress_enabled(true); |
218 } | |
219 | 237 |
220 return gesture_detector_.OnTouchEvent(e); | 238 return gesture_detector_.OnTouchEvent(e); |
221 } | 239 } |
222 | 240 |
223 // GestureDetector::GestureListener implementation. | 241 // GestureDetector::GestureListener implementation. |
224 virtual bool OnDown(const MotionEvent& e) OVERRIDE { | 242 virtual bool OnDown(const MotionEvent& e) OVERRIDE { |
225 current_down_time_ = e.GetEventTime(); | 243 current_down_time_ = e.GetEventTime(); |
226 ignore_single_tap_ = false; | 244 ignore_single_tap_ = false; |
227 seen_first_scroll_event_ = false; | 245 seen_first_scroll_event_ = false; |
228 last_raw_x_ = e.GetRawX(); | 246 last_raw_x_ = e.GetRawX(); |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 } | 354 } |
337 // This is a hack to address the issue where user hovers | 355 // This is a hack to address the issue where user hovers |
338 // over a link for longer than double_tap_timeout_, then | 356 // over a link for longer than double_tap_timeout_, then |
339 // OnSingleTapConfirmed() is not triggered. But we still | 357 // OnSingleTapConfirmed() is not triggered. But we still |
340 // want to trigger the tap event at UP. So we override | 358 // want to trigger the tap event at UP. So we override |
341 // OnSingleTapUp() in this case. This assumes singleTapUp | 359 // OnSingleTapUp() in this case. This assumes singleTapUp |
342 // gets always called before singleTapConfirmed. | 360 // gets always called before singleTapConfirmed. |
343 if (!ignore_single_tap_) { | 361 if (!ignore_single_tap_) { |
344 if (e.GetEventTime() - current_down_time_ > double_tap_timeout_) { | 362 if (e.GetEventTime() - current_down_time_ > double_tap_timeout_) { |
345 return OnSingleTapConfirmed(e); | 363 return OnSingleTapConfirmed(e); |
346 } else if (IsDoubleTapDisabled() || disable_click_delay_) { | 364 } else if (!IsDoubleTapEnabled() || disable_click_delay_) { |
347 // If double-tap has been disabled, there is no need to wait | 365 // If double-tap has been disabled, there is no need to wait |
348 // for the double-tap timeout. | 366 // for the double-tap timeout. |
349 return OnSingleTapConfirmed(e); | 367 return OnSingleTapConfirmed(e); |
350 } else { | 368 } else { |
351 // Notify Blink about this tapUp event anyway, when none of the above | 369 // Notify Blink about this tapUp event anyway, when none of the above |
352 // conditions applied. | 370 // conditions applied. |
353 provider_->Send(CreateGesture( | 371 provider_->Send(CreateGesture( |
354 ET_GESTURE_TAP_UNCONFIRMED, | 372 ET_GESTURE_TAP_UNCONFIRMED, |
355 e, | 373 e, |
356 CreateTapGestureDetails(ET_GESTURE_TAP_UNCONFIRMED, e))); | 374 CreateTapGestureDetails(ET_GESTURE_TAP_UNCONFIRMED, e))); |
(...skipping 17 matching lines...) Expand all Loading... |
374 provider_->Send(CreateGesture( | 392 provider_->Send(CreateGesture( |
375 ET_GESTURE_TAP, e, CreateTapGestureDetails(ET_GESTURE_TAP, e))); | 393 ET_GESTURE_TAP, e, CreateTapGestureDetails(ET_GESTURE_TAP, e))); |
376 return true; | 394 return true; |
377 } | 395 } |
378 | 396 |
379 virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE { return false; } | 397 virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE { return false; } |
380 | 398 |
381 virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE { | 399 virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE { |
382 switch (e.GetAction()) { | 400 switch (e.GetAction()) { |
383 case MotionEvent::ACTION_DOWN: | 401 case MotionEvent::ACTION_DOWN: |
384 // Note that this will be called before the corresponding |onDown()| | |
385 // of the same ACTION_DOWN event. Thus, the preceding TAP_DOWN | |
386 // should be cancelled prior to sending a new one (in |onDown()|). | |
387 double_tap_drag_zoom_anchor_x_ = e.GetX(); | |
388 double_tap_drag_zoom_anchor_y_ = e.GetY(); | |
389 double_tap_mode_ = DOUBLE_TAP_MODE_DRAG_DETECTION_IN_PROGRESS; | |
390 // If a long-press fires during a double-tap, the GestureDetector | |
391 // will stop feeding MotionEvents to |onDoubleTapEvent()|, | |
392 // preventing double-tap drag zoom. Long press detection will be | |
393 // re-enabled on the next ACTION_DOWN. | |
394 gesture_detector_.set_is_longpress_enabled(false); | 402 gesture_detector_.set_is_longpress_enabled(false); |
395 break; | 403 break; |
396 case MotionEvent::ACTION_MOVE: | |
397 if (double_tap_mode_ == DOUBLE_TAP_MODE_DRAG_DETECTION_IN_PROGRESS) { | |
398 float distance_x = double_tap_drag_zoom_anchor_x_ - e.GetX(); | |
399 float distance_y = double_tap_drag_zoom_anchor_y_ - e.GetY(); | |
400 | 404 |
401 // Begin double-tap drag zoom mode if the move distance is | |
402 // further than the threshold. | |
403 if (IsDistanceGreaterThanTouchSlop(distance_x, distance_y)) { | |
404 GestureEventDetails scroll_details( | |
405 ET_GESTURE_SCROLL_BEGIN, -distance_x, -distance_y); | |
406 provider_->Send( | |
407 CreateGesture(ET_GESTURE_SCROLL_BEGIN, e, scroll_details)); | |
408 provider_->Send( | |
409 CreateGesture(ET_GESTURE_PINCH_BEGIN, | |
410 e.GetEventTime(), | |
411 Round(double_tap_drag_zoom_anchor_x_), | |
412 Round(double_tap_drag_zoom_anchor_y_))); | |
413 double_tap_mode_ = DOUBLE_TAP_MODE_DRAG_ZOOM; | |
414 } | |
415 } else if (double_tap_mode_ == DOUBLE_TAP_MODE_DRAG_ZOOM) { | |
416 provider_->Send(CreateGesture(ET_GESTURE_SCROLL_UPDATE, e)); | |
417 | |
418 float dy = double_tap_y_ - e.GetY(); | |
419 float scale = std::pow(dy > 0 ? 1.0f - kDoubleTapDragZoomSpeed | |
420 : 1.0f + kDoubleTapDragZoomSpeed, | |
421 std::abs(dy * px_to_dp_)); | |
422 GestureEventDetails pinch_details(ET_GESTURE_PINCH_UPDATE, scale, 0); | |
423 provider_->Send(CreateGesture(ET_GESTURE_PINCH_UPDATE, | |
424 e.GetEventTime(), | |
425 Round(double_tap_drag_zoom_anchor_x_), | |
426 Round(double_tap_drag_zoom_anchor_y_), | |
427 pinch_details)); | |
428 } | |
429 break; | |
430 case MotionEvent::ACTION_UP: | 405 case MotionEvent::ACTION_UP: |
431 if (double_tap_mode_ != DOUBLE_TAP_MODE_DRAG_ZOOM) { | 406 if (!provider_->IsPinchInProgress() && |
432 // Normal double-tap gesture. | 407 !provider_->IsScrollInProgress()) { |
433 provider_->Send( | 408 provider_->Send( |
434 CreateGesture(ET_GESTURE_DOUBLE_TAP, | 409 CreateGesture(ET_GESTURE_DOUBLE_TAP, |
435 e, | 410 e, |
436 CreateTapGestureDetails(ET_GESTURE_DOUBLE_TAP, e))); | 411 CreateTapGestureDetails(ET_GESTURE_DOUBLE_TAP, e))); |
| 412 return true; |
437 } | 413 } |
438 EndDoubleTapDragIfNecessary(e); | |
439 break; | |
440 case MotionEvent::ACTION_CANCEL: | |
441 EndDoubleTapDragIfNecessary(e); | |
442 break; | 414 break; |
443 default: | 415 default: |
444 NOTREACHED() << "Invalid double-tap event."; | |
445 break; | 416 break; |
446 } | 417 } |
447 double_tap_y_ = e.GetY(); | 418 return false; |
448 return true; | |
449 } | 419 } |
450 | 420 |
451 virtual bool OnLongPress(const MotionEvent& e) OVERRIDE { | 421 virtual bool OnLongPress(const MotionEvent& e) OVERRIDE { |
452 DCHECK(!IsDoubleTapInProgress()); | 422 DCHECK(!IsDoubleTapInProgress()); |
453 SetIgnoreSingleTap(true); | 423 SetIgnoreSingleTap(true); |
454 | 424 |
455 GestureEventDetails long_press_details(ET_GESTURE_LONG_PRESS, 0, 0); | 425 GestureEventDetails long_press_details(ET_GESTURE_LONG_PRESS, 0, 0); |
456 long_press_details.set_bounding_box( | 426 long_press_details.set_bounding_box( |
457 gfx::RectF(e.GetTouchMajor(), e.GetTouchMajor())); | 427 gfx::RectF(e.GetTouchMajor(), e.GetTouchMajor())); |
458 provider_->Send( | 428 provider_->Send( |
459 CreateGesture(ET_GESTURE_LONG_PRESS, e, long_press_details)); | 429 CreateGesture(ET_GESTURE_LONG_PRESS, e, long_press_details)); |
460 | 430 |
461 // Returning true puts the GestureDetector in "longpress" mode, disabling | 431 // Returning true puts the GestureDetector in "longpress" mode, disabling |
462 // further scrolling. This is undesirable, as it is quite common for a | 432 // further scrolling. This is undesirable, as it is quite common for a |
463 // longpress gesture to fire on content that won't trigger a context menu. | 433 // longpress gesture to fire on content that won't trigger a context menu. |
464 return false; | 434 return false; |
465 } | 435 } |
466 | 436 |
467 void SetDoubleTapSupportForPlatformEnabled(bool enabled) { | 437 void SetDoubleTapEnabled(bool enabled) { |
468 DCHECK(!IsDoubleTapInProgress()); | 438 DCHECK(!IsDoubleTapInProgress()); |
469 DoubleTapMode double_tap_mode = | 439 if (enabled) { |
470 enabled ? DOUBLE_TAP_MODE_NONE : DOUBLE_TAP_MODE_DISABLED; | 440 gesture_detector_.set_doubletap_listener(this); |
471 if (double_tap_mode_ == double_tap_mode) | 441 } else { |
472 return; | 442 // TODO(jdduke): Send GESTURE_TAP if GESTURE_TAP_UNCONFIRMED already sent. |
473 double_tap_mode_ = double_tap_mode; | 443 gesture_detector_.set_doubletap_listener(NULL); |
474 UpdateDoubleTapListener(); | 444 } |
475 } | |
476 | |
477 void SetDoubleTapSupportForPageEnabled(bool enabled) { | |
478 if (double_tap_support_enabled_ == enabled) | |
479 return; | |
480 double_tap_support_enabled_ = enabled; | |
481 UpdateDoubleTapListener(); | |
482 } | |
483 | |
484 bool IsDoubleTapDisabled() const { | |
485 return double_tap_mode_ == DOUBLE_TAP_MODE_DISABLED || | |
486 !double_tap_support_enabled_; | |
487 } | 445 } |
488 | 446 |
489 bool IsClickDelayDisabled() const { return disable_click_delay_; } | 447 bool IsClickDelayDisabled() const { return disable_click_delay_; } |
490 | 448 |
491 bool IsDoubleTapInProgress() const { | 449 bool IsDoubleTapInProgress() const { |
492 return double_tap_mode_ != DOUBLE_TAP_MODE_DISABLED && | 450 return gesture_detector_.is_double_tapping(); |
493 double_tap_mode_ != DOUBLE_TAP_MODE_NONE; | |
494 } | 451 } |
495 | 452 |
496 private: | 453 private: |
497 enum DoubleTapMode { | |
498 DOUBLE_TAP_MODE_NONE, | |
499 DOUBLE_TAP_MODE_DRAG_DETECTION_IN_PROGRESS, | |
500 DOUBLE_TAP_MODE_DRAG_ZOOM, | |
501 DOUBLE_TAP_MODE_DISABLED | |
502 }; | |
503 | |
504 bool IsPointOutsideCurrentSlopRegion(float x, float y) const { | 454 bool IsPointOutsideCurrentSlopRegion(float x, float y) const { |
505 return IsDistanceGreaterThanTouchSlop(last_raw_x_ - x, last_raw_y_ - y); | 455 return IsDistanceGreaterThanTouchSlop(last_raw_x_ - x, last_raw_y_ - y); |
506 } | 456 } |
507 | 457 |
508 bool IsDistanceGreaterThanTouchSlop(float distance_x, | 458 bool IsDistanceGreaterThanTouchSlop(float distance_x, |
509 float distance_y) const { | 459 float distance_y) const { |
510 return distance_x * distance_x + distance_y * distance_y > | 460 return distance_x * distance_x + distance_y * distance_y > |
511 scaled_touch_slop_square_; | 461 scaled_touch_slop_square_; |
512 } | 462 } |
513 | 463 |
514 void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; } | 464 void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; } |
515 | 465 |
516 void EndDoubleTapDragIfNecessary(const MotionEvent& event) { | 466 bool IsDoubleTapEnabled() const { |
517 if (!IsDoubleTapInProgress()) | 467 return gesture_detector_.has_doubletap_listener(); |
518 return; | |
519 if (double_tap_mode_ == DOUBLE_TAP_MODE_DRAG_ZOOM) { | |
520 provider_->Send(CreateGesture(ET_GESTURE_PINCH_END, event)); | |
521 provider_->Send(CreateGesture(ET_GESTURE_SCROLL_END, event)); | |
522 } | |
523 double_tap_mode_ = DOUBLE_TAP_MODE_NONE; | |
524 UpdateDoubleTapListener(); | |
525 } | |
526 | |
527 void UpdateDoubleTapListener() { | |
528 if (IsDoubleTapDisabled()) { | |
529 // Defer nulling the DoubleTapListener until the double-tap gesture is | |
530 // complete. | |
531 if (IsDoubleTapInProgress()) | |
532 return; | |
533 gesture_detector_.set_doubletap_listener(NULL); | |
534 } else { | |
535 gesture_detector_.set_doubletap_listener(this); | |
536 } | |
537 } | 468 } |
538 | 469 |
539 GestureDetector gesture_detector_; | 470 GestureDetector gesture_detector_; |
540 SnapScrollController snap_scroll_controller_; | 471 SnapScrollController snap_scroll_controller_; |
541 | 472 |
542 GestureProvider* const provider_; | 473 GestureProvider* const provider_; |
543 | 474 |
544 const float px_to_dp_; | |
545 | |
546 // Whether the click delay should always be disabled by sending clicks for | 475 // Whether the click delay should always be disabled by sending clicks for |
547 // double-tap gestures. | 476 // double-tap gestures. |
548 const bool disable_click_delay_; | 477 const bool disable_click_delay_; |
549 | 478 |
550 const int scaled_touch_slop_; | 479 const int scaled_touch_slop_; |
551 | 480 |
552 // Cache of square of the scaled touch slop so we don't have to calculate it | 481 // Cache of square of the scaled touch slop so we don't have to calculate it |
553 // on every touch. | 482 // on every touch. |
554 const int scaled_touch_slop_square_; | 483 const int scaled_touch_slop_square_; |
555 | 484 |
556 const base::TimeDelta double_tap_timeout_; | 485 const base::TimeDelta double_tap_timeout_; |
557 | 486 |
558 base::TimeTicks current_down_time_; | 487 base::TimeTicks current_down_time_; |
559 | 488 |
560 // TODO(klobag): This is to avoid a bug in GestureDetector. With multi-touch, | 489 // TODO(klobag): This is to avoid a bug in GestureDetector. With multi-touch, |
561 // always_in_tap_region_ is not reset. So when the last finger is up, | 490 // always_in_tap_region_ is not reset. So when the last finger is up, |
562 // OnSingleTapUp() will be mistakenly fired. | 491 // OnSingleTapUp() will be mistakenly fired. |
563 bool ignore_single_tap_; | 492 bool ignore_single_tap_; |
564 | 493 |
565 // Used to remove the touch slop from the initial scroll event in a scroll | 494 // Used to remove the touch slop from the initial scroll event in a scroll |
566 // gesture. | 495 // gesture. |
567 bool seen_first_scroll_event_; | 496 bool seen_first_scroll_event_; |
568 | 497 |
569 // Indicate current double-tap mode state. | |
570 int double_tap_mode_; | |
571 | |
572 // On double-tap this will store the y coordinates of the touch. | |
573 float double_tap_y_; | |
574 | |
575 // The page's viewport and scale sometimes allow us to disable double-tap | |
576 // gesture detection, | |
577 // according to the logic in ContentViewCore.onRenderCoordinatesUpdated(). | |
578 bool double_tap_support_enabled_; | |
579 | |
580 // x, y coordinates for an Anchor on double-tap drag zoom. | |
581 float double_tap_drag_zoom_anchor_x_; | |
582 float double_tap_drag_zoom_anchor_y_; | |
583 | |
584 // Used to track the last rawX/Y coordinates for moves. This gives absolute | 498 // Used to track the last rawX/Y coordinates for moves. This gives absolute |
585 // scroll distance. | 499 // scroll distance. |
586 // Useful for full screen tracking. | 500 // Useful for full screen tracking. |
587 float last_raw_x_; | 501 float last_raw_x_; |
588 float last_raw_y_; | 502 float last_raw_y_; |
589 | 503 |
590 // Used to track the accumulated scroll error over time. This is used to | 504 // Used to track the accumulated scroll error over time. This is used to |
591 // remove the | 505 // remove the |
592 // rounding error we introduced by passing integers to webkit. | 506 // rounding error we introduced by passing integers to webkit. |
593 float accumulated_scroll_error_x_; | 507 float accumulated_scroll_error_x_; |
594 float accumulated_scroll_error_y_; | 508 float accumulated_scroll_error_y_; |
595 | 509 |
596 DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl); | 510 DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl); |
597 }; | 511 }; |
598 | 512 |
599 // GestureProvider | 513 // GestureProvider |
600 | 514 |
601 GestureProvider::GestureProvider(const Config& config, | 515 GestureProvider::GestureProvider(const Config& config, |
602 GestureProviderClient* client) | 516 GestureProviderClient* client) |
603 : client_(client), | 517 : client_(client), |
604 needs_show_press_event_(false), | 518 needs_show_press_event_(false), |
605 needs_tap_ending_event_(false), | 519 needs_tap_ending_event_(false), |
606 touch_scroll_in_progress_(false), | 520 touch_scroll_in_progress_(false), |
607 pinch_in_progress_(false) { | 521 pinch_in_progress_(false), |
| 522 double_tap_support_for_page_(true), |
| 523 double_tap_support_for_platform_(true) { |
608 DCHECK(client); | 524 DCHECK(client); |
609 InitGestureDetectors(config); | 525 InitGestureDetectors(config); |
610 } | 526 } |
611 | 527 |
612 GestureProvider::~GestureProvider() {} | 528 GestureProvider::~GestureProvider() {} |
613 | 529 |
614 bool GestureProvider::OnTouchEvent(const MotionEvent& event) { | 530 bool GestureProvider::OnTouchEvent(const MotionEvent& event) { |
615 TRACE_EVENT1("input", "GestureProvider::OnTouchEvent", | 531 TRACE_EVENT1("input", "GestureProvider::OnTouchEvent", |
616 "action", GetMotionEventActionName(event.GetAction())); | 532 "action", GetMotionEventActionName(event.GetAction())); |
617 if (!CanHandle(event)) | 533 if (!CanHandle(event)) |
618 return false; | 534 return false; |
619 | 535 |
620 const bool was_touch_scrolling_ = touch_scroll_in_progress_; | |
621 const bool in_scale_gesture = | 536 const bool in_scale_gesture = |
622 scale_gesture_listener_->IsScaleGestureDetectionInProgress(); | 537 scale_gesture_listener_->IsScaleGestureDetectionInProgress(); |
623 | 538 |
624 if (event.GetAction() == MotionEvent::ACTION_DOWN) { | 539 if (event.GetAction() == MotionEvent::ACTION_DOWN) { |
625 current_down_event_ = event.Clone(); | 540 current_down_event_ = event.Clone(); |
626 touch_scroll_in_progress_ = false; | 541 touch_scroll_in_progress_ = false; |
627 needs_show_press_event_ = true; | 542 needs_show_press_event_ = true; |
628 current_longpress_time_ = base::TimeTicks(); | 543 current_longpress_time_ = base::TimeTicks(); |
629 SendTapCancelIfNecessary(event); | 544 SendTapCancelIfNecessary(event); |
630 } | 545 } |
631 | 546 |
632 bool handled = gesture_listener_->OnTouchEvent(event, in_scale_gesture); | 547 bool handled = gesture_listener_->OnTouchEvent(event, in_scale_gesture); |
633 handled |= scale_gesture_listener_->OnTouchEvent(event); | 548 handled |= scale_gesture_listener_->OnTouchEvent(event); |
634 | 549 |
635 if (event.GetAction() == MotionEvent::ACTION_UP || | 550 if (event.GetAction() == MotionEvent::ACTION_UP || |
636 event.GetAction() == MotionEvent::ACTION_CANCEL) { | 551 event.GetAction() == MotionEvent::ACTION_CANCEL) { |
637 // "Last finger raised" could be an end to movement, but it should | 552 // Note: This call will have no effect if a fling was just generated, as |
638 // only terminate scrolling if the event did not cause a fling. | 553 // |Fling()| will have already signalled an end to touch-scrolling. |
639 if (was_touch_scrolling_ && !handled) | 554 EndTouchScrollIfNecessary(event.GetEventTime(), true); |
640 EndTouchScrollIfNecessary(event.GetEventTime(), true); | |
641 | 555 |
642 // We shouldn't necessarily cancel a tap on ACTION_UP, as the double-tap | 556 // We shouldn't necessarily cancel a tap on ACTION_UP, as the double-tap |
643 // timeout may yet trigger a SINGLE_TAP. | 557 // timeout may yet trigger a SINGLE_TAP. |
644 if (event.GetAction() == MotionEvent::ACTION_CANCEL) | 558 if (event.GetAction() == MotionEvent::ACTION_CANCEL) |
645 SendTapCancelIfNecessary(event); | 559 SendTapCancelIfNecessary(event); |
646 | 560 |
| 561 UpdateDoubleTapDetectionSupport(); |
| 562 |
647 current_down_event_.reset(); | 563 current_down_event_.reset(); |
648 } | 564 } |
649 | 565 |
650 return true; | 566 return true; |
651 } | 567 } |
652 | 568 |
653 void GestureProvider::ResetGestureDetectors() { | 569 void GestureProvider::ResetGestureDetectors() { |
654 if (!current_down_event_) | 570 if (!current_down_event_) |
655 return; | 571 return; |
656 scoped_ptr<MotionEvent> cancel_event = current_down_event_->Cancel(); | 572 scoped_ptr<MotionEvent> cancel_event = current_down_event_->Cancel(); |
657 gesture_listener_->OnTouchEvent(*cancel_event, false); | 573 gesture_listener_->OnTouchEvent(*cancel_event, false); |
658 scale_gesture_listener_->OnTouchEvent(*cancel_event); | 574 scale_gesture_listener_->OnTouchEvent(*cancel_event); |
659 } | 575 } |
660 | 576 |
661 void GestureProvider::SetMultiTouchSupportEnabled(bool enabled) { | 577 void GestureProvider::SetMultiTouchSupportEnabled(bool enabled) { |
662 scale_gesture_listener_->set_ignore_detector_events(!enabled); | 578 scale_gesture_listener_->SetMultiTouchEnabled(!enabled); |
663 } | 579 } |
664 | 580 |
665 void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) { | 581 void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) { |
666 gesture_listener_->SetDoubleTapSupportForPlatformEnabled(enabled); | 582 double_tap_support_for_platform_ = enabled; |
| 583 UpdateDoubleTapDetectionSupport(); |
667 } | 584 } |
668 | 585 |
669 void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) { | 586 void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) { |
670 gesture_listener_->SetDoubleTapSupportForPageEnabled(enabled); | 587 double_tap_support_for_page_ = enabled; |
| 588 UpdateDoubleTapDetectionSupport(); |
671 } | 589 } |
672 | 590 |
673 bool GestureProvider::IsScrollInProgress() const { | 591 bool GestureProvider::IsScrollInProgress() const { |
674 // TODO(wangxianzhu): Also return true when fling is active once the UI knows | 592 // TODO(wangxianzhu): Also return true when fling is active once the UI knows |
675 // exactly when the fling ends. | 593 // exactly when the fling ends. |
676 return touch_scroll_in_progress_; | 594 return touch_scroll_in_progress_; |
677 } | 595 } |
678 | 596 |
679 bool GestureProvider::IsPinchInProgress() const { return pinch_in_progress_; } | 597 bool GestureProvider::IsPinchInProgress() const { return pinch_in_progress_; } |
680 | 598 |
681 bool GestureProvider::IsDoubleTapInProgress() const { | 599 bool GestureProvider::IsDoubleTapInProgress() const { |
682 return gesture_listener_->IsDoubleTapInProgress(); | 600 return gesture_listener_->IsDoubleTapInProgress() || |
| 601 scale_gesture_listener_->IsDoubleTapInProgress(); |
| 602 } |
| 603 |
| 604 bool GestureProvider::IsDoubleTapSupported() const { |
| 605 return double_tap_support_for_page_ && double_tap_support_for_platform_; |
683 } | 606 } |
684 | 607 |
685 bool GestureProvider::IsClickDelayDisabled() const { | 608 bool GestureProvider::IsClickDelayDisabled() const { |
686 return gesture_listener_->IsClickDelayDisabled(); | 609 return gesture_listener_->IsClickDelayDisabled(); |
687 } | 610 } |
688 | 611 |
689 void GestureProvider::InitGestureDetectors(const Config& config) { | 612 void GestureProvider::InitGestureDetectors(const Config& config) { |
690 TRACE_EVENT0("input", "GestureProvider::InitGestureDetectors"); | 613 TRACE_EVENT0("input", "GestureProvider::InitGestureDetectors"); |
691 gesture_listener_.reset( | 614 gesture_listener_.reset( |
692 new GestureListenerImpl(config.gesture_detector_config, | 615 new GestureListenerImpl(config.gesture_detector_config, |
693 config.snap_scroll_controller_config, | 616 config.snap_scroll_controller_config, |
694 config.disable_click_delay, | 617 config.disable_click_delay, |
695 this)); | 618 this)); |
696 | 619 |
697 scale_gesture_listener_.reset( | 620 scale_gesture_listener_.reset(new ScaleGestureListenerImpl( |
698 new ScaleGestureListenerImpl(config.scale_gesture_detector_config, this)); | 621 config.scale_gesture_detector_config, |
| 622 config.snap_scroll_controller_config.device_scale_factor, |
| 623 this)); |
| 624 |
| 625 UpdateDoubleTapDetectionSupport(); |
699 } | 626 } |
700 | 627 |
701 bool GestureProvider::CanHandle(const MotionEvent& event) const { | 628 bool GestureProvider::CanHandle(const MotionEvent& event) const { |
702 return event.GetAction() == MotionEvent::ACTION_DOWN || current_down_event_; | 629 return event.GetAction() == MotionEvent::ACTION_DOWN || current_down_event_; |
703 } | 630 } |
704 | 631 |
705 void GestureProvider::Fling(base::TimeTicks time, | 632 void GestureProvider::Fling(base::TimeTicks time, |
706 float x, | 633 float x, |
707 float y, | 634 float y, |
708 float velocity_x, | 635 float velocity_x, |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
769 current_longpress_time_ = base::TimeTicks(); | 696 current_longpress_time_ = base::TimeTicks(); |
770 break; | 697 break; |
771 case ET_GESTURE_SCROLL_BEGIN: | 698 case ET_GESTURE_SCROLL_BEGIN: |
772 touch_scroll_in_progress_ = true; | 699 touch_scroll_in_progress_ = true; |
773 SendTapCancelIfNecessary(*current_down_event_); | 700 SendTapCancelIfNecessary(*current_down_event_); |
774 break; | 701 break; |
775 case ET_GESTURE_SCROLL_END: | 702 case ET_GESTURE_SCROLL_END: |
776 touch_scroll_in_progress_ = false; | 703 touch_scroll_in_progress_ = false; |
777 break; | 704 break; |
778 case ET_GESTURE_PINCH_BEGIN: | 705 case ET_GESTURE_PINCH_BEGIN: |
| 706 if (!touch_scroll_in_progress_) |
| 707 Send(CreateGesture( |
| 708 ET_GESTURE_SCROLL_BEGIN, gesture.time, gesture.x, gesture.y)); |
779 pinch_in_progress_ = true; | 709 pinch_in_progress_ = true; |
780 break; | 710 break; |
781 case ET_GESTURE_PINCH_END: | 711 case ET_GESTURE_PINCH_END: |
782 pinch_in_progress_ = false; | 712 pinch_in_progress_ = false; |
783 break; | 713 break; |
784 default: | 714 default: |
785 break; | 715 break; |
786 }; | 716 }; |
787 | 717 |
788 client_->OnGestureEvent(gesture); | 718 client_->OnGestureEvent(gesture); |
(...skipping 22 matching lines...) Expand all Loading... |
811 | 741 |
812 void GestureProvider::EndTouchScrollIfNecessary(base::TimeTicks time, | 742 void GestureProvider::EndTouchScrollIfNecessary(base::TimeTicks time, |
813 bool send_scroll_end_event) { | 743 bool send_scroll_end_event) { |
814 if (!touch_scroll_in_progress_) | 744 if (!touch_scroll_in_progress_) |
815 return; | 745 return; |
816 touch_scroll_in_progress_ = false; | 746 touch_scroll_in_progress_ = false; |
817 if (send_scroll_end_event) | 747 if (send_scroll_end_event) |
818 Send(CreateGesture(ET_GESTURE_SCROLL_END, time, 0, 0)); | 748 Send(CreateGesture(ET_GESTURE_SCROLL_END, time, 0, 0)); |
819 } | 749 } |
820 | 750 |
| 751 void GestureProvider::UpdateDoubleTapDetectionSupport() { |
| 752 if (IsDoubleTapInProgress()) |
| 753 return; |
| 754 |
| 755 const bool supports_double_tap = IsDoubleTapSupported(); |
| 756 gesture_listener_->SetDoubleTapEnabled(supports_double_tap); |
| 757 scale_gesture_listener_->SetDoubleTapEnabled(supports_double_tap); |
| 758 } |
| 759 |
821 } // namespace ui | 760 } // namespace ui |
OLD | NEW |