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, NSRect fromRect, NSRect toRect) 56 { 57 int width = toRect.size.width; 58 int height = toRect.size.height; 59 CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); 60 CGContextRef cgRef = CGBitmapContextCreate(dstPixels, width, height, 8, width * 4, colorspace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); 61 CGColorSpaceRelease(colorspace); 62 NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:cgRef flipped:NO]; 63 CGContextRelease(cgRef); 64 NSGraphicsContext *oldContext = [[NSGraphicsContext currentContext] retain]; 65 [NSGraphicsContext setCurrentContext:context]; 66 [srcImage drawInRect:toRect 67 fromRect:fromRect 68 operation:NSCompositeSourceOver 69 fraction:1.0]; 70 [NSGraphicsContext setCurrentContext:oldContext]; 71 [oldContext release]; 72 } 73 74 static NSBitmapImageRep* CImage_CreateImageRep(JNIEnv *env, jintArray buffer, jint width, jint height) 75 { 76 NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 77 pixelsWide:width 78 pixelsHigh:height 79 bitsPerSample:8 80 samplesPerPixel:4 81 hasAlpha:YES 82 isPlanar:NO 83 colorSpaceName:NSDeviceRGBColorSpace 84 bitmapFormat:NSAlphaFirstBitmapFormat 85 bytesPerRow:width*4 // TODO: use explicit scanStride 86 bitsPerPixel:32]; 87 88 jint *imgData = (jint *)[imageRep bitmapData]; 89 if (imgData == NULL) return 0L; 90 91 jint *src = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL); 92 if (src == NULL) return 0L; 93 94 CImage_CopyArrayIntoNSImageRep(src, imgData, width, height); 95 96 (*env)->ReleasePrimitiveArrayCritical(env, buffer, src, JNI_ABORT); 97 98 return imageRep; 99 } 100 101 /* 102 * Class: sun_lwawt_macosx_CImage 103 * Method: nativeCreateNSImageFromArray 104 * Signature: ([III)J 105 */ 106 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromArray 107 (JNIEnv *env, jclass klass, jintArray buffer, jint width, jint height) 108 { 109 jlong result = 0L; 110 111 JNF_COCOA_ENTER(env); 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 143 jsize num = (*env)->GetArrayLength(env, buffers); 144 NSMutableArray * reps = [NSMutableArray arrayWithCapacity: num]; 145 146 jint * ws = (*env)->GetIntArrayElements(env, widths, NULL); 147 jint * hs = (*env)->GetIntArrayElements(env, heights, NULL); 148 149 jsize i; 150 for (i = 0; i < num; i++) { 151 jintArray buffer = (*env)->GetObjectArrayElement(env, buffers, i); 152 153 NSBitmapImageRep* imageRep = CImage_CreateImageRep(env, buffer, ws[i], hs[i]); 154 if (imageRep) { 155 [reps addObject: imageRep]; 156 } 157 } 158 159 (*env)->ReleaseIntArrayElements(env, heights, hs, JNI_ABORT); 160 (*env)->ReleaseIntArrayElements(env, widths, ws, JNI_ABORT); 161 162 if ([reps count]) { 163 NSImage *nsImage = [[NSImage alloc] initWithSize:NSMakeSize(0, 0)]; 164 [nsImage addRepresentations: reps]; 165 166 if (nsImage != nil) { 167 CFRetain(nsImage); // GC 168 } 169 170 result = ptr_to_jlong(nsImage); 171 } 172 173 JNF_COCOA_EXIT(env); 174 175 return result; 176 } 177 178 /* 179 * Class: sun_lwawt_macosx_CImage 180 * Method: nativeCreateNSImageFromIconSelector 181 * Signature: (I)J 182 */ 183 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromIconSelector 184 (JNIEnv *env, jclass klass, jint selector) 185 { 186 NSImage *image = nil; 187 188 JNF_COCOA_ENTER(env); 189 190 IconRef iconRef; 191 if (noErr == GetIconRef(kOnSystemDisk, kSystemIconsCreator, selector, &iconRef)) { 192 image = [[NSImage alloc] initWithIconRef:iconRef]; 193 if (image) CFRetain(image); // GC 194 ReleaseIconRef(iconRef); 195 } 196 197 JNF_COCOA_EXIT(env); 198 199 return ptr_to_jlong(image); 200 } 201 202 /* 203 * Class: sun_lwawt_macosx_CImage 204 * Method: nativeCreateNSImageFromFileContents 205 * Signature: (Ljava/lang/String;)J 206 */ 207 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromFileContents 208 (JNIEnv *env, jclass klass, jstring file) 209 { 210 NSImage *image = nil; 211 212 JNF_COCOA_ENTER(env); 213 214 NSString *path = JNFNormalizedNSStringForPath(env, file); 215 image = [[NSImage alloc] initByReferencingFile:path]; 216 if (image) CFRetain(image); // GC 217 218 JNF_COCOA_EXIT(env); 219 220 return ptr_to_jlong(image); 221 } 222 223 /* 224 * Class: sun_lwawt_macosx_CImage 225 * Method: nativeCreateNSImageOfFileFromLaunchServices 226 * Signature: (Ljava/lang/String;)J 227 */ 228 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageOfFileFromLaunchServices 229 (JNIEnv *env, jclass klass, jstring file) 230 { 231 __block NSImage *image = nil; 232 233 JNF_COCOA_ENTER(env); 234 235 NSString *path = JNFNormalizedNSStringForPath(env, file); 236 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ 237 image = [[NSWorkspace sharedWorkspace] iconForFile:path]; 238 [image setScalesWhenResized:TRUE]; 239 if (image) CFRetain(image); // GC 240 }]; 241 242 JNF_COCOA_EXIT(env); 243 244 return ptr_to_jlong(image); 245 } 246 247 /* 248 * Class: sun_lwawt_macosx_CImage 249 * Method: nativeCreateNSImageFromImageName 250 * Signature: (Ljava/lang/String;)J 251 */ 252 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromImageName 253 (JNIEnv *env, jclass klass, jstring name) 254 { 255 NSImage *image = nil; 256 257 JNF_COCOA_ENTER(env); 258 259 image = [NSImage imageNamed:JNFJavaToNSString(env, name)]; 260 if (image) CFRetain(image); // GC 261 262 JNF_COCOA_EXIT(env); 263 264 return ptr_to_jlong(image); 265 } 266 267 /* 268 * Class: sun_lwawt_macosx_CImage 269 * Method: nativeCopyNSImageIntoArray 270 * Signature: (J[IIIII)V 271 */ 272 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeCopyNSImageIntoArray 273 (JNIEnv *env, jclass klass, jlong nsImgPtr, jintArray buffer, jint sw, jint sh, jint dw, jint dh) 274 { 275 JNF_COCOA_ENTER(env); 276 277 NSImage *img = (NSImage *)jlong_to_ptr(nsImgPtr); 278 jint *dst = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL); 279 if (dst) { 280 NSRect fromRect = NSMakeRect(0, 0, sw, sh); 281 NSRect toRect = NSMakeRect(0, 0, dw, dh); 282 CImage_CopyNSImageIntoArray(img, dst, fromRect, toRect); 283 (*env)->ReleasePrimitiveArrayCritical(env, buffer, dst, JNI_ABORT); 284 } 285 286 JNF_COCOA_EXIT(env); 287 } 288 289 /* 290 * Class: sun_lwawt_macosx_CImage 291 * Method: nativeGetNSImageSize 292 * Signature: (J)Ljava/awt/geom/Dimension2D; 293 */ 294 JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CImage_nativeGetNSImageSize 295 (JNIEnv *env, jclass klass, jlong nsImgPtr) 296 { 297 jobject size = NULL; 298 299 JNF_COCOA_ENTER(env); 300 301 size = NSToJavaSize(env, [(NSImage *)jlong_to_ptr(nsImgPtr) size]); 302 303 JNF_COCOA_EXIT(env); 304 305 return size; 306 } 307 308 /* 309 * Class: sun_lwawt_macosx_CImage 310 * Method: nativeSetNSImageSize 311 * Signature: (JDD)V 312 */ 313 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeSetNSImageSize 314 (JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h) 315 { 316 if (!image) return; 317 NSImage *i = (NSImage *)jlong_to_ptr(image); 318 319 JNF_COCOA_ENTER(env); 320 321 [i setScalesWhenResized:TRUE]; 322 [i setSize:NSMakeSize(w, h)]; 323 324 JNF_COCOA_EXIT(env); 325 } 326 327 /* 328 * Class: sun_lwawt_macosx_CImage 329 * Method: nativeResizeNSImageRepresentations 330 * Signature: (JDD)V 331 */ 332 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeResizeNSImageRepresentations 333 (JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h) 334 { 335 if (!image) return; 336 NSImage *i = (NSImage *)jlong_to_ptr(image); 337 338 JNF_COCOA_ENTER(env); 339 340 NSImageRep *imageRep = nil; 341 NSArray *imageRepresentations = [i representations]; 342 NSEnumerator *imageEnumerator = [imageRepresentations objectEnumerator]; 343 while ((imageRep = [imageEnumerator nextObject]) != nil) { 344 [imageRep setSize:NSMakeSize(w, h)]; 345 } 346 347 JNF_COCOA_EXIT(env); 348 } 349 350 NSComparisonResult getOrder(BOOL order){ 351 return (NSComparisonResult) (order ? NSOrderedAscending : NSOrderedDescending); 352 } 353 354 /* 355 * Class: sun_lwawt_macosx_CImage 356 * Method: nativeGetNSImageRepresentationsCount 357 * Signature: (JDD)[Ljava/awt/geom/Dimension2D; 358 */ 359 JNIEXPORT jobjectArray JNICALL Java_sun_lwawt_macosx_CImage_nativeGetNSImageRepresentationSizes 360 (JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h) 361 { 362 if (!image) return 0; 363 jobjectArray jreturnArray = NULL; 364 NSImage *img = (NSImage *)jlong_to_ptr(image); 365 366 JNF_COCOA_ENTER(env); 367 368 NSArray *imageRepresentations = [image representations]; 369 if([imageRepresentations count] == 0){ 370 return NULL; 371 } 372 373 NSArray *sortedImageRepresentations = [imageRepresentations sortedArrayUsingComparator: ^(id obj1, id obj2) { 374 375 NSImageRep *imageRep1 = (NSImageRep *) obj1; 376 NSImageRep *imageRep2 = (NSImageRep *) obj2; 377 NSSize size1 = [imageRep1 size]; 378 NSSize size2 = [imageRep2 size]; 379 380 if (NSEqualSizes(size1, size2)) { 381 return getOrder([imageRep1 pixelsWide] <= [imageRep2 pixelsWide] && 382 [imageRep1 pixelsHigh] <= [imageRep2 pixelsHigh]); 383 } 384 385 return getOrder(size1.width <= size2.width && size1.height <= size2.height); 386 }]; 387 388 NSMutableArray *sortedPixelSizes = [[NSMutableArray alloc] init]; 389 NSSize lastSize = [[sortedImageRepresentations lastObject] size]; 390 NSSize imageRepSize = NSZeroSize; 391 392 jsize i; 393 jsize count = [sortedImageRepresentations count]; 394 for(i = 0; i < count; i++){ 395 imageRepSize = [[sortedImageRepresentations objectAtIndex: i] size]; 396 397 if ((w <= imageRepSize.width && h <= imageRepSize.height) 398 || NSEqualSizes(imageRepSize, lastSize)) { 399 break; 400 } 401 } 402 403 NSSize bestFitSize = imageRepSize; 404 405 for(; i < count; i++){ 406 NSImageRep *imageRep = [sortedImageRepresentations objectAtIndex: i]; 407 408 if (!NSEqualSizes([imageRep size], bestFitSize)) { 409 break; 410 } 411 412 NSSize pixelSize = NSMakeSize([imageRep pixelsWide], [imageRep pixelsHigh]); 413 [sortedPixelSizes addObject: [NSValue valueWithSize: pixelSize]]; 414 } 415 416 count = [sortedPixelSizes count]; 417 static JNF_CLASS_CACHE(jc_Dimension, "java/awt/Dimension"); 418 jreturnArray = JNFNewObjectArray(env, &jc_Dimension, count); 419 420 for(i = 0; i < count; i++){ 421 NSSize pixelSize = [[sortedPixelSizes objectAtIndex: i] sizeValue]; 422 423 (*env)->SetObjectArrayElement(env, jreturnArray, i, NSToJavaSize(env, pixelSize)); 424 if ((*env)->ExceptionOccurred(env)) { 425 (*env)->ExceptionDescribe(env); 426 (*env)->ExceptionClear(env); 427 continue; 428 } 429 } 430 431 JNF_COCOA_EXIT(env); 432 433 return jreturnArray; 434 }