8165485: Bad rendering of Swing UI controls with Motif L&F on HiDPI display
authoralexsch
Wed, 05 Oct 2016 18:42:34 +0400
changeset 41774 e9156811f79c
parent 41773 58254fa6487a
child 41775 cd8702847ab1
8165485: Bad rendering of Swing UI controls with Motif L&F on HiDPI display 8147600: [hidpi] invalid rendering of Swing UI controls (radiobuttons, choice etc.) Reviewed-by: serb
jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java
jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java
jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java
jdk/test/javax/swing/plaf/motif/8165485/MotifHiDPIIconsTest.java
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java	Wed Oct 05 18:29:18 2016 +0400
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java	Wed Oct 05 18:42:34 2016 +0400
@@ -298,31 +298,24 @@
         public void paintIcon(Component c, Graphics g, int xo, int yo) {
             int w = getIconWidth();
             int h = getIconHeight();
-
-            g.setColor(lightShadow);
-            g.drawLine(xo, yo, xo+w-1, yo);
-            g.drawLine(xo, yo+1, xo+w-3, yo+1);
-            g.setColor(darkShadow);
-            g.drawLine(xo+w-2, yo+1, xo+w-1, yo+1);
+            int x1 = xo + w - 1;
+            int y1 = yo;
+            int x2 = xo + w / 2;
+            int y2 = yo + h - 1;
 
-            for ( int x = xo+1, y = yo+2, dx = w-6; y+1 < yo+h; y += 2 ) {
-                g.setColor(lightShadow);
-                g.drawLine(x, y,   x+1, y);
-                g.drawLine(x, y+1, x+1, y+1);
-                if ( dx > 0 ) {
-                    g.setColor(fill);
-                    g.drawLine(x+2, y,   x+1+dx, y);
-                    g.drawLine(x+2, y+1, x+1+dx, y+1);
-                }
-                g.setColor(darkShadow);
-                g.drawLine(x+dx+2, y,   x+dx+3, y);
-                g.drawLine(x+dx+2, y+1, x+dx+3, y+1);
-                x += 1;
-                dx -= 2;
-            }
+            g.setColor(fill);
+            g.fillPolygon(new int[]{xo, x1, x2}, new int[]{yo, y1, y2}, 3);
+            g.setColor(lightShadow);
+            g.drawLine(xo, yo, x1, y1);
 
+            g.drawLine(xo, yo + 1, x2, y2);
+            g.drawLine(xo, yo + 1, x1, y1 + 1);
+            g.drawLine(xo + 1, yo + 1, x2, y2 - 1);
             g.setColor(darkShadow);
-            g.drawLine(xo+(w/2), yo+h-1, xo+(w/2), yo+h-1);
+            g.drawLine(x1, y1 + 1, x2, y2);
+            g.drawLine(x1 - 1, y1 + 1, x2, y2 - 1);
+            g.drawLine(x1 - 1, y1 + 1, x1, y1 + 1); // corner
+            g.drawLine(x2, y2, x2, y2); // corner
 
         }
 
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java	Wed Oct 05 18:29:18 2016 +0400
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java	Wed Oct 05 18:42:34 2016 +0400
@@ -249,17 +249,11 @@
                 if (check) {
                     // draw check
                     g.setColor(foreground);
-                    g.drawLine(csize-2,1,csize-2,2);
-                    g.drawLine(csize-3,2,csize-3,3);
-                    g.drawLine(csize-4,3,csize-4,4);
-                    g.drawLine(csize-5,4,csize-5,6);
-                    g.drawLine(csize-6,5,csize-6,8);
-                    g.drawLine(csize-7,6,csize-7,10);
-                    g.drawLine(csize-8,7,csize-8,10);
-                    g.drawLine(csize-9,6,csize-9,9);
-                    g.drawLine(csize-10,5,csize-10,8);
-                    g.drawLine(csize-11,5,csize-11,7);
-                    g.drawLine(csize-12,6,csize-12,6);
+                    int[] xa = {csize - 12, csize - 8, csize - 7, csize - 4,
+                                csize - 2, csize - 2, csize - 8, csize - 10,
+                                csize - 11};
+                    int[] ya = new int[]{6, 10, 10, 4, 2, 1, 7, 5, 5};
+                    g.fillPolygon(xa, ya, 9);
                 }
                 g.translate(-x, -y);
                 g.setColor(oldColor);
