From e6e654b90528054e74c3b753831618b51b60512e Mon Sep 17 00:00:00 2001 From: alexsch Date: Wed, 6 Aug 2014 15:30:04 +0400 Subject: [PATCH] 8040279: [macosx] Do not use the base image in the MultiResolutionBufferedImage Reviewed-by: serb, pchelko --- .../com/apple/laf/AquaImageFactory.java | 24 +--- .../classes/com/apple/laf/AquaPainter.java | 6 +- .../classes/com/apple/laf/AquaUtils.java | 6 +- .../classes/sun/lwawt/macosx/CImage.java | 36 +++--- .../image/AbstractMultiResolutionImage.java | 122 ++++++++++++++++++ ...e.java => MultiResolutionCachedImage.java} | 56 ++++---- .../swing/JMenuItem/8031573/bug8031573.java | 2 +- .../swing/JOptionPane/8024926/bug8024926.java | 2 +- 8 files changed, 176 insertions(+), 78 deletions(-) create mode 100644 src/share/classes/sun/awt/image/AbstractMultiResolutionImage.java rename src/share/classes/sun/awt/image/{MultiResolutionBufferedImage.java => MultiResolutionCachedImage.java} (80%) diff --git a/src/macosx/classes/com/apple/laf/AquaImageFactory.java b/src/macosx/classes/com/apple/laf/AquaImageFactory.java index 8fbc4c01a..d19486395 100644 --- a/src/macosx/classes/com/apple/laf/AquaImageFactory.java +++ b/src/macosx/classes/com/apple/laf/AquaImageFactory.java @@ -46,10 +46,8 @@ import com.apple.laf.AquaIcon.JRSUIControlSpec; import com.apple.laf.AquaIcon.SystemIcon; import com.apple.laf.AquaUtils.RecyclableObject; import com.apple.laf.AquaUtils.RecyclableSingleton; -import java.util.Arrays; -import java.util.List; -import sun.awt.image.MultiResolutionBufferedImage; import sun.awt.image.MultiResolutionImage; +import sun.awt.image.MultiResolutionCachedImage; public class AquaImageFactory { public static IconUIResource getConfirmImageIcon() { @@ -107,9 +105,9 @@ public class AquaImageFactory { private static final int kAlertIconSize = 64; static IconUIResource getAppIconCompositedOn(final Image background) { - if (background instanceof MultiResolutionBufferedImage) { + if (background instanceof MultiResolutionCachedImage) { int width = background.getWidth(null); - Image mrIconImage = ((MultiResolutionBufferedImage) background).map( + Image mrIconImage = ((MultiResolutionCachedImage) background).map( rv -> getAppIconImageCompositedOn(rv, rv.getWidth(null) / width)); return new IconUIResource(new ImageIcon(mrIconImage)); } @@ -287,21 +285,7 @@ public class AquaImageFactory { private static Image getNSIcon(String imageName) { Image icon = Toolkit.getDefaultToolkit() .getImage("NSImage://" + imageName); - - if (icon instanceof MultiResolutionImage) { - return icon; - } - - int w = icon.getWidth(null); - int h = icon.getHeight(null); - - Dimension[] sizes = new Dimension[]{ - new Dimension(w, h), new Dimension(2 * w, 2 * h) - }; - - return new MultiResolutionBufferedImage(icon, sizes, (width, height) -> - AquaUtils.getCImageCreator().createImageFromName( - imageName, width, height)); + return icon; } public static class NineSliceMetrics { diff --git a/src/macosx/classes/com/apple/laf/AquaPainter.java b/src/macosx/classes/com/apple/laf/AquaPainter.java index ee4fcba1a..a2ebaf1c9 100644 --- a/src/macosx/classes/com/apple/laf/AquaPainter.java +++ b/src/macosx/classes/com/apple/laf/AquaPainter.java @@ -174,11 +174,7 @@ abstract class AquaPainter { bounds, controlState); Image img = cache.getImage(key); if (img == null) { - - Image baseImage = createImage(imgX, imgY, imgW, imgH, bounds, - control, controlState); - - img = new MultiResolutionBufferedImage(baseImage, + img = new MultiResolutionCachedImage(imgW, imgH, (rvWidth, rvHeight) -> createImage(imgX, imgY, rvWidth, rvHeight, bounds, control, controlState)); diff --git a/src/macosx/classes/com/apple/laf/AquaUtils.java b/src/macosx/classes/com/apple/laf/AquaUtils.java index a20897f7b..078435b16 100644 --- a/src/macosx/classes/com/apple/laf/AquaUtils.java +++ b/src/macosx/classes/com/apple/laf/AquaUtils.java @@ -48,7 +48,7 @@ import sun.security.action.GetPropertyAction; import sun.swing.SwingUtilities2; import com.apple.laf.AquaImageFactory.SlicedImageControl; -import sun.awt.image.MultiResolutionBufferedImage; +import sun.awt.image.MultiResolutionCachedImage; final class AquaUtils { @@ -124,8 +124,8 @@ final class AquaUtils { static Image generateLightenedImage(final Image image, final int percent) { final GrayFilter filter = new GrayFilter(true, percent); - return (image instanceof MultiResolutionBufferedImage) - ? ((MultiResolutionBufferedImage) image).map( + return (image instanceof MultiResolutionCachedImage) + ? ((MultiResolutionCachedImage) image).map( rv -> generateLightenedImage(rv, filter)) : generateLightenedImage(image, filter); } diff --git a/src/macosx/classes/sun/lwawt/macosx/CImage.java b/src/macosx/classes/sun/lwawt/macosx/CImage.java index 7b0c826e4..0cbd570ac 100644 --- a/src/macosx/classes/sun/lwawt/macosx/CImage.java +++ b/src/macosx/classes/sun/lwawt/macosx/CImage.java @@ -32,7 +32,7 @@ import java.awt.image.*; import java.util.Arrays; import java.util.List; import sun.awt.image.MultiResolutionImage; -import sun.awt.image.MultiResolutionBufferedImage; +import sun.awt.image.MultiResolutionCachedImage; import sun.awt.image.SunWritableRaster; @@ -60,41 +60,41 @@ public class CImage extends CFRetainedResource { // This is used to create a CImage with an NSImage pointer. It MUST be a CFRetained // NSImage, and the CImage takes ownership of the non-GC retain. If callers need the // NSImage themselves, they MUST call retain on the NSImage themselves. - public BufferedImage createImageUsingNativeSize(final long image) { + public Image createImageUsingNativeSize(final long image) { if (image == 0) return null; final Dimension2D size = nativeGetNSImageSize(image); - return createBufferedImage(image, size.getWidth(), size.getHeight()); + return createImage(image, size.getWidth(), size.getHeight()); } // the width and height passed in as a parameter could differ than the width and the height of the NSImage (image), in that case, the image will be scaled - BufferedImage createBufferedImage(long image, double width, double height) { + Image createImage(long image, double width, double height) { if (image == 0) throw new Error("Unable to instantiate CImage with null native image reference."); return createImageWithSize(image, width, height); } - public BufferedImage createImageWithSize(final long image, final double width, final double height) { + public Image createImageWithSize(final long image, final double width, final double height) { final CImage img = new CImage(image); img.resize(width, height); return img.toImage(); } // This is used to create a CImage that represents the icon of the given file. - public BufferedImage createImageOfFile(final String file, final int width, final int height) { - return createBufferedImage(nativeCreateNSImageOfFileFromLaunchServices(file), width, height); + public Image createImageOfFile(final String file, final int width, final int height) { + return createImage(nativeCreateNSImageOfFileFromLaunchServices(file), width, height); } - public BufferedImage createImageFromFile(final String file, final double width, final double height) { + public Image createImageFromFile(final String file, final double width, final double height) { final long image = nativeCreateNSImageFromFileContents(file); nativeSetNSImageSize(image, width, height); - return createBufferedImage(image, width, height); + return createImage(image, width, height); } - public BufferedImage createSystemImageFromSelector(final String iconSelector, final int width, final int height) { - return createBufferedImage(nativeCreateNSImageFromIconSelector(getSelectorAsInt(iconSelector)), width, height); + public Image createSystemImageFromSelector(final String iconSelector, final int width, final int height) { + return createImage(nativeCreateNSImageFromIconSelector(getSelectorAsInt(iconSelector)), width, height); } public Image createImageFromName(final String name, final int width, final int height) { - return createBufferedImage(nativeCreateNSImageFromImageName(name), width, height); + return createImage(nativeCreateNSImageFromImageName(name), width, height); } public Image createImageFromName(final String name) { @@ -213,7 +213,7 @@ public class CImage extends CFRetainedResource { } /** @return A MultiResolution image created from nsImagePtr, or null. */ - private BufferedImage toImage() { + private Image toImage() { if (ptr == 0) return null; final Dimension2D size = nativeGetNSImageSize(ptr); @@ -224,11 +224,11 @@ public class CImage extends CFRetainedResource { = nativeGetNSImageRepresentationSizes(ptr, size.getWidth(), size.getHeight()); - BufferedImage baseImage = toImage(w, h, w, h); - - return sizes == null || sizes.length < 2 ? baseImage - : new MultiResolutionBufferedImage(baseImage, sizes, - (width, height) -> toImage(w, h, width, height)); + return sizes == null || sizes.length < 2 ? + new MultiResolutionCachedImage(w, h, (width, height) + -> toImage(w, h, width, height)) + : new MultiResolutionCachedImage(w, h, sizes, (width, height) + -> toImage(w, h, width, height)); } private BufferedImage toImage(int srcWidth, int srcHeight, int dstWidth, int dstHeight) { diff --git a/src/share/classes/sun/awt/image/AbstractMultiResolutionImage.java b/src/share/classes/sun/awt/image/AbstractMultiResolutionImage.java new file mode 100644 index 000000000..94c070916 --- /dev/null +++ b/src/share/classes/sun/awt/image/AbstractMultiResolutionImage.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package sun.awt.image; + +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.*; + +/** + * This class provides default implementations for the + * MultiResolutionImage interface. The developer needs only + * to subclass this abstract class and define the getResolutionVariant, + * getResolutionVariants, and getBaseImage methods. + * + * + * For example, + * {@code + * public class CustomMultiResolutionImage extends AbstractMultiResolutionImage { + * + * int baseImageIndex; + * Image[] resolutionVariants; + * + * public CustomMultiResolutionImage(int baseImageIndex, + * Image... resolutionVariants) { + * this.baseImageIndex = baseImageIndex; + * this.resolutionVariants = resolutionVariants; + * } + * + * @Override + * public Image getResolutionVariant(float logicalDPIX, float logicalDPIY, + * float baseImageWidth, float baseImageHeight, + * float destImageWidth, float destImageHeight) { + * // return a resolution variant based on the given logical DPI, + * // base image size, or destination image size + * } + * + * @Override + * public List getResolutionVariants() { + * return Arrays.asList(resolutionVariants); + * } + * + * protected Image getBaseImage() { + * return resolutionVariants[baseImageIndex]; + * } + * } + * } + * + * @see java.awt.Image + * @see java.awt.image.MultiResolutionImage + * + */ +public abstract class AbstractMultiResolutionImage extends java.awt.Image + implements MultiResolutionImage { + + /** + * @inheritDoc + */ + @Override + public int getWidth(ImageObserver observer) { + return getBaseImage().getWidth(null); + } + + /** + * @inheritDoc + */ + @Override + public int getHeight(ImageObserver observer) { + return getBaseImage().getHeight(null); + } + + /** + * @inheritDoc + */ + @Override + public ImageProducer getSource() { + return getBaseImage().getSource(); + } + + /** + * @inheritDoc + */ + @Override + public Graphics getGraphics() { + return getBaseImage().getGraphics(); + + } + + /** + * @inheritDoc + */ + @Override + public Object getProperty(String name, ImageObserver observer) { + return getBaseImage().getProperty(name, observer); + } + + /** + * @return base image + */ + protected abstract Image getBaseImage(); +} diff --git a/src/share/classes/sun/awt/image/MultiResolutionBufferedImage.java b/src/share/classes/sun/awt/image/MultiResolutionCachedImage.java similarity index 80% rename from src/share/classes/sun/awt/image/MultiResolutionBufferedImage.java rename to src/share/classes/sun/awt/image/MultiResolutionCachedImage.java index 74db82734..376827c08 100644 --- a/src/share/classes/sun/awt/image/MultiResolutionBufferedImage.java +++ b/src/share/classes/sun/awt/image/MultiResolutionCachedImage.java @@ -26,9 +26,7 @@ package sun.awt.image; import java.awt.Dimension; import java.awt.Image; -import java.awt.Graphics; import java.awt.geom.Dimension2D; -import java.awt.image.BufferedImage; import java.awt.image.ImageObserver; import java.util.Arrays; import java.util.List; @@ -36,50 +34,39 @@ import java.util.function.Function; import java.util.function.BiFunction; import java.util.stream.Collectors; -public class MultiResolutionBufferedImage extends BufferedImage - implements MultiResolutionImage { +public class MultiResolutionCachedImage extends AbstractMultiResolutionImage { - private final BiFunction mapper; + private final int baseImageWidth; + private final int baseImageHeight; private final Dimension2D[] sizes; + private final BiFunction mapper; private int availableInfo; - public MultiResolutionBufferedImage(Image baseImage, + public MultiResolutionCachedImage(int baseImageWidth, int baseImageHeight, BiFunction mapper) { - this(baseImage, new Dimension[]{new Dimension( - baseImage.getWidth(null), baseImage.getHeight(null)) + this(baseImageWidth, baseImageHeight, new Dimension[]{new Dimension( + baseImageWidth, baseImageHeight) }, mapper); } - public MultiResolutionBufferedImage(Image baseImage, + public MultiResolutionCachedImage(int baseImageWidth, int baseImageHeight, Dimension2D[] sizes, BiFunction mapper) { - super(baseImage.getWidth(null), baseImage.getHeight(null), - BufferedImage.TYPE_INT_ARGB_PRE); + this.baseImageWidth = baseImageWidth; + this.baseImageHeight = baseImageHeight; this.sizes = sizes; this.mapper = mapper; - this.availableInfo = getInfo(baseImage); - Graphics g = getGraphics(); - g.drawImage(baseImage, 0, 0, null); - g.dispose(); } @Override public Image getResolutionVariant(int width, int height) { - int baseWidth = getWidth(); - int baseHeight = getHeight(); - - if (baseWidth == width && baseHeight == height) { - return this; - } - ImageCache cache = ImageCache.getInstance(); ImageCacheKey key = new ImageCacheKey(this, width, height); Image resolutionVariant = cache.getImage(key); if (resolutionVariant == null) { resolutionVariant = mapper.apply(width, height); cache.setImage(key, resolutionVariant); - preload(resolutionVariant, availableInfo); } - + preload(resolutionVariant, availableInfo); return resolutionVariant; } @@ -90,30 +77,39 @@ public class MultiResolutionBufferedImage extends BufferedImage (int) size.getHeight())).collect(Collectors.toList()); } - public MultiResolutionBufferedImage map(Function mapper) { - return new MultiResolutionBufferedImage(mapper.apply(this), sizes, - (width, height) -> + public MultiResolutionCachedImage map(Function mapper) { + return new MultiResolutionCachedImage(baseImageWidth, baseImageHeight, + sizes, (width, height) -> mapper.apply(getResolutionVariant(width, height))); } @Override public int getWidth(ImageObserver observer) { - availableInfo |= ImageObserver.WIDTH; + updateInfo(observer, ImageObserver.WIDTH); return super.getWidth(observer); } @Override public int getHeight(ImageObserver observer) { - availableInfo |= ImageObserver.HEIGHT; + updateInfo(observer, ImageObserver.HEIGHT); return super.getHeight(observer); } @Override public Object getProperty(String name, ImageObserver observer) { - availableInfo |= ImageObserver.PROPERTIES; + updateInfo(observer, ImageObserver.PROPERTIES); return super.getProperty(name, observer); } + @Override + protected Image getBaseImage() { + return getResolutionVariant(baseImageWidth, baseImageHeight); + } + + private void updateInfo(ImageObserver observer, int info) { + availableInfo |= (observer == null) ? ImageObserver.ALLBITS : info; + } + private static int getInfo(Image image) { if (image instanceof ToolkitImage) { return ((ToolkitImage) image).getImageRep().check( diff --git a/test/javax/swing/JMenuItem/8031573/bug8031573.java b/test/javax/swing/JMenuItem/8031573/bug8031573.java index 5cb1dc504..2d36db7a1 100644 --- a/test/javax/swing/JMenuItem/8031573/bug8031573.java +++ b/test/javax/swing/JMenuItem/8031573/bug8031573.java @@ -28,7 +28,7 @@ import javax.swing.JMenuBar; import javax.swing.SwingUtilities; /* @test - * @bug 8031573 + * @bug 8031573 8040279 * @summary [macosx] Checkmarks of JCheckBoxMenuItems aren't rendered * in high resolution on Retina * @author Alexander Scherbatiy diff --git a/test/javax/swing/JOptionPane/8024926/bug8024926.java b/test/javax/swing/JOptionPane/8024926/bug8024926.java index 42f976b03..185537f3b 100644 --- a/test/javax/swing/JOptionPane/8024926/bug8024926.java +++ b/test/javax/swing/JOptionPane/8024926/bug8024926.java @@ -31,7 +31,7 @@ import sun.awt.OSInfo; /** * @test - * @bug 8024926 + * @bug 8024926 8040279 * @summary [macosx] AquaIcon HiDPI support * @author Alexander Scherbatiy * @run applet/manual=yesno bug8024926.html -- GitLab