Chromium Code Reviews| 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/stl_util.h" | 8 #include "base/stl_util.h" |
| 9 #include "base/trace_event/trace_event.h" | 9 #include "base/trace_event/trace_event.h" |
| 10 #include "content/browser/renderer_host/input/timeout_monitor.h" | 10 #include "content/browser/renderer_host/input/timeout_monitor.h" |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 35 WebInputEvent::TouchCancel, | 35 WebInputEvent::TouchCancel, |
| 36 // TODO(rbyers): Shouldn't we use a fresh timestamp? | 36 // TODO(rbyers): Shouldn't we use a fresh timestamp? |
| 37 event.event.timeStampSeconds, | 37 event.event.timeStampSeconds, |
| 38 &event.event); | 38 &event.event); |
| 39 return event; | 39 return event; |
| 40 } | 40 } |
| 41 | 41 |
| 42 bool ShouldTouchTriggerTimeout(const WebTouchEvent& event) { | 42 bool ShouldTouchTriggerTimeout(const WebTouchEvent& event) { |
| 43 return (event.type == WebInputEvent::TouchStart || | 43 return (event.type == WebInputEvent::TouchStart || |
| 44 event.type == WebInputEvent::TouchMove) && | 44 event.type == WebInputEvent::TouchMove) && |
| 45 !WebInputEventTraits::IgnoresAckDisposition(event); | 45 event.cancelable; |
| 46 } | 46 } |
| 47 | 47 |
| 48 // Compare all properties of touch points to determine the state. | 48 // Compare all properties of touch points to determine the state. |
| 49 bool HasPointChanged(const WebTouchPoint& point_1, | 49 bool HasPointChanged(const WebTouchPoint& point_1, |
| 50 const WebTouchPoint& point_2) { | 50 const WebTouchPoint& point_2) { |
| 51 DCHECK_EQ(point_1.id, point_2.id); | 51 DCHECK_EQ(point_1.id, point_2.id); |
| 52 if (point_1.screenPosition != point_2.screenPosition || | 52 if (point_1.screenPosition != point_2.screenPosition || |
| 53 point_1.position != point_2.position || | 53 point_1.position != point_2.position || |
| 54 point_1.radiusX != point_2.radiusX || | 54 point_1.radiusX != point_2.radiusX || |
| 55 point_1.radiusY != point_2.radiusY || | 55 point_1.radiusY != point_2.radiusY || |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 75 timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut, | 75 timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut, |
| 76 base::Unretained(this))), | 76 base::Unretained(this))), |
| 77 enabled_(true), | 77 enabled_(true), |
| 78 enabled_for_current_sequence_(false) { | 78 enabled_for_current_sequence_(false) { |
| 79 DCHECK(timeout_delay != base::TimeDelta()); | 79 DCHECK(timeout_delay != base::TimeDelta()); |
| 80 } | 80 } |
| 81 | 81 |
| 82 ~TouchTimeoutHandler() {} | 82 ~TouchTimeoutHandler() {} |
| 83 | 83 |
| 84 void StartIfNecessary(const TouchEventWithLatencyInfo& event) { | 84 void StartIfNecessary(const TouchEventWithLatencyInfo& event) { |
| 85 DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE); | 85 if (pending_ack_state_ != PENDING_ACK_NONE) |
| 86 return; | |
| 87 | |
| 86 if (!enabled_) | 88 if (!enabled_) |
| 87 return; | 89 return; |
| 88 | 90 |
| 89 if (!ShouldTouchTriggerTimeout(event.event)) | 91 if (!ShouldTouchTriggerTimeout(event.event)) |
| 90 return; | 92 return; |
| 91 | 93 |
| 92 if (WebTouchEventTraits::IsTouchSequenceStart(event.event)) | 94 if (WebTouchEventTraits::IsTouchSequenceStart(event.event)) |
| 93 enabled_for_current_sequence_ = true; | 95 enabled_for_current_sequence_ = true; |
| 94 | 96 |
| 95 if (!enabled_for_current_sequence_) | 97 if (!enabled_for_current_sequence_) |
| (...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 413 // also a touch-move, then the events can be coalesced into a single event. | 415 // also a touch-move, then the events can be coalesced into a single event. |
| 414 if (touch_queue_.size() > 1) { | 416 if (touch_queue_.size() > 1) { |
| 415 CoalescedWebTouchEvent* last_event = touch_queue_.back(); | 417 CoalescedWebTouchEvent* last_event = touch_queue_.back(); |
| 416 if (last_event->CoalesceEventIfPossible(event)) | 418 if (last_event->CoalesceEventIfPossible(event)) |
| 417 return; | 419 return; |
| 418 } | 420 } |
| 419 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); | 421 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); |
| 420 } | 422 } |
| 421 | 423 |
| 422 void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result, | 424 void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result, |
| 423 const LatencyInfo& latency_info) { | 425 const LatencyInfo& latency_info, |
| 426 const uint32 unique_touch_event_id) { | |
| 424 TRACE_EVENT0("input", "TouchEventQueue::ProcessTouchAck"); | 427 TRACE_EVENT0("input", "TouchEventQueue::ProcessTouchAck"); |
| 425 | 428 |
| 429 // We receive an ack for async touchmove from render. | |
| 430 if (!ack_pending_async_touchmove_.empty() && | |
| 431 ack_pending_async_touchmove_.front() == unique_touch_event_id) { | |
| 432 // Remove the first touchmove from the ack_pending_async_touchmove queue. | |
| 433 ack_pending_async_touchmove_.pop_front(); | |
| 434 // Send the next pending async touch move once we receive all acks back. | |
| 435 if (pending_async_touchmove_ && ack_pending_async_touchmove_.empty()) { | |
| 436 TouchEventWithLatencyInfo touch = *pending_async_touchmove_; | |
| 437 | |
| 438 // Dispatch the next pending async touch move when time expires. | |
| 439 if (touch.event.timeStampSeconds >= | |
| 440 last_sent_touch_timestamp_sec_ + kAsyncTouchMoveIntervalSec) { | |
| 441 touch.event.cancelable = false; | |
| 442 pending_async_touchmove_.reset(); | |
| 443 touch_queue_.push_front(new CoalescedWebTouchEvent(touch, true)); | |
| 444 SendTouchEventImmediately(&touch); | |
| 445 } | |
| 446 } | |
| 447 return; | |
| 448 } | |
| 449 | |
| 426 DCHECK(!dispatching_touch_ack_); | 450 DCHECK(!dispatching_touch_ack_); |
| 427 dispatching_touch_ = false; | 451 dispatching_touch_ = false; |
| 428 | 452 |
| 429 if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result)) | 453 if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result)) |
| 430 return; | 454 return; |
| 431 | 455 |
| 432 touchmove_slop_suppressor_->ConfirmTouchEvent(ack_result); | 456 touchmove_slop_suppressor_->ConfirmTouchEvent(ack_result); |
| 433 | 457 |
| 434 if (touch_queue_.empty()) | 458 if (touch_queue_.empty()) |
| 435 return; | 459 return; |
| 436 | 460 |
| 461 if (touch_queue_.front()->coalesced_event().event.uniqueTouchEventId != | |
|
jdduke (slow)
2015/05/01 19:11:09
This should probably be a DCHECK_EQ instead of an
lanwei
2015/05/07 04:11:37
Done.
| |
| 462 unique_touch_event_id) | |
| 463 return; | |
| 464 | |
| 437 PopTouchEventToClient(ack_result, latency_info); | 465 PopTouchEventToClient(ack_result, latency_info); |
| 438 TryForwardNextEventToRenderer(); | 466 TryForwardNextEventToRenderer(); |
| 439 } | 467 } |
| 440 | 468 |
| 441 void TouchEventQueue::TryForwardNextEventToRenderer() { | 469 void TouchEventQueue::TryForwardNextEventToRenderer() { |
| 442 DCHECK(!dispatching_touch_ack_); | 470 DCHECK(!dispatching_touch_ack_); |
| 443 // If there are queued touch events, then try to forward them to the renderer | 471 // If there are queued touch events, then try to forward them to the renderer |
| 444 // immediately, or ACK the events back to the client if appropriate. | 472 // immediately, or ACK the events back to the client if appropriate. |
| 445 while (!touch_queue_.empty()) { | 473 while (!touch_queue_.empty()) { |
| 446 PreFilterResult filter_result = | 474 PreFilterResult filter_result = |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 470 touch.event.type == WebInputEvent::TouchMove) { | 498 touch.event.type == WebInputEvent::TouchMove) { |
| 471 // Throttling touchmove's in a continuous touchmove stream while scrolling | 499 // Throttling touchmove's in a continuous touchmove stream while scrolling |
| 472 // reduces the risk of jank. However, it's still important that the web | 500 // reduces the risk of jank. However, it's still important that the web |
| 473 // application be sent touches at key points in the gesture stream, | 501 // application be sent touches at key points in the gesture stream, |
| 474 // e.g., when the application slop region is exceeded or touchmove | 502 // e.g., when the application slop region is exceeded or touchmove |
| 475 // coalescing fails because of different modifiers. | 503 // coalescing fails because of different modifiers. |
| 476 bool send_touchmove_now = size() > 1; | 504 bool send_touchmove_now = size() > 1; |
| 477 send_touchmove_now |= pending_async_touchmove_ && | 505 send_touchmove_now |= pending_async_touchmove_ && |
| 478 !pending_async_touchmove_->CanCoalesceWith(touch); | 506 !pending_async_touchmove_->CanCoalesceWith(touch); |
| 479 send_touchmove_now |= | 507 send_touchmove_now |= |
| 480 touch.event.timeStampSeconds >= | 508 ack_pending_async_touchmove_.empty() && |
| 481 last_sent_touch_timestamp_sec_ + kAsyncTouchMoveIntervalSec; | 509 (touch.event.timeStampSeconds >= |
| 510 last_sent_touch_timestamp_sec_ + kAsyncTouchMoveIntervalSec); | |
| 482 | 511 |
| 483 if (!send_touchmove_now) { | 512 if (!send_touchmove_now) { |
| 484 if (!pending_async_touchmove_) { | 513 if (!pending_async_touchmove_) { |
| 485 pending_async_touchmove_.reset(new TouchEventWithLatencyInfo(touch)); | 514 pending_async_touchmove_.reset(new TouchEventWithLatencyInfo(touch)); |
| 486 } else { | 515 } else { |
| 487 DCHECK(pending_async_touchmove_->CanCoalesceWith(touch)); | 516 DCHECK(pending_async_touchmove_->CanCoalesceWith(touch)); |
| 488 pending_async_touchmove_->CoalesceWith(touch); | 517 pending_async_touchmove_->CoalesceWith(touch); |
| 489 } | 518 } |
| 490 DCHECK_EQ(1U, size()); | 519 DCHECK_EQ(1U, size()); |
| 491 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 520 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 518 return; | 547 return; |
| 519 } | 548 } |
| 520 } | 549 } |
| 521 | 550 |
| 522 // Note: Touchstart events are marked cancelable to allow transitions between | 551 // Note: Touchstart events are marked cancelable to allow transitions between |
| 523 // platform scrolling and JS pinching. Touchend events, however, remain | 552 // platform scrolling and JS pinching. Touchend events, however, remain |
| 524 // uncancelable, mitigating the risk of jank when transitioning to a fling. | 553 // uncancelable, mitigating the risk of jank when transitioning to a fling. |
| 525 if (send_touch_events_async_ && touch.event.type != WebInputEvent::TouchStart) | 554 if (send_touch_events_async_ && touch.event.type != WebInputEvent::TouchStart) |
| 526 touch.event.cancelable = false; | 555 touch.event.cancelable = false; |
| 527 | 556 |
| 528 // A synchronous ack will reset |dispatching_touch_|, in which case | |
| 529 // the touch timeout should not be started. | |
| 530 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); | |
| 531 SendTouchEventImmediately(&touch); | 557 SendTouchEventImmediately(&touch); |
| 532 if (dispatching_touch_ && timeout_handler_) | |
| 533 timeout_handler_->StartIfNecessary(touch); | |
| 534 } | 558 } |
| 535 | 559 |
| 536 void TouchEventQueue::OnGestureScrollEvent( | 560 void TouchEventQueue::OnGestureScrollEvent( |
| 537 const GestureEventWithLatencyInfo& gesture_event) { | 561 const GestureEventWithLatencyInfo& gesture_event) { |
| 538 if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) { | 562 if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) { |
| 539 if (has_handler_for_current_sequence_ && | 563 if (has_handler_for_current_sequence_ && |
| 540 !drop_remaining_touches_in_sequence_) { | 564 !drop_remaining_touches_in_sequence_) { |
| 541 DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves()) | 565 DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves()) |
| 542 << "A touch handler should be offered a touchmove before scrolling."; | 566 << "A touch handler should be offered a touchmove before scrolling."; |
| 543 } | 567 } |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 663 break; | 687 break; |
| 664 } | 688 } |
| 665 } | 689 } |
| 666 } | 690 } |
| 667 | 691 |
| 668 if (last_sent_touchevent_) | 692 if (last_sent_touchevent_) |
| 669 *last_sent_touchevent_ = touch->event; | 693 *last_sent_touchevent_ = touch->event; |
| 670 else | 694 else |
| 671 last_sent_touchevent_.reset(new WebTouchEvent(touch->event)); | 695 last_sent_touchevent_.reset(new WebTouchEvent(touch->event)); |
| 672 | 696 |
| 697 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); | |
| 698 | |
| 673 client_->SendTouchEventImmediately(*touch); | 699 client_->SendTouchEventImmediately(*touch); |
| 700 | |
| 701 // A synchronous ack will reset |dispatching_touch_|, in which case the touch | |
| 702 // timeout should not be started and the count also should not be increased. | |
| 703 if (dispatching_touch_) { | |
| 704 if (touch->event.type == WebInputEvent::TouchMove && | |
| 705 !touch->event.cancelable) { | |
| 706 // When we send out a uncancelable touch move, we increase the count and | |
| 707 // we do not process input event ack any more, we will just ack to client | |
| 708 // and wait for the ack from render. Also we will remove it from the front | |
| 709 // of the queue. | |
| 710 ack_pending_async_touchmove_.push_back(touch->event.uniqueTouchEventId); | |
| 711 PopTouchEvent(); | |
| 712 dispatching_touch_ = false; | |
| 713 client_->OnTouchEventAck(*touch, INPUT_EVENT_ACK_STATE_IGNORED); | |
| 714 TryForwardNextEventToRenderer(); | |
| 715 } | |
| 716 | |
| 717 if (timeout_handler_) | |
| 718 timeout_handler_->StartIfNecessary(*touch); | |
| 719 } | |
| 674 } | 720 } |
| 675 | 721 |
| 676 TouchEventQueue::PreFilterResult | 722 TouchEventQueue::PreFilterResult |
| 677 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { | 723 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { |
| 678 if (WebTouchEventTraits::IsTouchSequenceStart(event)) { | 724 if (WebTouchEventTraits::IsTouchSequenceStart(event)) { |
| 679 has_handler_for_current_sequence_ = false; | 725 has_handler_for_current_sequence_ = false; |
| 680 send_touch_events_async_ = false; | 726 send_touch_events_async_ = false; |
| 681 pending_async_touchmove_.reset(); | 727 pending_async_touchmove_.reset(); |
| 682 last_sent_touchevent_.reset(); | 728 last_sent_touchevent_.reset(); |
| 683 | 729 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 750 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) | 796 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) |
| 751 send_touch_events_async_ = false; | 797 send_touch_events_async_ = false; |
| 752 has_handler_for_current_sequence_ |= | 798 has_handler_for_current_sequence_ |= |
| 753 ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; | 799 ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; |
| 754 } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) { | 800 } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) { |
| 755 has_handler_for_current_sequence_ = false; | 801 has_handler_for_current_sequence_ = false; |
| 756 } | 802 } |
| 757 } | 803 } |
| 758 | 804 |
| 759 } // namespace content | 805 } // namespace content |
| OLD | NEW |