--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -4725,22 +4725,16 @@ NSEvent* gLastDragMouseDownEvent = nil;
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
geckoEvent.button = WidgetMouseEvent::eMiddleButton;
// send event into Gecko by going directly to the
// the widget.
mGeckoChild->DispatchInputEvent(&geckoEvent);
}
-static int32_t RoundUp(double aDouble)
-{
- return aDouble < 0 ? static_cast<int32_t>(floor(aDouble)) :
- static_cast<int32_t>(ceil(aDouble));
-}
-
- (void)sendWheelStartOrStop:(EventMessage)msg forEvent:(NSEvent *)theEvent
{
WidgetWheelEvent wheelEvent(true, msg, mGeckoChild);
[self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent];
mExpectingWheelStop = (msg == eWheelOperationStart);
mGeckoChild->DispatchInputEvent(wheelEvent.AsInputEvent());
}
@@ -4782,16 +4776,59 @@ PanGestureTypeForEvent(NSEvent* aEvent)
return PanGestureInput::PANGESTURE_PAN;
}
default:
NS_ERROR("unexpected event phase");
return PanGestureInput::PANGESTURE_PAN;
}
}
+static int32_t RoundUp(double aDouble)
+{
+ return aDouble < 0 ? static_cast<int32_t>(floor(aDouble)) :
+ static_cast<int32_t>(ceil(aDouble));
+}
+
+static int32_t
+TakeLargestInt(gfx::Float* aFloat)
+{
+ int32_t result(*aFloat); // truncate towards zero
+ *aFloat -= result;
+ return result;
+}
+
+static gfx::IntPoint
+AccumulateIntegerDelta(NSEvent* aEvent)
+{
+ static gfx::Point sAccumulator(0.0f, 0.0f);
+ if (nsCocoaUtils::EventPhase(aEvent) == NSEventPhaseBegan) {
+ sAccumulator = gfx::Point(0.0f, 0.0f);
+ }
+ sAccumulator.x += [aEvent deltaX];
+ sAccumulator.y += [aEvent deltaY];
+ return gfx::IntPoint(TakeLargestInt(&sAccumulator.x),
+ TakeLargestInt(&sAccumulator.y));
+}
+
+static gfx::IntPoint
+GetIntegerDeltaForEvent(NSEvent* aEvent)
+{
+ if (nsCocoaFeatures::OnSierraOrLater()) {
+ return AccumulateIntegerDelta(aEvent);
+ }
+
+ // Pre-10.12, deltaX/deltaY had the accumulation behavior that we want, and
+ // it worked more reliably than doing it on our own, so use it on pre-10.12
+ // versions. For example, with a traditional USB mouse, the first wheel
+ // "tick" would always senda line scroll of at least one line, but with our
+ // own accumulation you sometimes need to do multiple wheel ticks before one
+ // line has been accumulated.
+ return gfx::IntPoint(RoundUp([aEvent deltaX]), RoundUp([aEvent deltaY]));
+}
+
- (void)scrollWheel:(NSEvent*)theEvent
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
if (gfxPrefs::AsyncPanZoomSeparateEventThread() && [self apzctm]) {
// Disable main-thread scrolling completely when using APZ with the
// separate event thread. This is bug 1013412.
return;
@@ -4829,18 +4866,17 @@ PanGestureTypeForEvent(NSEvent* aEvent)
ScreenPoint position = ViewAs<ScreenPixel>(
[self convertWindowCoordinates:locationInWindow],
PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
bool usePreciseDeltas = nsCocoaUtils::HasPreciseScrollingDeltas(theEvent) &&
Preferences::GetBool("mousewheel.enable_pixel_scrolling", true);
bool hasPhaseInformation = nsCocoaUtils::EventHasPhaseInformation(theEvent);
- int32_t lineOrPageDeltaX = RoundUp(-[theEvent deltaX]);
- int32_t lineOrPageDeltaY = RoundUp(-[theEvent deltaY]);
+ gfx::IntPoint lineOrPageDelta = -GetIntegerDeltaForEvent(theEvent);
Modifiers modifiers = nsCocoaUtils::ModifiersForEvent(theEvent);
NSTimeInterval beforeNow = [[NSProcessInfo processInfo] systemUptime] - [theEvent timestamp];
PRIntervalTime eventIntervalTime = PR_IntervalNow() - PR_MillisecondsToInterval(beforeNow * 1000);
TimeStamp eventTimeStamp = TimeStamp::Now() - TimeDuration::FromSeconds(beforeNow);
ScreenPoint preciseDelta;
@@ -4850,18 +4886,18 @@ PanGestureTypeForEvent(NSEvent* aEvent)
double scale = mGeckoChild->BackingScaleFactor();
preciseDelta = ScreenPoint(-pixelDeltaX * scale, -pixelDeltaY * scale);
}
if (usePreciseDeltas && hasPhaseInformation) {
PanGestureInput panEvent(PanGestureTypeForEvent(theEvent),
eventIntervalTime, eventTimeStamp,
position, preciseDelta, modifiers);
- panEvent.mLineOrPageDeltaX = lineOrPageDeltaX;
- panEvent.mLineOrPageDeltaY = lineOrPageDeltaY;
+ panEvent.mLineOrPageDeltaX = lineOrPageDelta.x;
+ panEvent.mLineOrPageDeltaY = lineOrPageDelta.y;
if (panEvent.mType == PanGestureInput::PANGESTURE_END) {
// Check if there's a momentum start event in the event queue, so that we
// can annotate this event.
NSEvent* nextWheelEvent =
[NSApp nextEventMatchingMask:NSScrollWheelMask
untilDate:[NSDate distantPast]
inMode:NSDefaultRunLoopMode
@@ -4879,34 +4915,34 @@ PanGestureTypeForEvent(NSEvent* aEvent)
// This is on 10.6 or old touchpads that don't have any phase information.
ScrollWheelInput wheelEvent(eventIntervalTime, eventTimeStamp, modifiers,
ScrollWheelInput::SCROLLMODE_INSTANT,
ScrollWheelInput::SCROLLDELTA_PIXEL,
position,
preciseDelta.x,
preciseDelta.y,
false);
- wheelEvent.mLineOrPageDeltaX = lineOrPageDeltaX;
- wheelEvent.mLineOrPageDeltaY = lineOrPageDeltaY;
+ wheelEvent.mLineOrPageDeltaX = lineOrPageDelta.x;
+ wheelEvent.mLineOrPageDeltaY = lineOrPageDelta.y;
wheelEvent.mIsMomentum = nsCocoaUtils::IsMomentumScrollEvent(theEvent);
mGeckoChild->DispatchAPZWheelInputEvent(wheelEvent, false);
} else {
ScrollWheelInput::ScrollMode scrollMode = ScrollWheelInput::SCROLLMODE_INSTANT;
if (gfxPrefs::SmoothScrollEnabled() && gfxPrefs::WheelSmoothScrollEnabled()) {
scrollMode = ScrollWheelInput::SCROLLMODE_SMOOTH;
}
ScrollWheelInput wheelEvent(eventIntervalTime, eventTimeStamp, modifiers,
scrollMode,
ScrollWheelInput::SCROLLDELTA_LINE,
position,
- lineOrPageDeltaX,
- lineOrPageDeltaY,
+ lineOrPageDelta.x,
+ lineOrPageDelta.y,
false);
- wheelEvent.mLineOrPageDeltaX = lineOrPageDeltaX;
- wheelEvent.mLineOrPageDeltaY = lineOrPageDeltaY;
+ wheelEvent.mLineOrPageDeltaX = lineOrPageDelta.x;
+ wheelEvent.mLineOrPageDeltaY = lineOrPageDelta.y;
mGeckoChild->DispatchAPZWheelInputEvent(wheelEvent, false);
}
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (void)handleAsyncScrollEvent:(CGEventRef)cgEvent ofType:(CGEventType)type
{