@@ -301,50 +295,18 @@
 
             if (checkIn){
                 g.setColor(shadow);
-                g.drawLine(x+5,y+0,x+8,y+0);
-                g.drawLine(x+3,y+1,x+4,y+1);
-                g.drawLine(x+9,y+1,x+9,y+1);
-                g.drawLine(x+2,y+2,x+2,y+2);
-                g.drawLine(x+1,y+3,x+1,y+3);
-                g.drawLine(x,y+4,x,y+9);
-                g.drawLine(x+1,y+10,x+1,y+10);
-                g.drawLine(x+2,y+11,x+2,y+11);
+                g.drawArc(x, y, w - 1, h - 1, 45, 180);
                 g.setColor(highlight);
-                g.drawLine(x+3,y+12,x+4,y+12);
-                g.drawLine(x+5,y+13,x+8,y+13);
-                g.drawLine(x+9,y+12,x+10,y+12);
-                g.drawLine(x+11,y+11,x+11,y+11);
-                g.drawLine(x+12,y+10,x+12,y+10);
-                g.drawLine(x+13,y+9,x+13,y+4);
-                g.drawLine(x+12,y+3,x+12,y+3);
-                g.drawLine(x+11,y+2,x+11,y+2);
-                g.drawLine(x+10,y+1,x+10,y+1);
+                g.drawArc(x, y, w - 1, h - 1, 45, -180);
                 g.setColor(dot);
-                g.fillRect(x+4,y+5,6,4);
-                g.drawLine(x+5,y+4,x+8,y+4);
-                g.drawLine(x+5,y+9,x+8,y+9);
+                g.fillOval(x + 3, y + 3, 7, 7);
             }
             else {
                 g.setColor(highlight);
-                g.drawLine(x+5,y+0,x+8,y+0);
-                g.drawLine(x+3,y+1,x+4,y+1);
-                g.drawLine(x+9,y+1,x+9,y+1);
-                g.drawLine(x+2,y+2,x+2,y+2);
-                g.drawLine(x+1,y+3,x+1,y+3);
-                g.drawLine(x,y+4,x,y+9);
-                g.drawLine(x+1,y+10,x+1,y+10);
-                g.drawLine(x+2,y+11,x+2,y+11);
+                g.drawArc(x, y, w - 1, h - 1, 45, 180);
 
                 g.setColor(shadow);
-                g.drawLine(x+3,y+12,x+4,y+12);
-                g.drawLine(x+5,y+13,x+8,y+13);
-                g.drawLine(x+9,y+12,x+10,y+12);
-                g.drawLine(x+11,y+11,x+11,y+11);
-                g.drawLine(x+12,y+10,x+12,y+10);
-                g.drawLine(x+13,y+9,x+13,y+4);
-                g.drawLine(x+12,y+3,x+12,y+3);
-                g.drawLine(x+11,y+2,x+11,y+2);
-                g.drawLine(x+10,y+1,x+10,y+1);
+                g.drawArc(x, y, w - 1, h - 1, 45, -180);
 
             }
         }
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java	Wed Oct 05 18:29:18 2016 +0400
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java	Wed Oct 05 18:42:34 2016 +0400
@@ -117,95 +117,57 @@
 
         switch (direction) {
         case NORTH:
+            g.setColor(fill);
+            g.fillPolygon(new int[]{cx, 0, s - 1}, new int[]{0, s - 1, s - 1}, 3);
+            g.setColor(trail);
+            g.drawLine(cx, 0, s - 1, s - 2);
+            g.drawLine(0, s - 1, s - 1, s - 1);
+            g.drawLine(s - 1, s - 2, s - 1, s - 1); // corner
             g.setColor(lead);
-            g.drawLine(cx, 0, cx, 0);
-            for (int x = cx - 1, y = 1, dx = 1; y <= s - 2; y += 2) {
-                g.setColor(lead);
-                g.drawLine(x, y, x, y);
-                if (y >= (s - 2)) {
-                    g.drawLine(x, y + 1, x, y + 1);
-                }
-                g.setColor(fill);
-                g.drawLine(x + 1, y, x + dx, y);
-                if (y < (s - 2)) {
-                    g.drawLine(x, y + 1, x + dx + 1, y + 1);
-                }
-                g.setColor(trail);
-                g.drawLine(x + dx + 1, y, x + dx + 1, y);
-                if (y >= (s - 2)) {
-                    g.drawLine(x + 1, y + 1, x + dx + 1, y + 1);
-                }
-                dx += 2;
-                x -= 1;
-            }
+            g.drawLine(cx, 0, 0, s - 2);
+            g.drawLine(cx, 0, cx, 0); // corner
+            g.drawLine(0, s - 1, 0, s - 1); // corner
             break;
 
         case SOUTH:
+            g.setColor(fill);
+            g.fillPolygon(new int[]{0, s - 1, cx}, new int[]{1, 1, s}, 3);
             g.setColor(trail);
-            g.drawLine(cx, s, cx, s);
-            for (int x = cx - 1, y = s - 1, dx = 1; y >= 1; y -= 2) {
-                g.setColor(lead);
-                g.drawLine(x, y, x, y);
-                if (y <= 2) {
-                    g.drawLine(x, y - 1, x + dx + 1, y - 1);
-                }
-                g.setColor(fill);
-                g.drawLine(x + 1, y, x + dx, y);
-                if (y > 2) {
-                    g.drawLine(x, y - 1, x + dx + 1, y - 1);
-                }
-                g.setColor(trail);
-                g.drawLine(x + dx + 1, y, x + dx + 1, y);
-
-                dx += 2;
-                x -= 1;
-            }
+            g.drawLine(s - 1, 2, cx, s);
+            g.drawLine(s - 1, 2, s - 1, 2); // corner
+            g.setColor(lead);
+            g.drawLine(0, 2, cx, s);
+            g.drawLine(0, 1, s - 1, 1);
+            g.drawLine(0, 1, 0, 2);
+            g.setColor(trail);
+            g.drawLine(cx, s, cx, s); // corner
             break;
 
         case EAST:
+            g.setColor(fill);
+            g.fillPolygon(new int[]{1, s, 1}, new int[]{0, cy, s}, 3);
+            g.setColor(trail);
+            g.drawLine(1, s, s, cy);
+            g.drawLine(2, s, 2, s); // corner
             g.setColor(lead);
+            g.drawLine(1, 0, 1, s);
+            g.drawLine(2, 0, s, cy);
+            g.drawLine(2, 0, 2, 0); // corner
             g.drawLine(s, cy, s, cy);
-            for (int y = cy - 1, x = s - 1, dy = 1; x >= 1; x -= 2) {
-                g.setColor(lead);
-                g.drawLine(x, y, x, y);
-                if (x <= 2) {
-                    g.drawLine(x - 1, y, x - 1, y + dy + 1);
-                }
-                g.setColor(fill);
-                g.drawLine(x, y + 1, x, y + dy);
-                if (x > 2) {
-                    g.drawLine(x - 1, y, x - 1, y + dy + 1);
-                }
-                g.setColor(trail);
-                g.drawLine(x, y + dy + 1, x, y + dy + 1);
-
-                dy += 2;
-                y -= 1;
-            }
             break;
 
         case WEST:
+            g.setColor(fill);
+            g.fillPolygon(new int[]{0, s - 1, s - 1}, new int[]{cy, 0, s}, 3);
+            g.drawLine(s - 1, 0, s - 1, s);
             g.setColor(trail);
-            g.drawLine(0, cy, 0, cy);
-            for (int y = cy - 1, x = 1, dy = 1; x <= s - 2; x += 2) {
-                g.setColor(lead);
-                g.drawLine(x, y, x, y);
-                if (x >= (s - 2)) {
-                    g.drawLine(x + 1, y, x + 1, y);
-                }
-                g.setColor(fill);
-                g.drawLine(x, y + 1, x, y + dy);
-                if (x < (s - 2)) {
-                    g.drawLine(x + 1, y, x + 1, y + dy + 1);
-                }
-                g.setColor(trail);
-                g.drawLine(x, y + dy + 1, x, y + dy + 1);
-                if (x >= (s - 2)) {
-                    g.drawLine(x + 1, y + 1, x + 1, y + dy + 1);
-                }
-                dy += 2;
-                y -= 1;
-            }
+            g.drawLine(0, cy, s - 1, s);
+            g.drawLine(s - 1, 0, s - 1, s);
+            g.setColor(lead);
+            g.drawLine(0, cy, s - 2, 0);
+            g.drawLine(s - 2, 0, s - 1, 0); // corner
+            g.setColor(trail);
+            g.drawLine(0, cy, 0, cy); // corner
             break;
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/plaf/motif/8165485/MotifHiDPIIconsTest.java	Wed Oct 05 18:42:34 2016 +0400
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 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.Color;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.SwingUtilities;
+
+/*
+ * @test
+ * @bug 8165485
+ * @summary Bad rendering of Swing UI controls with Motif L&F on HiDPI display
+ * @run main/manual/othervm -Dsun.java2d.uiScale=2
+ * -Dswing.defaultlaf=com.sun.java.swing.plaf.motif.MotifLookAndFeel MotifHiDPIIconsTest
+ */
+public class MotifHiDPIIconsTest {
+
+    private static volatile boolean testResult = false;
+    private static volatile CountDownLatch countDownLatch;
+    private static final String INSTRUCTIONS = "INSTRUCTIONS:\n"
+            + "Check that the icons are painted smoothly on Swing UI controls:\n"
+            + "  - JRadioButton\n"
+            + "  - JCheckBox\n"
+            + "  - JComboBox\n"
+            + "  - JScrollPane (vertical and horizontal scroll bars)\n"
+            + "\n"
+            + "If so, press PASS, else press FAIL.\n";
+
+    public static void main(String args[]) throws Exception {
+        countDownLatch = new CountDownLatch(1);
+
+        SwingUtilities.invokeLater(MotifHiDPIIconsTest::createUI);
+        countDownLatch.await(15, TimeUnit.MINUTES);
+
+        if (!testResult) {
+            throw new RuntimeException("Test fails!");
+        }
+    }
+
+    private static void createUI() {
+
+        final JFrame mainFrame = new JFrame("Motif L&F icons test");
+        GridBagLayout layout = new GridBagLayout();
+        JPanel mainControlPanel = new JPanel(layout);
+        JPanel resultButtonPanel = new JPanel(layout);
+
+        GridBagConstraints gbc = new GridBagConstraints();
+
+
+        JPanel testPanel = createJPanel();
+
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+        mainControlPanel.add(testPanel, gbc);
+
+        JTextArea instructionTextArea = new JTextArea();
+        instructionTextArea.setText(INSTRUCTIONS);
+        instructionTextArea.setEditable(false);
+        instructionTextArea.setBackground(Color.white);
+
+        gbc.gridx = 0;
+        gbc.gridy = 1;
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+        mainControlPanel.add(instructionTextArea, gbc);
+
+        JButton passButton = new JButton("Pass");
+        passButton.setActionCommand("Pass");
+        passButton.addActionListener((ActionEvent e) -> {
+            testResult = true;
+            mainFrame.dispose();
+            countDownLatch.countDown();
+
+        });
+
+        JButton failButton = new JButton("Fail");
+        failButton.setActionCommand("Fail");
+        failButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                mainFrame.dispose();
+                countDownLatch.countDown();
+            }
+        });
+
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        resultButtonPanel.add(passButton, gbc);
+
+        gbc.gridx = 1;
+        gbc.gridy = 0;
+        resultButtonPanel.add(failButton, gbc);
+
+        gbc.gridx = 0;
+        gbc.gridy = 2;
+        mainControlPanel.add(resultButtonPanel, gbc);
+
+        mainFrame.add(mainControlPanel);
+        mainFrame.pack();
+
+        mainFrame.addWindowListener(new WindowAdapter() {
+
+            @Override
+            public void windowClosing(WindowEvent e) {
+                mainFrame.dispose();
+                countDownLatch.countDown();
+            }
+        });
+        mainFrame.setVisible(true);
+    }
+
+    private static JPanel createJPanel() {
+        JPanel panel = new JPanel();
+        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+
+        JPanel iconPanel = new JPanel(new FlowLayout());
+        JRadioButton radioButton = new JRadioButton();
+        radioButton.setSelected(false);
+        iconPanel.add(radioButton);
+        radioButton = new JRadioButton();
+        radioButton.setSelected(true);
+        iconPanel.add(radioButton);
+        panel.add(iconPanel);
+
+        iconPanel = new JPanel(new FlowLayout());
+        JCheckBox checkBox = new JCheckBox();
+        checkBox.setSelected(false);
+        iconPanel.add(checkBox);
+        checkBox = new JCheckBox();
+        checkBox.setSelected(true);
+        iconPanel.add(checkBox);
+        panel.add(iconPanel);
+
+        iconPanel = new JPanel(new FlowLayout());
+        JComboBox<String> comboBox = new JComboBox(new String[]{"111", "222"});
+        iconPanel.add(comboBox);
+        panel.add(iconPanel);
+
+        iconPanel = new JPanel(new FlowLayout());
+        JTextArea textArea = new JTextArea(3, 7);
+        textArea.setText("AAA");
+        JScrollPane scrollPane = new JScrollPane(textArea);
+        scrollPane.setHorizontalScrollBarPolicy(
+                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
+        scrollPane.setVerticalScrollBarPolicy(
+                ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
+        iconPanel.add(scrollPane);
+        panel.add(iconPanel);
+
+        return panel;
+    }
+}