| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/renderer_host/input/fling_controller.h" |
| |
| #include "base/run_loop.h" |
| #include "base/test/scoped_task_environment.h" |
| #include "content/browser/renderer_host/input/gesture_event_queue.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/events/base_event_utils.h" |
| #include "ui/events/blink/fling_booster.h" |
| |
| using blink::WebGestureEvent; |
| using blink::WebInputEvent; |
| using blink::WebMouseWheelEvent; |
| |
| namespace content { |
| |
| class FakeFlingController : public FlingController { |
| public: |
| FakeFlingController(GestureEventQueue* gesture_event_queue, |
| |
| FlingControllerEventSenderClient* event_sender_client, |
| FlingControllerSchedulerClient* scheduler_client, |
| const Config& config) |
| : FlingController(gesture_event_queue, |
| event_sender_client, |
| scheduler_client, |
| config) {} |
| |
| bool FlingBoosted() const { return fling_booster_->fling_boosted(); } |
| }; |
| |
| class FlingControllerTest : public testing::Test, |
| public GestureEventQueueClient, |
| public FlingControllerEventSenderClient, |
| public FlingControllerSchedulerClient { |
| public: |
| // testing::Test |
| FlingControllerTest() |
| : scoped_task_environment_( |
| base::test::ScopedTaskEnvironment::MainThreadType::UI) {} |
| |
| ~FlingControllerTest() override {} |
| |
| void SetUp() override { |
| queue_ = std::make_unique<GestureEventQueue>(this, this, this, |
| GestureEventQueue::Config()); |
| fling_controller_ = std::make_unique<FakeFlingController>( |
| queue_.get(), this, this, FlingController::Config()); |
| } |
| |
| // GestureEventQueueClient |
| void SendGestureEventImmediately( |
| const GestureEventWithLatencyInfo& event) override {} |
| void OnGestureEventAck(const GestureEventWithLatencyInfo& event, |
| InputEventAckSource ack_source, |
| InputEventAckState ack_result) override {} |
| |
| // FlingControllerEventSenderClient |
| void SendGeneratedWheelEvent( |
| const MouseWheelEventWithLatencyInfo& wheel_event) override { |
| last_sent_wheel_ = wheel_event.event; |
| } |
| void SendGeneratedGestureScrollEvents( |
| const GestureEventWithLatencyInfo& gesture_event) override { |
| last_sent_gesture_ = gesture_event.event; |
| } |
| |
| // FlingControllerSchedulerClient |
| void ScheduleFlingProgress( |
| base::WeakPtr<FlingController> fling_controller) override { |
| DCHECK(!scheduled_next_fling_progress_); |
| scheduled_next_fling_progress_ = true; |
| } |
| void DidStopFlingingOnBrowser( |
| base::WeakPtr<FlingController> fling_controller) override { |
| notified_client_after_fling_stop_ = true; |
| } |
| |
| void SimulateFlingStart(blink::WebGestureDevice source_device, |
| const gfx::Vector2dF& velocity) { |
| scheduled_next_fling_progress_ = false; |
| WebGestureEvent fling_start(WebInputEvent::kGestureFlingStart, 0, |
| base::TimeTicks::Now(), source_device); |
| fling_start.data.fling_start.velocity_x = velocity.x(); |
| fling_start.data.fling_start.velocity_y = velocity.y(); |
| GestureEventWithLatencyInfo fling_start_with_latency(fling_start); |
| if (!fling_controller_->FilterGestureEvent(fling_start_with_latency)) |
| fling_controller_->ProcessGestureFlingStart(fling_start_with_latency); |
| } |
| |
| void SimulateFlingCancel(blink::WebGestureDevice source_device) { |
| notified_client_after_fling_stop_ = false; |
| WebGestureEvent fling_cancel(WebInputEvent::kGestureFlingCancel, 0, |
| base::TimeTicks::Now(), source_device); |
| // autoscroll fling cancel doesn't allow fling boosting. |
| if (source_device == blink::kWebGestureDeviceSyntheticAutoscroll) |
| fling_cancel.data.fling_cancel.prevent_boosting = true; |
| GestureEventWithLatencyInfo fling_cancel_with_latency(fling_cancel); |
| last_fling_cancel_filtered_ = |
| fling_controller_->FilterGestureEvent(fling_cancel_with_latency); |
| if (!last_fling_cancel_filtered_) |
| fling_controller_->ProcessGestureFlingCancel(fling_cancel_with_latency); |
| } |
| |
| void ProgressFling(base::TimeTicks current_time) { |
| DCHECK(scheduled_next_fling_progress_); |
| scheduled_next_fling_progress_ = false; |
| fling_controller_->ProgressFling(current_time); |
| } |
| |
| bool FlingInProgress() { return fling_controller_->fling_in_progress(); } |
| bool FlingBoosted() { return fling_controller_->FlingBoosted(); } |
| |
| protected: |
| std::unique_ptr<FakeFlingController> fling_controller_; |
| WebMouseWheelEvent last_sent_wheel_; |
| WebGestureEvent last_sent_gesture_; |
| bool last_fling_cancel_filtered_; |
| bool scheduled_next_fling_progress_; |
| bool notified_client_after_fling_stop_; |
| |
| private: |
| base::test::ScopedTaskEnvironment scoped_task_environment_; |
| std::unique_ptr<GestureEventQueue> queue_; |
| }; |
| |
| TEST_F(FlingControllerTest, |
| ControllerSendsWheelEndOnTouchpadFlingWithZeroVelocity) { |
| SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF()); |
| // The controller doesn't start a fling and sends a wheel end event |
| // immediately. |
| EXPECT_FALSE(FlingInProgress()); |
| EXPECT_EQ(WebMouseWheelEvent::kPhaseEnded, last_sent_wheel_.momentum_phase); |
| EXPECT_EQ(0.f, last_sent_wheel_.delta_x); |
| EXPECT_EQ(0.f, last_sent_wheel_.delta_y); |
| } |
| |
| TEST_F(FlingControllerTest, |
| ControllerSendsGSEOnTouchscreenFlingWithZeroVelocity) { |
| SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, gfx::Vector2dF()); |
| // The controller doesn't start a fling and sends a GSE immediately. |
| EXPECT_FALSE(FlingInProgress()); |
| EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType()); |
| } |
| |
| TEST_F(FlingControllerTest, ControllerHandlesTouchpadGestureFling) { |
| base::TimeTicks progress_time = base::TimeTicks::Now(); |
| SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| // The first wheel event must have momentum_phase == KPhaseBegan. |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase); |
| EXPECT_GT(last_sent_wheel_.delta_x, 0.f); |
| |
| // The rest of the wheel events must have momentum_phase == KPhaseChanged. |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| EXPECT_EQ(WebMouseWheelEvent::kPhaseChanged, last_sent_wheel_.momentum_phase); |
| EXPECT_GT(last_sent_wheel_.delta_x, 0.f); |
| |
| // Now cancel the fling. The GFC will get suppressed by fling booster. |
| SimulateFlingCancel(blink::kWebGestureDeviceTouchpad); |
| EXPECT_TRUE(last_fling_cancel_filtered_); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| // Wait for the boosting timer to expire. The delayed cancelation must work. |
| progress_time += base::TimeDelta::FromMilliseconds(500); |
| ProgressFling(progress_time); |
| EXPECT_FALSE(FlingInProgress()); |
| EXPECT_EQ(WebMouseWheelEvent::kPhaseEnded, last_sent_wheel_.momentum_phase); |
| EXPECT_EQ(0.f, last_sent_wheel_.delta_x); |
| EXPECT_EQ(0.f, last_sent_wheel_.delta_y); |
| } |
| |
| TEST_F(FlingControllerTest, ControllerHandlesTouchscreenGestureFling) { |
| base::TimeTicks progress_time = base::TimeTicks::Now(); |
| SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, |
| gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| // The fling progress will generate and send GSU events with inertial state. |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, last_sent_gesture_.GetType()); |
| EXPECT_EQ(WebGestureEvent::kMomentumPhase, |
| last_sent_gesture_.data.scroll_update.inertial_phase); |
| EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f); |
| |
| // Now cancel the fling. The GFC will get suppressed by fling booster. |
| SimulateFlingCancel(blink::kWebGestureDeviceTouchscreen); |
| EXPECT_TRUE(last_fling_cancel_filtered_); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| // Wait for the boosting timer to expire. The delayed cancelation must work. |
| progress_time += base::TimeDelta::FromMilliseconds(500); |
| ProgressFling(progress_time); |
| EXPECT_FALSE(FlingInProgress()); |
| EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType()); |
| } |
| |
| TEST_F(FlingControllerTest, ControllerSendsWheelEndWhenTouchpadFlingIsOver) { |
| base::TimeTicks progress_time = base::TimeTicks::Now(); |
| SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(100, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase); |
| EXPECT_GT(last_sent_wheel_.delta_x, 0.f); |
| |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| while (FlingInProgress()) { |
| EXPECT_EQ(WebMouseWheelEvent::kPhaseChanged, |
| last_sent_wheel_.momentum_phase); |
| EXPECT_GT(last_sent_wheel_.delta_x, 0.f); |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| } |
| |
| EXPECT_EQ(WebMouseWheelEvent::kPhaseEnded, last_sent_wheel_.momentum_phase); |
| EXPECT_EQ(0.f, last_sent_wheel_.delta_x); |
| EXPECT_EQ(0.f, last_sent_wheel_.delta_y); |
| } |
| |
| TEST_F(FlingControllerTest, ControllerSendsGSEWhenTouchscreenFlingIsOver) { |
| base::TimeTicks progress_time = base::TimeTicks::Now(); |
| SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, |
| gfx::Vector2dF(100, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| while (FlingInProgress()) { |
| ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, |
| last_sent_gesture_.GetType()); |
| EXPECT_EQ(WebGestureEvent::kMomentumPhase, |
| last_sent_gesture_.data.scroll_update.inertial_phase); |
| EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f); |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| } |
| |
| EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType()); |
| } |
| |
| TEST_F(FlingControllerTest, |
| EarlyTouchpadFlingCancelationOnInertialGSUAckNotConsumed) { |
| base::TimeTicks progress_time = base::TimeTicks::Now(); |
| SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase); |
| EXPECT_GT(last_sent_wheel_.delta_x, 0.f); |
| |
| // A non-consumed GSU ack in inertial state cancels out the rest of the fling. |
| WebGestureEvent scroll_update(WebInputEvent::kGestureScrollUpdate, 0, |
| base::TimeTicks::Now()); |
| scroll_update.data.scroll_update.inertial_phase = |
| WebGestureEvent::kMomentumPhase; |
| |
| fling_controller_->OnGestureEventAck( |
| GestureEventWithLatencyInfo(scroll_update), |
| INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_FALSE(FlingInProgress()); |
| EXPECT_EQ(WebMouseWheelEvent::kPhaseEnded, last_sent_wheel_.momentum_phase); |
| EXPECT_EQ(0.f, last_sent_wheel_.delta_x); |
| EXPECT_EQ(0.f, last_sent_wheel_.delta_y); |
| } |
| |
| TEST_F(FlingControllerTest, |
| EarlyTouchscreenFlingCancelationOnInertialGSUAckNotConsumed) { |
| base::TimeTicks progress_time = base::TimeTicks::Now(); |
| SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, |
| gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, last_sent_gesture_.GetType()); |
| EXPECT_EQ(WebGestureEvent::kMomentumPhase, |
| last_sent_gesture_.data.scroll_update.inertial_phase); |
| EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f); |
| |
| // A non-consumed GSU ack in inertial state cancels out the rest of the fling. |
| WebGestureEvent scroll_update(WebInputEvent::kGestureScrollUpdate, 0, |
| base::TimeTicks::Now()); |
| scroll_update.data.scroll_update.inertial_phase = |
| WebGestureEvent::kMomentumPhase; |
| |
| fling_controller_->OnGestureEventAck( |
| GestureEventWithLatencyInfo(scroll_update), |
| INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_FALSE(FlingInProgress()); |
| EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType()); |
| } |
| |
| TEST_F(FlingControllerTest, EarlyTouchpadFlingCancelationOnFlingStop) { |
| base::TimeTicks progress_time = base::TimeTicks::Now(); |
| SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase); |
| EXPECT_GT(last_sent_wheel_.delta_x, 0.f); |
| |
| fling_controller_->StopFling(); |
| EXPECT_FALSE(FlingInProgress()); |
| EXPECT_EQ(WebMouseWheelEvent::kPhaseEnded, last_sent_wheel_.momentum_phase); |
| EXPECT_EQ(0.f, last_sent_wheel_.delta_x); |
| EXPECT_EQ(0.f, last_sent_wheel_.delta_y); |
| } |
| |
| TEST_F(FlingControllerTest, EarlyTouchscreenFlingCancelationOnFlingStop) { |
| base::TimeTicks progress_time = base::TimeTicks::Now(); |
| SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, |
| gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| // progress fling must send GSU events. |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, last_sent_gesture_.GetType()); |
| EXPECT_EQ(WebGestureEvent::kMomentumPhase, |
| last_sent_gesture_.data.scroll_update.inertial_phase); |
| EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f); |
| |
| fling_controller_->StopFling(); |
| EXPECT_FALSE(FlingInProgress()); |
| EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType()); |
| } |
| |
| TEST_F(FlingControllerTest, GestureFlingCancelsFiltered) { |
| // GFC without previous GFS is dropped. |
| SimulateFlingCancel(blink::kWebGestureDeviceTouchscreen); |
| EXPECT_TRUE(last_fling_cancel_filtered_); |
| |
| // GFC after previous GFS is filtered by fling booster. |
| SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, |
| gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| SimulateFlingCancel(blink::kWebGestureDeviceTouchscreen); |
| EXPECT_TRUE(last_fling_cancel_filtered_); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| // Any other GFC while the fling cancelation is deferred gets filtered. |
| SimulateFlingCancel(blink::kWebGestureDeviceTouchscreen); |
| EXPECT_TRUE(last_fling_cancel_filtered_); |
| } |
| |
| // Flaky. https://crbug.com/836996. |
| TEST_F(FlingControllerTest, DISABLED_GestureFlingNotCancelledBySmallTimeDelta) { |
| base::TimeTicks progress_time = base::TimeTicks::Now(); |
| SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, |
| gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| // If we the first progress tick happens too close to the fling_start time, |
| // the controller won't send any GSU events, but the fling is still active. |
| // progress_time += base::TimeDelta::FromMilliseconds(1); |
| ProgressFling(progress_time); |
| EXPECT_EQ(blink::kWebGestureDeviceUninitialized, |
| last_sent_gesture_.SourceDevice()); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| // The rest of the progress flings must advance the fling normally. |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, |
| last_sent_gesture_.SourceDevice()); |
| ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, last_sent_gesture_.GetType()); |
| EXPECT_EQ(WebGestureEvent::kMomentumPhase, |
| last_sent_gesture_.data.scroll_update.inertial_phase); |
| EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f); |
| } |
| |
| TEST_F(FlingControllerTest, GestureFlingWithNegativeTimeDelta) { |
| base::TimeTicks progress_time = base::TimeTicks::Now(); |
| SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, |
| gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| // If we get a negative time delta, that is, the Progress tick time happens |
| // before the fling's start time then we should *not* try progressing the |
| // fling and instead reset the fling start time. |
| progress_time -= base::TimeDelta::FromMilliseconds(5); |
| ProgressFling(progress_time); |
| EXPECT_EQ(blink::kWebGestureDeviceUninitialized, |
| last_sent_gesture_.SourceDevice()); |
| |
| // The rest of the progress flings must advance the fling normally. |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, |
| last_sent_gesture_.SourceDevice()); |
| ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, last_sent_gesture_.GetType()); |
| EXPECT_EQ(WebGestureEvent::kMomentumPhase, |
| last_sent_gesture_.data.scroll_update.inertial_phase); |
| EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f); |
| } |
| |
| TEST_F(FlingControllerTest, ControllerBoostsTouchpadFling) { |
| base::TimeTicks progress_time = base::TimeTicks::Now(); |
| SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| // The first wheel event must have momentum_phase == KPhaseBegan. |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase); |
| EXPECT_GT(last_sent_wheel_.delta_x, 0.f); |
| |
| // The rest of the wheel events must have momentum_phase == KPhaseChanged. |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| EXPECT_EQ(WebMouseWheelEvent::kPhaseChanged, last_sent_wheel_.momentum_phase); |
| EXPECT_GT(last_sent_wheel_.delta_x, 0.f); |
| |
| // Now cancel the fling. The GFC will get suppressed by fling booster. |
| SimulateFlingCancel(blink::kWebGestureDeviceTouchpad); |
| EXPECT_TRUE(last_fling_cancel_filtered_); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| // The second GFS will boost the current active fling. |
| SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| EXPECT_TRUE(FlingBoosted()); |
| } |
| |
| TEST_F(FlingControllerTest, ControllerBoostsTouchscreenFling) { |
| base::TimeTicks progress_time = base::TimeTicks::Now(); |
| SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, |
| gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| // Fling progress must send GSU events. |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, last_sent_gesture_.GetType()); |
| EXPECT_EQ(WebGestureEvent::kMomentumPhase, |
| last_sent_gesture_.data.scroll_update.inertial_phase); |
| EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f); |
| |
| // Now cancel the fling. The GFC will get suppressed by fling booster. |
| SimulateFlingCancel(blink::kWebGestureDeviceTouchscreen); |
| EXPECT_TRUE(last_fling_cancel_filtered_); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| // The second GFS will boost the current active fling. |
| SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, |
| gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| EXPECT_TRUE(FlingBoosted()); |
| } |
| |
| TEST_F(FlingControllerTest, ControllerNotifiesTheClientAfterFlingStart) { |
| base::TimeTicks progress_time = base::TimeTicks::Now(); |
| SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, |
| gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| // Now cancel the fling. The GFC will get suppressed by fling booster. |
| SimulateFlingCancel(blink::kWebGestureDeviceTouchscreen); |
| EXPECT_TRUE(last_fling_cancel_filtered_); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| // Wait for the boosting timer to expire. The delayed cancelation must work |
| // and the client must be notified after fling cancelation. |
| progress_time += base::TimeDelta::FromMilliseconds(500); |
| ProgressFling(progress_time); |
| EXPECT_FALSE(FlingInProgress()); |
| EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType()); |
| EXPECT_TRUE(notified_client_after_fling_stop_); |
| } |
| |
| TEST_F(FlingControllerTest, MiddleClickAutoScrollFling) { |
| base::TimeTicks progress_time = base::TimeTicks::Now(); |
| SimulateFlingStart(blink::kWebGestureDeviceSyntheticAutoscroll, |
| gfx::Vector2dF(1000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| |
| progress_time += base::TimeDelta::FromMilliseconds(17); |
| ProgressFling(progress_time); |
| ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, last_sent_gesture_.GetType()); |
| EXPECT_EQ(WebGestureEvent::kMomentumPhase, |
| last_sent_gesture_.data.scroll_update.inertial_phase); |
| EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f); |
| |
| // Now send a new fling with different velocity and without sending a fling |
| // cancel event, the new fling should always replace the old one even when |
| // they are in the same direction. |
| SimulateFlingStart(blink::kWebGestureDeviceSyntheticAutoscroll, |
| gfx::Vector2dF(2000, 0)); |
| EXPECT_TRUE(FlingInProgress()); |
| EXPECT_FALSE(FlingBoosted()); |
| |
| // Now cancel the fling. The GFC won't get suppressed by fling booster since |
| // autoscroll fling doesn't have boosting. |
| SimulateFlingCancel(blink::kWebGestureDeviceSyntheticAutoscroll); |
| EXPECT_FALSE(last_fling_cancel_filtered_); |
| EXPECT_FALSE(FlingInProgress()); |
| } |
| |
| } // namespace content |