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

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

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

Powered by Google App Engine
This is Rietveld 408576698