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/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/browser/renderer_host/input/web_touch_event_traits.h" | 12 #include "content/browser/renderer_host/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 const double kAsyncTouchMoveIntervalS = .2; | |
25 | |
24 // Using a small epsilon when comparing slop distances allows pixel perfect | 26 // Using a small epsilon when comparing slop distances allows pixel perfect |
25 // slop determination when using fractional DIP coordinates (assuming the slop | 27 // slop determination when using fractional DIP coordinates (assuming the slop |
26 // region and DPI scale are reasonably proportioned). | 28 // region and DPI scale are reasonably proportioned). |
27 const float kSlopEpsilon = .05f; | 29 const float kSlopEpsilon = .05f; |
28 | 30 |
29 typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList; | 31 typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList; |
30 | 32 |
31 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( | 33 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( |
32 const TouchEventWithLatencyInfo& event_to_cancel) { | 34 const TouchEventWithLatencyInfo& event_to_cancel) { |
33 TouchEventWithLatencyInfo event = event_to_cancel; | 35 TouchEventWithLatencyInfo event = event_to_cancel; |
34 event.event.type = WebInputEvent::TouchCancel; | 36 event.event.type = WebInputEvent::TouchCancel; |
35 for (size_t i = 0; i < event.event.touchesLength; i++) | 37 for (size_t i = 0; i < event.event.touchesLength; i++) |
36 event.event.touches[i].state = WebTouchPoint::StateCancelled; | 38 event.event.touches[i].state = WebTouchPoint::StateCancelled; |
37 return event; | 39 return event; |
38 } | 40 } |
39 | 41 |
40 bool ShouldTouchTypeTriggerTimeout(WebInputEvent::Type type) { | 42 bool ShouldTouchTriggerTimeout(const WebInputEvent& event) { |
41 return type == WebInputEvent::TouchStart || | 43 return (event.type == WebInputEvent::TouchStart || |
42 type == WebInputEvent::TouchMove; | 44 event.type == WebInputEvent::TouchMove) && |
45 !WebInputEventTraits::IgnoresAckDisposition(event); | |
43 } | 46 } |
44 | 47 |
45 } // namespace | 48 } // namespace |
46 | 49 |
47 | 50 |
48 // Cancels a touch sequence if a touchstart or touchmove ack response is | 51 // Cancels a touch sequence if a touchstart or touchmove ack response is |
49 // sufficiently delayed. | 52 // sufficiently delayed. |
50 class TouchEventQueue::TouchTimeoutHandler { | 53 class TouchEventQueue::TouchTimeoutHandler { |
51 public: | 54 public: |
52 TouchTimeoutHandler(TouchEventQueue* touch_queue, | 55 TouchTimeoutHandler(TouchEventQueue* touch_queue, |
53 base::TimeDelta timeout_delay) | 56 base::TimeDelta timeout_delay) |
54 : touch_queue_(touch_queue), | 57 : touch_queue_(touch_queue), |
55 timeout_delay_(timeout_delay), | 58 timeout_delay_(timeout_delay), |
56 pending_ack_state_(PENDING_ACK_NONE), | 59 pending_ack_state_(PENDING_ACK_NONE), |
57 timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut, | 60 timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut, |
58 base::Unretained(this))) {} | 61 base::Unretained(this))) {} |
59 | 62 |
60 ~TouchTimeoutHandler() {} | 63 ~TouchTimeoutHandler() {} |
61 | 64 |
62 void Start(const TouchEventWithLatencyInfo& event) { | 65 void Start(const TouchEventWithLatencyInfo& event) { |
63 DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE); | 66 DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE); |
64 DCHECK(ShouldTouchTypeTriggerTimeout(event.event.type)); | 67 DCHECK(ShouldTouchTriggerTimeout(event.event)); |
65 timeout_event_ = event; | 68 timeout_event_ = event; |
66 timeout_monitor_.Restart(timeout_delay_); | 69 timeout_monitor_.Restart(timeout_delay_); |
67 } | 70 } |
68 | 71 |
69 bool ConfirmTouchEvent(InputEventAckState ack_result) { | 72 bool ConfirmTouchEvent(InputEventAckState ack_result) { |
70 switch (pending_ack_state_) { | 73 switch (pending_ack_state_) { |
71 case PENDING_ACK_NONE: | 74 case PENDING_ACK_NONE: |
72 timeout_monitor_.Stop(); | 75 timeout_monitor_.Stop(); |
73 return false; | 76 return false; |
74 case PENDING_ACK_ORIGINAL_EVENT: | 77 case PENDING_ACK_ORIGINAL_EVENT: |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
223 // track of all the original touch-events that were coalesced into a single | 226 // track of all the original touch-events that were coalesced into a single |
224 // event. The coalesced event is forwarded to the renderer, while the original | 227 // event. The coalesced event is forwarded to the renderer, while the original |
225 // touch-events are sent to the Client (on ACK for the coalesced event) so that | 228 // touch-events are sent to the Client (on ACK for the coalesced event) so that |
226 // the Client receives the event with their original timestamp. | 229 // the Client receives the event with their original timestamp. |
227 class CoalescedWebTouchEvent { | 230 class CoalescedWebTouchEvent { |
228 public: | 231 public: |
229 CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event, | 232 CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event, |
230 bool ignore_ack) | 233 bool ignore_ack) |
231 : coalesced_event_(event), | 234 : coalesced_event_(event), |
232 ignore_ack_(ignore_ack) { | 235 ignore_ack_(ignore_ack) { |
233 events_.push_back(event); | 236 if (!ignore_ack_) |
234 TRACE_EVENT_ASYNC_BEGIN0( | 237 events_.push_back(event); |
235 "input", "TouchEventQueue::QueueEvent", this); | 238 TRACE_EVENT_ASYNC_BEGIN0("input", "TouchEventQueue::QueueEvent", this); |
236 } | 239 } |
237 | 240 |
238 ~CoalescedWebTouchEvent() { | 241 ~CoalescedWebTouchEvent() { |
239 TRACE_EVENT_ASYNC_END0( | 242 TRACE_EVENT_ASYNC_END0("input", "TouchEventQueue::QueueEvent", this); |
240 "input", "TouchEventQueue::QueueEvent", this); | |
241 } | 243 } |
242 | 244 |
243 // Coalesces the event with the existing event if possible. Returns whether | 245 // Coalesces the event with the existing event if possible. Returns whether |
244 // the event was coalesced. | 246 // the event was coalesced. |
245 bool CoalesceEventIfPossible( | 247 bool CoalesceEventIfPossible( |
246 const TouchEventWithLatencyInfo& event_with_latency) { | 248 const TouchEventWithLatencyInfo& event_with_latency) { |
247 if (ignore_ack_) | 249 if (ignore_ack_) |
248 return false; | 250 return false; |
249 | 251 |
250 if (!coalesced_event_.CanCoalesceWith(event_with_latency)) | 252 if (!coalesced_event_.CanCoalesceWith(event_with_latency)) |
251 return false; | 253 return false; |
252 | 254 |
253 TRACE_EVENT_INSTANT0( | 255 TRACE_EVENT_INSTANT0( |
254 "input", "TouchEventQueue::MoveCoalesced", TRACE_EVENT_SCOPE_THREAD); | 256 "input", "TouchEventQueue::MoveCoalesced", TRACE_EVENT_SCOPE_THREAD); |
255 coalesced_event_.CoalesceWith(event_with_latency); | 257 coalesced_event_.CoalesceWith(event_with_latency); |
256 events_.push_back(event_with_latency); | |
257 return true; | 258 return true; |
258 } | 259 } |
259 | 260 |
260 const TouchEventWithLatencyInfo& coalesced_event() const { | 261 const TouchEventWithLatencyInfo& coalesced_event() const { |
261 return coalesced_event_; | 262 return coalesced_event_; |
262 } | 263 } |
263 | 264 |
264 WebTouchEventWithLatencyList::iterator begin() { | 265 WebTouchEventWithLatencyList::iterator begin() { |
266 DCHECK(!ignore_ack_); | |
aelias_OOO_until_Jul13
2014/04/22 01:56:39
This is a bit ugly. Instead of returning these it
jdduke (slow)
2014/04/23 19:57:41
Done.
| |
267 return events_.begin(); | |
268 } | |
269 | |
270 WebTouchEventWithLatencyList::const_iterator begin() const { | |
271 DCHECK(!ignore_ack_); | |
265 return events_.begin(); | 272 return events_.begin(); |
266 } | 273 } |
267 | 274 |
268 WebTouchEventWithLatencyList::iterator end() { | 275 WebTouchEventWithLatencyList::iterator end() { |
276 DCHECK(!ignore_ack_); | |
269 return events_.end(); | 277 return events_.end(); |
270 } | 278 } |
271 | 279 |
272 size_t size() const { return events_.size(); } | 280 WebTouchEventWithLatencyList::const_iterator end() const { |
281 DCHECK(!ignore_ack_); | |
282 return events_.end(); | |
283 } | |
273 | 284 |
274 bool ignore_ack() const { return ignore_ack_; } | 285 bool ignore_ack() const { return ignore_ack_; } |
275 | 286 |
276 private: | 287 private: |
277 // This is the event that is forwarded to the renderer. | 288 // This is the event that is forwarded to the renderer. |
278 TouchEventWithLatencyInfo coalesced_event_; | 289 TouchEventWithLatencyInfo coalesced_event_; |
279 | 290 |
280 // This is the list of the original events that were coalesced. | 291 // This is the list of the original events that were coalesced. |
281 WebTouchEventWithLatencyList events_; | 292 WebTouchEventWithLatencyList events_; |
282 | 293 |
283 // If |ignore_ack_| is true, don't send this touch event to client | 294 // If |ignore_ack_| is true, don't send this touch event to client |
284 // when the event is acked. | 295 // when the event is acked. |
285 bool ignore_ack_; | 296 bool ignore_ack_; |
aelias_OOO_until_Jul13
2014/04/22 01:56:39
Would async_ be a better name?
jdduke (slow)
2014/04/23 19:57:41
Probably, yes.
| |
286 | 297 |
287 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); | 298 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); |
288 }; | 299 }; |
289 | 300 |
290 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client, | 301 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client, |
291 TouchScrollingMode mode, | 302 TouchScrollingMode mode, |
292 double touchmove_suppression_length_dips) | 303 double touchmove_suppression_length_dips) |
293 : client_(client), | 304 : client_(client), |
294 dispatching_touch_ack_(NULL), | 305 dispatching_touch_ack_(NULL), |
295 dispatching_touch_(false), | 306 dispatching_touch_(false), |
296 touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT), | 307 touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT), |
297 ack_timeout_enabled_(false), | 308 ack_timeout_enabled_(false), |
298 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor( | 309 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor( |
299 touchmove_suppression_length_dips + kSlopEpsilon)), | 310 touchmove_suppression_length_dips + kSlopEpsilon)), |
300 absorbing_touch_moves_(false), | 311 absorbing_touch_moves_(false), |
312 async_touch_moves_(false), | |
313 last_sent_touch_timestamp_(0), | |
301 touch_scrolling_mode_(mode) { | 314 touch_scrolling_mode_(mode) { |
302 DCHECK(client); | 315 DCHECK(client); |
303 } | 316 } |
304 | 317 |
305 TouchEventQueue::~TouchEventQueue() { | 318 TouchEventQueue::~TouchEventQueue() { |
306 if (!touch_queue_.empty()) | 319 if (!touch_queue_.empty()) |
307 STLDeleteElements(&touch_queue_); | 320 STLDeleteElements(&touch_queue_); |
308 } | 321 } |
309 | 322 |
310 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { | 323 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { |
311 TRACE_EVENT0("input", "TouchEventQueue::QueueEvent"); | 324 TRACE_EVENT0("input", "TouchEventQueue::QueueEvent"); |
312 | 325 |
326 DCHECK(!dispatching_touch_ack_); | |
327 | |
313 // If the queueing of |event| was triggered by an ack dispatch, defer | 328 // If the queueing of |event| was triggered by an ack dispatch, defer |
314 // processing the event until the dispatch has finished. | 329 // processing the event until the dispatch has finished. |
315 if (touch_queue_.empty() && !dispatching_touch_ack_) { | 330 if (touch_queue_.empty()) { |
316 // Optimization of the case without touch handlers. Removing this path | 331 // Optimization of the case without touch handlers. Removing this path |
317 // yields identical results, but this avoids unnecessary allocations. | 332 // yields identical results, but this avoids unnecessary allocations. |
318 if (touch_filtering_state_ == DROP_ALL_TOUCHES || | 333 if (touch_filtering_state_ == DROP_ALL_TOUCHES || |
319 (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE && | 334 (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE && |
320 !WebTouchEventTraits::IsTouchSequenceStart(event.event))) { | 335 !WebTouchEventTraits::IsTouchSequenceStart(event.event))) { |
321 client_->OnTouchEventAck(event, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); | 336 client_->OnTouchEventAck(event, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); |
322 return; | 337 return; |
323 } | 338 } |
324 | 339 |
325 // There is no touch event in the queue. Forward it to the renderer | 340 // There is no touch event in the queue. Forward it to the renderer |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
371 UpdateTouchAckStates(acked_event, ack_result); | 386 UpdateTouchAckStates(acked_event, ack_result); |
372 PopTouchEventToClient(ack_result, latency_info); | 387 PopTouchEventToClient(ack_result, latency_info); |
373 TryForwardNextEventToRenderer(); | 388 TryForwardNextEventToRenderer(); |
374 } | 389 } |
375 | 390 |
376 void TouchEventQueue::TryForwardNextEventToRenderer() { | 391 void TouchEventQueue::TryForwardNextEventToRenderer() { |
377 DCHECK(!dispatching_touch_ack_); | 392 DCHECK(!dispatching_touch_ack_); |
378 // If there are queued touch events, then try to forward them to the renderer | 393 // If there are queued touch events, then try to forward them to the renderer |
379 // immediately, or ACK the events back to the client if appropriate. | 394 // immediately, or ACK the events back to the client if appropriate. |
380 while (!touch_queue_.empty()) { | 395 while (!touch_queue_.empty()) { |
381 const TouchEventWithLatencyInfo& touch = | 396 PreFilterResult result = |
382 touch_queue_.front()->coalesced_event(); | 397 FilterBeforeForwarding(touch_queue_.front()->coalesced_event().event); |
Rick Byers
2014/04/22 14:52:59
Thanks for the cleanup here - new names/signatures
| |
383 PreFilterResult result = FilterBeforeForwarding(touch.event); | |
384 switch (result) { | 398 switch (result) { |
385 case ACK_WITH_NO_CONSUMER_EXISTS: | 399 case ACK_WITH_NO_CONSUMER_EXISTS: |
386 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, | 400 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); |
387 LatencyInfo()); | |
388 break; | 401 break; |
389 case ACK_WITH_NOT_CONSUMED: | 402 case ACK_WITH_NOT_CONSUMED: |
390 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, | 403 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
391 LatencyInfo()); | |
392 break; | 404 break; |
393 case FORWARD_TO_RENDERER: | 405 case FORWARD_TO_RENDERER: |
394 ForwardToRenderer(touch); | 406 ForwardNextEventToRenderer(); |
395 return; | 407 return; |
396 } | 408 } |
397 } | 409 } |
398 } | 410 } |
399 | 411 |
400 void TouchEventQueue::ForwardToRenderer( | 412 void TouchEventQueue::ForwardNextEventToRenderer() { |
401 const TouchEventWithLatencyInfo& touch) { | |
402 TRACE_EVENT0("input", "TouchEventQueue::ForwardToRenderer"); | 413 TRACE_EVENT0("input", "TouchEventQueue::ForwardToRenderer"); |
403 | 414 |
415 DCHECK(!empty()); | |
404 DCHECK(!dispatching_touch_); | 416 DCHECK(!dispatching_touch_); |
405 DCHECK_NE(touch_filtering_state_, DROP_ALL_TOUCHES); | 417 DCHECK_NE(touch_filtering_state_, DROP_ALL_TOUCHES); |
418 TouchEventWithLatencyInfo touch = touch_queue_.front()->coalesced_event(); | |
406 | 419 |
407 if (WebTouchEventTraits::IsTouchSequenceStart(touch.event)) { | 420 if (WebTouchEventTraits::IsTouchSequenceStart(touch.event)) { |
408 touch_filtering_state_ = | 421 touch_filtering_state_ = |
409 ack_timeout_enabled_ ? FORWARD_TOUCHES_UNTIL_TIMEOUT | 422 ack_timeout_enabled_ ? FORWARD_TOUCHES_UNTIL_TIMEOUT |
410 : FORWARD_ALL_TOUCHES; | 423 : FORWARD_ALL_TOUCHES; |
411 touch_ack_states_.clear(); | 424 touch_ack_states_.clear(); |
412 absorbing_touch_moves_ = false; | 425 absorbing_touch_moves_ = false; |
426 async_touch_moves_ = false; | |
413 } | 427 } |
414 | 428 |
429 if (async_touch_moves_ && touch.event.type == WebInputEvent::TouchEnd) | |
430 touch.event.cancelable = false; | |
431 | |
432 if (async_touch_moves_ && touch.event.type == WebInputEvent::TouchMove) { | |
433 // If there are any events following this TouchMove, or sufficient time has | |
434 // past since sending the last touch event, flush any pending touch moves. | |
aelias_OOO_until_Jul13
2014/04/22 01:56:39
nit: "past" -> "passed"
jdduke (slow)
2014/04/23 19:57:41
Done.
| |
435 // TODO(jdduke): Should the touchmove be dropped if there are other pending | |
aelias_OOO_until_Jul13
2014/04/22 01:56:39
I don't think it should be dropped. I think it's
Rick Byers
2014/04/22 14:52:59
Agreed. Coalescing according to our rules is the
| |
436 // events? | |
437 const bool send_touch_move_now = | |
438 size() > 1 || | |
439 touch.event.timeStampSeconds > | |
440 last_sent_touch_timestamp_ + kAsyncTouchMoveIntervalS; | |
441 | |
442 // If there's a pending touchmove, coalescewith the new event. Otherwise | |
aelias_OOO_until_Jul13
2014/04/22 01:56:39
nit: missing space after "coalesce"
jdduke (slow)
2014/04/23 19:57:41
Done.
| |
443 // create it if necessary for deferral. | |
444 if (pending_async_touch_move_) { | |
445 DCHECK(pending_async_touch_move_->CanCoalesceWith(touch)); | |
Rick Byers
2014/04/22 14:52:59
Is this really guaranteed to be true? Eg. what if
jdduke (slow)
2014/04/23 19:57:41
Do our touch events use any modifiers? Android doe
| |
446 pending_async_touch_move_->CoalesceWith(touch); | |
447 } else { | |
448 if (!send_touch_move_now) | |
449 pending_async_touch_move_.reset(new TouchEventWithLatencyInfo(touch)); | |
450 } | |
451 | |
452 // Ack the event immediately, allowing associated gestures to be dispatched | |
453 // immediately. | |
454 if (!send_touch_move_now) { | |
455 DCHECK(pending_async_touch_move_); | |
456 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | |
457 return; | |
458 } | |
459 | |
460 if (pending_async_touch_move_) | |
461 touch = *pending_async_touch_move_.Pass(); | |
462 | |
463 touch.event.cancelable = false; | |
464 } | |
465 | |
466 // Sending an event should clear any pending async touchmoves. | |
467 pending_async_touch_move_.reset(); | |
468 last_sent_touch_timestamp_ = touch.event.timeStampSeconds; | |
469 | |
415 // A synchronous ack will reset |dispatching_touch_|, in which case | 470 // A synchronous ack will reset |dispatching_touch_|, in which case |
416 // the touch timeout should not be started. | 471 // the touch timeout should not be started. |
417 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); | 472 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); |
418 client_->SendTouchEventImmediately(touch); | 473 client_->SendTouchEventImmediately(touch); |
419 if (dispatching_touch_ && | 474 if (dispatching_touch_ && |
420 touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT && | 475 touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT && |
421 ShouldTouchTypeTriggerTimeout(touch.event.type)) { | 476 ShouldTouchTriggerTimeout(touch.event)) { |
422 DCHECK(timeout_handler_); | 477 DCHECK(timeout_handler_); |
423 timeout_handler_->Start(touch); | 478 timeout_handler_->Start(touch); |
424 } | 479 } |
425 } | 480 } |
426 | 481 |
427 void TouchEventQueue::OnGestureScrollEvent( | 482 void TouchEventQueue::OnGestureScrollEvent( |
428 const GestureEventWithLatencyInfo& gesture_event) { | 483 const GestureEventWithLatencyInfo& gesture_event) { |
429 if (gesture_event.event.type != blink::WebInputEvent::GestureScrollBegin) | 484 if (gesture_event.event.type != blink::WebInputEvent::GestureScrollBegin) |
430 return; | 485 return; |
431 | 486 |
487 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) { | |
488 pending_async_touch_move_.reset(); | |
489 async_touch_moves_ = true; | |
490 } | |
491 | |
432 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE) | 492 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE) |
433 absorbing_touch_moves_ = true; | 493 absorbing_touch_moves_ = true; |
434 | 494 |
435 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_TOUCHCANCEL) | 495 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_TOUCHCANCEL) |
436 return; | 496 return; |
437 | 497 |
438 // We assume that scroll events are generated synchronously from | 498 // We assume that scroll events are generated synchronously from |
439 // dispatching a touch event ack. This allows us to generate a synthetic | 499 // dispatching a touch event ack. This allows us to generate a synthetic |
440 // cancel event that has the same touch ids as the touch event that | 500 // cancel event that has the same touch ids as the touch event that |
441 // is being acked. Otherwise, we don't perform the touch-cancel optimization. | 501 // is being acked. Otherwise, we don't perform the touch-cancel optimization. |
(...skipping 12 matching lines...) Expand all Loading... | |
454 // in the queue is waiting for ack from renderer. So we can just insert | 514 // in the queue is waiting for ack from renderer. So we can just insert |
455 // the touch cancel at the beginning of the queue. | 515 // the touch cancel at the beginning of the queue. |
456 touch_queue_.push_front(new CoalescedWebTouchEvent( | 516 touch_queue_.push_front(new CoalescedWebTouchEvent( |
457 ObtainCancelEventForTouchEvent( | 517 ObtainCancelEventForTouchEvent( |
458 dispatching_touch_ack_->coalesced_event()), true)); | 518 dispatching_touch_ack_->coalesced_event()), true)); |
459 } | 519 } |
460 | 520 |
461 void TouchEventQueue::OnGestureEventAck( | 521 void TouchEventQueue::OnGestureEventAck( |
462 const GestureEventWithLatencyInfo& event, | 522 const GestureEventWithLatencyInfo& event, |
463 InputEventAckState ack_result) { | 523 InputEventAckState ack_result) { |
464 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE) | 524 if (event.event.type != blink::WebInputEvent::GestureScrollUpdate) |
465 return; | 525 return; |
466 | 526 |
467 if (event.event.type != blink::WebInputEvent::GestureScrollUpdate) | 527 bool event_consumed = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED); |
468 return; | 528 |
529 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) { | |
530 async_touch_moves_ = event_consumed; | |
531 if (!async_touch_moves_) { | |
532 // TODO(jdduke): Should this be flushed? | |
aelias_OOO_until_Jul13
2014/04/22 01:56:39
I think it should.
| |
533 pending_async_touch_move_.reset(); | |
534 } | |
535 } | |
469 | 536 |
470 // Suspend sending touchmove events as long as the scroll events are handled. | 537 // Suspend sending touchmove events as long as the scroll events are handled. |
471 // Note that there's no guarantee that this ACK is for the most recent | 538 // Note that there's no guarantee that this ACK is for the most recent |
472 // gesture event (or even part of the current sequence). Worst case, the | 539 // gesture event (or even part of the current sequence). Worst case, the |
473 // delay in updating the absorption state should only result in minor UI | 540 // delay in updating the absorption state should only result in minor UI |
474 // glitches. | 541 // glitches. |
475 absorbing_touch_moves_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED); | 542 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE) |
543 absorbing_touch_moves_ = event_consumed; | |
476 } | 544 } |
477 | 545 |
478 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) { | 546 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) { |
479 DCHECK(!dispatching_touch_ack_); | 547 DCHECK(!dispatching_touch_ack_); |
480 DCHECK(!dispatching_touch_); | 548 DCHECK(!dispatching_touch_); |
481 | 549 |
482 if (has_handlers) { | 550 if (has_handlers) { |
483 if (touch_filtering_state_ == DROP_ALL_TOUCHES) { | 551 if (touch_filtering_state_ == DROP_ALL_TOUCHES) { |
484 // If no touch handler was previously registered, ensure that we don't | 552 // If no touch handler was previously registered, ensure that we don't |
485 // send a partial touch sequence to the renderer. | 553 // send a partial touch sequence to the renderer. |
486 DCHECK(touch_queue_.empty()); | 554 DCHECK(touch_queue_.empty()); |
487 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; | 555 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; |
488 } | 556 } |
489 } else { | 557 } else { |
490 // TODO(jdduke): Synthesize a TouchCancel if necessary to update Blink touch | 558 // TODO(jdduke): Synthesize a TouchCancel if necessary to update Blink touch |
491 // state tracking (e.g., if the touch handler was removed mid-sequence). | 559 // state tracking (e.g., if the touch handler was removed mid-sequence). |
492 touch_filtering_state_ = DROP_ALL_TOUCHES; | 560 touch_filtering_state_ = DROP_ALL_TOUCHES; |
561 pending_async_touch_move_.reset(); | |
493 if (timeout_handler_) | 562 if (timeout_handler_) |
494 timeout_handler_->Reset(); | 563 timeout_handler_->Reset(); |
495 if (!touch_queue_.empty()) | 564 if (!touch_queue_.empty()) |
496 ProcessTouchAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, LatencyInfo()); | 565 ProcessTouchAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, LatencyInfo()); |
497 // As there is no touch handler, ack'ing the event should flush the queue. | 566 // As there is no touch handler, ack'ing the event should flush the queue. |
498 DCHECK(touch_queue_.empty()); | 567 DCHECK(touch_queue_.empty()); |
499 } | 568 } |
500 } | 569 } |
501 | 570 |
502 bool TouchEventQueue::IsPendingAckTouchStart() const { | 571 bool TouchEventQueue::IsPendingAckTouchStart() const { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
535 } | 604 } |
536 | 605 |
537 const TouchEventWithLatencyInfo& | 606 const TouchEventWithLatencyInfo& |
538 TouchEventQueue::GetLatestEventForTesting() const { | 607 TouchEventQueue::GetLatestEventForTesting() const { |
539 return touch_queue_.back()->coalesced_event(); | 608 return touch_queue_.back()->coalesced_event(); |
540 } | 609 } |
541 | 610 |
542 void TouchEventQueue::FlushQueue() { | 611 void TouchEventQueue::FlushQueue() { |
543 DCHECK(!dispatching_touch_ack_); | 612 DCHECK(!dispatching_touch_ack_); |
544 DCHECK(!dispatching_touch_); | 613 DCHECK(!dispatching_touch_); |
614 pending_async_touch_move_.reset(); | |
545 if (touch_filtering_state_ != DROP_ALL_TOUCHES) | 615 if (touch_filtering_state_ != DROP_ALL_TOUCHES) |
546 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; | 616 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; |
547 while (!touch_queue_.empty()) { | 617 while (!touch_queue_.empty()) |
548 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, | 618 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); |
549 LatencyInfo()); | 619 } |
550 } | 620 |
621 void TouchEventQueue::PopTouchEventToClient( | |
622 InputEventAckState ack_result) { | |
623 AckTouchEventToClient(ack_result, *PopTouchEvent()); | |
551 } | 624 } |
552 | 625 |
553 void TouchEventQueue::PopTouchEventToClient( | 626 void TouchEventQueue::PopTouchEventToClient( |
554 InputEventAckState ack_result, | 627 InputEventAckState ack_result, |
555 const LatencyInfo& renderer_latency_info) { | 628 const LatencyInfo& renderer_latency_info) { |
629 scoped_ptr<CoalescedWebTouchEvent> acked_event = PopTouchEvent(); | |
630 if (acked_event->ignore_ack()) | |
631 return; | |
632 for (WebTouchEventWithLatencyList::iterator iter = acked_event->begin(), | |
633 end = acked_event->end(); | |
634 iter != end; ++iter) { | |
635 iter->latency.AddNewLatencyFrom(renderer_latency_info); | |
636 } | |
637 AckTouchEventToClient(ack_result, *acked_event); | |
638 } | |
639 | |
640 void TouchEventQueue::AckTouchEventToClient( | |
641 InputEventAckState ack_result, | |
642 const CoalescedWebTouchEvent& acked_event) { | |
556 DCHECK(!dispatching_touch_ack_); | 643 DCHECK(!dispatching_touch_ack_); |
557 if (touch_queue_.empty()) | 644 if (acked_event.ignore_ack()) |
558 return; | |
559 scoped_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front()); | |
560 touch_queue_.pop_front(); | |
561 | |
562 if (acked_event->ignore_ack()) | |
563 return; | 645 return; |
564 | 646 |
565 // Note that acking the touch-event may result in multiple gestures being sent | 647 // Note that acking the touch-event may result in multiple gestures being sent |
566 // to the renderer, or touch-events being queued. | 648 // to the renderer, or touch-events being queued. |
567 base::AutoReset<CoalescedWebTouchEvent*> | 649 base::AutoReset<const CoalescedWebTouchEvent*> |
568 dispatching_touch_ack(&dispatching_touch_ack_, acked_event.get()); | 650 dispatching_touch_ack(&dispatching_touch_ack_, &acked_event); |
569 | 651 |
570 for (WebTouchEventWithLatencyList::iterator iter = acked_event->begin(), | 652 for (WebTouchEventWithLatencyList::const_iterator iter = acked_event.begin(), |
571 end = acked_event->end(); | 653 end = acked_event.end(); |
572 iter != end; ++iter) { | 654 iter != end; ++iter) { |
573 iter->latency.AddNewLatencyFrom(renderer_latency_info); | |
574 client_->OnTouchEventAck((*iter), ack_result); | 655 client_->OnTouchEventAck((*iter), ack_result); |
575 } | 656 } |
576 } | 657 } |
577 | 658 |
659 scoped_ptr<CoalescedWebTouchEvent> TouchEventQueue::PopTouchEvent() { | |
660 DCHECK(!touch_queue_.empty()); | |
661 scoped_ptr<CoalescedWebTouchEvent> event(touch_queue_.front()); | |
662 touch_queue_.pop_front(); | |
663 return event.Pass(); | |
664 } | |
665 | |
578 TouchEventQueue::PreFilterResult | 666 TouchEventQueue::PreFilterResult |
579 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { | 667 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { |
580 if (timeout_handler_ && timeout_handler_->FilterEvent(event)) | 668 if (timeout_handler_ && timeout_handler_->FilterEvent(event)) |
581 return ACK_WITH_NO_CONSUMER_EXISTS; | 669 return ACK_WITH_NO_CONSUMER_EXISTS; |
582 | 670 |
583 if (touchmove_slop_suppressor_->FilterEvent(event)) | 671 if (touchmove_slop_suppressor_->FilterEvent(event)) |
584 return ACK_WITH_NOT_CONSUMED; | 672 return ACK_WITH_NOT_CONSUMED; |
585 | 673 |
586 if (touch_filtering_state_ == DROP_ALL_TOUCHES) | 674 if (touch_filtering_state_ == DROP_ALL_TOUCHES) |
587 return ACK_WITH_NO_CONSUMER_EXISTS; | 675 return ACK_WITH_NO_CONSUMER_EXISTS; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
635 } else if (event.type == WebInputEvent::TouchStart) { | 723 } else if (event.type == WebInputEvent::TouchStart) { |
636 for (unsigned i = 0; i < event.touchesLength; ++i) { | 724 for (unsigned i = 0; i < event.touchesLength; ++i) { |
637 const WebTouchPoint& point = event.touches[i]; | 725 const WebTouchPoint& point = event.touches[i]; |
638 if (point.state == WebTouchPoint::StatePressed) | 726 if (point.state == WebTouchPoint::StatePressed) |
639 touch_ack_states_[point.id] = ack_result; | 727 touch_ack_states_[point.id] = ack_result; |
640 } | 728 } |
641 } | 729 } |
642 } | 730 } |
643 | 731 |
644 } // namespace content | 732 } // namespace content |
OLD | NEW |