Mohsen Izadi | 9830436c | 2017-12-21 18:02:46 | [diff] [blame] | 1 | // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "content/browser/renderer_host/overscroll_controller.h" |
| 6 | |
| 7 | #include <memory> |
| 8 | |
| 9 | #include "base/containers/queue.h" |
| 10 | #include "content/browser/renderer_host/overscroll_controller_delegate.h" |
| 11 | #include "content/common/input/synthetic_web_input_event_builders.h" |
| 12 | #include "content/test/test_overscroll_delegate.h" |
| 13 | #include "testing/gtest/include/gtest/gtest.h" |
chaopeng | 1d469b0 | 2018-04-05 15:41:07 | [diff] [blame^] | 14 | #include "third_party/WebKit/public/platform/WebInputEvent.h" |
Mohsen Izadi | 9830436c | 2017-12-21 18:02:46 | [diff] [blame] | 15 | |
| 16 | namespace content { |
| 17 | |
| 18 | class OverscrollControllerTest : public ::testing::Test { |
| 19 | protected: |
| 20 | OverscrollControllerTest() {} |
| 21 | ~OverscrollControllerTest() override {} |
| 22 | |
| 23 | void SetUp() override { |
| 24 | delegate_ = std::make_unique<TestOverscrollDelegate>(gfx::Size(400, 300)); |
| 25 | controller_ = std::make_unique<OverscrollController>(); |
| 26 | controller_->set_delegate(delegate_.get()); |
| 27 | } |
| 28 | |
| 29 | void TearDown() override { |
| 30 | controller_ = nullptr; |
| 31 | delegate_ = nullptr; |
| 32 | } |
| 33 | |
| 34 | // Creates and sends a mouse-wheel event to the overscroll controller. Returns |
| 35 | // |true| if the event is consumed by the overscroll controller. |
| 36 | bool SimulateMouseWheel(float dx, float dy) { |
| 37 | DCHECK(!current_event_); |
| 38 | current_event_ = std::make_unique<blink::WebMouseWheelEvent>( |
| 39 | SyntheticWebMouseWheelEventBuilder::Build(0, 0, dx, dy, 0, true)); |
| 40 | return controller_->WillHandleEvent(*current_event_); |
| 41 | } |
| 42 | |
chaopeng | 1d469b0 | 2018-04-05 15:41:07 | [diff] [blame^] | 43 | // Creates and sends a gesture event to the overscroll controller. Returns |
| 44 | // |true| if the event is consumed by the overscroll controller. |
| 45 | bool SimulateGestureEvent(blink::WebInputEvent::Type type, |
| 46 | blink::WebGestureDevice source_device) { |
| 47 | DCHECK(!current_event_); |
| 48 | current_event_ = std::make_unique<blink::WebGestureEvent>( |
| 49 | SyntheticWebGestureEventBuilder::Build(type, source_device)); |
| 50 | return controller_->WillHandleEvent(*current_event_); |
| 51 | } |
| 52 | |
Mohsen Izadi | 9830436c | 2017-12-21 18:02:46 | [diff] [blame] | 53 | // Creates and sends a gesture-scroll-update event to the overscroll |
| 54 | // controller. Returns |true| if the event is consumed by the overscroll |
| 55 | // controller. |
| 56 | bool SimulateGestureScrollUpdate(float dx, |
| 57 | float dy, |
chaopeng | 1d469b0 | 2018-04-05 15:41:07 | [diff] [blame^] | 58 | blink::WebGestureDevice device, |
| 59 | bool inertial_update) { |
Mohsen Izadi | 9830436c | 2017-12-21 18:02:46 | [diff] [blame] | 60 | DCHECK(!current_event_); |
chaopeng | 1d469b0 | 2018-04-05 15:41:07 | [diff] [blame^] | 61 | auto event = std::make_unique<blink::WebGestureEvent>( |
Mohsen Izadi | 9830436c | 2017-12-21 18:02:46 | [diff] [blame] | 62 | SyntheticWebGestureEventBuilder::BuildScrollUpdate(dx, dy, 0, device)); |
chaopeng | 1d469b0 | 2018-04-05 15:41:07 | [diff] [blame^] | 63 | if (inertial_update) { |
| 64 | event->data.scroll_update.inertial_phase = |
| 65 | blink::WebGestureEvent::kMomentumPhase; |
| 66 | } |
| 67 | current_event_ = std::move(event); |
Mohsen Izadi | 9830436c | 2017-12-21 18:02:46 | [diff] [blame] | 68 | return controller_->WillHandleEvent(*current_event_); |
| 69 | } |
| 70 | |
| 71 | // Notifies the overscroll controller that the current event is ACKed. |
| 72 | void SimulateAck(bool processed) { |
| 73 | DCHECK(current_event_); |
| 74 | controller_->ReceivedEventACK(*current_event_, processed); |
| 75 | current_event_ = nullptr; |
| 76 | } |
| 77 | |
| 78 | TestOverscrollDelegate* delegate() const { return delegate_.get(); } |
| 79 | |
| 80 | OverscrollMode controller_mode() const { |
| 81 | return controller_->overscroll_mode_; |
| 82 | } |
| 83 | |
| 84 | OverscrollSource controller_source() const { |
| 85 | return controller_->overscroll_source_; |
| 86 | } |
| 87 | |
| 88 | private: |
| 89 | std::unique_ptr<TestOverscrollDelegate> delegate_; |
| 90 | std::unique_ptr<OverscrollController> controller_; |
| 91 | |
| 92 | // Keeps track of the last event that has been processed by the overscroll |
| 93 | // controller which is not yet ACKed. Will be null if no event is processed or |
| 94 | // the last event is ACKed. |
| 95 | std::unique_ptr<blink::WebInputEvent> current_event_; |
| 96 | |
| 97 | DISALLOW_COPY_AND_ASSIGN(OverscrollControllerTest); |
| 98 | }; |
| 99 | |
| 100 | // Tests that if a mouse-wheel is consumed by content before overscroll is |
| 101 | // initiated, overscroll will not initiate anymore. |
| 102 | TEST_F(OverscrollControllerTest, MouseWheelConsumedPreventsOverscroll) { |
| 103 | // Simulate a mouse-wheel, ACK it as not processed, simulate the corresponding |
| 104 | // gesture scroll-update event, and ACK it is not processed. Since it is not |
| 105 | // passing the start threshold, no overscroll should happen. |
| 106 | EXPECT_FALSE(SimulateMouseWheel(10, 0)); |
| 107 | SimulateAck(false); |
chaopeng | 1d469b0 | 2018-04-05 15:41:07 | [diff] [blame^] | 108 | EXPECT_FALSE(SimulateGestureScrollUpdate( |
| 109 | 10, 0, blink::kWebGestureDeviceTouchpad, false)); |
Mohsen Izadi | 9830436c | 2017-12-21 18:02:46 | [diff] [blame] | 110 | SimulateAck(false); |
| 111 | EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); |
| 112 | EXPECT_EQ(OverscrollSource::NONE, controller_source()); |
| 113 | EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); |
| 114 | EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); |
| 115 | |
| 116 | // Simulate a mouse-wheel and ACK it as processed. No gesture scroll-update |
| 117 | // needs to be simulated. Still no overscroll. |
| 118 | EXPECT_FALSE(SimulateMouseWheel(10, 0)); |
| 119 | SimulateAck(true); |
| 120 | EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); |
| 121 | EXPECT_EQ(OverscrollSource::NONE, controller_source()); |
| 122 | EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); |
| 123 | EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); |
| 124 | |
| 125 | // Simulate a mouse-wheel and the corresponding gesture scroll-update both |
| 126 | // ACKed as not processed. Although the scroll passes overscroll start |
| 127 | // threshold, no overscroll should happen since the previous mouse-wheel was |
| 128 | // marked as processed. |
| 129 | EXPECT_FALSE(SimulateMouseWheel(100, 0)); |
| 130 | SimulateAck(false); |
chaopeng | 1d469b0 | 2018-04-05 15:41:07 | [diff] [blame^] | 131 | EXPECT_FALSE(SimulateGestureScrollUpdate( |
| 132 | 100, 0, blink::kWebGestureDeviceTouchpad, false)); |
Mohsen Izadi | 9830436c | 2017-12-21 18:02:46 | [diff] [blame] | 133 | SimulateAck(false); |
| 134 | EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); |
| 135 | EXPECT_EQ(OverscrollSource::NONE, controller_source()); |
| 136 | EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); |
| 137 | EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); |
| 138 | } |
| 139 | |
chaopeng | 1d469b0 | 2018-04-05 15:41:07 | [diff] [blame^] | 140 | // Verifying the inertial scroll event completes overscroll. After that we will |
| 141 | // ignore the following inertial scroll events until new sequence start. |
| 142 | TEST_F(OverscrollControllerTest, |
| 143 | InertialGestureScrollUpdateCompletesOverscroll) { |
| 144 | EXPECT_FALSE(SimulateGestureEvent(blink::WebInputEvent::kGestureScrollBegin, |
| 145 | blink::kWebGestureDeviceTouchpad)); |
| 146 | SimulateAck(false); |
| 147 | |
| 148 | EXPECT_FALSE(SimulateGestureScrollUpdate( |
| 149 | 200, 0, blink::kWebGestureDeviceTouchpad, false)); |
| 150 | SimulateAck(false); |
| 151 | EXPECT_EQ(OVERSCROLL_EAST, controller_mode()); |
| 152 | EXPECT_EQ(OverscrollSource::TOUCHPAD, controller_source()); |
| 153 | EXPECT_EQ(OVERSCROLL_EAST, delegate()->current_mode()); |
| 154 | EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); |
| 155 | |
| 156 | // Inertial update event complete the overscroll action. |
| 157 | EXPECT_FALSE(SimulateGestureScrollUpdate( |
| 158 | 100, 0, blink::kWebGestureDeviceTouchpad, true)); |
| 159 | SimulateAck(false); |
| 160 | EXPECT_EQ(OVERSCROLL_EAST, controller_mode()); |
| 161 | EXPECT_EQ(OverscrollSource::TOUCHPAD, controller_source()); |
| 162 | EXPECT_EQ(OVERSCROLL_EAST, delegate()->current_mode()); |
| 163 | EXPECT_EQ(OVERSCROLL_EAST, delegate()->completed_mode()); |
| 164 | |
| 165 | // Next Inertial update event would be consumed by overscroll controller. |
| 166 | EXPECT_TRUE(SimulateGestureScrollUpdate( |
| 167 | 100, 0, blink::kWebGestureDeviceTouchpad, true)); |
| 168 | } |
| 169 | |
Mohsen Izadi | 9830436c | 2017-12-21 18:02:46 | [diff] [blame] | 170 | } // namespace content |