8149371: multi-res. image: -Dsun.java2d.uiScale does not work for Window icons (some ambiguity for Window.setIconImages()?)
authorrchamyal
Mon, 26 Sep 2016 12:33:40 +0530
changeset 41395 2a6f7eb1dc23
parent 41394 da0318151636
child 41396 d72f3a09b3ae
8149371: multi-res. image: -Dsun.java2d.uiScale does not work for Window icons (some ambiguity for Window.setIconImages()?) Reviewed-by: serb, alexsch Contributed-by: rajeev.chamyal@oracle.com
jdk/src/java.desktop/share/classes/java/awt/Window.java
jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java
jdk/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java
jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp
jdk/test/java/awt/image/multiresolution/MultiResolutionIcon/MultiResIconTest.java
--- a/jdk/src/java.desktop/share/classes/java/awt/Window.java	Sun Sep 25 02:55:18 2016 +0300
+++ b/jdk/src/java.desktop/share/classes/java/awt/Window.java	Mon Sep 26 12:33:40 2016 +0530
@@ -678,6 +678,10 @@
      * Depending on the platform capabilities one or several images
      * of different dimensions will be used as the window's icon.
      * <p>
+     * The {@code icons} list can contain {@code MultiResolutionImage} images also.
+     * Suitable image depending on screen resolution is extracted from
+     * base {@code MultiResolutionImage} image and added to the icons list
+     * while base resolution image is removed from list.
      * The {@code icons} list is scanned for the images of most
      * appropriate dimensions from the beginning. If the list contains
      * several images of the same size, the first will be used.
--- a/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java	Sun Sep 25 02:55:18 2016 +0300
+++ b/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java	Mon Sep 26 12:33:40 2016 +0530
@@ -46,6 +46,7 @@
 import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
 import java.security.AccessController;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.Locale;
@@ -887,12 +888,21 @@
         if (width == 0 || height == 0) {
             return null;
         }
+        java.util.List<Image> multiResAndnormalImages = new ArrayList<>(imageList.size());
+        for (Image image : imageList) {
+            if ((image instanceof MultiResolutionImage)) {
+                Image im = ((MultiResolutionImage) image).getResolutionVariant(width, height);
+                multiResAndnormalImages.add(im);
+            } else {
+                multiResAndnormalImages.add(image);
+            }
+        }
         Image bestImage = null;
         int bestWidth = 0;
         int bestHeight = 0;
         double bestSimilarity = 3; //Impossibly high value
         double bestScaleFactor = 0;
