8163193: Metal L&F gradient is lighter on HiDPI display after the fix JDK-8143064
authoralexsch
Wed, 31 Aug 2016 11:13:53 +0300
changeset 40986 6aac489a48d2
parent 40730 0d19d6d18c0b
child 40987 eb13c2ec3f9a
8163193: Metal L&F gradient is lighter on HiDPI display after the fix JDK-8143064 Reviewed-by: serb, ssadetsky
jdk/src/java.desktop/share/classes/sun/swing/CachedPainter.java
jdk/test/javax/swing/plaf/metal/MetalGradient/8163193/ButtonGradientTest.java
--- 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;
+    }
+}