changeset 9886:ab05318e0d74

8040279: [macosx] Do not use the base image in the MultiResolutionBufferedImage Reviewed-by: serb, pchelko
author alexsch
date Wed, 06 Aug 2014 15:30:04 +0400
parents ebab5c9c6c76
children 82a4137fce5e
files src/macosx/classes/com/apple/laf/AquaImageFactory.java src/macosx/classes/com/apple/laf/AquaPainter.java src/macosx/classes/com/apple/laf/AquaUtils.java src/macosx/classes/sun/lwawt/macosx/CImage.java src/share/classes/sun/awt/image/AbstractMultiResolutionImage.java src/share/classes/sun/awt/image/MultiResolutionBufferedImage.java src/share/classes/sun/awt/image/MultiResolutionCachedImage.java test/javax/swing/JMenuItem/8031573/bug8031573.java test/javax/swing/JOptionPane/8024926/bug8024926.java
diffstat 9 files changed, 331 insertions(+), 233 deletions(-) [+]
line wrap: on
line diff
--- a/src/macosx/classes/com/apple/laf/AquaImageFactory.java	Tue Aug 05 08:30:05 2014 +0400
+++ b/src/macosx/classes/com/apple/laf/AquaImageFactory.java	Wed Aug 06 15:30:04 2014 +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() {
@@ -107,9 +105,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));
         }
@@ -287,21 +285,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 {
--- a/src/macosx/classes/com/apple/laf/AquaPainter.java	Tue Aug 05 08:30:05 2014 +0400
+++ b/src/macosx/classes/com/apple/laf/AquaPainter.java	Wed Aug 06 15:30:04 2014 +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));
 
--- a/src/macosx/classes/com/apple/laf/AquaUtils.java	Tue Aug 05 08:30:05 2014 +0400
+++ b/src/macosx/classes/com/apple/laf/AquaUtils.java	Wed Aug 06 15:30:04 2014 +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);
     }
--- a/src/macosx/classes/sun/lwawt/macosx/CImage.java	Tue Aug 05 08:30:05 2014 +0400
+++ b/src/macosx/classes/sun/lwawt/macosx/CImage.java	Wed Aug 06 15:30:04 2014 +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;
 
@@ -60,41 +60,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) {
@@ -213,7 +213,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);
@@ -224,11 +224,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) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/awt/image/AbstractMultiResolutionImage.java	Wed Aug 06 15:30:04 2014 +0400
@@ -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
+ * <code>MultiResolutionImage</code> interface. The developer needs only
+ * to subclass this abstract class and define the <code>getResolutionVariant</code>,
+ * <code>getResolutionVariants</code>, and <code>getBaseImage</code> 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<Image> 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();
+}
--- a/src/share/classes/sun/awt/image/MultiResolutionBufferedImage.java	Tue Aug 05 08:30:05 2014 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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<Integer, Integer, Image> mapper;
-    private final Dimension2D[] sizes;
-    private int availableInfo;
-
-    public MultiResolutionBufferedImage(Image baseImage,
-            BiFunction<Integer, Integer, Image> mapper) {
-        this(baseImage, new Dimension[]{new Dimension(
-            baseImage.getWidth(null), baseImage.getHeight(null))
-        }, mapper);
-    }
-
-    public MultiResolutionBufferedImage(Image baseImage,
-            Dimension2D[] sizes, BiFunction<Integer, Integer, Image> 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<Image> getResolutionVariants() {
-        return Arrays.stream(sizes).map((Function<Dimension2D, Image>) size
-                -> getResolutionVariant((int) size.getWidth(),
-                        (int) size.getHeight())).collect(Collectors.toList());
-    }
-
-    public MultiResolutionBufferedImage map(Function<Image, Image> 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/awt/image/MultiResolutionCachedImage.java	Wed Aug 06 15:30:04 2014 +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<Integer, Integer, Image> mapper;
+    private int availableInfo;
+
+    public MultiResolutionCachedImage(int baseImageWidth, int baseImageHeight,
+            BiFunction<Integer, Integer, Image> mapper) {
+        this(baseImageWidth, baseImageHeight, new Dimension[]{new Dimension(
+            baseImageWidth, baseImageHeight)
+        }, mapper);
+    }
+
+    public MultiResolutionCachedImage(int baseImageWidth, int baseImageHeight,
+            Dimension2D[] sizes, BiFunction<Integer, Integer, Image> 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<Image> getResolutionVariants() {
+        return Arrays.stream(sizes).map((Function<Dimension2D, Image>) size
+                -> getResolutionVariant((int) size.getWidth(),
+                        (int) size.getHeight())).collect(Collectors.toList());
+    }
+
+    public MultiResolutionCachedImage map(Function<Image, Image> 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
--- a/test/javax/swing/JMenuItem/8031573/bug8031573.java	Tue Aug 05 08:30:05 2014 +0400
+++ b/test/javax/swing/JMenuItem/8031573/bug8031573.java	Wed Aug 06 15:30:04 2014 +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
--- a/test/javax/swing/JOptionPane/8024926/bug8024926.java	Tue Aug 05 08:30:05 2014 +0400
+++ b/test/javax/swing/JOptionPane/8024926/bug8024926.java	Wed Aug 06 15:30:04 2014 +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