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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 49 event.type == WebInputEvent::TouchMove) && | 49 event.type == WebInputEvent::TouchMove) && |
| 50 !WebInputEventTraits::IgnoresAckDisposition(event); | 50 !WebInputEventTraits::IgnoresAckDisposition(event); |
| 51 } | 51 } |
| 52 | 52 |
| 53 bool OutsideApplicationSlopRegion(const WebTouchEvent& event, | 53 bool OutsideApplicationSlopRegion(const WebTouchEvent& event, |
| 54 const gfx::PointF& anchor) { | 54 const gfx::PointF& anchor) { |
| 55 return (gfx::PointF(event.touches[0].position) - anchor).LengthSquared() > | 55 return (gfx::PointF(event.touches[0].position) - anchor).LengthSquared() > |
| 56 kApplicationSlopRegionLengthDipsSqared; | 56 kApplicationSlopRegionLengthDipsSqared; |
| 57 } | 57 } |
| 58 | 58 |
| 59 // Compare all properties of touch points to determine the state. | |
| 60 bool HasPointChanged(const WebTouchPoint& last_point, | |
| 61 const WebTouchPoint& current_point) { | |
| 62 if (last_point.position != current_point.position || | |
| 63 last_point.radiusX != current_point.radiusX || | |
| 64 last_point.radiusY != current_point.radiusY || | |
| 65 last_point.rotationAngle != current_point.rotationAngle || | |
| 66 last_point.force != current_point.force || | |
| 67 last_point.screenPosition != current_point.screenPosition) { | |
|
jdduke (slow)
2015/01/29 16:53:19
Nit: Let's put the |screenPosition| comparison fir
USE s.singapati at gmail.com
2015/01/30 12:19:27
Done.
| |
| 68 return true; | |
| 69 } | |
| 70 return false; | |
| 71 } | |
| 72 | |
| 59 } // namespace | 73 } // namespace |
| 60 | 74 |
| 61 | 75 |
| 62 // Cancels a touch sequence if a touchstart or touchmove ack response is | 76 // Cancels a touch sequence if a touchstart or touchmove ack response is |
| 63 // sufficiently delayed. | 77 // sufficiently delayed. |
| 64 class TouchEventQueue::TouchTimeoutHandler { | 78 class TouchEventQueue::TouchTimeoutHandler { |
| 65 public: | 79 public: |
| 66 TouchTimeoutHandler(TouchEventQueue* touch_queue, | 80 TouchTimeoutHandler(TouchEventQueue* touch_queue, |
| 67 base::TimeDelta timeout_delay) | 81 base::TimeDelta timeout_delay) |
| 68 : touch_queue_(touch_queue), | 82 : touch_queue_(touch_queue), |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 100 case PENDING_ACK_NONE: | 114 case PENDING_ACK_NONE: |
| 101 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) | 115 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) |
| 102 enabled_for_current_sequence_ = false; | 116 enabled_for_current_sequence_ = false; |
| 103 timeout_monitor_.Stop(); | 117 timeout_monitor_.Stop(); |
| 104 return false; | 118 return false; |
| 105 case PENDING_ACK_ORIGINAL_EVENT: | 119 case PENDING_ACK_ORIGINAL_EVENT: |
| 106 if (AckedTimeoutEventRequiresCancel(ack_result)) { | 120 if (AckedTimeoutEventRequiresCancel(ack_result)) { |
| 107 SetPendingAckState(PENDING_ACK_CANCEL_EVENT); | 121 SetPendingAckState(PENDING_ACK_CANCEL_EVENT); |
| 108 TouchEventWithLatencyInfo cancel_event = | 122 TouchEventWithLatencyInfo cancel_event = |
| 109 ObtainCancelEventForTouchEvent(timeout_event_); | 123 ObtainCancelEventForTouchEvent(timeout_event_); |
| 110 touch_queue_->SendTouchEventImmediately(cancel_event); | 124 touch_queue_->SendTouchEventImmediately(&cancel_event); |
| 111 } else { | 125 } else { |
| 112 SetPendingAckState(PENDING_ACK_NONE); | 126 SetPendingAckState(PENDING_ACK_NONE); |
| 113 touch_queue_->UpdateTouchConsumerStates(timeout_event_.event, | 127 touch_queue_->UpdateTouchConsumerStates(timeout_event_.event, |
| 114 ack_result); | 128 ack_result); |
| 115 } | 129 } |
| 116 return true; | 130 return true; |
| 117 case PENDING_ACK_CANCEL_EVENT: | 131 case PENDING_ACK_CANCEL_EVENT: |
| 118 SetPendingAckState(PENDING_ACK_NONE); | 132 SetPendingAckState(PENDING_ACK_NONE); |
| 119 return true; | 133 return true; |
| 120 } | 134 } |
| (...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 508 if (pending_async_touchmove_->CanCoalesceWith(touch)) { | 522 if (pending_async_touchmove_->CanCoalesceWith(touch)) { |
| 509 pending_async_touchmove_->CoalesceWith(touch); | 523 pending_async_touchmove_->CoalesceWith(touch); |
| 510 pending_async_touchmove_->event.cancelable = !send_touch_events_async_; | 524 pending_async_touchmove_->event.cancelable = !send_touch_events_async_; |
| 511 touch = *pending_async_touchmove_; | 525 touch = *pending_async_touchmove_; |
| 512 pending_async_touchmove_.reset(); | 526 pending_async_touchmove_.reset(); |
| 513 } else { | 527 } else { |
| 514 scoped_ptr<TouchEventWithLatencyInfo> async_move = | 528 scoped_ptr<TouchEventWithLatencyInfo> async_move = |
| 515 pending_async_touchmove_.Pass(); | 529 pending_async_touchmove_.Pass(); |
| 516 async_move->event.cancelable = false; | 530 async_move->event.cancelable = false; |
| 517 touch_queue_.push_front(new CoalescedWebTouchEvent(*async_move, true)); | 531 touch_queue_.push_front(new CoalescedWebTouchEvent(*async_move, true)); |
| 518 SendTouchEventImmediately(*async_move); | 532 SendTouchEventImmediately(async_move.get()); |
| 519 return; | 533 return; |
| 520 } | 534 } |
| 521 } | 535 } |
| 522 | 536 |
| 523 // Note: Touchstart events are marked cancelable to allow transitions between | 537 // Note: Touchstart events are marked cancelable to allow transitions between |
| 524 // platform scrolling and JS pinching. Touchend events, however, remain | 538 // platform scrolling and JS pinching. Touchend events, however, remain |
| 525 // uncancelable, mitigating the risk of jank when transitioning to a fling. | 539 // uncancelable, mitigating the risk of jank when transitioning to a fling. |
| 526 if (send_touch_events_async_ && touch.event.type != WebInputEvent::TouchStart) | 540 if (send_touch_events_async_ && touch.event.type != WebInputEvent::TouchStart) |
| 527 touch.event.cancelable = false; | 541 touch.event.cancelable = false; |
| 528 | 542 |
| 529 // A synchronous ack will reset |dispatching_touch_|, in which case | 543 // A synchronous ack will reset |dispatching_touch_|, in which case |
| 530 // the touch timeout should not be started. | 544 // the touch timeout should not be started. |
| 531 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); | 545 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); |
| 532 SendTouchEventImmediately(touch); | 546 SendTouchEventImmediately(&touch); |
| 533 if (dispatching_touch_ && timeout_handler_) | 547 if (dispatching_touch_ && timeout_handler_) |
| 534 timeout_handler_->StartIfNecessary(touch); | 548 timeout_handler_->StartIfNecessary(touch); |
| 535 } | 549 } |
| 536 | 550 |
| 537 void TouchEventQueue::OnGestureScrollEvent( | 551 void TouchEventQueue::OnGestureScrollEvent( |
| 538 const GestureEventWithLatencyInfo& gesture_event) { | 552 const GestureEventWithLatencyInfo& gesture_event) { |
| 539 if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) { | 553 if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) { |
| 540 if (!touch_consumer_states_.is_empty() && | 554 if (!touch_consumer_states_.is_empty() && |
| 541 !drop_remaining_touches_in_sequence_) { | 555 !drop_remaining_touches_in_sequence_) { |
| 542 DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves()) | 556 DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves()) |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 686 } | 700 } |
| 687 | 701 |
| 688 scoped_ptr<CoalescedWebTouchEvent> TouchEventQueue::PopTouchEvent() { | 702 scoped_ptr<CoalescedWebTouchEvent> TouchEventQueue::PopTouchEvent() { |
| 689 DCHECK(!touch_queue_.empty()); | 703 DCHECK(!touch_queue_.empty()); |
| 690 scoped_ptr<CoalescedWebTouchEvent> event(touch_queue_.front()); | 704 scoped_ptr<CoalescedWebTouchEvent> event(touch_queue_.front()); |
| 691 touch_queue_.pop_front(); | 705 touch_queue_.pop_front(); |
| 692 return event.Pass(); | 706 return event.Pass(); |
| 693 } | 707 } |
| 694 | 708 |
| 695 void TouchEventQueue::SendTouchEventImmediately( | 709 void TouchEventQueue::SendTouchEventImmediately( |
| 696 const TouchEventWithLatencyInfo& touch) { | 710 TouchEventWithLatencyInfo* touch) { |
| 697 if (needs_async_touchmove_for_outer_slop_region_) { | 711 if (needs_async_touchmove_for_outer_slop_region_) { |
| 698 // Any event other than a touchmove (e.g., touchcancel or secondary | 712 // Any event other than a touchmove (e.g., touchcancel or secondary |
| 699 // touchstart) after a scroll has started will interrupt the need to send a | 713 // touchstart) after a scroll has started will interrupt the need to send a |
| 700 // an outer slop-region exceeding touchmove. | 714 // an outer slop-region exceeding touchmove. |
| 701 if (touch.event.type != WebInputEvent::TouchMove || | 715 if (touch->event.type != WebInputEvent::TouchMove || |
| 702 OutsideApplicationSlopRegion(touch.event, | 716 OutsideApplicationSlopRegion(touch->event, |
| 703 touch_sequence_start_position_)) | 717 touch_sequence_start_position_)) |
| 704 needs_async_touchmove_for_outer_slop_region_ = false; | 718 needs_async_touchmove_for_outer_slop_region_ = false; |
| 705 } | 719 } |
| 706 | 720 |
| 707 client_->SendTouchEventImmediately(touch); | 721 // For touchmove events, compare touch points position from current event |
| 722 // to last sent event and update touch points state. | |
| 723 if (touch->event.type == WebInputEvent::TouchMove) { | |
| 724 CHECK(last_sent_touchevent_); | |
| 725 for (unsigned int i = 0; i < last_sent_touchevent_->touchesLength; ++i) { | |
| 726 const WebTouchPoint& last_touch_point = | |
| 727 last_sent_touchevent_->touches[i]; | |
| 728 // Touches with same id may not have same index in Touches array. | |
| 729 for (unsigned int j = 0; j < touch->event.touchesLength; ++j) { | |
| 730 const WebTouchPoint& current_touchmove_point = touch->event.touches[j]; | |
| 731 if (current_touchmove_point.id != last_touch_point.id) | |
| 732 continue; | |
| 733 | |
| 734 if (!HasPointChanged(last_touch_point, current_touchmove_point)) | |
| 735 touch->event.touches[j].state = WebTouchPoint::StateStationary; | |
| 736 | |
| 737 break; | |
| 738 } | |
| 739 } | |
| 740 } | |
| 741 | |
| 742 if (last_sent_touchevent_) | |
| 743 *last_sent_touchevent_ = touch->event; | |
| 744 else | |
| 745 last_sent_touchevent_.reset(new WebTouchEvent(touch->event)); | |
| 746 | |
| 747 client_->SendTouchEventImmediately(*touch); | |
| 708 } | 748 } |
| 709 | 749 |
| 710 TouchEventQueue::PreFilterResult | 750 TouchEventQueue::PreFilterResult |
| 711 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { | 751 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { |
| 712 if (timeout_handler_ && timeout_handler_->FilterEvent(event)) | 752 if (timeout_handler_ && timeout_handler_->FilterEvent(event)) |
| 713 return ACK_WITH_NO_CONSUMER_EXISTS; | 753 return ACK_WITH_NO_CONSUMER_EXISTS; |
| 714 | 754 |
| 715 if (touchmove_slop_suppressor_->FilterEvent(event)) | 755 if (touchmove_slop_suppressor_->FilterEvent(event)) |
| 716 return ACK_WITH_NOT_CONSUMED; | 756 return ACK_WITH_NOT_CONSUMED; |
| 717 | 757 |
| 718 if (WebTouchEventTraits::IsTouchSequenceStart(event)) { | 758 if (WebTouchEventTraits::IsTouchSequenceStart(event)) { |
| 719 touch_consumer_states_.clear(); | 759 touch_consumer_states_.clear(); |
| 720 send_touch_events_async_ = false; | 760 send_touch_events_async_ = false; |
| 721 pending_async_touchmove_.reset(); | 761 pending_async_touchmove_.reset(); |
| 762 last_sent_touchevent_.reset(); | |
| 763 | |
| 722 touch_sequence_start_position_ = gfx::PointF(event.touches[0].position); | 764 touch_sequence_start_position_ = gfx::PointF(event.touches[0].position); |
| 723 drop_remaining_touches_in_sequence_ = false; | 765 drop_remaining_touches_in_sequence_ = false; |
| 724 if (!has_handlers_) { | 766 if (!has_handlers_) { |
| 725 drop_remaining_touches_in_sequence_ = true; | 767 drop_remaining_touches_in_sequence_ = true; |
| 726 return ACK_WITH_NO_CONSUMER_EXISTS; | 768 return ACK_WITH_NO_CONSUMER_EXISTS; |
| 727 } | 769 } |
| 728 } | 770 } |
| 729 | 771 |
| 730 if (drop_remaining_touches_in_sequence_ && | 772 if (drop_remaining_touches_in_sequence_ && |
| 731 event.type != WebInputEvent::TouchCancel) { | 773 event.type != WebInputEvent::TouchCancel) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 771 if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) | 813 if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) |
| 772 touch_consumer_states_.mark_bit(point.id); | 814 touch_consumer_states_.mark_bit(point.id); |
| 773 else | 815 else |
| 774 touch_consumer_states_.clear_bit(point.id); | 816 touch_consumer_states_.clear_bit(point.id); |
| 775 } | 817 } |
| 776 } | 818 } |
| 777 } | 819 } |
| 778 } | 820 } |
| 779 | 821 |
| 780 } // namespace content | 822 } // namespace content |
| OLD | NEW |