1 /* 2 * Copyright (c) 2011, 2014, 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 #import "jni_util.h" 26 27 #import <Cocoa/Cocoa.h> 28 #import <JavaNativeFoundation/JavaNativeFoundation.h> 29 30 #import "GeomUtilities.h" 31 #import "ThreadUtilities.h" 32 33 #import "sun_lwawt_macosx_CImage.h" 34 35 36 static void CImage_CopyArrayIntoNSImageRep 37 (jint *srcPixels, jint *dstPixels, int width, int height) 38 { 39 int x, y; 40 // TODO: test this on big endian systems (not sure if its correct)... 41 for (y = 0; y < height; y++) { 42 for (x = 0; x < width; x++) { 43 jint pix = srcPixels[x]; 44 jint a = (pix >> 24) & 0xff; 45 jint r = (pix >> 16) & 0xff; 46 jint g = (pix >> 8) & 0xff; 47 jint b = (pix ) & 0xff; 48 dstPixels[x] = (b << 24) | (g << 16) | (r << 8) | a; 49 } 50 srcPixels += width; // TODO: use explicit scanStride 51 dstPixels += width; 52 } 53 } 54 55 static void CImage_CopyNSImageIntoArray 56 (NSImage *srcImage, jint *dstPixels, NSRect fromRect, NSRect toRect) 57 { 58 int width = toRect.size.width; 59 int height = toRect.size.height; 60 CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); 61 CGContextRef cgRef = CGBitmapContextCreate(dstPixels, width, height, 62 8, width * 4, colorspace, 63 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); 64 CGColorSpaceRelease(colorspace); 65 NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:cgRef flipped:NO]; 66 CGContextRelease(cgRef); 67 NSGraphicsContext *oldContext = [[NSGraphicsContext currentContext] retain]; 68 [NSGraphicsContext setCurrentContext:context]; 69 [srcImage drawInRect:toRect 70 fromRect:fromRect 71 operation:NSCompositeSourceOver 72 fraction:1.0]; 73 [NSGraphicsContext setCurrentContext:oldContext]; 74 [oldContext release]; 75 } 76 77 static NSBitmapImageRep* CImage_CreateImageRep(JNIEnv *env, jintArray buffer, jint width, jint height) 78 { 79 NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 80 pixelsWide:width 81 pixelsHigh:height 82 bitsPerSample:8 83 samplesPerPixel:4 84 hasAlpha:YES 85 isPlanar:NO 86 colorSpaceName:NSDeviceRGBColorSpace 87 bitmapFormat:NSAlphaFirstBitmapFormat 88 bytesPerRow:width*4 // TODO: use explicit scanStride 89 bitsPerPixel:32]; 90 91 jint *imgData = (jint *)[imageRep bitmapData]; 92 if (imgData == NULL) return 0L; 93 94 jint *src = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL); 95 if (src == NULL) return 0L; 96 97 CImage_CopyArrayIntoNSImageRep(src, imgData, width, height); 98 99 (*env)->ReleasePrimitiveArrayCritical(env, buffer, src, JNI_ABORT); 100 101 return imageRep; 102 } 103 104 /* 105 * Class: sun_lwawt_macosx_CImage 106 * Method: nativeCreateNSImageFromArray 107 * Signature: ([III)J 108 */ 109 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromArray 110 (JNIEnv *env, jclass klass, jintArray buffer, jint width, jint height) 111 { 112 jlong result = 0L; 113 114 JNF_COCOA_ENTER(env); 115 116 NSBitmapImageRep* imageRep = CImage_CreateImageRep(env, buffer, width, height); 117 if (imageRep) { 118 NSImage *nsImage = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; 119 [nsImage addRepresentation:imageRep]; 120 [imageRep release]; 121 122 if (nsImage != nil) { 123 CFRetain(nsImage); // GC 124 } 125 126 result = ptr_to_jlong(nsImage); 127 } 128 129 JNF_COCOA_EXIT(env); 130 131 return result; 132 } 133 134 /* 135 * Class: sun_lwawt_macosx_CImage 136 * Method: nativeCreateNSImageFromArrays 137 * Signature: ([[I[I[I)J 138 */ 139 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromArrays 140 (JNIEnv *env, jclass klass, jobjectArray buffers, jintArray widths, jintArray heights) 141 { 142 jlong result = 0L; 143 144 JNF_COCOA_ENTER(env); 145 146 jsize num = (*env)->GetArrayLength(env, buffers); 147 NSMutableArray * reps = [NSMutableArray arrayWithCapacity: num]; 148 149 jint * ws = (*env)->GetIntArrayElements(env, widths, NULL); 150 if (ws != NULL) { 151 jint * hs = (*env)->GetIntArrayElements(env, heights, NULL); 152 if (hs != NULL) { 153 jsize i; 154 for (i = 0; i < num; i++) { 155 jintArray buffer = (*env)->GetObjectArrayElement(env, buffers, i); 156 157 NSBitmapImageRep* imageRep = CImage_CreateImageRep(env, buffer, ws[i], hs[i]); 158 if (imageRep) { 159 [reps addObject: imageRep]; 160 } 161 } 162 163 (*env)->ReleaseIntArrayElements(env, heights, hs, JNI_ABORT); 164 } 165 (*env)->ReleaseIntArrayElements(env, widths, ws, JNI_ABORT); 166 } 167 if ([reps count]) { 168 NSImage *nsImage = [[NSImage alloc] initWithSize:NSMakeSize(0, 0)]; 169 [nsImage addRepresentations: reps]; 170 171 if (nsImage != nil) { 172 CFRetain(nsImage); // GC 173 } 174 175 result = ptr_to_jlong(nsImage); 176 } 177 178 JNF_COCOA_EXIT(env); 179 180 return result; 181 } 182 183 /* 184 * Class: sun_lwawt_macosx_CImage 185 * Method: nativeCreateNSImageFromIconSelector 186 * Signature: (I)J 187 */ 188 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromIconSelector 189 (JNIEnv *env, jclass klass, jint selector) 190 { 191 NSImage *image = nil; 192 193 JNF_COCOA_ENTER(env); 194 195 IconRef iconRef; 196 if (noErr == GetIconRef(kOnSystemDisk, kSystemIconsCreator, selector, &iconRef)) { 197 image = [[NSImage alloc] initWithIconRef:iconRef]; 198 if (image) CFRetain(image); // GC 199 ReleaseIconRef(iconRef); 200 } 201 202 JNF_COCOA_EXIT(env); 203 204 return ptr_to_jlong(image); 205 } 206 207 /* 208 * Class: sun_lwawt_macosx_CImage 209 * Method: nativeCreateNSImageFromFileContents 210 * Signature: (Ljava/lang/String;)J 211 */ 212 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromFileContents 213 (JNIEnv *env, jclass klass, jstring file) 214 { 215 NSImage *image = nil; 216 217 JNF_COCOA_ENTER(env); 218 219 NSString *path = JNFNormalizedNSStringForPath(env, file); 220 image = [[NSImage alloc] initByReferencingFile:path]; 221 if (image) CFRetain(image); // GC 222 223 JNF_COCOA_EXIT(env); 224 225 return ptr_to_jlong(image); 226 } 227 228 /* 229 * Class: sun_lwawt_macosx_CImage 230 * Method: nativeCreateNSImageOfFileFromLaunchServices 231 * Signature: (Ljava/lang/String;)J 232 */ 233 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageOfFileFromLaunchServices 234 (JNIEnv *env, jclass klass, jstring file) 235 { 236 __block NSImage *image = nil; 237 238 JNF_COCOA_ENTER(env); 239 240 NSString *path = JNFNormalizedNSStringForPath(env, file); 241 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ 242 image = [[NSWorkspace sharedWorkspace] iconForFile:path]; 243 [image setScalesWhenResized:TRUE]; 244 if (image) CFRetain(image); // GC 245 }]; 246 247 JNF_COCOA_EXIT(env); 248 249 return ptr_to_jlong(image); 250 } 251 252 /* 253 * Class: sun_lwawt_macosx_CImage 254 * Method: nativeCreateNSImageFromImageName 255 * Signature: (Ljava/lang/String;)J 256 */ 257 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromImageName 258 (JNIEnv *env, jclass klass, jstring name) 259 { 260 NSImage *image = nil; 261 262 JNF_COCOA_ENTER(env); 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[IIIII)V 276 */ 277 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeCopyNSImageIntoArray 278 (JNIEnv *env, jclass klass, jlong nsImgPtr, jintArray buffer, jint sw, jint sh, 279 jint dw, jint dh) 280 { 281 JNF_COCOA_ENTER(env); 282 283 NSImage *img = (NSImage *)jlong_to_ptr(nsImgPtr); 284 jint *dst = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL); 285 if (dst) { 286 NSRect fromRect = NSMakeRect(0, 0, sw, sh); 287 NSRect toRect = NSMakeRect(0, 0, dw, dh); 288 CImage_CopyNSImageIntoArray(img, dst, fromRect, toRect); 289 (*env)->ReleasePrimitiveArrayCritical(env, buffer, dst, JNI_ABORT); 290 } 291 292 JNF_COCOA_EXIT(env); 293 } 294 295 /* 296 * Class: sun_lwawt_macosx_CImage 297 * Method: nativeGetNSImageSize 298 * Signature: (J)Ljava/awt/geom/Dimension2D; 299 */ 300 JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CImage_nativeGetNSImageSize 301 (JNIEnv *env, jclass klass, jlong nsImgPtr) 302 { 303 jobject size = NULL; 304 305 JNF_COCOA_ENTER(env); 306 307 size = NSToJavaSize(env, [(NSImage *)jlong_to_ptr(nsImgPtr) size]); 308 309 JNF_COCOA_EXIT(env); 310 311 return size; 312 } 313 314 /* 315 * Class: sun_lwawt_macosx_CImage 316 * Method: nativeSetNSImageSize 317 * Signature: (JDD)V 318 */ 319 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeSetNSImageSize 320 (JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h) 321 { 322 if (!image) return; 323 NSImage *i = (NSImage *)jlong_to_ptr(image); 324 325 JNF_COCOA_ENTER(env); 326 327 [i setScalesWhenResized:TRUE]; 328 [i setSize:NSMakeSize(w, h)]; 329 330 JNF_COCOA_EXIT(env); 331 } 332 333 /* 334 * Class: sun_lwawt_macosx_CImage 335 * Method: nativeResizeNSImageRepresentations 336 * Signature: (JDD)V 337 */ 338 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeResizeNSImageRepresentations 339 (JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h) 340 { 341 if (!image) return; 342 NSImage *i = (NSImage *)jlong_to_ptr(image); 343 344 JNF_COCOA_ENTER(env); 345 346 NSImageRep *imageRep = nil; 347 NSArray *imageRepresentations = [i representations]; 348 NSEnumerator *imageEnumerator = [imageRepresentations objectEnumerator]; 349 while ((imageRep = [imageEnumerator nextObject]) != nil) { 350 [imageRep setSize:NSMakeSize(w, h)]; 351 } 352 353 JNF_COCOA_EXIT(env); 354 } 355 356 NSComparisonResult getOrder(BOOL order){ 357 return (NSComparisonResult) (order ? NSOrderedAscending : NSOrderedDescending); 358 } 359 360 /* 361 * Class: sun_lwawt_macosx_CImage 362 * Method: nativeGetNSImageRepresentationsCount 363 * Signature: (JDD)[Ljava/awt/geom/Dimension2D; 364 */ 365 JNIEXPORT jobjectArray JNICALL 366 Java_sun_lwawt_macosx_CImage_nativeGetNSImageRepresentationSizes 367 (JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h) 368 { 369 if (!image) return NULL; 370 jobjectArray jreturnArray = NULL; 371 NSImage *img = (NSImage *)jlong_to_ptr(image); 372 373 JNF_COCOA_ENTER(env); 374 375 NSArray *imageRepresentations = [img representations]; 376 if([imageRepresentations count] == 0){ 377 return NULL; 378 } 379 380 NSArray *sortedImageRepresentations = [imageRepresentations 381 sortedArrayUsingComparator: ^(id obj1, id obj2) { 382 383 NSImageRep *imageRep1 = (NSImageRep *) obj1; 384 NSImageRep *imageRep2 = (NSImageRep *) obj2; 385 NSSize size1 = [imageRep1 size]; 386 NSSize size2 = [imageRep2 size]; 387 388 if (NSEqualSizes(size1, size2)) { 389 return getOrder([imageRep1 pixelsWide] <= [imageRep2 pixelsWide] && 390 [imageRep1 pixelsHigh] <= [imageRep2 pixelsHigh]); 391 } 392 393 return getOrder(size1.width <= size2.width && size1.height <= size2.height); 394 }]; 395 396 NSMutableArray *sortedPixelSizes = [[NSMutableArray alloc] init]; 397 NSSize lastSize = [[sortedImageRepresentations lastObject] size]; 398 399 NSUInteger i = [sortedImageRepresentations indexOfObjectPassingTest: 400 ^BOOL(id obj, NSUInteger idx, BOOL *stop) { 401 NSSize imageRepSize = [obj size]; 402 return (w <= imageRepSize.width && h <= imageRepSize.height) 403 || NSEqualSizes(imageRepSize, lastSize); 404 }]; 405 406 NSUInteger count = [sortedImageRepresentations count]; 407 i = (i == NSNotFound) ? count - 1 : i; 408 NSSize bestFitSize = [[sortedImageRepresentations objectAtIndex: i] size]; 409 410 for(; i < count; i++){ 411 NSImageRep *imageRep = [sortedImageRepresentations objectAtIndex: i]; 412 413 if (!NSEqualSizes([imageRep size], bestFitSize)) { 414 break; 415 } 416 417 NSSize pixelSize = NSMakeSize( 418 [imageRep pixelsWide], [imageRep pixelsHigh]); 419 [sortedPixelSizes addObject: [NSValue valueWithSize: pixelSize]]; 420 } 421 422 count = [sortedPixelSizes count]; 423 static JNF_CLASS_CACHE(jc_Dimension, "java/awt/Dimension"); 424 jreturnArray = JNFNewObjectArray(env, &jc_Dimension, count); 425 CHECK_NULL_RETURN(jreturnArray, NULL); 426 427 for(i = 0; i < count; i++){ 428 NSSize pixelSize = [[sortedPixelSizes objectAtIndex: i] sizeValue]; 429 430 (*env)->SetObjectArrayElement(env, jreturnArray, i, 431 NSToJavaSize(env, pixelSize)); 432 JNU_CHECK_EXCEPTION_RETURN(env, NULL); 433 } 434 435 JNF_COCOA_EXIT(env); 436 437 return jreturnArray; 438 } 439 440 /* 441 * Class: sun_lwawt_macosx_CImage 442 * Method: nativeGetPlatformImageBytes 443 * Signature: ([III)[B 444 */ 445 JNIEXPORT jbyteArray JNICALL Java_sun_lwawt_macosx_CImage_nativeGetPlatformImageBytes 446 (JNIEnv *env, jclass klass, jintArray buffer, jint width, jint height) 447 { 448 jbyteArray result = 0L; 449 450 JNF_COCOA_ENTER(env); 451 452 NSBitmapImageRep* imageRep = CImage_CreateImageRep(env, buffer, width, height); 453 if (imageRep) { 454 NSData *tiffImage = [imageRep TIFFRepresentation]; 455 jsize tiffSize = (jsize)[tiffImage length]; 456 result = (*env)->NewByteArray(env, tiffSize); 457 CHECK_NULL_RETURN(result, nil); 458 jbyte *tiffData = (jbyte *)(*env)->GetPrimitiveArrayCritical(env, result, 0); 459 CHECK_NULL_RETURN(tiffData, nil); 460 [tiffImage getBytes:tiffData]; 461 (*env)->ReleasePrimitiveArrayCritical(env, result, tiffData, 0); 462 [imageRep release]; 463 } 464 465 JNF_COCOA_EXIT(env); 466 467 return result; 468 } 469 470 /* 471 * Class: sun_lwawt_macosx_CImage 472 * Method: nativeCreateNSImageFromBytes 473 * Signature: ([B)J 474 */ 475 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromBytes 476 (JNIEnv *env, jclass klass, jbyteArray sourceData) 477 { 478 jlong result = 0L; 479 CHECK_NULL_RETURN(sourceData, 0L); 480 481 JNF_COCOA_ENTER(env); 482 483 jsize sourceSize = (*env)->GetArrayLength(env, sourceData); 484 if (sourceSize == 0) return 0L; 485 486 jbyte *sourceBytes = (*env)->GetPrimitiveArrayCritical(env, sourceData, NULL); 487 CHECK_NULL_RETURN(sourceBytes, 0L); 488 NSData *rawData = [NSData dataWithBytes:sourceBytes length:sourceSize]; 489 490 NSImage *newImage = [[NSImage alloc] initWithData:rawData]; 491 if (newImage) CFRetain(newImage); // GC 492 [newImage release]; 493 494 (*env)->ReleasePrimitiveArrayCritical(env, sourceData, sourceBytes, JNI_ABORT); 495 CHECK_NULL_RETURN(newImage, 0L); 496 497 result = ptr_to_jlong(newImage); 498 JNF_COCOA_EXIT(env); 499 500 return result; 501 } 502