OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/input/touch_event_queue.h" | 5 #include "content/browser/renderer_host/input/touch_event_queue.h" |
6 | 6 |
7 #include "base/auto_reset.h" | 7 #include "base/auto_reset.h" |
8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "content/browser/renderer_host/input/timeout_monitor.h" | 10 #include "content/browser/renderer_host/input/timeout_monitor.h" |
(...skipping 10 matching lines...) Expand all Loading... |
21 | 21 |
22 // Time interval at which touchmove events will be forwarded to the client while | 22 // Time interval at which touchmove events will be forwarded to the client while |
23 // scrolling is active and possible. | 23 // scrolling is active and possible. |
24 const double kAsyncTouchMoveIntervalSec = .2; | 24 const double kAsyncTouchMoveIntervalSec = .2; |
25 | 25 |
26 // A slop region just larger than that used by many web applications. When | 26 // A slop region just larger than that used by many web applications. When |
27 // touchmove's are being sent asynchronously, movement outside this region will | 27 // touchmove's are being sent asynchronously, movement outside this region will |
28 // trigger an immediate async touchmove to cancel potential tap-related logic. | 28 // trigger an immediate async touchmove to cancel potential tap-related logic. |
29 const double kApplicationSlopRegionLengthDipsSqared = 15. * 15.; | 29 const double kApplicationSlopRegionLengthDipsSqared = 15. * 15.; |
30 | 30 |
31 // Using a small epsilon when comparing slop distances allows pixel perfect | 31 // A sanity check on touches received to ensure that touch movement outside |
32 // slop determination when using fractional DIP coordinates (assuming the slop | 32 // the platform slop region will cause scrolling, as indicated by the event's |
33 // region and DPI scale are reasonably proportioned). | 33 // |causesScrollingIfUncanceled| bit. |
34 const float kSlopEpsilon = .05f; | 34 const double kMaxConceivablePlatformSlopRegionLengthDipsSquared = 60. * 60.; |
35 | 35 |
36 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( | 36 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( |
37 const TouchEventWithLatencyInfo& event_to_cancel) { | 37 const TouchEventWithLatencyInfo& event_to_cancel) { |
38 TouchEventWithLatencyInfo event = event_to_cancel; | 38 TouchEventWithLatencyInfo event = event_to_cancel; |
39 WebTouchEventTraits::ResetTypeAndTouchStates( | 39 WebTouchEventTraits::ResetTypeAndTouchStates( |
40 WebInputEvent::TouchCancel, | 40 WebInputEvent::TouchCancel, |
41 // TODO(rbyers): Shouldn't we use a fresh timestamp? | 41 // TODO(rbyers): Shouldn't we use a fresh timestamp? |
42 event.event.timeStampSeconds, | 42 event.event.timeStampSeconds, |
43 &event.event); | 43 &event.event); |
44 return event; | 44 return event; |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 // The event for which the ack timeout is triggered. | 208 // The event for which the ack timeout is triggered. |
209 TouchEventWithLatencyInfo timeout_event_; | 209 TouchEventWithLatencyInfo timeout_event_; |
210 | 210 |
211 // Provides timeout-based callback behavior. | 211 // Provides timeout-based callback behavior. |
212 TimeoutMonitor timeout_monitor_; | 212 TimeoutMonitor timeout_monitor_; |
213 | 213 |
214 bool enabled_; | 214 bool enabled_; |
215 bool enabled_for_current_sequence_; | 215 bool enabled_for_current_sequence_; |
216 }; | 216 }; |
217 | 217 |
218 // Provides touchmove slop suppression for a single touch that remains within | 218 // Provides touchmove slop suppression for a touch sequence until a |
219 // a given slop region, unless the touchstart is preventDefault'ed. | 219 // (unprevented) touch will trigger immediate scrolling. |
220 // TODO(jdduke): Use a flag bundled with each TouchEvent declaring whether it | |
221 // has exceeded the slop region, removing duplicated slop determination logic. | |
222 class TouchEventQueue::TouchMoveSlopSuppressor { | 220 class TouchEventQueue::TouchMoveSlopSuppressor { |
223 public: | 221 public: |
224 TouchMoveSlopSuppressor(double slop_suppression_length_dips) | 222 TouchMoveSlopSuppressor() : suppressing_touchmoves_(false) {} |
225 : slop_suppression_length_dips_squared_(0), | |
226 suppressing_touchmoves_(false) { | |
227 if (slop_suppression_length_dips) { | |
228 slop_suppression_length_dips += kSlopEpsilon; | |
229 slop_suppression_length_dips_squared_ = | |
230 slop_suppression_length_dips * slop_suppression_length_dips; | |
231 } | |
232 } | |
233 | 223 |
234 bool FilterEvent(const WebTouchEvent& event) { | 224 bool FilterEvent(const WebTouchEvent& event) { |
235 if (WebTouchEventTraits::IsTouchSequenceStart(event)) { | 225 if (WebTouchEventTraits::IsTouchSequenceStart(event)) { |
236 touch_sequence_start_position_ = | 226 suppressing_touchmoves_ = true; |
237 gfx::PointF(event.touches[0].position); | 227 touch_start_location_ = gfx::PointF(event.touches[0].position); |
238 suppressing_touchmoves_ = slop_suppression_length_dips_squared_ != 0; | |
239 } | 228 } |
240 | 229 |
241 if (event.type == WebInputEvent::TouchEnd || | 230 if (event.type == WebInputEvent::TouchEnd || |
242 event.type == WebInputEvent::TouchCancel) | 231 event.type == WebInputEvent::TouchCancel) |
243 suppressing_touchmoves_ = false; | 232 suppressing_touchmoves_ = false; |
244 | 233 |
245 if (event.type != WebInputEvent::TouchMove) | 234 if (event.type != WebInputEvent::TouchMove) |
246 return false; | 235 return false; |
247 | 236 |
248 if (suppressing_touchmoves_) { | 237 if (suppressing_touchmoves_) { |
249 // Movement with a secondary pointer should terminate suppression. | |
250 if (event.touchesLength > 1) { | 238 if (event.touchesLength > 1) { |
251 suppressing_touchmoves_ = false; | 239 suppressing_touchmoves_ = false; |
252 } else if (event.touchesLength == 1) { | 240 } else if (event.causesScrollingIfUncanceled) { |
253 // Movement outside of the slop region should terminate suppression. | 241 suppressing_touchmoves_ = false; |
254 gfx::PointF position(event.touches[0].position); | 242 } else { |
255 if ((position - touch_sequence_start_position_).LengthSquared() > | 243 // No sane slop region should be larger than 60 DIPs. |
256 slop_suppression_length_dips_squared_) | 244 DCHECK_LT((gfx::PointF(event.touches[0].position) - |
257 suppressing_touchmoves_ = false; | 245 touch_start_location_).LengthSquared(), |
| 246 kMaxConceivablePlatformSlopRegionLengthDipsSquared); |
258 } | 247 } |
259 } | 248 } |
| 249 |
260 return suppressing_touchmoves_; | 250 return suppressing_touchmoves_; |
261 } | 251 } |
262 | 252 |
263 void ConfirmTouchEvent(InputEventAckState ack_result) { | 253 void ConfirmTouchEvent(InputEventAckState ack_result) { |
264 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) | 254 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) |
265 suppressing_touchmoves_ = false; | 255 suppressing_touchmoves_ = false; |
266 } | 256 } |
267 | 257 |
268 bool suppressing_touchmoves() const { return suppressing_touchmoves_; } | 258 bool suppressing_touchmoves() const { return suppressing_touchmoves_; } |
269 | 259 |
270 private: | 260 private: |
271 double slop_suppression_length_dips_squared_; | |
272 gfx::PointF touch_sequence_start_position_; | |
273 bool suppressing_touchmoves_; | 261 bool suppressing_touchmoves_; |
274 | 262 |
| 263 // Sanity check that the upstream touch provider is properly reporting whether |
| 264 // the touch sequence will cause scrolling. |
| 265 gfx::PointF touch_start_location_; |
| 266 |
275 DISALLOW_COPY_AND_ASSIGN(TouchMoveSlopSuppressor); | 267 DISALLOW_COPY_AND_ASSIGN(TouchMoveSlopSuppressor); |
276 }; | 268 }; |
277 | 269 |
278 // This class represents a single coalesced touch event. However, it also keeps | 270 // This class represents a single coalesced touch event. However, it also keeps |
279 // track of all the original touch-events that were coalesced into a single | 271 // track of all the original touch-events that were coalesced into a single |
280 // event. The coalesced event is forwarded to the renderer, while the original | 272 // event. The coalesced event is forwarded to the renderer, while the original |
281 // touch-events are sent to the Client (on ACK for the coalesced event) so that | 273 // touch-events are sent to the Client (on ACK for the coalesced event) so that |
282 // the Client receives the event with their original timestamp. | 274 // the Client receives the event with their original timestamp. |
283 class CoalescedWebTouchEvent { | 275 class CoalescedWebTouchEvent { |
284 public: | 276 public: |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 // Note that this will be empty if no coalescing has occurred. | 347 // Note that this will be empty if no coalescing has occurred. |
356 typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList; | 348 typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList; |
357 WebTouchEventWithLatencyList uncoaleseced_events_to_ack_; | 349 WebTouchEventWithLatencyList uncoaleseced_events_to_ack_; |
358 | 350 |
359 bool suppress_client_ack_; | 351 bool suppress_client_ack_; |
360 | 352 |
361 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); | 353 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); |
362 }; | 354 }; |
363 | 355 |
364 TouchEventQueue::Config::Config() | 356 TouchEventQueue::Config::Config() |
365 : touchmove_slop_suppression_length_dips(0), | 357 : touch_scrolling_mode(TOUCH_SCROLLING_MODE_DEFAULT), |
366 touch_scrolling_mode(TOUCH_SCROLLING_MODE_DEFAULT), | |
367 touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(200)), | 358 touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(200)), |
368 touch_ack_timeout_supported(false) { | 359 touch_ack_timeout_supported(false) { |
369 } | 360 } |
370 | 361 |
371 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client, | 362 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client, |
372 const Config& config) | 363 const Config& config) |
373 : client_(client), | 364 : client_(client), |
374 dispatching_touch_ack_(NULL), | 365 dispatching_touch_ack_(NULL), |
375 dispatching_touch_(false), | 366 dispatching_touch_(false), |
376 has_handlers_(true), | 367 has_handlers_(true), |
377 drop_remaining_touches_in_sequence_(false), | 368 drop_remaining_touches_in_sequence_(false), |
378 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor( | 369 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor), |
379 config.touchmove_slop_suppression_length_dips)), | |
380 send_touch_events_async_(false), | 370 send_touch_events_async_(false), |
381 needs_async_touchmove_for_outer_slop_region_(false), | 371 needs_async_touchmove_for_outer_slop_region_(false), |
382 last_sent_touch_timestamp_sec_(0), | 372 last_sent_touch_timestamp_sec_(0), |
383 touch_scrolling_mode_(config.touch_scrolling_mode) { | 373 touch_scrolling_mode_(config.touch_scrolling_mode) { |
384 DCHECK(client); | 374 DCHECK(client); |
385 if (config.touch_ack_timeout_supported) { | 375 if (config.touch_ack_timeout_supported) { |
386 timeout_handler_.reset( | 376 timeout_handler_.reset( |
387 new TouchTimeoutHandler(this, config.touch_ack_timeout_delay)); | 377 new TouchTimeoutHandler(this, config.touch_ack_timeout_delay)); |
388 } | 378 } |
389 } | 379 } |
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
777 if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) | 767 if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) |
778 touch_consumer_states_.mark_bit(point.id); | 768 touch_consumer_states_.mark_bit(point.id); |
779 else | 769 else |
780 touch_consumer_states_.clear_bit(point.id); | 770 touch_consumer_states_.clear_bit(point.id); |
781 } | 771 } |
782 } | 772 } |
783 } | 773 } |
784 } | 774 } |
785 | 775 |
786 } // namespace content | 776 } // namespace content |
OLD | NEW |