8163193: Metal L&F gradient is lighter on HiDPI display after the fix JDK-8143064
Reviewed-by: serb, ssadetsky
--- a/jdk/src/java.desktop/share/classes/sun/swing/CachedPainter.java Tue Aug 30 08:45:21 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/swing/CachedPainter.java Wed Aug 31 11:13:53 2016 +0300
@@ -107,13 +107,16 @@
ImageCache cache = getCache(key);
Image image = cache.getImage(key, config, w, h, args);
int attempts = 0;
+ VolatileImage volatileImage = (image instanceof VolatileImage)
+ ? (VolatileImage) image
+ : null;
do {
boolean draw = false;
- if (image instanceof VolatileImage) {
+ if (volatileImage != null) {
// See if we need to recreate the image
- switch (((VolatileImage)image).validate(config)) {
+ switch (volatileImage.validate(config)) {
case VolatileImage.IMAGE_INCOMPATIBLE:
- ((VolatileImage)image).flush();
+ volatileImage.flush();
image = null;
break;
case VolatileImage.IMAGE_RESTORED:
@@ -126,11 +129,14 @@
image = createImage(c, w, h, config, args);
cache.setImage(key, config, w, h, args, image);
draw = true;
+ volatileImage = (image instanceof VolatileImage)
+ ? (VolatileImage) image
+ : null;
}
if (draw) {
// Render to the Image
Graphics2D g2 = (Graphics2D) image.getGraphics();
- if (w != baseWidth || h != baseHeight) {
+ if (volatileImage == null && (w != baseWidth || h != baseHeight)) {
g2.scale((double) w / baseWidth, (double) h / baseHeight);
}
paintToImage(c, image, g2, baseWidth, baseHeight, args);
@@ -140,8 +146,8 @@
// If we did this 3 times and the contents are still lost
// assume we're painting to a VolatileImage that is bogus and
// give up. Presumably we'll be called again to paint.
- } while ((image instanceof VolatileImage) &&
- ((VolatileImage)image).contentsLost() && ++attempts < 3);
+ } while ((volatileImage != null) &&
+ volatileImage.contentsLost() && ++attempts < 3);
return image;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/plaf/metal/MetalGradient/8163193/ButtonGradientTest.java Wed Aug 31 11:13:53 2016 +0300
@@ -0,0 +1,134 @@
+/*
+ * 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.BorderLayout;
+import java.awt.Color;
+import java.awt.GradientPaint;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.image.BufferedImage;
+import java.util.List;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.plaf.metal.MetalLookAndFeel;
+
+/*
+ * @test
+ * @bug 8163193
+ * @key headful
+ * @summary Metal L&F gradient is lighter on HiDPI display
+ * @run main/othervm -Dsun.java2d.uiScale=2 ButtonGradientTest
+ */
+public class ButtonGradientTest {
+
+ private static JFrame frame;
+ private static JButton button;
+
+ public static void main(String[] args) throws Exception {
+ try {
+ testGradient();
+ } finally {
+ SwingUtilities.invokeAndWait(() -> {
+ if (frame != null) {
+ frame.dispose();
+ }
+ });
+ }
+ }
+
+ private static void testGradient() throws Exception {
+ Robot robot = new Robot();
+ robot.setAutoDelay(50);
+
+ SwingUtilities.invokeAndWait(ButtonGradientTest::createAndShowGUI);
+ robot.waitForIdle();
+
+ Rectangle rect = getButtonBounds();
+ List<?> gradient = (List) UIManager.get("Button.gradient");
+ float ratio = ((Number) gradient.get(0)).floatValue();
+ Color c1 = (Color) gradient.get(2);
+ Color c2 = (Color) gradient.get(3);
+ int mid = (int) (ratio * rect.height);
+
+ Color gradientColor = getGradientColor(rect.width, mid, c1, c2);
+ int x = rect.x + rect.width / 2;
+ int y = rect.y + mid / 2;
+ Color buttonColor = robot.getPixelColor(x, y);
+
+ if (!similarColors(buttonColor, gradientColor)) {
+ throw new RuntimeException("Button gradient is changed!");
+ }
+ }
+
+ private static void createAndShowGUI() {
+
+ try {
+ UIManager.setLookAndFeel(new MetalLookAndFeel());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ frame = new JFrame();
+ frame.setSize(300, 300);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+ JPanel panel = new JPanel(new BorderLayout());
+ button = new JButton("");
+ panel.add(button);
+ frame.getContentPane().add(panel);
+ frame.setVisible(true);
+ }
+
+ private static Rectangle getButtonBounds() throws Exception {
+ Rectangle[] rectangles = new Rectangle[1];
+ SwingUtilities.invokeAndWait(() -> {
+ rectangles[0] = button.getBounds();
+ rectangles[0].setLocation(button.getLocationOnScreen());
+ });
+ return rectangles[0];
+ }
+
+ private static Color getGradientColor(int w, int h, Color c1, Color c2) {
+ GradientPaint gradient = new GradientPaint(0, 0, c1, 0, h, c2, true);
+ BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ Graphics2D g = img.createGraphics();
+ g.setPaint(gradient);
+ g.fillRect(0, 0, w, h);
+ g.dispose();
+ return new Color(img.getRGB(w / 2, h / 2));
+ }
+
+ private static boolean similarColors(Color c1, Color c2) {
+ return similar(c1.getRed(), c2.getRed())
+ && similar(c1.getGreen(), c2.getGreen())
+ && similar(c1.getBlue(), c2.getBlue());
+ }
+
+ private static boolean similar(int i1, int i2) {
+ return Math.abs(i2 - i1) < 7;
+ }
+}