Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(816)

Side by Side Diff: content/browser/renderer_host/render_widget_host_view_mac_unittest.mm

Issue 2902303002: phase based wheel scroll latching for mac (Closed)
Patch Set: in -> after Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/renderer_host/render_widget_host_view_mac.h" 5 #include "content/browser/renderer_host/render_widget_host_view_mac.h"
6 6
7 #include <Cocoa/Cocoa.h> 7 #include <Cocoa/Cocoa.h>
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <stdint.h> 9 #include <stdint.h>
10 #include <tuple> 10 #include <tuple>
11 11
12 #include "base/command_line.h" 12 #include "base/command_line.h"
13 #include "base/mac/scoped_nsautorelease_pool.h" 13 #include "base/mac/scoped_nsautorelease_pool.h"
14 #include "base/mac/sdk_forward_declarations.h" 14 #include "base/mac/sdk_forward_declarations.h"
15 #include "base/macros.h" 15 #include "base/macros.h"
16 #include "base/run_loop.h" 16 #include "base/run_loop.h"
17 #include "base/strings/utf_string_conversions.h" 17 #include "base/strings/utf_string_conversions.h"
18 #include "base/test/histogram_tester.h" 18 #include "base/test/histogram_tester.h"
19 #include "base/test/scoped_feature_list.h"
19 #include "base/test/simple_test_tick_clock.h" 20 #include "base/test/simple_test_tick_clock.h"
21 #include "base/threading/thread_task_runner_handle.h"
20 #include "content/browser/browser_thread_impl.h" 22 #include "content/browser/browser_thread_impl.h"
21 #include "content/browser/compositor/test/no_transport_image_transport_factory.h " 23 #include "content/browser/compositor/test/no_transport_image_transport_factory.h "
22 #include "content/browser/frame_host/render_widget_host_view_guest.h" 24 #include "content/browser/frame_host/render_widget_host_view_guest.h"
23 #include "content/browser/gpu/compositor_util.h" 25 #include "content/browser/gpu/compositor_util.h"
24 #include "content/browser/renderer_host/render_widget_host_delegate.h" 26 #include "content/browser/renderer_host/render_widget_host_delegate.h"
25 #include "content/browser/renderer_host/text_input_manager.h" 27 #include "content/browser/renderer_host/text_input_manager.h"
26 #include "content/common/input_messages.h" 28 #include "content/common/input_messages.h"
27 #include "content/common/text_input_state.h" 29 #include "content/common/text_input_state.h"
28 #include "content/common/view_messages.h" 30 #include "content/common/view_messages.h"
29 #include "content/public/browser/notification_types.h" 31 #include "content/public/browser/notification_types.h"
30 #include "content/public/browser/render_widget_host_view_mac_delegate.h" 32 #include "content/public/browser/render_widget_host_view_mac_delegate.h"
33 #include "content/public/common/content_features.h"
31 #include "content/public/common/content_switches.h" 34 #include "content/public/common/content_switches.h"
32 #include "content/public/test/mock_render_process_host.h" 35 #include "content/public/test/mock_render_process_host.h"
33 #include "content/public/test/test_browser_context.h" 36 #include "content/public/test/test_browser_context.h"
34 #include "content/public/test/test_utils.h" 37 #include "content/public/test/test_utils.h"
35 #include "content/test/test_render_view_host.h" 38 #include "content/test/test_render_view_host.h"
36 #include "gpu/ipc/common/gpu_messages.h" 39 #include "gpu/ipc/common/gpu_messages.h"
37 #include "gpu/ipc/service/image_transport_surface.h" 40 #include "gpu/ipc/service/image_transport_surface.h"
38 #include "testing/gmock/include/gmock/gmock.h" 41 #include "testing/gmock/include/gmock/gmock.h"
39 #include "testing/gtest/include/gtest/gtest.h" 42 #include "testing/gtest/include/gtest/gtest.h"
40 #include "testing/gtest_mac.h" 43 #include "testing/gtest_mac.h"
41 #import "third_party/ocmock/OCMock/OCMock.h" 44 #import "third_party/ocmock/OCMock/OCMock.h"
42 #import "third_party/ocmock/ocmock_extensions.h" 45 #import "third_party/ocmock/ocmock_extensions.h"
43 #import "ui/base/test/scoped_fake_nswindow_focus.h" 46 #import "ui/base/test/scoped_fake_nswindow_focus.h"
44 #include "ui/events/base_event_utils.h" 47 #include "ui/events/base_event_utils.h"
45 #include "ui/events/blink/web_input_event_traits.h" 48 #include "ui/events/blink/web_input_event_traits.h"
46 #include "ui/events/test/cocoa_test_event_utils.h" 49 #include "ui/events/test/cocoa_test_event_utils.h"
47 #import "ui/gfx/test/ui_cocoa_test_helper.h" 50 #import "ui/gfx/test/ui_cocoa_test_helper.h"
48 #include "ui/latency/latency_info.h" 51 #include "ui/latency/latency_info.h"
49 52
50 // Helper class with methods used to mock -[NSEvent phase], used by 53 // Helper class with methods used to mock -[NSEvent phase], used by
51 // |MockScrollWheelEventWithPhase()|. 54 // |MockScrollWheelEventWithPhase()|.
52 @interface MockPhaseMethods : NSObject { 55 @interface MockPhaseMethods : NSObject {
53 } 56 }
54 57
58 - (NSEventPhase)phaseNone;
55 - (NSEventPhase)phaseBegan; 59 - (NSEventPhase)phaseBegan;
56 - (NSEventPhase)phaseChanged; 60 - (NSEventPhase)phaseChanged;
57 - (NSEventPhase)phaseEnded; 61 - (NSEventPhase)phaseEnded;
58 @end 62 @end
59 63
60 @implementation MockPhaseMethods 64 @implementation MockPhaseMethods
61 65
66 - (NSEventPhase)phaseNone {
67 return NSEventPhaseNone;
68 }
62 - (NSEventPhase)phaseBegan { 69 - (NSEventPhase)phaseBegan {
63 return NSEventPhaseBegan; 70 return NSEventPhaseBegan;
64 } 71 }
65 - (NSEventPhase)phaseChanged { 72 - (NSEventPhase)phaseChanged {
66 return NSEventPhaseChanged; 73 return NSEventPhaseChanged;
67 } 74 }
68 - (NSEventPhase)phaseEnded { 75 - (NSEventPhase)phaseEnded {
69 return NSEventPhaseEnded; 76 return NSEventPhaseEnded;
70 } 77 }
71 78
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 CGEventTimestamp timestamp = 0; 297 CGEventTimestamp timestamp = 0;
291 CGEventSetTimestamp(cg_event, timestamp); 298 CGEventSetTimestamp(cg_event, timestamp);
292 NSEvent* event = [NSEvent eventWithCGEvent:cg_event]; 299 NSEvent* event = [NSEvent eventWithCGEvent:cg_event];
293 CFRelease(cg_event); 300 CFRelease(cg_event);
294 method_setImplementation( 301 method_setImplementation(
295 class_getInstanceMethod([NSEvent class], @selector(phase)), 302 class_getInstanceMethod([NSEvent class], @selector(phase)),
296 [MockPhaseMethods instanceMethodForSelector:mockPhaseSelector]); 303 [MockPhaseMethods instanceMethodForSelector:mockPhaseSelector]);
297 return event; 304 return event;
298 } 305 }
299 306
307 NSEvent* MockScrollWheelEventWithMomentumPhase(SEL mockPhaseSelector,
308 int32_t delta) {
309 // Create a dum event with phaseNone. This is for resetting the phase info of
tdresser 2017/05/25 15:18:37 dum -> dummy?
sahel 2017/05/25 16:00:04 Done.
310 // CGEventRef.
311 MockScrollWheelEventWithPhase(@selector(phaseNone), 0);
312 CGEventRef cg_event1 = CGEventCreateScrollWheelEvent(
tdresser 2017/05/25 15:18:36 Why event1 instead of just event? (and below with
sahel 2017/05/25 16:00:04 Done.
313 nullptr, kCGScrollEventUnitLine, 1, delta, 0);
314 CGEventTimestamp timestamp = 0;
315 CGEventSetTimestamp(cg_event1, timestamp);
316 // CGEventSetIntegerValueField(cg_event1, kCGScrollWheelEventMomentumPhase,
317 // cg_momentum_phase);
tdresser 2017/05/25 15:18:36 Should these lines be removed?
sahel 2017/05/25 16:00:04 Done, I am sorry for the sloppy unittest file, I d
318 // CGEventSetFlags(cg_event1, static_cast<CGEventFlags>(0));
319 NSEvent* event1 = [NSEvent eventWithCGEvent:cg_event1];
320 CFRelease(cg_event1);
321 method_setImplementation(
322 class_getInstanceMethod([NSEvent class], @selector(momentumPhase)),
323 [MockPhaseMethods instanceMethodForSelector:mockPhaseSelector]);
324 return event1;
325 }
326
300 } // namespace 327 } // namespace
301 328
302 class RenderWidgetHostViewMacTest : public RenderViewHostImplTestHarness { 329 class RenderWidgetHostViewMacTest : public RenderViewHostImplTestHarness {
303 public: 330 public:
304 RenderWidgetHostViewMacTest() : rwhv_mac_(nullptr), old_rwhv_(nullptr) { 331 RenderWidgetHostViewMacTest() : rwhv_mac_(nullptr), old_rwhv_(nullptr) {
305 std::unique_ptr<base::SimpleTestTickClock> mock_clock( 332 std::unique_ptr<base::SimpleTestTickClock> mock_clock(
306 new base::SimpleTestTickClock()); 333 new base::SimpleTestTickClock());
307 mock_clock->Advance(base::TimeDelta::FromMilliseconds(100)); 334 mock_clock->Advance(base::TimeDelta::FromMilliseconds(100));
308 ui::SetEventTickClockForTesting(std::move(mock_clock)); 335 ui::SetEventTickClockForTesting(std::move(mock_clock));
309 } 336 }
(...skipping 991 matching lines...) Expand 10 before | Expand all | Expand 10 after
1301 EXPECT_FALSE([view->cocoa_view() isOpaque]); 1328 EXPECT_FALSE([view->cocoa_view() isOpaque]);
1302 set_background = process_host->sink().GetUniqueMessageMatching( 1329 set_background = process_host->sink().GetUniqueMessageMatching(
1303 ViewMsg_SetBackgroundOpaque::ID); 1330 ViewMsg_SetBackgroundOpaque::ID);
1304 ASSERT_TRUE(set_background); 1331 ASSERT_TRUE(set_background);
1305 ViewMsg_SetBackgroundOpaque::Read(set_background, &sent_background); 1332 ViewMsg_SetBackgroundOpaque::Read(set_background, &sent_background);
1306 EXPECT_FALSE(std::get<0>(sent_background)); 1333 EXPECT_FALSE(std::get<0>(sent_background));
1307 1334
1308 host->ShutdownAndDestroyWidget(true); 1335 host->ShutdownAndDestroyWidget(true);
1309 } 1336 }
1310 1337
1338 class RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest
1339 : public RenderWidgetHostViewMacTest {
1340 public:
1341 RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest() {
1342 feature_list_.InitFromCommandLine(
1343 features::kTouchpadAndWheelScrollLatching.name, "");
1344 }
1345
1346 private:
1347 base::test::ScopedFeatureList feature_list_;
1348 };
1349
1350 TEST_F(RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest,
1351 WheelWithPhaseEndedIsNotForwardedImmediately) {
tdresser 2017/05/25 15:18:36 Can you add a comment briefly explaining why it sh
sahel 2017/05/25 16:00:04 Done.
1352 // Initialize the view associated with a MockRenderWidgetHostImpl, rather than
1353 // the MockRenderProcessHost that is set up by the test harness which mocks
1354 // out |OnMessageReceived()|.
1355 TestBrowserContext browser_context;
1356 MockRenderProcessHost* process_host =
1357 new MockRenderProcessHost(&browser_context);
1358 process_host->Init();
1359 MockRenderWidgetHostDelegate delegate;
1360 int32_t routing_id = process_host->GetNextRoutingID();
1361 MockRenderWidgetHostImpl* host =
1362 new MockRenderWidgetHostImpl(&delegate, process_host, routing_id);
1363 RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host, false);
1364 process_host->sink().ClearMessages();
1365
1366 // Send an initial wheel event for scrolling by 3 lines.
1367 NSEvent* wheelEvent1 =
1368 MockScrollWheelEventWithPhase(@selector(phaseBegan), 3);
1369 [view->cocoa_view() scrollWheel:wheelEvent1];
1370 ASSERT_EQ(1U, process_host->sink().message_count());
1371 process_host->sink().ClearMessages();
1372
1373 // Indicate that the wheel event was unhandled.
1374 InputEventAck unhandled_ack(InputEventAckSource::COMPOSITOR_THREAD,
1375 blink::WebInputEvent::kMouseWheel,
1376 INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
1377 std::unique_ptr<IPC::Message> response1(
1378 new InputHostMsg_HandleInputEvent_ACK(0, unhandled_ack));
1379 host->OnMessageReceived(*response1);
1380 ASSERT_EQ(2U, process_host->sink().message_count());
1381 process_host->sink().ClearMessages();
1382
1383 // Send a wheel event with phaseEnded. When wheel scroll latching is enabled
1384 // the evnet will be dropped and the mouse_wheel_end_dispatch_timer_ will
tdresser 2017/05/25 15:18:37 evnet -> event
sahel 2017/05/25 16:00:04 Done.
1385 // start.
1386 NSEvent* wheelEvent2 =
1387 MockScrollWheelEventWithPhase(@selector(phaseEnded), 0);
1388 [view->cocoa_view() scrollWheel:wheelEvent2];
1389 ASSERT_EQ(0U, process_host->sink().message_count());
1390 DCHECK(view->mouse_wheel_end_dispatch_timer_.IsRunning());
1391 process_host->sink().ClearMessages();
1392
1393 host->ShutdownAndDestroyWidget(true);
1394 }
1395
1396 TEST_F(RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest,
1397 WheelWithMomentumPhaseBeganStopsTheWheelEndDispatchTimer) {
1398 // Initialize the view associated with a MockRenderWidgetHostImpl, rather than
1399 // the MockRenderProcessHost that is set up by the test harness which mocks
1400 // out |OnMessageReceived()|.
1401 TestBrowserContext browser_context;
1402 MockRenderProcessHost* process_host =
1403 new MockRenderProcessHost(&browser_context);
1404 process_host->Init();
1405 MockRenderWidgetHostDelegate delegate;
1406 int32_t routing_id = process_host->GetNextRoutingID();
1407 MockRenderWidgetHostImpl* host =
1408 new MockRenderWidgetHostImpl(&delegate, process_host, routing_id);
1409 RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host, false);
1410 process_host->sink().ClearMessages();
1411
1412 // Send an initial wheel event for scrolling by 3 lines.
1413 NSEvent* wheelEvent1 =
1414 MockScrollWheelEventWithPhase(@selector(phaseBegan), 3);
1415 [view->cocoa_view() scrollWheel:wheelEvent1];
1416 ASSERT_EQ(1U, process_host->sink().message_count());
1417 process_host->sink().ClearMessages();
1418
1419 // Indicate that the wheel event was unhandled.
1420 InputEventAck unhandled_ack(InputEventAckSource::COMPOSITOR_THREAD,
1421 blink::WebInputEvent::kMouseWheel,
1422 INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
1423 std::unique_ptr<IPC::Message> response1(
1424 new InputHostMsg_HandleInputEvent_ACK(0, unhandled_ack));
1425 host->OnMessageReceived(*response1);
1426 ASSERT_EQ(2U, process_host->sink().message_count());
1427 process_host->sink().ClearMessages();
1428
1429 // Send a wheel event with phaseEnded. When wheel scroll latching is enabled
1430 // the evnet will be dropped and the mouse_wheel_end_dispatch_timer_ will
tdresser 2017/05/25 15:18:37 evnet -> event
sahel 2017/05/25 16:00:04 Done.
1431 // start.
1432 NSEvent* wheelEvent2 =
1433 MockScrollWheelEventWithPhase(@selector(phaseEnded), 0);
1434 [view->cocoa_view() scrollWheel:wheelEvent2];
1435 ASSERT_EQ(0U, process_host->sink().message_count());
1436 DCHECK(view->mouse_wheel_end_dispatch_timer_.IsRunning());
1437 process_host->sink().ClearMessages();
1438
1439 // Send a wheel event with momentum phase started, this should stop the wheel
1440 // end dispatch timer.
1441 NSEvent* wheelEvent3 =
1442 MockScrollWheelEventWithMomentumPhase(@selector(phaseBegan), 3);
1443 ASSERT_TRUE(wheelEvent3);
1444 [view->cocoa_view() scrollWheel:wheelEvent3];
1445 ASSERT_EQ(1U, process_host->sink().message_count());
1446 DCHECK(!view->mouse_wheel_end_dispatch_timer_.IsRunning());
1447 process_host->sink().ClearMessages();
1448
1449 host->ShutdownAndDestroyWidget(true);
1450 }
1451
1452 TEST_F(RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest,
1453 WheelWithPhaseBeganDispatchesThePendingWheelEnd) {
1454 // Initialize the view associated with a MockRenderWidgetHostImpl, rather than
1455 // the MockRenderProcessHost that is set up by the test harness which mocks
1456 // out |OnMessageReceived()|.
1457 TestBrowserContext browser_context;
1458 MockRenderProcessHost* process_host =
1459 new MockRenderProcessHost(&browser_context);
1460 process_host->Init();
1461 MockRenderWidgetHostDelegate delegate;
1462 int32_t routing_id = process_host->GetNextRoutingID();
1463 MockRenderWidgetHostImpl* host =
1464 new MockRenderWidgetHostImpl(&delegate, process_host, routing_id);
1465 RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host, false);
1466 process_host->sink().ClearMessages();
1467
1468 // Send an initial wheel event for scrolling by 3 lines.
1469 NSEvent* wheelEvent1 =
1470 MockScrollWheelEventWithPhase(@selector(phaseBegan), 3);
1471 [view->cocoa_view() scrollWheel:wheelEvent1];
1472 ASSERT_EQ(1U, process_host->sink().message_count());
1473 process_host->sink().ClearMessages();
1474
1475 // Indicate that the wheel event was unhandled.
1476 InputEventAck unhandled_ack(InputEventAckSource::COMPOSITOR_THREAD,
1477 blink::WebInputEvent::kMouseWheel,
1478 INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
1479 std::unique_ptr<IPC::Message> response1(
1480 new InputHostMsg_HandleInputEvent_ACK(0, unhandled_ack));
1481 host->OnMessageReceived(*response1);
1482 ASSERT_EQ(2U, process_host->sink().message_count());
1483 process_host->sink().ClearMessages();
1484
1485 // Send a wheel event with phaseEnded. When wheel scroll latching is enabled
1486 // the evnet will be dropped and the mouse_wheel_end_dispatch_timer_ will
tdresser 2017/05/25 15:18:36 evnet -> event
sahel 2017/05/25 16:00:04 Done.
1487 // start.
1488 NSEvent* wheelEvent2 =
1489 MockScrollWheelEventWithPhase(@selector(phaseEnded), 0);
1490 [view->cocoa_view() scrollWheel:wheelEvent2];
1491 ASSERT_EQ(0U, process_host->sink().message_count());
1492 DCHECK(view->mouse_wheel_end_dispatch_timer_.IsRunning());
1493 process_host->sink().ClearMessages();
1494
1495 // Send a wheel event with phase started, this should stop the wheel end
1496 // dispatch timer and dispatch the pending wheel end event for the previous
1497 // scroll sequence.
1498 NSEvent* wheelEvent3 =
1499 MockScrollWheelEventWithPhase(@selector(phaseBegan), 3);
1500 ASSERT_TRUE(wheelEvent3);
1501 [view->cocoa_view() scrollWheel:wheelEvent3];
1502 ASSERT_EQ(2U, process_host->sink().message_count());
1503 DCHECK(!view->mouse_wheel_end_dispatch_timer_.IsRunning());
1504 process_host->sink().ClearMessages();
1505
1506 host->ShutdownAndDestroyWidget(true);
1507 }
1508
1311 class RenderWidgetHostViewMacPinchTest : public RenderWidgetHostViewMacTest { 1509 class RenderWidgetHostViewMacPinchTest : public RenderWidgetHostViewMacTest {
1312 public: 1510 public:
1313 RenderWidgetHostViewMacPinchTest() : process_host_(nullptr) {} 1511 RenderWidgetHostViewMacPinchTest() : process_host_(nullptr) {}
1314 1512
1315 bool ZoomDisabledForPinchUpdateMessage() { 1513 bool ZoomDisabledForPinchUpdateMessage() {
1316 const IPC::Message* message = nullptr; 1514 const IPC::Message* message = nullptr;
1317 // The first message may be a PinchBegin. Go for the second message if 1515 // The first message may be a PinchBegin. Go for the second message if
1318 // there are two. 1516 // there are two.
1319 switch (process_host_->sink().message_count()) { 1517 switch (process_host_->sink().message_count()) {
1320 case 1: 1518 case 1:
(...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after
1836 // -performKeyEquivalent: now returns YES to prevent further propagation, and 2034 // -performKeyEquivalent: now returns YES to prevent further propagation, and
1837 // the event is sent to the renderer. 2035 // the event is sent to the renderer.
1838 EXPECT_TRUE([window performKeyEquivalent:key_down]); 2036 EXPECT_TRUE([window performKeyEquivalent:key_down]);
1839 EXPECT_EQ(2U, process_host->sink().message_count()); 2037 EXPECT_EQ(2U, process_host->sink().message_count());
1840 EXPECT_EQ("RawKeyDown Char", GetInputMessageTypes(process_host)); 2038 EXPECT_EQ("RawKeyDown Char", GetInputMessageTypes(process_host));
1841 2039
1842 rwhv_mac_->release_pepper_fullscreen_window_for_testing(); 2040 rwhv_mac_->release_pepper_fullscreen_window_for_testing();
1843 } 2041 }
1844 2042
1845 } // namespace content 2043 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698