| Index: content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
|
| diff --git a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
|
| index e482c755c8966ead410ed6881e340c63afa52a83..7bf0b1c5c8c63e93f77b9345c3ade86d98815f7a 100644
|
| --- a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
|
| +++ b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
|
| @@ -16,7 +16,9 @@
|
| #include "base/run_loop.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "base/test/histogram_tester.h"
|
| +#include "base/test/scoped_feature_list.h"
|
| #include "base/test/simple_test_tick_clock.h"
|
| +#include "base/threading/thread_task_runner_handle.h"
|
| #include "content/browser/browser_thread_impl.h"
|
| #include "content/browser/compositor/test/no_transport_image_transport_factory.h"
|
| #include "content/browser/frame_host/render_widget_host_view_guest.h"
|
| @@ -28,6 +30,7 @@
|
| #include "content/common/view_messages.h"
|
| #include "content/public/browser/notification_types.h"
|
| #include "content/public/browser/render_widget_host_view_mac_delegate.h"
|
| +#include "content/public/common/content_features.h"
|
| #include "content/public/common/content_switches.h"
|
| #include "content/public/test/mock_render_process_host.h"
|
| #include "content/public/test/test_browser_context.h"
|
| @@ -52,6 +55,7 @@
|
| @interface MockPhaseMethods : NSObject {
|
| }
|
|
|
| +- (NSEventPhase)phaseNone;
|
| - (NSEventPhase)phaseBegan;
|
| - (NSEventPhase)phaseChanged;
|
| - (NSEventPhase)phaseEnded;
|
| @@ -59,6 +63,9 @@
|
|
|
| @implementation MockPhaseMethods
|
|
|
| +- (NSEventPhase)phaseNone {
|
| + return NSEventPhaseNone;
|
| +}
|
| - (NSEventPhase)phaseBegan {
|
| return NSEventPhaseBegan;
|
| }
|
| @@ -297,6 +304,23 @@ NSEvent* MockScrollWheelEventWithPhase(SEL mockPhaseSelector, int32_t delta) {
|
| return event;
|
| }
|
|
|
| +NSEvent* MockScrollWheelEventWithMomentumPhase(SEL mockPhaseSelector,
|
| + int32_t delta) {
|
| + // Create a dummy event with phaseNone. This is for resetting the phase info
|
| + // of CGEventRef.
|
| + MockScrollWheelEventWithPhase(@selector(phaseNone), 0);
|
| + CGEventRef cg_event = CGEventCreateScrollWheelEvent(
|
| + nullptr, kCGScrollEventUnitLine, 1, delta, 0);
|
| + CGEventTimestamp timestamp = 0;
|
| + CGEventSetTimestamp(cg_event, timestamp);
|
| + NSEvent* event = [NSEvent eventWithCGEvent:cg_event];
|
| + CFRelease(cg_event);
|
| + method_setImplementation(
|
| + class_getInstanceMethod([NSEvent class], @selector(momentumPhase)),
|
| + [MockPhaseMethods instanceMethodForSelector:mockPhaseSelector]);
|
| + return event;
|
| +}
|
| +
|
| } // namespace
|
|
|
| class RenderWidgetHostViewMacTest : public RenderViewHostImplTestHarness {
|
| @@ -1308,6 +1332,180 @@ TEST_F(RenderWidgetHostViewMacTest, Background) {
|
| host->ShutdownAndDestroyWidget(true);
|
| }
|
|
|
| +class RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest
|
| + : public RenderWidgetHostViewMacTest {
|
| + public:
|
| + RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest() {
|
| + feature_list_.InitFromCommandLine(
|
| + features::kTouchpadAndWheelScrollLatching.name, "");
|
| + }
|
| +
|
| + private:
|
| + base::test::ScopedFeatureList feature_list_;
|
| +};
|
| +
|
| +// When wheel scroll latching is enabled, wheel end events are not sent
|
| +// immediately, instead we start a timer to see if momentum phase of the scroll
|
| +// starts or not.
|
| +TEST_F(RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest,
|
| + WheelWithPhaseEndedIsNotForwardedImmediately) {
|
| + // Initialize the view associated with a MockRenderWidgetHostImpl, rather than
|
| + // the MockRenderProcessHost that is set up by the test harness which mocks
|
| + // out |OnMessageReceived()|.
|
| + TestBrowserContext browser_context;
|
| + MockRenderProcessHost* process_host =
|
| + new MockRenderProcessHost(&browser_context);
|
| + process_host->Init();
|
| + MockRenderWidgetHostDelegate delegate;
|
| + int32_t routing_id = process_host->GetNextRoutingID();
|
| + MockRenderWidgetHostImpl* host =
|
| + new MockRenderWidgetHostImpl(&delegate, process_host, routing_id);
|
| + RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host, false);
|
| + process_host->sink().ClearMessages();
|
| +
|
| + // Send an initial wheel event for scrolling by 3 lines.
|
| + NSEvent* wheelEvent1 =
|
| + MockScrollWheelEventWithPhase(@selector(phaseBegan), 3);
|
| + [view->cocoa_view() scrollWheel:wheelEvent1];
|
| + ASSERT_EQ(1U, process_host->sink().message_count());
|
| + process_host->sink().ClearMessages();
|
| +
|
| + // Indicate that the wheel event was unhandled.
|
| + InputEventAck unhandled_ack(InputEventAckSource::COMPOSITOR_THREAD,
|
| + blink::WebInputEvent::kMouseWheel,
|
| + INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
|
| + std::unique_ptr<IPC::Message> response1(
|
| + new InputHostMsg_HandleInputEvent_ACK(0, unhandled_ack));
|
| + host->OnMessageReceived(*response1);
|
| + ASSERT_EQ(2U, process_host->sink().message_count());
|
| + process_host->sink().ClearMessages();
|
| +
|
| + // Send a wheel event with phaseEnded. When wheel scroll latching is enabled
|
| + // the event will be dropped and the mouse_wheel_end_dispatch_timer_ will
|
| + // start.
|
| + NSEvent* wheelEvent2 =
|
| + MockScrollWheelEventWithPhase(@selector(phaseEnded), 0);
|
| + [view->cocoa_view() scrollWheel:wheelEvent2];
|
| + ASSERT_EQ(0U, process_host->sink().message_count());
|
| + DCHECK(view->HasPendingWheelEndEvent());
|
| + process_host->sink().ClearMessages();
|
| +
|
| + host->ShutdownAndDestroyWidget(true);
|
| +}
|
| +
|
| +TEST_F(RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest,
|
| + WheelWithMomentumPhaseBeganStopsTheWheelEndDispatchTimer) {
|
| + // Initialize the view associated with a MockRenderWidgetHostImpl, rather than
|
| + // the MockRenderProcessHost that is set up by the test harness which mocks
|
| + // out |OnMessageReceived()|.
|
| + TestBrowserContext browser_context;
|
| + MockRenderProcessHost* process_host =
|
| + new MockRenderProcessHost(&browser_context);
|
| + process_host->Init();
|
| + MockRenderWidgetHostDelegate delegate;
|
| + int32_t routing_id = process_host->GetNextRoutingID();
|
| + MockRenderWidgetHostImpl* host =
|
| + new MockRenderWidgetHostImpl(&delegate, process_host, routing_id);
|
| + RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host, false);
|
| + process_host->sink().ClearMessages();
|
| +
|
| + // Send an initial wheel event for scrolling by 3 lines.
|
| + NSEvent* wheelEvent1 =
|
| + MockScrollWheelEventWithPhase(@selector(phaseBegan), 3);
|
| + [view->cocoa_view() scrollWheel:wheelEvent1];
|
| + ASSERT_EQ(1U, process_host->sink().message_count());
|
| + process_host->sink().ClearMessages();
|
| +
|
| + // Indicate that the wheel event was unhandled.
|
| + InputEventAck unhandled_ack(InputEventAckSource::COMPOSITOR_THREAD,
|
| + blink::WebInputEvent::kMouseWheel,
|
| + INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
|
| + std::unique_ptr<IPC::Message> response1(
|
| + new InputHostMsg_HandleInputEvent_ACK(0, unhandled_ack));
|
| + host->OnMessageReceived(*response1);
|
| + ASSERT_EQ(2U, process_host->sink().message_count());
|
| + process_host->sink().ClearMessages();
|
| +
|
| + // Send a wheel event with phaseEnded. When wheel scroll latching is enabled
|
| + // the event will be dropped and the mouse_wheel_end_dispatch_timer_ will
|
| + // start.
|
| + NSEvent* wheelEvent2 =
|
| + MockScrollWheelEventWithPhase(@selector(phaseEnded), 0);
|
| + [view->cocoa_view() scrollWheel:wheelEvent2];
|
| + ASSERT_EQ(0U, process_host->sink().message_count());
|
| + DCHECK(view->HasPendingWheelEndEvent());
|
| + process_host->sink().ClearMessages();
|
| +
|
| + // Send a wheel event with momentum phase started, this should stop the wheel
|
| + // end dispatch timer.
|
| + NSEvent* wheelEvent3 =
|
| + MockScrollWheelEventWithMomentumPhase(@selector(phaseBegan), 3);
|
| + ASSERT_TRUE(wheelEvent3);
|
| + [view->cocoa_view() scrollWheel:wheelEvent3];
|
| + ASSERT_EQ(1U, process_host->sink().message_count());
|
| + DCHECK(!view->HasPendingWheelEndEvent());
|
| + process_host->sink().ClearMessages();
|
| +
|
| + host->ShutdownAndDestroyWidget(true);
|
| +}
|
| +
|
| +TEST_F(RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest,
|
| + WheelWithPhaseBeganDispatchesThePendingWheelEnd) {
|
| + // Initialize the view associated with a MockRenderWidgetHostImpl, rather than
|
| + // the MockRenderProcessHost that is set up by the test harness which mocks
|
| + // out |OnMessageReceived()|.
|
| + TestBrowserContext browser_context;
|
| + MockRenderProcessHost* process_host =
|
| + new MockRenderProcessHost(&browser_context);
|
| + process_host->Init();
|
| + MockRenderWidgetHostDelegate delegate;
|
| + int32_t routing_id = process_host->GetNextRoutingID();
|
| + MockRenderWidgetHostImpl* host =
|
| + new MockRenderWidgetHostImpl(&delegate, process_host, routing_id);
|
| + RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host, false);
|
| + process_host->sink().ClearMessages();
|
| +
|
| + // Send an initial wheel event for scrolling by 3 lines.
|
| + NSEvent* wheelEvent1 =
|
| + MockScrollWheelEventWithPhase(@selector(phaseBegan), 3);
|
| + [view->cocoa_view() scrollWheel:wheelEvent1];
|
| + ASSERT_EQ(1U, process_host->sink().message_count());
|
| + process_host->sink().ClearMessages();
|
| +
|
| + // Indicate that the wheel event was unhandled.
|
| + InputEventAck unhandled_ack(InputEventAckSource::COMPOSITOR_THREAD,
|
| + blink::WebInputEvent::kMouseWheel,
|
| + INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
|
| + std::unique_ptr<IPC::Message> response1(
|
| + new InputHostMsg_HandleInputEvent_ACK(0, unhandled_ack));
|
| + host->OnMessageReceived(*response1);
|
| + ASSERT_EQ(2U, process_host->sink().message_count());
|
| + process_host->sink().ClearMessages();
|
| +
|
| + // Send a wheel event with phaseEnded. When wheel scroll latching is enabled
|
| + // the event will be dropped and the mouse_wheel_end_dispatch_timer_ will
|
| + // start.
|
| + NSEvent* wheelEvent2 =
|
| + MockScrollWheelEventWithPhase(@selector(phaseEnded), 0);
|
| + [view->cocoa_view() scrollWheel:wheelEvent2];
|
| + ASSERT_EQ(0U, process_host->sink().message_count());
|
| + DCHECK(view->HasPendingWheelEndEvent());
|
| + process_host->sink().ClearMessages();
|
| +
|
| + // Send a wheel event with phase started, this should stop the wheel end
|
| + // dispatch timer and dispatch the pending wheel end event for the previous
|
| + // scroll sequence.
|
| + NSEvent* wheelEvent3 =
|
| + MockScrollWheelEventWithPhase(@selector(phaseBegan), 3);
|
| + ASSERT_TRUE(wheelEvent3);
|
| + [view->cocoa_view() scrollWheel:wheelEvent3];
|
| + ASSERT_EQ(2U, process_host->sink().message_count());
|
| + DCHECK(!view->HasPendingWheelEndEvent());
|
| + process_host->sink().ClearMessages();
|
| +
|
| + host->ShutdownAndDestroyWidget(true);
|
| +}
|
| +
|
| class RenderWidgetHostViewMacPinchTest : public RenderWidgetHostViewMacTest {
|
| public:
|
| RenderWidgetHostViewMacPinchTest() : process_host_(nullptr) {}
|
|
|