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 <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
10 #include "base/macros.h" | 10 #include "base/macros.h" |
| 11 #include "base/memory/ptr_util.h" |
11 #include "base/metrics/histogram_macros.h" | 12 #include "base/metrics/histogram_macros.h" |
12 #include "base/stl_util.h" | |
13 #include "base/trace_event/trace_event.h" | 13 #include "base/trace_event/trace_event.h" |
14 #include "content/browser/renderer_host/input/timeout_monitor.h" | 14 #include "content/browser/renderer_host/input/timeout_monitor.h" |
15 #include "content/common/input/web_touch_event_traits.h" | 15 #include "content/common/input/web_touch_event_traits.h" |
16 #include "ui/gfx/geometry/point_f.h" | 16 #include "ui/gfx/geometry/point_f.h" |
17 | 17 |
18 using blink::WebInputEvent; | 18 using blink::WebInputEvent; |
19 using blink::WebTouchEvent; | 19 using blink::WebTouchEvent; |
20 using blink::WebTouchPoint; | 20 using blink::WebTouchPoint; |
21 using ui::LatencyInfo; | 21 using ui::LatencyInfo; |
22 | 22 |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 } | 254 } |
255 | 255 |
256 base::TimeDelta GetTimeoutDelay() const { | 256 base::TimeDelta GetTimeoutDelay() const { |
257 return use_mobile_timeout_ ? mobile_timeout_delay_ : desktop_timeout_delay_; | 257 return use_mobile_timeout_ ? mobile_timeout_delay_ : desktop_timeout_delay_; |
258 } | 258 } |
259 | 259 |
260 bool HasTimeoutEvent() const { | 260 bool HasTimeoutEvent() const { |
261 return pending_ack_state_ != PENDING_ACK_NONE; | 261 return pending_ack_state_ != PENDING_ACK_NONE; |
262 } | 262 } |
263 | 263 |
264 | |
265 TouchEventQueue* touch_queue_; | 264 TouchEventQueue* touch_queue_; |
266 | 265 |
267 // How long to wait on a touch ack before cancelling the touch sequence. | 266 // How long to wait on a touch ack before cancelling the touch sequence. |
268 const base::TimeDelta desktop_timeout_delay_; | 267 const base::TimeDelta desktop_timeout_delay_; |
269 const base::TimeDelta mobile_timeout_delay_; | 268 const base::TimeDelta mobile_timeout_delay_; |
270 bool use_mobile_timeout_; | 269 bool use_mobile_timeout_; |
271 | 270 |
272 // The touch event source for which we expect the next ack. | 271 // The touch event source for which we expect the next ack. |
273 PendingAckState pending_ack_state_; | 272 PendingAckState pending_ack_state_; |
274 | 273 |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 DCHECK(client); | 443 DCHECK(client); |
445 if (config.touch_ack_timeout_supported) { | 444 if (config.touch_ack_timeout_supported) { |
446 timeout_handler_.reset( | 445 timeout_handler_.reset( |
447 new TouchTimeoutHandler(this, | 446 new TouchTimeoutHandler(this, |
448 config.desktop_touch_ack_timeout_delay, | 447 config.desktop_touch_ack_timeout_delay, |
449 config.mobile_touch_ack_timeout_delay)); | 448 config.mobile_touch_ack_timeout_delay)); |
450 } | 449 } |
451 } | 450 } |
452 | 451 |
453 TouchEventQueue::~TouchEventQueue() { | 452 TouchEventQueue::~TouchEventQueue() { |
454 if (!touch_queue_.empty()) | |
455 base::STLDeleteElements(&touch_queue_); | |
456 } | 453 } |
457 | 454 |
458 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { | 455 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { |
459 TRACE_EVENT0("input", "TouchEventQueue::QueueEvent"); | 456 TRACE_EVENT0("input", "TouchEventQueue::QueueEvent"); |
460 | 457 |
461 // If the queueing of |event| was triggered by an ack dispatch, defer | 458 // If the queueing of |event| was triggered by an ack dispatch, defer |
462 // processing the event until the dispatch has finished. | 459 // processing the event until the dispatch has finished. |
463 if (touch_queue_.empty() && !dispatching_touch_ack_) { | 460 if (touch_queue_.empty() && !dispatching_touch_ack_) { |
464 // Optimization of the case without touch handlers. Removing this path | 461 // Optimization of the case without touch handlers. Removing this path |
465 // yields identical results, but this avoids unnecessary allocations. | 462 // yields identical results, but this avoids unnecessary allocations. |
466 PreFilterResult filter_result = FilterBeforeForwarding(event.event); | 463 PreFilterResult filter_result = FilterBeforeForwarding(event.event); |
467 if (filter_result != FORWARD_TO_RENDERER) { | 464 if (filter_result != FORWARD_TO_RENDERER) { |
468 client_->OnFilteringTouchEvent(event.event); | 465 client_->OnFilteringTouchEvent(event.event); |
469 client_->OnTouchEventAck(event, | 466 client_->OnTouchEventAck(event, |
470 filter_result == ACK_WITH_NO_CONSUMER_EXISTS | 467 filter_result == ACK_WITH_NO_CONSUMER_EXISTS |
471 ? INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS | 468 ? INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS |
472 : INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 469 : INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
473 return; | 470 return; |
474 } | 471 } |
475 | 472 |
476 // There is no touch event in the queue. Forward it to the renderer | 473 // There is no touch event in the queue. Forward it to the renderer |
477 // immediately. | 474 // immediately. |
478 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); | 475 touch_queue_.push_back( |
| 476 base::MakeUnique<CoalescedWebTouchEvent>(event, false)); |
479 ForwardNextEventToRenderer(); | 477 ForwardNextEventToRenderer(); |
480 return; | 478 return; |
481 } | 479 } |
482 | 480 |
483 // If the last queued touch-event was a touch-move, and the current event is | 481 // If the last queued touch-event was a touch-move, and the current event is |
484 // also a touch-move, then the events can be coalesced into a single event. | 482 // also a touch-move, then the events can be coalesced into a single event. |
485 if (touch_queue_.size() > 1) { | 483 if (touch_queue_.size() > 1) { |
486 CoalescedWebTouchEvent* last_event = touch_queue_.back(); | 484 CoalescedWebTouchEvent* last_event = touch_queue_.back().get(); |
487 if (last_event->CoalesceEventIfPossible(event)) | 485 if (last_event->CoalesceEventIfPossible(event)) |
488 return; | 486 return; |
489 } | 487 } |
490 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); | 488 touch_queue_.push_back( |
| 489 base::MakeUnique<CoalescedWebTouchEvent>(event, false)); |
491 } | 490 } |
492 | 491 |
493 void TouchEventQueue::PrependTouchScrollNotification() { | 492 void TouchEventQueue::PrependTouchScrollNotification() { |
494 TRACE_EVENT0("input", "TouchEventQueue::PrependTouchScrollNotification"); | 493 TRACE_EVENT0("input", "TouchEventQueue::PrependTouchScrollNotification"); |
495 | 494 |
496 // The queue should have an in-flight event when this method is called because | 495 // The queue should have an in-flight event when this method is called because |
497 // this method is triggered by InputRouterImpl::SendGestureEvent, which is | 496 // this method is triggered by InputRouterImpl::SendGestureEvent, which is |
498 // triggered by TouchEventQueue::AckTouchEventToClient, which has just | 497 // triggered by TouchEventQueue::AckTouchEventToClient, which has just |
499 // received an ack for the in-flight event. We leave the head of the queue | 498 // received an ack for the in-flight event. We leave the head of the queue |
500 // untouched since it is the in-flight event. | 499 // untouched since it is the in-flight event. |
501 // | 500 // |
502 // However, for the (integration) tests in RenderWidgetHostTest that trigger | 501 // However, for the (integration) tests in RenderWidgetHostTest that trigger |
503 // this method indirectly, they push the TouchScrollStarted event into | 502 // this method indirectly, they push the TouchScrollStarted event into |
504 // TouchEventQueue without any way to dispatch it. Below we added a check for | 503 // TouchEventQueue without any way to dispatch it. Below we added a check for |
505 // non-empty queue to keep those tests as-is w/o exposing internals of this | 504 // non-empty queue to keep those tests as-is w/o exposing internals of this |
506 // class all the way up. | 505 // class all the way up. |
507 if (!touch_queue_.empty()) { | 506 if (!touch_queue_.empty()) { |
508 TouchEventWithLatencyInfo touch; | 507 TouchEventWithLatencyInfo touch; |
509 touch.event.type = WebInputEvent::TouchScrollStarted; | 508 touch.event.type = WebInputEvent::TouchScrollStarted; |
510 touch.event.uniqueTouchEventId = 0; | 509 touch.event.uniqueTouchEventId = 0; |
511 touch.event.touchesLength = 0; | 510 touch.event.touchesLength = 0; |
512 touch.event.dispatchType = WebInputEvent::EventNonBlocking; | 511 touch.event.dispatchType = WebInputEvent::EventNonBlocking; |
513 | 512 |
514 auto it = touch_queue_.begin(); | 513 auto it = touch_queue_.begin(); |
515 DCHECK(it != touch_queue_.end()); | 514 DCHECK(it != touch_queue_.end()); |
516 touch_queue_.insert(++it, new CoalescedWebTouchEvent(touch, false)); | 515 touch_queue_.insert(++it, |
| 516 base::MakeUnique<CoalescedWebTouchEvent>(touch, false)); |
517 } | 517 } |
518 } | 518 } |
519 | 519 |
520 void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result, | 520 void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result, |
521 const LatencyInfo& latency_info, | 521 const LatencyInfo& latency_info, |
522 const uint32_t unique_touch_event_id) { | 522 const uint32_t unique_touch_event_id) { |
523 TRACE_EVENT0("input", "TouchEventQueue::ProcessTouchAck"); | 523 TRACE_EVENT0("input", "TouchEventQueue::ProcessTouchAck"); |
524 | 524 |
525 // We receive an ack for async touchmove from render. | 525 // We receive an ack for async touchmove from render. |
526 if (!ack_pending_async_touchmove_ids_.empty() && | 526 if (!ack_pending_async_touchmove_ids_.empty() && |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
653 touch.event.dispatchType = WebInputEvent::EventNonBlocking; | 653 touch.event.dispatchType = WebInputEvent::EventNonBlocking; |
654 | 654 |
655 SendTouchEventImmediately(&touch); | 655 SendTouchEventImmediately(&touch); |
656 } | 656 } |
657 | 657 |
658 void TouchEventQueue::FlushPendingAsyncTouchmove() { | 658 void TouchEventQueue::FlushPendingAsyncTouchmove() { |
659 DCHECK(!dispatching_touch_); | 659 DCHECK(!dispatching_touch_); |
660 std::unique_ptr<TouchEventWithLatencyInfo> touch = | 660 std::unique_ptr<TouchEventWithLatencyInfo> touch = |
661 std::move(pending_async_touchmove_); | 661 std::move(pending_async_touchmove_); |
662 touch->event.dispatchType = WebInputEvent::EventNonBlocking; | 662 touch->event.dispatchType = WebInputEvent::EventNonBlocking; |
663 touch_queue_.push_front(new CoalescedWebTouchEvent(*touch, true)); | 663 touch_queue_.push_front( |
| 664 base::MakeUnique<CoalescedWebTouchEvent>(*touch, true)); |
664 SendTouchEventImmediately(touch.get()); | 665 SendTouchEventImmediately(touch.get()); |
665 } | 666 } |
666 | 667 |
667 void TouchEventQueue::OnGestureScrollEvent( | 668 void TouchEventQueue::OnGestureScrollEvent( |
668 const GestureEventWithLatencyInfo& gesture_event) { | 669 const GestureEventWithLatencyInfo& gesture_event) { |
669 if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) { | 670 if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) { |
670 if (has_handler_for_current_sequence_ && | 671 if (has_handler_for_current_sequence_ && |
671 !drop_remaining_touches_in_sequence_) { | 672 !drop_remaining_touches_in_sequence_) { |
672 DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves()) | 673 DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves()) |
673 << "A touch handler should be offered a touchmove before scrolling."; | 674 << "A touch handler should be offered a touchmove before scrolling."; |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
763 } | 764 } |
764 | 765 |
765 void TouchEventQueue::AckTouchEventToClient( | 766 void TouchEventQueue::AckTouchEventToClient( |
766 InputEventAckState ack_result, | 767 InputEventAckState ack_result, |
767 const ui::LatencyInfo* optional_latency_info) { | 768 const ui::LatencyInfo* optional_latency_info) { |
768 DCHECK(!dispatching_touch_ack_); | 769 DCHECK(!dispatching_touch_ack_); |
769 if (touch_queue_.empty()) { | 770 if (touch_queue_.empty()) { |
770 NOTREACHED() << "Too many acks"; | 771 NOTREACHED() << "Too many acks"; |
771 return; | 772 return; |
772 } | 773 } |
773 std::unique_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front()); | 774 std::unique_ptr<CoalescedWebTouchEvent> acked_event = |
| 775 std::move(touch_queue_.front()); |
774 DCHECK(acked_event); | 776 DCHECK(acked_event); |
775 | 777 |
776 UpdateTouchConsumerStates(acked_event->coalesced_event().event, ack_result); | 778 UpdateTouchConsumerStates(acked_event->coalesced_event().event, ack_result); |
777 | 779 |
778 // Note that acking the touch-event may result in multiple gestures being sent | 780 // Note that acking the touch-event may result in multiple gestures being sent |
779 // to the renderer, or touch-events being queued. | 781 // to the renderer, or touch-events being queued. |
780 base::AutoReset<bool> dispatching_touch_ack(&dispatching_touch_ack_, true); | 782 base::AutoReset<bool> dispatching_touch_ack(&dispatching_touch_ack_, true); |
781 | 783 |
782 // Skip ack for TouchScrollStarted since it was synthesized within the queue. | 784 // Skip ack for TouchScrollStarted since it was synthesized within the queue. |
783 if (acked_event->coalesced_event().event.type != | 785 if (acked_event->coalesced_event().event.type != |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
934 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) | 936 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) |
935 send_touch_events_async_ = false; | 937 send_touch_events_async_ = false; |
936 has_handler_for_current_sequence_ |= | 938 has_handler_for_current_sequence_ |= |
937 ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; | 939 ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; |
938 } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) { | 940 } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) { |
939 has_handler_for_current_sequence_ = false; | 941 has_handler_for_current_sequence_ = false; |
940 } | 942 } |
941 } | 943 } |
942 | 944 |
943 } // namespace content | 945 } // namespace content |
OLD | NEW |