# HG changeset patch # User serb # Date 1424958099 -10800 # Node ID f16389ada5f36f1648ae26335ff8e22f1e3bf808 # Parent a7367abd4c4c92440bac79096f0868b0ef176e76 8073795: JMenuBar looks bad under retina Reviewed-by: alexsch, azvegint diff -r a7367abd4c4c -r f16389ada5f3 jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarBorder.java --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarBorder.java Wed Feb 25 13:45:09 2015 -0800 +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarBorder.java Thu Feb 26 16:41:39 2015 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -25,46 +25,33 @@ package com.apple.laf; -import java.awt.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; import javax.swing.border.Border; +import sun.swing.SwingUtilities2; + +/** + * The class represents the border of a {@code JMenuBar}. + */ public class AquaMenuBarBorder implements Border { - public AquaMenuBarBorder() { - super(); + + @Override + public void paintBorder(final Component c, final Graphics g, final int x, + final int y, final int width, final int height) { + g.setColor(Color.gray); + SwingUtilities2.drawHLine(g, x, x + width - 1, y + height - 1); } - /** - * Paints the border for the specified component with the specified - * position and size. - * @param c the component for which this border is being painted - * @param g the paint graphics - * @param x the x position of the painted border - * @param y the y position of the painted border - * @param width the width of the painted border - * @param height the height of the painted border - */ - public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height) { - // for now we don't paint a border. We let the button paint it since there - // needs to be a strict ordering for aqua components. - //paintButton(c, g, x, y, width, height); - g.setColor(Color.gray); - g.drawLine(x, y + height - 1, x + width, y + height - 1); - } - - /** - * Returns the insets of the border. - * @param c the component for which this border insets value applies - */ + @Override public Insets getBorderInsets(final Component c) { return new Insets(0, 0, 1, 0); } - /** - * Returns whether or not the border is opaque. If the border - * is opaque, it is responsible for filling in it's own - * background when painting. - */ + @Override public boolean isBorderOpaque() { return false; } diff -r a7367abd4c4c -r f16389ada5f3 jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicBorders.java --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicBorders.java Wed Feb 25 13:45:09 2015 -0800 +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicBorders.java Thu Feb 26 16:41:39 2015 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -37,6 +37,8 @@ import java.awt.Color; import java.awt.Graphics; +import sun.swing.SwingUtilities2; + /** * Factory object that can vend Borders appropriate for the basic L & F. * @author Georges Saab @@ -453,10 +455,10 @@ Color oldColor = g.getColor(); g.translate(x, y); g.setColor(shadow); - g.drawLine(0, height-2, width, height-2); + SwingUtilities2.drawHLine(g, 0, width - 1, height - 2); g.setColor(highlight); - g.drawLine(0, height-1, width, height-1); - g.translate(-x,-y); + SwingUtilities2.drawHLine(g, 0, width - 1, height - 1); + g.translate(-x, -y); g.setColor(oldColor); } diff -r a7367abd4c4c -r f16389ada5f3 jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalBorders.java --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalBorders.java Wed Feb 25 13:45:09 2015 -0800 +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalBorders.java Thu Feb 26 16:41:39 2015 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -40,6 +40,7 @@ import java.awt.Window; import sun.swing.StringUIClientPropertyKey; +import sun.swing.SwingUtilities2; /** @@ -559,25 +560,22 @@ protected static Insets borderInsets = new Insets( 1, 0, 1, 0 ); public void paintBorder( Component c, Graphics g, int x, int y, int w, int h ) { - g.translate( x, y ); + g.translate(x, y); if (MetalLookAndFeel.usingOcean()) { - // Only paint a border if we're not next to a horizontal - // toolbar - if ((c instanceof JMenuBar) && !MetalToolBarUI.doesMenuBarBorderToolBar((JMenuBar)c)) { + // Only paint a border if we're not next to a horizontal toolbar + if (c instanceof JMenuBar + && !MetalToolBarUI.doesMenuBarBorderToolBar((JMenuBar)c)) { g.setColor(MetalLookAndFeel.getControl()); - g.drawLine(0, h - 2, w, h - 2); + SwingUtilities2.drawHLine(g, 0, w - 1, h - 2); g.setColor(UIManager.getColor("MenuBar.borderColor")); - g.drawLine(0, h - 1, w, h - 1); + SwingUtilities2.drawHLine(g, 0, w - 1, h - 1); } + } else { + g.setColor(MetalLookAndFeel.getControlShadow()); + SwingUtilities2.drawHLine(g, 0, w - 1, h - 1); } - else { - g.setColor( MetalLookAndFeel.getControlShadow() ); - g.drawLine( 0, h-1, w, h-1 ); - } - - g.translate( -x, -y ); - + g.translate(-x, -y); } public Insets getBorderInsets(Component c, Insets newInsets) { diff -r a7367abd4c4c -r f16389ada5f3 jdk/test/javax/swing/JMenuBar/MisplacedBorder/MisplacedBorder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JMenuBar/MisplacedBorder/MisplacedBorder.java Thu Feb 26 16:41:39 2015 +0300 @@ -0,0 +1,135 @@ +/* + * 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.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE; +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/** + * @test + * @bug 8073795 + * @summary JMenuBar has incorrect border when the window is on retina display. + * @author Sergey Bylokhov + * @run main/othervm MisplacedBorder + * @run main/othervm -Dswing.metalTheme=steel MisplacedBorder + */ +public final class MisplacedBorder implements Runnable { + + public static final int W = 400; + public static final int H = 400; + + public static void main(final String[] args) throws Exception { + for (final UIManager.LookAndFeelInfo laf : getInstalledLookAndFeels()) { + SwingUtilities.invokeAndWait(() -> setLookAndFeel(laf)); + SwingUtilities.invokeAndWait(new MisplacedBorder()); + } + System.out.println("Test passed"); + } + + @Override + public void run() { + final JMenuBar menubar = new JMenuBar(); + menubar.add(new JMenu("")); + menubar.add(new JMenu("")); + final JFrame frame = new JFrame(); + frame.setUndecorated(true); + frame.setJMenuBar(menubar); + frame.setSize(W / 3, H / 3); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + + // draw menu bar using standard order. + final BufferedImage bi1 = step1(menubar); + + // draw menu border on top of the menu bar, nothing should be changed. + final BufferedImage bi2 = step2(menubar); + frame.dispose(); + + for (int x = 0; x < W; ++x) { + for (int y = 0; y < H; ++y) { + if (bi1.getRGB(x, y) != bi2.getRGB(x, y)) { + try { + ImageIO.write(bi1, "png", new File("image1.png")); + ImageIO.write(bi2, "png", new File("image2.png")); + } catch (IOException e) { + e.printStackTrace(); + } + throw new RuntimeException("Failed: wrong color"); + } + } + } + } + + /** + * Draws standard JMenuBar. + */ + private BufferedImage step1(final JMenuBar menubar) { + final BufferedImage bi1 = new BufferedImage(W, H, TYPE_INT_ARGB_PRE); + final Graphics2D g2d = bi1.createGraphics(); + g2d.scale(2, 2); + g2d.setColor(Color.RED); + g2d.fillRect(0, 0, W, H); + menubar.paintAll(g2d); + g2d.dispose(); + return bi1; + } + + /** + * Draws standard JMenuBar and border on top of it. + */ + private BufferedImage step2(final JMenuBar menubar) { + final BufferedImage bi2 = new BufferedImage(W, H, TYPE_INT_ARGB_PRE); + final Graphics2D g2d2 = bi2.createGraphics(); + g2d2.scale(2, 2); + g2d2.setColor(Color.RED); + g2d2.fillRect(0, 0, W, H); + menubar.paintAll(g2d2); + menubar.getBorder().paintBorder(menubar, g2d2, menubar.getX(), menubar + .getX(), menubar.getWidth(), menubar.getHeight()); + g2d2.dispose(); + return bi2; + } + + private static void setLookAndFeel(final UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + System.out.println("LookAndFeel: " + laf.getClassName()); + } catch (ClassNotFoundException | InstantiationException | + UnsupportedLookAndFeelException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file