Chromium Code Reviews| Index: ui/events/cocoa/events_mac_unittest.mm |
| diff --git a/ui/events/cocoa/events_mac_unittest.mm b/ui/events/cocoa/events_mac_unittest.mm |
| index e30202f301fe8a8ef376f0b86e1db3f66b8aa57a..26ba13588ef1f0fb4eaa8d7b75e4245de210211d 100644 |
| --- a/ui/events/cocoa/events_mac_unittest.mm |
| +++ b/ui/events/cocoa/events_mac_unittest.mm |
| @@ -11,6 +11,7 @@ |
| #include "base/mac/sdk_forward_declarations.h" |
| #include "base/macros.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| +#import "ui/events/cocoa/cocoa_event_utils.h" |
| #include "ui/events/event_constants.h" |
| #include "ui/events/event_utils.h" |
| #import "ui/events/test/cocoa_test_event_utils.h" |
| @@ -61,14 +62,87 @@ class EventsMacTest : public CocoaTest { |
| NSEvent* TestScrollEvent(const gfx::Point& window_location, |
| int32_t delta_x, |
| int32_t delta_y) { |
| + bool precise = false; |
| return cocoa_test_event_utils::TestScrollEvent( |
| - Flip(window_location).ToCGPoint(), test_window(), delta_x, delta_y); |
| + Flip(window_location).ToCGPoint(), test_window(), delta_x, delta_y, |
| + precise, NSEventPhaseNone, NSEventPhaseNone); |
| } |
| + // Creates the sequence of events generated by a trackpad scroll. |
| + // |initial_rest| indicates whether there is a pause before scrolling starts. |
| + // |delta_y| is the portion to scroll without momentum (fingers on the |
| + // trackpad). |momentum_delta_y| is the momentum portion. A zero delta skips |
| + // that phase (if both are zero, the |initial_rest| is cancelled). |
| + void TrackpadScrollSequence(bool initial_rest, |
| + int32_t delta_y, |
| + int32_t momentum_delta_y, |
| + std::vector<NSEvent*>* events); |
|
sky
2016/09/23 17:47:08
Is there an equivalent to std::unique_ptr you can
tapted
2016/09/26 11:12:20
Done (made this more idiomatic).
scoped_nsobject
|
| + |
| + protected: |
| + const gfx::Point default_location_ = gfx::Point(10, 20); |
| + |
| private: |
| DISALLOW_COPY_AND_ASSIGN(EventsMacTest); |
| }; |
| +// Trackpad scroll sequences below determined empirically on OSX 10.11 (linking |
| +// to 10.10 SDK), and dumping out with NSLog in -[NSView scrollWheel:]. First |
| +// created using a Magic Trackpad 2 on a MacPro. See the Trackpad* test cases |
| +// below for example event streams. |
| +void EventsMacTest::TrackpadScrollSequence(bool initial_rest, |
| + int32_t delta_y, |
| + int32_t momentum_delta_y, |
| + std::vector<NSEvent*>* events) { |
| + int32_t delta_x = 0; // Just test vertical scrolling for now. |
| + |
| + // Resting part. |
| + if (initial_rest) { |
| + // MayBegin always has a zero delta. |
| + events->push_back(cocoa_test_event_utils::TestScrollEvent( |
| + Flip(default_location_).ToCGPoint(), test_window(), delta_x, 0, true, |
| + NSEventPhaseMayBegin, NSEventPhaseNone)); |
| + if (delta_y == 0) { |
| + // Rest and release: event gets cancelled. |
| + DCHECK_EQ(0, momentum_delta_y); // Pretty sure this is impossible. |
| + events->push_back(cocoa_test_event_utils::TestScrollEvent( |
| + Flip(default_location_).ToCGPoint(), test_window(), delta_x, 0, true, |
| + NSEventPhaseCancelled, NSEventPhaseNone)); |
| + return; |
| + } |
| + } |
| + |
| + // With or without a rest, a begin is sent. It can have a non-zero |
| + // deviceDeltaY but regular deltaY is always 0. |
| + events->push_back(cocoa_test_event_utils::TestScrollEvent( |
| + Flip(default_location_).ToCGPoint(), test_window(), delta_x, 0, true, |
| + NSEventPhaseBegan, NSEventPhaseNone)); |
| + |
| + events->push_back(cocoa_test_event_utils::TestScrollEvent( |
| + Flip(default_location_).ToCGPoint(), test_window(), delta_x, delta_y, |
| + true, NSEventPhaseChanged, NSEventPhaseNone)); |
| + |
| + // With or without momentum, an end is sent for the non-momentum part. |
| + events->push_back(cocoa_test_event_utils::TestScrollEvent( |
| + Flip(default_location_).ToCGPoint(), test_window(), delta_x, 0, true, |
| + NSEventPhaseEnded, NSEventPhaseNone)); |
| + |
| + if (momentum_delta_y == 0) |
| + return; |
| + |
| + // Flick part. Basically the same, but with phase and momentumPhase swapped. |
| + events->push_back(cocoa_test_event_utils::TestScrollEvent( |
| + Flip(default_location_).ToCGPoint(), test_window(), delta_x, 0, true, |
| + NSEventPhaseNone, NSEventPhaseBegan)); |
| + |
| + events->push_back(cocoa_test_event_utils::TestScrollEvent( |
| + Flip(default_location_).ToCGPoint(), test_window(), delta_x, |
| + momentum_delta_y, true, NSEventPhaseNone, NSEventPhaseChanged)); |
| + |
| + events->push_back(cocoa_test_event_utils::TestScrollEvent( |
| + Flip(default_location_).ToCGPoint(), test_window(), delta_x, 0, true, |
| + NSEventPhaseNone, NSEventPhaseEnded)); |
| +} |
| + |
| } // namespace |
| TEST_F(EventsMacTest, EventFlagsFromNative) { |
| @@ -155,7 +229,7 @@ TEST_F(EventsMacTest, ButtonEvents) { |
| // Scroll up. |
| event = TestScrollEvent(location, 0, 1); |
| - EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event)); |
| + EXPECT_EQ(ui::ET_SCROLL, ui::EventTypeFromNative(event)); |
| EXPECT_EQ(0, ui::EventFlagsFromNative(event)); |
| EXPECT_EQ(location.ToString(), ui::EventLocationFromNative(event).ToString()); |
| offset = ui::GetMouseWheelOffset(event); |
| @@ -164,7 +238,7 @@ TEST_F(EventsMacTest, ButtonEvents) { |
| // Scroll down. |
| event = TestScrollEvent(location, 0, -1); |
| - EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event)); |
| + EXPECT_EQ(ui::ET_SCROLL, ui::EventTypeFromNative(event)); |
| EXPECT_EQ(0, ui::EventFlagsFromNative(event)); |
| EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
| offset = ui::GetMouseWheelOffset(event); |
| @@ -173,7 +247,7 @@ TEST_F(EventsMacTest, ButtonEvents) { |
| // Scroll left. |
| event = TestScrollEvent(location, 1, 0); |
| - EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event)); |
| + EXPECT_EQ(ui::ET_SCROLL, ui::EventTypeFromNative(event)); |
| EXPECT_EQ(0, ui::EventFlagsFromNative(event)); |
| EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
| offset = ui::GetMouseWheelOffset(event); |
| @@ -182,7 +256,7 @@ TEST_F(EventsMacTest, ButtonEvents) { |
| // Scroll right. |
| event = TestScrollEvent(location, -1, 0); |
| - EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event)); |
| + EXPECT_EQ(ui::ET_SCROLL, ui::EventTypeFromNative(event)); |
| EXPECT_EQ(0, ui::EventFlagsFromNative(event)); |
| EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
| offset = ui::GetMouseWheelOffset(event); |
| @@ -261,4 +335,170 @@ TEST_F(EventsMacTest, EventTypeFromNative) { |
| EXPECT_EQ(ui::ET_MOUSE_EXITED, ui::EventTypeFromNative(event)); |
| } |
| +// Verify that a mouse wheel scroll event is correctly lacking phase data. |
| +TEST_F(EventsMacTest, MouseWheelScroll) { |
| + int32_t wheel_delta_y = 2; |
| + |
| + NSEvent* ns_wheel = TestScrollEvent(default_location_, 0, wheel_delta_y); |
| + EXPECT_FALSE([ns_wheel hasPreciseScrollingDeltas]); |
| + ui::ScrollEvent wheel(ns_wheel); |
| + EXPECT_EQ(ui::ET_SCROLL, wheel.type()); |
| + |
| + // Currently wheel events still say two for finger count, but this may change. |
| + EXPECT_EQ(2, wheel.finger_count()); |
| + |
| + // Note the phase is "end" for wheel events, not "none". There is always an |
| + // "end" when no more events are expected. |
| + EXPECT_EQ(ui::EM_PHASE_END, wheel.momentum_phase()); |
| + EXPECT_EQ(default_location_, wheel.location()); |
| + |
| + float pixel_delta_y = wheel_delta_y * ui::kScrollbarPixelsPerCocoaTick; |
| + EXPECT_EQ(pixel_delta_y, wheel.y_offset_ordinal()); |
| + EXPECT_EQ(0, wheel.x_offset_ordinal()); |
| +} |
| + |
| +// Test the event flow for a trackpad "rest" that doesn't result in scrolling |
| +// nor momentum. Also check the boring stuff like type, finger count and |
| +// location, which isn't phase-specific. |
| +// Sequence: |
| +// (1) NSEvent: type=ScrollWheel loc=(780,41) time=14909.3 flags=0x100 win=<set> |
| +// {deviceD,d}elta{X,Y,Z}=0 count:0 phase=MayBegin momentumPhase=None |
| +// (2) NSEvent: type=ScrollWheel loc=(780,41) time=14912.9 flags=0x100 win=<set> |
| +// {deviceD,d}elta{X,Y,Z}=0 count:0 phase=Cancelled momentumPhase=None. |
| +TEST_F(EventsMacTest, TrackpadRestRelease) { |
| + std::vector<NSEvent*> ns_events; |
| + TrackpadScrollSequence(true, 0, 0, &ns_events); |
| + ASSERT_EQ(2u, ns_events.size()); |
| + EXPECT_TRUE([ns_events[0] hasPreciseScrollingDeltas]); |
| + |
| + ui::ScrollEvent rest(ns_events[0]); |
| + EXPECT_EQ(ui::ET_SCROLL, rest.type()); |
| + EXPECT_EQ(2, rest.finger_count()); |
| + EXPECT_EQ(ui::EM_PHASE_MAY_BEGIN, rest.momentum_phase()); |
| + EXPECT_EQ(0, rest.y_offset_ordinal()); |
| + EXPECT_EQ(default_location_, rest.location()); |
| + |
| + ui::ScrollEvent cancel(ns_events[1]); |
| + EXPECT_EQ(ui::ET_SCROLL, cancel.type()); |
| + EXPECT_EQ(2, cancel.finger_count()); |
| + EXPECT_EQ(ui::EM_PHASE_END, cancel.momentum_phase()); |
| + EXPECT_EQ(0, cancel.y_offset_ordinal()); |
| + EXPECT_EQ(default_location_, cancel.location()); |
| +} |
| + |
| +// Test the event flow for touching the trackpad while "in motion" already, then |
| +// pausing so that a flick is not generated. deltaX and deltaZ are always zero. |
| +// Note, deviceDeltaX may take on an integer value even though deltaX is zero. |
| +// Sequence: |
| +// (1) NSEvent: type=ScrollWheel loc=(780,41) time=15263.2 flags=0x100 win=<set> |
| +// deltaY=0.000000 deviceDeltaY=1.000000 phase=Began momentumPhase=None |
| +// (n) NSEvent: type=ScrollWheel loc=(780,41) time=15263.2 flags=0x100 win=<set> |
| +// deltaY=0.400024 deviceDeltaY=3.000000 phase=Changed momentumPhase=None |
| +// (3) NSEvent: type=ScrollWheel loc=(780,41) time=15264.2 flags=0x100 win=<set> |
| +// deltaY=0.000000 deviceDeltaY=0.000000 phase=Ended momentumPhase=None. |
| +TEST_F(EventsMacTest, TrackpadScrollThenRest) { |
| + int32_t delta_y = 21; |
| + |
| + std::vector<NSEvent*> ns_events; |
| + TrackpadScrollSequence(false, delta_y, 0, &ns_events); |
| + ASSERT_EQ(3u, ns_events.size()); |
| + |
| + ui::ScrollEvent begin(ns_events[0]); |
| + EXPECT_EQ(ui::EM_PHASE_MAY_BEGIN, begin.momentum_phase()); |
| + EXPECT_EQ(0, begin.y_offset_ordinal()); |
| + |
| + ui::ScrollEvent update(ns_events[1]); |
| + // There's no momentum yet, so phase is none. |
| + EXPECT_EQ(ui::EM_PHASE_NONE, update.momentum_phase()); |
| + // Note: No pixel conversion for "precise" deltas. |
| + EXPECT_EQ(delta_y, update.y_offset_ordinal()); |
| + |
| + ui::ScrollEvent end(ns_events[2]); |
| + EXPECT_EQ(ui::EM_PHASE_END, end.momentum_phase()); |
| + EXPECT_EQ(0, end.y_offset_ordinal()); |
| +} |
| + |
| +// Same as the above, but with an initial rest, which is not cancelled. This |
| +// results in multiple MAY_BEGIN phases. |
| +TEST_F(EventsMacTest, TrackpadRestThenScrollThenRest) { |
| + int32_t delta_y = 21; |
| + |
| + std::vector<NSEvent*> ns_events; |
| + TrackpadScrollSequence(true, delta_y, 0, &ns_events); |
| + ASSERT_EQ(4u, ns_events.size()); |
| + |
| + ui::ScrollEvent rest(ns_events[0]); |
| + EXPECT_EQ(ui::EM_PHASE_MAY_BEGIN, rest.momentum_phase()); |
| + EXPECT_EQ(0, rest.y_offset_ordinal()); |
| + |
| + ui::ScrollEvent begin(ns_events[1]); |
| + EXPECT_EQ(ui::EM_PHASE_MAY_BEGIN, begin.momentum_phase()); |
| + EXPECT_EQ(0, begin.y_offset_ordinal()); |
| + |
| + ui::ScrollEvent update(ns_events[2]); |
| + EXPECT_EQ(ui::EM_PHASE_NONE, update.momentum_phase()); |
| + EXPECT_EQ(delta_y, update.y_offset_ordinal()); |
| + |
| + ui::ScrollEvent end(ns_events[3]); |
| + EXPECT_EQ(ui::EM_PHASE_END, end.momentum_phase()); |
| + EXPECT_EQ(0, end.y_offset_ordinal()); |
| +} |
| + |
| +// Test the event flows that lead to momentum, with and without an initial rest. |
| +// Example sequence (no initial rest): |
| +// (1) NSEvent: type=ScrollWheel loc=(780,41) time=15187.5 flags=0x100 win=<set> |
| +// deltaY=0.000000 deviceDeltaY=1.000000 phase=Began momentumPhase=None |
| +// (n) NSEvent: type=ScrollWheel loc=(780,41) time=15187.5 flags=0x100 win=<set> |
| +// deltaY=0.500031 deviceDeltaY=4.000000 phase=Changed momentumPhase=None |
| +// (3) NSEvent: type=ScrollWheel loc=(780,41) time=15187.6 flags=0x100 win=<set> |
| +// deltaY=0.000000 deviceDeltaY=0.000000 phase=Ended momentumPhase=None |
| +// (4) NSEvent: type=ScrollWheel loc=(780,41) time=15187.6 flags=0x100 win=<set> |
| +// deltaY=0.900055 deviceDeltaY=3.000000 phase=None momentumPhase=Began |
| +// (n) NSEvent: type=ScrollWheel loc=(780,41) time=15187.6 flags=0x100 win=<set> |
| +// deltaY=0.300018 deviceDeltaY=3.000000 phase=None momentumPhase=Changed |
| +// (6) NSEvent: type=ScrollWheel loc=(780,41) time=15188.0 flags=0x100 win=<set> |
| +// deltaY=0.000000 deviceDeltaY=0.000000 phase=None momentumPhase=Ended. |
| +TEST_F(EventsMacTest, TrackpadScrollThenFlick) { |
| + int32_t delta_y = 21; |
| + int32_t momentum_delta_y = 33; |
| + |
| + std::vector<NSEvent*> ns_events; |
| + TrackpadScrollSequence(false, delta_y, momentum_delta_y, &ns_events); |
| + ASSERT_EQ(6u, ns_events.size()); |
| + |
| + // Non-momentum part. |
| + { |
| + ui::ScrollEvent begin(ns_events[0]); |
| + EXPECT_EQ(ui::EM_PHASE_MAY_BEGIN, begin.momentum_phase()); |
| + EXPECT_EQ(0, begin.y_offset_ordinal()); |
| + |
| + ui::ScrollEvent update(ns_events[1]); |
| + EXPECT_EQ(ui::EM_PHASE_NONE, update.momentum_phase()); |
| + EXPECT_EQ(delta_y, update.y_offset_ordinal()); |
| + |
| + ui::ScrollEvent end(ns_events[2]); |
| + // Even though the event stream continues, AppKit doesn't provide a way to |
| + // know this without peeking at future events. So this "end" mid-stream is |
| + // unavoidable. |
| + EXPECT_EQ(ui::EM_PHASE_END, end.momentum_phase()); |
| + EXPECT_EQ(0, end.y_offset_ordinal()); |
| + } |
| + // Momentum part. |
| + { |
| + ui::ScrollEvent begin(ns_events[3]); |
| + // Since a momentum "begin" is really a continuation of the stream, it's |
| + // currently treated as an update, but the offsets should always be zero. |
| + EXPECT_EQ(ui::EM_PHASE_INERTIAL_UPDATE, begin.momentum_phase()); |
| + EXPECT_EQ(0, begin.y_offset_ordinal()); |
| + |
| + ui::ScrollEvent update(ns_events[4]); |
| + EXPECT_EQ(ui::EM_PHASE_INERTIAL_UPDATE, update.momentum_phase()); |
| + EXPECT_EQ(momentum_delta_y, update.y_offset_ordinal()); |
| + |
| + ui::ScrollEvent end(ns_events[5]); |
| + EXPECT_EQ(ui::EM_PHASE_END, end.momentum_phase()); |
| + EXPECT_EQ(0, end.y_offset_ordinal()); |
| + } |
| +} |
| + |
| } // namespace ui |