Index: content/browser/renderer_host/input/touch_event_queue_unittest.cc |
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 3e756566eda2d0b852c2cc7d012f7181a5901a3c..04534a176e729a3883ece67ab974c58d46af86cd 100644 |
--- a/content/browser/renderer_host/input/touch_event_queue_unittest.cc |
+++ b/content/browser/renderer_host/input/touch_event_queue_unittest.cc |
@@ -5,6 +5,8 @@ |
#include "base/basictypes.h" |
#include "base/logging.h" |
#include "base/memory/scoped_ptr.h" |
+#include "base/message_loop/message_loop.h" |
+#include "content/browser/renderer_host/input/timeout_monitor.h" |
#include "content/browser/renderer_host/input/touch_event_queue.h" |
#include "content/common/input/synthetic_web_input_event_builders.h" |
#include "testing/gtest/include/gtest/gtest.h" |
@@ -16,6 +18,9 @@ using blink::WebTouchEvent; |
using blink::WebTouchPoint; |
namespace content { |
+namespace { |
+const size_t kDefaultTouchTimeoutDelayMs = 10; |
+} |
class TouchEventQueueTest : public testing::Test, |
public TouchEventQueueClient { |
@@ -67,6 +72,10 @@ class TouchEventQueueTest : public testing::Test, |
protected: |
+ void SetUpForTimeoutTesting(size_t timeout_delay_ms) { |
+ queue_->SetAckTimeoutEnabled(true, timeout_delay_ms); |
+ } |
+ |
void SendTouchEvent(const WebTouchEvent& event) { |
queue_->QueueEvent(TouchEventWithLatencyInfo(event, ui::LatencyInfo())); |
} |
@@ -131,12 +140,24 @@ class TouchEventQueueTest : public testing::Test, |
queue_->FlushQueue(); |
} |
+ void SetEnableTouchForwarding(bool enabled) { |
+ queue_->no_touch_to_renderer_ = !enabled; |
+ } |
+ |
+ bool WillForwardTouchEvents() { |
+ return !queue_->no_touch_to_renderer_ && !queue_->HasTimeoutEvent(); |
+ } |
+ |
+ bool IsTimeoutRunning() { |
+ return queue_->IsTimeoutRunningForTesting(); |
+ } |
+ |
size_t queued_event_count() const { |
- return queue_->GetQueueSize(); |
+ return queue_->size(); |
} |
const WebTouchEvent& latest_event() const { |
- return queue_->GetLatestEvent().event; |
+ return queue_->GetLatestEventForTesting().event; |
} |
const WebTouchEvent& acked_event() const { |
@@ -170,6 +191,7 @@ class TouchEventQueueTest : public testing::Test, |
scoped_ptr<WebTouchEvent> followup_touch_event_; |
scoped_ptr<WebGestureEvent> followup_gesture_event_; |
scoped_ptr<InputEventAckState> sync_ack_result_; |
+ base::MessageLoopForUI message_loop_; |
}; |
@@ -707,7 +729,7 @@ TEST_F(TouchEventQueueTest, ImmediateAckWithFollowupEvents) { |
// Tests basic TouchEvent forwarding suppression. |
TEST_F(TouchEventQueueTest, NoTouchBasic) { |
// Disable TouchEvent forwarding. |
- set_no_touch_to_renderer(true); |
+ SetEnableTouchForwarding(false); |
MoveTouchPoint(0, 30, 5); |
SendTouchEvent(); |
EXPECT_EQ(0U, GetAndResetSentEventCount()); |
@@ -732,7 +754,7 @@ TEST_F(TouchEventQueueTest, NoTouchBasic) { |
EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
// Enable TouchEvent forwarding. |
- set_no_touch_to_renderer(false); |
+ SetEnableTouchForwarding(true); |
PressTouchPoint(80, 10); |
SendTouchEvent(); |
@@ -778,9 +800,9 @@ TEST_F(TouchEventQueueTest, NoTouchOnScroll) { |
WebGestureEvent followup_scroll; |
followup_scroll.type = WebInputEvent::GestureScrollBegin; |
SetFollowupEvent(followup_scroll); |
- ASSERT_FALSE(no_touch_to_renderer()); |
+ ASSERT_TRUE(WillForwardTouchEvents()); |
SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
- EXPECT_TRUE(no_touch_to_renderer()); |
+ EXPECT_FALSE(WillForwardTouchEvents()); |
EXPECT_EQ(1U, GetAndResetSentEventCount()); |
EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
EXPECT_EQ(2U, queued_event_count()); |
@@ -794,7 +816,7 @@ TEST_F(TouchEventQueueTest, NoTouchOnScroll) { |
EXPECT_EQ(0U, GetAndResetSentEventCount()); |
EXPECT_EQ(WebInputEvent::TouchStart, acked_event().type); |
- // TouchMove should not be sent to renderer. |
+ // TouchMove should not be sent to the renderer. |
MoveTouchPoint(0, 30, 5); |
SendTouchEvent(); |
EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
@@ -803,9 +825,9 @@ TEST_F(TouchEventQueueTest, NoTouchOnScroll) { |
// GestureScrollUpdates should not change affect touch forwarding. |
SendGestureEvent(WebInputEvent::GestureScrollUpdate); |
- EXPECT_TRUE(no_touch_to_renderer()); |
+ EXPECT_FALSE(WillForwardTouchEvents()); |
- // TouchEnd should not be sent to renderer. |
+ // TouchEnd should not be sent to the renderer. |
ReleaseTouchPoint(0); |
SendTouchEvent(); |
EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
@@ -814,7 +836,7 @@ TEST_F(TouchEventQueueTest, NoTouchOnScroll) { |
// GestureScrollEnd will resume the sending of TouchEvents to renderer. |
SendGestureEvent(blink::WebInputEvent::GestureScrollEnd); |
- EXPECT_FALSE(no_touch_to_renderer()); |
+ EXPECT_TRUE(WillForwardTouchEvents()); |
// Now TouchEvents should be forwarded normally. |
PressTouchPoint(80, 10); |
@@ -836,4 +858,262 @@ TEST_F(TouchEventQueueTest, NoTouchOnScroll) { |
EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
} |
+// Tests that the touch timeout is started when sending certain touch types. |
+TEST_F(TouchEventQueueTest, TouchTimeoutTypes) { |
+ SetUpForTimeoutTesting(kDefaultTouchTimeoutDelayMs); |
+ |
+ // Sending a TouchStart will start the timeout. |
+ PressTouchPoint(0, 1); |
+ SendTouchEvent(); |
+ EXPECT_TRUE(IsTimeoutRunning()); |
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ |
+ // A TouchMove should start the timeout. |
+ MoveTouchPoint(0, 5, 5); |
+ SendTouchEvent(); |
+ EXPECT_TRUE(IsTimeoutRunning()); |
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ |
+ // A TouchEnd should not start the timeout. |
+ ReleaseTouchPoint(0); |
+ SendTouchEvent(); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ |
+ // A TouchCancel should not start the timeout. |
+ PressTouchPoint(0, 1); |
+ SendTouchEvent(); |
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ ASSERT_FALSE(IsTimeoutRunning()); |
+ CancelTouchPoint(0); |
+ SendTouchEvent(); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+} |
+ |
+// Tests that a delayed TouchEvent ack will trigger a TouchCancel timeout, |
+// disabling touch forwarding until the next TouchStart is received after |
+// the timeout events are ack'ed. |
+TEST_F(TouchEventQueueTest, TouchTimeoutBasic) { |
+ SetUpForTimeoutTesting(kDefaultTouchTimeoutDelayMs); |
+ |
+ // Queue a TouchStart. |
+ GetAndResetSentEventCount(); |
+ GetAndResetAckedEventCount(); |
+ PressTouchPoint(0, 1); |
+ SendTouchEvent(); |
+ ASSERT_EQ(1U, GetAndResetSentEventCount()); |
+ ASSERT_EQ(0U, GetAndResetAckedEventCount()); |
+ EXPECT_TRUE(IsTimeoutRunning()); |
+ EXPECT_TRUE(WillForwardTouchEvents()); |
+ |
+ // Delay the ack. |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::MessageLoop::QuitClosure(), |
+ base::TimeDelta::FromMilliseconds(kDefaultTouchTimeoutDelayMs * 2)); |
+ base::MessageLoop::current()->Run(); |
+ |
+ // The timeout should have fired, sending a TouchCancel and ack'ing the |
+ // TouchStart immediately. TouchEvent forwarding is disabled until both |
+ // acks are received. |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ EXPECT_FALSE(WillForwardTouchEvents()); |
+ EXPECT_EQ(1U, GetAndResetSentEventCount()); |
+ EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
+ |
+ // Ack'ing the original event should have no effect; we're still waiting |
+ // on the cancel ack. |
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ EXPECT_FALSE(WillForwardTouchEvents()); |
+ EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
+ EXPECT_EQ(0U, GetAndResetSentEventCount()); |
+ |
+ // Touch events should not be forwarded until we receive the original acks. |
+ PressTouchPoint(0, 1); |
+ SendTouchEvent(); |
+ ASSERT_EQ(0U, GetAndResetSentEventCount()); |
+ ASSERT_EQ(1U, GetAndResetAckedEventCount()); |
+ |
+ // The synthetic TouchCancel ack should not reach the client, but should |
+ // resume touch forwarding. |
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(0U, GetAndResetSentEventCount()); |
+ EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
+ EXPECT_TRUE(WillForwardTouchEvents()); |
+ |
+ // Subsequent events should be handled normally. |
+ PressTouchPoint(0, 1); |
+ SendTouchEvent(); |
+ EXPECT_EQ(1U, GetAndResetSentEventCount()); |
+ EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
+} |
+ |
+// Tests that the timeout is never started if the renderer consumes |
+// a TouchEvent from the current touch sequence. |
+TEST_F(TouchEventQueueTest, NoTouchTimeoutIfRendererIsConsumingGesture) { |
+ SetUpForTimeoutTesting(kDefaultTouchTimeoutDelayMs); |
+ |
+ // Queue a TouchStart. |
+ PressTouchPoint(0, 1); |
+ SendTouchEvent(); |
+ ASSERT_TRUE(IsTimeoutRunning()); |
+ |
+ // Mark the event as consumed. This should prevent the timeout from |
+ // being activated on subsequent TouchEvents in this gesture. |
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ |
+ // A TouchMove should not start the timeout. |
+ MoveTouchPoint(0, 5, 5); |
+ SendTouchEvent(); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ |
+ // A TouchCancel should not start the timeout. |
+ CancelTouchPoint(0); |
+ SendTouchEvent(); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+} |
+ |
+// Tests that the timeout is never started if the ack is synchronous. |
+TEST_F(TouchEventQueueTest, NoTouchTimeoutIfAckIsSynchronous) { |
+ SetUpForTimeoutTesting(kDefaultTouchTimeoutDelayMs); |
+ |
+ // Queue a TouchStart. |
+ SetSyncAckResult(INPUT_EVENT_ACK_STATE_CONSUMED); |
+ ASSERT_FALSE(IsTimeoutRunning()); |
+ PressTouchPoint(0, 1); |
+ SendTouchEvent(); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+} |
+ |
+// Tests that a TouchCancel timeout plays nice when the timed out touch stream |
+// turns into a scroll gesture sequence. |
+TEST_F(TouchEventQueueTest, TouchTimeoutWithFollowupGesture) { |
+ SetUpForTimeoutTesting(kDefaultTouchTimeoutDelayMs); |
+ |
+ // Queue a TouchStart. |
+ PressTouchPoint(0, 1); |
+ SendTouchEvent(); |
+ EXPECT_TRUE(IsTimeoutRunning()); |
+ EXPECT_TRUE(WillForwardTouchEvents()); |
+ EXPECT_EQ(1U, GetAndResetSentEventCount()); |
+ |
+ // The cancelled sequence may turn into a scroll gesture. |
+ WebGestureEvent followup_scroll; |
+ followup_scroll.type = WebInputEvent::GestureScrollBegin; |
+ SetFollowupEvent(followup_scroll); |
+ |
+ // Delay the ack. |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::MessageLoop::QuitClosure(), |
+ base::TimeDelta::FromMilliseconds(kDefaultTouchTimeoutDelayMs * 2)); |
+ base::MessageLoop::current()->Run(); |
+ |
+ // The timeout should have fired, disabling touch forwarding until both acks |
+ // are received, acking the timed out event, and forwarding a TouchCancel. |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ EXPECT_FALSE(WillForwardTouchEvents()); |
+ EXPECT_EQ(1U, GetAndResetSentEventCount()); |
+ EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
+ |
+ // Ack the original event. |
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ EXPECT_FALSE(WillForwardTouchEvents()); |
+ |
+ // Ack the cancel event. Normally, this would resume touch forwarding, |
+ // but we're still within a scroll gesture so it remains disabled. |
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ EXPECT_FALSE(WillForwardTouchEvents()); |
+ |
+ // Try to forward a touch event. |
+ GetAndResetSentEventCount(); |
+ GetAndResetAckedEventCount(); |
+ PressTouchPoint(0, 1); |
+ SendTouchEvent(); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ EXPECT_EQ(0U, GetAndResetSentEventCount()); |
+ EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
+ |
+ // Now end the scroll sequence, resuming touch handling. |
+ SendGestureEvent(blink::WebInputEvent::GestureScrollEnd); |
+ EXPECT_TRUE(WillForwardTouchEvents()); |
+ PressTouchPoint(0, 1); |
+ SendTouchEvent(); |
+ EXPECT_TRUE(IsTimeoutRunning()); |
+ EXPECT_EQ(1U, GetAndResetSentEventCount()); |
+ EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
+} |
+ |
+// Tests that a TouchCancel timeout plays nice when the timed out touch stream |
+// turns into a scroll gesture sequence, but the original event acks are |
+// significantly delayed. |
+TEST_F(TouchEventQueueTest, TouchTimeoutWithFollowupGestureAndDelayedAck) { |
+ SetUpForTimeoutTesting(kDefaultTouchTimeoutDelayMs); |
+ |
+ // Queue a TouchStart. |
+ PressTouchPoint(0, 1); |
+ SendTouchEvent(); |
+ EXPECT_TRUE(IsTimeoutRunning()); |
+ EXPECT_TRUE(WillForwardTouchEvents()); |
+ EXPECT_EQ(1U, GetAndResetSentEventCount()); |
+ |
+ // The cancelled sequence may turn into a scroll gesture. |
+ WebGestureEvent followup_scroll; |
+ followup_scroll.type = WebInputEvent::GestureScrollBegin; |
+ SetFollowupEvent(followup_scroll); |
+ |
+ // Delay the ack. |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::MessageLoop::QuitClosure(), |
+ base::TimeDelta::FromMilliseconds(kDefaultTouchTimeoutDelayMs * 2)); |
+ base::MessageLoop::current()->Run(); |
+ |
+ // The timeout should have fired, disabling touch forwarding until both acks |
+ // are received, acking the timed out event, and forwarding a TouchCancel. |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ EXPECT_FALSE(WillForwardTouchEvents()); |
+ EXPECT_EQ(1U, GetAndResetSentEventCount()); |
+ EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
+ |
+ // Try to forward a touch event. |
+ GetAndResetSentEventCount(); |
+ GetAndResetAckedEventCount(); |
+ PressTouchPoint(0, 1); |
+ SendTouchEvent(); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ EXPECT_EQ(0U, GetAndResetSentEventCount()); |
+ EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
+ |
+ // Now end the scroll sequence. Events will not be forwarded until the two |
+ // outstanding touch acks are received. |
+ SendGestureEvent(blink::WebInputEvent::GestureScrollEnd); |
+ PressTouchPoint(0, 1); |
+ SendTouchEvent(); |
+ EXPECT_FALSE(IsTimeoutRunning()); |
+ EXPECT_EQ(0U, GetAndResetSentEventCount()); |
+ EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
+ |
+ // Ack the original and cancel events. Events will now be forwarded. |
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
+ EXPECT_EQ(0U, GetAndResetSentEventCount()); |
+ EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
+ |
+ PressTouchPoint(0, 1); |
+ SendTouchEvent(); |
+ EXPECT_TRUE(IsTimeoutRunning()); |
+ EXPECT_EQ(1U, GetAndResetSentEventCount()); |
+} |
+ |
} // namespace content |