author | alexsch |
Fri, 23 Sep 2016 09:14:29 +0300 | |
changeset 41392 | ce5748c8192a |
parent 41391 | fdd0ab85d1c1 |
child 41393 | ebc8d972cd3f |
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java Tue Sep 20 21:26:33 2016 +0300 +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java Fri Sep 23 09:14:29 2016 +0300 @@ -36,6 +36,7 @@ import static com.sun.java.swing.plaf.windows.XPStyle.Skin; import sun.swing.MenuItemCheckIconFactory; +import sun.swing.SwingUtilities2; /** * Factory object that can vend Icons appropriate for the Windows {@literal L & F}. @@ -400,15 +401,24 @@ // paint check if (model.isSelected()) { - g.drawLine(x+9, y+3, x+9, y+3); - g.drawLine(x+8, y+4, x+9, y+4); - g.drawLine(x+7, y+5, x+9, y+5); - g.drawLine(x+6, y+6, x+8, y+6); - g.drawLine(x+3, y+7, x+7, y+7); - g.drawLine(x+4, y+8, x+6, y+8); - g.drawLine(x+5, y+9, x+5, y+9); - g.drawLine(x+3, y+5, x+3, y+5); - g.drawLine(x+3, y+6, x+4, y+6); + if (SwingUtilities2.isScaledGraphics(g)) { + int[] xPoints = {3, 5, 9, 9, 5, 3}; + int[] yPoints = {5, 7, 3, 5, 9, 7}; + g.translate(x, y); + g.fillPolygon(xPoints, yPoints, 6); + g.drawPolygon(xPoints, yPoints, 6); + g.translate(-x, -y); + } else { + g.drawLine(x + 9, y + 3, x + 9, y + 3); + g.drawLine(x + 8, y + 4, x + 9, y + 4); + g.drawLine(x + 7, y + 5, x + 9, y + 5); + g.drawLine(x + 6, y + 6, x + 8, y + 6); + g.drawLine(x + 3, y + 7, x + 7, y + 7); + g.drawLine(x + 4, y + 8, x + 6, y + 8); + g.drawLine(x + 5, y + 9, x + 5, y + 9); + g.drawLine(x + 3, y + 5, x + 3, y + 5); + g.drawLine(x + 3, y + 6, x + 4, y + 6); + } } } } @@ -475,54 +485,94 @@ g.fillRect(x+2, y+2, 8, 8); + boolean isScaledGraphics = SwingUtilities2.isScaledGraphics(g); + + if (isScaledGraphics) { + + Graphics2D g2d = (Graphics2D) g; + Stroke oldStroke = g2d.getStroke(); + g2d.setStroke(new BasicStroke(1.03f, BasicStroke.CAP_ROUND, + BasicStroke.JOIN_ROUND)); + Object aaHint = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + // outter left arc - g.setColor(UIManager.getColor("RadioButton.shadow")); - g.drawLine(x+4, y+0, x+7, y+0); - g.drawLine(x+2, y+1, x+3, y+1); - g.drawLine(x+8, y+1, x+9, y+1); - g.drawLine(x+1, y+2, x+1, y+3); - g.drawLine(x+0, y+4, x+0, y+7); - g.drawLine(x+1, y+8, x+1, y+9); + g.setColor(UIManager.getColor("RadioButton.shadow")); + g.drawArc(x, y, 11, 11, 45, 180); + // outter right arc + g.setColor(UIManager.getColor("RadioButton.highlight")); + g.drawArc(x, y, 11, 11, 45, -180); + // inner left arc + g.setColor(UIManager.getColor("RadioButton.darkShadow")); + g.drawArc(x + 1, y + 1, 9, 9, 45, 180); + // inner right arc + g.setColor(UIManager.getColor("RadioButton.light")); + g.drawArc(x + 1, y + 1, 9, 9, 45, -180); + + g2d.setStroke(oldStroke); - // outter right arc - g.setColor(UIManager.getColor("RadioButton.highlight")); - g.drawLine(x+2, y+10, x+3, y+10); - g.drawLine(x+4, y+11, x+7, y+11); - g.drawLine(x+8, y+10, x+9, y+10); - g.drawLine(x+10, y+9, x+10, y+8); - g.drawLine(x+11, y+7, x+11, y+4); - g.drawLine(x+10, y+3, x+10, y+2); + if (model.isSelected()) { + if (model.isEnabled()) { + g.setColor(UIManager.getColor("RadioButton.foreground")); + } else { + g.setColor(UIManager.getColor("RadioButton.shadow")); + } + g.fillOval(x + 3, y + 3, 5, 5); + } + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, aaHint); + + } else { + + // outter left arc + g.setColor(UIManager.getColor("RadioButton.shadow")); + g.drawLine(x+4, y+0, x+7, y+0); + g.drawLine(x+2, y+1, x+3, y+1); + g.drawLine(x+8, y+1, x+9, y+1); + g.drawLine(x+1, y+2, x+1, y+3); + g.drawLine(x+0, y+4, x+0, y+7); + g.drawLine(x+1, y+8, x+1, y+9); + + // outter right arc + g.setColor(UIManager.getColor("RadioButton.highlight")); + g.drawLine(x+2, y+10, x+3, y+10); + g.drawLine(x+4, y+11, x+7, y+11); + g.drawLine(x+8, y+10, x+9, y+10); + g.drawLine(x+10, y+9, x+10, y+8); + g.drawLine(x+11, y+7, x+11, y+4); + g.drawLine(x+10, y+3, x+10, y+2); - // inner left arc - g.setColor(UIManager.getColor("RadioButton.darkShadow")); - g.drawLine(x+4, y+1, x+7, y+1); - g.drawLine(x+2, y+2, x+3, y+2); - g.drawLine(x+8, y+2, x+9, y+2); - g.drawLine(x+2, y+3, x+2, y+3); - g.drawLine(x+1, y+4, x+1, y+7); - g.drawLine(x+2, y+8, x+2, y+8); + // inner left arc + g.setColor(UIManager.getColor("RadioButton.darkShadow")); + g.drawLine(x+4, y+1, x+7, y+1); + g.drawLine(x+2, y+2, x+3, y+2); + g.drawLine(x+8, y+2, x+9, y+2); + g.drawLine(x+2, y+3, x+2, y+3); + g.drawLine(x+1, y+4, x+1, y+7); + g.drawLine(x+2, y+8, x+2, y+8); - // inner right arc - g.setColor(UIManager.getColor("RadioButton.light")); - g.drawLine(x+2, y+9, x+3, y+9); - g.drawLine(x+4, y+10, x+7, y+10); - g.drawLine(x+8, y+9, x+9, y+9); - g.drawLine(x+9, y+8, x+9, y+8); - g.drawLine(x+10, y+7, x+10, y+4); - g.drawLine(x+9, y+3, x+9, y+3); + // inner right arc + g.setColor(UIManager.getColor("RadioButton.light")); + g.drawLine(x+2, y+9, x+3, y+9); + g.drawLine(x+4, y+10, x+7, y+10); + g.drawLine(x+8, y+9, x+9, y+9); + g.drawLine(x+9, y+8, x+9, y+8); + g.drawLine(x+10, y+7, x+10, y+4); + g.drawLine(x+9, y+3, x+9, y+3); - // indicate whether selected or not - if (model.isSelected()) { - if (model.isEnabled()) { - g.setColor(UIManager.getColor("RadioButton.foreground")); - } else { - g.setColor(UIManager.getColor("RadioButton.shadow")); + // indicate whether selected or not + if (model.isSelected()) { + if (model.isEnabled()) { + g.setColor(UIManager.getColor("RadioButton.foreground")); + } else { + g.setColor(UIManager.getColor("RadioButton.shadow")); + } + g.fillRect(x+4, y+5, 4, 2); + g.fillRect(x+5, y+4, 2, 4); } - g.fillRect(x+4, y+5, 4, 2); - g.fillRect(x+5, y+4, 2, 4); } } }
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicArrowButton.java Tue Sep 20 21:26:33 2016 +0300 +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicArrowButton.java Fri Sep 23 09:14:29 2016 +0300 @@ -27,9 +27,13 @@ import java.awt.Dimension; import java.awt.Graphics; import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.geom.Path2D; import javax.swing.*; import javax.swing.plaf.UIResource; +import sun.swing.SwingUtilities2; /** * JButton object that draws a scaled Arrow in one of the cardinal directions. @@ -236,6 +240,16 @@ */ public void paintTriangle(Graphics g, int x, int y, int size, int direction, boolean isEnabled) { + if (SwingUtilities2.isScaledGraphics(g)) { + paintScaledTriangle(g, x, y, size, direction, isEnabled); + } else { + paintUnscaledTriangle(g, x, y, size, direction, isEnabled); + } + } + + private void paintUnscaledTriangle(Graphics g, int x, int y, int size, + int direction, boolean isEnabled) + { Color oldColor = g.getColor(); int mid, i, j; @@ -309,4 +323,32 @@ g.setColor(oldColor); } + private void paintScaledTriangle(Graphics g, double x, double y, double size, + int direction, boolean isEnabled) { + size = Math.max(size, 2); + Path2D.Double path = new Path2D.Double(); + path.moveTo(-size, size / 2); + path.lineTo(size, size / 2); + path.lineTo(0, -size / 2); + path.closePath(); + AffineTransform affineTransform = new AffineTransform(); + affineTransform.rotate(Math.PI * (direction - 1) / 4); + path.transform(affineTransform); + + Graphics2D g2d = (Graphics2D) g; + double tx = x + size / 2; + double ty = y + size / 2; + g2d.translate(tx, ty); + Color oldColor = g.getColor(); + if (!isEnabled) { + g2d.translate(1, 0); + g2d.setColor(highlight); + g2d.fill(path); + g2d.translate(-1, 0); + } + g2d.setColor(isEnabled ? darkShadow : shadow); + g2d.fill(path); + g2d.translate(-tx, -ty); + g2d.setColor(oldColor); + } }
--- a/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java Tue Sep 20 21:26:33 2016 +0300 +++ b/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java Fri Sep 23 09:14:29 2016 +0300 @@ -31,6 +31,8 @@ import java.awt.event.*; import java.awt.font.*; import java.awt.geom.AffineTransform; +import static java.awt.geom.AffineTransform.TYPE_FLIP; +import static java.awt.geom.AffineTransform.TYPE_TRANSLATION; import java.awt.print.PrinterGraphics; import java.text.BreakIterator; import java.text.CharacterIterator; @@ -2036,6 +2038,14 @@ return path; } + public static boolean isScaledGraphics(Graphics g) { + if (g instanceof Graphics2D) { + AffineTransform tx = ((Graphics2D) g).getTransform(); + return (tx.getType() & ~(TYPE_TRANSLATION | TYPE_FLIP)) != 0; + } + return false; + } + /** * Used to listen to "blit" repaints in RepaintManager. */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/plaf/windows/8165594/WindowsClassicHiDPIIconsTest.java Fri Sep 23 09:14:29 2016 +0300 @@ -0,0 +1,193 @@ +/* + * 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 8165594 + * @key headful + * @requires (os.family == "windows") + * @summary Bad rendering of Swing UI controls with Windows Classic L&F on HiDPI + * display + * @run main/manual/othervm -Dsun.java2d.uiScale=2 + * -Dswing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel + * WindowsClassicHiDPIIconsTest + */ + +public class WindowsClassicHiDPIIconsTest { + + 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(WindowsClassicHiDPIIconsTest::createUI); + countDownLatch.await(15, TimeUnit.MINUTES); + + if (!testResult) { + throw new RuntimeException("Test fails!"); + } + } + + private static void createUI() { + + final JFrame mainFrame = new JFrame("Windows Classic 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; + } +}