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" |
11 #include "ui/events/event_constants.h" | 11 #include "ui/events/event_constants.h" |
12 #include "ui/events/gesture_detection/gesture_event_data.h" | 12 #include "ui/events/gesture_detection/gesture_event_data.h" |
13 #include "ui/events/gesture_detection/motion_event.h" | 13 #include "ui/events/gesture_detection/motion_event.h" |
14 | 14 |
15 namespace ui { | 15 namespace ui { |
16 namespace { | 16 namespace { |
17 | 17 |
18 // Double-tap drag zoom sensitivity (speed). | 18 // Double-tap drag zoom sensitivity (speed). |
19 const float kDoubleTapDragZoomSpeed = 0.005f; | 19 const float kDoubleTapDragZoomSpeed = 0.005f; |
20 | 20 |
21 const char* GetMotionEventActionName(MotionEvent::Action action) { | 21 const char* GetMotionEventActionName(MotionEvent::Action action) { |
22 switch(action) { | 22 switch (action) { |
23 case MotionEvent::ACTION_POINTER_DOWN: return "ACTION_POINTER_DOWN"; | 23 case MotionEvent::ACTION_POINTER_DOWN: |
24 case MotionEvent::ACTION_POINTER_UP: return "ACTION_POINTER_UP"; | 24 return "ACTION_POINTER_DOWN"; |
25 case MotionEvent::ACTION_DOWN: return "ACTION_DOWN"; | 25 case MotionEvent::ACTION_POINTER_UP: |
26 case MotionEvent::ACTION_UP: return "ACTION_UP"; | 26 return "ACTION_POINTER_UP"; |
27 case MotionEvent::ACTION_CANCEL: return "ACTION_CANCEL"; | 27 case MotionEvent::ACTION_DOWN: |
28 case MotionEvent::ACTION_MOVE: return "ACTION_MOVE"; | 28 return "ACTION_DOWN"; |
| 29 case MotionEvent::ACTION_UP: |
| 30 return "ACTION_UP"; |
| 31 case MotionEvent::ACTION_CANCEL: |
| 32 return "ACTION_CANCEL"; |
| 33 case MotionEvent::ACTION_MOVE: |
| 34 return "ACTION_MOVE"; |
29 } | 35 } |
30 return ""; | 36 return ""; |
31 } | 37 } |
32 | 38 |
33 gfx::RectF GetBoundingBox(const MotionEvent& event) { | 39 gfx::RectF GetBoundingBox(const MotionEvent& event) { |
34 // Can't use gfx::RectF::Union, as it ignores touches with a radius of 0. | 40 // Can't use gfx::RectF::Union, as it ignores touches with a radius of 0. |
35 float left = std::numeric_limits<float>::max(); | 41 float left = std::numeric_limits<float>::max(); |
36 float top = std::numeric_limits<float>::max(); | 42 float top = std::numeric_limits<float>::max(); |
37 float right = -std::numeric_limits<float>::max(); | 43 float right = -std::numeric_limits<float>::max(); |
38 float bottom = -std::numeric_limits<float>::max(); | 44 float bottom = -std::numeric_limits<float>::max(); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 event.GetRawX(), | 109 event.GetRawX(), |
104 event.GetRawY(), | 110 event.GetRawY(), |
105 event.GetPointerCount(), | 111 event.GetPointerCount(), |
106 GetBoundingBox(event)); | 112 GetBoundingBox(event)); |
107 } | 113 } |
108 | 114 |
109 GestureEventData CreateGesture(EventType type, const MotionEvent& event) { | 115 GestureEventData CreateGesture(EventType type, const MotionEvent& event) { |
110 return CreateGesture(GestureEventDetails(type, 0, 0), event); | 116 return CreateGesture(GestureEventDetails(type, 0, 0), event); |
111 } | 117 } |
112 | 118 |
113 GestureEventDetails CreateTapGestureDetails(EventType type) { | 119 GestureEventData CreateTapGesture(EventType type, const MotionEvent& event) { |
114 // Set the tap count to 1 even for ET_GESTURE_DOUBLE_TAP, in order to be | 120 // Set the tap count to 1 even for ET_GESTURE_DOUBLE_TAP, in order to be |
115 // consistent with double tap behavior on a mobile viewport. See | 121 // consistent with double tap behavior on a mobile viewport. See |
116 // crbug.com/234986 for context. | 122 // crbug.com/234986 for context. |
117 GestureEventDetails tap_details(type, 1, 0); | 123 return CreateGesture(GestureEventDetails(type, 1, 0), event); |
118 return tap_details; | |
119 } | 124 } |
120 | 125 |
121 gfx::RectF ClampBoundingBox(const gfx::RectF& bounds, | 126 gfx::RectF ClampBoundingBox(const gfx::RectF& bounds, |
122 float min_length, | 127 float min_length, |
123 float max_length) { | 128 float max_length) { |
124 float width = bounds.width(); | 129 float width = bounds.width(); |
125 float height = bounds.height(); | 130 float height = bounds.height(); |
126 if (min_length) { | 131 if (min_length) { |
127 width = std::max(min_length, width); | 132 width = std::max(min_length, width); |
128 height = std::max(min_length, height); | 133 height = std::max(min_length, height); |
129 } | 134 } |
130 if (max_length) { | 135 if (max_length) { |
131 width = std::min(max_length, width); | 136 width = std::min(max_length, width); |
132 height = std::min(max_length, height); | 137 height = std::min(max_length, height); |
133 } | 138 } |
134 const gfx::PointF center = bounds.CenterPoint(); | 139 const gfx::PointF center = bounds.CenterPoint(); |
135 return gfx::RectF( | 140 return gfx::RectF( |
136 center.x() - width / 2.f, center.y() - height / 2.f, width, height); | 141 center.x() - width / 2.f, center.y() - height / 2.f, width, height); |
137 } | 142 } |
138 | 143 |
139 } // namespace | 144 } // namespace |
140 | 145 |
141 // GestureProvider:::Config | 146 // GestureProvider:::Config |
142 | 147 |
143 GestureProvider::Config::Config() | 148 GestureProvider::Config::Config() |
144 : display(gfx::Display::kInvalidDisplayID, gfx::Rect(1, 1)), | 149 : display(gfx::Display::kInvalidDisplayID, gfx::Rect(1, 1)), |
145 disable_click_delay(false), | 150 disable_click_delay(false), |
146 gesture_begin_end_types_enabled(false), | 151 gesture_begin_end_types_enabled(false), |
147 min_gesture_bounds_length(0), | 152 min_gesture_bounds_length(0), |
148 max_gesture_bounds_length(0) {} | 153 max_gesture_bounds_length(0) { |
| 154 } |
149 | 155 |
150 GestureProvider::Config::~Config() {} | 156 GestureProvider::Config::~Config() { |
| 157 } |
151 | 158 |
152 // GestureProvider::ScaleGestureListener | 159 // GestureProvider::GestureListener |
153 | 160 |
154 class GestureProvider::ScaleGestureListenerImpl | 161 class GestureProvider::GestureListenerImpl |
155 : public ScaleGestureDetector::ScaleGestureListener { | 162 : public ScaleGestureDetector::ScaleGestureListener, |
| 163 public GestureDetector::GestureListener, |
| 164 public GestureDetector::DoubleTapListener { |
156 public: | 165 public: |
157 ScaleGestureListenerImpl(const ScaleGestureDetector::Config& config, | 166 GestureListenerImpl(const GestureProvider::Config& config, |
158 GestureProvider* provider) | 167 GestureProviderClient* client) |
159 : scale_gesture_detector_(config, this), | 168 : config_(config), |
160 provider_(provider), | 169 client_(client), |
161 ignore_multitouch_events_(false), | 170 gesture_detector_(config.gesture_detector_config, this, this), |
| 171 scale_gesture_detector_(config.scale_gesture_detector_config, this), |
| 172 snap_scroll_controller_(config.display), |
| 173 ignore_multitouch_zoom_events_(false), |
| 174 ignore_single_tap_(false), |
162 pinch_event_sent_(false), | 175 pinch_event_sent_(false), |
163 min_pinch_update_span_delta_(config.min_pinch_update_span_delta) {} | 176 scroll_event_sent_(false) {} |
164 | 177 |
165 bool OnTouchEvent(const MotionEvent& event) { | 178 void OnTouchEvent(const MotionEvent& event) { |
166 // TODO: Need to deal with multi-touch transition. | |
167 const bool in_scale_gesture = IsScaleGestureDetectionInProgress(); | 179 const bool in_scale_gesture = IsScaleGestureDetectionInProgress(); |
168 bool handled = scale_gesture_detector_.OnTouchEvent(event); | 180 snap_scroll_controller_.SetSnapScrollingMode(event, in_scale_gesture); |
169 if (!in_scale_gesture && | 181 if (in_scale_gesture) |
170 (event.GetAction() == MotionEvent::ACTION_UP || | 182 SetIgnoreSingleTap(true); |
171 event.GetAction() == MotionEvent::ACTION_CANCEL)) { | 183 |
172 return false; | 184 const MotionEvent::Action action = event.GetAction(); |
| 185 if (action == MotionEvent::ACTION_DOWN) { |
| 186 current_down_time_ = event.GetEventTime(); |
| 187 current_longpress_time_ = base::TimeTicks(); |
| 188 ignore_single_tap_ = false; |
| 189 scroll_event_sent_ = false; |
| 190 pinch_event_sent_ = false; |
| 191 gesture_detector_.set_longpress_enabled(true); |
173 } | 192 } |
174 return handled; | 193 |
| 194 gesture_detector_.OnTouchEvent(event); |
| 195 scale_gesture_detector_.OnTouchEvent(event); |
| 196 |
| 197 if (action == MotionEvent::ACTION_UP || |
| 198 action == MotionEvent::ACTION_CANCEL) { |
| 199 // Note: This call will have no effect if a fling was just generated, as |
| 200 // |Fling()| will have already signalled an end to touch-scrolling. |
| 201 if (scroll_event_sent_) |
| 202 Send(CreateGesture(ET_GESTURE_SCROLL_END, event)); |
| 203 current_down_time_ = base::TimeTicks(); |
| 204 } |
| 205 } |
| 206 |
| 207 void Send(GestureEventData gesture) { |
| 208 DCHECK(!gesture.time.is_null()); |
| 209 // The only valid events that should be sent without an active touch |
| 210 // sequence are SHOW_PRESS and TAP, potentially triggered by the double-tap |
| 211 // delay timing out. |
| 212 DCHECK(!current_down_time_.is_null() || gesture.type() == ET_GESTURE_TAP || |
| 213 gesture.type() == ET_GESTURE_SHOW_PRESS || |
| 214 gesture.type() == ET_GESTURE_BEGIN || |
| 215 gesture.type() == ET_GESTURE_END); |
| 216 |
| 217 if (gesture.primary_tool_type == MotionEvent::TOOL_TYPE_UNKNOWN || |
| 218 gesture.primary_tool_type == MotionEvent::TOOL_TYPE_FINGER) { |
| 219 gesture.details.set_bounding_box( |
| 220 ClampBoundingBox(gesture.details.bounding_box_f(), |
| 221 config_.min_gesture_bounds_length, |
| 222 config_.max_gesture_bounds_length)); |
| 223 } |
| 224 |
| 225 switch (gesture.type()) { |
| 226 case ET_GESTURE_LONG_PRESS: |
| 227 DCHECK(!IsScaleGestureDetectionInProgress()); |
| 228 current_longpress_time_ = gesture.time; |
| 229 break; |
| 230 case ET_GESTURE_LONG_TAP: |
| 231 current_longpress_time_ = base::TimeTicks(); |
| 232 break; |
| 233 case ET_GESTURE_SCROLL_BEGIN: |
| 234 DCHECK(!scroll_event_sent_); |
| 235 scroll_event_sent_ = true; |
| 236 break; |
| 237 case ET_GESTURE_SCROLL_END: |
| 238 DCHECK(scroll_event_sent_); |
| 239 if (pinch_event_sent_) |
| 240 Send(GestureEventData(ET_GESTURE_PINCH_END, gesture)); |
| 241 scroll_event_sent_ = false; |
| 242 break; |
| 243 case ET_SCROLL_FLING_START: |
| 244 DCHECK(scroll_event_sent_); |
| 245 scroll_event_sent_ = false; |
| 246 break; |
| 247 case ET_GESTURE_PINCH_BEGIN: |
| 248 DCHECK(!pinch_event_sent_); |
| 249 if (!scroll_event_sent_) |
| 250 Send(GestureEventData(ET_GESTURE_SCROLL_BEGIN, gesture)); |
| 251 pinch_event_sent_ = true; |
| 252 break; |
| 253 case ET_GESTURE_PINCH_END: |
| 254 DCHECK(pinch_event_sent_); |
| 255 pinch_event_sent_ = false; |
| 256 break; |
| 257 case ET_GESTURE_SHOW_PRESS: |
| 258 // It's possible that a double-tap drag zoom (from ScaleGestureDetector) |
| 259 // will start before the press gesture fires (from GestureDetector), in |
| 260 // which case the press should simply be dropped. |
| 261 if (pinch_event_sent_ || scroll_event_sent_) |
| 262 return; |
| 263 default: |
| 264 break; |
| 265 }; |
| 266 |
| 267 client_->OnGestureEvent(gesture); |
175 } | 268 } |
176 | 269 |
177 // ScaleGestureDetector::ScaleGestureListener implementation. | 270 // ScaleGestureDetector::ScaleGestureListener implementation. |
178 virtual bool OnScaleBegin(const ScaleGestureDetector& detector, | 271 virtual bool OnScaleBegin(const ScaleGestureDetector& detector, |
179 const MotionEvent& e) OVERRIDE { | 272 const MotionEvent& e) OVERRIDE { |
180 if (ignore_multitouch_events_ && !detector.InDoubleTapMode()) | 273 if (ignore_multitouch_zoom_events_ && !detector.InDoubleTapMode()) |
181 return false; | 274 return false; |
182 pinch_event_sent_ = false; | |
183 return true; | 275 return true; |
184 } | 276 } |
185 | 277 |
186 virtual void OnScaleEnd(const ScaleGestureDetector& detector, | 278 virtual void OnScaleEnd(const ScaleGestureDetector& detector, |
187 const MotionEvent& e) OVERRIDE { | 279 const MotionEvent& e) OVERRIDE { |
188 if (!pinch_event_sent_) | 280 if (!pinch_event_sent_) |
189 return; | 281 return; |
190 provider_->Send(CreateGesture(ET_GESTURE_PINCH_END, e)); | 282 Send(CreateGesture(ET_GESTURE_PINCH_END, e)); |
191 pinch_event_sent_ = false; | |
192 } | 283 } |
193 | 284 |
194 virtual bool OnScale(const ScaleGestureDetector& detector, | 285 virtual bool OnScale(const ScaleGestureDetector& detector, |
195 const MotionEvent& e) OVERRIDE { | 286 const MotionEvent& e) OVERRIDE { |
196 if (ignore_multitouch_events_ && !detector.InDoubleTapMode()) | 287 if (ignore_multitouch_zoom_events_ && !detector.InDoubleTapMode()) |
197 return false; | 288 return false; |
198 if (!pinch_event_sent_) { | 289 if (!pinch_event_sent_) { |
199 pinch_event_sent_ = true; | 290 Send(CreateGesture(ET_GESTURE_PINCH_BEGIN, |
200 provider_->Send(CreateGesture(ET_GESTURE_PINCH_BEGIN, | 291 e.GetId(), |
201 e.GetId(), | 292 e.GetToolType(), |
202 e.GetToolType(), | 293 detector.GetEventTime(), |
203 detector.GetEventTime(), | 294 detector.GetFocusX(), |
204 detector.GetFocusX(), | 295 detector.GetFocusY(), |
205 detector.GetFocusY(), | 296 detector.GetFocusX() + e.GetRawOffsetX(), |
206 detector.GetFocusX() + e.GetRawOffsetX(), | 297 detector.GetFocusY() + e.GetRawOffsetY(), |
207 detector.GetFocusY() + e.GetRawOffsetY(), | 298 e.GetPointerCount(), |
208 e.GetPointerCount(), | 299 GetBoundingBox(e))); |
209 GetBoundingBox(e))); | |
210 } | 300 } |
211 | 301 |
212 if (std::abs(detector.GetCurrentSpan() - detector.GetPreviousSpan()) < | 302 if (std::abs(detector.GetCurrentSpan() - detector.GetPreviousSpan()) < |
213 min_pinch_update_span_delta_) { | 303 config_.scale_gesture_detector_config.min_pinch_update_span_delta) { |
214 return false; | 304 return false; |
215 } | 305 } |
216 | 306 |
217 float scale = detector.GetScaleFactor(); | 307 float scale = detector.GetScaleFactor(); |
218 if (scale == 1) | 308 if (scale == 1) |
219 return true; | 309 return true; |
220 | 310 |
221 if (detector.InDoubleTapMode()) { | 311 if (detector.InDoubleTapMode()) { |
222 // Relative changes in the double-tap scale factor computed by |detector| | 312 // Relative changes in the double-tap scale factor computed by |detector| |
223 // diminish as the touch moves away from the original double-tap focus. | 313 // diminish as the touch moves away from the original double-tap focus. |
224 // For historical reasons, Chrome has instead adopted a scale factor | 314 // For historical reasons, Chrome has instead adopted a scale factor |
225 // computation that is invariant to the focal distance, where | 315 // computation that is invariant to the focal distance, where |
226 // the scale delta remains constant if the touch velocity is constant. | 316 // the scale delta remains constant if the touch velocity is constant. |
227 float dy = | 317 float dy = |
228 (detector.GetCurrentSpanY() - detector.GetPreviousSpanY()) * 0.5f; | 318 (detector.GetCurrentSpanY() - detector.GetPreviousSpanY()) * 0.5f; |
229 scale = std::pow(scale > 1 ? 1.0f + kDoubleTapDragZoomSpeed | 319 scale = std::pow(scale > 1 ? 1.0f + kDoubleTapDragZoomSpeed |
230 : 1.0f - kDoubleTapDragZoomSpeed, | 320 : 1.0f - kDoubleTapDragZoomSpeed, |
231 std::abs(dy)); | 321 std::abs(dy)); |
232 } | 322 } |
233 GestureEventDetails pinch_details(ET_GESTURE_PINCH_UPDATE, scale, 0); | 323 GestureEventDetails pinch_details(ET_GESTURE_PINCH_UPDATE, scale, 0); |
234 provider_->Send(CreateGesture(pinch_details, | 324 Send(CreateGesture(pinch_details, |
235 e.GetId(), | 325 e.GetId(), |
236 e.GetToolType(), | 326 e.GetToolType(), |
237 detector.GetEventTime(), | 327 detector.GetEventTime(), |
238 detector.GetFocusX(), | 328 detector.GetFocusX(), |
239 detector.GetFocusY(), | 329 detector.GetFocusY(), |
240 detector.GetFocusX() + e.GetRawOffsetX(), | 330 detector.GetFocusX() + e.GetRawOffsetX(), |
241 detector.GetFocusY() + e.GetRawOffsetY(), | 331 detector.GetFocusY() + e.GetRawOffsetY(), |
242 e.GetPointerCount(), | 332 e.GetPointerCount(), |
243 GetBoundingBox(e))); | 333 GetBoundingBox(e))); |
244 return true; | 334 return true; |
245 } | 335 } |
246 | 336 |
247 void SetDoubleTapEnabled(bool enabled) { | |
248 DCHECK(!IsDoubleTapInProgress()); | |
249 scale_gesture_detector_.SetQuickScaleEnabled(enabled); | |
250 } | |
251 | |
252 void SetMultiTouchEnabled(bool enabled) { | |
253 // Note that returning false from OnScaleBegin / OnScale makes the | |
254 // gesture detector not to emit further scaling notifications | |
255 // related to this gesture. Thus, if detector events are enabled in | |
256 // the middle of the gesture, we don't need to do anything. | |
257 ignore_multitouch_events_ = !enabled; | |
258 } | |
259 | |
260 bool IsDoubleTapInProgress() const { | |
261 return IsScaleGestureDetectionInProgress() && InDoubleTapMode(); | |
262 } | |
263 | |
264 bool IsScaleGestureDetectionInProgress() const { | |
265 return scale_gesture_detector_.IsInProgress(); | |
266 } | |
267 | |
268 private: | |
269 bool InDoubleTapMode() const { | |
270 return scale_gesture_detector_.InDoubleTapMode(); | |
271 } | |
272 | |
273 ScaleGestureDetector scale_gesture_detector_; | |
274 | |
275 GestureProvider* const provider_; | |
276 | |
277 // Completely silence multi-touch (pinch) scaling events. Used in WebView when | |
278 // zoom support is turned off. | |
279 bool ignore_multitouch_events_; | |
280 | |
281 // Whether any pinch zoom event has been sent to native. | |
282 bool pinch_event_sent_; | |
283 | |
284 // The minimum change in span required before this is considered a pinch. See | |
285 // crbug.com/373318. | |
286 float min_pinch_update_span_delta_; | |
287 | |
288 DISALLOW_COPY_AND_ASSIGN(ScaleGestureListenerImpl); | |
289 }; | |
290 | |
291 // GestureProvider::GestureListener | |
292 | |
293 class GestureProvider::GestureListenerImpl | |
294 : public GestureDetector::GestureListener, | |
295 public GestureDetector::DoubleTapListener { | |
296 public: | |
297 GestureListenerImpl( | |
298 const gfx::Display& display, | |
299 const GestureDetector::Config& gesture_detector_config, | |
300 bool disable_click_delay, | |
301 GestureProvider* provider) | |
302 : gesture_detector_(gesture_detector_config, this, this), | |
303 snap_scroll_controller_(display), | |
304 provider_(provider), | |
305 disable_click_delay_(disable_click_delay), | |
306 touch_slop_(gesture_detector_config.touch_slop), | |
307 double_tap_timeout_(gesture_detector_config.double_tap_timeout), | |
308 ignore_single_tap_(false), | |
309 seen_first_scroll_event_(false) {} | |
310 | |
311 virtual ~GestureListenerImpl() {} | |
312 | |
313 bool OnTouchEvent(const MotionEvent& e, | |
314 bool is_scale_gesture_detection_in_progress) { | |
315 snap_scroll_controller_.SetSnapScrollingMode( | |
316 e, is_scale_gesture_detection_in_progress); | |
317 | |
318 if (is_scale_gesture_detection_in_progress) | |
319 SetIgnoreSingleTap(true); | |
320 | |
321 if (e.GetAction() == MotionEvent::ACTION_DOWN) | |
322 gesture_detector_.set_longpress_enabled(true); | |
323 | |
324 return gesture_detector_.OnTouchEvent(e); | |
325 } | |
326 | |
327 // GestureDetector::GestureListener implementation. | 337 // GestureDetector::GestureListener implementation. |
328 virtual bool OnDown(const MotionEvent& e) OVERRIDE { | 338 virtual bool OnDown(const MotionEvent& e) OVERRIDE { |
329 current_down_time_ = e.GetEventTime(); | |
330 ignore_single_tap_ = false; | |
331 seen_first_scroll_event_ = false; | |
332 | |
333 GestureEventDetails tap_details(ET_GESTURE_TAP_DOWN, 0, 0); | 339 GestureEventDetails tap_details(ET_GESTURE_TAP_DOWN, 0, 0); |
334 provider_->Send(CreateGesture(tap_details, e)); | 340 Send(CreateGesture(tap_details, e)); |
335 | 341 |
336 // Return true to indicate that we want to handle touch. | 342 // Return true to indicate that we want to handle touch. |
337 return true; | 343 return true; |
338 } | 344 } |
339 | 345 |
340 virtual bool OnScroll(const MotionEvent& e1, | 346 virtual bool OnScroll(const MotionEvent& e1, |
341 const MotionEvent& e2, | 347 const MotionEvent& e2, |
342 float raw_distance_x, | 348 float raw_distance_x, |
343 float raw_distance_y) OVERRIDE { | 349 float raw_distance_y) OVERRIDE { |
344 float distance_x = raw_distance_x; | 350 float distance_x = raw_distance_x; |
345 float distance_y = raw_distance_y; | 351 float distance_y = raw_distance_y; |
346 if (!seen_first_scroll_event_) { | 352 if (!scroll_event_sent_) { |
347 // Remove the touch slop region from the first scroll event to avoid a | 353 // Remove the touch slop region from the first scroll event to avoid a |
348 // jump. | 354 // jump. |
349 seen_first_scroll_event_ = true; | |
350 double distance = | 355 double distance = |
351 std::sqrt(distance_x * distance_x + distance_y * distance_y); | 356 std::sqrt(distance_x * distance_x + distance_y * distance_y); |
352 double epsilon = 1e-3; | 357 double epsilon = 1e-3; |
353 if (distance > epsilon) { | 358 if (distance > epsilon) { |
354 double ratio = std::max(0., distance - touch_slop_) / distance; | 359 double ratio = |
| 360 std::max(0., |
| 361 distance - config_.gesture_detector_config.touch_slop) / |
| 362 distance; |
355 distance_x *= ratio; | 363 distance_x *= ratio; |
356 distance_y *= ratio; | 364 distance_y *= ratio; |
357 } | 365 } |
358 } | |
359 snap_scroll_controller_.UpdateSnapScrollMode(distance_x, distance_y); | |
360 if (snap_scroll_controller_.IsSnappingScrolls()) { | |
361 if (snap_scroll_controller_.IsSnapHorizontal()) { | |
362 distance_y = 0; | |
363 } else { | |
364 distance_x = 0; | |
365 } | |
366 } | |
367 | 366 |
368 if (!provider_->IsScrollInProgress()) { | |
369 // Note that scroll start hints are in distance traveled, where | 367 // Note that scroll start hints are in distance traveled, where |
370 // scroll deltas are in the opposite direction. | 368 // scroll deltas are in the opposite direction. |
371 GestureEventDetails scroll_details( | 369 GestureEventDetails scroll_details( |
372 ET_GESTURE_SCROLL_BEGIN, -raw_distance_x, -raw_distance_y); | 370 ET_GESTURE_SCROLL_BEGIN, -raw_distance_x, -raw_distance_y); |
373 | 371 |
374 // Use the co-ordinates from the touch down, as these co-ordinates are | 372 // Use the co-ordinates from the touch down, as these co-ordinates are |
375 // used to determine which layer the scroll should affect. | 373 // used to determine which layer the scroll should affect. |
376 provider_->Send(CreateGesture(scroll_details, | 374 Send(CreateGesture(scroll_details, |
377 e2.GetId(), | 375 e2.GetId(), |
378 e2.GetToolType(), | 376 e2.GetToolType(), |
379 e2.GetEventTime(), | 377 e2.GetEventTime(), |
380 e1.GetX(), | 378 e1.GetX(), |
381 e1.GetY(), | 379 e1.GetY(), |
382 e1.GetRawX(), | 380 e1.GetRawX(), |
383 e1.GetRawY(), | 381 e1.GetRawY(), |
384 e2.GetPointerCount(), | 382 e2.GetPointerCount(), |
385 GetBoundingBox(e2))); | 383 GetBoundingBox(e2))); |
| 384 DCHECK(scroll_event_sent_); |
| 385 } |
| 386 |
| 387 snap_scroll_controller_.UpdateSnapScrollMode(distance_x, distance_y); |
| 388 if (snap_scroll_controller_.IsSnappingScrolls()) { |
| 389 if (snap_scroll_controller_.IsSnapHorizontal()) |
| 390 distance_y = 0; |
| 391 else |
| 392 distance_x = 0; |
386 } | 393 } |
387 | 394 |
388 if (distance_x || distance_y) { | 395 if (distance_x || distance_y) { |
389 const gfx::RectF bounding_box = GetBoundingBox(e2); | 396 const gfx::RectF bounding_box = GetBoundingBox(e2); |
390 const gfx::PointF center = bounding_box.CenterPoint(); | 397 const gfx::PointF center = bounding_box.CenterPoint(); |
391 const gfx::PointF raw_center = | 398 const gfx::PointF raw_center = |
392 center + gfx::Vector2dF(e2.GetRawOffsetX(), e2.GetRawOffsetY()); | 399 center + gfx::Vector2dF(e2.GetRawOffsetX(), e2.GetRawOffsetY()); |
393 GestureEventDetails scroll_details( | 400 GestureEventDetails scroll_details( |
394 ET_GESTURE_SCROLL_UPDATE, -distance_x, -distance_y); | 401 ET_GESTURE_SCROLL_UPDATE, -distance_x, -distance_y); |
395 provider_->Send(CreateGesture(scroll_details, | 402 Send(CreateGesture(scroll_details, |
396 e2.GetId(), | 403 e2.GetId(), |
397 e2.GetToolType(), | 404 e2.GetToolType(), |
398 e2.GetEventTime(), | 405 e2.GetEventTime(), |
399 center.x(), | 406 center.x(), |
400 center.y(), | 407 center.y(), |
401 raw_center.x(), | 408 raw_center.x(), |
402 raw_center.y(), | 409 raw_center.y(), |
403 e2.GetPointerCount(), | 410 e2.GetPointerCount(), |
404 bounding_box)); | 411 bounding_box)); |
405 } | 412 } |
406 | 413 |
407 return true; | 414 return true; |
408 } | 415 } |
409 | 416 |
410 virtual bool OnFling(const MotionEvent& e1, | 417 virtual bool OnFling(const MotionEvent& e1, |
411 const MotionEvent& e2, | 418 const MotionEvent& e2, |
412 float velocity_x, | 419 float velocity_x, |
413 float velocity_y) OVERRIDE { | 420 float velocity_y) OVERRIDE { |
414 if (snap_scroll_controller_.IsSnappingScrolls()) { | 421 if (snap_scroll_controller_.IsSnappingScrolls()) { |
415 if (snap_scroll_controller_.IsSnapHorizontal()) { | 422 if (snap_scroll_controller_.IsSnapHorizontal()) { |
416 velocity_y = 0; | 423 velocity_y = 0; |
417 } else { | 424 } else { |
418 velocity_x = 0; | 425 velocity_x = 0; |
419 } | 426 } |
420 } | 427 } |
421 | 428 |
422 provider_->Fling(e2, velocity_x, velocity_y); | 429 if (!velocity_x && !velocity_y) |
| 430 return true; |
| 431 |
| 432 if (!scroll_event_sent_) { |
| 433 // The native side needs a ET_GESTURE_SCROLL_BEGIN before |
| 434 // ET_SCROLL_FLING_START to send the fling to the correct target. |
| 435 // The distance traveled in one second is a reasonable scroll start hint. |
| 436 GestureEventDetails scroll_details( |
| 437 ET_GESTURE_SCROLL_BEGIN, velocity_x, velocity_y); |
| 438 Send(CreateGesture(scroll_details, e2)); |
| 439 } |
| 440 |
| 441 GestureEventDetails fling_details( |
| 442 ET_SCROLL_FLING_START, velocity_x, velocity_y); |
| 443 Send(CreateGesture(fling_details, e2)); |
423 return true; | 444 return true; |
424 } | 445 } |
425 | 446 |
426 virtual bool OnSwipe(const MotionEvent& e1, | 447 virtual bool OnSwipe(const MotionEvent& e1, |
427 const MotionEvent& e2, | 448 const MotionEvent& e2, |
428 float velocity_x, | 449 float velocity_x, |
429 float velocity_y) OVERRIDE { | 450 float velocity_y) OVERRIDE { |
430 GestureEventDetails swipe_details(ET_GESTURE_SWIPE, velocity_x, velocity_y); | 451 GestureEventDetails swipe_details(ET_GESTURE_SWIPE, velocity_x, velocity_y); |
431 provider_->Send(CreateGesture(swipe_details, e2)); | 452 Send(CreateGesture(swipe_details, e2)); |
432 return true; | 453 return true; |
433 } | 454 } |
434 | 455 |
435 virtual bool OnTwoFingerTap(const MotionEvent& e1, | 456 virtual bool OnTwoFingerTap(const MotionEvent& e1, |
436 const MotionEvent& e2) OVERRIDE { | 457 const MotionEvent& e2) OVERRIDE { |
437 // The location of the two finger tap event should be the location of the | 458 // The location of the two finger tap event should be the location of the |
438 // primary pointer. | 459 // primary pointer. |
439 GestureEventDetails two_finger_tap_details(ET_GESTURE_TWO_FINGER_TAP, | 460 GestureEventDetails two_finger_tap_details( |
440 e1.GetTouchMajor(), | 461 ET_GESTURE_TWO_FINGER_TAP, e1.GetTouchMajor(), e1.GetTouchMajor()); |
441 e1.GetTouchMajor()); | 462 Send(CreateGesture(two_finger_tap_details, |
442 provider_->Send(CreateGesture(two_finger_tap_details, | 463 e2.GetId(), |
443 e2.GetId(), | 464 e2.GetToolType(), |
444 e2.GetToolType(), | 465 e2.GetEventTime(), |
445 e2.GetEventTime(), | 466 e1.GetX(), |
446 e1.GetX(), | 467 e1.GetY(), |
447 e1.GetY(), | 468 e1.GetRawX(), |
448 e1.GetRawX(), | 469 e1.GetRawY(), |
449 e1.GetRawY(), | 470 e2.GetPointerCount(), |
450 e2.GetPointerCount(), | 471 GetBoundingBox(e2))); |
451 GetBoundingBox(e2))); | |
452 return true; | 472 return true; |
453 } | 473 } |
454 | 474 |
455 virtual void OnShowPress(const MotionEvent& e) OVERRIDE { | 475 virtual void OnShowPress(const MotionEvent& e) OVERRIDE { |
456 GestureEventDetails show_press_details(ET_GESTURE_SHOW_PRESS, 0, 0); | 476 GestureEventDetails show_press_details(ET_GESTURE_SHOW_PRESS, 0, 0); |
457 provider_->Send(CreateGesture(show_press_details, e)); | 477 Send(CreateGesture(show_press_details, e)); |
458 } | 478 } |
459 | 479 |
460 virtual bool OnSingleTapUp(const MotionEvent& e) OVERRIDE { | 480 virtual bool OnSingleTapUp(const MotionEvent& e) OVERRIDE { |
461 // This is a hack to address the issue where user hovers | 481 // This is a hack to address the issue where user hovers |
462 // over a link for longer than double_tap_timeout_, then | 482 // over a link for longer than double_tap_timeout_, then |
463 // OnSingleTapConfirmed() is not triggered. But we still | 483 // OnSingleTapConfirmed() is not triggered. But we still |
464 // want to trigger the tap event at UP. So we override | 484 // want to trigger the tap event at UP. So we override |
465 // OnSingleTapUp() in this case. This assumes singleTapUp | 485 // OnSingleTapUp() in this case. This assumes singleTapUp |
466 // gets always called before singleTapConfirmed. | 486 // gets always called before singleTapConfirmed. |
467 if (!ignore_single_tap_) { | 487 if (!ignore_single_tap_) { |
468 if (e.GetEventTime() - current_down_time_ > double_tap_timeout_) { | 488 if (e.GetEventTime() - current_down_time_ > |
| 489 config_.gesture_detector_config.double_tap_timeout) { |
469 return OnSingleTapConfirmed(e); | 490 return OnSingleTapConfirmed(e); |
470 } else if (!IsDoubleTapEnabled() || disable_click_delay_) { | 491 } else if (!IsDoubleTapEnabled() || config_.disable_click_delay) { |
471 // If double-tap has been disabled, there is no need to wait | 492 // If double-tap has been disabled, there is no need to wait |
472 // for the double-tap timeout. | 493 // for the double-tap timeout. |
473 return OnSingleTapConfirmed(e); | 494 return OnSingleTapConfirmed(e); |
474 } else { | 495 } else { |
475 // Notify Blink about this tapUp event anyway, when none of the above | 496 // Notify Blink about this tapUp event anyway, when none of the above |
476 // conditions applied. | 497 // conditions applied. |
477 provider_->Send(CreateGesture( | 498 Send(CreateTapGesture(ET_GESTURE_TAP_UNCONFIRMED, e)); |
478 CreateTapGestureDetails(ET_GESTURE_TAP_UNCONFIRMED), e)); | |
479 } | 499 } |
480 } | 500 } |
481 | 501 |
482 return provider_->SendLongTapIfNecessary(e); | 502 if (e.GetAction() == MotionEvent::ACTION_UP && |
| 503 !current_longpress_time_.is_null() && |
| 504 !IsScaleGestureDetectionInProgress()) { |
| 505 GestureEventDetails long_tap_details(ET_GESTURE_LONG_TAP, 0, 0); |
| 506 Send(CreateGesture(long_tap_details, e)); |
| 507 return true; |
| 508 } |
| 509 |
| 510 return false; |
483 } | 511 } |
484 | 512 |
485 // GestureDetector::DoubleTapListener implementation. | 513 // GestureDetector::DoubleTapListener implementation. |
486 virtual bool OnSingleTapConfirmed(const MotionEvent& e) OVERRIDE { | 514 virtual bool OnSingleTapConfirmed(const MotionEvent& e) OVERRIDE { |
487 // Long taps in the edges of the screen have their events delayed by | 515 // Long taps in the edges of the screen have their events delayed by |
488 // ContentViewHolder for tab swipe operations. As a consequence of the delay | 516 // ContentViewHolder for tab swipe operations. As a consequence of the delay |
489 // this method might be called after receiving the up event. | 517 // this method might be called after receiving the up event. |
490 // These corner cases should be ignored. | 518 // These corner cases should be ignored. |
491 if (ignore_single_tap_) | 519 if (ignore_single_tap_) |
492 return true; | 520 return true; |
493 | 521 |
494 ignore_single_tap_ = true; | 522 ignore_single_tap_ = true; |
495 | 523 |
496 provider_->Send(CreateGesture(CreateTapGestureDetails(ET_GESTURE_TAP), e)); | 524 Send(CreateTapGesture(ET_GESTURE_TAP, e)); |
497 return true; | 525 return true; |
498 } | 526 } |
499 | 527 |
500 virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE { return false; } | 528 virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE { |
| 529 return scale_gesture_detector_.OnDoubleTap(e); |
| 530 } |
501 | 531 |
502 virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE { | 532 virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE { |
503 switch (e.GetAction()) { | 533 switch (e.GetAction()) { |
504 case MotionEvent::ACTION_DOWN: | 534 case MotionEvent::ACTION_DOWN: |
505 gesture_detector_.set_longpress_enabled(false); | 535 gesture_detector_.set_longpress_enabled(false); |
506 break; | 536 break; |
507 | 537 |
508 case MotionEvent::ACTION_UP: | 538 case MotionEvent::ACTION_UP: |
509 if (!provider_->IsPinchInProgress() && | 539 if (!IsPinchInProgress() && !IsScrollInProgress()) { |
510 !provider_->IsScrollInProgress()) { | 540 Send(CreateTapGesture(ET_GESTURE_DOUBLE_TAP, e)); |
511 provider_->Send( | |
512 CreateGesture(CreateTapGestureDetails(ET_GESTURE_DOUBLE_TAP), e)); | |
513 return true; | 541 return true; |
514 } | 542 } |
515 break; | 543 break; |
| 544 |
516 default: | 545 default: |
517 break; | 546 break; |
518 } | 547 } |
519 return false; | 548 return false; |
520 } | 549 } |
521 | 550 |
522 virtual void OnLongPress(const MotionEvent& e) OVERRIDE { | 551 virtual void OnLongPress(const MotionEvent& e) OVERRIDE { |
523 DCHECK(!IsDoubleTapInProgress()); | 552 DCHECK(!IsDoubleTapInProgress()); |
524 SetIgnoreSingleTap(true); | 553 SetIgnoreSingleTap(true); |
525 | |
526 GestureEventDetails long_press_details(ET_GESTURE_LONG_PRESS, 0, 0); | 554 GestureEventDetails long_press_details(ET_GESTURE_LONG_PRESS, 0, 0); |
527 provider_->Send(CreateGesture(long_press_details, e)); | 555 Send(CreateGesture(long_press_details, e)); |
528 } | 556 } |
529 | 557 |
530 void SetDoubleTapEnabled(bool enabled) { | 558 void SetDoubleTapEnabled(bool enabled) { |
531 DCHECK(!IsDoubleTapInProgress()); | 559 DCHECK(!IsDoubleTapInProgress()); |
532 gesture_detector_.SetDoubleTapListener(enabled ? this : NULL); | 560 gesture_detector_.SetDoubleTapListener(enabled ? this : NULL); |
533 } | 561 } |
534 | 562 |
535 bool IsDoubleTapInProgress() const { | 563 void SetMultiTouchZoomEnabled(bool enabled) { |
536 return gesture_detector_.is_double_tapping(); | 564 // Note that returning false from |OnScaleBegin()| or |OnScale()| prevents |
| 565 // the detector from emitting further scale updates for the current touch |
| 566 // sequence. Thus, if multitouch events are enabled in the middle of a |
| 567 // gesture, it will only take effect with the next gesture. |
| 568 ignore_multitouch_zoom_events_ = !enabled; |
537 } | 569 } |
538 | 570 |
| 571 bool IsDoubleTapInProgress() const { |
| 572 return gesture_detector_.is_double_tapping() || |
| 573 (IsScaleGestureDetectionInProgress() && InDoubleTapMode()); |
| 574 } |
| 575 |
| 576 bool IsScrollInProgress() const { return scroll_event_sent_; } |
| 577 |
| 578 bool IsPinchInProgress() const { return pinch_event_sent_; } |
| 579 |
539 private: | 580 private: |
540 void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; } | 581 bool IsScaleGestureDetectionInProgress() const { |
| 582 return scale_gesture_detector_.IsInProgress(); |
| 583 } |
| 584 |
| 585 bool InDoubleTapMode() const { |
| 586 return scale_gesture_detector_.InDoubleTapMode(); |
| 587 } |
541 | 588 |
542 bool IsDoubleTapEnabled() const { | 589 bool IsDoubleTapEnabled() const { |
543 return gesture_detector_.has_doubletap_listener(); | 590 return gesture_detector_.has_doubletap_listener(); |
544 } | 591 } |
545 | 592 |
| 593 void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; } |
| 594 |
| 595 const GestureProvider::Config config_; |
| 596 GestureProviderClient* const client_; |
| 597 |
546 GestureDetector gesture_detector_; | 598 GestureDetector gesture_detector_; |
| 599 ScaleGestureDetector scale_gesture_detector_; |
547 SnapScrollController snap_scroll_controller_; | 600 SnapScrollController snap_scroll_controller_; |
548 | 601 |
549 GestureProvider* const provider_; | |
550 | |
551 // Whether the click delay should always be disabled by sending clicks for | |
552 // double-tap gestures. | |
553 const bool disable_click_delay_; | |
554 | |
555 const float touch_slop_; | |
556 | |
557 const base::TimeDelta double_tap_timeout_; | |
558 | |
559 base::TimeTicks current_down_time_; | 602 base::TimeTicks current_down_time_; |
560 | 603 |
| 604 // Keeps track of the current GESTURE_LONG_PRESS event. If a context menu is |
| 605 // opened after a GESTURE_LONG_PRESS, this is used to insert a |
| 606 // GESTURE_TAP_CANCEL for removing any ::active styling. |
| 607 base::TimeTicks current_longpress_time_; |
| 608 |
| 609 // Completely silence multi-touch (pinch) scaling events. Used in WebView when |
| 610 // zoom support is turned off. |
| 611 bool ignore_multitouch_zoom_events_; |
| 612 |
561 // TODO(klobag): This is to avoid a bug in GestureDetector. With multi-touch, | 613 // TODO(klobag): This is to avoid a bug in GestureDetector. With multi-touch, |
562 // always_in_tap_region_ is not reset. So when the last finger is up, | 614 // always_in_tap_region_ is not reset. So when the last finger is up, |
563 // OnSingleTapUp() will be mistakenly fired. | 615 // |OnSingleTapUp()| will be mistakenly fired. |
564 bool ignore_single_tap_; | 616 bool ignore_single_tap_; |
565 | 617 |
566 // Used to remove the touch slop from the initial scroll event in a scroll | 618 // Tracks whether {PINCH|SCROLL}_BEGIN events have been forwarded for the |
567 // gesture. | 619 // current touch sequence. |
568 bool seen_first_scroll_event_; | 620 bool pinch_event_sent_; |
| 621 bool scroll_event_sent_; |
569 | 622 |
570 DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl); | 623 DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl); |
571 }; | 624 }; |
572 | 625 |
573 // GestureProvider | 626 // GestureProvider |
574 | 627 |
575 GestureProvider::GestureProvider(const Config& config, | 628 GestureProvider::GestureProvider(const Config& config, |
576 GestureProviderClient* client) | 629 GestureProviderClient* client) |
577 : client_(client), | 630 : double_tap_support_for_page_(true), |
578 touch_scroll_in_progress_(false), | |
579 pinch_in_progress_(false), | |
580 double_tap_support_for_page_(true), | |
581 double_tap_support_for_platform_(true), | 631 double_tap_support_for_platform_(true), |
582 gesture_begin_end_types_enabled_(config.gesture_begin_end_types_enabled), | 632 gesture_begin_end_types_enabled_(config.gesture_begin_end_types_enabled) { |
583 min_gesture_bounds_length_(config.min_gesture_bounds_length), | |
584 max_gesture_bounds_length_(config.max_gesture_bounds_length) { | |
585 DCHECK(client); | 633 DCHECK(client); |
586 DCHECK(!min_gesture_bounds_length_ || !max_gesture_bounds_length_ || | 634 DCHECK(!config.min_gesture_bounds_length || |
587 min_gesture_bounds_length_ <= max_gesture_bounds_length_); | 635 !config.max_gesture_bounds_length || |
588 InitGestureDetectors(config); | 636 config.min_gesture_bounds_length <= config.max_gesture_bounds_length); |
| 637 TRACE_EVENT0("input", "GestureProvider::InitGestureDetectors"); |
| 638 gesture_listener_.reset(new GestureListenerImpl(config, client)); |
| 639 UpdateDoubleTapDetectionSupport(); |
589 } | 640 } |
590 | 641 |
591 GestureProvider::~GestureProvider() {} | 642 GestureProvider::~GestureProvider() { |
| 643 } |
592 | 644 |
593 bool GestureProvider::OnTouchEvent(const MotionEvent& event) { | 645 bool GestureProvider::OnTouchEvent(const MotionEvent& event) { |
594 TRACE_EVENT1("input", "GestureProvider::OnTouchEvent", | 646 TRACE_EVENT1("input", |
595 "action", GetMotionEventActionName(event.GetAction())); | 647 "GestureProvider::OnTouchEvent", |
| 648 "action", |
| 649 GetMotionEventActionName(event.GetAction())); |
596 | 650 |
597 DCHECK_NE(0u, event.GetPointerCount()); | 651 DCHECK_NE(0u, event.GetPointerCount()); |
598 | 652 |
599 if (!CanHandle(event)) | 653 if (!CanHandle(event)) |
600 return false; | 654 return false; |
601 | 655 |
602 const bool in_scale_gesture = | |
603 scale_gesture_listener_->IsScaleGestureDetectionInProgress(); | |
604 | |
605 OnTouchEventHandlingBegin(event); | 656 OnTouchEventHandlingBegin(event); |
606 gesture_listener_->OnTouchEvent(event, in_scale_gesture); | 657 gesture_listener_->OnTouchEvent(event); |
607 scale_gesture_listener_->OnTouchEvent(event); | |
608 OnTouchEventHandlingEnd(event); | 658 OnTouchEventHandlingEnd(event); |
609 return true; | 659 return true; |
610 } | 660 } |
611 | 661 |
612 void GestureProvider::SetMultiTouchZoomSupportEnabled(bool enabled) { | 662 void GestureProvider::SetMultiTouchZoomSupportEnabled(bool enabled) { |
613 scale_gesture_listener_->SetMultiTouchEnabled(enabled); | 663 gesture_listener_->SetMultiTouchZoomEnabled(enabled); |
614 } | 664 } |
615 | 665 |
616 void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) { | 666 void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) { |
617 if (double_tap_support_for_platform_ == enabled) | 667 if (double_tap_support_for_platform_ == enabled) |
618 return; | 668 return; |
619 double_tap_support_for_platform_ = enabled; | 669 double_tap_support_for_platform_ = enabled; |
620 UpdateDoubleTapDetectionSupport(); | 670 UpdateDoubleTapDetectionSupport(); |
621 } | 671 } |
622 | 672 |
623 void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) { | 673 void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) { |
624 if (double_tap_support_for_page_ == enabled) | 674 if (double_tap_support_for_page_ == enabled) |
625 return; | 675 return; |
626 double_tap_support_for_page_ = enabled; | 676 double_tap_support_for_page_ = enabled; |
627 UpdateDoubleTapDetectionSupport(); | 677 UpdateDoubleTapDetectionSupport(); |
628 } | 678 } |
629 | 679 |
630 bool GestureProvider::IsScrollInProgress() const { | 680 bool GestureProvider::IsScrollInProgress() const { |
631 // TODO(wangxianzhu): Also return true when fling is active once the UI knows | 681 return gesture_listener_->IsScrollInProgress(); |
632 // exactly when the fling ends. | |
633 return touch_scroll_in_progress_; | |
634 } | 682 } |
635 | 683 |
636 bool GestureProvider::IsPinchInProgress() const { return pinch_in_progress_; } | 684 bool GestureProvider::IsPinchInProgress() const { |
| 685 return gesture_listener_->IsPinchInProgress(); |
| 686 } |
637 | 687 |
638 bool GestureProvider::IsDoubleTapInProgress() const { | 688 bool GestureProvider::IsDoubleTapInProgress() const { |
639 return gesture_listener_->IsDoubleTapInProgress() || | 689 return gesture_listener_->IsDoubleTapInProgress(); |
640 scale_gesture_listener_->IsDoubleTapInProgress(); | |
641 } | |
642 | |
643 void GestureProvider::InitGestureDetectors(const Config& config) { | |
644 TRACE_EVENT0("input", "GestureProvider::InitGestureDetectors"); | |
645 gesture_listener_.reset( | |
646 new GestureListenerImpl(config.display, | |
647 config.gesture_detector_config, | |
648 config.disable_click_delay, | |
649 this)); | |
650 | |
651 scale_gesture_listener_.reset( | |
652 new ScaleGestureListenerImpl(config.scale_gesture_detector_config, this)); | |
653 | |
654 UpdateDoubleTapDetectionSupport(); | |
655 } | 690 } |
656 | 691 |
657 bool GestureProvider::CanHandle(const MotionEvent& event) const { | 692 bool GestureProvider::CanHandle(const MotionEvent& event) const { |
658 // Aura requires one cancel event per touch point, whereas Android requires | 693 // Aura requires one cancel event per touch point, whereas Android requires |
659 // one cancel event per touch sequence. Thus we need to allow extra cancel | 694 // one cancel event per touch sequence. Thus we need to allow extra cancel |
660 // events. | 695 // events. |
661 return event.GetAction() == MotionEvent::ACTION_DOWN || current_down_event_ || | 696 return current_down_event_ || event.GetAction() == MotionEvent::ACTION_DOWN || |
662 event.GetAction() == MotionEvent::ACTION_CANCEL; | 697 event.GetAction() == MotionEvent::ACTION_CANCEL; |
663 } | 698 } |
664 | 699 |
665 void GestureProvider::Fling(const MotionEvent& event, | |
666 float velocity_x, | |
667 float velocity_y) { | |
668 if (!velocity_x && !velocity_y) { | |
669 EndTouchScrollIfNecessary(event, true); | |
670 return; | |
671 } | |
672 | |
673 if (!touch_scroll_in_progress_) { | |
674 // The native side needs a ET_GESTURE_SCROLL_BEGIN before | |
675 // ET_SCROLL_FLING_START to send the fling to the correct target. Send if it | |
676 // has not sent. The distance traveled in one second is a reasonable scroll | |
677 // start hint. | |
678 GestureEventDetails scroll_details( | |
679 ET_GESTURE_SCROLL_BEGIN, velocity_x, velocity_y); | |
680 Send(CreateGesture(scroll_details, event)); | |
681 } | |
682 EndTouchScrollIfNecessary(event, false); | |
683 | |
684 GestureEventDetails fling_details( | |
685 ET_SCROLL_FLING_START, velocity_x, velocity_y); | |
686 Send(CreateGesture(fling_details, event)); | |
687 } | |
688 | |
689 void GestureProvider::Send(GestureEventData gesture) { | |
690 DCHECK(!gesture.time.is_null()); | |
691 // The only valid events that should be sent without an active touch sequence | |
692 // are SHOW_PRESS and TAP, potentially triggered by the double-tap | |
693 // delay timing out. | |
694 DCHECK(current_down_event_ || gesture.type() == ET_GESTURE_TAP || | |
695 gesture.type() == ET_GESTURE_SHOW_PRESS || | |
696 gesture.type() == ET_GESTURE_END); | |
697 | |
698 if (gesture.primary_tool_type == MotionEvent::TOOL_TYPE_UNKNOWN || | |
699 gesture.primary_tool_type == MotionEvent::TOOL_TYPE_FINGER) { | |
700 gesture.details.set_bounding_box( | |
701 ClampBoundingBox(gesture.details.bounding_box_f(), | |
702 min_gesture_bounds_length_, | |
703 max_gesture_bounds_length_)); | |
704 } | |
705 | |
706 switch (gesture.type()) { | |
707 case ET_GESTURE_LONG_PRESS: | |
708 DCHECK(!scale_gesture_listener_->IsScaleGestureDetectionInProgress()); | |
709 current_longpress_time_ = gesture.time; | |
710 break; | |
711 case ET_GESTURE_LONG_TAP: | |
712 current_longpress_time_ = base::TimeTicks(); | |
713 break; | |
714 case ET_GESTURE_SCROLL_BEGIN: | |
715 DCHECK(!touch_scroll_in_progress_); | |
716 touch_scroll_in_progress_ = true; | |
717 break; | |
718 case ET_GESTURE_SCROLL_END: | |
719 DCHECK(touch_scroll_in_progress_); | |
720 if (pinch_in_progress_) | |
721 Send(GestureEventData(ET_GESTURE_PINCH_END, gesture)); | |
722 touch_scroll_in_progress_ = false; | |
723 break; | |
724 case ET_GESTURE_PINCH_BEGIN: | |
725 DCHECK(!pinch_in_progress_); | |
726 if (!touch_scroll_in_progress_) | |
727 Send(GestureEventData(ET_GESTURE_SCROLL_BEGIN, gesture)); | |
728 pinch_in_progress_ = true; | |
729 break; | |
730 case ET_GESTURE_PINCH_END: | |
731 DCHECK(pinch_in_progress_); | |
732 pinch_in_progress_ = false; | |
733 break; | |
734 case ET_GESTURE_SHOW_PRESS: | |
735 // It's possible that a double-tap drag zoom (from ScaleGestureDetector) | |
736 // will start before the press gesture fires (from GestureDetector), in | |
737 // which case the press should simply be dropped. | |
738 if (pinch_in_progress_ || touch_scroll_in_progress_) | |
739 return; | |
740 default: | |
741 break; | |
742 }; | |
743 | |
744 client_->OnGestureEvent(gesture); | |
745 } | |
746 | |
747 bool GestureProvider::SendLongTapIfNecessary(const MotionEvent& event) { | |
748 if (event.GetAction() == MotionEvent::ACTION_UP && | |
749 !current_longpress_time_.is_null() && | |
750 !scale_gesture_listener_->IsScaleGestureDetectionInProgress()) { | |
751 GestureEventDetails long_tap_details(ET_GESTURE_LONG_TAP, 0, 0); | |
752 Send(CreateGesture(long_tap_details, event)); | |
753 return true; | |
754 } | |
755 return false; | |
756 } | |
757 | |
758 void GestureProvider::EndTouchScrollIfNecessary(const MotionEvent& event, | |
759 bool send_scroll_end_event) { | |
760 if (!touch_scroll_in_progress_) | |
761 return; | |
762 if (send_scroll_end_event) | |
763 Send(CreateGesture(ET_GESTURE_SCROLL_END, event)); | |
764 touch_scroll_in_progress_ = false; | |
765 } | |
766 | |
767 void GestureProvider::OnTouchEventHandlingBegin(const MotionEvent& event) { | 700 void GestureProvider::OnTouchEventHandlingBegin(const MotionEvent& event) { |
768 switch (event.GetAction()) { | 701 switch (event.GetAction()) { |
769 case MotionEvent::ACTION_DOWN: | 702 case MotionEvent::ACTION_DOWN: |
770 current_down_event_ = event.Clone(); | 703 current_down_event_ = event.Clone(); |
771 touch_scroll_in_progress_ = false; | |
772 pinch_in_progress_ = false; | |
773 current_longpress_time_ = base::TimeTicks(); | |
774 if (gesture_begin_end_types_enabled_) | 704 if (gesture_begin_end_types_enabled_) |
775 Send(CreateGesture(ET_GESTURE_BEGIN, event)); | 705 gesture_listener_->Send(CreateGesture(ET_GESTURE_BEGIN, event)); |
776 break; | 706 break; |
777 case MotionEvent::ACTION_POINTER_DOWN: | 707 case MotionEvent::ACTION_POINTER_DOWN: |
778 if (gesture_begin_end_types_enabled_) { | 708 if (gesture_begin_end_types_enabled_) { |
779 const int action_index = event.GetActionIndex(); | 709 const int action_index = event.GetActionIndex(); |
780 Send(CreateGesture(ET_GESTURE_BEGIN, | 710 gesture_listener_->Send(CreateGesture(ET_GESTURE_BEGIN, |
781 event.GetId(), | 711 event.GetId(), |
782 event.GetToolType(), | 712 event.GetToolType(), |
783 event.GetEventTime(), | 713 event.GetEventTime(), |
784 event.GetX(action_index), | 714 event.GetX(action_index), |
785 event.GetY(action_index), | 715 event.GetY(action_index), |
786 event.GetRawX(action_index), | 716 event.GetRawX(action_index), |
787 event.GetRawY(action_index), | 717 event.GetRawY(action_index), |
788 event.GetPointerCount(), | 718 event.GetPointerCount(), |
789 GetBoundingBox(event))); | 719 GetBoundingBox(event))); |
790 } | 720 } |
791 break; | 721 break; |
792 case MotionEvent::ACTION_POINTER_UP: | 722 case MotionEvent::ACTION_POINTER_UP: |
793 case MotionEvent::ACTION_UP: | 723 case MotionEvent::ACTION_UP: |
794 case MotionEvent::ACTION_CANCEL: | 724 case MotionEvent::ACTION_CANCEL: |
795 case MotionEvent::ACTION_MOVE: | 725 case MotionEvent::ACTION_MOVE: |
796 break; | 726 break; |
797 } | 727 } |
798 } | 728 } |
799 | 729 |
800 void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) { | 730 void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) { |
801 switch (event.GetAction()) { | 731 switch (event.GetAction()) { |
802 case MotionEvent::ACTION_UP: | 732 case MotionEvent::ACTION_UP: |
803 case MotionEvent::ACTION_CANCEL: { | 733 case MotionEvent::ACTION_CANCEL: { |
804 // Note: This call will have no effect if a fling was just generated, as | |
805 // |Fling()| will have already signalled an end to touch-scrolling. | |
806 EndTouchScrollIfNecessary(event, true); | |
807 | |
808 if (gesture_begin_end_types_enabled_) | 734 if (gesture_begin_end_types_enabled_) |
809 Send(CreateGesture(ET_GESTURE_END, event)); | 735 gesture_listener_->Send(CreateGesture(ET_GESTURE_END, event)); |
810 | 736 |
811 current_down_event_.reset(); | 737 current_down_event_.reset(); |
812 | 738 |
813 UpdateDoubleTapDetectionSupport(); | 739 UpdateDoubleTapDetectionSupport(); |
814 break; | 740 break; |
815 } | 741 } |
816 case MotionEvent::ACTION_POINTER_UP: | 742 case MotionEvent::ACTION_POINTER_UP: |
817 if (gesture_begin_end_types_enabled_) | 743 if (gesture_begin_end_types_enabled_) |
818 Send(CreateGesture(ET_GESTURE_END, event)); | 744 gesture_listener_->Send(CreateGesture(ET_GESTURE_END, event)); |
819 break; | 745 break; |
820 case MotionEvent::ACTION_DOWN: | 746 case MotionEvent::ACTION_DOWN: |
821 case MotionEvent::ACTION_POINTER_DOWN: | 747 case MotionEvent::ACTION_POINTER_DOWN: |
822 case MotionEvent::ACTION_MOVE: | 748 case MotionEvent::ACTION_MOVE: |
823 break; | 749 break; |
824 } | 750 } |
825 } | 751 } |
826 | 752 |
827 void GestureProvider::UpdateDoubleTapDetectionSupport() { | 753 void GestureProvider::UpdateDoubleTapDetectionSupport() { |
828 // The GestureDetector requires that any provided DoubleTapListener remain | 754 // The GestureDetector requires that any provided DoubleTapListener remain |
829 // attached to it for the duration of a touch sequence. Defer any potential | 755 // attached to it for the duration of a touch sequence. Defer any potential |
830 // null'ing of the listener until the sequence has ended. | 756 // null'ing of the listener until the sequence has ended. |
831 if (current_down_event_) | 757 if (current_down_event_) |
832 return; | 758 return; |
833 | 759 |
834 const bool double_tap_enabled = double_tap_support_for_page_ && | 760 const bool double_tap_enabled = |
835 double_tap_support_for_platform_; | 761 double_tap_support_for_page_ && double_tap_support_for_platform_; |
836 gesture_listener_->SetDoubleTapEnabled(double_tap_enabled); | 762 gesture_listener_->SetDoubleTapEnabled(double_tap_enabled); |
837 scale_gesture_listener_->SetDoubleTapEnabled(double_tap_enabled); | |
838 } | 763 } |
839 | 764 |
840 } // namespace ui | 765 } // namespace ui |
OLD | NEW |