Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: trunk/src/content/browser/renderer_host/input/touch_event_queue.cc

Issue 252023005: Revert 266470 "Implement async touchmove dispatch during scroll" (Closed) Base URL: svn://svn.chromium.org/chrome/
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/command_line.h" 8 #include "base/command_line.h"
9 #include "base/debug/trace_event.h" 9 #include "base/debug/trace_event.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
11 #include "content/browser/renderer_host/input/timeout_monitor.h" 11 #include "content/browser/renderer_host/input/timeout_monitor.h"
12 #include "content/common/input/web_touch_event_traits.h" 12 #include "content/common/input/web_touch_event_traits.h"
13 #include "content/public/common/content_switches.h" 13 #include "content/public/common/content_switches.h"
14 #include "ui/gfx/geometry/point_f.h" 14 #include "ui/gfx/geometry/point_f.h"
15 15
16 using blink::WebInputEvent; 16 using blink::WebInputEvent;
17 using blink::WebTouchEvent; 17 using blink::WebTouchEvent;
18 using blink::WebTouchPoint; 18 using blink::WebTouchPoint;
19 using ui::LatencyInfo; 19 using ui::LatencyInfo;
20 20
21 namespace content { 21 namespace content {
22 namespace { 22 namespace {
23 23
24 // Time interval at which touchmove events will be forwarded to the client while
25 // scrolling is active and possible.
26 const double kAsyncTouchMoveIntervalSec = .2;
27
28 // A slop region just larger than that used by many web applications. When
29 // touchmove's are being sent asynchronously, movement outside this region will
30 // trigger an immediate async touchmove to cancel potential tap-related logic.
31 const double kApplicationSlopRegionLengthDipsSqared = 15. * 15.;
32
33 // Using a small epsilon when comparing slop distances allows pixel perfect 24 // Using a small epsilon when comparing slop distances allows pixel perfect
34 // slop determination when using fractional DIP coordinates (assuming the slop 25 // slop determination when using fractional DIP coordinates (assuming the slop
35 // region and DPI scale are reasonably proportioned). 26 // region and DPI scale are reasonably proportioned).
36 const float kSlopEpsilon = .05f; 27 const float kSlopEpsilon = .05f;
37 28
38 typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList; 29 typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList;
39 30
40 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( 31 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent(
41 const TouchEventWithLatencyInfo& event_to_cancel) { 32 const TouchEventWithLatencyInfo& event_to_cancel) {
42 TouchEventWithLatencyInfo event = event_to_cancel; 33 TouchEventWithLatencyInfo event = event_to_cancel;
43 WebTouchEventTraits::ResetTypeAndTouchStates( 34 WebTouchEventTraits::ResetTypeAndTouchStates(
44 WebInputEvent::TouchCancel, 35 WebInputEvent::TouchCancel,
45 // TODO(rbyers): Shouldn't we use a fresh timestamp? 36 // TODO(rbyers): Shouldn't we use a fresh timestamp?
46 event.event.timeStampSeconds, 37 event.event.timeStampSeconds,
47 &event.event); 38 &event.event);
48 return event; 39 return event;
49 } 40 }
50 41
51 bool ShouldTouchTriggerTimeout(const WebTouchEvent& event) { 42 bool ShouldTouchTypeTriggerTimeout(WebInputEvent::Type type) {
52 return (event.type == WebInputEvent::TouchStart || 43 return type == WebInputEvent::TouchStart ||
53 event.type == WebInputEvent::TouchMove) && 44 type == WebInputEvent::TouchMove;
54 !WebInputEventTraits::IgnoresAckDisposition(event);
55 }
56
57 bool OutsideApplicationSlopRegion(const WebTouchEvent& event,
58 const gfx::PointF& anchor) {
59 return (gfx::PointF(event.touches[0].position) - anchor).LengthSquared() >
60 kApplicationSlopRegionLengthDipsSqared;
61 } 45 }
62 46
63 } // namespace 47 } // namespace
64 48
65 49
66 // Cancels a touch sequence if a touchstart or touchmove ack response is 50 // Cancels a touch sequence if a touchstart or touchmove ack response is
67 // sufficiently delayed. 51 // sufficiently delayed.
68 class TouchEventQueue::TouchTimeoutHandler { 52 class TouchEventQueue::TouchTimeoutHandler {
69 public: 53 public:
70 TouchTimeoutHandler(TouchEventQueue* touch_queue, 54 TouchTimeoutHandler(TouchEventQueue* touch_queue,
71 base::TimeDelta timeout_delay) 55 base::TimeDelta timeout_delay)
72 : touch_queue_(touch_queue), 56 : touch_queue_(touch_queue),
73 timeout_delay_(timeout_delay), 57 timeout_delay_(timeout_delay),
74 pending_ack_state_(PENDING_ACK_NONE), 58 pending_ack_state_(PENDING_ACK_NONE),
75 timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut, 59 timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut,
76 base::Unretained(this))) {} 60 base::Unretained(this))) {}
77 61
78 ~TouchTimeoutHandler() {} 62 ~TouchTimeoutHandler() {}
79 63
80 void Start(const TouchEventWithLatencyInfo& event) { 64 void Start(const TouchEventWithLatencyInfo& event) {
81 DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE); 65 DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE);
82 DCHECK(ShouldTouchTriggerTimeout(event.event)); 66 DCHECK(ShouldTouchTypeTriggerTimeout(event.event.type));
83 timeout_event_ = event; 67 timeout_event_ = event;
84 timeout_monitor_.Restart(timeout_delay_); 68 timeout_monitor_.Restart(timeout_delay_);
85 } 69 }
86 70
87 bool ConfirmTouchEvent(InputEventAckState ack_result) { 71 bool ConfirmTouchEvent(InputEventAckState ack_result) {
88 switch (pending_ack_state_) { 72 switch (pending_ack_state_) {
89 case PENDING_ACK_NONE: 73 case PENDING_ACK_NONE:
90 timeout_monitor_.Stop(); 74 timeout_monitor_.Stop();
91 return false; 75 return false;
92 case PENDING_ACK_ORIGINAL_EVENT: 76 case PENDING_ACK_ORIGINAL_EVENT:
93 if (AckedTimeoutEventRequiresCancel(ack_result)) { 77 if (AckedTimeoutEventRequiresCancel(ack_result)) {
94 SetPendingAckState(PENDING_ACK_CANCEL_EVENT); 78 SetPendingAckState(PENDING_ACK_CANCEL_EVENT);
95 TouchEventWithLatencyInfo cancel_event = 79 TouchEventWithLatencyInfo cancel_event =
96 ObtainCancelEventForTouchEvent(timeout_event_); 80 ObtainCancelEventForTouchEvent(timeout_event_);
97 touch_queue_->SendTouchEventImmediately(cancel_event); 81 touch_queue_->client_->SendTouchEventImmediately(cancel_event);
98 } else { 82 } else {
99 SetPendingAckState(PENDING_ACK_NONE); 83 SetPendingAckState(PENDING_ACK_NONE);
100 touch_queue_->UpdateTouchAckStates(timeout_event_.event, ack_result); 84 touch_queue_->UpdateTouchAckStates(timeout_event_.event, ack_result);
101 } 85 }
102 return true; 86 return true;
103 case PENDING_ACK_CANCEL_EVENT: 87 case PENDING_ACK_CANCEL_EVENT:
104 SetPendingAckState(PENDING_ACK_NONE); 88 SetPendingAckState(PENDING_ACK_NONE);
105 return true; 89 return true;
106 } 90 }
107 return false; 91 return false;
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 DISALLOW_COPY_AND_ASSIGN(TouchMoveSlopSuppressor); 221 DISALLOW_COPY_AND_ASSIGN(TouchMoveSlopSuppressor);
238 }; 222 };
239 223
240 // This class represents a single coalesced touch event. However, it also keeps 224 // This class represents a single coalesced touch event. However, it also keeps
241 // track of all the original touch-events that were coalesced into a single 225 // track of all the original touch-events that were coalesced into a single
242 // event. The coalesced event is forwarded to the renderer, while the original 226 // event. The coalesced event is forwarded to the renderer, while the original
243 // touch-events are sent to the Client (on ACK for the coalesced event) so that 227 // touch-events are sent to the Client (on ACK for the coalesced event) so that
244 // the Client receives the event with their original timestamp. 228 // the Client receives the event with their original timestamp.
245 class CoalescedWebTouchEvent { 229 class CoalescedWebTouchEvent {
246 public: 230 public:
247 // Events for which |async| is true will not be ack'ed to the client after the 231 CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event,
248 // corresponding ack is received following dispatch. 232 bool ignore_ack)
249 CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event, bool async) 233 : coalesced_event_(event),
250 : coalesced_event_(event) { 234 ignore_ack_(ignore_ack) {
251 if (async) 235 events_.push_back(event);
252 coalesced_event_.event.cancelable = false; 236 TRACE_EVENT_ASYNC_BEGIN0(
253 else 237 "input", "TouchEventQueue::QueueEvent", this);
254 events_to_ack_.push_back(event);
255
256 TRACE_EVENT_ASYNC_BEGIN0("input", "TouchEventQueue::QueueEvent", this);
257 } 238 }
258 239
259 ~CoalescedWebTouchEvent() { 240 ~CoalescedWebTouchEvent() {
260 TRACE_EVENT_ASYNC_END0("input", "TouchEventQueue::QueueEvent", this); 241 TRACE_EVENT_ASYNC_END0(
242 "input", "TouchEventQueue::QueueEvent", this);
261 } 243 }
262 244
263 // Coalesces the event with the existing event if possible. Returns whether 245 // Coalesces the event with the existing event if possible. Returns whether
264 // the event was coalesced. 246 // the event was coalesced.
265 bool CoalesceEventIfPossible( 247 bool CoalesceEventIfPossible(
266 const TouchEventWithLatencyInfo& event_with_latency) { 248 const TouchEventWithLatencyInfo& event_with_latency) {
267 if (!WillDispatchAckToClient()) 249 if (ignore_ack_)
268 return false; 250 return false;
269 251
270 if (!coalesced_event_.CanCoalesceWith(event_with_latency)) 252 if (!coalesced_event_.CanCoalesceWith(event_with_latency))
271 return false; 253 return false;
272 254
273 TRACE_EVENT_INSTANT0( 255 TRACE_EVENT_INSTANT0(
274 "input", "TouchEventQueue::MoveCoalesced", TRACE_EVENT_SCOPE_THREAD); 256 "input", "TouchEventQueue::MoveCoalesced", TRACE_EVENT_SCOPE_THREAD);
275 coalesced_event_.CoalesceWith(event_with_latency); 257 coalesced_event_.CoalesceWith(event_with_latency);
276 events_to_ack_.push_back(event_with_latency); 258 events_.push_back(event_with_latency);
277 return true; 259 return true;
278 } 260 }
279 261
280 void UpdateLatencyInfoForAck(const ui::LatencyInfo& renderer_latency_info) {
281 if (!WillDispatchAckToClient())
282 return;
283
284 for (WebTouchEventWithLatencyList::iterator iter = events_to_ack_.begin(),
285 end = events_to_ack_.end();
286 iter != end;
287 ++iter) {
288 iter->latency.AddNewLatencyFrom(renderer_latency_info);
289 }
290 }
291
292 void DispatchAckToClient(InputEventAckState ack_result,
293 TouchEventQueueClient* client) {
294 DCHECK(client);
295 if (!WillDispatchAckToClient())
296 return;
297
298 for (WebTouchEventWithLatencyList::const_iterator
299 iter = events_to_ack_.begin(),
300 end = events_to_ack_.end();
301 iter != end;
302 ++iter) {
303 client->OnTouchEventAck(*iter, ack_result);
304 }
305 }
306
307 const TouchEventWithLatencyInfo& coalesced_event() const { 262 const TouchEventWithLatencyInfo& coalesced_event() const {
308 return coalesced_event_; 263 return coalesced_event_;
309 } 264 }
310 265
266 WebTouchEventWithLatencyList::iterator begin() {
267 return events_.begin();
268 }
269
270 WebTouchEventWithLatencyList::iterator end() {
271 return events_.end();
272 }
273
274 size_t size() const { return events_.size(); }
275
276 bool ignore_ack() const { return ignore_ack_; }
277
311 private: 278 private:
312 bool WillDispatchAckToClient() const { return !events_to_ack_.empty(); }
313
314 // This is the event that is forwarded to the renderer. 279 // This is the event that is forwarded to the renderer.
315 TouchEventWithLatencyInfo coalesced_event_; 280 TouchEventWithLatencyInfo coalesced_event_;
316 281
317 // This is the list of the original events that were coalesced, each requiring 282 // This is the list of the original events that were coalesced.
318 // future ack dispatch to the client. 283 WebTouchEventWithLatencyList events_;
319 WebTouchEventWithLatencyList events_to_ack_; 284
285 // If |ignore_ack_| is true, don't send this touch event to client
286 // when the event is acked.
287 bool ignore_ack_;
320 288
321 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); 289 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent);
322 }; 290 };
323 291
324 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client, 292 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client,
325 TouchScrollingMode mode, 293 TouchScrollingMode mode,
326 double touchmove_suppression_length_dips) 294 double touchmove_suppression_length_dips)
327 : client_(client), 295 : client_(client),
328 dispatching_touch_ack_(NULL), 296 dispatching_touch_ack_(NULL),
329 dispatching_touch_(false), 297 dispatching_touch_(false),
330 touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT), 298 touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT),
331 ack_timeout_enabled_(false), 299 ack_timeout_enabled_(false),
332 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor( 300 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor(
333 touchmove_suppression_length_dips + kSlopEpsilon)), 301 touchmove_suppression_length_dips + kSlopEpsilon)),
334 send_touch_events_async_(false), 302 absorbing_touch_moves_(false),
335 last_sent_touch_timestamp_sec_(0),
336 touch_scrolling_mode_(mode) { 303 touch_scrolling_mode_(mode) {
337 DCHECK(client); 304 DCHECK(client);
338 } 305 }
339 306
340 TouchEventQueue::~TouchEventQueue() { 307 TouchEventQueue::~TouchEventQueue() {
341 if (!touch_queue_.empty()) 308 if (!touch_queue_.empty())
342 STLDeleteElements(&touch_queue_); 309 STLDeleteElements(&touch_queue_);
343 } 310 }
344 311
345 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { 312 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) {
346 TRACE_EVENT0("input", "TouchEventQueue::QueueEvent"); 313 TRACE_EVENT0("input", "TouchEventQueue::QueueEvent");
347 314
348 // If the queueing of |event| was triggered by an ack dispatch, defer 315 // If the queueing of |event| was triggered by an ack dispatch, defer
349 // processing the event until the dispatch has finished. 316 // processing the event until the dispatch has finished.
350 if (touch_queue_.empty() && !dispatching_touch_ack_) { 317 if (touch_queue_.empty() && !dispatching_touch_ack_) {
351 // Optimization of the case without touch handlers. Removing this path 318 // Optimization of the case without touch handlers. Removing this path
352 // yields identical results, but this avoids unnecessary allocations. 319 // yields identical results, but this avoids unnecessary allocations.
353 PreFilterResult filter_result = FilterBeforeForwarding(event.event); 320 if (touch_filtering_state_ == DROP_ALL_TOUCHES ||
354 if (filter_result != FORWARD_TO_RENDERER) { 321 (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE &&
355 client_->OnTouchEventAck(event, 322 !WebTouchEventTraits::IsTouchSequenceStart(event.event))) {
356 filter_result == ACK_WITH_NO_CONSUMER_EXISTS 323 client_->OnTouchEventAck(event, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
357 ? INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
358 : INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
359 return; 324 return;
360 } 325 }
361 326
362 // There is no touch event in the queue. Forward it to the renderer 327 // There is no touch event in the queue. Forward it to the renderer
363 // immediately. 328 // immediately.
364 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); 329 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false));
365 ForwardNextEventToRenderer(); 330 TryForwardNextEventToRenderer();
366 return; 331 return;
367 } 332 }
368 333
369 // If the last queued touch-event was a touch-move, and the current event is 334 // If the last queued touch-event was a touch-move, and the current event is
370 // also a touch-move, then the events can be coalesced into a single event. 335 // also a touch-move, then the events can be coalesced into a single event.
371 if (touch_queue_.size() > 1) { 336 if (touch_queue_.size() > 1) {
372 CoalescedWebTouchEvent* last_event = touch_queue_.back(); 337 CoalescedWebTouchEvent* last_event = touch_queue_.back();
373 if (last_event->CoalesceEventIfPossible(event)) 338 if (last_event->CoalesceEventIfPossible(event))
374 return; 339 return;
375 } 340 }
(...skipping 22 matching lines...) Expand all
398 touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT) { 363 touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT) {
399 touch_filtering_state_ = FORWARD_ALL_TOUCHES; 364 touch_filtering_state_ = FORWARD_ALL_TOUCHES;
400 } 365 }
401 366
402 if (ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS && 367 if (ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS &&
403 touch_filtering_state_ != DROP_ALL_TOUCHES && 368 touch_filtering_state_ != DROP_ALL_TOUCHES &&
404 WebTouchEventTraits::IsTouchSequenceStart(acked_event)) { 369 WebTouchEventTraits::IsTouchSequenceStart(acked_event)) {
405 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; 370 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
406 } 371 }
407 372
373 UpdateTouchAckStates(acked_event, ack_result);
408 PopTouchEventToClient(ack_result, latency_info); 374 PopTouchEventToClient(ack_result, latency_info);
409 TryForwardNextEventToRenderer(); 375 TryForwardNextEventToRenderer();
410 } 376 }
411 377
412 void TouchEventQueue::TryForwardNextEventToRenderer() { 378 void TouchEventQueue::TryForwardNextEventToRenderer() {
413 DCHECK(!dispatching_touch_ack_); 379 DCHECK(!dispatching_touch_ack_);
414 // If there are queued touch events, then try to forward them to the renderer 380 // If there are queued touch events, then try to forward them to the renderer
415 // immediately, or ACK the events back to the client if appropriate. 381 // immediately, or ACK the events back to the client if appropriate.
416 while (!touch_queue_.empty()) { 382 while (!touch_queue_.empty()) {
417 PreFilterResult filter_result = 383 const TouchEventWithLatencyInfo& touch =
418 FilterBeforeForwarding(touch_queue_.front()->coalesced_event().event); 384 touch_queue_.front()->coalesced_event();
419 switch (filter_result) { 385 PreFilterResult result = FilterBeforeForwarding(touch.event);
386 switch (result) {
420 case ACK_WITH_NO_CONSUMER_EXISTS: 387 case ACK_WITH_NO_CONSUMER_EXISTS:
421 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); 388 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
389 LatencyInfo());
422 break; 390 break;
423 case ACK_WITH_NOT_CONSUMED: 391 case ACK_WITH_NOT_CONSUMED:
424 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); 392 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED,
393 LatencyInfo());
425 break; 394 break;
426 case FORWARD_TO_RENDERER: 395 case FORWARD_TO_RENDERER:
427 ForwardNextEventToRenderer(); 396 ForwardToRenderer(touch);
428 return; 397 return;
429 } 398 }
430 } 399 }
431 } 400 }
432 401
433 void TouchEventQueue::ForwardNextEventToRenderer() { 402 void TouchEventQueue::ForwardToRenderer(
434 TRACE_EVENT0("input", "TouchEventQueue::ForwardNextEventToRenderer"); 403 const TouchEventWithLatencyInfo& touch) {
404 TRACE_EVENT0("input", "TouchEventQueue::ForwardToRenderer");
435 405
436 DCHECK(!empty());
437 DCHECK(!dispatching_touch_); 406 DCHECK(!dispatching_touch_);
438 DCHECK_NE(touch_filtering_state_, DROP_ALL_TOUCHES); 407 DCHECK_NE(touch_filtering_state_, DROP_ALL_TOUCHES);
439 TouchEventWithLatencyInfo touch = touch_queue_.front()->coalesced_event();
440 408
441 if (WebTouchEventTraits::IsTouchSequenceStart(touch.event)) { 409 if (WebTouchEventTraits::IsTouchSequenceStart(touch.event)) {
442 touch_filtering_state_ = 410 touch_filtering_state_ =
443 ack_timeout_enabled_ ? FORWARD_TOUCHES_UNTIL_TIMEOUT 411 ack_timeout_enabled_ ? FORWARD_TOUCHES_UNTIL_TIMEOUT
444 : FORWARD_ALL_TOUCHES; 412 : FORWARD_ALL_TOUCHES;
445 touch_ack_states_.clear(); 413 touch_ack_states_.clear();
446 send_touch_events_async_ = false; 414 absorbing_touch_moves_ = false;
447 touch_sequence_start_position_ =
448 gfx::PointF(touch.event.touches[0].position);
449 } 415 }
450 416
451 if (send_touch_events_async_ &&
452 touch.event.type == WebInputEvent::TouchMove) {
453 // Throttling touchmove's in a continuous touchmove stream while scrolling
454 // reduces the risk of jank. However, it's still important that the web
455 // application be sent touches at key points in the gesture stream,
456 // e.g., when the application slop region is exceeded or touchmove
457 // coalescing fails because of different modifiers.
458 const bool send_touch_move_now =
459 size() > 1 ||
460 (touch.event.timeStampSeconds >=
461 last_sent_touch_timestamp_sec_ + kAsyncTouchMoveIntervalSec) ||
462 (needs_async_touch_move_for_outer_slop_region_ &&
463 OutsideApplicationSlopRegion(touch.event,
464 touch_sequence_start_position_)) ||
465 (pending_async_touch_move_ &&
466 !pending_async_touch_move_->CanCoalesceWith(touch));
467
468 if (!send_touch_move_now) {
469 if (!pending_async_touch_move_) {
470 pending_async_touch_move_.reset(new TouchEventWithLatencyInfo(touch));
471 } else {
472 DCHECK(pending_async_touch_move_->CanCoalesceWith(touch));
473 pending_async_touch_move_->CoalesceWith(touch);
474 }
475 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
476 return;
477 }
478 }
479
480 last_sent_touch_timestamp_sec_ = touch.event.timeStampSeconds;
481
482 // Flush any pending async touch move. If it can be combined with the current
483 // (touchmove) event, great, otherwise send it immediately but separately. Its
484 // ack will trigger forwarding of the original |touch| event.
485 if (pending_async_touch_move_) {
486 if (pending_async_touch_move_->CanCoalesceWith(touch)) {
487 pending_async_touch_move_->CoalesceWith(touch);
488 pending_async_touch_move_->event.cancelable = !send_touch_events_async_;
489 touch = *pending_async_touch_move_.Pass();
490 } else {
491 scoped_ptr<TouchEventWithLatencyInfo> async_move =
492 pending_async_touch_move_.Pass();
493 async_move->event.cancelable = false;
494 touch_queue_.push_front(new CoalescedWebTouchEvent(*async_move, true));
495 SendTouchEventImmediately(*async_move);
496 return;
497 }
498 }
499
500 // Note: Marking touchstart events as not-cancelable prevents them from
501 // blocking subsequent gestures, but it may not be the best long term solution
502 // for tracking touch point dispatch.
503 if (send_touch_events_async_)
504 touch.event.cancelable = false;
505
506 // A synchronous ack will reset |dispatching_touch_|, in which case 417 // A synchronous ack will reset |dispatching_touch_|, in which case
507 // the touch timeout should not be started. 418 // the touch timeout should not be started.
508 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); 419 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true);
509 SendTouchEventImmediately(touch); 420 client_->SendTouchEventImmediately(touch);
510 if (dispatching_touch_ && 421 if (dispatching_touch_ &&
511 touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT && 422 touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT &&
512 ShouldTouchTriggerTimeout(touch.event)) { 423 ShouldTouchTypeTriggerTimeout(touch.event.type)) {
513 DCHECK(timeout_handler_); 424 DCHECK(timeout_handler_);
514 timeout_handler_->Start(touch); 425 timeout_handler_->Start(touch);
515 } 426 }
516 } 427 }
517 428
518 void TouchEventQueue::OnGestureScrollEvent( 429 void TouchEventQueue::OnGestureScrollEvent(
519 const GestureEventWithLatencyInfo& gesture_event) { 430 const GestureEventWithLatencyInfo& gesture_event) {
520 if (gesture_event.event.type != blink::WebInputEvent::GestureScrollBegin) 431 if (gesture_event.event.type != blink::WebInputEvent::GestureScrollBegin)
521 return; 432 return;
522 433
523 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) { 434 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE)
524 pending_async_touch_move_.reset(); 435 absorbing_touch_moves_ = true;
525 send_touch_events_async_ = true;
526 needs_async_touch_move_for_outer_slop_region_ = true;
527 return;
528 }
529 436
530 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_TOUCHCANCEL) 437 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_TOUCHCANCEL)
531 return; 438 return;
532 439
533 // We assume that scroll events are generated synchronously from 440 // We assume that scroll events are generated synchronously from
534 // dispatching a touch event ack. This allows us to generate a synthetic 441 // dispatching a touch event ack. This allows us to generate a synthetic
535 // cancel event that has the same touch ids as the touch event that 442 // cancel event that has the same touch ids as the touch event that
536 // is being acked. Otherwise, we don't perform the touch-cancel optimization. 443 // is being acked. Otherwise, we don't perform the touch-cancel optimization.
537 if (!dispatching_touch_ack_) 444 if (!dispatching_touch_ack_)
538 return; 445 return;
(...skipping 10 matching lines...) Expand all
549 // in the queue is waiting for ack from renderer. So we can just insert 456 // in the queue is waiting for ack from renderer. So we can just insert
550 // the touch cancel at the beginning of the queue. 457 // the touch cancel at the beginning of the queue.
551 touch_queue_.push_front(new CoalescedWebTouchEvent( 458 touch_queue_.push_front(new CoalescedWebTouchEvent(
552 ObtainCancelEventForTouchEvent( 459 ObtainCancelEventForTouchEvent(
553 dispatching_touch_ack_->coalesced_event()), true)); 460 dispatching_touch_ack_->coalesced_event()), true));
554 } 461 }
555 462
556 void TouchEventQueue::OnGestureEventAck( 463 void TouchEventQueue::OnGestureEventAck(
557 const GestureEventWithLatencyInfo& event, 464 const GestureEventWithLatencyInfo& event,
558 InputEventAckState ack_result) { 465 InputEventAckState ack_result) {
559 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) 466 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE)
560 return; 467 return;
561 468
562 if (event.event.type != blink::WebInputEvent::GestureScrollUpdate) 469 if (event.event.type != blink::WebInputEvent::GestureScrollUpdate)
563 return; 470 return;
564 471
565 // Throttle sending touchmove events as long as the scroll events are handled. 472 // Suspend sending touchmove events as long as the scroll events are handled.
566 // Note that there's no guarantee that this ACK is for the most recent 473 // Note that there's no guarantee that this ACK is for the most recent
567 // gesture event (or even part of the current sequence). Worst case, the 474 // gesture event (or even part of the current sequence). Worst case, the
568 // delay in updating the absorption state will result in minor UI glitches. 475 // delay in updating the absorption state should only result in minor UI
569 // A valid |pending_async_touch_move_| will be flushed when the next event is 476 // glitches.
570 // forwarded. 477 absorbing_touch_moves_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED);
571 send_touch_events_async_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED);
572 if (!send_touch_events_async_)
573 needs_async_touch_move_for_outer_slop_region_ = false;
574 } 478 }
575 479
576 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) { 480 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) {
577 DCHECK(!dispatching_touch_ack_); 481 DCHECK(!dispatching_touch_ack_);
578 DCHECK(!dispatching_touch_); 482 DCHECK(!dispatching_touch_);
579 483
580 if (has_handlers) { 484 if (has_handlers) {
581 if (touch_filtering_state_ == DROP_ALL_TOUCHES) { 485 if (touch_filtering_state_ == DROP_ALL_TOUCHES) {
582 // If no touch handler was previously registered, ensure that we don't 486 // If no touch handler was previously registered, ensure that we don't
583 // send a partial touch sequence to the renderer. 487 // send a partial touch sequence to the renderer.
584 DCHECK(touch_queue_.empty()); 488 DCHECK(touch_queue_.empty());
585 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; 489 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
586 } 490 }
587 } else { 491 } else {
588 // TODO(jdduke): Synthesize a TouchCancel if necessary to update Blink touch 492 // TODO(jdduke): Synthesize a TouchCancel if necessary to update Blink touch
589 // state tracking (e.g., if the touch handler was removed mid-sequence). 493 // state tracking (e.g., if the touch handler was removed mid-sequence).
590 touch_filtering_state_ = DROP_ALL_TOUCHES; 494 touch_filtering_state_ = DROP_ALL_TOUCHES;
591 pending_async_touch_move_.reset();
592 if (timeout_handler_) 495 if (timeout_handler_)
593 timeout_handler_->Reset(); 496 timeout_handler_->Reset();
594 if (!touch_queue_.empty()) 497 if (!touch_queue_.empty())
595 ProcessTouchAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, LatencyInfo()); 498 ProcessTouchAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, LatencyInfo());
596 // As there is no touch handler, ack'ing the event should flush the queue. 499 // As there is no touch handler, ack'ing the event should flush the queue.
597 DCHECK(touch_queue_.empty()); 500 DCHECK(touch_queue_.empty());
598 } 501 }
599 } 502 }
600 503
601 bool TouchEventQueue::IsPendingAckTouchStart() const { 504 bool TouchEventQueue::IsPendingAckTouchStart() const {
(...skipping 20 matching lines...) Expand all
622 return; 525 return;
623 } 526 }
624 527
625 ack_timeout_enabled_ = true; 528 ack_timeout_enabled_ = true;
626 if (!timeout_handler_) 529 if (!timeout_handler_)
627 timeout_handler_.reset(new TouchTimeoutHandler(this, ack_timeout_delay)); 530 timeout_handler_.reset(new TouchTimeoutHandler(this, ack_timeout_delay));
628 else 531 else
629 timeout_handler_->set_timeout_delay(ack_timeout_delay); 532 timeout_handler_->set_timeout_delay(ack_timeout_delay);
630 } 533 }
631 534
632 bool TouchEventQueue::HasPendingAsyncTouchMoveForTesting() const {
633 return pending_async_touch_move_;
634 }
635
636 bool TouchEventQueue::IsTimeoutRunningForTesting() const { 535 bool TouchEventQueue::IsTimeoutRunningForTesting() const {
637 return timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning(); 536 return timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning();
638 } 537 }
639 538
640 const TouchEventWithLatencyInfo& 539 const TouchEventWithLatencyInfo&
641 TouchEventQueue::GetLatestEventForTesting() const { 540 TouchEventQueue::GetLatestEventForTesting() const {
642 return touch_queue_.back()->coalesced_event(); 541 return touch_queue_.back()->coalesced_event();
643 } 542 }
644 543
645 void TouchEventQueue::FlushQueue() { 544 void TouchEventQueue::FlushQueue() {
646 DCHECK(!dispatching_touch_ack_); 545 DCHECK(!dispatching_touch_ack_);
647 DCHECK(!dispatching_touch_); 546 DCHECK(!dispatching_touch_);
648 pending_async_touch_move_.reset();
649 if (touch_filtering_state_ != DROP_ALL_TOUCHES) 547 if (touch_filtering_state_ != DROP_ALL_TOUCHES)
650 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; 548 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
651 while (!touch_queue_.empty()) 549 while (!touch_queue_.empty()) {
652 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); 550 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
653 } 551 LatencyInfo());
654 552 }
655 void TouchEventQueue::PopTouchEventToClient(InputEventAckState ack_result) {
656 AckTouchEventToClient(ack_result, PopTouchEvent());
657 } 553 }
658 554
659 void TouchEventQueue::PopTouchEventToClient( 555 void TouchEventQueue::PopTouchEventToClient(
660 InputEventAckState ack_result, 556 InputEventAckState ack_result,
661 const LatencyInfo& renderer_latency_info) { 557 const LatencyInfo& renderer_latency_info) {
662 scoped_ptr<CoalescedWebTouchEvent> acked_event = PopTouchEvent(); 558 DCHECK(!dispatching_touch_ack_);
663 acked_event->UpdateLatencyInfoForAck(renderer_latency_info); 559 if (touch_queue_.empty())
664 AckTouchEventToClient(ack_result, acked_event.Pass()); 560 return;
665 } 561 scoped_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front());
562 touch_queue_.pop_front();
666 563
667 void TouchEventQueue::AckTouchEventToClient( 564 if (acked_event->ignore_ack())
668 InputEventAckState ack_result, 565 return;
669 scoped_ptr<CoalescedWebTouchEvent> acked_event) {
670 DCHECK(acked_event);
671 DCHECK(!dispatching_touch_ack_);
672 UpdateTouchAckStates(acked_event->coalesced_event().event, ack_result);
673 566
674 // Note that acking the touch-event may result in multiple gestures being sent 567 // Note that acking the touch-event may result in multiple gestures being sent
675 // to the renderer, or touch-events being queued. 568 // to the renderer, or touch-events being queued.
676 base::AutoReset<const CoalescedWebTouchEvent*> dispatching_touch_ack( 569 base::AutoReset<CoalescedWebTouchEvent*>
677 &dispatching_touch_ack_, acked_event.get()); 570 dispatching_touch_ack(&dispatching_touch_ack_, acked_event.get());
678 acked_event->DispatchAckToClient(ack_result, client_);
679 }
680 571
681 scoped_ptr<CoalescedWebTouchEvent> TouchEventQueue::PopTouchEvent() { 572 for (WebTouchEventWithLatencyList::iterator iter = acked_event->begin(),
682 DCHECK(!touch_queue_.empty()); 573 end = acked_event->end();
683 scoped_ptr<CoalescedWebTouchEvent> event(touch_queue_.front()); 574 iter != end; ++iter) {
684 touch_queue_.pop_front(); 575 iter->latency.AddNewLatencyFrom(renderer_latency_info);
685 return event.Pass(); 576 client_->OnTouchEventAck((*iter), ack_result);
686 }
687
688 void TouchEventQueue::SendTouchEventImmediately(
689 const TouchEventWithLatencyInfo& touch) {
690 if (needs_async_touch_move_for_outer_slop_region_) {
691 // Any event other than a touchmove (e.g., touchcancel or secondary
692 // touchstart) after a scroll has started will interrupt the need to send a
693 // an outer slop-region exceeding touchmove.
694 if (touch.event.type != WebInputEvent::TouchMove ||
695 OutsideApplicationSlopRegion(touch.event,
696 touch_sequence_start_position_))
697 needs_async_touch_move_for_outer_slop_region_ = false;
698 } 577 }
699
700 client_->SendTouchEventImmediately(touch);
701 } 578 }
702 579
703 TouchEventQueue::PreFilterResult 580 TouchEventQueue::PreFilterResult
704 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { 581 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) {
705 if (timeout_handler_ && timeout_handler_->FilterEvent(event)) 582 if (timeout_handler_ && timeout_handler_->FilterEvent(event))
706 return ACK_WITH_NO_CONSUMER_EXISTS; 583 return ACK_WITH_NO_CONSUMER_EXISTS;
707 584
708 if (touchmove_slop_suppressor_->FilterEvent(event)) 585 if (touchmove_slop_suppressor_->FilterEvent(event))
709 return ACK_WITH_NOT_CONSUMED; 586 return ACK_WITH_NOT_CONSUMED;
710 587
711 if (touch_filtering_state_ == DROP_ALL_TOUCHES) 588 if (touch_filtering_state_ == DROP_ALL_TOUCHES)
712 return ACK_WITH_NO_CONSUMER_EXISTS; 589 return ACK_WITH_NO_CONSUMER_EXISTS;
713 590
714 if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE && 591 if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE &&
715 event.type != WebInputEvent::TouchCancel) { 592 event.type != WebInputEvent::TouchCancel) {
716 if (WebTouchEventTraits::IsTouchSequenceStart(event)) 593 if (WebTouchEventTraits::IsTouchSequenceStart(event))
717 return FORWARD_TO_RENDERER; 594 return FORWARD_TO_RENDERER;
718 return ACK_WITH_NO_CONSUMER_EXISTS; 595 return ACK_WITH_NOT_CONSUMED;
719 } 596 }
720 597
598 if (absorbing_touch_moves_ && event.type == WebInputEvent::TouchMove)
599 return ACK_WITH_NOT_CONSUMED;
600
721 // Touch press events should always be forwarded to the renderer. 601 // Touch press events should always be forwarded to the renderer.
722 if (event.type == WebInputEvent::TouchStart) 602 if (event.type == WebInputEvent::TouchStart)
723 return FORWARD_TO_RENDERER; 603 return FORWARD_TO_RENDERER;
724 604
725 for (unsigned int i = 0; i < event.touchesLength; ++i) { 605 for (unsigned int i = 0; i < event.touchesLength; ++i) {
726 const WebTouchPoint& point = event.touches[i]; 606 const WebTouchPoint& point = event.touches[i];
727 // If a point has been stationary, then don't take it into account. 607 // If a point has been stationary, then don't take it into account.
728 if (point.state == WebTouchPoint::StateStationary) 608 if (point.state == WebTouchPoint::StateStationary)
729 continue; 609 continue;
730 610
(...skipping 26 matching lines...) Expand all
757 } else if (event.type == WebInputEvent::TouchStart) { 637 } else if (event.type == WebInputEvent::TouchStart) {
758 for (unsigned i = 0; i < event.touchesLength; ++i) { 638 for (unsigned i = 0; i < event.touchesLength; ++i) {
759 const WebTouchPoint& point = event.touches[i]; 639 const WebTouchPoint& point = event.touches[i];
760 if (point.state == WebTouchPoint::StatePressed) 640 if (point.state == WebTouchPoint::StatePressed)
761 touch_ack_states_[point.id] = ack_result; 641 touch_ack_states_[point.id] = ack_result;
762 } 642 }
763 } 643 }
764 } 644 }
765 645
766 } // namespace content 646 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698