summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/browser/renderer_host/input/touch_event_queue.cc78
-rw-r--r--content/browser/renderer_host/input/touch_event_queue.h10
-rw-r--r--content/browser/renderer_host/input/touch_event_queue_unittest.cc134
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.