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...) 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()) { | |
tdresser
2014/08/22 18:19:04
While you're here, you could switch to a braceless
jdduke (slow)
2014/08/22 20:33:10
Done.
| |
390 distance_y = 0; | |
391 } else { | |
392 distance_x = 0; | |
393 } | |
386 } | 394 } |
387 | 395 |
388 if (distance_x || distance_y) { | 396 if (distance_x || distance_y) { |
389 const gfx::RectF bounding_box = GetBoundingBox(e2); | 397 const gfx::RectF bounding_box = GetBoundingBox(e2); |
390 const gfx::PointF center = bounding_box.CenterPoint(); | 398 const gfx::PointF center = bounding_box.CenterPoint(); |
391 const gfx::PointF raw_center = | 399 const gfx::PointF raw_center = |
392 center + gfx::Vector2dF(e2.GetRawOffsetX(), e2.GetRawOffsetY()); | 400 center + gfx::Vector2dF(e2.GetRawOffsetX(), e2.GetRawOffsetY()); |
393 GestureEventDetails scroll_details( | 401 GestureEventDetails scroll_details( |
394 ET_GESTURE_SCROLL_UPDATE, -distance_x, -distance_y); | 402 ET_GESTURE_SCROLL_UPDATE, -distance_x, -distance_y); |
395 provider_->Send(CreateGesture(scroll_details, | 403 Send(CreateGesture(scroll_details, |
396 e2.GetId(), | 404 e2.GetId(), |
397 e2.GetToolType(), | 405 e2.GetToolType(), |
398 e2.GetEventTime(), | 406 e2.GetEventTime(), |
399 center.x(), | 407 center.x(), |
400 center.y(), | 408 center.y(), |
401 raw_center.x(), | 409 raw_center.x(), |
402 raw_center.y(), | 410 raw_center.y(), |
403 e2.GetPointerCount(), | 411 e2.GetPointerCount(), |
404 bounding_box)); | 412 bounding_box)); |
405 } | 413 } |
406 | 414 |
407 return true; | 415 return true; |
408 } | 416 } |
409 | 417 |
410 virtual bool OnFling(const MotionEvent& e1, | 418 virtual bool OnFling(const MotionEvent& e1, |
411 const MotionEvent& e2, | 419 const MotionEvent& e2, |
412 float velocity_x, | 420 float velocity_x, |
413 float velocity_y) OVERRIDE { | 421 float velocity_y) OVERRIDE { |
414 if (snap_scroll_controller_.IsSnappingScrolls()) { | 422 if (snap_scroll_controller_.IsSnappingScrolls()) { |
415 if (snap_scroll_controller_.IsSnapHorizontal()) { | 423 if (snap_scroll_controller_.IsSnapHorizontal()) { |
416 velocity_y = 0; | 424 velocity_y = 0; |
417 } else { | 425 } else { |
418 velocity_x = 0; | 426 velocity_x = 0; |
419 } | 427 } |
420 } | 428 } |
421 | 429 |
422 provider_->Fling(e2, velocity_x, velocity_y); | 430 if (!velocity_x && !velocity_y) |
431 return true; | |
432 | |
433 if (!scroll_event_sent_) { | |
434 // The native side needs a ET_GESTURE_SCROLL_BEGIN before | |
435 // ET_SCROLL_FLING_START to send the fling to the correct target. | |
436 // The distance traveled in one second is a reasonable scroll start hint. | |
437 GestureEventDetails scroll_details( | |
438 ET_GESTURE_SCROLL_BEGIN, velocity_x, velocity_y); | |
439 Send(CreateGesture(scroll_details, e2)); | |
440 } | |
441 | |
442 GestureEventDetails fling_details( | |
443 ET_SCROLL_FLING_START, velocity_x, velocity_y); | |
444 Send(CreateGesture(fling_details, e2)); | |
423 return true; | 445 return true; |
424 } | 446 } |
425 | 447 |
426 virtual bool OnSwipe(const MotionEvent& e1, | 448 virtual bool OnSwipe(const MotionEvent& e1, |
427 const MotionEvent& e2, | 449 const MotionEvent& e2, |
428 float velocity_x, | 450 float velocity_x, |
429 float velocity_y) OVERRIDE { | 451 float velocity_y) OVERRIDE { |
430 GestureEventDetails swipe_details(ET_GESTURE_SWIPE, velocity_x, velocity_y); | 452 GestureEventDetails swipe_details(ET_GESTURE_SWIPE, velocity_x, velocity_y); |
431 provider_->Send(CreateGesture(swipe_details, e2)); | 453 Send(CreateGesture(swipe_details, e2)); |
432 return true; | 454 return true; |
433 } | 455 } |
434 | 456 |
435 virtual bool OnTwoFingerTap(const MotionEvent& e1, | 457 virtual bool OnTwoFingerTap(const MotionEvent& e1, |
436 const MotionEvent& e2) OVERRIDE { | 458 const MotionEvent& e2) OVERRIDE { |
437 // The location of the two finger tap event should be the location of the | 459 // The location of the two finger tap event should be the location of the |
438 // primary pointer. | 460 // primary pointer. |
439 GestureEventDetails two_finger_tap_details(ET_GESTURE_TWO_FINGER_TAP, | 461 GestureEventDetails two_finger_tap_details( |
440 e1.GetTouchMajor(), | 462 ET_GESTURE_TWO_FINGER_TAP, e1.GetTouchMajor(), e1.GetTouchMajor()); |
441 e1.GetTouchMajor()); | 463 Send(CreateGesture(two_finger_tap_details, |
442 provider_->Send(CreateGesture(two_finger_tap_details, | 464 e2.GetId(), |
443 e2.GetId(), | 465 e2.GetToolType(), |
444 e2.GetToolType(), | 466 e2.GetEventTime(), |
445 e2.GetEventTime(), | 467 e1.GetX(), |
446 e1.GetX(), | 468 e1.GetY(), |
447 e1.GetY(), | 469 e1.GetRawX(), |
448 e1.GetRawX(), | 470 e1.GetRawY(), |
449 e1.GetRawY(), | 471 e2.GetPointerCount(), |
450 e2.GetPointerCount(), | 472 GetBoundingBox(e2))); |
451 GetBoundingBox(e2))); | |
452 return true; | 473 return true; |
453 } | 474 } |
454 | 475 |
455 virtual void OnShowPress(const MotionEvent& e) OVERRIDE { | 476 virtual void OnShowPress(const MotionEvent& e) OVERRIDE { |
456 GestureEventDetails show_press_details(ET_GESTURE_SHOW_PRESS, 0, 0); | 477 GestureEventDetails show_press_details(ET_GESTURE_SHOW_PRESS, 0, 0); |
457 provider_->Send(CreateGesture(show_press_details, e)); | 478 Send(CreateGesture(show_press_details, e)); |
458 } | 479 } |
459 | 480 |
460 virtual bool OnSingleTapUp(const MotionEvent& e) OVERRIDE { | 481 virtual bool OnSingleTapUp(const MotionEvent& e) OVERRIDE { |
461 // This is a hack to address the issue where user hovers | 482 // This is a hack to address the issue where user hovers |
462 // over a link for longer than double_tap_timeout_, then | 483 // over a link for longer than double_tap_timeout_, then |
463 // OnSingleTapConfirmed() is not triggered. But we still | 484 // OnSingleTapConfirmed() is not triggered. But we still |
464 // want to trigger the tap event at UP. So we override | 485 // want to trigger the tap event at UP. So we override |
465 // OnSingleTapUp() in this case. This assumes singleTapUp | 486 // OnSingleTapUp() in this case. This assumes singleTapUp |
466 // gets always called before singleTapConfirmed. | 487 // gets always called before singleTapConfirmed. |
467 if (!ignore_single_tap_) { | 488 if (!ignore_single_tap_) { |
468 if (e.GetEventTime() - current_down_time_ > double_tap_timeout_) { | 489 if (e.GetEventTime() - current_down_time_ > |
490 config_.gesture_detector_config.double_tap_timeout) { | |
469 return OnSingleTapConfirmed(e); | 491 return OnSingleTapConfirmed(e); |
470 } else if (!IsDoubleTapEnabled() || disable_click_delay_) { | 492 } else if (!IsDoubleTapEnabled() || config_.disable_click_delay) { |
471 // If double-tap has been disabled, there is no need to wait | 493 // If double-tap has been disabled, there is no need to wait |
472 // for the double-tap timeout. | 494 // for the double-tap timeout. |
473 return OnSingleTapConfirmed(e); | 495 return OnSingleTapConfirmed(e); |
474 } else { | 496 } else { |
475 // Notify Blink about this tapUp event anyway, when none of the above | 497 // Notify Blink about this tapUp event anyway, when none of the above |
476 // conditions applied. | 498 // conditions applied. |
477 provider_->Send(CreateGesture( | 499 Send(CreateTapGesture(ET_GESTURE_TAP_UNCONFIRMED, e)); |
478 CreateTapGestureDetails(ET_GESTURE_TAP_UNCONFIRMED), e)); | |
479 } | 500 } |
480 } | 501 } |
481 | 502 |
482 return provider_->SendLongTapIfNecessary(e); | 503 if (e.GetAction() == MotionEvent::ACTION_UP && |
504 !current_longpress_time_.is_null() && | |
505 !IsScaleGestureDetectionInProgress()) { | |
506 GestureEventDetails long_tap_details(ET_GESTURE_LONG_TAP, 0, 0); | |
507 Send(CreateGesture(long_tap_details, e)); | |
508 return true; | |
509 } | |
510 | |
511 return false; | |
483 } | 512 } |
484 | 513 |
485 // GestureDetector::DoubleTapListener implementation. | 514 // GestureDetector::DoubleTapListener implementation. |
486 virtual bool OnSingleTapConfirmed(const MotionEvent& e) OVERRIDE { | 515 virtual bool OnSingleTapConfirmed(const MotionEvent& e) OVERRIDE { |
487 // Long taps in the edges of the screen have their events delayed by | 516 // 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 | 517 // ContentViewHolder for tab swipe operations. As a consequence of the delay |
489 // this method might be called after receiving the up event. | 518 // this method might be called after receiving the up event. |
490 // These corner cases should be ignored. | 519 // These corner cases should be ignored. |
491 if (ignore_single_tap_) | 520 if (ignore_single_tap_) |
492 return true; | 521 return true; |
493 | 522 |
494 ignore_single_tap_ = true; | 523 ignore_single_tap_ = true; |
495 | 524 |
496 provider_->Send(CreateGesture(CreateTapGestureDetails(ET_GESTURE_TAP), e)); | 525 Send(CreateTapGesture(ET_GESTURE_TAP, e)); |
497 return true; | 526 return true; |
498 } | 527 } |
499 | 528 |
500 virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE { return false; } | 529 virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE { |
530 return scale_gesture_detector_.OnDoubleTap(e); | |
531 } | |
501 | 532 |
502 virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE { | 533 virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE { |
503 switch (e.GetAction()) { | 534 switch (e.GetAction()) { |
504 case MotionEvent::ACTION_DOWN: | 535 case MotionEvent::ACTION_DOWN: |
505 gesture_detector_.set_longpress_enabled(false); | 536 gesture_detector_.set_longpress_enabled(false); |
506 break; | 537 break; |
507 | 538 |
508 case MotionEvent::ACTION_UP: | 539 case MotionEvent::ACTION_UP: |
509 if (!provider_->IsPinchInProgress() && | 540 if (!IsPinchInProgress() && !IsScrollInProgress()) { |
510 !provider_->IsScrollInProgress()) { | 541 Send(CreateTapGesture(ET_GESTURE_DOUBLE_TAP, e)); |
511 provider_->Send( | |
512 CreateGesture(CreateTapGestureDetails(ET_GESTURE_DOUBLE_TAP), e)); | |
513 return true; | 542 return true; |
514 } | 543 } |
515 break; | 544 break; |
545 | |
516 default: | 546 default: |
517 break; | 547 break; |
518 } | 548 } |
519 return false; | 549 return false; |
520 } | 550 } |
521 | 551 |
522 virtual void OnLongPress(const MotionEvent& e) OVERRIDE { | 552 virtual void OnLongPress(const MotionEvent& e) OVERRIDE { |
523 DCHECK(!IsDoubleTapInProgress()); | 553 DCHECK(!IsDoubleTapInProgress()); |
524 SetIgnoreSingleTap(true); | 554 SetIgnoreSingleTap(true); |
525 | |
526 GestureEventDetails long_press_details(ET_GESTURE_LONG_PRESS, 0, 0); | 555 GestureEventDetails long_press_details(ET_GESTURE_LONG_PRESS, 0, 0); |
527 provider_->Send(CreateGesture(long_press_details, e)); | 556 Send(CreateGesture(long_press_details, e)); |
528 } | 557 } |
529 | 558 |
530 void SetDoubleTapEnabled(bool enabled) { | 559 void SetDoubleTapEnabled(bool enabled) { |
531 DCHECK(!IsDoubleTapInProgress()); | 560 DCHECK(!IsDoubleTapInProgress()); |
532 gesture_detector_.SetDoubleTapListener(enabled ? this : NULL); | 561 gesture_detector_.SetDoubleTapListener(enabled ? this : NULL); |
533 } | 562 } |
534 | 563 |
535 bool IsDoubleTapInProgress() const { | 564 void SetMultiTouchZoomEnabled(bool enabled) { |
536 return gesture_detector_.is_double_tapping(); | 565 // Note that returning false from OnScaleBegin / OnScale makes the |
566 // gesture detector not to emit further scaling notifications | |
tdresser
2014/08/22 18:19:04
Might as well reword this comment while you're her
jdduke (slow)
2014/08/22 20:33:09
Ah, yeah this can be cleaned up. I think we still
| |
567 // related to this gesture. Thus, if detector events are enabled in | |
568 // the middle of the gesture, we don't need to do anything. | |
569 ignore_multitouch_zoom_events_ = !enabled; | |
537 } | 570 } |
538 | 571 |
572 bool IsDoubleTapInProgress() const { | |
573 return gesture_detector_.is_double_tapping() || | |
574 (IsScaleGestureDetectionInProgress() && InDoubleTapMode()); | |
575 } | |
576 | |
577 bool IsScrollInProgress() const { return scroll_event_sent_; } | |
578 | |
579 bool IsPinchInProgress() const { return pinch_event_sent_; } | |
580 | |
539 private: | 581 private: |
540 void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; } | 582 bool IsScaleGestureDetectionInProgress() const { |
583 return scale_gesture_detector_.IsInProgress(); | |
584 } | |
585 | |
586 bool InDoubleTapMode() const { | |
587 return scale_gesture_detector_.InDoubleTapMode(); | |
588 } | |
541 | 589 |
542 bool IsDoubleTapEnabled() const { | 590 bool IsDoubleTapEnabled() const { |
543 return gesture_detector_.has_doubletap_listener(); | 591 return gesture_detector_.has_doubletap_listener(); |
544 } | 592 } |
545 | 593 |
594 void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; } | |
595 | |
596 const GestureProvider::Config config_; | |
597 GestureProviderClient* const client_; | |
598 | |
546 GestureDetector gesture_detector_; | 599 GestureDetector gesture_detector_; |
600 ScaleGestureDetector scale_gesture_detector_; | |
547 SnapScrollController snap_scroll_controller_; | 601 SnapScrollController snap_scroll_controller_; |
548 | 602 |
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_; | 603 base::TimeTicks current_down_time_; |
560 | 604 |
605 // Keeps track of the current GESTURE_LONG_PRESS event. If a context menu is | |
606 // opened after a GESTURE_LONG_PRESS, this is used to insert a | |
607 // GESTURE_TAP_CANCEL for removing any ::active styling. | |
608 base::TimeTicks current_longpress_time_; | |
609 | |
610 // Completely silence multi-touch (pinch) scaling events. Used in WebView when | |
611 // zoom support is turned off. | |
612 bool ignore_multitouch_zoom_events_; | |
613 | |
561 // TODO(klobag): This is to avoid a bug in GestureDetector. With multi-touch, | 614 // 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, | 615 // always_in_tap_region_ is not reset. So when the last finger is up, |
563 // OnSingleTapUp() will be mistakenly fired. | 616 // |OnSingleTapUp()| will be mistakenly fired. |
564 bool ignore_single_tap_; | 617 bool ignore_single_tap_; |
565 | 618 |
566 // Used to remove the touch slop from the initial scroll event in a scroll | 619 // Tracks whether {PINCH|SCROLL|_BEGIN events have been forwadred for the |
tdresser
2014/08/22 18:19:04
forwadred -> forwarded
{PINCH|SCROLL|_BEGIN -> ...
jdduke (slow)
2014/08/22 20:33:09
Done.
| |
567 // gesture. | 620 // current touch sequence. |
568 bool seen_first_scroll_event_; | 621 bool pinch_event_sent_; |
622 bool scroll_event_sent_; | |
569 | 623 |
570 DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl); | 624 DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl); |
571 }; | 625 }; |
572 | 626 |
573 // GestureProvider | 627 // GestureProvider |
574 | 628 |
575 GestureProvider::GestureProvider(const Config& config, | 629 GestureProvider::GestureProvider(const Config& config, |
576 GestureProviderClient* client) | 630 GestureProviderClient* client) |
577 : client_(client), | 631 : 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), | 632 double_tap_support_for_platform_(true), |
582 gesture_begin_end_types_enabled_(config.gesture_begin_end_types_enabled), | 633 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); | 634 DCHECK(client); |
586 DCHECK(!min_gesture_bounds_length_ || !max_gesture_bounds_length_ || | 635 DCHECK(!config.min_gesture_bounds_length || |
587 min_gesture_bounds_length_ <= max_gesture_bounds_length_); | 636 !config.max_gesture_bounds_length || |
588 InitGestureDetectors(config); | 637 config.min_gesture_bounds_length <= config.max_gesture_bounds_length); |
638 TRACE_EVENT0("input", "GestureProvider::InitGestureDetectors"); | |
639 gesture_listener_.reset(new GestureListenerImpl(config, client)); | |
640 UpdateDoubleTapDetectionSupport(); | |
589 } | 641 } |
590 | 642 |
591 GestureProvider::~GestureProvider() {} | 643 GestureProvider::~GestureProvider() { |
644 } | |
592 | 645 |
593 bool GestureProvider::OnTouchEvent(const MotionEvent& event) { | 646 bool GestureProvider::OnTouchEvent(const MotionEvent& event) { |
594 TRACE_EVENT1("input", "GestureProvider::OnTouchEvent", | 647 TRACE_EVENT1("input", |
595 "action", GetMotionEventActionName(event.GetAction())); | 648 "GestureProvider::OnTouchEvent", |
649 "action", | |
650 GetMotionEventActionName(event.GetAction())); | |
596 | 651 |
597 DCHECK_NE(0u, event.GetPointerCount()); | 652 DCHECK_NE(0u, event.GetPointerCount()); |
598 | 653 |
599 if (!CanHandle(event)) | 654 if (!CanHandle(event)) |
600 return false; | 655 return false; |
601 | 656 |
602 const bool in_scale_gesture = | |
603 scale_gesture_listener_->IsScaleGestureDetectionInProgress(); | |
604 | |
605 OnTouchEventHandlingBegin(event); | 657 OnTouchEventHandlingBegin(event); |
606 gesture_listener_->OnTouchEvent(event, in_scale_gesture); | 658 gesture_listener_->OnTouchEvent(event); |
607 scale_gesture_listener_->OnTouchEvent(event); | |
608 OnTouchEventHandlingEnd(event); | 659 OnTouchEventHandlingEnd(event); |
609 return true; | 660 return true; |
610 } | 661 } |
611 | 662 |
612 void GestureProvider::SetMultiTouchZoomSupportEnabled(bool enabled) { | 663 void GestureProvider::SetMultiTouchZoomSupportEnabled(bool enabled) { |
613 scale_gesture_listener_->SetMultiTouchEnabled(enabled); | 664 gesture_listener_->SetMultiTouchZoomEnabled(enabled); |
614 } | 665 } |
615 | 666 |
616 void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) { | 667 void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) { |
617 if (double_tap_support_for_platform_ == enabled) | 668 if (double_tap_support_for_platform_ == enabled) |
618 return; | 669 return; |
619 double_tap_support_for_platform_ = enabled; | 670 double_tap_support_for_platform_ = enabled; |
620 UpdateDoubleTapDetectionSupport(); | 671 UpdateDoubleTapDetectionSupport(); |
621 } | 672 } |
622 | 673 |
623 void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) { | 674 void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) { |
624 if (double_tap_support_for_page_ == enabled) | 675 if (double_tap_support_for_page_ == enabled) |
625 return; | 676 return; |
626 double_tap_support_for_page_ = enabled; | 677 double_tap_support_for_page_ = enabled; |
627 UpdateDoubleTapDetectionSupport(); | 678 UpdateDoubleTapDetectionSupport(); |
628 } | 679 } |
629 | 680 |
630 bool GestureProvider::IsScrollInProgress() const { | 681 bool GestureProvider::IsScrollInProgress() const { |
631 // TODO(wangxianzhu): Also return true when fling is active once the UI knows | 682 return gesture_listener_->IsScrollInProgress(); |
632 // exactly when the fling ends. | |
633 return touch_scroll_in_progress_; | |
634 } | 683 } |
635 | 684 |
636 bool GestureProvider::IsPinchInProgress() const { return pinch_in_progress_; } | 685 bool GestureProvider::IsPinchInProgress() const { |
686 return gesture_listener_->IsPinchInProgress(); | |
687 } | |
637 | 688 |
638 bool GestureProvider::IsDoubleTapInProgress() const { | 689 bool GestureProvider::IsDoubleTapInProgress() const { |
639 return gesture_listener_->IsDoubleTapInProgress() || | 690 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 } | 691 } |
656 | 692 |
657 bool GestureProvider::CanHandle(const MotionEvent& event) const { | 693 bool GestureProvider::CanHandle(const MotionEvent& event) const { |
658 // Aura requires one cancel event per touch point, whereas Android requires | 694 // 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 | 695 // one cancel event per touch sequence. Thus we need to allow extra cancel |
660 // events. | 696 // events. |
661 return event.GetAction() == MotionEvent::ACTION_DOWN || current_down_event_ || | 697 return current_down_event_ || event.GetAction() == MotionEvent::ACTION_DOWN || |
662 event.GetAction() == MotionEvent::ACTION_CANCEL; | 698 event.GetAction() == MotionEvent::ACTION_CANCEL; |
663 } | 699 } |
664 | 700 |
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) { | 701 void GestureProvider::OnTouchEventHandlingBegin(const MotionEvent& event) { |
768 switch (event.GetAction()) { | 702 switch (event.GetAction()) { |
769 case MotionEvent::ACTION_DOWN: | 703 case MotionEvent::ACTION_DOWN: |
770 current_down_event_ = event.Clone(); | 704 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_) | 705 if (gesture_begin_end_types_enabled_) |
775 Send(CreateGesture(ET_GESTURE_BEGIN, event)); | 706 gesture_listener_->Send(CreateGesture(ET_GESTURE_BEGIN, event)); |
776 break; | 707 break; |
777 case MotionEvent::ACTION_POINTER_DOWN: | 708 case MotionEvent::ACTION_POINTER_DOWN: |
778 if (gesture_begin_end_types_enabled_) { | 709 if (gesture_begin_end_types_enabled_) { |
779 const int action_index = event.GetActionIndex(); | 710 const int action_index = event.GetActionIndex(); |
780 Send(CreateGesture(ET_GESTURE_BEGIN, | 711 gesture_listener_->Send(CreateGesture(ET_GESTURE_BEGIN, |
781 event.GetId(), | 712 event.GetId(), |
782 event.GetToolType(), | 713 event.GetToolType(), |
783 event.GetEventTime(), | 714 event.GetEventTime(), |
784 event.GetX(action_index), | 715 event.GetX(action_index), |
785 event.GetY(action_index), | 716 event.GetY(action_index), |
786 event.GetRawX(action_index), | 717 event.GetRawX(action_index), |
787 event.GetRawY(action_index), | 718 event.GetRawY(action_index), |
788 event.GetPointerCount(), | 719 event.GetPointerCount(), |
789 GetBoundingBox(event))); | 720 GetBoundingBox(event))); |
790 } | 721 } |
791 break; | 722 break; |
792 case MotionEvent::ACTION_POINTER_UP: | 723 case MotionEvent::ACTION_POINTER_UP: |
793 case MotionEvent::ACTION_UP: | 724 case MotionEvent::ACTION_UP: |
794 case MotionEvent::ACTION_CANCEL: | 725 case MotionEvent::ACTION_CANCEL: |
795 case MotionEvent::ACTION_MOVE: | 726 case MotionEvent::ACTION_MOVE: |
796 break; | 727 break; |
797 } | 728 } |
798 } | 729 } |
799 | 730 |
800 void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) { | 731 void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) { |
801 switch (event.GetAction()) { | 732 switch (event.GetAction()) { |
802 case MotionEvent::ACTION_UP: | 733 case MotionEvent::ACTION_UP: |
803 case MotionEvent::ACTION_CANCEL: { | 734 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_) | 735 if (gesture_begin_end_types_enabled_) |
809 Send(CreateGesture(ET_GESTURE_END, event)); | 736 gesture_listener_->Send(CreateGesture(ET_GESTURE_END, event)); |
810 | 737 |
811 current_down_event_.reset(); | 738 current_down_event_.reset(); |
812 | 739 |
813 UpdateDoubleTapDetectionSupport(); | 740 UpdateDoubleTapDetectionSupport(); |
814 break; | 741 break; |
815 } | 742 } |
816 case MotionEvent::ACTION_POINTER_UP: | 743 case MotionEvent::ACTION_POINTER_UP: |
817 if (gesture_begin_end_types_enabled_) | 744 if (gesture_begin_end_types_enabled_) |
818 Send(CreateGesture(ET_GESTURE_END, event)); | 745 gesture_listener_->Send(CreateGesture(ET_GESTURE_END, event)); |
819 break; | 746 break; |
820 case MotionEvent::ACTION_DOWN: | 747 case MotionEvent::ACTION_DOWN: |
821 case MotionEvent::ACTION_POINTER_DOWN: | 748 case MotionEvent::ACTION_POINTER_DOWN: |
822 case MotionEvent::ACTION_MOVE: | 749 case MotionEvent::ACTION_MOVE: |
823 break; | 750 break; |
824 } | 751 } |
825 } | 752 } |
826 | 753 |
827 void GestureProvider::UpdateDoubleTapDetectionSupport() { | 754 void GestureProvider::UpdateDoubleTapDetectionSupport() { |
828 // The GestureDetector requires that any provided DoubleTapListener remain | 755 // The GestureDetector requires that any provided DoubleTapListener remain |
829 // attached to it for the duration of a touch sequence. Defer any potential | 756 // attached to it for the duration of a touch sequence. Defer any potential |
830 // null'ing of the listener until the sequence has ended. | 757 // null'ing of the listener until the sequence has ended. |
831 if (current_down_event_) | 758 if (current_down_event_) |
832 return; | 759 return; |
833 | 760 |
834 const bool double_tap_enabled = double_tap_support_for_page_ && | 761 const bool double_tap_enabled = |
835 double_tap_support_for_platform_; | 762 double_tap_support_for_page_ && double_tap_support_for_platform_; |
836 gesture_listener_->SetDoubleTapEnabled(double_tap_enabled); | 763 gesture_listener_->SetDoubleTapEnabled(double_tap_enabled); |
837 scale_gesture_listener_->SetDoubleTapEnabled(double_tap_enabled); | |
838 } | 764 } |
839 | 765 |
840 } // namespace ui | 766 } // namespace ui |
OLD | NEW |