Commit a3f1d98f authored by jdduke@chromium.org's avatar jdduke@chromium.org

Allow exclusive touchmove slop regions in the TouchEventQueue

Aura's current slop region is boundary exclusive, whereas Android's is boundary
inclusive.  With the unified GR, both platforms will use a boundary inclusive
slop region, but until such time the TouchEventQueue should support either
model.  Allow this distinction via a configurable TouchEventQueue::Config
parameter.

BUG=354763

Review URL: https://codereview.chromium.org/273933002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@269496 0039d316-1c4b-4281-b951-d872f2087c98
parent 063854ec
...@@ -60,6 +60,8 @@ TouchEventQueue::Config GetTouchEventQueueConfig() { ...@@ -60,6 +60,8 @@ TouchEventQueue::Config GetTouchEventQueueConfig() {
config.touchmove_slop_suppression_length_dips = config.touchmove_slop_suppression_length_dips =
ui::GestureConfiguration::max_touch_move_in_pixels_for_click(); ui::GestureConfiguration::max_touch_move_in_pixels_for_click();
// TODO(jdduke): Remove when unified GR enabled, crbug.com/332418.
config.touchmove_slop_suppression_region_includes_boundary = false;
return config; return config;
} }
......
...@@ -181,7 +181,8 @@ void InputRouterImpl::SendGestureEvent( ...@@ -181,7 +181,8 @@ void InputRouterImpl::SendGestureEvent(
if (touch_action_filter_.FilterGestureEvent(&gesture_event.event)) if (touch_action_filter_.FilterGestureEvent(&gesture_event.event))
return; return;
touch_event_queue_.OnGestureScrollEvent(gesture_event); if (gesture_event.event.sourceDevice == WebGestureEvent::Touchscreen)
touch_event_queue_.OnGestureScrollEvent(gesture_event);
if (!IsInOverscrollGesture() && if (!IsInOverscrollGesture() &&
!gesture_event_queue_.ShouldForward(gesture_event)) { !gesture_event_queue_.ShouldForward(gesture_event)) {
......
...@@ -204,6 +204,10 @@ class TouchEventQueue::TouchMoveSlopSuppressor { ...@@ -204,6 +204,10 @@ class TouchEventQueue::TouchMoveSlopSuppressor {
suppressing_touchmoves_ = slop_suppression_length_dips_squared_ != 0; suppressing_touchmoves_ = slop_suppression_length_dips_squared_ != 0;
} }
if (event.type == WebInputEvent::TouchEnd ||
event.type == WebInputEvent::TouchCancel)
suppressing_touchmoves_ = false;
if (event.type != WebInputEvent::TouchMove) if (event.type != WebInputEvent::TouchMove)
return false; return false;
...@@ -227,6 +231,8 @@ class TouchEventQueue::TouchMoveSlopSuppressor { ...@@ -227,6 +231,8 @@ class TouchEventQueue::TouchMoveSlopSuppressor {
suppressing_touchmoves_ = false; suppressing_touchmoves_ = false;
} }
bool suppressing_touchmoves() const { return suppressing_touchmoves_; }
private: private:
double slop_suppression_length_dips_squared_; double slop_suppression_length_dips_squared_;
gfx::PointF touch_sequence_start_position_; gfx::PointF touch_sequence_start_position_;
...@@ -322,6 +328,7 @@ class CoalescedWebTouchEvent { ...@@ -322,6 +328,7 @@ class CoalescedWebTouchEvent {
TouchEventQueue::Config::Config() TouchEventQueue::Config::Config()
: touchmove_slop_suppression_length_dips(0), : touchmove_slop_suppression_length_dips(0),
touchmove_slop_suppression_region_includes_boundary(true),
touch_scrolling_mode(TOUCH_SCROLLING_MODE_DEFAULT), touch_scrolling_mode(TOUCH_SCROLLING_MODE_DEFAULT),
touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(200)), touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(200)),
touch_ack_timeout_supported(false) { touch_ack_timeout_supported(false) {
...@@ -335,7 +342,10 @@ TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client, ...@@ -335,7 +342,10 @@ TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client,
touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT), touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT),
ack_timeout_enabled_(config.touch_ack_timeout_supported), ack_timeout_enabled_(config.touch_ack_timeout_supported),
touchmove_slop_suppressor_(new TouchMoveSlopSuppressor( touchmove_slop_suppressor_(new TouchMoveSlopSuppressor(
config.touchmove_slop_suppression_length_dips + kSlopEpsilon)), config.touchmove_slop_suppression_length_dips +
(config.touchmove_slop_suppression_region_includes_boundary
? kSlopEpsilon
: -kSlopEpsilon))),
send_touch_events_async_(false), send_touch_events_async_(false),
needs_async_touchmove_for_outer_slop_region_(false), needs_async_touchmove_for_outer_slop_region_(false),
last_sent_touch_timestamp_sec_(0), last_sent_touch_timestamp_sec_(0),
...@@ -527,6 +537,12 @@ void TouchEventQueue::OnGestureScrollEvent( ...@@ -527,6 +537,12 @@ void TouchEventQueue::OnGestureScrollEvent(
if (gesture_event.event.type != blink::WebInputEvent::GestureScrollBegin) if (gesture_event.event.type != blink::WebInputEvent::GestureScrollBegin)
return; return;
if (touch_filtering_state_ != DROP_ALL_TOUCHES &&
touch_filtering_state_ != DROP_TOUCHES_IN_SEQUENCE) {
DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves())
<< "The renderer should be offered a touchmove before scrolling begins";
}
if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) { if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) {
if (touch_filtering_state_ != DROP_ALL_TOUCHES && if (touch_filtering_state_ != DROP_ALL_TOUCHES &&
touch_filtering_state_ != DROP_TOUCHES_IN_SEQUENCE) { touch_filtering_state_ != DROP_TOUCHES_IN_SEQUENCE) {
......
...@@ -62,6 +62,11 @@ class CONTENT_EXPORT TouchEventQueue { ...@@ -62,6 +62,11 @@ class CONTENT_EXPORT TouchEventQueue {
// Defaults to 0 (disabled). // Defaults to 0 (disabled).
double touchmove_slop_suppression_length_dips; double touchmove_slop_suppression_length_dips;
// Whether the touchmove slop suppression region is boundary inclusive.
// Defaults to true.
// TODO(jdduke): Remove when unified GR enabled, crbug.com/332418.
bool touchmove_slop_suppression_region_includes_boundary;
// Determines the type of touch scrolling. // Determines the type of touch scrolling.
// Defaults to TouchEventQueue:::TOUCH_SCROLLING_MODE_DEFAULT. // Defaults to TouchEventQueue:::TOUCH_SCROLLING_MODE_DEFAULT.
TouchEventQueue::TouchScrollingMode touch_scrolling_mode; TouchEventQueue::TouchScrollingMode touch_scrolling_mode;
......
...@@ -35,6 +35,7 @@ class TouchEventQueueTest : public testing::Test, ...@@ -35,6 +35,7 @@ class TouchEventQueueTest : public testing::Test,
acked_event_count_(0), acked_event_count_(0),
last_acked_event_state_(INPUT_EVENT_ACK_STATE_UNKNOWN), last_acked_event_state_(INPUT_EVENT_ACK_STATE_UNKNOWN),
slop_length_dips_(0), slop_length_dips_(0),
slop_includes_boundary_(true),
touch_scrolling_mode_(TouchEventQueue::TOUCH_SCROLLING_MODE_DEFAULT) {} touch_scrolling_mode_(TouchEventQueue::TOUCH_SCROLLING_MODE_DEFAULT) {}
virtual ~TouchEventQueueTest() {} virtual ~TouchEventQueueTest() {}
...@@ -80,6 +81,8 @@ class TouchEventQueueTest : public testing::Test, ...@@ -80,6 +81,8 @@ class TouchEventQueueTest : public testing::Test,
TouchEventQueue::Config config; TouchEventQueue::Config config;
config.touch_scrolling_mode = touch_scrolling_mode_; config.touch_scrolling_mode = touch_scrolling_mode_;
config.touchmove_slop_suppression_length_dips = slop_length_dips_; config.touchmove_slop_suppression_length_dips = slop_length_dips_;
config.touchmove_slop_suppression_region_includes_boundary =
slop_includes_boundary_;
return config; return config;
} }
...@@ -88,8 +91,10 @@ class TouchEventQueueTest : public testing::Test, ...@@ -88,8 +91,10 @@ class TouchEventQueueTest : public testing::Test,
ResetQueueWithConfig(CreateConfig()); ResetQueueWithConfig(CreateConfig());
} }
void SetUpForTouchMoveSlopTesting(double slop_length_dips) { void SetUpForTouchMoveSlopTesting(double slop_length_dips,
bool slop_includes_boundary) {
slop_length_dips_ = slop_length_dips; slop_length_dips_ = slop_length_dips;
slop_includes_boundary_ = slop_includes_boundary;
ResetQueueWithConfig(CreateConfig()); ResetQueueWithConfig(CreateConfig());
} }
...@@ -248,6 +253,7 @@ class TouchEventQueueTest : public testing::Test, ...@@ -248,6 +253,7 @@ class TouchEventQueueTest : public testing::Test,
scoped_ptr<WebGestureEvent> followup_gesture_event_; scoped_ptr<WebGestureEvent> followup_gesture_event_;
scoped_ptr<InputEventAckState> sync_ack_result_; scoped_ptr<InputEventAckState> sync_ack_result_;
double slop_length_dips_; double slop_length_dips_;
bool slop_includes_boundary_;
TouchEventQueue::TouchScrollingMode touch_scrolling_mode_; TouchEventQueue::TouchScrollingMode touch_scrolling_mode_;
base::MessageLoopForUI message_loop_; base::MessageLoopForUI message_loop_;
}; };
...@@ -1347,12 +1353,13 @@ TEST_F(TouchEventQueueTest, NoCancelOnTouchTimeoutWithoutConsumer) { ...@@ -1347,12 +1353,13 @@ TEST_F(TouchEventQueueTest, NoCancelOnTouchTimeoutWithoutConsumer) {
EXPECT_EQ(0U, GetAndResetAckedEventCount()); EXPECT_EQ(0U, GetAndResetAckedEventCount());
} }
// Tests that TouchMove's are dropped if within the slop suppression region // Tests that TouchMove's are dropped if within the boundary-inclusive slop
// for an unconsumed TouchStart // suppression region for an unconsumed TouchStart.
TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithinSlopRegion) { TEST_F(TouchEventQueueTest, TouchMoveSuppressionIncludingSlopBoundary) {
const double kSlopLengthDips = 10.; const double kSlopLengthDips = 10.;
const double kHalfSlopLengthDips = kSlopLengthDips / 2; const double kHalfSlopLengthDips = kSlopLengthDips / 2;
SetUpForTouchMoveSlopTesting(kSlopLengthDips); const bool slop_includes_boundary = true;
SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
// Queue a TouchStart. // Queue a TouchStart.
PressTouchPoint(0, 0); PressTouchPoint(0, 0);
...@@ -1379,6 +1386,18 @@ TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithinSlopRegion) { ...@@ -1379,6 +1386,18 @@ TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithinSlopRegion) {
EXPECT_EQ(1U, GetAndResetAckedEventCount()); EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state()); EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state());
MoveTouchPoint(0, -kSlopLengthDips, 0);
EXPECT_EQ(0U, queued_event_count());
EXPECT_EQ(0U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state());
MoveTouchPoint(0, 0, kSlopLengthDips);
EXPECT_EQ(0U, queued_event_count());
EXPECT_EQ(0U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state());
// As soon as a TouchMove exceeds the (Euclidean) distance, no more // As soon as a TouchMove exceeds the (Euclidean) distance, no more
// TouchMove's should be suppressed. // TouchMove's should be suppressed.
const double kFortyFiveDegreeSlopLengthXY = const double kFortyFiveDegreeSlopLengthXY =
...@@ -1420,12 +1439,57 @@ TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithinSlopRegion) { ...@@ -1420,12 +1439,57 @@ TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithinSlopRegion) {
EXPECT_EQ(1U, GetAndResetAckedEventCount()); EXPECT_EQ(1U, GetAndResetAckedEventCount());
} }
// Tests that TouchMove's are dropped if within the boundary-exclusive slop
// suppression region for an unconsumed TouchStart.
TEST_F(TouchEventQueueTest, TouchMoveSuppressionExcludingSlopBoundary) {
const double kSlopLengthDips = 10.;
const double kHalfSlopLengthDips = kSlopLengthDips / 2;
const bool slop_includes_boundary = false;
SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
// Queue a TouchStart.
PressTouchPoint(0, 0);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
ASSERT_EQ(1U, GetAndResetSentEventCount());
ASSERT_EQ(1U, GetAndResetAckedEventCount());
// TouchMove's within the region should be suppressed.
MoveTouchPoint(0, 0, kHalfSlopLengthDips);
EXPECT_EQ(0U, queued_event_count());
EXPECT_EQ(0U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state());
MoveTouchPoint(0, kSlopLengthDips - 0.2f, 0);
EXPECT_EQ(0U, queued_event_count());
EXPECT_EQ(0U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state());
// As soon as a TouchMove reaches the (Euclidean) slop distance, no more
// TouchMove's should be suppressed.
MoveTouchPoint(0, kSlopLengthDips, 0);
EXPECT_EQ(1U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(0U, GetAndResetAckedEventCount());
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(1U, GetAndResetAckedEventCount());
MoveTouchPoint(0, kHalfSlopLengthDips, 0);
EXPECT_EQ(1U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(0U, GetAndResetAckedEventCount());
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(1U, GetAndResetAckedEventCount());
}
// Tests that TouchMove's are not dropped within the slop suppression region if // Tests that TouchMove's are not dropped within the slop suppression region if
// the touchstart was consumed. // the touchstart was consumed.
TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterTouchConsumed) { TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterTouchConsumed) {
const double kSlopLengthDips = 10.; const double kSlopLengthDips = 10.;
const double kHalfSlopLengthDips = kSlopLengthDips / 2; const double kHalfSlopLengthDips = kSlopLengthDips / 2;
SetUpForTouchMoveSlopTesting(kSlopLengthDips); const bool slop_includes_boundary = true;
SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
// Queue a TouchStart. // Queue a TouchStart.
PressTouchPoint(0, 0); PressTouchPoint(0, 0);
...@@ -1446,7 +1510,9 @@ TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterTouchConsumed) { ...@@ -1446,7 +1510,9 @@ TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterTouchConsumed) {
TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithDIPScaling) { TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithDIPScaling) {
const float kSlopLengthPixels = 7.f; const float kSlopLengthPixels = 7.f;
const float kDPIScale = 3.f; const float kDPIScale = 3.f;
SetUpForTouchMoveSlopTesting(kSlopLengthPixels / kDPIScale); const bool slop_includes_boundary = true;
SetUpForTouchMoveSlopTesting(kSlopLengthPixels / kDPIScale,
slop_includes_boundary);
// Queue a TouchStart. // Queue a TouchStart.
PressTouchPoint(0, 0); PressTouchPoint(0, 0);
...@@ -1486,7 +1552,8 @@ TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithDIPScaling) { ...@@ -1486,7 +1552,8 @@ TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithDIPScaling) {
TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterMultiTouch) { TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterMultiTouch) {
const double kSlopLengthDips = 10.; const double kSlopLengthDips = 10.;
const double kHalfSlopLengthDips = kSlopLengthDips / 2; const double kHalfSlopLengthDips = kSlopLengthDips / 2;
SetUpForTouchMoveSlopTesting(kSlopLengthDips); const bool slop_includes_boundary = true;
SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
// Queue a TouchStart. // Queue a TouchStart.
PressTouchPoint(0, 0); PressTouchPoint(0, 0);
...@@ -1833,8 +1900,14 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithAckTimeout) { ...@@ -1833,8 +1900,14 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithAckTimeout) {
PressTouchPoint(0, 0); PressTouchPoint(0, 0);
EXPECT_EQ(1U, GetAndResetSentEventCount()); EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_TRUE(IsTimeoutRunning()); EXPECT_TRUE(IsTimeoutRunning());
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_FALSE(IsTimeoutRunning());
// The start of a scroll gesture should trigger async touch event dispatch. // The start of a scroll gesture should trigger async touch event dispatch.
MoveTouchPoint(0, 1, 1);
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_TRUE(IsTimeoutRunning());
WebGestureEvent followup_scroll; WebGestureEvent followup_scroll;
followup_scroll.type = WebInputEvent::GestureScrollBegin; followup_scroll.type = WebInputEvent::GestureScrollBegin;
SetFollowupEvent(followup_scroll); SetFollowupEvent(followup_scroll);
...@@ -1907,8 +1980,12 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithTouchCancelAfterAck) { ...@@ -1907,8 +1980,12 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithTouchCancelAfterAck) {
PressTouchPoint(0, 0); PressTouchPoint(0, 0);
EXPECT_EQ(1U, GetAndResetSentEventCount()); EXPECT_EQ(1U, GetAndResetSentEventCount());
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(1U, GetAndResetAckedEventCount());
// The start of a scroll gesture should trigger async touch event dispatch. // The start of a scroll gesture should trigger async touch event dispatch.
MoveTouchPoint(0, 1, 1);
EXPECT_EQ(1U, GetAndResetSentEventCount());
WebGestureEvent followup_scroll; WebGestureEvent followup_scroll;
followup_scroll.type = WebInputEvent::GestureScrollBegin; followup_scroll.type = WebInputEvent::GestureScrollBegin;
SetFollowupEvent(followup_scroll); SetFollowupEvent(followup_scroll);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment