--- old/src/java.desktop/share/classes/sun/awt/SunToolkit.java 2016-09-02 16:54:27.579275999 +0530 +++ new/src/java.desktop/share/classes/sun/awt/SunToolkit.java 2016-09-02 16:54:27.195084002 +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; @@ -55,7 +56,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; - +import java.util.LinkedList; import sun.awt.im.InputContext; import sun.awt.image.ByteArrayImageSource; import sun.awt.image.FileImageSource; @@ -907,12 +908,29 @@ if (width == 0 || height == 0) { return null; } + java.util.List multiResolutionList = new LinkedList<>(); + java.util.List imagesToRemove = new ArrayList<>(); + for (Image image : imageList) { + if (image instanceof MultiResolutionImage) { + imagesToRemove.add(image); + Image im = ((MultiResolutionImage) image).getResolutionVariant(width, height); + multiResolutionList.add(im); + } + } + multiResolutionList.addAll(imageList); + multiResolutionList.removeAll(imagesToRemove); + Collections.sort(multiResolutionList, (Image m1, Image m2) -> { + return m1.getWidth(null) < m2.getWidth(null) && + m1.getHeight(null) < m2.getHeight(null) ? -1 : + m1.getHeight(null) == m2.getHeight(null) && + m1.getWidth(null) == m2.getWidth(null) ? 0 : 1; + }); Image bestImage = null; int bestWidth = 0; int bestHeight = 0; double bestSimilarity = 3; //Impossibly high value double bestScaleFactor = 0; - for (Iterator i = imageList.iterator();i.hasNext();) { + for (Iterator i = multiResolutionList.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). --- old/src/java.desktop/share/classes/java/awt/Window.java 2016-09-02 16:54:29.176073999 +0530 +++ new/src/java.desktop/share/classes/java/awt/Window.java 2016-09-02 16:54:28.535754000 +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. *

+ * The {@code icons} list can contain MultiResolutionImage images also. + * Suitable image depending on screen resolution is extracted from + * base 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. --- old/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java 2016-09-02 16:54:30.240606000 +0530 +++ new/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java 2016-09-02 16:54:29.816394000 +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, --- old/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp 2016-09-02 16:54:31.613292000 +0530 +++ new/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp 2016-09-02 16:54:30.980976000 +0530 @@ -46,11 +46,16 @@ #include "sun_awt_windows_WCanvasPeer.h" #include - +#include #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,41 @@ { 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; + } + HWND hWnd = ::GetDesktopWindow(); + HDC hDC = ::GetDC(hWnd); + int dpi = GetDeviceCaps(hDC, logPixels); + if (dpi != 0 && dpi != 96) { + float invScaleX = 96.0f / dpi; + value = (int) ROUND_TO_INT(value * invScaleX); + } + ::ReleaseDC(hWnd, hDC); + return value; +} + /* * Class: sun_awt_windows_WWindowPeer * Method: setIconImagesData --- /dev/null 2016-09-02 16:25:18.795428000 +0530 +++ new/test/java/awt/image/multiresolution/MultiResolutionIcon/MultiResIconTest.java 2016-09-02 16:54:32.521746000 +0530 @@ -0,0 +1,203 @@ +/* + * 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 MultiResIconTest -Dsun.java2d.uiScale=2 + */ +import java.awt.Color; +import java.awt.EventQueue; +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.lang.reflect.InvocationTargetException; +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(); + frame = new TestFrame(); + } catch (Exception ex) { + } + } + + private static void createUI() throws Exception { + SwingUtilities.invokeAndWait(() -> { + f = new JDialog(); + f.setTitle("Instruction Dialog"); + layout = new GridBagLayout(); + mainControlPanel = new JPanel(layout); + resultButtonPanel = new JPanel(layout); + GridBagConstraints gbc = new GridBagConstraints(); + String instructions + = " INSTRUCTIONS:

" + + "1) Test frame title icon and frame color should be green." + + "
" + + "2) Test frame task bar icon should be blue
" + + "3) If color are same as mentioned in 1 and 2 press pass
" + + " else press fail.

"; + + 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() { + try { + EventQueue.invokeAndWait(this::CreateUI); + } catch (InterruptedException ex) { + } catch (InvocationTargetException ex) { + } + } + + 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(); + } +} +