Skip to content

Commit

Permalink
MacViews: Send Mac scrollWheel NSEvents as ui::ET_SCROLL (ui::ScrollE…
Browse files Browse the repository at this point in the history
…vent).

On Mac, mouse wheel ticks and two-finger trackpad scroll events both
arrive via -[NSView scrollWheel:]. These are currently converted to a
ui::MouseWheel. However, ui::MouseWheel doesn't have the necessary event
phase information that the cc::InputHandler needs to properly calculate
scroll elasticity.

ui::ScrollEvent is a closer fit, but Mac generates a continuous event
"stream" through the momentum portion of a scroll "flick". To support
this, add an EventMomentumPhase enum, and populate the ScrollEvent with
it.  EventMomentumPhase is a simplified representation of the phase
information on the native NSEvent: it hides states that don't matter to
the scrolling machinery for the cc::InputHandler (i.e.
cc::LayerTreeHostImpl).

Elastic scrolling overview CL: http://crrev.com/2189583004

Add test coverage by fleshing out cocoa_test_event_utils::
TestScrollEvent(..). Fixes possible flakiness in tests using that method
since it didn't previously set event flags explicitly to zero. The
result could be that NSEvent uses the current global keyboard state to
populate its event flags, which could be influenced by tests running in
parallel.

BUG=355659, 615948, 640457

Review-Url: https://codereview.chromium.org/2193153002
Cr-Commit-Position: refs/heads/master@{#421082}
  • Loading branch information
tapted authored and Commit bot committed Sep 27, 2016
1 parent 3663253 commit b94b06c
Show file tree
Hide file tree
Showing 18 changed files with 431 additions and 35 deletions.
12 changes: 12 additions & 0 deletions base/mac/sdk_forward_declarations.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ BASE_EXPORT extern NSString* const NSAppearanceNameVibrantLight;
topLevelObjects:(NSArray**)topLevelObjects;
@end

@interface NSArray (MountainLionSDK)
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
@end

@interface NSDictionary (MountainLionSDK)
- (id)objectForKeyedSubscript:(id)key;
@end

@interface NSMutableDictionary (MountainLionSDK)
- (void)setObject:(id)obj forKeyedSubscript:(id<NSCopying>)key;
@end

#endif // MAC_OS_X_VERSION_10_8

// Once Chrome no longer supports OSX 10.8, everything within this preprocessor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -576,10 +576,10 @@
}
}

// Flaky - https://crbug.com/640457
// Test that a ui::Event and blink::WebInputEvent made from the same NSEvent
// have the same values for comparable fields.
TEST(WebInputEventBuilderMacTest, DISABLED_ScrollWheelMatchesUIEvent) {
TEST(WebInputEventBuilderMacTest, ScrollWheelMatchesUIEvent) {
bool precise = false;
CGFloat delta_x = 123;
CGFloat delta_y = 321;
NSPoint location = NSMakePoint(11, 22);
Expand All @@ -593,7 +593,10 @@
defer:NO];

NSEvent* mac_event = cocoa_test_event_utils::TestScrollEvent(
location, window, delta_x, delta_y);
location, window, delta_x, delta_y, precise, NSEventPhaseNone,
NSEventPhaseNone);
EXPECT_EQ(delta_x, [mac_event deltaX]);
EXPECT_EQ(delta_y, [mac_event deltaY]);

blink::WebMouseWheelEvent web_event =
content::WebMouseWheelEventBuilder::Build(mac_event,
Expand Down
47 changes: 43 additions & 4 deletions ui/events/cocoa/events_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) {
case NSMouseMoved:
return ET_MOUSE_MOVED;
case NSScrollWheel:
return ET_MOUSEWHEEL;
return ET_SCROLL;
case NSMouseEntered:
return ET_MOUSE_ENTERED;
case NSMouseExited:
Expand Down Expand Up @@ -198,9 +198,48 @@ bool GetScrollOffsets(const base::NativeEvent& native_event,
float* y_offset,
float* x_offset_ordinal,
float* y_offset_ordinal,
int* finger_count) {
NOTIMPLEMENTED();
return false;
int* finger_count,
EventMomentumPhase* momentum_phase) {
gfx::Vector2d offset = GetMouseWheelOffset(native_event);
*x_offset = *x_offset_ordinal = offset.x();
*y_offset = *y_offset_ordinal = offset.y();

// For non-scrolling events, the finger count can be determined with
// [[native_event touchesMatchingPhase:NSTouchPhaseTouching inView:nil] count]
// but it's illegal to ask that of scroll events, so say two fingers.
*finger_count = 2;

// If a user just rests two fingers on the touchpad without moving, AppKit
// uses NSEventPhaseMayBegin. Treat this the same as NSEventPhaseBegan.
const NSUInteger kBeginPhaseMask = NSEventPhaseBegan | NSEventPhaseMayBegin;
const NSUInteger kEndPhaseMask = NSEventPhaseCancelled | NSEventPhaseEnded;

// Note: although the NSEventPhase constants are bit flags, the logic here
// assumes AppKit will not combine them, so momentum phase should only be set
// once. If one of these DCHECKs fails it could mean some new hardware that
// needs tests in events_mac_unittest.mm.
DCHECK_EQ(EventMomentumPhase::NONE, *momentum_phase);

if ([native_event phase] & kBeginPhaseMask)
*momentum_phase = EventMomentumPhase::MAY_BEGIN;

if (([native_event phase] | [native_event momentumPhase]) & kEndPhaseMask) {
DCHECK_EQ(EventMomentumPhase::NONE, *momentum_phase);
*momentum_phase = EventMomentumPhase::END;
} else if ([native_event momentumPhase] != NSEventPhaseNone) {
DCHECK_EQ(EventMomentumPhase::NONE, *momentum_phase);
*momentum_phase = EventMomentumPhase::INERTIAL_UPDATE;
}

// If the event completely lacks phase information, there won't be further
// updates, so they must be treated as an end.
if (([native_event phase] | [native_event momentumPhase]) ==
NSEventPhaseNone) {
DCHECK_EQ(EventMomentumPhase::NONE, *momentum_phase);
*momentum_phase = EventMomentumPhase::END;
}

return true;
}

bool GetFlingData(const base::NativeEvent& native_event,
Expand Down
Loading

0 comments on commit b94b06c

Please sign in to comment.