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
--- 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;
+ }
+}