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] autorelease]; 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 result = ptr_to_jlong(nsImage); 121 } 122 123 JNF_COCOA_EXIT(env); 124 125 return result; 126 } 127 128 /* 129 * Class: sun_lwawt_macosx_CImage 130 * Method: nativeCreateNSImageFromArrays 131 * Signature: ([[I[I[I)J 132 */ 133 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromArrays 134 (JNIEnv *env, jclass klass, jobjectArray buffers, jintArray widths, jintArray heights) 135 { 136 jlong result = 0L; 137 138 JNF_COCOA_ENTER(env); 139 140 jsize num = (*env)->GetArrayLength(env, buffers); 141 NSMutableArray * reps = [NSMutableArray arrayWithCapacity: num]; 142 143 jint * ws = (*env)->GetIntArrayElements(env, widths, NULL); 144 if (ws != NULL) { 145 jint * hs = (*env)->GetIntArrayElements(env, heights, NULL); 146 if (hs != NULL) { 147 jsize i; 148 for (i = 0; i < num; i++) { 149 jintArray buffer = (*env)->GetObjectArrayElement(env, buffers, i); 150 151 NSBitmapImageRep* imageRep = CImage_CreateImageRep(env, buffer, ws[i], hs[i]); 152 if (imageRep) { 153 [reps addObject: imageRep]; 154 } 155 } 156 157 (*env)->ReleaseIntArrayElements(env, heights, hs, JNI_ABORT); 158 } 159 (*env)->ReleaseIntArrayElements(env, widths, ws, JNI_ABORT); 160 } 161 if ([reps count]) { 162 NSImage *nsImage = [[NSImage alloc] initWithSize:NSMakeSize(0, 0)]; 163 [nsImage addRepresentations: reps]; 164 result = ptr_to_jlong(nsImage); 165 } 166 167 JNF_COCOA_EXIT(env); 168 169 return result; 170 } 171 172 /* 173 * Class: sun_lwawt_macosx_CImage 174 * Method: nativeCreateNSImageFromIconSelector 175 * Signature: (I)J 176 */ 177 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromIconSelector 178 (JNIEnv *env, jclass klass, jint selector) 179 { 180 NSImage *image = nil; 181 182 JNF_COCOA_ENTER(env); 183 184 IconRef iconRef; 185 if (noErr == GetIconRef(kOnSystemDisk, kSystemIconsCreator, selector, &iconRef)) { 186 image = [[NSImage alloc] initWithIconRef:iconRef]; 187 ReleaseIconRef(iconRef); 188 } 189 190 JNF_COCOA_EXIT(env); 191 192 return ptr_to_jlong(image); 193 } 194 195 /* 196 * Class: sun_lwawt_macosx_CImage 197 * Method: nativeCreateNSImageFromFileContents 198 * Signature: (Ljava/lang/String;)J 199 */ 200 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromFileContents 201 (JNIEnv *env, jclass klass, jstring file) 202 { 203 NSImage *image = nil; 204 205 JNF_COCOA_ENTER(env); 206 207 NSString *path = JNFNormalizedNSStringForPath(env, file); 208 image = [[NSImage alloc] initByReferencingFile:path]; 209 210 JNF_COCOA_EXIT(env); 211 212 return ptr_to_jlong(image); 213 } 214 215 /* 216 * Class: sun_lwawt_macosx_CImage 217 * Method: nativeCreateNSImageOfFileFromLaunchServices 218 * Signature: (Ljava/lang/String;)J 219 */ 220 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageOfFileFromLaunchServices 221 (JNIEnv *env, jclass klass, jstring file) 222 { 223 __block NSImage *image = nil; 224 225 JNF_COCOA_ENTER(env); 226 227 NSString *path = JNFNormalizedNSStringForPath(env, file); 228 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ 229 image = [[[NSWorkspace sharedWorkspace] iconForFile:path] retain]; 230 [image setScalesWhenResized:TRUE]; 231 }]; 232 233 JNF_COCOA_EXIT(env); 234 235 return ptr_to_jlong(image); 236 } 237 238 /* 239 * Class: sun_lwawt_macosx_CImage 240 * Method: nativeCreateNSImageFromImageName 241 * Signature: (Ljava/lang/String;)J 242 */ 243 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromImageName 244 (JNIEnv *env, jclass klass, jstring name) 245 { 246 NSImage *image = nil; 247 248 JNF_COCOA_ENTER(env); 249 250 image = [[NSImage imageNamed:JNFJavaToNSString(env, name)] retain]; 251 252 JNF_COCOA_EXIT(env); 253 254 return ptr_to_jlong(image); 255 } 256 257 /* 258 * Class: sun_lwawt_macosx_CImage 259 * Method: nativeCopyNSImageIntoArray 260 * Signature: (J[IIIII)V 261 */ 262 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeCopyNSImageIntoArray 263 (JNIEnv *env, jclass klass, jlong nsImgPtr, jintArray buffer, jint sw, jint sh, 264 jint dw, jint dh) 265 { 266 JNF_COCOA_ENTER(env); 267 268 NSImage *img = (NSImage *)jlong_to_ptr(nsImgPtr); 269 jint *dst = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL); 270 if (dst) { 271 NSRect fromRect = NSMakeRect(0, 0, sw, sh); 272 NSRect toRect = NSMakeRect(0, 0, dw, dh); 273 CImage_CopyNSImageIntoArray(img, dst, fromRect, toRect); 274 (*env)->ReleasePrimitiveArrayCritical(env, buffer, dst, JNI_ABORT); 275 } 276 277 JNF_COCOA_EXIT(env); 278 } 279 280 /* 281 * Class: sun_lwawt_macosx_CImage 282 * Method: nativeGetNSImageSize 283 * Signature: (J)Ljava/awt/geom/Dimension2D; 284 */ 285 JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CImage_nativeGetNSImageSize 286 (JNIEnv *env, jclass klass, jlong nsImgPtr) 287 { 288 jobject size = NULL; 289 290 JNF_COCOA_ENTER(env); 291 292 size = NSToJavaSize(env, [(NSImage *)jlong_to_ptr(nsImgPtr) size]); 293 294 JNF_COCOA_EXIT(env); 295 296 return size; 297 } 298 299 /* 300 * Class: sun_lwawt_macosx_CImage 301 * Method: nativeSetNSImageSize 302 * Signature: (JDD)V 303 */ 304 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeSetNSImageSize 305 (JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h) 306 { 307 if (!image) return; 308 NSImage *i = (NSImage *)jlong_to_ptr(image); 309 310 JNF_COCOA_ENTER(env); 311 312 [i setScalesWhenResized:TRUE]; 313 [i setSize:NSMakeSize(w, h)]; 314 315 JNF_COCOA_EXIT(env); 316 } 317 318 /* 319 * Class: sun_lwawt_macosx_CImage 320 * Method: nativeResizeNSImageRepresentations 321 * Signature: (JDD)V 322 */ 323 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeResizeNSImageRepresentations 324 (JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h) 325 { 326 if (!image) return; 327 NSImage *i = (NSImage *)jlong_to_ptr(image); 328 329 JNF_COCOA_ENTER(env); 330 331 NSImageRep *imageRep = nil; 332 NSArray *imageRepresentations = [i representations]; 333 NSEnumerator *imageEnumerator = [imageRepresentations objectEnumerator]; 334 while ((imageRep = [imageEnumerator nextObject]) != nil) { 335 [imageRep setSize:NSMakeSize(w, h)]; 336 } 337 338 JNF_COCOA_EXIT(env); 339 } 340 341 NSComparisonResult getOrder(BOOL order){ 342 return (NSComparisonResult) (order ? NSOrderedAscending : NSOrderedDescending); 343 } 344 345 /* 346 * Class: sun_lwawt_macosx_CImage 347 * Method: nativeGetNSImageRepresentationsCount 348 * Signature: (JDD)[Ljava/awt/geom/Dimension2D; 349 */ 350 JNIEXPORT jobjectArray JNICALL 351 Java_sun_lwawt_macosx_CImage_nativeGetNSImageRepresentationSizes 352 (JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h) 353 { 354 if (!image) return NULL; 355 jobjectArray jreturnArray = NULL; 356 NSImage *img = (NSImage *)jlong_to_ptr(image); 357 358 JNF_COCOA_ENTER(env); 359 360 NSArray *imageRepresentations = [img representations]; 361 if([imageRepresentations count] == 0){ 362 return NULL; 363 } 364 365 NSArray *sortedImageRepresentations = [imageRepresentations 366 sortedArrayUsingComparator: ^(id obj1, id obj2) { 367 368 NSImageRep *imageRep1 = (NSImageRep *) obj1; 369 NSImageRep *imageRep2 = (NSImageRep *) obj2; 370 NSSize size1 = [imageRep1 size]; 371 NSSize size2 = [imageRep2 size]; 372 373 if (NSEqualSizes(size1, size2)) { 374 return getOrder([imageRep1 pixelsWide] <= [imageRep2 pixelsWide] && 375 [imageRep1 pixelsHigh] <= [imageRep2 pixelsHigh]); 376 } 377 378 return getOrder(size1.width <= size2.width && size1.height <= size2.height); 379 }]; 380 381 NSMutableArray *sortedPixelSizes = [[[NSMutableArray alloc] init] autorelease]; 382 NSSize lastSize = [[sortedImageRepresentations lastObject] size]; 383 384 NSUInteger i = [sortedImageRepresentations indexOfObjectPassingTest: 385 ^BOOL(id obj, NSUInteger idx, BOOL *stop) { 386 NSSize imageRepSize = [obj size]; 387 return (w <= imageRepSize.width && h <= imageRepSize.height) 388 || NSEqualSizes(imageRepSize, lastSize); 389 }]; 390 391 NSUInteger count = [sortedImageRepresentations count]; 392 i = (i == NSNotFound) ? count - 1 : i; 393 NSSize bestFitSize = [[sortedImageRepresentations objectAtIndex: i] size]; 394 395 for(; i < count; i++){ 396 NSImageRep *imageRep = [sortedImageRepresentations objectAtIndex: i]; 397 398 if (!NSEqualSizes([imageRep size], bestFitSize)) { 399 break; 400 } 401 402 NSSize pixelSize = NSMakeSize( 403 [imageRep pixelsWide], [imageRep pixelsHigh]); 404 [sortedPixelSizes addObject: [NSValue valueWithSize: pixelSize]]; 405 } 406 407 count = [sortedPixelSizes count]; 408 static JNF_CLASS_CACHE(jc_Dimension, "java/awt/Dimension"); 409 jreturnArray = JNFNewObjectArray(env, &jc_Dimension, count); 410 CHECK_NULL_RETURN(jreturnArray, NULL); 411 412 for(i = 0; i < count; i++){ 413 NSSize pixelSize = [[sortedPixelSizes objectAtIndex: i] sizeValue]; 414 415 (*env)->SetObjectArrayElement(env, jreturnArray, i, 416 NSToJavaSize(env, pixelSize)); 417 JNU_CHECK_EXCEPTION_RETURN(env, NULL); 418 } 419 420 JNF_COCOA_EXIT(env); 421 422 return jreturnArray; 423 } 424 425 /* 426 * Class: sun_lwawt_macosx_CImage 427 * Method: nativeGetPlatformImageBytes 428 * Signature: ([III)[B 429 */ 430 JNIEXPORT jbyteArray JNICALL Java_sun_lwawt_macosx_CImage_nativeGetPlatformImageBytes 431 (JNIEnv *env, jclass klass, jintArray buffer, jint width, jint height) 432 { 433 jbyteArray result = 0L; 434 435 JNF_COCOA_ENTER(env); 436 437 NSBitmapImageRep* imageRep = CImage_CreateImageRep(env, buffer, width, height); 438 if (imageRep) { 439 NSData *tiffImage = [imageRep TIFFRepresentation]; 440 jsize tiffSize = (jsize)[tiffImage length]; 441 result = (*env)->NewByteArray(env, tiffSize); 442 CHECK_NULL_RETURN(result, nil); 443 jbyte *tiffData = (jbyte *)(*env)->GetPrimitiveArrayCritical(env, result, 0); 444 CHECK_NULL_RETURN(tiffData, nil); 445 [tiffImage getBytes:tiffData]; 446 (*env)->ReleasePrimitiveArrayCritical(env, result, tiffData, 0); 447 } 448 449 JNF_COCOA_EXIT(env); 450 451 return result; 452 } 453 454 /* 455 * Class: sun_lwawt_macosx_CImage 456 * Method: nativeCreateNSImageFromBytes 457 * Signature: ([B)J 458 */ 459 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromBytes 460 (JNIEnv *env, jclass klass, jbyteArray sourceData) 461 { 462 jlong result = 0L; 463 CHECK_NULL_RETURN(sourceData, 0L); 464 465 JNF_COCOA_ENTER(env); 466 467 jsize sourceSize = (*env)->GetArrayLength(env, sourceData); 468 if (sourceSize == 0) return 0L; 469 470 jbyte *sourceBytes = (*env)->GetPrimitiveArrayCritical(env, sourceData, NULL); 471 CHECK_NULL_RETURN(sourceBytes, 0L); 472 NSData *rawData = [NSData dataWithBytes:sourceBytes length:sourceSize]; 473 NSImage *newImage = [[NSImage alloc] initWithData:rawData]; 474 475 (*env)->ReleasePrimitiveArrayCritical(env, sourceData, sourceBytes, JNI_ABORT); 476 CHECK_NULL_RETURN(newImage, 0L); 477 478 result = ptr_to_jlong(newImage); 479 JNF_COCOA_EXIT(env); 480 481 return result; 482 }