changeset 11963:6042757c329b jdk8u101-b02

Merge
author asaha
date Sat, 21 May 2016 23:20:12 -0700
parents 283de90a396e (current diff) f5c7bc7c1f87 (diff)
children 544199dbea50
files .hgtags test/javax/swing/JScrollPane/8033000/bug8033000.java
diffstat 6 files changed, 367 insertions(+), 185 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Sat May 21 23:15:53 2016 -0700
+++ b/.hgtags	Sat May 21 23:20:12 2016 -0700
@@ -544,6 +544,11 @@
 32c49f4a16599e376e4e46bb33c7bcc486e52ff3 jdk8u74-b02
 9c828e688240362b6f1b761b619cdaa070462c4e jdk8u74-b31
 6968ca30f8fdc9429fcd56187e16f46b215b474b jdk8u74-b32
+02e1209648050922a5a9f2789d9d359795f6f834 jdk8u77-b00
+f08584a0fde9344b0aa4766984266ca68b9a5018 jdk8u77-b01
+1a3e81c05703bb36def80a57681e1692c866f621 jdk8u77-b02
+c44179bce874a97e93ffd7b76a226af417e017a4 jdk8u77-b03
+8c3f4e540348daed7263bae092b0e5f212478b00 jdk8u77-b31
 1d4b343084874b1afa1cdd504b9b1e50bab7f121 jdk8u72-b31
 7cfd2c51c501df909833aa0fb6e40c50c61621ed jdk8u75-b00
 9e00a43602f87930c2318b2567002871ad9c59dd jdk8u75-b01
--- a/src/share/classes/java/math/BigInteger.java	Sat May 21 23:15:53 2016 -0700
+++ b/src/share/classes/java/math/BigInteger.java	Sat May 21 23:20:12 2016 -0700
@@ -276,6 +276,15 @@
      */
     private static final int MULTIPLY_SQUARE_THRESHOLD = 20;
 
+    /**
+     * The threshold for using an intrinsic version of
+     * implMontgomeryXXX to perform Montgomery multiplication.  If the
+     * number of ints in the number is more than this value we do not
+     * use the intrinsic.
+     */
+    private static final int MONTGOMERY_INTRINSIC_THRESHOLD = 512;
+
+
     // Constructors
 
     /**
@@ -1573,7 +1582,7 @@
      * Multiplies int arrays x and y to the specified lengths and places
      * the result into z. There will be no leading zeros in the resultant array.
      */
-    private int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
+    private static int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
         int xstart = xlen - 1;
         int ystart = ylen - 1;
 
@@ -1897,6 +1906,43 @@
      * int array z.  The contents of x are not changed.
      */
     private static final int[] squareToLen(int[] x, int len, int[] z) {
+         int zlen = len << 1;
+         if (z == null || z.length < zlen)
+             z = new int[zlen];
+
+         // Execute checks before calling intrinsified method.
+         implSquareToLenChecks(x, len, z, zlen);
+         return implSquareToLen(x, len, z, zlen);
+     }
+
+     /**
+      * Parameters validation.
+      */
+     private static void implSquareToLenChecks(int[] x, int len, int[] z, int zlen) throws RuntimeException {
+         if (len < 1) {
+             throw new IllegalArgumentException("invalid input length: " + len);
+         }
+         if (len > x.length) {
+             throw new IllegalArgumentException("input length out of bound: " +
+                                        len + " > " + x.length);
+         }
+         if (len * 2 > z.length) {
+             throw new IllegalArgumentException("input length out of bound: " +
+                                        (len * 2) + " > " + z.length);
+         }
+         if (zlen < 1) {
+             throw new IllegalArgumentException("invalid input length: " + zlen);
+         }
+         if (zlen > z.length) {
+             throw new IllegalArgumentException("input length out of bound: " +
+                                        len + " > " + z.length);
+         }
+     }
+
+     /**
+      * Java Runtime may use intrinsic for this method.
+      */
+     private static final int[] implSquareToLen(int[] x, int len, int[] z, int zlen) {
         /*
          * The algorithm used here is adapted from Colin Plumb's C library.
          * Technique: Consider the partial products in the multiplication
@@ -1931,9 +1977,6 @@
          * again.  The low bit is simply a copy of the low bit of the
          * input, so it doesn't need special care.
          */
-        int zlen = len << 1;
-        if (z == null || z.length < zlen)
-            z = new int[zlen];
 
         // Store the squares, right shifted one bit (i.e., divided by 2)
         int lastProductLowWord = 0;
@@ -2501,6 +2544,75 @@
         return (invertResult ? result.modInverse(m) : result);
     }
 
