--- old/src/macosx/classes/sun/lwawt/macosx/CImage.java 2014-02-04 15:41:13.000000000 +0400 +++ new/src/macosx/classes/sun/lwawt/macosx/CImage.java 2014-02-04 15:41:12.000000000 +0400 @@ -42,10 +42,11 @@ private static native long nativeCreateNSImageOfFileFromLaunchServices(String file); private static native long nativeCreateNSImageFromImageName(String name); private static native long nativeCreateNSImageFromIconSelector(int selector); - private static native void nativeCopyNSImageIntoArray(long image, int[] buffer, int w, int h); + private static native void nativeCopyNSImageIntoArray(long image, int[] buffer, int sw, int sh, int dw, int dh); private static native Dimension2D nativeGetNSImageSize(long image); private static native void nativeSetNSImageSize(long image, double w, double h); private static native void nativeResizeNSImageRepresentations(long image, double w, double h); + private static native Dimension2D[] nativeGetNSImageRepresentationSizes(long image, double w, double h); static Creator creator = new Creator(); static Creator getCreator() { @@ -210,18 +211,42 @@ super(nsImagePtr, true); } - /** @return A BufferedImage created from nsImagePtr, or null. */ - public BufferedImage toImage() { + /** @return A MultiResolution image created from nsImagePtr, or null. */ + private BufferedImage toImage() { if (ptr == 0) return null; final Dimension2D size = nativeGetNSImageSize(ptr); - final int w = (int)size.getWidth(); - final int h = (int)size.getHeight(); + final int w = (int) size.getWidth(); + final int h = (int) size.getHeight(); - final BufferedImage bimg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE); + Dimension2D[] sizes = + nativeGetNSImageRepresentationSizes(ptr, + size.getWidth(), size.getHeight()); + + if (sizes == null || sizes.length < 2) { + return toImage(w, h, w, h); + } + + BufferedImage[] images = new BufferedImage[sizes.length]; + int currentImageIndex = 0; + + for (int i = 0; i < sizes.length; i++) { + int imageRepWidth = (int) sizes[i].getWidth(); + int imageRepHeight = (int) sizes[i].getHeight(); + + if(imageRepHeight <= w && imageRepHeight <= h){ + currentImageIndex = i; + } + images[i] = toImage(w, h, imageRepWidth, imageRepHeight); + } + return new MultiResolutionBufferedImage(images, currentImageIndex); + } + + private BufferedImage toImage(int srcWidth, int srcHeight, int dstWidth, int dstHeight) { + final BufferedImage bimg = new BufferedImage(dstWidth, dstHeight, BufferedImage.TYPE_INT_ARGB_PRE); final DataBufferInt dbi = (DataBufferInt)bimg.getRaster().getDataBuffer(); final int[] buffer = SunWritableRaster.stealData(dbi, 0); - nativeCopyNSImageIntoArray(ptr, buffer, w, h); + nativeCopyNSImageIntoArray(ptr, buffer, srcWidth, srcHeight, dstWidth, dstHeight); SunWritableRaster.markDirty(dbi); return bimg; } @@ -235,4 +260,35 @@ void resizeRepresentations(double w, double h) { if (ptr != 0) nativeResizeNSImageRepresentations(ptr, w, h); } + + private static class MultiResolutionBufferedImage extends BufferedImage + implements MultiResolutionImage { + + BufferedImage[] resolutionVariants; + + public MultiResolutionBufferedImage(BufferedImage[] images, int baseIndex) { + super(images[baseIndex].getWidth(), images[baseIndex].getHeight(), + images[baseIndex].getType()); + this.resolutionVariants = images; + Graphics g = getGraphics(); + g.drawImage(images[baseIndex], 0, 0, null); + g.dispose(); + images[baseIndex] = this; + } + + @Override + public Image getResolutionVariant(int width, int height) { + for (BufferedImage image : resolutionVariants) { + if (width <= image.getWidth() && height <= image.getHeight()) { + return image; + } + } + return this; + } + + @Override + public List getResolutionVariants() { + return Arrays.asList(resolutionVariants); + } + } } --- old/src/macosx/native/sun/awt/CImage.m 2014-02-04 15:41:14.000000000 +0400 +++ new/src/macosx/native/sun/awt/CImage.m 2014-02-04 15:41:13.000000000 +0400 @@ -52,8 +52,10 @@ } static void CImage_CopyNSImageIntoArray -(NSImage *srcImage, jint *dstPixels, int width, int height) +(NSImage *srcImage, jint *dstPixels, NSRect fromRect, NSRect toRect) { + int width = toRect.size.width; + int height = toRect.size.height; CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGContextRef cgRef = CGBitmapContextCreate(dstPixels, width, height, 8, width * 4, colorspace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); CGColorSpaceRelease(colorspace); @@ -61,9 +63,8 @@ CGContextRelease(cgRef); NSGraphicsContext *oldContext = [[NSGraphicsContext currentContext] retain]; [NSGraphicsContext setCurrentContext:context]; - NSRect rect = NSMakeRect(0, 0, width, height); - [srcImage drawInRect:rect - fromRect:rect + [srcImage drawInRect:toRect + fromRect:fromRect operation:NSCompositeSourceOver fraction:1.0]; [NSGraphicsContext setCurrentContext:oldContext]; @@ -266,21 +267,23 @@ /* * Class: sun_lwawt_macosx_CImage * Method: nativeCopyNSImageIntoArray - * Signature: (J[III)V + * Signature: (J[IIIII)V */ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeCopyNSImageIntoArray -(JNIEnv *env, jclass klass, jlong nsImgPtr, jintArray buffer, jint w, jint h) +(JNIEnv *env, jclass klass, jlong nsImgPtr, jintArray buffer, jint sw, jint sh, jint dw, jint dh) { -JNF_COCOA_ENTER(env); - + JNF_COCOA_ENTER(env); + NSImage *img = (NSImage *)jlong_to_ptr(nsImgPtr); jint *dst = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL); if (dst) { - CImage_CopyNSImageIntoArray(img, dst, w, h); + NSRect fromRect = NSMakeRect(0, 0, sw, sh); + NSRect toRect = NSMakeRect(0, 0, dw, dh); + CImage_CopyNSImageIntoArray(img, dst, fromRect, toRect); (*env)->ReleasePrimitiveArrayCritical(env, buffer, dst, JNI_ABORT); } - -JNF_COCOA_EXIT(env); + + JNF_COCOA_EXIT(env); } /* @@ -343,3 +346,59 @@ JNF_COCOA_EXIT(env); } + +/* + * Class: sun_lwawt_macosx_CImage + * Method: nativeGetNSImageRepresentationsCount + * Signature: (JDD)Ljava/awt/geom/Dimension2D; + */ +JNIEXPORT jobjectArray JNICALL Java_sun_lwawt_macosx_CImage_nativeGetNSImageRepresentationSizes +(JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h) +{ + if (!image) return 0; + jobjectArray jreturnArray = NULL; + NSImage *img = (NSImage *)jlong_to_ptr(image); + +JNF_COCOA_ENTER(env); + + NSMutableArray *imagePixelSizes = [[NSMutableArray alloc] init]; + + NSImageRep *imageRep = nil; + NSEnumerator *imageEnumerator = [[img representations] objectEnumerator]; + + while ((imageRep = [imageEnumerator nextObject]) != nil) { + NSSize imageRepSize = [imageRep size]; + if (imageRepSize.width == w && imageRepSize.height == h){ + NSSize pixelSize = NSMakeSize([imageRep pixelsWide], [imageRep pixelsHigh]); + [imagePixelSizes addObject: [NSValue valueWithSize: pixelSize]]; + } + } + + NSArray *sortedPixelSizes = [imagePixelSizes sortedArrayUsingComparator: ^(id obj1, id obj2) { + NSSize size1 = [obj1 sizeValue]; + NSSize size2 = [obj2 sizeValue]; + return (NSComparisonResult) ((size1.width <= size2.width && size1.height <= size2.height) ? + NSOrderedAscending : + NSOrderedDescending); + }]; + + jsize count = [sortedPixelSizes count]; + static JNF_CLASS_CACHE(jc_Dimension, "java/awt/Dimension"); + jreturnArray = JNFNewObjectArray(env, &jc_Dimension, count); + + jsize i; + for(i = 0; i < count; i++){ + NSSize pixelSize = [[sortedPixelSizes objectAtIndex: i] sizeValue]; + + (*env)->SetObjectArrayElement(env, jreturnArray, i, NSToJavaSize(env, pixelSize)); + if ((*env)->ExceptionOccurred(env)) { + (*env)->ExceptionDescribe(env); + (*env)->ExceptionClear(env); + continue; + } + } + +JNF_COCOA_EXIT(env); + + return jreturnArray; +} \ No newline at end of file --- /dev/null 2014-02-04 15:41:15.000000000 +0400 +++ new/test/java/awt/image/MultiResolutionImage/NSImageToMultiResolutionImageTest.java 2014-02-04 15:41:15.000000000 +0400 @@ -0,0 +1,66 @@ +/* + * 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. + * + * 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. + */ + +import java.awt.Image; +import java.awt.Toolkit; +import sun.awt.OSInfo; +import sun.awt.image.MultiResolutionImage; +/* + * @test + * @bug 8033534 + * @summary [macosx] Get MultiResolution image from native system + * @author Alexander Scherbatiy + * @run main NSImageToMultiResolutionImageTest + */ + +public class NSImageToMultiResolutionImageTest { + + public static void main(String[] args) throws Exception { + + if (OSInfo.getOSType() != OSInfo.OSType.MACOSX) { + return; + } + + String icon = "NSImage://NSApplicationIcon"; + final Image image = Toolkit.getDefaultToolkit().getImage(icon); + + if (!(image instanceof MultiResolutionImage)) { + throw new RuntimeException("Icon does not have resolution variants!"); + } + + MultiResolutionImage multiResolutionImage = (MultiResolutionImage) image; + + int width = 0; + int height = 0; + + for (Image resolutionVariant : multiResolutionImage.getResolutionVariants()) { + int rvWidth = resolutionVariant.getWidth(null); + int rvHeight = resolutionVariant.getHeight(null); + if (rvWidth < width || rvHeight < height) { + throw new RuntimeException("Resolution variants are not sorted!"); + } + width = rvWidth; + height = rvHeight; + } + } +}