8151385: [hidpi] JOptionPane-Icons only partially visible when using Windows 10 L&F
Reviewed-by: serb, alexsch
This commit is contained in:
parent
0c483d8e20
commit
6d82cbce2a
@ -27,7 +27,9 @@ package sun.awt.shell;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.image.AbstractMultiResolutionImage;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
@ -982,11 +984,12 @@ final class Win32ShellFolder2 extends ShellFolder {
|
||||
|
||||
// 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);
|
||||
|
||||
static native int[] getStandardViewButton0(int iconIndex);
|
||||
// Get buttons from native toolbar implementation.
|
||||
static native int[] getStandardViewButton0(int iconIndex, boolean small);
|
||||
|
||||
// Should be called from the COM thread
|
||||
private long getIShellIcon() {
|
||||
@ -1000,12 +1003,17 @@ final class Win32ShellFolder2 extends ShellFolder {
|
||||
private static Image makeIcon(long hIcon, boolean getLargeIcon) {
|
||||
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);
|
||||
if (iconBits != null) {
|
||||
BufferedImage img = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
|
||||
// icons are always square
|
||||
final int size = (int) Math.sqrt(iconBits.length);
|
||||
final int baseSize = getLargeIcon ? 32 : 16;
|
||||
final BufferedImage img =
|
||||
new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
|
||||
img.setRGB(0, 0, size, size, iconBits, 0, size);
|
||||
return img;
|
||||
return size == baseSize
|
||||
? img
|
||||
: new MultiResolutionIconImage(baseSize, img);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -1298,4 +1306,39 @@ final class Win32ShellFolder2 extends ShellFolder {
|
||||
});
|
||||
}
|
||||
|
||||
static class MultiResolutionIconImage extends AbstractMultiResolutionImage {
|
||||
|
||||
final int baseSize;
|
||||
final Image resolutionVariant;
|
||||
|
||||
public MultiResolutionIconImage(int baseSize, Image resolutionVariant) {
|
||||
this.baseSize = baseSize;
|
||||
this.resolutionVariant = resolutionVariant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth(ImageObserver observer) {
|
||||
return baseSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight(ImageObserver observer) {
|
||||
return baseSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Image getBaseImage() {
|
||||
return resolutionVariant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getResolutionVariant(double width, double height) {
|
||||
return resolutionVariant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Image> getResolutionVariants() {
|
||||
return Arrays.asList(resolutionVariant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ package sun.awt.shell;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BaseMultiResolutionImage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
@ -116,13 +117,21 @@ final class Win32ShellFolderManager2 extends ShellFolderManager {
|
||||
return result;
|
||||
}
|
||||
|
||||
BufferedImage img = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
|
||||
final int[] iconBits = Win32ShellFolder2
|
||||
.getStandardViewButton0(iconIndex, true);
|
||||
if (iconBits != null) {
|
||||
// icons are always square
|
||||
final int size = (int) Math.sqrt(iconBits.length);
|
||||
final BufferedImage img =
|
||||
new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
|
||||
img.setRGB(0, 0, size, size, iconBits, 0, size);
|
||||
|
||||
img.setRGB(0, 0, 16, 16, Win32ShellFolder2.getStandardViewButton0(iconIndex), 0, 16);
|
||||
STANDARD_VIEW_BUTTONS[iconIndex] = (size == 16)
|
||||
? img
|
||||
: new MultiResolutionIconImage(16, img);
|
||||
}
|
||||
|
||||
STANDARD_VIEW_BUTTONS[iconIndex] = img;
|
||||
|
||||
return img;
|
||||
return STANDARD_VIEW_BUTTONS[iconIndex];
|
||||
}
|
||||
|
||||
// Special folders
|
||||
|
@ -930,19 +930,43 @@ JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_disposeIcon
|
||||
/*
|
||||
* 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));
|
||||
@ -954,7 +978,7 @@ JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconBits
|
||||
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.
|
||||
@ -969,7 +993,7 @@ JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconBits
|
||||
}
|
||||
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++) {
|
||||
@ -1001,10 +1025,10 @@ JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconBits
|
||||
/*
|
||||
* Class: sun_awt_shell_Win32ShellFolder2
|
||||
* Method: getStandardViewButton0
|
||||
* Signature: (I)[I
|
||||
* Signature: (IZ)[I
|
||||
*/
|
||||
JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getStandardViewButton0
|
||||
(JNIEnv* env, jclass cls, jint iconIndex)
|
||||
(JNIEnv* env, jclass cls, jint iconIndex, jboolean smallIcon)
|
||||
{
|
||||
jintArray result = NULL;
|
||||
|
||||
@ -1014,7 +1038,8 @@ JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getStandardView
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
if (hWndToolbar != NULL) {
|
||||
SendMessage(hWndToolbar, TB_LOADIMAGES, (WPARAM)IDB_VIEW_SMALL_COLOR, (LPARAM)HINST_COMMCTRL);
|
||||
WPARAM size = smallIcon ? (WPARAM)IDB_VIEW_SMALL_COLOR : (WPARAM)IDB_VIEW_LARGE_COLOR;
|
||||
SendMessage(hWndToolbar, TB_LOADIMAGES, size, (LPARAM)HINST_COMMCTRL);
|
||||
|
||||
HIMAGELIST hImageList = (HIMAGELIST) SendMessage(hWndToolbar, TB_GETIMAGELIST, 0, 0);
|
||||
|
||||
@ -1022,7 +1047,7 @@ JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getStandardView
|
||||
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);
|
||||
}
|
||||
|
61
jdk/test/sun/awt/shell/BadHiDPIIcon.java
Normal file
61
jdk/test/sun/awt/shell/BadHiDPIIcon.java
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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"
|
||||
* @modules java.desktop/sun.awt.shell
|
||||
* @run main BadHiDPIIcon
|
||||
*/
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.MultiResolutionImage;
|
||||
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
|
||||
Image icon = (Image) ShellFolder.get("optionPaneIcon Error");
|
||||
final BufferedImage image = getBufferedImage(icon);
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
private static BufferedImage getBufferedImage(Image image) {
|
||||
if (image instanceof MultiResolutionImage) {
|
||||
MultiResolutionImage mrImage = (MultiResolutionImage) image;
|
||||
return (BufferedImage) mrImage.getResolutionVariant(32, 32);
|
||||
}
|
||||
return (BufferedImage) image;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user