diff options
Diffstat (limited to 'chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc')
-rw-r--r-- | chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc | 915 |
1 files changed, 874 insertions, 41 deletions
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc index 4eef57c2d54..da442867180 100644 --- a/chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc +++ b/chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc @@ -23,27 +23,35 @@ #include "cc/surfaces/surface.h" #include "cc/surfaces/surface_manager.h" #include "content/browser/browser_thread_impl.h" -#include "content/browser/compositor/resize_lock.h" +#include "content/browser/compositor/gl_helper.h" #include "content/browser/compositor/test/no_transport_image_transport_factory.h" #include "content/browser/frame_host/render_widget_host_view_guest.h" #include "content/browser/gpu/compositor_util.h" #include "content/browser/renderer_host/input/input_router.h" +#include "content/browser/renderer_host/input/mouse_wheel_event_queue.h" #include "content/browser/renderer_host/input/web_input_event_util.h" #include "content/browser/renderer_host/overscroll_controller.h" #include "content/browser/renderer_host/overscroll_controller_delegate.h" +#include "content/browser/renderer_host/render_view_host_factory.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/browser/renderer_host/resize_lock.h" +#include "content/browser/web_contents/web_contents_view_aura.h" #include "content/common/host_shared_bitmap_manager.h" +#include "content/common/input/input_event_utils.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" #include "content/public/browser/render_widget_host_view_frame_subscriber.h" +#include "content/public/browser/web_contents_view_delegate.h" +#include "content/public/common/context_menu_params.h" #include "content/public/test/mock_render_process_host.h" #include "content/public/test/test_browser_context.h" +#include "content/test/test_render_view_host.h" +#include "content/test/test_web_contents.h" #include "ipc/ipc_test_sink.h" +#include "media/base/video_frame.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/aura/client/aura_constants.h" @@ -144,9 +152,11 @@ class TestOverscrollDelegate : public OverscrollControllerDelegate { class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate { public: - MockRenderWidgetHostDelegate() {} + MockRenderWidgetHostDelegate() : rwh_(nullptr) {} ~MockRenderWidgetHostDelegate() override {} const NativeWebKeyboardEvent* last_event() const { return last_event_.get(); } + void set_widget_host(RenderWidgetHostImpl* rwh) { rwh_ = rwh; } + protected: // RenderWidgetHostDelegate: bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, @@ -158,9 +168,14 @@ class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate { void Copy() override {} void Paste() override {} void SelectAll() override {} + void SendScreenRects() override { + if (rwh_) + rwh_->SendScreenRects(); + } private: scoped_ptr<NativeWebKeyboardEvent> last_event_; + RenderWidgetHostImpl* rwh_; DISALLOW_COPY_AND_ASSIGN(MockRenderWidgetHostDelegate); }; @@ -262,7 +277,7 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura { FakeRenderWidgetHostViewAura(RenderWidgetHost* widget, bool is_guest_view_hack) : RenderWidgetHostViewAura(widget, is_guest_view_hack), - has_resize_lock_(false) {} + can_create_resize_lock_(true) {} void UseFakeDispatcher() { dispatcher_ = new FakeWindowEventDispatcher(window()->GetHost()); @@ -279,7 +294,9 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura { new FakeResizeLock(desired_size, defer_compositor_lock)); } - bool DelegatedFrameCanCreateResizeLock() const override { return true; } + bool DelegatedFrameCanCreateResizeLock() const override { + return can_create_resize_lock_; + } void RunOnCompositingDidCommit() { GetDelegatedFrameHost()->OnCompositingDidCommitForTesting( @@ -299,16 +316,12 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura { } } - cc::DelegatedFrameProvider* frame_provider() const { - return GetDelegatedFrameHost()->FrameProviderForTesting(); - } - cc::SurfaceId surface_id() const { return GetDelegatedFrameHost()->SurfaceIdForTesting(); } bool HasFrameData() const { - return frame_provider() || !surface_id().is_null(); + return !surface_id().is_null(); } bool released_front_lock_active() const { @@ -327,7 +340,7 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura { return pointer_state(); } - bool has_resize_lock_; + bool can_create_resize_lock_; gfx::Size last_frame_size_; scoped_ptr<cc::CopyOutputRequest> last_copy_request_; FakeWindowEventDispatcher* dispatcher_; @@ -402,8 +415,10 @@ class RenderWidgetHostViewAuraTest : public testing::Test { sink_ = &process_host_->sink(); int32_t routing_id = process_host_->GetNextRoutingID(); - parent_host_ = - new RenderWidgetHostImpl(&delegate_, process_host_, routing_id, false); + delegates_.push_back(make_scoped_ptr(new MockRenderWidgetHostDelegate)); + parent_host_ = new RenderWidgetHostImpl(delegates_.back().get(), + process_host_, routing_id, false); + delegates_.back()->set_widget_host(parent_host_); parent_view_ = new RenderWidgetHostViewAura(parent_host_, is_guest_view_hack_); parent_view_->InitAsChild(NULL); @@ -412,8 +427,10 @@ class RenderWidgetHostViewAuraTest : public testing::Test { gfx::Rect()); routing_id = process_host_->GetNextRoutingID(); - widget_host_ = - new RenderWidgetHostImpl(&delegate_, process_host_, routing_id, false); + delegates_.push_back(make_scoped_ptr(new MockRenderWidgetHostDelegate)); + widget_host_ = new RenderWidgetHostImpl(delegates_.back().get(), + process_host_, routing_id, false); + delegates_.back()->set_widget_host(widget_host_); widget_host_->Init(); view_ = new FakeRenderWidgetHostViewAura(widget_host_, is_guest_view_hack_); } @@ -502,8 +519,8 @@ class RenderWidgetHostViewAuraTest : public testing::Test { return; } - if (!WebInputEventTraits::WillReceiveAckFromRenderer( - *base::get<0>(params))) + InputEventDispatchType dispatch_type = base::get<2>(params); + if (dispatch_type == InputEventDispatchType::DISPATCH_TYPE_NON_BLOCKING) return; const blink::WebInputEvent* event = base::get<0>(params); @@ -525,7 +542,7 @@ class RenderWidgetHostViewAuraTest : public testing::Test { BrowserThreadImpl browser_thread_for_ui_; scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_; scoped_ptr<BrowserContext> browser_context_; - MockRenderWidgetHostDelegate delegate_; + std::vector<scoped_ptr<MockRenderWidgetHostDelegate>> delegates_; MockRenderProcessHost* process_host_; // Tests should set these to NULL if they've already triggered their @@ -588,12 +605,27 @@ class RenderWidgetHostViewAuraOverscrollTest protected: void SetUpOverscrollEnvironmentWithDebounce(int debounce_interval_in_ms) { - SetUpOverscrollEnvironmentImpl(debounce_interval_in_ms); + SetUpOverscrollEnvironmentImpl(debounce_interval_in_ms, false); + } + + void SetUpOverscrollEnvironmentWithWheelGestures() { + SetUpOverscrollEnvironmentImpl(0, true); + } + + void SetUpOverscrollEnvironment() { + SetUpOverscrollEnvironmentImpl(0, false); } - void SetUpOverscrollEnvironment() { SetUpOverscrollEnvironmentImpl(0); } + void SetUpOverscrollEnvironmentImpl(int debounce_interval_in_ms, + bool enable_wheel_gestures) { + CHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableWheelGestures) && + !base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableWheelGestures)); + base::CommandLine::ForCurrentProcess()->AppendSwitch( + enable_wheel_gestures ? switches::kEnableWheelGestures + : switches::kDisableWheelGestures); - void SetUpOverscrollEnvironmentImpl(int debounce_interval_in_ms) { ui::GestureConfiguration::GetInstance()->set_scroll_debounce_interval_in_ms( debounce_interval_in_ms); @@ -1078,9 +1110,10 @@ TEST_F(RenderWidgetHostViewAuraTest, SetCompositionText) { EXPECT_EQ(underlines[i].background_color, base::get<1>(params)[i].backgroundColor); } + EXPECT_EQ(gfx::Range::InvalidRange(), base::get<2>(params)); // highlighted range - EXPECT_EQ(4, base::get<2>(params)) << "Should be the same to the caret pos"; EXPECT_EQ(4, base::get<3>(params)) << "Should be the same to the caret pos"; + EXPECT_EQ(4, base::get<4>(params)) << "Should be the same to the caret pos"; } view_->ImeCancelComposition(); @@ -1655,6 +1688,54 @@ TEST_F(RenderWidgetHostViewAuraTest, RecreateLayers) { } } +// If the view size is larger than the compositor frame then extra layers +// should be created to fill the gap. +TEST_F(RenderWidgetHostViewAuraTest, DelegatedFrameGutter) { + gfx::Size large_size(100, 100); + gfx::Size small_size(40, 45); + gfx::Size medium_size(40, 95); + + // Prevent the DelegatedFrameHost from skipping frames. + view_->can_create_resize_lock_ = false; + + view_->InitAsChild(NULL); + aura::client::ParentWindowWithContext( + view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), + gfx::Rect()); + view_->SetSize(large_size); + view_->Show(); + scoped_ptr<cc::CompositorFrame> frame = + MakeDelegatedFrame(1.f, small_size, gfx::Rect(small_size)); + frame->metadata.root_background_color = SK_ColorRED; + view_->OnSwapCompositorFrame(0, std::move(frame)); + + ui::Layer* parent_layer = view_->GetNativeView()->layer(); + + ASSERT_EQ(2u, parent_layer->children().size()); + EXPECT_EQ(gfx::Rect(40, 0, 60, 100), parent_layer->children()[0]->bounds()); + EXPECT_EQ(SK_ColorRED, parent_layer->children()[0]->background_color()); + EXPECT_EQ(gfx::Rect(0, 45, 40, 55), parent_layer->children()[1]->bounds()); + EXPECT_EQ(SK_ColorRED, parent_layer->children()[1]->background_color()); + + view_->SetSize(medium_size); + + // Right gutter is unnecessary. + ASSERT_EQ(1u, parent_layer->children().size()); + EXPECT_EQ(gfx::Rect(0, 45, 40, 50), parent_layer->children()[0]->bounds()); + + frame = MakeDelegatedFrame(1.f, medium_size, gfx::Rect(medium_size)); + view_->OnSwapCompositorFrame(0, std::move(frame)); + EXPECT_EQ(0u, parent_layer->children().size()); + + view_->SetSize(large_size); + ASSERT_EQ(2u, parent_layer->children().size()); + + // This should evict the frame and remove the gutter layers. + view_->Hide(); + view_->SetSize(small_size); + ASSERT_EQ(0u, parent_layer->children().size()); +} + TEST_F(RenderWidgetHostViewAuraTest, Resize) { gfx::Size size1(100, 100); gfx::Size size2(200, 200); @@ -1920,8 +2001,10 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) { // Create a bunch of renderers. for (size_t i = 0; i < renderer_count; ++i) { int32_t routing_id = process_host_->GetNextRoutingID(); - hosts[i] = - new RenderWidgetHostImpl(&delegate_, process_host_, routing_id, false); + delegates_.push_back(make_scoped_ptr(new MockRenderWidgetHostDelegate)); + hosts[i] = new RenderWidgetHostImpl(delegates_.back().get(), process_host_, + routing_id, false); + delegates_.back()->set_widget_host(hosts[i]); hosts[i]->Init(); views[i] = new FakeRenderWidgetHostViewAura(hosts[i], false); views[i]->InitAsChild(NULL); @@ -2084,8 +2167,10 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithLocking) { // Create a bunch of renderers. for (size_t i = 0; i < renderer_count; ++i) { int32_t routing_id = process_host_->GetNextRoutingID(); - hosts[i] = - new RenderWidgetHostImpl(&delegate_, process_host_, routing_id, false); + delegates_.push_back(make_scoped_ptr(new MockRenderWidgetHostDelegate)); + hosts[i] = new RenderWidgetHostImpl(delegates_.back().get(), process_host_, + routing_id, false); + delegates_.back()->set_widget_host(hosts[i]); hosts[i]->Init(); views[i] = new FakeRenderWidgetHostViewAura(hosts[i], false); views[i]->InitAsChild(NULL); @@ -2153,8 +2238,10 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithMemoryPressure) { // Create a bunch of renderers. for (size_t i = 0; i < renderer_count; ++i) { int32_t routing_id = process_host_->GetNextRoutingID(); - hosts[i] = - new RenderWidgetHostImpl(&delegate_, process_host_, routing_id, false); + delegates_.push_back(make_scoped_ptr(new MockRenderWidgetHostDelegate)); + hosts[i] = new RenderWidgetHostImpl(delegates_.back().get(), process_host_, + routing_id, false); + delegates_.back()->set_widget_host(hosts[i]); hosts[i]->Init(); views[i] = new FakeRenderWidgetHostViewAura(hosts[i], false); views[i]->InitAsChild(NULL); @@ -2215,9 +2302,6 @@ TEST_F(RenderWidgetHostViewAuraTest, SoftwareDPIChange) { view_->OnSwapCompositorFrame( 1, MakeDelegatedFrame(1.f, frame_size, gfx::Rect(frame_size))); - // Save the frame provider. - scoped_refptr<cc::DelegatedFrameProvider> frame_provider = - view_->frame_provider(); cc::SurfaceId surface_id = view_->surface_id(); // This frame will have the same number of physical pixels, but has a new @@ -2225,13 +2309,10 @@ TEST_F(RenderWidgetHostViewAuraTest, SoftwareDPIChange) { view_->OnSwapCompositorFrame( 1, MakeDelegatedFrame(2.f, frame_size, gfx::Rect(frame_size))); - // When we get a new frame with the same frame size in physical pixels, but a - // different scale, we should generate a new frame provider, as the final - // result will need to be scaled differently to the screen. - if (frame_provider.get()) - EXPECT_NE(frame_provider.get(), view_->frame_provider()); - else - EXPECT_NE(surface_id, view_->surface_id()); + // When we get a new frame with the same frame size in physical pixels, but + // a different scale, we should generate a surface, as the final result will + // need to be scaled differently to the screen. + EXPECT_NE(surface_id, view_->surface_id()); } class RenderWidgetHostViewAuraCopyRequestTest @@ -2578,6 +2659,70 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, WheelScrollEventOverscrolls) { EXPECT_EQ(1U, sink_->message_count()); } +// Disabled on MacOS because it doesn't support wheel gestures +// just yet. +#if defined(OS_MACOSX) +#define MAYBE_WheelScrollEventOverscrollsWithWheelGestures \ + DISABLED_WheelScrollEventOverscrollsWithWheelGestures +#else +#define MAYBE_WheelScrollEventOverscrollsWithWheelGestures \ + WheelScrollEventOverscrollsWithWheelGestures +#endif +TEST_F(RenderWidgetHostViewAuraOverscrollTest, + MAYBE_WheelScrollEventOverscrollsWithWheelGestures) { + SetUpOverscrollEnvironmentWithWheelGestures(); + + // 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); + + // ScrollBegin, ScrollUpdate, MouseWheel will be queued events + EXPECT_EQ(3U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); + + // 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); + // ScrollUpdate, MouseWheel will be queued events + EXPECT_EQ(2U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + 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, @@ -2642,6 +2787,65 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode()); } +// Tests that if some scroll events are consumed towards the start, then +// subsequent scrolls do not horizontal overscroll. +// Disabled on MacOS because it doesn't support wheel gestures +// just yet. +#if defined(OS_MACOSX) +#define MAYBE_WheelScrollConsumedDoNotHorizOverscrollWithWheelGestures \ + DISABLED_WheelScrollConsumedDoNotHorizOverscrollWithWheelGestures +#else +#define MAYBE_WheelScrollConsumedDoNotHorizOverscrollWithWheelGestures \ + WheelScrollConsumedDoNotHorizOverscrollWithWheelGestures +#endif +TEST_F(RenderWidgetHostViewAuraOverscrollTest, + MAYBE_WheelScrollConsumedDoNotHorizOverscrollWithWheelGestures) { + SetUpOverscrollEnvironmentWithWheelGestures(); + + // 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_NOT_CONSUMED); + // ScrollBegin, ScrollUpdate, MouseWheel will be queued events + EXPECT_EQ(3U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_CONSUMED); + + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); + + // 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()); + // ScrollUpdate, MouseWheel will be queued events + EXPECT_EQ(2U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + // ScrollUpdate will be queued events + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + + EXPECT_EQ(0U, sink_->message_count()); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); +} + // Tests that wheel-scrolling correctly turns overscroll on and off. TEST_F(RenderWidgetHostViewAuraOverscrollTest, WheelScrollOverscrollToggle) { SetUpOverscrollEnvironment(); @@ -2701,6 +2905,95 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, WheelScrollOverscrollToggle) { EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); } +// Tests that wheel-scrolling correctly turns overscroll on and off. +// Disabled on MacOS because it doesn't support wheel gestures +// just yet. +#if defined(OS_MACOSX) +#define MAYBE_WheelScrollOverscrollToggleWithWheelGestures \ + DISABLED_WheelScrollOverscrollToggleWithWheelGestures +#else +#define MAYBE_WheelScrollOverscrollToggleWithWheelGestures \ + WheelScrollOverscrollToggleWithWheelGestures +#endif +TEST_F(RenderWidgetHostViewAuraOverscrollTest, + MAYBE_WheelScrollOverscrollToggleWithWheelGestures) { + SetUpOverscrollEnvironmentWithWheelGestures(); + + // 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); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(2U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); + + // Scroll some more so as to not overscroll. + SimulateWheelEvent(10, 0, 0, true); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + 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(40, 0, 0, true); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + 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(60.f, overscroll_delta_x()); + EXPECT_EQ(10.f, overscroll_delegate()->delta_x()); + EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); + + // Scroll in the reverse direction enough to abort the overscroll. + SimulateWheelEvent(-20, 0, 0, true); + 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()); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); + + // Continue to scroll in the reverse direction. + SimulateWheelEvent(-20, 0, 0, true); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(0U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); + + // Continue to scroll in the reverse direction enough to initiate overscroll + // in that direction. + SimulateWheelEvent(-55, 0, 0, true); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(0U, GetSentMessageCountAndResetSink()); + 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(); @@ -2744,6 +3037,68 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, EXPECT_EQ(2U, sink_->message_count()); } +// Disabled on MacOS because it doesn't support wheel gestures +// just yet. +#if defined(OS_MACOSX) +#define MAYBE_ScrollEventsOverscrollWithFlingAndWheelGestures \ + DISABLED_ScrollEventsOverscrollWithFlingAndWheelGestures +#else +#define MAYBE_ScrollEventsOverscrollWithFlingAndWheelGestures \ + ScrollEventsOverscrollWithFlingAndWheelGestures +#endif +TEST_F(RenderWidgetHostViewAuraOverscrollTest, + MAYBE_ScrollEventsOverscrollWithFlingAndWheelGestures) { + SetUpOverscrollEnvironmentWithWheelGestures(); + + // 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); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(2U, GetSentMessageCountAndResetSink()); + 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(0U, 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); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + 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); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + 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(0U, 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. + SimulateGestureEvent(WebInputEvent::GestureScrollBegin, + blink::WebGestureDeviceTouchscreen); + SimulateGestureFlingStartEvent(0.f, 0.1f, blink::WebGestureDeviceTouchpad); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + EXPECT_EQ(3U, sink_->message_count()); +} + // Same as ScrollEventsOverscrollWithFling, but with zero velocity. Checks that // the zero-velocity fling does not reach the renderer. TEST_F(RenderWidgetHostViewAuraOverscrollTest, @@ -2788,6 +3143,70 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, EXPECT_EQ(2U, sink_->message_count()); } +// Same as ScrollEventsOverscrollWithFling, but with zero velocity. Checks that +// the zero-velocity fling does not reach the renderer. +// Disabled on MacOS because it doesn't support wheel gestures +// just yet. +#if defined(OS_MACOSX) +#define MAYBE_ScrollEventsOverscrollWithZeroFlingAndWheelGestures \ + DISABLED_ScrollEventsOverscrollWithZeroFlingAndWheelGestures +#else +#define MAYBE_ScrollEventsOverscrollWithZeroFlingAndWheelGestures \ + ScrollEventsOverscrollWithZeroFlingAndWheelGestures +#endif +TEST_F(RenderWidgetHostViewAuraOverscrollTest, + MAYBE_ScrollEventsOverscrollWithZeroFlingAndWheelGestures) { + SetUpOverscrollEnvironmentWithWheelGestures(); + + // 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); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(2U, GetSentMessageCountAndResetSink()); + 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(0U, 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(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + 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); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + 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(60.f, overscroll_delta_x()); + EXPECT_EQ(10.f, overscroll_delegate()->delta_x()); + EXPECT_EQ(0.f, overscroll_delegate()->delta_y()); + EXPECT_EQ(0U, 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. + SimulateGestureEvent(WebInputEvent::GestureScrollBegin, + blink::WebGestureDeviceTouchscreen); + SimulateGestureFlingStartEvent(10.f, 0.f, blink::WebGestureDeviceTouchpad); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + EXPECT_EQ(3U, 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) { @@ -3260,6 +3679,61 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); } +// Disabled on MacOS because it doesn't support wheel gestures +// just yet. +#if defined(OS_MACOSX) +#define MAYBE_OverscrollDirectionChangeMouseWheelWithWheelGestures \ + DISABLED_OverscrollDirectionChangeMouseWheelWithWheelGestures +#else +#define MAYBE_OverscrollDirectionChangeMouseWheelWithWheelGestures \ + OverscrollDirectionChangeMouseWheelWithWheelGestures +#endif +TEST_F(RenderWidgetHostViewAuraOverscrollTest, + MAYBE_OverscrollDirectionChangeMouseWheelWithWheelGestures) { + SetUpOverscrollEnvironmentWithWheelGestures(); + + // Send wheel event and receive ack as not consumed. + SimulateWheelEvent(125, -5, 0, true); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + + // ScrollBegin, ScrollUpdate messages. + EXPECT_EQ(2U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); + EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode()); + + // Send another wheel event, but in the reverse direction. The overscroll + // controller will not consume the event, because it is not triggering + // gesture-nav. + + SimulateWheelEvent(-260, 0, 0, true); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + + // Since it was unhandled; the overscroll should now be west + EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode()); + EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->current_mode()); + + SimulateWheelEvent(-20, 0, 0, true); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + + // wheel event ack generates gesture scroll update; which gets consumed + // solely by the overflow controller. + EXPECT_EQ(0U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode()); + EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->current_mode()); +} + // Tests that if a mouse-move event completes the overscroll gesture, future // move events do reach the renderer. TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollMouseMoveCompletion) { @@ -3340,6 +3814,101 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollMouseMoveCompletion) { INPUT_EVENT_ACK_STATE_NOT_CONSUMED); } +// Tests that if a mouse-move event completes the overscroll gesture, future +// move events do reach the renderer. +// Disabled on MacOS because it doesn't support wheel gestures +// just yet. +#if defined(OS_MACOSX) +#define MAYBE_OverscrollMouseMoveCompletionWheelGestures \ + DISABLED_OverscrollMouseMoveCompletionWheelGestures +#else +#define MAYBE_OverscrollMouseMoveCompletionWheelGestures \ + OverscrollMouseMoveCompletionWheelGestures +#endif +TEST_F(RenderWidgetHostViewAuraOverscrollTest, + MAYBE_OverscrollMouseMoveCompletionWheelGestures) { + SetUpOverscrollEnvironmentWithWheelGestures(); + + 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(3U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); + + // 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(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + 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, + blink::WebGestureDeviceTouchscreen); + 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, + blink::WebGestureDeviceTouchscreen); + 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, @@ -3374,11 +3943,14 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, // consumed and have triggered a fling animation (as tracked by the router). EXPECT_FALSE(parent_host_->input_router()->HasPendingEvents()); + SimulateGestureEvent(WebInputEvent::GestureScrollEnd, + blink::WebGestureDeviceTouchscreen); + 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(2U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(3U, GetSentMessageCountAndResetSink()); // The first wheel scroll did not scroll content. Overscroll should not start // yet, since enough hasn't been scrolled. @@ -3496,7 +4068,7 @@ TEST_F(RenderWidgetHostViewAuraTest, KeyEvent) { ui::EF_NONE); view_->OnKeyEvent(&key_event); - const NativeWebKeyboardEvent* event = delegate_.last_event(); + const NativeWebKeyboardEvent* event = delegates_.back()->last_event(); EXPECT_NE(nullptr, event); if (event) { EXPECT_EQ(key_event.key_code(), event->windowsKeyCode); @@ -3627,6 +4199,112 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, ScrollDeltasResetOnEnd) { EXPECT_EQ(0.f, overscroll_delta_y()); } +// Tests that the scroll deltas stored within the overscroll controller get +// reset at the end of the overscroll gesture even if the overscroll threshold +// isn't surpassed and the overscroll mode stays OVERSCROLL_NONE. +// Disabled on MacOS because it doesn't support wheel gestures +// just yet. +#if defined(OS_MACOSX) +#define MAYBE_ScrollDeltasResetOnEndWithWheelGestures \ + DISABLED_ScrollDeltasResetOnEndWithWheelGestures +#else +#define MAYBE_ScrollDeltasResetOnEndWithWheelGestures \ + ScrollDeltasResetOnEndWithWheelGestures +#endif +TEST_F(RenderWidgetHostViewAuraOverscrollTest, + MAYBE_ScrollDeltasResetOnEndWithWheelGestures) { + SetUpOverscrollEnvironmentWithWheelGestures(); + // Wheel event scroll ending with mouse move. + SimulateWheelEvent(-30, -10, 0, true); // sent directly + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + EXPECT_EQ(-30.f, overscroll_delta_x()); + EXPECT_EQ(-10.f, overscroll_delta_y()); + SimulateMouseMove(5, 10, 0); + EXPECT_EQ(0.f, overscroll_delta_x()); + EXPECT_EQ(0.f, overscroll_delta_y()); + + // Scroll gesture. + SimulateGestureEvent(WebInputEvent::GestureScrollBegin, + blink::WebGestureDeviceTouchscreen); + SimulateGestureScrollUpdateEvent(-30, -5, 0); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + EXPECT_EQ(-30.f, overscroll_delta_x()); + EXPECT_EQ(-5.f, overscroll_delta_y()); + SimulateGestureEvent(WebInputEvent::GestureScrollEnd, + blink::WebGestureDeviceTouchscreen); + EXPECT_EQ(0.f, overscroll_delta_x()); + EXPECT_EQ(0.f, overscroll_delta_y()); + + // Wheel event scroll ending with a fling. + SimulateWheelEvent(5, 0, 0, true); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + SimulateWheelEvent(10, -5, 0, true); + SendInputEventACK(WebInputEvent::MouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + SendInputEventACK(WebInputEvent::GestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + EXPECT_EQ(15.f, overscroll_delta_x()); + EXPECT_EQ(-5.f, overscroll_delta_y()); + SimulateGestureEvent(WebInputEvent::GestureScrollBegin, + blink::WebGestureDeviceTouchscreen); + SimulateGestureFlingStartEvent(0.f, 0.1f, blink::WebGestureDeviceTouchpad); + EXPECT_EQ(0.f, overscroll_delta_x()); + EXPECT_EQ(0.f, overscroll_delta_y()); +} + +TEST_F(RenderWidgetHostViewAuraTest, ForwardMouseEvent) { + aura::Window* root = parent_view_->GetNativeView()->GetRootWindow(); + + // Set up test delegate and window hierarchy. + aura::test::EventCountDelegate delegate; + scoped_ptr<aura::Window> parent(new aura::Window(&delegate)); + parent->Init(ui::LAYER_TEXTURED); + root->AddChild(parent.get()); + view_->InitAsChild(parent.get()); + + // Simulate mouse events, ensure they are forwarded to delegate. + ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), + ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, + 0); + view_->OnMouseEvent(&mouse_event); + EXPECT_EQ("1 0", delegate.GetMouseButtonCountsAndReset()); + + // Simulate mouse events, ensure they are forwarded to delegate. + mouse_event = ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), + ui::EventTimeForNow(), 0, 0); + view_->OnMouseEvent(&mouse_event); + EXPECT_EQ("0 1 0", delegate.GetMouseMotionCountsAndReset()); + + // Lock the mouse, simulate, and ensure they are forwarded. + view_->LockMouse(); + + mouse_event = + ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), + ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0); + view_->OnMouseEvent(&mouse_event); + EXPECT_EQ("1 0", delegate.GetMouseButtonCountsAndReset()); + + mouse_event = ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), + ui::EventTimeForNow(), 0, 0); + view_->OnMouseEvent(&mouse_event); + EXPECT_EQ("0 1 0", delegate.GetMouseMotionCountsAndReset()); + + view_->UnlockMouse(); + + // view_ will be destroyed when parent is destroyed. + view_ = nullptr; +} + // Tests the RenderWidgetHostImpl sends the correct surface ID namespace to // the renderer process. TEST_F(RenderWidgetHostViewAuraTest, SurfaceIdNamespaceInitialized) { @@ -3645,4 +4323,159 @@ TEST_F(RenderWidgetHostViewAuraTest, SurfaceIdNamespaceInitialized) { EXPECT_EQ(view_->GetSurfaceIdNamespace(), base::get<0>(params)); } +// This class provides functionality to test a RenderWidgetHostViewAura +// instance which has been hooked up to a test RenderViewHost instance and +// a WebContents instance. +class RenderWidgetHostViewAuraWithViewHarnessTest + : public RenderViewHostImplTestHarness { + public: + RenderWidgetHostViewAuraWithViewHarnessTest() + : view_(nullptr) {} + ~RenderWidgetHostViewAuraWithViewHarnessTest() override {} + + protected: + void SetUp() override { + ImageTransportFactory::InitializeForUnitTests( + scoped_ptr<ImageTransportFactory>( + new NoTransportImageTransportFactory)); + RenderViewHostImplTestHarness::SetUp(); + // Delete the current RenderWidgetHostView instance before setting + // the RWHVA as the view. + delete contents()->GetRenderViewHost()->GetWidget()->GetView(); + // This instance is destroyed in the TearDown method below. + view_ = new RenderWidgetHostViewAura( + contents()->GetRenderViewHost()->GetWidget(), + false); + } + + void TearDown() override { + view_->Destroy(); + RenderViewHostImplTestHarness::TearDown(); + ImageTransportFactory::Terminate(); + } + + RenderWidgetHostViewAura* view() { + return view_; + } + + private: + RenderWidgetHostViewAura* view_; + + DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraWithViewHarnessTest); +}; + +// Provides a mock implementation of the WebContentsViewDelegate class. +// Currently provides functionality to validate the ShowContextMenu +// callback. +class MockWebContentsViewDelegate : public WebContentsViewDelegate { + public: + MockWebContentsViewDelegate() + : context_menu_request_received_(false) {} + + ~MockWebContentsViewDelegate() override {} + + bool context_menu_request_received() const { + return context_menu_request_received_; + } + + ui::MenuSourceType context_menu_source_type() const { + return context_menu_params_.source_type; + } + + // WebContentsViewDelegate overrides. + void ShowContextMenu(RenderFrameHost* render_frame_host, + const ContextMenuParams& params) override { + context_menu_request_received_ = true; + context_menu_params_ = params; + } + + void ClearState() { + context_menu_request_received_ = false; + context_menu_params_.source_type = ui::MENU_SOURCE_NONE; + } + + private: + bool context_menu_request_received_; + ContextMenuParams context_menu_params_; + + DISALLOW_COPY_AND_ASSIGN(MockWebContentsViewDelegate); +}; + +// On Windows we don't want the context menu to be displayed in the context of +// a long press gesture. It should be displayed when the touch is released. +// On other platforms we should display the context menu in the long press +// gesture. +// This test validates this behavior. +TEST_F(RenderWidgetHostViewAuraWithViewHarnessTest, + ContextMenuTest) { + // This instance will be destroyed when the WebContents instance is + // destroyed. + MockWebContentsViewDelegate* delegate = new MockWebContentsViewDelegate; + static_cast<WebContentsViewAura*>( + contents()->GetView())->SetDelegateForTesting(delegate); + + RenderViewHostFactory::set_is_real_render_view_host(true); + + // A context menu request with the MENU_SOURCE_MOUSE source type should + // result in the MockWebContentsViewDelegate::ShowContextMenu method + // getting called. This means that the request worked correctly. + ContextMenuParams context_menu_params; + context_menu_params.source_type = ui::MENU_SOURCE_MOUSE; + contents()->ShowContextMenu(contents()->GetRenderViewHost()->GetMainFrame(), + context_menu_params); + EXPECT_TRUE(delegate->context_menu_request_received()); + EXPECT_EQ(delegate->context_menu_source_type(), ui::MENU_SOURCE_MOUSE); + + // A context menu request with the MENU_SOURCE_TOUCH source type should + // result in the MockWebContentsViewDelegate::ShowContextMenu method + // getting called on all platforms. This means that the request worked + // correctly. + delegate->ClearState(); + context_menu_params.source_type = ui::MENU_SOURCE_TOUCH; + contents()->ShowContextMenu(contents()->GetRenderViewHost()->GetMainFrame(), + context_menu_params); + EXPECT_TRUE(delegate->context_menu_request_received()); + + // A context menu request with the MENU_SOURCE_LONG_TAP source type should + // result in the MockWebContentsViewDelegate::ShowContextMenu method + // getting called on all platforms. This means that the request worked + // correctly. + delegate->ClearState(); + context_menu_params.source_type = ui::MENU_SOURCE_LONG_TAP; + contents()->ShowContextMenu(contents()->GetRenderViewHost()->GetMainFrame(), + context_menu_params); + EXPECT_TRUE(delegate->context_menu_request_received()); + + // A context menu request with the MENU_SOURCE_LONG_PRESS source type should + // result in the MockWebContentsViewDelegate::ShowContextMenu method + // getting called on non Windows platforms. This means that the request + // worked correctly. On Windows this should be blocked. + delegate->ClearState(); + context_menu_params.source_type = ui::MENU_SOURCE_LONG_PRESS; + contents()->ShowContextMenu(contents()->GetRenderViewHost()->GetMainFrame(), + context_menu_params); +#if defined(OS_WIN) + EXPECT_FALSE(delegate->context_menu_request_received()); +#else + EXPECT_TRUE(delegate->context_menu_request_received()); +#endif + +#if defined(OS_WIN) + // On Windows the context menu request blocked above should be received when + // the ET_GESTURE_LONG_TAP gesture is sent to the RenderWidgetHostViewAura + // instance. This means that the touch was released. + delegate->ClearState(); + + ui::GestureEventDetails event_details(ui::ET_GESTURE_LONG_TAP); + ui::GestureEvent gesture_event( + 100, 100, 0, ui::EventTimeForNow(), event_details); + view()->OnGestureEvent(&gesture_event); + + EXPECT_TRUE(delegate->context_menu_request_received()); + EXPECT_EQ(delegate->context_menu_source_type(), ui::MENU_SOURCE_TOUCH); +#endif + + RenderViewHostFactory::set_is_real_render_view_host(false); +} + } // namespace content |