--- /dev/null 2014-04-21 16:37:45.000000000 +0400 +++ new/src/share/classes/sun/awt/image/AbstractMultiResolutionImage.java 2014-04-21 16:37:44.000000000 +0400 @@ -0,0 +1,123 @@ +/* + * 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 + * + * @since 1.9 + */ +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(); +} --- /dev/null 2014-04-21 16:37:46.000000000 +0400 +++ new/src/share/classes/sun/awt/image/MultiResolutionCachedImage.java 2014-04-21 16:37:45.000000000 +0400 @@ -0,0 +1,181 @@ +/* + * 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.Dimension; +import java.awt.Image; +import java.awt.geom.Dimension2D; +import java.awt.image.ImageObserver; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +public class MultiResolutionCachedImage extends AbstractMultiResolutionImage { + + private final int baseImageWidth; + private final int baseImageHeight; + private final Dimension2D[] sizes; + private final BiFunction mapper; + private int availableInfo; + + public MultiResolutionCachedImage(int baseImageWidth, int baseImageHeight, + BiFunction mapper) { + this(baseImageWidth, baseImageHeight, new Dimension[]{new Dimension( + baseImageWidth, baseImageHeight) + }, mapper); + } + + public MultiResolutionCachedImage(int baseImageWidth, int baseImageHeight, + Dimension2D[] sizes, BiFunction mapper) { + this.baseImageWidth = baseImageWidth; + this.baseImageHeight = baseImageHeight; + this.sizes = sizes; + this.mapper = mapper; + } + + @Override + public Image getResolutionVariant(int width, int height) { + 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); + return resolutionVariant; + } + + @Override + public List getResolutionVariants() { + return Arrays.stream(sizes).map((Function) size + -> getResolutionVariant((int) size.getWidth(), + (int) size.getHeight())).collect(Collectors.toList()); + } + + public MultiResolutionCachedImage map(Function mapper) { + return new MultiResolutionCachedImage(baseImageWidth, baseImageHeight, + sizes, (width, height) -> + mapper.apply(getResolutionVariant(width, height))); + } + + @Override + public int getWidth(ImageObserver observer) { + updateInfo(observer, ImageObserver.WIDTH); + return super.getWidth(observer); + } + + @Override + public int getHeight(ImageObserver observer) { + updateInfo(observer, ImageObserver.HEIGHT); + return super.getHeight(observer); + } + + @Override + public Object getProperty(String name, ImageObserver observer) { + 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( + (img, infoflags, x, y, w, h) -> false); + } + return 0; + } + + private static void preload(Image image, int availableInfo) { + if (availableInfo != 0 && image instanceof ToolkitImage) { + ((ToolkitImage) image).preload(new ImageObserver() { + int flags = availableInfo; + + @Override + public boolean imageUpdate(Image img, int infoflags, + int x, int y, int width, int height) { + flags &= ~infoflags; + return (flags != 0) && ((infoflags + & (ImageObserver.ERROR | ImageObserver.ABORT)) == 0); + } + }); + } + } + + private static class ImageCacheKey implements ImageCache.PixelsKey { + + private final int pixelCount; + private final int hash; + + private final int w; + private final int h; + private final Image baseImage; + + ImageCacheKey(final Image baseImage, + final int w, final int h) { + this.baseImage = baseImage; + this.w = w; + this.h = h; + this.pixelCount = w * h; + hash = hash(); + } + + @Override + public int getPixelCount() { + return pixelCount; + } + + private int hash() { + int hash = baseImage.hashCode(); + hash = 31 * hash + w; + hash = 31 * hash + h; + return hash; + } + + @Override + public int hashCode() { + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ImageCacheKey) { + ImageCacheKey key = (ImageCacheKey) obj; + return baseImage == key.baseImage && w == key.w && h == key.h; + } + return false; + } + } +} \ No newline at end of file --- old/src/share/classes/sun/awt/image/MultiResolutionBufferedImage.java 2014-04-21 16:37:47.000000000 +0400 +++ /dev/null 2014-04-21 16:37:47.000000000 +0400 @@ -1,185 +0,0 @@ -/* - * 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.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; -import java.util.function.Function; -import java.util.function.BiFunction; -import java.util.stream.Collectors; - -public class MultiResolutionBufferedImage extends BufferedImage - implements MultiResolutionImage { - - private final BiFunction mapper; - private final Dimension2D[] sizes; - private int availableInfo; - - public MultiResolutionBufferedImage(Image baseImage, - BiFunction mapper) { - this(baseImage, new Dimension[]{new Dimension( - baseImage.getWidth(null), baseImage.getHeight(null)) - }, mapper); - } - - public MultiResolutionBufferedImage(Image baseImage, - Dimension2D[] sizes, BiFunction mapper) { - super(baseImage.getWidth(null), baseImage.getHeight(null), - BufferedImage.TYPE_INT_ARGB_PRE); - 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); - } - - return resolutionVariant; - } - - @Override - public List getResolutionVariants() { - return Arrays.stream(sizes).map((Function) size - -> getResolutionVariant((int) size.getWidth(), - (int) size.getHeight())).collect(Collectors.toList()); - } - - public MultiResolutionBufferedImage map(Function mapper) { - return new MultiResolutionBufferedImage(mapper.apply(this), sizes, - (width, height) -> - mapper.apply(getResolutionVariant(width, height))); - } - - @Override - public int getWidth(ImageObserver observer) { - availableInfo |= ImageObserver.WIDTH; - return super.getWidth(observer); - } - - @Override - public int getHeight(ImageObserver observer) { - availableInfo |= ImageObserver.HEIGHT; - return super.getHeight(observer); - } - - @Override - public Object getProperty(String name, ImageObserver observer) { - availableInfo |= ImageObserver.PROPERTIES; - return super.getProperty(name, observer); - } - - private static int getInfo(Image image) { - if (image instanceof ToolkitImage) { - return ((ToolkitImage) image).getImageRep().check( - (img, infoflags, x, y, w, h) -> false); - } - return 0; - } - - private static void preload(Image image, int availableInfo) { - if (availableInfo != 0 && image instanceof ToolkitImage) { - ((ToolkitImage) image).preload(new ImageObserver() { - int flags = availableInfo; - - @Override - public boolean imageUpdate(Image img, int infoflags, - int x, int y, int width, int height) { - flags &= ~infoflags; - return (flags != 0) && ((infoflags - & (ImageObserver.ERROR | ImageObserver.ABORT)) == 0); - } - }); - } - } - - private static class ImageCacheKey implements ImageCache.PixelsKey { - - private final int pixelCount; - private final int hash; - - private final int w; - private final int h; - private final Image baseImage; - - ImageCacheKey(final Image baseImage, - final int w, final int h) { - this.baseImage = baseImage; - this.w = w; - this.h = h; - this.pixelCount = w * h; - hash = hash(); - } - - @Override - public int getPixelCount() { - return pixelCount; - } - - private int hash() { - int hash = baseImage.hashCode(); - hash = 31 * hash + w; - hash = 31 * hash + h; - return hash; - } - - @Override - public int hashCode() { - return hash; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ImageCacheKey) { - ImageCacheKey key = (ImageCacheKey) obj; - return baseImage == key.baseImage && w == key.w && h == key.h; - } - return false; - } - } -} \ No newline at end of file --- old/src/macosx/classes/com/apple/laf/AquaImageFactory.java 2014-04-21 16:37:48.000000000 +0400 +++ new/src/macosx/classes/com/apple/laf/AquaImageFactory.java 2014-04-21 16:37:47.000000000 +0400 @@ -46,10 +46,8 @@ 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() { @@ -125,9 +123,9 @@ 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)); } @@ -306,21 +304,7 @@ 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 { --- old/src/macosx/classes/com/apple/laf/AquaPainter.java 2014-04-21 16:37:49.000000000 +0400 +++ new/src/macosx/classes/com/apple/laf/AquaPainter.java 2014-04-21 16:37:48.000000000 +0400 @@ -174,11 +174,7 @@ 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)); --- old/src/macosx/classes/com/apple/laf/AquaUtils.java 2014-04-21 16:37:50.000000000 +0400 +++ new/src/macosx/classes/com/apple/laf/AquaUtils.java 2014-04-21 16:37:49.000000000 +0400 @@ -48,7 +48,7 @@ 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 @@ 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); } --- old/src/macosx/classes/sun/lwawt/macosx/CImage.java 2014-04-21 16:37:51.000000000 +0400 +++ new/src/macosx/classes/sun/lwawt/macosx/CImage.java 2014-04-21 16:37:50.000000000 +0400 @@ -32,7 +32,7 @@ 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; @@ -62,41 +62,41 @@ // 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) { @@ -232,7 +232,7 @@ } /** @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); @@ -243,11 +243,11 @@ = 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) { --- old/test/javax/swing/JMenuItem/8031573/bug8031573.java 2014-04-21 16:37:52.000000000 +0400 +++ new/test/javax/swing/JMenuItem/8031573/bug8031573.java 2014-04-21 16:37:51.000000000 +0400 @@ -28,7 +28,7 @@ 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 --- old/test/javax/swing/JOptionPane/8024926/bug8024926.java 2014-04-21 16:37:52.000000000 +0400 +++ new/test/javax/swing/JOptionPane/8024926/bug8024926.java 2014-04-21 16:37:52.000000000 +0400 @@ -31,7 +31,7 @@ /** * @test - * @bug 8024926 + * @bug 8024926 8040279 * @summary [macosx] AquaIcon HiDPI support * @author Alexander Scherbatiy * @run applet/manual=yesno bug8024926.html