Index: content/browser/renderer_host/render_widget_host_view_aura_unittest.cc |
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc |
index 2a418dfcc1ade891b6f2172a09a56c4a5266e1b7..80e951783553577f4120015b9823f2472ad0cf13 100644 |
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc |
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc |
@@ -15,11 +15,14 @@ |
#include "cc/output/copy_output_request.h" |
#include "content/browser/browser_thread_impl.h" |
#include "content/browser/compositor/resize_lock.h" |
+#include "content/browser/renderer_host/overscroll_controller.h" |
+#include "content/browser/renderer_host/overscroll_controller_delegate.h" |
#include "content/browser/renderer_host/render_widget_host_delegate.h" |
#include "content/browser/renderer_host/render_widget_host_impl.h" |
#include "content/common/gpu/client/gl_helper.h" |
#include "content/common/gpu/gpu_messages.h" |
#include "content/common/host_shared_bitmap_manager.h" |
+#include "content/common/input/synthetic_web_input_event_builders.h" |
#include "content/common/input_messages.h" |
#include "content/common/view_messages.h" |
#include "content/public/browser/render_widget_host_view.h" |
@@ -48,10 +51,18 @@ |
#include "ui/compositor/test/in_process_context_factory.h" |
#include "ui/events/event.h" |
#include "ui/events/event_utils.h" |
+#include "ui/events/gestures/gesture_configuration.h" |
#include "ui/wm/core/default_activation_client.h" |
using testing::_; |
+using blink::WebGestureEvent; |
+using blink::WebInputEvent; |
+using blink::WebMouseEvent; |
+using blink::WebMouseWheelEvent; |
+using blink::WebTouchEvent; |
+using blink::WebTouchPoint; |
+ |
namespace content { |
namespace { |
@@ -84,6 +95,61 @@ class TestScreenPositionClient |
} |
}; |
+class TestOverscrollDelegate : public OverscrollControllerDelegate { |
+ public: |
+ explicit TestOverscrollDelegate(RenderWidgetHostView* view) |
+ : view_(view), |
+ current_mode_(OVERSCROLL_NONE), |
+ completed_mode_(OVERSCROLL_NONE), |
+ delta_x_(0.f), |
+ delta_y_(0.f) {} |
+ |
+ virtual ~TestOverscrollDelegate() {} |
+ |
+ OverscrollMode current_mode() const { return current_mode_; } |
+ OverscrollMode completed_mode() const { return completed_mode_; } |
+ float delta_x() const { return delta_x_; } |
+ float delta_y() const { return delta_y_; } |
+ |
+ void Reset() { |
+ current_mode_ = OVERSCROLL_NONE; |
+ completed_mode_ = OVERSCROLL_NONE; |
+ delta_x_ = delta_y_ = 0.f; |
+ } |
+ |
+ private: |
+ // Overridden from OverscrollControllerDelegate: |
+ virtual gfx::Rect GetVisibleBounds() const OVERRIDE { |
+ return view_->IsShowing() ? view_->GetViewBounds() : gfx::Rect(); |
+ } |
+ |
+ virtual void OnOverscrollUpdate(float delta_x, float delta_y) OVERRIDE { |
+ delta_x_ = delta_x; |
+ delta_y_ = delta_y; |
+ } |
+ |
+ virtual void OnOverscrollComplete(OverscrollMode overscroll_mode) OVERRIDE { |
+ EXPECT_EQ(current_mode_, overscroll_mode); |
+ completed_mode_ = overscroll_mode; |
+ current_mode_ = OVERSCROLL_NONE; |
+ } |
+ |
+ virtual void OnOverscrollModeChange(OverscrollMode old_mode, |
+ OverscrollMode new_mode) OVERRIDE { |
+ EXPECT_EQ(current_mode_, old_mode); |
+ current_mode_ = new_mode; |
+ delta_x_ = delta_y_ = 0.f; |
+ } |
+ |
+ RenderWidgetHostView* view_; |
+ OverscrollMode current_mode_; |
+ OverscrollMode completed_mode_; |
+ float delta_x_; |
+ float delta_y_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TestOverscrollDelegate); |
+}; |
+ |
class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate { |
public: |
MockRenderWidgetHostDelegate() {} |
@@ -203,6 +269,43 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura { |
scoped_ptr<cc::CopyOutputRequest> last_copy_request_; |
}; |
+// A layout manager that always resizes a child to the root window size. |
+class FullscreenLayoutManager : public aura::LayoutManager { |
+ public: |
+ explicit FullscreenLayoutManager(aura::Window* owner) : owner_(owner) {} |
+ virtual ~FullscreenLayoutManager() {} |
+ |
+ // Overridden from aura::LayoutManager: |
+ virtual void OnWindowResized() OVERRIDE { |
+ aura::Window::Windows::const_iterator i; |
+ for (i = owner_->children().begin(); i != owner_->children().end(); ++i) { |
+ (*i)->SetBounds(gfx::Rect()); |
+ } |
+ } |
+ virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE { |
+ child->SetBounds(gfx::Rect()); |
+ } |
+ virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {} |
+ virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {} |
+ virtual void OnChildWindowVisibilityChanged(aura::Window* child, |
+ bool visible) OVERRIDE {} |
+ virtual void SetChildBounds(aura::Window* child, |
+ const gfx::Rect& requested_bounds) OVERRIDE { |
+ SetChildBoundsDirect(child, gfx::Rect(owner_->bounds().size())); |
+ } |
+ |
+ private: |
+ aura::Window* owner_; |
+ DISALLOW_COPY_AND_ASSIGN(FullscreenLayoutManager); |
+}; |
+ |
+class MockWindowObserver : public aura::WindowObserver { |
+ public: |
+ MOCK_METHOD2(OnWindowPaintScheduled, void(aura::Window*, const gfx::Rect&)); |
+}; |
+ |
+} // namespace |
+ |
class RenderWidgetHostViewAuraTest : public testing::Test { |
public: |
RenderWidgetHostViewAuraTest() |
@@ -281,59 +384,237 @@ class RenderWidgetHostViewAuraTest : public testing::Test { |
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraTest); |
}; |
-class RenderWidgetHostViewAuraShutdownTest |
+class RenderWidgetHostViewAuraOverscrollTest |
: public RenderWidgetHostViewAuraTest { |
public: |
- RenderWidgetHostViewAuraShutdownTest() {} |
+ RenderWidgetHostViewAuraOverscrollTest() {} |
- virtual void TearDown() OVERRIDE { |
- // No TearDownEnvironment here, we do this explicitly during the test. |
+ // We explicitly invoke SetUp to allow gesture debounce customization. |
+ virtual void SetUp() {} |
+ |
+ protected: |
+ void SetUpOverscrollEnvironmentWithDebounce(int debounce_interval_in_ms) { |
+ SetUpOverscrollEnvironmentImpl(debounce_interval_in_ms); |
} |
- private: |
- DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraShutdownTest); |
-}; |
+ void SetUpOverscrollEnvironment() { SetUpOverscrollEnvironmentImpl(0); } |
-// A layout manager that always resizes a child to the root window size. |
-class FullscreenLayoutManager : public aura::LayoutManager { |
- public: |
- explicit FullscreenLayoutManager(aura::Window* owner) |
- : owner_(owner) {} |
- virtual ~FullscreenLayoutManager() {} |
+ void SetUpOverscrollEnvironmentImpl(int debounce_interval_in_ms) { |
+ ui::GestureConfiguration::set_scroll_debounce_interval_in_ms( |
+ debounce_interval_in_ms); |
- // Overridden from aura::LayoutManager: |
- virtual void OnWindowResized() OVERRIDE { |
- aura::Window::Windows::const_iterator i; |
- for (i = owner_->children().begin(); i != owner_->children().end(); ++i) { |
- (*i)->SetBounds(gfx::Rect()); |
- } |
+ RenderWidgetHostViewAuraTest::SetUp(); |
+ |
+ view_->SetOverscrollControllerEnabled(true); |
+ overscroll_delegate_.reset(new TestOverscrollDelegate(view_)); |
+ view_->overscroll_controller()->set_delegate(overscroll_delegate_.get()); |
+ |
+ view_->InitAsChild(NULL); |
+ view_->SetBounds(gfx::Rect(0, 0, 400, 200)); |
+ view_->Show(); |
+ |
+ sink_->ClearMessages(); |
} |
- virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE { |
- child->SetBounds(gfx::Rect()); |
+ |
+ // TODO(jdduke): Simulate ui::Events, injecting through the view. |
+ void SimulateMouseEvent(WebInputEvent::Type type) { |
+ widget_host_->ForwardMouseEvent(SyntheticWebMouseEventBuilder::Build(type)); |
} |
- virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE { |
+ |
+ void SimulateMouseEventWithLatencyInfo(WebInputEvent::Type type, |
+ const ui::LatencyInfo& ui_latency) { |
+ widget_host_->ForwardMouseEventWithLatencyInfo( |
+ SyntheticWebMouseEventBuilder::Build(type), ui_latency); |
} |
- virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE { |
+ |
+ void SimulateWheelEvent(float dX, float dY, int modifiers, bool precise) { |
+ widget_host_->ForwardWheelEvent( |
+ SyntheticWebMouseWheelEventBuilder::Build(dX, dY, modifiers, precise)); |
} |
- virtual void OnChildWindowVisibilityChanged(aura::Window* child, |
- bool visible) OVERRIDE { |
+ |
+ void SimulateWheelEventWithLatencyInfo(float dX, |
+ float dY, |
+ int modifiers, |
+ bool precise, |
+ const ui::LatencyInfo& ui_latency) { |
+ widget_host_->ForwardWheelEventWithLatencyInfo( |
+ SyntheticWebMouseWheelEventBuilder::Build(dX, dY, modifiers, precise), |
+ ui_latency); |
} |
- virtual void SetChildBounds(aura::Window* child, |
- const gfx::Rect& requested_bounds) OVERRIDE { |
- SetChildBoundsDirect(child, gfx::Rect(owner_->bounds().size())); |
+ |
+ void SimulateMouseMove(int x, int y, int modifiers) { |
+ SimulateMouseEvent(WebInputEvent::MouseMove, x, y, modifiers, false); |
+ } |
+ |
+ void SimulateMouseEvent(WebInputEvent::Type type, |
+ int x, |
+ int y, |
+ int modifiers, |
+ bool pressed) { |
+ WebMouseEvent event = |
+ SyntheticWebMouseEventBuilder::Build(type, x, y, modifiers); |
+ if (pressed) |
+ event.button = WebMouseEvent::ButtonLeft; |
+ widget_host_->ForwardMouseEvent(event); |
+ } |
+ |
+ void SimulateWheelEventWithPhase(WebMouseWheelEvent::Phase phase) { |
+ widget_host_->ForwardWheelEvent( |
+ SyntheticWebMouseWheelEventBuilder::Build(phase)); |
+ } |
+ |
+ // Inject provided synthetic WebGestureEvent instance. |
+ void SimulateGestureEventCore(const WebGestureEvent& gesture_event) { |
+ widget_host_->ForwardGestureEvent(gesture_event); |
+ } |
+ |
+ void SimulateGestureEventCoreWithLatencyInfo( |
+ const WebGestureEvent& gesture_event, |
+ const ui::LatencyInfo& ui_latency) { |
+ widget_host_->ForwardGestureEventWithLatencyInfo(gesture_event, ui_latency); |
+ } |
+ |
+ // Inject simple synthetic WebGestureEvent instances. |
+ void SimulateGestureEvent(WebInputEvent::Type type, |
+ WebGestureEvent::SourceDevice sourceDevice) { |
+ SimulateGestureEventCore( |
+ SyntheticWebGestureEventBuilder::Build(type, sourceDevice)); |
+ } |
+ |
+ void SimulateGestureEventWithLatencyInfo( |
+ WebInputEvent::Type type, |
+ WebGestureEvent::SourceDevice sourceDevice, |
+ const ui::LatencyInfo& ui_latency) { |
+ SimulateGestureEventCoreWithLatencyInfo( |
+ SyntheticWebGestureEventBuilder::Build(type, sourceDevice), ui_latency); |
+ } |
+ |
+ void SimulateGestureScrollUpdateEvent(float dX, float dY, int modifiers) { |
+ SimulateGestureEventCore( |
+ SyntheticWebGestureEventBuilder::BuildScrollUpdate(dX, dY, modifiers)); |
+ } |
+ |
+ void SimulateGesturePinchUpdateEvent(float scale, |
+ float anchorX, |
+ float anchorY, |
+ int modifiers) { |
+ SimulateGestureEventCore(SyntheticWebGestureEventBuilder::BuildPinchUpdate( |
+ scale, anchorX, anchorY, modifiers, WebGestureEvent::Touchscreen)); |
+ } |
+ |
+ // Inject synthetic GestureFlingStart events. |
+ void SimulateGestureFlingStartEvent( |
+ float velocityX, |
+ float velocityY, |
+ WebGestureEvent::SourceDevice sourceDevice) { |
+ SimulateGestureEventCore(SyntheticWebGestureEventBuilder::BuildFling( |
+ velocityX, velocityY, sourceDevice)); |
+ } |
+ |
+ void SendInputEventACK(WebInputEvent::Type type, |
+ InputEventAckState ack_result) { |
+ InputHostMsg_HandleInputEvent_ACK_Params ack; |
+ ack.type = type; |
+ ack.state = ack_result; |
+ InputHostMsg_HandleInputEvent_ACK response(0, ack); |
+ widget_host_->OnMessageReceived(response); |
} |
+ bool ScrollStateIsContentScrolling() const { |
+ return scroll_state() == OverscrollController::STATE_CONTENT_SCROLLING; |
+ } |
+ |
+ bool ScrollStateIsOverscrolling() const { |
+ return scroll_state() == OverscrollController::STATE_OVERSCROLLING; |
+ } |
+ |
+ bool ScrollStateIsUnknown() const { |
+ return scroll_state() == OverscrollController::STATE_UNKNOWN; |
+ } |
+ |
+ OverscrollController::ScrollState scroll_state() const { |
+ return view_->overscroll_controller()->scroll_state_; |
+ } |
+ |
+ OverscrollMode overscroll_mode() const { |
+ return view_->overscroll_controller()->overscroll_mode_; |
+ } |
+ |
+ float overscroll_delta_x() const { |
+ return view_->overscroll_controller()->overscroll_delta_x_; |
+ } |
+ |
+ float overscroll_delta_y() const { |
+ return view_->overscroll_controller()->overscroll_delta_y_; |
+ } |
+ |
+ TestOverscrollDelegate* overscroll_delegate() { |
+ return overscroll_delegate_.get(); |
+ } |
+ |
+ void SendTouchEvent() { |
+ widget_host_->ForwardTouchEventWithLatencyInfo(touch_event_, |
+ ui::LatencyInfo()); |
+ touch_event_.ResetPoints(); |
+ } |
+ |
+ void PressTouchPoint(int x, int y) { |
+ touch_event_.PressPoint(x, y); |
+ SendTouchEvent(); |
+ } |
+ |
+ void MoveTouchPoint(int index, int x, int y) { |
+ touch_event_.MovePoint(index, x, y); |
+ SendTouchEvent(); |
+ } |
+ |
+ void ReleaseTouchPoint(int index) { |
+ touch_event_.ReleasePoint(index); |
+ SendTouchEvent(); |
+ } |
+ |
+ size_t GetSentMessageCountAndResetSink() { |
+ size_t count = sink_->message_count(); |
+ sink_->ClearMessages(); |
+ return count; |
+ } |
+ |
+ void AckLastSentInputEventIfNecessary(InputEventAckState ack_result) { |
+ if (!sink_->message_count()) |
+ return; |
+ |
+ InputMsg_HandleInputEvent::Param params; |
+ if (!InputMsg_HandleInputEvent::Read( |
+ sink_->GetMessageAt(sink_->message_count() - 1), ¶ms)) { |
+ return; |
+ } |
+ |
+ if (WebInputEventTraits::IgnoresAckDisposition(*params.a)) |
+ return; |
+ |
+ SendInputEventACK(params.a->type, ack_result); |
+ } |
+ |
+ SyntheticWebTouchEvent touch_event_; |
+ |
+ scoped_ptr<TestOverscrollDelegate> overscroll_delegate_; |
+ |
private: |
- aura::Window* owner_; |
- DISALLOW_COPY_AND_ASSIGN(FullscreenLayoutManager); |
+ DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraOverscrollTest); |
}; |
-class MockWindowObserver : public aura::WindowObserver { |
+class RenderWidgetHostViewAuraShutdownTest |
+ : public RenderWidgetHostViewAuraTest { |
public: |
- MOCK_METHOD2(OnWindowPaintScheduled, void(aura::Window*, const gfx::Rect&)); |
-}; |
+ RenderWidgetHostViewAuraShutdownTest() {} |
-} // namespace |
+ virtual void TearDown() OVERRIDE { |
+ // No TearDownEnvironment here, we do this explicitly during the test. |
+ } |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraShutdownTest); |
+}; |
// Checks that a fullscreen view has the correct show-state and receives the |
// focus. |
@@ -1519,4 +1800,871 @@ TEST_F(RenderWidgetHostViewAuraTest, VisibleViewportTest) { |
EXPECT_EQ(60, params.a.visible_viewport_size.height()); |
} |
+// Tests that scroll ACKs are correctly handled by the overscroll-navigation |
+// controller. |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, WheelScrollEventOverscrolls) { |
+ SetUpOverscrollEnvironment(); |
+ |
+ // Simulate wheel events. |
+ SimulateWheelEvent(-5, 0, 0, true); // sent directly |
+ SimulateWheelEvent(-1, 1, 0, true); // enqueued |
+ SimulateWheelEvent(-10, -3, 0, true); // coalesced into previous event |
+ SimulateWheelEvent(-15, -1, 0, true); // coalesced into previous event |
+ SimulateWheelEvent(-30, -3, 0, true); // coalesced into previous event |
+ SimulateWheelEvent(-20, 6, 1, true); // enqueued, different modifiers |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Receive ACK the first wheel event as not processed. |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Receive ACK for the second (coalesced) event as not processed. This will |
+ // start a back navigation. However, this will also cause the queued next |
+ // event to be sent to the renderer. But since overscroll navigation has |
+ // started, that event will also be included in the overscroll computation |
+ // instead of being sent to the renderer. So the result will be an overscroll |
+ // back navigation, and no event will be sent to the renderer. |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(-81.f, overscroll_delta_x()); |
+ EXPECT_EQ(-31.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ |
+ // Send a mouse-move event. This should cancel the overscroll navigation. |
+ SimulateMouseMove(5, 10, 0); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, sink_->message_count()); |
+} |
+ |
+// Tests that if some scroll events are consumed towards the start, then |
+// subsequent scrolls do not horizontal overscroll. |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, |
+ WheelScrollConsumedDoNotHorizOverscroll) { |
+ SetUpOverscrollEnvironment(); |
+ |
+ // Simulate wheel events. |
+ SimulateWheelEvent(-5, 0, 0, true); // sent directly |
+ SimulateWheelEvent(-1, -1, 0, true); // enqueued |
+ SimulateWheelEvent(-10, -3, 0, true); // coalesced into previous event |
+ SimulateWheelEvent(-15, -1, 0, true); // coalesced into previous event |
+ SimulateWheelEvent(-30, -3, 0, true); // coalesced into previous event |
+ SimulateWheelEvent(-20, 6, 1, true); // enqueued, different modifiers |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Receive ACK the first wheel event as processed. |
+ SendInputEventACK(WebInputEvent::MouseWheel, INPUT_EVENT_ACK_STATE_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Receive ACK for the second (coalesced) event as not processed. This should |
+ // not initiate overscroll, since the beginning of the scroll has been |
+ // consumed. The queued event with different modifiers should be sent to the |
+ // renderer. |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ |
+ // Indicate the end of the scrolling from the touchpad. |
+ SimulateGestureFlingStartEvent(-1200.f, 0.f, WebGestureEvent::Touchpad); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Start another scroll. This time, do not consume any scroll events. |
+ SimulateWheelEvent(0, -5, 0, true); // sent directly |
+ SimulateWheelEvent(0, -1, 0, true); // enqueued |
+ SimulateWheelEvent(-10, -3, 0, true); // coalesced into previous event |
+ SimulateWheelEvent(-15, -1, 0, true); // coalesced into previous event |
+ SimulateWheelEvent(-30, -3, 0, true); // coalesced into previous event |
+ SimulateWheelEvent(-20, 6, 1, true); // enqueued, different modifiers |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Receive ACK for the first wheel and the subsequent coalesced event as not |
+ // processed. This should start a back-overscroll. |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode()); |
+} |
+ |
+// Tests that wheel-scrolling correctly turns overscroll on and off. |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, WheelScrollOverscrollToggle) { |
+ SetUpOverscrollEnvironment(); |
+ |
+ // Send a wheel event. ACK the event as not processed. This should not |
+ // initiate an overscroll gesture since it doesn't cross the threshold yet. |
+ SimulateWheelEvent(10, 0, 0, true); |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Scroll some more so as to not overscroll. |
+ SimulateWheelEvent(10, 0, 0, true); |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Scroll some more to initiate an overscroll. |
+ SimulateWheelEvent(40, 0, 0, true); |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(60.f, overscroll_delta_x()); |
+ EXPECT_EQ(10.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Scroll in the reverse direction enough to abort the overscroll. |
+ SimulateWheelEvent(-20, 0, 0, true); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ |
+ // Continue to scroll in the reverse direction. |
+ SimulateWheelEvent(-20, 0, 0, true); |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Continue to scroll in the reverse direction enough to initiate overscroll |
+ // in that direction. |
+ SimulateWheelEvent(-55, 0, 0, true); |
+ EXPECT_EQ(1U, sink_->message_count()); |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(-75.f, overscroll_delta_x()); |
+ EXPECT_EQ(-25.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); |
+} |
+ |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, |
+ ScrollEventsOverscrollWithFling) { |
+ SetUpOverscrollEnvironment(); |
+ |
+ // Send a wheel event. ACK the event as not processed. This should not |
+ // initiate an overscroll gesture since it doesn't cross the threshold yet. |
+ SimulateWheelEvent(10, 0, 0, true); |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Scroll some more so as to not overscroll. |
+ SimulateWheelEvent(20, 0, 0, true); |
+ EXPECT_EQ(1U, sink_->message_count()); |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ sink_->ClearMessages(); |
+ |
+ // Scroll some more to initiate an overscroll. |
+ SimulateWheelEvent(30, 0, 0, true); |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(60.f, overscroll_delta_x()); |
+ EXPECT_EQ(10.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Send a fling start, but with a small velocity, so that the overscroll is |
+ // aborted. The fling should proceed to the renderer, through the gesture |
+ // event filter. |
+ SimulateGestureFlingStartEvent(0.f, 0.1f, WebGestureEvent::Touchpad); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(1U, sink_->message_count()); |
+} |
+ |
+// Same as ScrollEventsOverscrollWithFling, but with zero velocity. Checks that |
+// the zero-velocity fling does not reach the renderer. |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, |
+ ScrollEventsOverscrollWithZeroFling) { |
+ SetUpOverscrollEnvironment(); |
+ |
+ // Send a wheel event. ACK the event as not processed. This should not |
+ // initiate an overscroll gesture since it doesn't cross the threshold yet. |
+ SimulateWheelEvent(10, 0, 0, true); |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Scroll some more so as to not overscroll. |
+ SimulateWheelEvent(20, 0, 0, true); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ |
+ // Scroll some more to initiate an overscroll. |
+ SimulateWheelEvent(30, 0, 0, true); |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(60.f, overscroll_delta_x()); |
+ EXPECT_EQ(10.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Send a fling start, but with a small velocity, so that the overscroll is |
+ // aborted. The fling should proceed to the renderer, through the gesture |
+ // event filter. |
+ SimulateGestureFlingStartEvent(10.f, 0.f, WebGestureEvent::Touchpad); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(1U, sink_->message_count()); |
+} |
+ |
+// Tests that a fling in the opposite direction of the overscroll cancels the |
+// overscroll nav instead of completing it. |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, ReverseFlingCancelsOverscroll) { |
+ SetUpOverscrollEnvironment(); |
+ |
+ { |
+ // Start and end a gesture in the same direction without processing the |
+ // gesture events in the renderer. This should initiate and complete an |
+ // overscroll navigation. |
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin, |
+ WebGestureEvent::Touchscreen); |
+ SimulateGestureScrollUpdateEvent(300, -5, 0); |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ sink_->ClearMessages(); |
+ |
+ SimulateGestureEvent(WebInputEvent::GestureScrollEnd, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->completed_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, sink_->message_count()); |
+ } |
+ |
+ { |
+ // Start over, except instead of ending the gesture with ScrollEnd, end it |
+ // with a FlingStart, with velocity in the reverse direction. This should |
+ // initiate an overscroll navigation, but it should be cancelled because of |
+ // the fling in the opposite direction. |
+ overscroll_delegate()->Reset(); |
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin, |
+ WebGestureEvent::Touchscreen); |
+ SimulateGestureScrollUpdateEvent(-300, -5, 0); |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->current_mode()); |
+ sink_->ClearMessages(); |
+ |
+ SimulateGestureFlingStartEvent(100, 0, WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->completed_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, sink_->message_count()); |
+ } |
+} |
+ |
+// Tests that touch-scroll events are handled correctly by the overscroll |
+// controller. This also tests that the overscroll controller and the |
+// gesture-event filter play nice with each other. |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, GestureScrollOverscrolls) { |
+ SetUpOverscrollEnvironment(); |
+ |
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Send another gesture event and ACK as not being processed. This should |
+ // initiate the navigation gesture. |
+ SimulateGestureScrollUpdateEvent(55, -5, 0); |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(55.f, overscroll_delta_x()); |
+ EXPECT_EQ(-5.f, overscroll_delta_y()); |
+ EXPECT_EQ(5.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(-5.f, overscroll_delegate()->delta_y()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Send another gesture update event. This event should be consumed by the |
+ // controller, and not be forwarded to the renderer. The gesture-event filter |
+ // should not also receive this event. |
+ SimulateGestureScrollUpdateEvent(10, -5, 0); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(65.f, overscroll_delta_x()); |
+ EXPECT_EQ(-10.f, overscroll_delta_y()); |
+ EXPECT_EQ(15.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(-10.f, overscroll_delegate()->delta_y()); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ |
+ // Now send a scroll end. This should cancel the overscroll gesture, and send |
+ // the event to the renderer. The gesture-event filter should receive this |
+ // event. |
+ SimulateGestureEvent(WebInputEvent::GestureScrollEnd, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, sink_->message_count()); |
+} |
+ |
+// Tests that if the page is scrolled because of a scroll-gesture, then that |
+// particular scroll sequence never generates overscroll if the scroll direction |
+// is horizontal. |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, |
+ GestureScrollConsumedHorizontal) { |
+ SetUpOverscrollEnvironment(); |
+ |
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin, |
+ WebGestureEvent::Touchscreen); |
+ SimulateGestureScrollUpdateEvent(10, 0, 0); |
+ |
+ // Start scrolling on content. ACK both events as being processed. |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ sink_->ClearMessages(); |
+ |
+ // Send another gesture event and ACK as not being processed. This should |
+ // not initiate overscroll because the beginning of the scroll event did |
+ // scroll some content on the page. Since there was no overscroll, the event |
+ // should reach the renderer. |
+ SimulateGestureScrollUpdateEvent(55, 0, 0); |
+ EXPECT_EQ(1U, sink_->message_count()); |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+} |
+ |
+// Tests that the overscroll controller plays nice with touch-scrolls and the |
+// gesture event filter with debounce filtering turned on. |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, |
+ GestureScrollDebounceOverscrolls) { |
+ SetUpOverscrollEnvironmentWithDebounce(100); |
+ |
+ // Start scrolling. Receive ACK as it being processed. |
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Send update events. |
+ SimulateGestureScrollUpdateEvent(25, 0, 0); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Quickly end and restart the scroll gesture. These two events should get |
+ // discarded. |
+ SimulateGestureEvent(WebInputEvent::GestureScrollEnd, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ |
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ |
+ // Send another update event. This should get into the queue. |
+ SimulateGestureScrollUpdateEvent(30, 0, 0); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ |
+ // Receive an ACK for the first scroll-update event as not being processed. |
+ // This will contribute to the overscroll gesture, but not enough for the |
+ // overscroll controller to start consuming gesture events. This also cause |
+ // the queued gesture event to be forwarded to the renderer. |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Send another update event. This should get into the queue. |
+ SimulateGestureScrollUpdateEvent(10, 0, 0); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ |
+ // Receive an ACK for the second scroll-update event as not being processed. |
+ // This will now initiate an overscroll. This will also cause the queued |
+ // gesture event to be released. But instead of going to the renderer, it will |
+ // be consumed by the overscroll controller. |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(65.f, overscroll_delta_x()); |
+ EXPECT_EQ(15.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+} |
+ |
+// Tests that the gesture debounce timer plays nice with the overscroll |
+// controller. |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, |
+ GestureScrollDebounceTimerOverscroll) { |
+ SetUpOverscrollEnvironmentWithDebounce(10); |
+ |
+ // Start scrolling. Receive ACK as it being processed. |
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Send update events. |
+ SimulateGestureScrollUpdateEvent(55, 0, 0); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Send an end event. This should get in the debounce queue. |
+ SimulateGestureEvent(WebInputEvent::GestureScrollEnd, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ |
+ // Receive ACK for the scroll-update event. |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(55.f, overscroll_delta_x()); |
+ EXPECT_EQ(5.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ |
+ // Let the timer for the debounce queue fire. That should release the queued |
+ // scroll-end event. Since overscroll has started, but there hasn't been |
+ // enough overscroll to complete the gesture, the overscroll controller |
+ // will reset the state. The scroll-end should therefore be dispatched to the |
+ // renderer, and the gesture-event-filter should await an ACK for it. |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::MessageLoop::QuitClosure(), |
+ base::TimeDelta::FromMilliseconds(15)); |
+ base::MessageLoop::current()->Run(); |
+ |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, sink_->message_count()); |
+} |
+ |
+// Tests that when touch-events are dispatched to the renderer, the overscroll |
+// gesture deals with them correctly. |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollWithTouchEvents) { |
+ SetUpOverscrollEnvironmentWithDebounce(10); |
+ widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true)); |
+ sink_->ClearMessages(); |
+ |
+ // The test sends an intermingled sequence of touch and gesture events. |
+ PressTouchPoint(0, 1); |
+ SendInputEventACK(WebInputEvent::TouchStart, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ MoveTouchPoint(0, 20, 5); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ SendInputEventACK(WebInputEvent::TouchMove, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ |
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ SimulateGestureScrollUpdateEvent(20, 0, 0); |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ |
+ // Another touch move event should reach the renderer since overscroll hasn't |
+ // started yet. Note that touch events sent during the scroll period may |
+ // not require an ack (having been marked uncancelable). |
+ MoveTouchPoint(0, 65, 10); |
+ AckLastSentInputEventIfNecessary(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ SimulateGestureScrollUpdateEvent(45, 0, 0); |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(65.f, overscroll_delta_x()); |
+ EXPECT_EQ(15.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Send another touch event. The page should get the touch-move event, even |
+ // though overscroll has started. |
+ MoveTouchPoint(0, 55, 5); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(65.f, overscroll_delta_x()); |
+ EXPECT_EQ(15.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); |
+ AckLastSentInputEventIfNecessary(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ SimulateGestureScrollUpdateEvent(-10, 0, 0); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(55.f, overscroll_delta_x()); |
+ EXPECT_EQ(5.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); |
+ |
+ PressTouchPoint(255, 5); |
+ AckLastSentInputEventIfNecessary(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ SimulateGestureScrollUpdateEvent(200, 0, 0); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(255.f, overscroll_delta_x()); |
+ EXPECT_EQ(205.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); |
+ |
+ // The touch-end/cancel event should always reach the renderer if the page has |
+ // touch handlers. |
+ ReleaseTouchPoint(1); |
+ AckLastSentInputEventIfNecessary(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ ReleaseTouchPoint(0); |
+ AckLastSentInputEventIfNecessary(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ SimulateGestureEvent(blink::WebInputEvent::GestureScrollEnd, |
+ WebGestureEvent::Touchscreen); |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::MessageLoop::QuitClosure(), |
+ base::TimeDelta::FromMilliseconds(10)); |
+ base::MessageLoop::current()->Run(); |
+ EXPECT_EQ(1U, sink_->message_count()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->completed_mode()); |
+} |
+ |
+// Tests that touch-gesture end is dispatched to the renderer at the end of a |
+// touch-gesture initiated overscroll. |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, |
+ TouchGestureEndDispatchedAfterOverscrollComplete) { |
+ SetUpOverscrollEnvironmentWithDebounce(10); |
+ widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true)); |
+ sink_->ClearMessages(); |
+ |
+ // Start scrolling. Receive ACK as it being processed. |
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ // The scroll begin event will have received a synthetic ack from the input |
+ // router. |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ |
+ // Send update events. |
+ SimulateGestureScrollUpdateEvent(55, -5, 0); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(55.f, overscroll_delta_x()); |
+ EXPECT_EQ(5.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(-5.f, overscroll_delegate()->delta_y()); |
+ |
+ // Send end event. |
+ SimulateGestureEvent(blink::WebInputEvent::GestureScrollEnd, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::MessageLoop::QuitClosure(), |
+ base::TimeDelta::FromMilliseconds(10)); |
+ base::MessageLoop::current()->Run(); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->completed_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Start scrolling. Receive ACK as it being processed. |
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ |
+ // Send update events. |
+ SimulateGestureScrollUpdateEvent(235, -5, 0); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(235.f, overscroll_delta_x()); |
+ EXPECT_EQ(185.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(-5.f, overscroll_delegate()->delta_y()); |
+ |
+ // Send end event. |
+ SimulateGestureEvent(blink::WebInputEvent::GestureScrollEnd, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::MessageLoop::QuitClosure(), |
+ base::TimeDelta::FromMilliseconds(10)); |
+ base::MessageLoop::current()->Run(); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->completed_mode()); |
+ EXPECT_EQ(1U, sink_->message_count()); |
+} |
+ |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollDirectionChange) { |
+ SetUpOverscrollEnvironmentWithDebounce(100); |
+ |
+ // Start scrolling. Receive ACK as it being processed. |
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Send update events and receive ack as not consumed. |
+ SimulateGestureScrollUpdateEvent(125, -5, 0); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ |
+ // Send another update event, but in the reverse direction. The overscroll |
+ // controller will consume the event, and reset the overscroll mode. |
+ SimulateGestureScrollUpdateEvent(-260, 0, 0); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ |
+ // Since the overscroll mode has been reset, the next scroll update events |
+ // should reach the renderer. |
+ SimulateGestureScrollUpdateEvent(-20, 0, 0); |
+ EXPECT_EQ(1U, sink_->message_count()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+} |
+ |
+// Tests that if a mouse-move event completes the overscroll gesture, future |
+// move events do reach the renderer. |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollMouseMoveCompletion) { |
+ SetUpOverscrollEnvironment(); |
+ |
+ SimulateWheelEvent(5, 0, 0, true); // sent directly |
+ SimulateWheelEvent(-1, 0, 0, true); // enqueued |
+ SimulateWheelEvent(-10, -3, 0, true); // coalesced into previous event |
+ SimulateWheelEvent(-15, -1, 0, true); // coalesced into previous event |
+ SimulateWheelEvent(-30, -3, 0, true); // coalesced into previous event |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Receive ACK the first wheel event as not processed. |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Receive ACK for the second (coalesced) event as not processed. This will |
+ // start an overcroll gesture. |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ |
+ // Send a mouse-move event. This should cancel the overscroll navigation |
+ // (since the amount overscrolled is not above the threshold), and so the |
+ // mouse-move should reach the renderer. |
+ SimulateMouseMove(5, 10, 0); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->completed_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ SendInputEventACK(WebInputEvent::MouseMove, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ |
+ // Moving the mouse more should continue to send the events to the renderer. |
+ SimulateMouseMove(5, 10, 0); |
+ SendInputEventACK(WebInputEvent::MouseMove, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Now try with gestures. |
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin, |
+ WebGestureEvent::Touchscreen); |
+ SimulateGestureScrollUpdateEvent(300, -5, 0); |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ sink_->ClearMessages(); |
+ |
+ // Overscroll gesture is in progress. Send a mouse-move now. This should |
+ // complete the gesture (because the amount overscrolled is above the |
+ // threshold). |
+ SimulateMouseMove(5, 10, 0); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->completed_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ SendInputEventACK(WebInputEvent::MouseMove, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ |
+ SimulateGestureEvent(WebInputEvent::GestureScrollEnd, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Move mouse some more. The mouse-move events should reach the renderer. |
+ SimulateMouseMove(5, 10, 0); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ SendInputEventACK(WebInputEvent::MouseMove, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+} |
+ |
+// Tests that if a page scrolled, then the overscroll controller's states are |
+// reset after the end of the scroll. |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, |
+ OverscrollStateResetsAfterScroll) { |
+ SetUpOverscrollEnvironment(); |
+ |
+ SimulateWheelEvent(0, 5, 0, true); // sent directly |
+ SimulateWheelEvent(0, 30, 0, true); // enqueued |
+ SimulateWheelEvent(0, 40, 0, true); // coalesced into previous event |
+ SimulateWheelEvent(0, 10, 0, true); // coalesced into previous event |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // The first wheel event is consumed. Dispatches the queued wheel event. |
+ SendInputEventACK(WebInputEvent::MouseWheel, INPUT_EVENT_ACK_STATE_CONSUMED); |
+ EXPECT_TRUE(ScrollStateIsContentScrolling()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // The second wheel event is consumed. |
+ SendInputEventACK(WebInputEvent::MouseWheel, INPUT_EVENT_ACK_STATE_CONSUMED); |
+ EXPECT_TRUE(ScrollStateIsContentScrolling()); |
+ |
+ // Touchpad scroll can end with a zero-velocity fling. But it is not |
+ // dispatched, but it should still reset the overscroll controller state. |
+ SimulateGestureFlingStartEvent(0.f, 0.f, WebGestureEvent::Touchpad); |
+ EXPECT_TRUE(ScrollStateIsUnknown()); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ |
+ SimulateWheelEvent(-5, 0, 0, true); // sent directly |
+ SimulateWheelEvent(-60, 0, 0, true); // enqueued |
+ SimulateWheelEvent(-100, 0, 0, true); // coalesced into previous event |
+ EXPECT_TRUE(ScrollStateIsUnknown()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // The first wheel scroll did not scroll content. Overscroll should not start |
+ // yet, since enough hasn't been scrolled. |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_TRUE(ScrollStateIsUnknown()); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ SendInputEventACK(WebInputEvent::MouseWheel, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode()); |
+ EXPECT_TRUE(ScrollStateIsOverscrolling()); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+ |
+ SimulateGestureFlingStartEvent(0.f, 0.f, WebGestureEvent::Touchpad); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->completed_mode()); |
+ EXPECT_TRUE(ScrollStateIsUnknown()); |
+ EXPECT_EQ(0U, sink_->message_count()); |
+} |
+ |
+TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollResetsOnBlur) { |
+ SetUpOverscrollEnvironment(); |
+ |
+ // Start an overscroll with gesture scroll. In the middle of the scroll, blur |
+ // the host. |
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin, |
+ WebGestureEvent::Touchscreen); |
+ SimulateGestureScrollUpdateEvent(300, -5, 0); |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(2U, GetSentMessageCountAndResetSink()); |
+ |
+ view_->OnWindowFocused(NULL, view_->GetAttachedWindow()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->completed_mode()); |
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_x()); |
+ EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); |
+ sink_->ClearMessages(); |
+ |
+ SimulateGestureEvent(WebInputEvent::GestureScrollEnd, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); |
+ |
+ // Start a scroll gesture again. This should correctly start the overscroll |
+ // after the threshold. |
+ SimulateGestureEvent(WebInputEvent::GestureScrollBegin, |
+ WebGestureEvent::Touchscreen); |
+ SimulateGestureScrollUpdateEvent(300, -5, 0); |
+ SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->completed_mode()); |
+ |
+ SimulateGestureEvent(WebInputEvent::GestureScrollEnd, |
+ WebGestureEvent::Touchscreen); |
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); |
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->completed_mode()); |
+ EXPECT_EQ(3U, sink_->message_count()); |
+} |
+ |
} // namespace content |