-        for (Iterator<Image> i = imageList.iterator();i.hasNext();) {
+        for (Iterator<Image> i = multiResAndnormalImages.iterator();i.hasNext();) {
             //Iterate imageList looking for best matching image.
             //'Similarity' measure is defined as good scale factor and small insets.
             //best possible similarity is 0 (no scale, no insets).
--- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java	Sun Sep 25 02:55:18 2016 +0300
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java	Mon Sep 26 12:33:40 2016 +0530
@@ -34,7 +34,7 @@
 import java.util.*;
 import java.util.List;
 import sun.util.logging.PlatformLogger;
-
+import java.awt.geom.AffineTransform;
 import sun.awt.*;
 
 import sun.java2d.pipe.Region;
@@ -391,6 +391,11 @@
             int h = getSysIconHeight();
             int smw = getSysSmIconWidth();
             int smh = getSysSmIconHeight();
+            AffineTransform tx = getGraphicsConfiguration().getDefaultTransform();
+            w = Region.clipScale(w, tx.getScaleX());
+            h = Region.clipScale(h, tx.getScaleY());
+            smw = Region.clipScale(smw, tx.getScaleX());
+            smh = Region.clipScale(smh, tx.getScaleY());
             DataBufferInt iconData = SunToolkit.getScaledIconData(imageList,
                                                                   w, h);
             DataBufferInt iconSmData = SunToolkit.getScaledIconData(imageList,
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp	Sun Sep 25 02:55:18 2016 +0300
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp	Mon Sep 26 12:33:40 2016 +0530
@@ -46,11 +46,16 @@
 #include "sun_awt_windows_WCanvasPeer.h"
 
 #include <windowsx.h>
-
+#include <math.h>
 #if !defined(__int3264)
 typedef __int32 LONG_PTR;
 #endif // __int3264
 
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#  define ROUND_TO_INT(num)    ((int) round(num))
+#else
+#  define ROUND_TO_INT(num)    ((int) floor((num) + 0.5))
+#endif
 // Used for Swing's Menu/Tooltip animation Support
 const int UNSPECIFIED = 0;
 const int TOOLTIP = 1;
@@ -3097,7 +3102,7 @@
 
     env->DeleteGlobalRef(self);
 }
-
+extern "C" int getSystemMetricValue(int msgType);
 extern "C" {
 
 /*
@@ -3407,7 +3412,7 @@
 {
     TRY;
 
-    return ::GetSystemMetrics(SM_CYICON);
+    return getSystemMetricValue(SM_CYICON);
 
     CATCH_BAD_ALLOC_RET(0);
 }
@@ -3422,7 +3427,7 @@
 {
     TRY;
 
-    return ::GetSystemMetrics(SM_CXICON);
+    return getSystemMetricValue(SM_CXICON);
 
     CATCH_BAD_ALLOC_RET(0);
 }
@@ -3437,7 +3442,7 @@
 {
     TRY;
 
-    return ::GetSystemMetrics(SM_CYSMICON);
+    return getSystemMetricValue(SM_CYSMICON);
 
     CATCH_BAD_ALLOC_RET(0);
 }
@@ -3452,11 +3457,44 @@
 {
     TRY;
 
-    return ::GetSystemMetrics(SM_CXSMICON);
+    return getSystemMetricValue(SM_CXSMICON);
 
     CATCH_BAD_ALLOC_RET(0);
 }
 
+int getSystemMetricValue(int msgType) {
+    int value = 1;
+    int logPixels = LOGPIXELSX;
+    switch (msgType) {
+        case SM_CXICON:
+            value = ::GetSystemMetrics(SM_CXICON);
+            break;
+        case SM_CYICON:
+            value = ::GetSystemMetrics(SM_CYICON);
+            logPixels = LOGPIXELSY;
+            break;
+        case SM_CXSMICON:
+            value = ::GetSystemMetrics(SM_CXSMICON);
+            break;
+        case SM_CYSMICON:
+            value = ::GetSystemMetrics(SM_CYSMICON);
+            logPixels = LOGPIXELSY;
+            break;
+    }
+    static int dpi = -1;
+    if (dpi == -1) {
+        HWND hWnd = ::GetDesktopWindow();
+        HDC hDC = ::GetDC(hWnd);
+        dpi = GetDeviceCaps(hDC, logPixels);
+        ::ReleaseDC(hWnd, hDC);
+    }
+    if(dpi != 0 && dpi != 96) {
+        float invScaleX = 96.0f / dpi;
+        value = (int) ROUND_TO_INT(value * invScaleX);
+    }
+    return value;
+}
+
 /*
  * Class:     sun_awt_windows_WWindowPeer
  * Method:    setIconImagesData
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/image/multiresolution/MultiResolutionIcon/MultiResIconTest.java	Mon Sep 26 12:33:40 2016 +0530
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @key headful
+ * @bug 8149371
+ * @summary multi-res. image: -Dsun.java2d.uiScale does not work for Window
+ * icons (some ambiguity for Window.setIconImages()?)
+ * @run main/othervm/manual -Dsun.java2d.uiScale=2 MultiResIconTest
+ */
+import java.awt.Color;
+import java.awt.Graphics;
+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.awt.image.BaseMultiResolutionImage;
+import java.awt.image.BufferedImage;
+import java.util.concurrent.CountDownLatch;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+public class MultiResIconTest {
+
+    private static GridBagLayout layout;
+    private static JPanel mainControlPanel;
+    private static JPanel resultButtonPanel;
+    private static JLabel instructionText;
+    private static JButton passButton;
+    private static JButton failButton;
+    private static JDialog f;
+    private static CountDownLatch latch;
+    private static TestFrame frame;
+
+    private static BufferedImage generateImage(int x, Color c) {
+
+        BufferedImage img = new BufferedImage(x, x, BufferedImage.TYPE_INT_RGB);
+        Graphics g = img.getGraphics();
+        g.setColor(c);
+        g.fillRect(0, 0, x, x);
+        g.setColor(Color.WHITE);
+        g.fillRect(x / 3, x / 3, x / 3, x / 3);
+        return img;
+    }
+
+    public MultiResIconTest() {
+        try {
+            latch = new CountDownLatch(1);
+            createUI();
+            latch.await();
+        } catch (Exception ex) {
+        }
+    }
+
+    private static void createUI() throws Exception {
+        SwingUtilities.invokeAndWait(() -> {
+            frame = new TestFrame();
+            f = new JDialog(frame);
+            f.setTitle("Instruction Dialog");
+            layout = new GridBagLayout();
+            mainControlPanel = new JPanel(layout);
+            resultButtonPanel = new JPanel(layout);
+            GridBagConstraints gbc = new GridBagConstraints();
+            String instructions
+                    = "<html>    INSTRUCTIONS:<br><br>"
+                    + "1) Test frame title icon and frame color should be green."
+                    + "<br>"
+                    + "2) Test frame task bar icon should be blue<br>"
+                    + "3) If color are same as mentioned in 1 and 2 press pass<br>"
+                    + "   else press fail.<br><br></html>";
+
+            instructionText = new JLabel();
+            instructionText.setText(instructions);
+
+            gbc.gridx = 0;
+            gbc.gridy = 0;
+            gbc.fill = GridBagConstraints.HORIZONTAL;
+            mainControlPanel.add(instructionText, gbc);
+            passButton = new JButton("Pass");
+            passButton.setActionCommand("Pass");
+            passButton.addActionListener((ActionEvent e) -> {
+                latch.countDown();
+                f.dispose();
+                frame.dispose();
+            });
+            failButton = new JButton("Fail");
+            failButton.setActionCommand("Fail");
+            failButton.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    latch.countDown();
+                    f.dispose();
+                    frame.dispose();
+                    throw new RuntimeException("Test Failed");
+                }
+            });
+            gbc.gridx = 1;
+            gbc.gridy = 0;
+            resultButtonPanel.add(passButton, gbc);
+            gbc.gridx = 2;
+            gbc.gridy = 0;
+            resultButtonPanel.add(failButton, gbc);
+
+            gbc.gridx = 0;
+            gbc.gridy = 1;
+            mainControlPanel.add(resultButtonPanel, gbc);
+
+            f.add(mainControlPanel);
+            f.setSize(400, 200);
+            f.setLocationRelativeTo(null);
+            f.setVisible(true);
+
+            f.addWindowListener(new WindowAdapter() {
+                @Override
+                public void windowClosing(WindowEvent e) {
+                    latch.countDown();
+                    f.dispose();
+                    frame.dispose();
+                }
+            });
+        });
+    }
+
+    private static class TestFrame extends JFrame {
+
+        private static final int W = 200;
+
+        private static final BaseMultiResolutionImage IMG
+                = new BaseMultiResolutionImage(
+                        new BufferedImage[]{generateImage(W, Color.RED),
+                            generateImage(2 * W, Color.GREEN),
+                            generateImage(4 * W, Color.BLUE)});
+
+        private static final BaseMultiResolutionImage ICON
+                = new BaseMultiResolutionImage(
+                        new BufferedImage[]{generateImage(16, Color.RED),
+                            generateImage(32, Color.GREEN),
+                            generateImage(64, Color.BLUE),
+                            generateImage(128, Color.BLACK),
+                            generateImage(256, Color.GRAY)});
+
+        public TestFrame() {
+            createUI();
+        }
+
+        private void createUI() {
+            setTitle("Test Frame");
+            setIconImage(ICON);
+            addWindowListener(new WindowAdapter() {
+                @Override
+                public void windowClosing(WindowEvent e) {
+                    dispose();
+                }
+            });
+            setSize(W, W);
+            setLocation(50, 50);
+            setResizable(false);
+            setVisible(true);
+        }
+
+        @Override
+        public void paint(Graphics gr) {
+            gr.drawImage(IMG, 0, 0, this);
+        }
+    }
+
+    public static void main(String[] args) {
+        new MultiResIconTest();
+    }
+}
+