1 /*
   2  * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #import <Cocoa/Cocoa.h>
  27 #import <JavaNativeFoundation/JavaNativeFoundation.h>
  28 
  29 #import "GeomUtilities.h"
  30 #import "ThreadUtilities.h"
  31 
  32 #import "sun_lwawt_macosx_CImage.h"
  33 
  34 
  35 static void CImage_CopyArrayIntoNSImageRep
  36 (jint *srcPixels, jint *dstPixels, int width, int height)
  37 {
  38     int x, y;
  39     // TODO: test this on big endian systems (not sure if its correct)...
  40     for (y = 0; y < height; y++) {
  41         for (x = 0; x < width; x++) {
  42             jint pix = srcPixels[x];
  43             jint a = (pix >> 24) & 0xff;
  44             jint r = (pix >> 16) & 0xff;
  45             jint g = (pix >>  8) & 0xff;
  46             jint b = (pix      ) & 0xff;
  47             dstPixels[x] = (b << 24) | (g << 16) | (r << 8) | a;
  48         }
  49         srcPixels += width; // TODO: use explicit scanStride
  50         dstPixels += width;
  51     }
  52 }
  53 
  54 static void CImage_CopyNSImageIntoArray
  55 (NSImage *srcImage, jint *dstPixels, int width, int height)
  56 {
  57     CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
  58     CGContextRef cgRef = CGBitmapContextCreate(dstPixels, width, height, 8, width * 4, colorspace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
  59     CGColorSpaceRelease(colorspace);
  60     NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:cgRef flipped:NO];
  61     CGContextRelease(cgRef);
  62     NSGraphicsContext *oldContext = [[NSGraphicsContext currentContext] retain];
  63     [NSGraphicsContext setCurrentContext:context];
  64     NSRect rect = NSMakeRect(0, 0, width, height);
  65     [srcImage drawInRect:rect
  66                 fromRect:rect
  67                operation:NSCompositeSourceOver
  68                 fraction:1.0];
  69     [NSGraphicsContext setCurrentContext:oldContext];
  70     [oldContext release];
  71 }
  72 
  73 static NSBitmapImageRep* CImage_CreateImageRep(JNIEnv *env, jintArray buffer, jint width, jint height)
  74 {
  75     NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
  76                                                                          pixelsWide:width
  77                                                                          pixelsHigh:height
  78                                                                       bitsPerSample:8
  79                                                                     samplesPerPixel:4
  80                                                                            hasAlpha:YES
  81                                                                            isPlanar:NO
  82                                                                      colorSpaceName:NSDeviceRGBColorSpace
  83                                                                        bitmapFormat:NSAlphaFirstBitmapFormat
  84                                                                         bytesPerRow:width*4 // TODO: use explicit scanStride
  85                                                                        bitsPerPixel:32];
  86 
  87     jint *imgData = (jint *)[imageRep bitmapData];
  88     if (imgData == NULL) return 0L;
  89 
  90     jint *src = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL);
  91     if (src == NULL) return 0L;
  92 
  93     CImage_CopyArrayIntoNSImageRep(src, imgData, width, height);
  94 
  95     (*env)->ReleasePrimitiveArrayCritical(env, buffer, src, JNI_ABORT);
  96 
  97     return imageRep;
  98 }
  99 
 100 /*
 101  * Class:     sun_lwawt_macosx_CImage
 102  * Method:    nativeCreateNSImageFromArray
 103  * Signature: ([III)J
 104  */
 105 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromArray
 106 (JNIEnv *env, jclass klass, jintArray buffer, jint width, jint height)
 107 {
 108     jlong result = 0L;
 109 
 110 JNF_COCOA_ENTER(env);
 111 AWT_ASSERT_ANY_THREAD;
 112 
 113     NSBitmapImageRep* imageRep = CImage_CreateImageRep(env, buffer, width, height);
 114     if (imageRep) {
 115         NSImage *nsImage = [[NSImage alloc] initWithSize:NSMakeSize(width, height)];
 116         [nsImage addRepresentation:imageRep];
 117         [imageRep release];
 118 
 119         if (nsImage != nil) {
 120             CFRetain(nsImage); // GC
 121         }
 122 
 123         result = ptr_to_jlong(nsImage);
 124     }
 125 
 126 JNF_COCOA_EXIT(env);
 127 
 128     return result;
 129 }
 130 
 131 /*
 132  * Class:     sun_lwawt_macosx_CImage
 133  * Method:    nativeCreateNSImageFromArrays
 134  * Signature: ([[I[I[I)J
 135  */
 136 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromArrays
 137 (JNIEnv *env, jclass klass, jobjectArray buffers, jintArray widths, jintArray heights)
 138 {
 139     jlong result = 0L;
 140 
 141 JNF_COCOA_ENTER(env);
 142 AWT_ASSERT_ANY_THREAD;
 143 
 144     jsize num = (*env)->GetArrayLength(env, buffers);
 145     NSMutableArray * reps = [NSMutableArray arrayWithCapacity: num];
 146 
 147     jint * ws = (*env)->GetIntArrayElements(env, widths, NULL);
 148     jint * hs = (*env)->GetIntArrayElements(env, heights, NULL);
 149 
 150     jsize i;
 151     for (i = 0; i < num; i++) {
 152         jintArray buffer = (*env)->GetObjectArrayElement(env, buffers, i);
 153 
 154         NSBitmapImageRep* imageRep = CImage_CreateImageRep(env, buffer, ws[i], hs[i]);
 155         if (imageRep) {
 156             [reps addObject: imageRep];
 157         }
 158     }
 159 
 160     (*env)->ReleaseIntArrayElements(env, heights, hs, JNI_ABORT);
 161     (*env)->ReleaseIntArrayElements(env, widths, ws, JNI_ABORT);
 162 
 163     if ([reps count]) {
 164         NSImage *nsImage = [[NSImage alloc] initWithSize:NSMakeSize(0, 0)];
 165         [nsImage addRepresentations: reps];
 166 
 167         if (nsImage != nil) {
 168             CFRetain(nsImage); // GC
 169         }
 170 
 171         result = ptr_to_jlong(nsImage);
 172     }
 173 
 174 JNF_COCOA_EXIT(env);
 175 
 176     return result;
 177 }
 178 
 179 /*
 180  * Class:     sun_lwawt_macosx_CImage
 181  * Method:    nativeCreateNSImageFromIconSelector
 182  * Signature: (I)J
 183  */
 184 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromIconSelector
 185 (JNIEnv *env, jclass klass, jint selector)
 186 {
 187     NSImage *image = nil;
 188 
 189 JNF_COCOA_ENTER(env);
 190 AWT_ASSERT_ANY_THREAD;
 191 
 192     IconRef iconRef;
 193     if (noErr == GetIconRef(kOnSystemDisk, kSystemIconsCreator, selector, &iconRef)) {
 194         image = [[NSImage alloc] initWithIconRef:iconRef];
 195         if (image) CFRetain(image); // GC
 196         ReleaseIconRef(iconRef);
 197     }
 198 
 199 JNF_COCOA_EXIT(env);
 200 
 201     return ptr_to_jlong(image);
 202 }
 203 
 204 /*
 205  * Class:     sun_lwawt_macosx_CImage
 206  * Method:    nativeCreateNSImageFromFileContents
 207  * Signature: (Ljava/lang/String;)J
 208  */
 209 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromFileContents
 210 (JNIEnv *env, jclass klass, jstring file)
 211 {
 212     NSImage *image = nil;
 213 
 214 JNF_COCOA_ENTER(env);
 215 AWT_ASSERT_ANY_THREAD;
 216 
 217     NSString *path = JNFNormalizedNSStringForPath(env, file);
 218     image = [[NSImage alloc] initByReferencingFile:path];
 219     if (image) CFRetain(image); // GC
 220 
 221 JNF_COCOA_EXIT(env);
 222 
 223     return ptr_to_jlong(image);
 224 }
 225 
 226 /*
 227  * Class:     sun_lwawt_macosx_CImage
 228  * Method:    nativeCreateNSImageOfFileFromLaunchServices
 229  * Signature: (Ljava/lang/String;)J
 230  */
 231 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageOfFileFromLaunchServices
 232 (JNIEnv *env, jclass klass, jstring file)
 233 {
 234     __block NSImage *image = nil;
 235 
 236 JNF_COCOA_ENTER(env);
 237 AWT_ASSERT_ANY_THREAD;
 238 
 239     NSString *path = JNFNormalizedNSStringForPath(env, file);
 240     [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
 241         image = [[NSWorkspace sharedWorkspace] iconForFile:path];
 242         [image setScalesWhenResized:TRUE];
 243         if (image) CFRetain(image); // GC
 244     }];
 245 
 246 JNF_COCOA_EXIT(env);
 247 
 248     return ptr_to_jlong(image);
 249 }
 250 
 251 /*
 252  * Class:     sun_lwawt_macosx_CImage
 253  * Method:    nativeCreateNSImageFromImageName
 254  * Signature: (Ljava/lang/String;)J
 255  */
 256 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromImageName
 257 (JNIEnv *env, jclass klass, jstring name)
 258 {
 259     NSImage *image = nil;
 260 
 261 JNF_COCOA_ENTER(env);
 262 AWT_ASSERT_ANY_THREAD;
 263 
 264     image = [NSImage imageNamed:JNFJavaToNSString(env, name)];
 265     if (image) CFRetain(image); // GC
 266 
 267 JNF_COCOA_EXIT(env);
 268 
 269     return ptr_to_jlong(image);
 270 }
 271 
 272 /*
 273  * Class:     sun_lwawt_macosx_CImage
 274  * Method:    nativeCopyNSImageIntoArray
 275  * Signature: (J[III)V
 276  */
 277 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeCopyNSImageIntoArray
 278 (JNIEnv *env, jclass klass, jlong nsImgPtr, jintArray buffer, jint w, jint h)
 279 {
 280 JNF_COCOA_ENTER(env);
 281 AWT_ASSERT_ANY_THREAD;
 282 
 283     NSImage *img = (NSImage *)jlong_to_ptr(nsImgPtr);
 284     jint *dst = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL);
 285     if (dst) {
 286         CImage_CopyNSImageIntoArray(img, dst, w, h);
 287         (*env)->ReleasePrimitiveArrayCritical(env, buffer, dst, JNI_ABORT);
 288     }
 289 
 290 JNF_COCOA_EXIT(env);
 291 }
 292 
 293 /*
 294  * Class:     sun_lwawt_macosx_CImage
 295  * Method:    nativeGetNSImageSize
 296  * Signature: (J)Ljava/awt/geom/Dimension2D;
 297  */
 298 JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CImage_nativeGetNSImageSize
 299 (JNIEnv *env, jclass klass, jlong nsImgPtr)
 300 {
 301     jobject size = NULL;
 302 
 303 JNF_COCOA_ENTER(env);
 304 AWT_ASSERT_ANY_THREAD;
 305 
 306     size = NSToJavaSize(env, [(NSImage *)jlong_to_ptr(nsImgPtr) size]);
 307 
 308 JNF_COCOA_EXIT(env);
 309 
 310     return size;
 311 }
 312 
 313 /*
 314  * Class:     sun_lwawt_macosx_CImage
 315  * Method:    nativeSetNSImageSize
 316  * Signature: (JDD)V
 317  */
 318 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeSetNSImageSize
 319 (JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h)
 320 {
 321     if (!image) return;
 322     NSImage *i = (NSImage *)jlong_to_ptr(image);
 323 
 324 JNF_COCOA_ENTER(env);
 325 
 326     [i setScalesWhenResized:TRUE];
 327     [i setSize:NSMakeSize(w, h)];
 328 
 329 JNF_COCOA_EXIT(env);
 330 }