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
--- 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();
+ }
+}
+