+    // Montgomery multiplication.  These are wrappers for
+    // implMontgomeryXX routines which are expected to be replaced by
+    // virtual machine intrinsics.  We don't use the intrinsics for
+    // very large operands: MONTGOMERY_INTRINSIC_THRESHOLD should be
+    // larger than any reasonable crypto key.
+    private static int[] montgomeryMultiply(int[] a, int[] b, int[] n, int len, long inv,
+                                            int[] product) {
+        implMontgomeryMultiplyChecks(a, b, n, len, product);
+        if (len > MONTGOMERY_INTRINSIC_THRESHOLD) {
+            // Very long argument: do not use an intrinsic
+            product = multiplyToLen(a, len, b, len, product);
+            return montReduce(product, n, len, (int)inv);
+        } else {
+            return implMontgomeryMultiply(a, b, n, len, inv, materialize(product, len));
+        }
+    }
+    private static int[] montgomerySquare(int[] a, int[] n, int len, long inv,
+                                          int[] product) {
+        implMontgomeryMultiplyChecks(a, a, n, len, product);
+        if (len > MONTGOMERY_INTRINSIC_THRESHOLD) {
+            // Very long argument: do not use an intrinsic
+            product = squareToLen(a, len, product);
+            return montReduce(product, n, len, (int)inv);
+        } else {
+            return implMontgomerySquare(a, n, len, inv, materialize(product, len));
+        }
+    }
+
+    // Range-check everything.
+    private static void implMontgomeryMultiplyChecks
+        (int[] a, int[] b, int[] n, int len, int[] product) throws RuntimeException {
+        if (len % 2 != 0) {
+            throw new IllegalArgumentException("input array length must be even: " + len);
+        }
+
+        if (len < 1) {
+            throw new IllegalArgumentException("invalid input length: " + len);
+        }
+
+        if (len > a.length ||
+            len > b.length ||
+            len > n.length ||
+            (product != null && len > product.length)) {
+            throw new IllegalArgumentException("input array length out of bound: " + len);
+        }
+    }
+
+    // Make sure that the int array z (which is expected to contain
+    // the result of a Montgomery multiplication) is present and
+    // sufficiently large.
+    private static int[] materialize(int[] z, int len) {
+         if (z == null || z.length < len)
+             z = new int[len];
+         return z;
+    }
+
+    // These methods are intended to be be replaced by virtual machine
+    // intrinsics.
+    private static int[] implMontgomeryMultiply(int[] a, int[] b, int[] n, int len,
+                                         long inv, int[] product) {
+        product = multiplyToLen(a, len, b, len, product);
+        return montReduce(product, n, len, (int)inv);
+    }
+    private static int[] implMontgomerySquare(int[] a, int[] n, int len,
+                                       long inv, int[] product) {
+        product = squareToLen(a, len, product);
+        return montReduce(product, n, len, (int)inv);
+    }
+
     static int[] bnExpModThreshTable = {7, 25, 81, 241, 673, 1793,
                                                 Integer.MAX_VALUE}; // Sentinel
 
@@ -2579,6 +2691,17 @@
         int[] mod = z.mag;
         int modLen = mod.length;
 
+        // Make modLen even. It is conventional to use a cryptographic
+        // modulus that is 512, 768, 1024, or 2048 bits, so this code
+        // will not normally be executed. However, it is necessary for
+        // the correct functioning of the HotSpot intrinsics.
+        if ((modLen & 1) != 0) {
+            int[] x = new int[modLen + 1];
+            System.arraycopy(mod, 0, x, 1, modLen);
+            mod = x;
+            modLen++;
+        }
+
         // Select an appropriate window size
         int wbits = 0;
         int ebits = bitLength(exp, exp.length);
@@ -2597,8 +2720,10 @@
         for (int i=0; i < tblmask; i++)
             table[i] = new int[modLen];
 
