diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index 4142736a0bff..2b811174f012 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -4742,12 +4742,6 @@ NSEvent* gLastDragMouseDownEvent = nil; mGeckoChild->DispatchInputEvent(&geckoEvent); } -static int32_t RoundUp(double aDouble) -{ - return aDouble < 0 ? static_cast(floor(aDouble)) : - static_cast(ceil(aDouble)); -} - - (void)sendWheelStartOrStop:(EventMessage)msg forEvent:(NSEvent *)theEvent { WidgetWheelEvent wheelEvent(true, msg, mGeckoChild); @@ -4799,6 +4793,49 @@ PanGestureTypeForEvent(NSEvent* aEvent) } } +static int32_t RoundUp(double aDouble) +{ + return aDouble < 0 ? static_cast(floor(aDouble)) : + static_cast(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; @@ -4846,8 +4883,7 @@ PanGestureTypeForEvent(NSEvent* aEvent) 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); @@ -4867,8 +4903,8 @@ PanGestureTypeForEvent(NSEvent* aEvent) 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 @@ -4896,8 +4932,8 @@ PanGestureTypeForEvent(NSEvent* aEvent) 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 { @@ -4909,11 +4945,11 @@ PanGestureTypeForEvent(NSEvent* aEvent) 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); }