diff options
3 files changed, 82 insertions, 140 deletions
diff --git a/content/browser/renderer_host/input/touch_event_queue.cc b/content/browser/renderer_host/input/touch_event_queue.cc index 6ac63ce..6adc661 100644 --- a/content/browser/renderer_host/input/touch_event_queue.cc +++ b/content/browser/renderer_host/input/touch_event_queue.cc @@ -367,6 +367,7 @@ TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client, dispatching_touch_ack_(NULL), dispatching_touch_(false), has_handlers_(true), + has_handler_for_current_sequence_(false), drop_remaining_touches_in_sequence_(false), touchmove_slop_suppressor_(new TouchMoveSlopSuppressor), send_touch_events_async_(false), @@ -534,13 +535,13 @@ void TouchEventQueue::ForwardNextEventToRenderer() { void TouchEventQueue::OnGestureScrollEvent( const GestureEventWithLatencyInfo& gesture_event) { if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) { - if (!touch_consumer_states_.is_empty() && + if (has_handler_for_current_sequence_ && !drop_remaining_touches_in_sequence_) { DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves()) << "A touch handler should be offered a touchmove before scrolling."; } - if (!drop_remaining_touches_in_sequence_ && - touch_consumer_states_.is_empty()) { + if (!has_handler_for_current_sequence_ && + !drop_remaining_touches_in_sequence_) { // If no touch points have a consumer, prevent all subsequent touch events // received during the scroll from reaching the renderer. This ensures // that the first touchstart the renderer sees in any given sequence can @@ -683,14 +684,8 @@ void TouchEventQueue::SendTouchEventImmediately( TouchEventQueue::PreFilterResult TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { - if (timeout_handler_ && timeout_handler_->FilterEvent(event)) - return ACK_WITH_NO_CONSUMER_EXISTS; - - if (touchmove_slop_suppressor_->FilterEvent(event)) - return ACK_WITH_NOT_CONSUMED; - if (WebTouchEventTraits::IsTouchSequenceStart(event)) { - touch_consumer_states_.clear(); + has_handler_for_current_sequence_ = false; send_touch_events_async_ = false; pending_async_touchmove_.reset(); last_sent_touchevent_.reset(); @@ -703,22 +698,41 @@ TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { } } + if (timeout_handler_ && timeout_handler_->FilterEvent(event)) + return ACK_WITH_NO_CONSUMER_EXISTS; + + if (touchmove_slop_suppressor_->FilterEvent(event)) + return ACK_WITH_NOT_CONSUMED; + if (drop_remaining_touches_in_sequence_ && event.type != WebInputEvent::TouchCancel) { return ACK_WITH_NO_CONSUMER_EXISTS; } - if (event.type == WebInputEvent::TouchStart) - return has_handlers_ ? FORWARD_TO_RENDERER : ACK_WITH_NO_CONSUMER_EXISTS; + if (event.type == WebInputEvent::TouchStart) { + return (has_handlers_ || has_handler_for_current_sequence_) + ? FORWARD_TO_RENDERER + : ACK_WITH_NO_CONSUMER_EXISTS; + } + + if (has_handler_for_current_sequence_) { + // Only forward a touch if it has a non-stationary pointer that is active + // in the current touch sequence. + for (size_t i = 0; i < event.touchesLength; ++i) { + const WebTouchPoint& point = event.touches[i]; + if (point.state == WebTouchPoint::StateStationary) + continue; - for (unsigned int i = 0; i < event.touchesLength; ++i) { - const WebTouchPoint& point = event.touches[i]; - // If a point has been stationary, then don't take it into account. - if (point.state == WebTouchPoint::StateStationary) - continue; + // |last_sent_touchevent_| will be non-null as long as there is an + // active touch sequence being forwarded to the renderer. + if (!last_sent_touchevent_) + continue; - if (touch_consumer_states_.has_bit(point.id)) - return FORWARD_TO_RENDERER; + for (size_t j = 0; j < last_sent_touchevent_->touchesLength; ++j) { + if (point.id == last_sent_touchevent_->touches[j].id) + return FORWARD_TO_RENDERER; + } + } } return ACK_WITH_NO_CONSUMER_EXISTS; @@ -726,29 +740,13 @@ TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { void TouchEventQueue::UpdateTouchConsumerStates(const WebTouchEvent& event, InputEventAckState ack_result) { - // Update the ACK status for each touch point in the ACKed event. - if (event.type == WebInputEvent::TouchEnd || - event.type == WebInputEvent::TouchCancel) { - // The points have been released. Erase the ACK states. - for (unsigned i = 0; i < event.touchesLength; ++i) { - const WebTouchPoint& point = event.touches[i]; - if (point.state == WebTouchPoint::StateReleased || - point.state == WebTouchPoint::StateCancelled) - touch_consumer_states_.clear_bit(point.id); - } - } else if (event.type == WebInputEvent::TouchStart) { + if (event.type == WebInputEvent::TouchStart) { if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) send_touch_events_async_ = false; - - for (unsigned i = 0; i < event.touchesLength; ++i) { - const WebTouchPoint& point = event.touches[i]; - if (point.state == WebTouchPoint::StatePressed) { - if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) - touch_consumer_states_.mark_bit(point.id); - else - touch_consumer_states_.clear_bit(point.id); - } - } + has_handler_for_current_sequence_ |= + ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; + } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) { + has_handler_for_current_sequence_ = false; } } diff --git a/content/browser/renderer_host/input/touch_event_queue.h b/content/browser/renderer_host/input/touch_event_queue.h index 584935f..88e3e73 100644 --- a/content/browser/renderer_host/input/touch_event_queue.h +++ b/content/browser/renderer_host/input/touch_event_queue.h @@ -14,7 +14,6 @@ #include "content/common/content_export.h" #include "content/common/input/input_event_ack_state.h" #include "third_party/WebKit/public/web/WebInputEvent.h" -#include "ui/events/gesture_detection/bitset_32.h" #include "ui/gfx/geometry/point_f.h" namespace content { @@ -164,12 +163,6 @@ class CONTENT_EXPORT TouchEventQueue { typedef std::deque<CoalescedWebTouchEvent*> TouchQueue; TouchQueue touch_queue_; - // Maps whether each active pointer has a consumer (i.e., a touch point has a - // valid consumer iff |touch_consumer_states[pointer.id]| is true.). - // TODO(jdduke): Consider simply tracking whether *any* touchstart had a - // consumer, crbug.com/416497. - ui::BitSet32 touch_consumer_states_; - // Position of the first touch in the most recent sequence forwarded to the // client. gfx::PointF touch_sequence_start_position_; @@ -186,6 +179,9 @@ class CONTENT_EXPORT TouchEventQueue { // Whether the renderer has at least one touch handler. bool has_handlers_; + // Whether any pointer in the touch sequence reported having a consumer. + bool has_handler_for_current_sequence_; + // Whether to allow any remaining touches for the current sequence. Note that // this is a stricter condition than an empty |touch_consumer_states_|, as it // also prevents forwarding of touchstart events for new pointers in the diff --git a/content/browser/renderer_host/input/touch_event_queue_unittest.cc b/content/browser/renderer_host/input/touch_event_queue_unittest.cc index 5af6743..8d50b0b 100644 --- a/content/browser/renderer_host/input/touch_event_queue_unittest.cc +++ b/content/browser/renderer_host/input/touch_event_queue_unittest.cc @@ -371,10 +371,9 @@ TEST_F(TouchEventQueueTest, BasicMultiTouch) { EXPECT_EQ(kPointerCount - 1, GetAndResetSentEventCount()); } -// Tests that the touch-queue continues delivering events for an active pointer -// after all handlers are removed, but acks new pointers immediately as having -// no consumer. -TEST_F(TouchEventQueueTest, NoNewTouchesForwardedAfterHandlersRemoved) { +// Tests that the touch-queue continues delivering events for an active touch +// sequence after all handlers are removed. +TEST_F(TouchEventQueueTest, TouchesForwardedIfHandlerRemovedDuringSequence) { OnHasTouchEventHandlers(true); EXPECT_EQ(0U, queued_event_count()); EXPECT_EQ(0U, GetAndResetSentEventCount()); @@ -396,21 +395,27 @@ TEST_F(TouchEventQueueTest, NoNewTouchesForwardedAfterHandlersRemoved) { EXPECT_EQ(0U, queued_event_count()); EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, acked_event_state()); - // Try forwarding a new pointer. It should be rejected immediately. + // Try forwarding a new pointer. It should be forwarded as usual. PressTouchPoint(2, 2); + EXPECT_EQ(1U, GetAndResetSentEventCount()); + SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); EXPECT_EQ(1U, GetAndResetAckedEventCount()); EXPECT_EQ(0U, queued_event_count()); - EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state()); - // Further events for the pointer without a handler should not be forwarded. + // Further events for any pointer should be forwarded, even for pointers that + // reported no consumer. MoveTouchPoint(1, 3, 3); ReleaseTouchPoint(1); - EXPECT_EQ(2U, GetAndResetAckedEventCount()); - EXPECT_EQ(0U, queued_event_count()); - EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state()); + EXPECT_EQ(1U, GetAndResetSentEventCount()); + EXPECT_EQ(0U, GetAndResetAckedEventCount()); + SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); + EXPECT_EQ(1U, GetAndResetSentEventCount()); + EXPECT_EQ(1U, GetAndResetAckedEventCount()); + SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); + EXPECT_EQ(0U, GetAndResetSentEventCount()); + EXPECT_EQ(1U, GetAndResetAckedEventCount()); - // Events for the first pointer, that had a handler, should be forwarded, even - // if the renderer reports that no handlers exist. + // Events for the first pointer, that had a handler, should be forwarded. MoveTouchPoint(0, 4, 4); ReleaseTouchPoint(0); EXPECT_EQ(1U, GetAndResetSentEventCount()); @@ -728,113 +733,56 @@ TEST_F(TouchEventQueueTest, NoConsumer) { } TEST_F(TouchEventQueueTest, ConsumerIgnoreMultiFinger) { - // Press two touch points and move them around a bit. The renderer consumes - // the events for the first touch point, but returns NO_CONSUMER_EXISTS for - // the second touch point. - + // Interleave three pointer press, move and release events. PressTouchPoint(1, 1); - EXPECT_EQ(1U, GetAndResetSentEventCount()); - MoveTouchPoint(0, 5, 5); - PressTouchPoint(10, 10); - - MoveTouchPoint(0, 2, 2); - - MoveTouchPoint(1, 4, 10); - - MoveTouchPoints(0, 10, 10, 1, 20, 20); + MoveTouchPoint(1, 15, 15); + PressTouchPoint(20, 20); + MoveTouchPoint(2, 25, 25); + ReleaseTouchPoint(2); + MoveTouchPoint(1, 20, 20); + ReleaseTouchPoint(1); + MoveTouchPoint(0, 10, 10); + ReleaseTouchPoint(0); // Since the first touch-press is still pending ACK, no other event should // have been sent to the renderer. + EXPECT_EQ(1U, GetAndResetSentEventCount()); EXPECT_EQ(0U, GetAndResetSentEventCount()); - // The queue includes the two presses, the first touch-move of the first - // point, and a coalesced touch-move of both points. - EXPECT_EQ(4U, queued_event_count()); + EXPECT_EQ(11U, queued_event_count()); // ACK the first press as CONSUMED. This should cause the first touch-move of // the first touch-point to be dispatched. SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED); EXPECT_EQ(1U, GetAndResetSentEventCount()); - EXPECT_EQ(3U, queued_event_count()); + EXPECT_EQ(10U, queued_event_count()); // ACK the first move as CONSUMED. SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED); EXPECT_EQ(1U, GetAndResetSentEventCount()); - EXPECT_EQ(2U, queued_event_count()); + EXPECT_EQ(9U, queued_event_count()); - // ACK the second press as NO_CONSUMER_EXISTS. This will dequeue the coalesced - // touch-move event (which contains both touch points). Although the second - // touch-point does not need to be sent to the renderer, the first touch-point - // did move, and so the coalesced touch-event will be sent to the renderer. + // ACK the second press as NO_CONSUMER_EXISTS. The second pointer's touchmove + // should still be forwarded, despite lacking a direct consumer. SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); EXPECT_EQ(1U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, queued_event_count()); + EXPECT_EQ(8U, queued_event_count()); // ACK the coalesced move as NOT_CONSUMED. SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(0U, queued_event_count()); - - // Move just the second touch point. Because the first touch point did not - // move, this event should not reach the renderer. - MoveTouchPoint(1, 30, 30); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(0U, queued_event_count()); - - // Move just the first touch point. This should reach the renderer. - MoveTouchPoint(0, 10, 10); - EXPECT_EQ(1U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, queued_event_count()); - - // Move both fingers. This event should reach the renderer (after the ACK of - // the previous move event is received), because the first touch point did - // move. - MoveTouchPoints(0, 15, 15, 1, 25, 25); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - - SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED); EXPECT_EQ(1U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, queued_event_count()); - - SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(0U, queued_event_count()); - - // Release the first finger. Then move the second finger around some, then - // press another finger. Once the release event is ACKed, the move events of - // the second finger should be immediately released to the view, and the - // touch-press event should be dispatched to the renderer. - ReleaseTouchPoint(0); - EXPECT_EQ(1U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, queued_event_count()); - - MoveTouchPoint(1, 40, 40); - - MoveTouchPoint(1, 50, 50); + EXPECT_EQ(7U, queued_event_count()); - PressTouchPoint(1, 1); - - MoveTouchPoint(1, 30, 30); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(4U, queued_event_count()); - - SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - EXPECT_EQ(1U, GetAndResetSentEventCount()); - EXPECT_EQ(2U, queued_event_count()); - EXPECT_EQ(WebInputEvent::TouchMove, acked_event().type); - - // ACK the press with NO_CONSUMED_EXISTS. This should release the queued - // touch-move events to the view. + // All remaining touch events should be forwarded, even if the third pointer + // press also reports no consumer. SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(0U, queued_event_count()); - EXPECT_EQ(WebInputEvent::TouchMove, acked_event().type); + EXPECT_EQ(6U, queued_event_count()); - ReleaseTouchPoint(2); - ReleaseTouchPoint(1); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(0U, queued_event_count()); + while (queued_event_count()) + SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + + EXPECT_EQ(6U, GetAndResetSentEventCount()); } // Tests that touch-event's enqueued via a touch ack are properly handled. |