--- old/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java 2016-03-07 16:28:42.000000000 +0100 +++ new/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java 2016-03-07 16:28:42.000000000 +0100 @@ -928,7 +928,7 @@ // Return the bits from an HICON. This has a side effect of setting // the imageHash variable for efficient caching / comparing. - private static native int[] getIconBits(long hIcon, int iconSize); + private static native int[] getIconBits(long hIcon); // Dispose the HICON private static native void disposeIcon(long hIcon); @@ -943,13 +943,14 @@ return pIShellIcon; } - private static Image makeIcon(long hIcon, boolean getLargeIcon) { + private static Image makeIcon(long hIcon) { if (hIcon != 0L && hIcon != -1L) { // Get the bits. This has the side effect of setting the imageHash value for this object. - int size = getLargeIcon ? 32 : 16; - int[] iconBits = getIconBits(hIcon, size); + final int[] iconBits = getIconBits(hIcon); + // icons are always square + final int size = (int)Math.sqrt(iconBits.length); if (iconBits != null) { - BufferedImage img = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); + final BufferedImage img = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); img.setRGB(0, 0, size, size, iconBits, 0, size); return img; } @@ -986,7 +987,7 @@ newIcon = (Image) imageCache.get(Integer.valueOf(index)); if (newIcon == null) { long hIcon = getIcon(getAbsolutePath(), getLargeIcon); - newIcon = makeIcon(hIcon, getLargeIcon); + newIcon = makeIcon(hIcon); disposeIcon(hIcon); if (newIcon != null) { imageCache.put(Integer.valueOf(index), newIcon); @@ -999,7 +1000,7 @@ // These are only cached per object long hIcon = extractIcon(getParentIShellFolder(), getRelativePIDL(), getLargeIcon); - newIcon = makeIcon(hIcon, getLargeIcon); + newIcon = makeIcon(hIcon); disposeIcon(hIcon); } @@ -1023,7 +1024,7 @@ */ static Image getSystemIcon(SystemIcon iconType) { long hIcon = getSystemIcon(iconType.getIconID()); - Image icon = makeIcon(hIcon, true); + Image icon = makeIcon(hIcon); disposeIcon(hIcon); return icon; } @@ -1044,7 +1045,7 @@ long hIcon = getIconResource("shell32.dll", iconID, size, size, useVGAColors); if (hIcon != 0) { - Image icon = makeIcon(hIcon, getLargeIcon); + Image icon = makeIcon(hIcon); disposeIcon(hIcon); return icon; } --- old/src/windows/native/sun/windows/ShellFolder2.cpp 2016-03-07 16:28:42.000000000 +0100 +++ new/src/windows/native/sun/windows/ShellFolder2.cpp 2016-03-07 16:28:42.000000000 +0100 @@ -912,19 +912,43 @@ /* * Class: sun_awt_shell_Win32ShellFolder2 * Method: getIconBits - * Signature: (JI)[I + * Signature: (J)[I */ JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconBits - (JNIEnv* env, jclass cls, jlong hicon, jint iconSize) + (JNIEnv* env, jclass cls, jlong hicon) { + const int MAX_ICON_SIZE = 128; + int iconSize = 0; jintArray iconBits = NULL; + BITMAP bmp; + memset(&bmp, 0, sizeof(BITMAP)); + // Get the icon info ICONINFO iconInfo; if (fn_GetIconInfo((HICON)hicon, &iconInfo)) { // Get the screen DC HDC dc = GetDC(NULL); if (dc != NULL) { + // find out the icon size in order to deal with different sizes + // delivered depending on HiDPI mode or SD DPI mode. + if (iconInfo.hbmColor) { + const int nWrittenBytes = GetObject(iconInfo.hbmColor, sizeof(bmp), &bmp); + if(nWrittenBytes > 0) { + iconSize = bmp.bmWidth; + } + } else if (iconInfo.hbmMask) { + // Icon has no color plane, image data stored in mask + const int nWrittenBytes = GetObject(iconInfo.hbmMask, sizeof(bmp), &bmp); + if (nWrittenBytes > 0) { + iconSize = bmp.bmWidth; + } + } + // limit iconSize to MAX_ICON_SIZE, so that the colorBits and maskBits + // arrays are big enough. + // (logic: rather show bad icons than overrun the array size) + iconSize = iconSize > MAX_ICON_SIZE ? MAX_ICON_SIZE : iconSize; + // Set up BITMAPINFO BITMAPINFO bmi; memset(&bmi, 0, sizeof(BITMAPINFO)); @@ -936,7 +960,7 @@ bmi.bmiHeader.biCompression = BI_RGB; // Extract the color bitmap int nBits = iconSize * iconSize; - long colorBits[1024]; + long colorBits[MAX_ICON_SIZE * MAX_ICON_SIZE]; GetDIBits(dc, iconInfo.hbmColor, 0, iconSize, colorBits, &bmi, DIB_RGB_COLORS); // XP supports alpha in some icons, and depending on device. // This should take precedence over the icon mask bits. @@ -951,7 +975,7 @@ } if (!hasAlpha) { // Extract the mask bitmap - long maskBits[1024]; + long maskBits[MAX_ICON_SIZE * MAX_ICON_SIZE]; GetDIBits(dc, iconInfo.hbmMask, 0, iconSize, maskBits, &bmi, DIB_RGB_COLORS); // Copy the mask alphas into the color bits for (int i = 0; i < nBits; i++) { @@ -965,9 +989,9 @@ // Create java array iconBits = env->NewIntArray(nBits); if (!(env->ExceptionCheck())) { - // Copy values to java array - env->SetIntArrayRegion(iconBits, 0, nBits, colorBits); - } + // Copy values to java array + env->SetIntArrayRegion(iconBits, 0, nBits, colorBits); + } } // Fix 4745575 GDI Resource Leak // MSDN @@ -1004,7 +1028,7 @@ HICON hIcon = ImageList_GetIcon(hImageList, iconIndex, ILD_TRANSPARENT); if (hIcon != NULL) { - result = Java_sun_awt_shell_Win32ShellFolder2_getIconBits(env, cls, ptr_to_jlong(hIcon), 16); + result = Java_sun_awt_shell_Win32ShellFolder2_getIconBits(env, cls, ptr_to_jlong(hIcon)); DestroyIcon(hIcon); } --- /dev/null 2016-03-07 16:28:43.000000000 +0100 +++ new/test/sun/awt/shell/BadHiDPIIcon.java 2016-03-07 16:28:43.000000000 +0100 @@ -0,0 +1,50 @@ +/* + * 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 + * @bug 8151385 + * @summary JOptionPane icons are cropped on Windows 10 with HiDPI display + * @author Hendrik Schreiber + * @requires os.family == "windows" + * @run main BadHiDPIIcon + */ + +import java.awt.image.BufferedImage; +import sun.awt.shell.ShellFolder; + +public class BadHiDPIIcon { + + public static void main(String[] args) { + // the error icon is round and in all four corner transparent + // we check that all corners are identical + final BufferedImage image = (BufferedImage)ShellFolder.get("optionPaneIcon Error"); + final int upperLeft = image.getRGB(0, 0); + final int upperRight = image.getRGB(image.getWidth()-1, 0); + final int lowerLeft = image.getRGB(0, image.getHeight()-1); + final int lowerRight = image.getRGB(image.getWidth()-1, image.getHeight()-1); + if (upperLeft != upperRight || upperLeft != lowerLeft || upperLeft != lowerRight) { + throw new RuntimeException("optionPaneIcon Error is not a round icon with transparent background."); + } + } +}