提交 e6e654b9 编写于 作者: A alexsch

8040279: [macosx] Do not use the base image in the MultiResolutionBufferedImage

Reviewed-by: serb, pchelko
上级 717c5e10
...@@ -46,10 +46,8 @@ import com.apple.laf.AquaIcon.JRSUIControlSpec; ...@@ -46,10 +46,8 @@ import com.apple.laf.AquaIcon.JRSUIControlSpec;
import com.apple.laf.AquaIcon.SystemIcon; import com.apple.laf.AquaIcon.SystemIcon;
import com.apple.laf.AquaUtils.RecyclableObject; import com.apple.laf.AquaUtils.RecyclableObject;
import com.apple.laf.AquaUtils.RecyclableSingleton; 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.MultiResolutionImage;
import sun.awt.image.MultiResolutionCachedImage;
public class AquaImageFactory { public class AquaImageFactory {
public static IconUIResource getConfirmImageIcon() { public static IconUIResource getConfirmImageIcon() {
...@@ -107,9 +105,9 @@ public class AquaImageFactory { ...@@ -107,9 +105,9 @@ public class AquaImageFactory {
private static final int kAlertIconSize = 64; private static final int kAlertIconSize = 64;
static IconUIResource getAppIconCompositedOn(final Image background) { static IconUIResource getAppIconCompositedOn(final Image background) {
if (background instanceof MultiResolutionBufferedImage) { if (background instanceof MultiResolutionCachedImage) {
int width = background.getWidth(null); int width = background.getWidth(null);
Image mrIconImage = ((MultiResolutionBufferedImage) background).map( Image mrIconImage = ((MultiResolutionCachedImage) background).map(
rv -> getAppIconImageCompositedOn(rv, rv.getWidth(null) / width)); rv -> getAppIconImageCompositedOn(rv, rv.getWidth(null) / width));
return new IconUIResource(new ImageIcon(mrIconImage)); return new IconUIResource(new ImageIcon(mrIconImage));
} }
...@@ -287,23 +285,9 @@ public class AquaImageFactory { ...@@ -287,23 +285,9 @@ public class AquaImageFactory {
private static Image getNSIcon(String imageName) { private static Image getNSIcon(String imageName) {
Image icon = Toolkit.getDefaultToolkit() Image icon = Toolkit.getDefaultToolkit()
.getImage("NSImage://" + imageName); .getImage("NSImage://" + imageName);
if (icon instanceof MultiResolutionImage) {
return icon; 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));
}
public static class NineSliceMetrics { public static class NineSliceMetrics {
public final int wCut, eCut, nCut, sCut; public final int wCut, eCut, nCut, sCut;
public final int minW, minH; public final int minW, minH;
......
...@@ -174,11 +174,7 @@ abstract class AquaPainter <T extends JRSUIState> { ...@@ -174,11 +174,7 @@ abstract class AquaPainter <T extends JRSUIState> {
bounds, controlState); bounds, controlState);
Image img = cache.getImage(key); Image img = cache.getImage(key);
if (img == null) { if (img == null) {
img = new MultiResolutionCachedImage(imgW, imgH,
Image baseImage = createImage(imgX, imgY, imgW, imgH, bounds,
control, controlState);
img = new MultiResolutionBufferedImage(baseImage,
(rvWidth, rvHeight) -> createImage(imgX, imgY, (rvWidth, rvHeight) -> createImage(imgX, imgY,
rvWidth, rvHeight, bounds, control, controlState)); rvWidth, rvHeight, bounds, control, controlState));
......
...@@ -48,7 +48,7 @@ import sun.security.action.GetPropertyAction; ...@@ -48,7 +48,7 @@ import sun.security.action.GetPropertyAction;
import sun.swing.SwingUtilities2; import sun.swing.SwingUtilities2;
import com.apple.laf.AquaImageFactory.SlicedImageControl; import com.apple.laf.AquaImageFactory.SlicedImageControl;
import sun.awt.image.MultiResolutionBufferedImage; import sun.awt.image.MultiResolutionCachedImage;
final class AquaUtils { final class AquaUtils {
...@@ -124,8 +124,8 @@ final class AquaUtils { ...@@ -124,8 +124,8 @@ final class AquaUtils {
static Image generateLightenedImage(final Image image, final int percent) { static Image generateLightenedImage(final Image image, final int percent) {
final GrayFilter filter = new GrayFilter(true, percent); final GrayFilter filter = new GrayFilter(true, percent);
return (image instanceof MultiResolutionBufferedImage) return (image instanceof MultiResolutionCachedImage)
? ((MultiResolutionBufferedImage) image).map( ? ((MultiResolutionCachedImage) image).map(
rv -> generateLightenedImage(rv, filter)) rv -> generateLightenedImage(rv, filter))
: generateLightenedImage(image, filter); : generateLightenedImage(image, filter);
} }
......
...@@ -32,7 +32,7 @@ import java.awt.image.*; ...@@ -32,7 +32,7 @@ import java.awt.image.*;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import sun.awt.image.MultiResolutionImage; import sun.awt.image.MultiResolutionImage;
import sun.awt.image.MultiResolutionBufferedImage; import sun.awt.image.MultiResolutionCachedImage;
import sun.awt.image.SunWritableRaster; import sun.awt.image.SunWritableRaster;
...@@ -60,41 +60,41 @@ public class CImage extends CFRetainedResource { ...@@ -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 // 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, and the CImage takes ownership of the non-GC retain. If callers need the
// NSImage themselves, they MUST call retain on the NSImage themselves. // 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; if (image == 0) return null;
final Dimension2D size = nativeGetNSImageSize(image); 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 // 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."); if (image == 0) throw new Error("Unable to instantiate CImage with null native image reference.");
return createImageWithSize(image, width, height); 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); final CImage img = new CImage(image);
img.resize(width, height); img.resize(width, height);
return img.toImage(); return img.toImage();
} }
// This is used to create a CImage that represents the icon of the given file. // 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) { public Image createImageOfFile(final String file, final int width, final int height) {
return createBufferedImage(nativeCreateNSImageOfFileFromLaunchServices(file), width, 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); final long image = nativeCreateNSImageFromFileContents(file);
nativeSetNSImageSize(image, width, height); 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) { public Image createSystemImageFromSelector(final String iconSelector, final int width, final int height) {
return createBufferedImage(nativeCreateNSImageFromIconSelector(getSelectorAsInt(iconSelector)), width, height); return createImage(nativeCreateNSImageFromIconSelector(getSelectorAsInt(iconSelector)), width, height);
} }
public Image createImageFromName(final String name, final int width, final int 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) { public Image createImageFromName(final String name) {
...@@ -213,7 +213,7 @@ public class CImage extends CFRetainedResource { ...@@ -213,7 +213,7 @@ public class CImage extends CFRetainedResource {
} }
/** @return A MultiResolution image created from nsImagePtr, or null. */ /** @return A MultiResolution image created from nsImagePtr, or null. */
private BufferedImage toImage() { private Image toImage() {
if (ptr == 0) return null; if (ptr == 0) return null;
final Dimension2D size = nativeGetNSImageSize(ptr); final Dimension2D size = nativeGetNSImageSize(ptr);
...@@ -224,11 +224,11 @@ public class CImage extends CFRetainedResource { ...@@ -224,11 +224,11 @@ public class CImage extends CFRetainedResource {
= nativeGetNSImageRepresentationSizes(ptr, = nativeGetNSImageRepresentationSizes(ptr,
size.getWidth(), size.getHeight()); size.getWidth(), size.getHeight());
BufferedImage baseImage = toImage(w, h, w, h); return sizes == null || sizes.length < 2 ?
new MultiResolutionCachedImage(w, h, (width, height)
return sizes == null || sizes.length < 2 ? baseImage -> toImage(w, h, width, height))
: new MultiResolutionBufferedImage(baseImage, sizes, : new MultiResolutionCachedImage(w, h, sizes, (width, height)
(width, height) -> toImage(w, h, width, height)); -> toImage(w, h, width, height));
} }
private BufferedImage toImage(int srcWidth, int srcHeight, int dstWidth, int dstHeight) { private BufferedImage toImage(int srcWidth, int srcHeight, int dstWidth, int dstHeight) {
......
/*
* 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();
}
...@@ -26,9 +26,7 @@ package sun.awt.image; ...@@ -26,9 +26,7 @@ package sun.awt.image;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Image; import java.awt.Image;
import java.awt.Graphics;
import java.awt.geom.Dimension2D; import java.awt.geom.Dimension2D;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver; import java.awt.image.ImageObserver;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
...@@ -36,50 +34,39 @@ import java.util.function.Function; ...@@ -36,50 +34,39 @@ import java.util.function.Function;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class MultiResolutionBufferedImage extends BufferedImage public class MultiResolutionCachedImage extends AbstractMultiResolutionImage {
implements MultiResolutionImage {
private final BiFunction<Integer, Integer, Image> mapper; private final int baseImageWidth;
private final int baseImageHeight;
private final Dimension2D[] sizes; private final Dimension2D[] sizes;
private final BiFunction<Integer, Integer, Image> mapper;
private int availableInfo; private int availableInfo;
public MultiResolutionBufferedImage(Image baseImage, public MultiResolutionCachedImage(int baseImageWidth, int baseImageHeight,
BiFunction<Integer, Integer, Image> mapper) { BiFunction<Integer, Integer, Image> mapper) {
this(baseImage, new Dimension[]{new Dimension( this(baseImageWidth, baseImageHeight, new Dimension[]{new Dimension(
baseImage.getWidth(null), baseImage.getHeight(null)) baseImageWidth, baseImageHeight)
}, mapper); }, mapper);
} }
public MultiResolutionBufferedImage(Image baseImage, public MultiResolutionCachedImage(int baseImageWidth, int baseImageHeight,
Dimension2D[] sizes, BiFunction<Integer, Integer, Image> mapper) { Dimension2D[] sizes, BiFunction<Integer, Integer, Image> mapper) {
super(baseImage.getWidth(null), baseImage.getHeight(null), this.baseImageWidth = baseImageWidth;
BufferedImage.TYPE_INT_ARGB_PRE); this.baseImageHeight = baseImageHeight;
this.sizes = sizes; this.sizes = sizes;
this.mapper = mapper; this.mapper = mapper;
this.availableInfo = getInfo(baseImage);
Graphics g = getGraphics();
g.drawImage(baseImage, 0, 0, null);
g.dispose();
} }
@Override @Override
public Image getResolutionVariant(int width, int height) { public Image getResolutionVariant(int width, int height) {
int baseWidth = getWidth();
int baseHeight = getHeight();
if (baseWidth == width && baseHeight == height) {
return this;
}
ImageCache cache = ImageCache.getInstance(); ImageCache cache = ImageCache.getInstance();
ImageCacheKey key = new ImageCacheKey(this, width, height); ImageCacheKey key = new ImageCacheKey(this, width, height);
Image resolutionVariant = cache.getImage(key); Image resolutionVariant = cache.getImage(key);
if (resolutionVariant == null) { if (resolutionVariant == null) {
resolutionVariant = mapper.apply(width, height); resolutionVariant = mapper.apply(width, height);
cache.setImage(key, resolutionVariant); cache.setImage(key, resolutionVariant);
preload(resolutionVariant, availableInfo);
} }
preload(resolutionVariant, availableInfo);
return resolutionVariant; return resolutionVariant;
} }
...@@ -90,30 +77,39 @@ public class MultiResolutionBufferedImage extends BufferedImage ...@@ -90,30 +77,39 @@ public class MultiResolutionBufferedImage extends BufferedImage
(int) size.getHeight())).collect(Collectors.toList()); (int) size.getHeight())).collect(Collectors.toList());
} }
public MultiResolutionBufferedImage map(Function<Image, Image> mapper) { public MultiResolutionCachedImage map(Function<Image, Image> mapper) {
return new MultiResolutionBufferedImage(mapper.apply(this), sizes, return new MultiResolutionCachedImage(baseImageWidth, baseImageHeight,
(width, height) -> sizes, (width, height) ->
mapper.apply(getResolutionVariant(width, height))); mapper.apply(getResolutionVariant(width, height)));
} }
@Override @Override
public int getWidth(ImageObserver observer) { public int getWidth(ImageObserver observer) {
availableInfo |= ImageObserver.WIDTH; updateInfo(observer, ImageObserver.WIDTH);
return super.getWidth(observer); return super.getWidth(observer);
} }
@Override @Override
public int getHeight(ImageObserver observer) { public int getHeight(ImageObserver observer) {
availableInfo |= ImageObserver.HEIGHT; updateInfo(observer, ImageObserver.HEIGHT);
return super.getHeight(observer); return super.getHeight(observer);
} }
@Override @Override
public Object getProperty(String name, ImageObserver observer) { public Object getProperty(String name, ImageObserver observer) {
availableInfo |= ImageObserver.PROPERTIES; updateInfo(observer, ImageObserver.PROPERTIES);
return super.getProperty(name, observer); 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) { private static int getInfo(Image image) {
if (image instanceof ToolkitImage) { if (image instanceof ToolkitImage) {
return ((ToolkitImage) image).getImageRep().check( return ((ToolkitImage) image).getImageRep().check(
......
...@@ -28,7 +28,7 @@ import javax.swing.JMenuBar; ...@@ -28,7 +28,7 @@ import javax.swing.JMenuBar;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
/* @test /* @test
* @bug 8031573 * @bug 8031573 8040279
* @summary [macosx] Checkmarks of JCheckBoxMenuItems aren't rendered * @summary [macosx] Checkmarks of JCheckBoxMenuItems aren't rendered
* in high resolution on Retina * in high resolution on Retina
* @author Alexander Scherbatiy * @author Alexander Scherbatiy
......
...@@ -31,7 +31,7 @@ import sun.awt.OSInfo; ...@@ -31,7 +31,7 @@ import sun.awt.OSInfo;
/** /**
* @test * @test
* @bug 8024926 * @bug 8024926 8040279
* @summary [macosx] AquaIcon HiDPI support * @summary [macosx] AquaIcon HiDPI support
* @author Alexander Scherbatiy * @author Alexander Scherbatiy
* @run applet/manual=yesno bug8024926.html * @run applet/manual=yesno bug8024926.html
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册