| 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..0c46a98b1b840304458c7937d275a68ec12287a3 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).
|
| + NSArray* TrackpadScrollSequence(bool initial_rest,
|
| + int32_t delta_y,
|
| + int32_t momentum_delta_y);
|
| +
|
| + 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.
|
| +NSArray* EventsMacTest::TrackpadScrollSequence(bool initial_rest,
|
| + int32_t delta_y,
|
| + int32_t momentum_delta_y) {
|
| + int32_t delta_x = 0; // Just test vertical scrolling for now.
|
| + base::scoped_nsobject<NSMutableArray> events([[NSMutableArray alloc] init]);
|
| +
|
| + // Resting part.
|
| + if (initial_rest) {
|
| + // MayBegin always has a zero delta.
|
| + [events addObject: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 addObject:cocoa_test_event_utils::TestScrollEvent(
|
| + Flip(default_location_).ToCGPoint(), test_window(), delta_x, 0, true,
|
| + NSEventPhaseCancelled, NSEventPhaseNone)];
|
| + return events.autorelease();
|
| + }
|
| + }
|
| +
|
| + // With or without a rest, a begin is sent. It can have a non-zero
|
| + // deviceDeltaY but regular deltaY is always 0.
|
| + [events addObject:cocoa_test_event_utils::TestScrollEvent(
|
| + Flip(default_location_).ToCGPoint(), test_window(), delta_x, 0, true,
|
| + NSEventPhaseBegan, NSEventPhaseNone)];
|
| +
|
| + [events addObject: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 addObject:cocoa_test_event_utils::TestScrollEvent(
|
| + Flip(default_location_).ToCGPoint(), test_window(), delta_x, 0, true,
|
| + NSEventPhaseEnded, NSEventPhaseNone)];
|
| +
|
| + if (momentum_delta_y == 0)
|
| + return events.autorelease();
|
| +
|
| + // Flick part. Basically the same, but with phase and momentumPhase swapped.
|
| + [events addObject:cocoa_test_event_utils::TestScrollEvent(
|
| + Flip(default_location_).ToCGPoint(), test_window(), delta_x, 0, true,
|
| + NSEventPhaseNone, NSEventPhaseBegan)];
|
| +
|
| + [events addObject:cocoa_test_event_utils::TestScrollEvent(
|
| + Flip(default_location_).ToCGPoint(), test_window(), delta_x,
|
| + momentum_delta_y, true, NSEventPhaseNone, NSEventPhaseChanged)];
|
| +
|
| + [events addObject:cocoa_test_event_utils::TestScrollEvent(
|
| + Flip(default_location_).ToCGPoint(), test_window(), delta_x, 0, true,
|
| + NSEventPhaseNone, NSEventPhaseEnded)];
|
| + return events.autorelease();
|
| +}
|
| +
|
| } // 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,166 @@ 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::EventMomentumPhase::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) {
|
| + NSArray* ns_events = TrackpadScrollSequence(true, 0, 0);
|
| + ASSERT_EQ(2u, [ns_events count]);
|
| + 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::EventMomentumPhase::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::EventMomentumPhase::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;
|
| +
|
| + NSArray* ns_events = TrackpadScrollSequence(false, delta_y, 0);
|
| + ASSERT_EQ(3u, [ns_events count]);
|
| +
|
| + ui::ScrollEvent begin(ns_events[0]);
|
| + EXPECT_EQ(ui::EventMomentumPhase::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::EventMomentumPhase::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::EventMomentumPhase::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;
|
| +
|
| + NSArray* ns_events = TrackpadScrollSequence(true, delta_y, 0);
|
| + ASSERT_EQ(4u, [ns_events count]);
|
| +
|
| + ui::ScrollEvent rest(ns_events[0]);
|
| + EXPECT_EQ(ui::EventMomentumPhase::MAY_BEGIN, rest.momentum_phase());
|
| + EXPECT_EQ(0, rest.y_offset_ordinal());
|
| +
|
| + ui::ScrollEvent begin(ns_events[1]);
|
| + EXPECT_EQ(ui::EventMomentumPhase::MAY_BEGIN, begin.momentum_phase());
|
| + EXPECT_EQ(0, begin.y_offset_ordinal());
|
| +
|
| + ui::ScrollEvent update(ns_events[2]);
|
| + EXPECT_EQ(ui::EventMomentumPhase::NONE, update.momentum_phase());
|
| + EXPECT_EQ(delta_y, update.y_offset_ordinal());
|
| +
|
| + ui::ScrollEvent end(ns_events[3]);
|
| + EXPECT_EQ(ui::EventMomentumPhase::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;
|
| +
|
| + NSArray* ns_events = TrackpadScrollSequence(false, delta_y, momentum_delta_y);
|
| + ASSERT_EQ(6u, [ns_events count]);
|
| +
|
| + // Non-momentum part.
|
| + {
|
| + ui::ScrollEvent begin(ns_events[0]);
|
| + EXPECT_EQ(ui::EventMomentumPhase::MAY_BEGIN, begin.momentum_phase());
|
| + EXPECT_EQ(0, begin.y_offset_ordinal());
|
| +
|
| + ui::ScrollEvent update(ns_events[1]);
|
| + EXPECT_EQ(ui::EventMomentumPhase::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::EventMomentumPhase::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::EventMomentumPhase::INERTIAL_UPDATE, begin.momentum_phase());
|
| + EXPECT_EQ(0, begin.y_offset_ordinal());
|
| +
|
| + ui::ScrollEvent update(ns_events[4]);
|
| + EXPECT_EQ(ui::EventMomentumPhase::INERTIAL_UPDATE, update.momentum_phase());
|
| + EXPECT_EQ(momentum_delta_y, update.y_offset_ordinal());
|
| +
|
| + ui::ScrollEvent end(ns_events[5]);
|
| + EXPECT_EQ(ui::EventMomentumPhase::END, end.momentum_phase());
|
| + EXPECT_EQ(0, end.y_offset_ordinal());
|
| + }
|
| +}
|
| +
|
| } // namespace ui
|
|
|