From 97d1be1080a44aabe4c6fdb197ff7617a54d9ba3 Mon Sep 17 00:00:00 2001 From: malenkov Date: Fri, 24 Feb 2017 12:04:59 +0400 Subject: [PATCH] 8173876: Fast precise scrolling and DeltaAccumulator fix for macOS Sierra 10.12.2 Reviewed-by: serb, alexsch --- .../sun/lwawt/macosx/CPlatformResponder.java | 25 +++++------ .../classes/sun/lwawt/macosx/NSEvent.java | 4 +- src/macosx/native/sun/awt/AWTView.m | 11 ++++- src/macosx/native/sun/awt/CTrayIcon.m | 11 ++++- src/macosx/native/sun/awt/LWCToolkit.h | 1 + src/macosx/native/sun/awt/LWCToolkit.m | 41 +++++++++++++------ .../TooMuchWheelRotationEventsTest.java | 2 +- 7 files changed, 62 insertions(+), 33 deletions(-) diff --git a/src/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java b/src/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java index 15c377f99..3cccfa5cd 100644 --- a/src/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java +++ b/src/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java @@ -262,9 +262,8 @@ final class CPlatformResponder { static class DeltaAccumulator { - static final double MIN_THRESHOLD = 0.1; - static final double MAX_THRESHOLD = 0.5; double accumulatedDelta; + boolean accumulate; int getRoundedDelta(double delta, int scrollPhase) { @@ -275,25 +274,23 @@ final class CPlatformResponder { roundDelta = delta > 0 ? 1 : -1; } } else { // trackpad - boolean begin = scrollPhase == NSEvent.SCROLL_PHASE_BEGAN; - boolean end = scrollPhase == NSEvent.SCROLL_MASK_PHASE_ENDED - || scrollPhase == NSEvent.SCROLL_MASK_PHASE_CANCELLED; - - if (begin) { + if (scrollPhase == NSEvent.SCROLL_PHASE_BEGAN) { accumulatedDelta = 0; + accumulate = true; + } + else if (scrollPhase == NSEvent.SCROLL_PHASE_MOMENTUM_BEGAN) { + accumulate = true; } + if (accumulate) { - accumulatedDelta += delta; + accumulatedDelta += delta; - double absAccumulatedDelta = Math.abs(accumulatedDelta); - if (absAccumulatedDelta > MAX_THRESHOLD) { roundDelta = (int) Math.round(accumulatedDelta); + accumulatedDelta -= roundDelta; - } - if (end) { - if (roundDelta == 0 && absAccumulatedDelta > MIN_THRESHOLD) { - roundDelta = accumulatedDelta > 0 ? 1 : -1; + if (scrollPhase == NSEvent.SCROLL_PHASE_ENDED) { + accumulate = false; } } } diff --git a/src/macosx/classes/sun/lwawt/macosx/NSEvent.java b/src/macosx/classes/sun/lwawt/macosx/NSEvent.java index eccc25743..3a8508d48 100644 --- a/src/macosx/classes/sun/lwawt/macosx/NSEvent.java +++ b/src/macosx/classes/sun/lwawt/macosx/NSEvent.java @@ -36,8 +36,8 @@ final class NSEvent { static final int SCROLL_PHASE_UNSUPPORTED = 1; static final int SCROLL_PHASE_BEGAN = 2; static final int SCROLL_PHASE_CONTINUED = 3; - static final int SCROLL_MASK_PHASE_CANCELLED = 4; - static final int SCROLL_MASK_PHASE_ENDED = 5; + static final int SCROLL_PHASE_MOMENTUM_BEGAN = 4; + static final int SCROLL_PHASE_ENDED = 5; private int type; private int modifierFlags; diff --git a/src/macosx/native/sun/awt/AWTView.m b/src/macosx/native/sun/awt/AWTView.m index 35c9440ba..74d685a8e 100644 --- a/src/macosx/native/sun/awt/AWTView.m +++ b/src/macosx/native/sun/awt/AWTView.m @@ -385,6 +385,13 @@ AWT_ASSERT_APPKIT_THREAD; clickCount = [event clickCount]; } + jdouble deltaX = [event deltaX]; + jdouble deltaY = [event deltaY]; + if ([AWTToolkit hasPreciseScrollingDeltas: event]) { + deltaX = [event scrollingDeltaX] * 0.1; + deltaY = [event scrollingDeltaY] * 0.1; + } + static JNF_CLASS_CACHE(jc_NSEvent, "sun/lwawt/macosx/NSEvent"); static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IIIIIIIIDDI)V"); jobject jEvent = JNFNewObject(env, jctor_NSEvent, @@ -394,8 +401,8 @@ AWT_ASSERT_APPKIT_THREAD; [event buttonNumber], (jint)localPoint.x, (jint)localPoint.y, (jint)absP.x, (jint)absP.y, - [event deltaY], - [event deltaX], + deltaY, + deltaX, [AWTToolkit scrollStateWithEvent: event]); if (jEvent == nil) { // Unable to create event by some reason. diff --git a/src/macosx/native/sun/awt/CTrayIcon.m b/src/macosx/native/sun/awt/CTrayIcon.m index b3967df97..bcf82cf07 100644 --- a/src/macosx/native/sun/awt/CTrayIcon.m +++ b/src/macosx/native/sun/awt/CTrayIcon.m @@ -135,6 +135,13 @@ static NSSize ScaledImageSizeForStatusBar(NSSize imageSize) { clickCount = [event clickCount]; + jdouble deltaX = [event deltaX]; + jdouble deltaY = [event deltaY]; + if ([AWTToolkit hasPreciseScrollingDeltas: event]) { + deltaX = [event scrollingDeltaX] * 0.1; + deltaY = [event scrollingDeltaY] * 0.1; + } + static JNF_CLASS_CACHE(jc_NSEvent, "sun/lwawt/macosx/NSEvent"); static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IIIIIIIIDDI)V"); jobject jEvent = JNFNewObject(env, jctor_NSEvent, @@ -144,8 +151,8 @@ static NSSize ScaledImageSizeForStatusBar(NSSize imageSize) { [event buttonNumber], (jint)localPoint.x, (jint)localPoint.y, (jint)absP.x, (jint)absP.y, - [event deltaY], - [event deltaX], + deltaY, + deltaX, [AWTToolkit scrollStateWithEvent: event]); if (jEvent == nil) { // Unable to create event by some reason. diff --git a/src/macosx/native/sun/awt/LWCToolkit.h b/src/macosx/native/sun/awt/LWCToolkit.h index 0a5750151..a81bc2da0 100644 --- a/src/macosx/native/sun/awt/LWCToolkit.h +++ b/src/macosx/native/sun/awt/LWCToolkit.h @@ -41,6 +41,7 @@ extern jint* gButtonDownMasks; + (long) getEventCount; + (void) eventCountPlusPlus; + (jint) scrollStateWithEvent: (NSEvent*) event; ++ (BOOL) hasPreciseScrollingDeltas: (NSEvent*) event; @end /* diff --git a/src/macosx/native/sun/awt/LWCToolkit.m b/src/macosx/native/sun/awt/LWCToolkit.m index 871f319d4..f56f58770 100644 --- a/src/macosx/native/sun/awt/LWCToolkit.m +++ b/src/macosx/native/sun/awt/LWCToolkit.m @@ -43,7 +43,7 @@ #define SCROLL_PHASE_UNSUPPORTED 1 #define SCROLL_PHASE_BEGAN 2 #define SCROLL_PHASE_CONTINUED 3 -#define SCROLL_PHASE_CANCELLED 4 +#define SCROLL_PHASE_MOMENTUM_BEGAN 4 #define SCROLL_PHASE_ENDED 5 int gNumberOfButtons; @@ -62,21 +62,38 @@ static long eventCount; } + (jint) scrollStateWithEvent: (NSEvent*) event { - + if ([event type] != NSScrollWheel) { return 0; } - - NSEventPhase phase = [event phase]; - NSEventPhase momentumPhase = [event momentumPhase]; - - if (!phase && !momentumPhase) return SCROLL_PHASE_UNSUPPORTED; - switch (phase) { - case NSEventPhaseBegan: return SCROLL_PHASE_BEGAN; - case NSEventPhaseCancelled: return SCROLL_PHASE_CANCELLED; - case NSEventPhaseEnded: return SCROLL_PHASE_ENDED; + + if ([event phase]) { + // process a phase of manual scrolling + switch ([event phase]) { + case NSEventPhaseBegan: return SCROLL_PHASE_BEGAN; + case NSEventPhaseCancelled: return SCROLL_PHASE_ENDED; + case NSEventPhaseEnded: return SCROLL_PHASE_ENDED; + default: return SCROLL_PHASE_CONTINUED; + } } - return SCROLL_PHASE_CONTINUED; + + if ([event momentumPhase]) { + // process a phase of automatic scrolling + switch ([event momentumPhase]) { + case NSEventPhaseBegan: return SCROLL_PHASE_MOMENTUM_BEGAN; + case NSEventPhaseCancelled: return SCROLL_PHASE_ENDED; + case NSEventPhaseEnded: return SCROLL_PHASE_ENDED; + default: return SCROLL_PHASE_CONTINUED; + } + } + // phase and momentum phase both are not set + return SCROLL_PHASE_UNSUPPORTED; +} + ++ (BOOL) hasPreciseScrollingDeltas: (NSEvent*) event { + return [event type] == NSScrollWheel + && [event respondsToSelector:@selector(hasPreciseScrollingDeltas)] + && [event hasPreciseScrollingDeltas]; } @end diff --git a/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java b/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java index a58bc7016..ba23035c2 100644 --- a/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java +++ b/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java @@ -40,7 +40,7 @@ import javax.swing.SwingUtilities; /* * @test - * @bug 8166591 + * @bug 8166591 8173876 * @summary [macos 10.12] Trackpad scrolling of text on OS X 10.12 Sierra * is very fast (Trackpad, Retina only) * @run main/manual/othervm TooMuchWheelRotationEventsTest -- GitLab