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() {
config.touchmove_slop_suppression_length_dips =
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;
}
......
......@@ -181,7 +181,8 @@ void InputRouterImpl::SendGestureEvent(
if (touch_action_filter_.FilterGestureEvent(&gesture_event.event))
return;
touch_event_queue_.OnGestureScrollEvent(gesture_event);
if (gesture_event.event.sourceDevice == WebGestureEvent::Touchscreen)
touch_event_queue_.OnGestureScrollEvent(gesture_event);
if (!IsInOverscrollGesture() &&
!gesture_event_queue_.ShouldForward(gesture_event)) {
......
......@@ -204,6 +204,10 @@ class TouchEventQueue::TouchMoveSlopSuppressor {
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)
return false;
......@@ -227,6 +231,8 @@ class TouchEventQueue::TouchMoveSlopSuppressor {
suppressing_touchmoves_ = false;
}
bool suppressing_touchmoves() const { return suppressing_touchmoves_; }
private:
double slop_suppression_length_dips_squared_;
gfx::PointF touch_sequence_start_position_;
......@@ -322,6 +328,7 @@ class CoalescedWebTouchEvent {
TouchEventQueue::Config::Config()
: touchmove_slop_suppression_length_dips(0),
touchmove_slop_suppression_region_includes_boundary(true),
touch_scrolling_mode(TOUCH_SCROLLING_MODE_DEFAULT),
touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(200)),
touch_ack_timeout_supported(false) {
......@@ -335,7 +342,10 @@ TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client,
touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT),
ack_timeout_enabled_(config.touch_ack_timeout_supported),
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),
needs_async_touchmove_for_outer_slop_region_(false),
last_sent_touch_timestamp_sec_(0),
......@@ -527,6 +537,12 @@ void TouchEventQueue::OnGestureScrollEvent(
if (gesture_event.event.type != blink::WebInputEvent::GestureScrollBegin)
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_filtering_state_ != DROP_ALL_TOUCHES &&
touch_filtering_state_ != DROP_TOUCHES_IN_SEQUENCE) {
......
......@@ -62,6 +62,11 @@ class CONTENT_EXPORT TouchEventQueue {
// Defaults to 0 (disabled).
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.
// Defaults to TouchEventQueue:::TOUCH_SCROLLING_MODE_DEFAULT.
TouchEventQueue::TouchScrollingMode touch_scrolling_mode;
......
......@@ -35,6 +35,7 @@ class TouchEventQueueTest : public testing::Test,
acked_event_count_(0),
last_acked_event_state_(INPUT_EVENT_ACK_STATE_UNKNOWN),
slop_length_dips_(0),
slop_includes_boundary_(true),
touch_scrolling_mode_(TouchEventQueue::TOUCH_SCROLLING_MODE_DEFAULT) {}
virtual ~TouchEventQueueTest() {}
......@@ -80,6 +81,8 @@ class TouchEventQueueTest : public testing::Test,
TouchEventQueue::Config config;
config.touch_scrolling_mode = touch_scrolling_mode_;
config.touchmove_slop_suppression_length_dips = slop_length_dips_;
config.touchmove_slop_suppression_region_includes_boundary =
slop_includes_boundary_;
return config;
}
......@@ -88,8 +91,10 @@ class TouchEventQueueTest : public testing::Test,
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_includes_boundary_ = slop_includes_boundary;
ResetQueueWithConfig(CreateConfig());
}
......@@ -248,6 +253,7 @@ class TouchEventQueueTest : public testing::Test,
scoped_ptr<WebGestureEvent> followup_gesture_event_;
scoped_ptr<InputEventAckState> sync_ack_result_;
double slop_length_dips_;
bool slop_includes_boundary_;
TouchEventQueue::TouchScrollingMode touch_scrolling_mode_;
base::MessageLoopForUI message_loop_;
};
......@@ -1347,12 +1353,13 @@ TEST_F(TouchEventQueueTest, NoCancelOnTouchTimeoutWithoutConsumer) {
EXPECT_EQ(0U, GetAndResetAckedEventCount());
}
// Tests that TouchMove's are dropped if within the slop suppression region
// for an unconsumed TouchStart
TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithinSlopRegion) {
// Tests that TouchMove's are dropped if within the boundary-inclusive slop
// suppression region for an unconsumed TouchStart.
TEST_F(TouchEventQueueTest, TouchMoveSuppressionIncludingSlopBoundary) {
const double kSlopLengthDips = 10.;
const double kHalfSlopLengthDips = kSlopLengthDips / 2;
SetUpForTouchMoveSlopTesting(kSlopLengthDips);
const bool slop_includes_boundary = true;
SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
// Queue a TouchStart.
PressTouchPoint(0, 0);
......@@ -1379,6 +1386,18 @@ TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithinSlopRegion) {
EXPECT_EQ(1U, GetAndResetAckedEventCount());
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
// TouchMove's should be suppressed.
const double kFortyFiveDegreeSlopLengthXY =
......@@ -1420,12 +1439,57 @@ TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithinSlopRegion) {
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
// the touchstart was consumed.
TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterTouchConsumed) {
const double kSlopLengthDips = 10.;
const double kHalfSlopLengthDips = kSlopLengthDips / 2;
SetUpForTouchMoveSlopTesting(kSlopLengthDips);
const bool slop_includes_boundary = true;
SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
// Queue a TouchStart.
PressTouchPoint(0, 0);
......@@ -1446,7 +1510,9 @@ TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterTouchConsumed) {
TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithDIPScaling) {
const float kSlopLengthPixels = 7.f;
const float kDPIScale = 3.f;
SetUpForTouchMoveSlopTesting(kSlopLengthPixels / kDPIScale);
const bool slop_includes_boundary = true;
SetUpForTouchMoveSlopTesting(kSlopLengthPixels / kDPIScale,
slop_includes_boundary);
// Queue a TouchStart.
PressTouchPoint(0, 0);
......@@ -1486,7 +1552,8 @@ TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithDIPScaling) {
TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterMultiTouch) {
const double kSlopLengthDips = 10.;
const double kHalfSlopLengthDips = kSlopLengthDips / 2;
SetUpForTouchMoveSlopTesting(kSlopLengthDips);
const bool slop_includes_boundary = true;
SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
// Queue a TouchStart.
PressTouchPoint(0, 0);
......@@ -1833,8 +1900,14 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithAckTimeout) {
PressTouchPoint(0, 0);
EXPECT_EQ(1U, GetAndResetSentEventCount());
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.
MoveTouchPoint(0, 1, 1);
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_TRUE(IsTimeoutRunning());
WebGestureEvent followup_scroll;
followup_scroll.type = WebInputEvent::GestureScrollBegin;
SetFollowupEvent(followup_scroll);
......@@ -1907,8 +1980,12 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithTouchCancelAfterAck) {
PressTouchPoint(0, 0);
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.
MoveTouchPoint(0, 1, 1);
EXPECT_EQ(1U, GetAndResetSentEventCount());
WebGestureEvent followup_scroll;
followup_scroll.type = WebInputEvent::GestureScrollBegin;
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