-        // Compute the modular inverse
-        int inv = -MutableBigInteger.inverseMod32(mod[modLen-1]);
+        // Compute the modular inverse of the least significant 64-bit
+        // digit of the modulus
+        long n0 = (mod[modLen-1] & LONG_MASK) + ((mod[modLen-2] & LONG_MASK) << 32);
+        long inv = -MutableBigInteger.inverseMod64(n0);
 
         // Convert base to Montgomery form
         int[] a = leftShift(base, base.length, modLen << 5);
@@ -2606,6 +2731,8 @@
         MutableBigInteger q = new MutableBigInteger(),
                           a2 = new MutableBigInteger(a),
                           b2 = new MutableBigInteger(mod);
+        b2.normalize(); // MutableBigInteger.divide() assumes that its
+                        // divisor is in normal form.
 
         MutableBigInteger r= a2.divide(b2, q);
         table[0] = r.toIntArray();
@@ -2614,22 +2741,19 @@
         if (table[0].length < modLen) {
            int offset = modLen - table[0].length;
            int[] t2 = new int[modLen];
-           for (int i=0; i < table[0].length; i++)
-               t2[i+offset] = table[0][i];
+           System.arraycopy(table[0], 0, t2, offset, table[0].length);
            table[0] = t2;
         }
 
         // Set b to the square of the base
-        int[] b = squareToLen(table[0], modLen, null);
-        b = montReduce(b, mod, modLen, inv);
+        int[] b = montgomerySquare(table[0], mod, modLen, inv, null);
 
         // Set t to high half of b
         int[] t = Arrays.copyOf(b, modLen);
 
         // Fill in the table with odd powers of the base
         for (int i=1; i < tblmask; i++) {
-            int[] prod = multiplyToLen(t, modLen, table[i-1], modLen, null);
-            table[i] = montReduce(prod, mod, modLen, inv);
+            table[i] = montgomeryMultiply(t, table[i-1], mod, modLen, inv, null);
         }
 
         // Pre load the window that slides over the exponent
@@ -2700,8 +2824,7 @@
                     isone = false;
                 } else {
                     t = b;
-                    a = multiplyToLen(t, modLen, mult, modLen, a);
-                    a = montReduce(a, mod, modLen, inv);
+                    a = montgomeryMultiply(t, mult, mod, modLen, inv, a);
                     t = a; a = b; b = t;
                 }
             }
@@ -2713,8 +2836,7 @@
             // Square the input
             if (!isone) {
                 t = b;
-                a = squareToLen(t, modLen, a);
-                a = montReduce(a, mod, modLen, inv);
+                a = montgomerySquare(t, mod, modLen, inv, a);
                 t = a; a = b; b = t;
             }
         }
@@ -2723,7 +2845,7 @@
         int[] t2 = new int[2*modLen];
         System.arraycopy(b, 0, t2, modLen, modLen);
 
-        b = montReduce(t2, mod, modLen, inv);
+        b = montReduce(t2, mod, modLen, (int)inv);
 
         t2 = Arrays.copyOf(b, modLen);
 
