8033534: [macosx] Get MultiResolution image from native system
authoralexsch
Tue, 04 Mar 2014 17:06:00 +0400
changeset 23615 a0825e77bfad
parent 23614 4f16281f93cf
child 23616 d4680386f38a
8033534: [macosx] Get MultiResolution image from native system Reviewed-by: serb, pchelko
jdk/src/macosx/classes/sun/lwawt/macosx/CImage.java
jdk/src/macosx/native/sun/awt/CImage.m
jdk/test/java/awt/image/MultiResolutionImage/NSImageToMultiResolutionImageTest.java
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CImage.java	Tue Mar 04 13:40:58 2014 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CImage.java	Tue Mar 04 17:06:00 2014 +0400
@@ -32,6 +32,7 @@
 import java.util.Arrays;
 import java.util.List;
 import sun.awt.image.MultiResolutionImage;
+import sun.awt.image.MultiResolutionBufferedImage;
 
 import sun.awt.image.SunWritableRaster;
 
@@ -42,10 +43,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 +212,43 @@
         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 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(BufferedImage.TYPE_INT_ARGB_PRE,
+                currentImageIndex, images);
+    }
+
+    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;
     }
--- a/jdk/src/macosx/native/sun/awt/CImage.m	Tue Mar 04 13:40:58 2014 +0400
+++ b/jdk/src/macosx/native/sun/awt/CImage.m	Tue Mar 04 17:06:00 2014 +0400
@@ -22,6 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+#import "jni_util.h"
 
 #import <Cocoa/Cocoa.h>
 #import <JavaNativeFoundation/JavaNativeFoundation.h>
@@ -52,18 +53,21 @@
 }
 
 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);
+    CGContextRef cgRef = CGBitmapContextCreate(dstPixels, width, height,
+                                8, width * 4, colorspace,
+                                kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
     CGColorSpaceRelease(colorspace);
     NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:cgRef flipped:NO];
     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];
@@ -268,17 +272,20 @@
 /*
  * 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);
 
     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);
     }
 
@@ -345,3 +352,87 @@
     
 JNF_COCOA_EXIT(env);
 }
+
+NSComparisonResult getOrder(BOOL order){
+    return (NSComparisonResult) (order ? NSOrderedAscending : NSOrderedDescending);
+}
+
+/*
+ * 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 NULL;
+    jobjectArray jreturnArray = NULL;
+    NSImage *img = (NSImage *)jlong_to_ptr(image);
+
+JNF_COCOA_ENTER(env);
+        
+    NSArray *imageRepresentations = [img representations];
+    if([imageRepresentations count] == 0){
+        return NULL;
+    }
+    
+    NSArray *sortedImageRepresentations = [imageRepresentations
+                    sortedArrayUsingComparator: ^(id obj1, id obj2) {
+        
+        NSImageRep *imageRep1 = (NSImageRep *) obj1;
+        NSImageRep *imageRep2 = (NSImageRep *) obj2;
+        NSSize size1 = [imageRep1 size];
+        NSSize size2 = [imageRep2 size];
+        
+        if (NSEqualSizes(size1, size2)) {
+            return getOrder([imageRep1 pixelsWide] <= [imageRep2 pixelsWide] &&
+                            [imageRep1 pixelsHigh] <= [imageRep2 pixelsHigh]);
+        }
+
+        return getOrder(size1.width <= size2.width && size1.height <= size2.height);
+    }];
+
+    NSMutableArray *sortedPixelSizes = [[NSMutableArray alloc] init];
+    NSSize lastSize = [[sortedImageRepresentations lastObject] size];
+    
+    NSUInteger i = [sortedImageRepresentations indexOfObjectPassingTest:
+               ^BOOL(id obj, NSUInteger idx, BOOL *stop) {
+        NSSize imageRepSize = [obj size];
+        return (w <= imageRepSize.width && h <= imageRepSize.height)
+                   || NSEqualSizes(imageRepSize, lastSize);
+    }];
+
+    NSUInteger count = [sortedImageRepresentations count];
+    i = (i == NSNotFound) ? count - 1 : i;
+    NSSize bestFitSize = [[sortedImageRepresentations objectAtIndex: i] size];
+
+    for(; i < count; i++){
+        NSImageRep *imageRep = [sortedImageRepresentations objectAtIndex: i];
+
+        if (!NSEqualSizes([imageRep size], bestFitSize)) {
+            break;
+        }
+
+        NSSize pixelSize = NSMakeSize(
+                                [imageRep pixelsWide], [imageRep pixelsHigh]);
+        [sortedPixelSizes addObject: [NSValue valueWithSize: pixelSize]];
+    }
+
+    count = [sortedPixelSizes count];
+    static JNF_CLASS_CACHE(jc_Dimension, "java/awt/Dimension");
+    jreturnArray = JNFNewObjectArray(env, &jc_Dimension, count);
+    CHECK_NULL_RETURN(jreturnArray, NULL);
+
+    for(i = 0; i < count; i++){
+        NSSize pixelSize = [[sortedPixelSizes objectAtIndex: i] sizeValue];
+
+        (*env)->SetObjectArrayElement(env, jreturnArray, i,
+                                      NSToJavaSize(env, pixelSize));
+        JNU_CHECK_EXCEPTION_RETURN(env, NULL);
+    }
+
+JNF_COCOA_EXIT(env);
+
+    return jreturnArray;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/image/MultiResolutionImage/NSImageToMultiResolutionImageTest.java	Tue Mar 04 17:06:00 2014 +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;
+        }
+    }
+}