@@ -2791,6 +2913,32 @@
      * Multiply an array by one word k and add to result, return the carry
      */
     static int mulAdd(int[] out, int[] in, int offset, int len, int k) {
+        implMulAddCheck(out, in, offset, len, k);
+        return implMulAdd(out, in, offset, len, k);
+    }
+
+    /**
+     * Parameters validation.
+     */
+    private static void implMulAddCheck(int[] out, int[] in, int offset, int len, int k) {
+        if (len > in.length) {
+            throw new IllegalArgumentException("input length is out of bound: " + len + " > " + in.length);
+        }
+        if (offset < 0) {
+            throw new IllegalArgumentException("input offset is invalid: " + offset);
+        }
+        if (offset > (out.length - 1)) {
+            throw new IllegalArgumentException("input offset is out of bound: " + offset + " > " + (out.length - 1));
+        }
+        if (len > (out.length - offset)) {
+            throw new IllegalArgumentException("input len is out of bound: " + len + " > " + (out.length - offset));
+        }
+    }
+
+    /**
+     * Java Runtime may use intrinsic for this method.
+     */
+    private static int implMulAdd(int[] out, int[] in, int offset, int len, int k) {
         long kLong = k & LONG_MASK;
         long carry = 0;
 
--- a/src/share/classes/java/math/MutableBigInteger.java	Sat May 21 23:15:53 2016 -0700
+++ b/src/share/classes/java/math/MutableBigInteger.java	Sat May 21 23:20:12 2016 -0700
@@ -2065,6 +2065,21 @@
     }
 
     /**
+     * Returns the multiplicative inverse of val mod 2^64.  Assumes val is odd.
+     */
+    static long inverseMod64(long val) {
+        // Newton's iteration!
+        long t = val;
+        t *= 2 - val*t;
+        t *= 2 - val*t;
+        t *= 2 - val*t;
+        t *= 2 - val*t;
+        t *= 2 - val*t;
+        assert(t * val == 1);
+        return t;
+    }
+
+    /**
      * Calculate the multiplicative inverse of 2^k mod mod, where mod is odd.
      */
     static MutableBigInteger modInverseBP2(MutableBigInteger mod, int k) {
--- a/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java	Sat May 21 23:15:53 2016 -0700
+++ b/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java	Sat May 21 23:20:12 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -870,18 +870,13 @@
                 int orientation = SwingConstants.VERTICAL;
 
                 // find which scrollbar to scroll, or return if none
-                if (toScroll == null || !toScroll.isVisible()) {
+                if (toScroll == null || !toScroll.isVisible()
+                        || e.isShiftDown()) {
                     toScroll = scrollpane.getHorizontalScrollBar();
                     if (toScroll == null || !toScroll.isVisible()) {
                         return;
                     }
                     orientation = SwingConstants.HORIZONTAL;
-                } else if(e.isShiftDown()){
-                    JScrollBar hScroll = scrollpane.getHorizontalScrollBar();
-                    if (hScroll != null && hScroll.isVisible()) {
-                        toScroll = hScroll;
-                        orientation = SwingConstants.HORIZONTAL;
-                    }
                 }
 
                 e.consume();
--- a/test/javax/swing/JScrollPane/8033000/bug8033000.java	Sat May 21 23:15:53 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-import java.awt.BorderLayout;
-import java.awt.Point;
-import java.awt.Robot;
-import java.awt.event.KeyEvent;
-import javax.swing.JFrame;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
-import javax.swing.SwingUtilities;
-import javax.swing.UIManager;
-import sun.awt.OSInfo;
-
-/**
- * @test
- * @bug 8033000
- * @author Alexander Scherbatiy
- * @summary No Horizontal Mouse Wheel Support In BasicScrollPaneUI
- * @run main bug8033000
- */
-public class bug8033000 {
-
-    private static JScrollPane scrollPane;
-    private static JTextArea textArea;
-    private static Point point;
-    private static final int delta;
-
-    static {
-        delta = OSInfo.getOSType().equals(OSInfo.OSType.MACOSX) ? -30 : 30;
-    }
-
-    public static void main(String[] args) throws Exception {
-
-        Robot robot = new Robot();
-        robot.setAutoDelay(50);
-
-        SwingUtilities.invokeAndWait(bug8033000::createAndShowGUI);
-        robot.waitForIdle();
-
-        SwingUtilities.invokeAndWait(() -> {
-            Point locationOnScreen = scrollPane.getLocationOnScreen();
-            point = new Point(
-                    locationOnScreen.x + scrollPane.getWidth() / 2,
-                    locationOnScreen.y + scrollPane.getHeight() / 2);
-        });
-
-        robot.mouseMove(point.x, point.y);
-        robot.waitForIdle();
-
-        // vertical scroll bar is enabled
-        initScrollPane(true, false);
-        robot.waitForIdle();
-        robot.mouseWheel(delta);
-        robot.waitForIdle();
-        checkScrollPane(true);
-
-        // vertical scroll bar is enabled + shift
-        initScrollPane(true, false);
-        robot.waitForIdle();
-        robot.keyPress(KeyEvent.VK_SHIFT);
-        robot.mouseWheel(delta);
-        robot.keyRelease(KeyEvent.VK_SHIFT);
-        robot.waitForIdle();
-        checkScrollPane(true);
-
-        // horizontal scroll bar is enabled
-        initScrollPane(false, true);
-        robot.waitForIdle();
-        robot.mouseWheel(delta);
-        robot.waitForIdle();
-        checkScrollPane(false);
-
-        // horizontal scroll bar is enabled + shift
-        initScrollPane(false, true);
-        robot.waitForIdle();
-        robot.keyPress(KeyEvent.VK_SHIFT);
-        robot.mouseWheel(delta);
-        robot.keyRelease(KeyEvent.VK_SHIFT);
-        robot.waitForIdle();
-        checkScrollPane(false);
-
-        // both scroll bars are enabled
-        initScrollPane(true, true);
-        robot.waitForIdle();
-        robot.mouseWheel(delta);
-        robot.waitForIdle();
-        checkScrollPane(true);
-
-        // both scroll bars are enabled + shift
-        initScrollPane(true, true);
-        robot.waitForIdle();
-        robot.keyPress(KeyEvent.VK_SHIFT);
-        robot.mouseWheel(delta);
-        robot.keyRelease(KeyEvent.VK_SHIFT);
-        robot.waitForIdle();
-        checkScrollPane(false);
-    }
-
-    static void initScrollPane(boolean vVisible, boolean hVisible) throws Exception {
-        SwingUtilities.invokeAndWait(() -> {
-            scrollPane.getVerticalScrollBar().setValue(0);
-            scrollPane.getHorizontalScrollBar().setValue(0);
-
-            textArea.setRows(vVisible ? 100 : 1);
-            textArea.setColumns(hVisible ? 100 : 1);
-            scrollPane.getVerticalScrollBar().setVisible(vVisible);
-            scrollPane.getHorizontalScrollBar().setVisible(hVisible);
-        });
-    }
-
-    static void checkScrollPane(boolean verticalScrolled) throws Exception {
-        SwingUtilities.invokeAndWait(() -> {
-
-            if (verticalScrolled) {
-                if (scrollPane.getVerticalScrollBar().getValue() == 0
-                        || scrollPane.getHorizontalScrollBar().getValue() != 0) {
-                    throw new RuntimeException("Wrong vertical scrolling!");
-                }
-            } else {
-                if (scrollPane.getVerticalScrollBar().getValue() != 0
-                        || scrollPane.getHorizontalScrollBar().getValue() == 0) {
-                    throw new RuntimeException("Wrong horizontal scrolling!");
-                }
-            }
-        });
-    }
-
-    static void createAndShowGUI() {
-        JFrame frame = new JFrame();
-        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-        frame.setSize(300, 300);
-        textArea = new JTextArea("Hello World!");
-        scrollPane = new JScrollPane(textArea);
-        JPanel panel = new JPanel(new BorderLayout());
-        panel.add(scrollPane, BorderLayout.CENTER);
-        frame.getContentPane().add(panel);
-        frame.setVisible(true);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/swing/JScrollPane/HorizontalMouseWheelOnShiftPressed/HorizontalMouseWheelOnShiftPressed.java	Sat May 21 23:20:12 2016 -0700
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.event.KeyEvent;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+
+import sun.awt.OSInfo;
+
+/**
+ * @test
+ * @bug 8033000 8147994
+ * @author Alexander Scherbatiy
+ * @summary No Horizontal Mouse Wheel Support In BasicScrollPaneUI
+ * @run main HorizontalMouseWheelOnShiftPressed
+ */
+public class HorizontalMouseWheelOnShiftPressed {
+
+    private static JScrollPane scrollPane;
+    private static JTextArea textArea;
+    private static Point point;
+    private static final int delta;
+    private static JFrame frame;
+
+    static {
+        delta = OSInfo.getOSType().equals(OSInfo.OSType.MACOSX) ? -30 : 30;
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        Robot robot = new Robot();
+        robot.setAutoDelay(50);
+
+        SwingUtilities.invokeAndWait(
+                HorizontalMouseWheelOnShiftPressed::createAndShowGUI);
+        robot.waitForIdle();
+        try {
+            test(robot);
+        } finally {
+            frame.dispose();
+        }
+    }
+
+    private static void test(Robot robot) throws Exception {
+        SwingUtilities.invokeAndWait(() -> {
+            Point locationOnScreen = scrollPane.getLocationOnScreen();
+            point = new Point(
+                    locationOnScreen.x + scrollPane.getWidth() / 2,
+                    locationOnScreen.y + scrollPane.getHeight() / 2);
+        });
+
+        robot.mouseMove(point.x, point.y);
+        robot.waitForIdle();
+
+        // vertical scroll bar is enabled
+        initScrollPane(true, false);
+        robot.waitForIdle();
+        robot.mouseWheel(delta);
+        robot.waitForIdle();
+        checkScrollPane(true, false);
+
+        // vertical scroll bar is enabled + shift
+        initScrollPane(true, false);
+        robot.waitForIdle();
+        robot.keyPress(KeyEvent.VK_SHIFT);
+        robot.mouseWheel(delta);
+        robot.keyRelease(KeyEvent.VK_SHIFT);
+        robot.waitForIdle();
+        checkScrollPane(false, false);
+
+        // horizontal scroll bar is enabled
+        initScrollPane(false, true);
+        robot.waitForIdle();
+        robot.mouseWheel(delta);
+        robot.waitForIdle();
+        checkScrollPane(false, true);
+
+        // horizontal scroll bar is enabled + shift
+        initScrollPane(false, true);
+        robot.waitForIdle();
+        robot.keyPress(KeyEvent.VK_SHIFT);
+        robot.mouseWheel(delta);
+        robot.keyRelease(KeyEvent.VK_SHIFT);
+        robot.waitForIdle();
+        checkScrollPane(false, true);
+
+        // both scroll bars are enabled
+        initScrollPane(true, true);
+        robot.waitForIdle();
+        robot.mouseWheel(delta);
+        robot.waitForIdle();
+        checkScrollPane(true, false);
+
+        // both scroll bars are enabled + shift
+        initScrollPane(true, true);
+        robot.waitForIdle();
+        robot.keyPress(KeyEvent.VK_SHIFT);
+        robot.mouseWheel(delta);
+        robot.keyRelease(KeyEvent.VK_SHIFT);
+        robot.waitForIdle();
+        checkScrollPane(false, true);
+    }
+
+    static void initScrollPane(boolean vVisible, boolean hVisible) throws Exception {
+        SwingUtilities.invokeAndWait(() -> {
+            scrollPane.getVerticalScrollBar().setValue(0);
+            scrollPane.getHorizontalScrollBar().setValue(0);
+
+            textArea.setRows(vVisible ? 100 : 1);
+            textArea.setColumns(hVisible ? 100 : 1);
+            scrollPane.getVerticalScrollBar().setVisible(vVisible);
+            scrollPane.getHorizontalScrollBar().setVisible(hVisible);
+        });
+    }
+
+    static void checkScrollPane(boolean verticalScrolled,
+                                boolean horizontalScrolled) throws Exception {
+        SwingUtilities.invokeAndWait(() -> {
+
+            if (verticalScrolled) {
+                if (scrollPane.getVerticalScrollBar().getValue() == 0) {
+                    throw new RuntimeException("Wrong vertical scrolling!");
+                }
+            } else{
+                if (scrollPane.getVerticalScrollBar().getValue() != 0) {
+                    throw new RuntimeException("Wrong vertical scrolling!");
+                }
+            }
+            if (horizontalScrolled) {
+                if (scrollPane.getHorizontalScrollBar().getValue() == 0) {
+                    throw new RuntimeException("Wrong horizontal scrolling!");
+                }
+            } else {
+                if (scrollPane.getHorizontalScrollBar().getValue() != 0) {
+                    throw new RuntimeException("Wrong horizontal scrolling!");
+                }
+            }
+        });
+    }
+
+    static void createAndShowGUI() {
+        frame = new JFrame();
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        frame.setSize(300, 300);
+        frame.setLocationRelativeTo(null);
+        textArea = new JTextArea("Hello World!");
+        scrollPane = new JScrollPane(textArea);
+        JPanel panel = new JPanel(new BorderLayout());
+        panel.add(scrollPane, BorderLayout.CENTER);
+        frame.getContentPane().add(panel);
+        frame.setVisible(true);
+    }
+}