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 36static 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 55static 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 77static 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 */ 109JNIEXPORT 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 114JNF_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 123JNF_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 */ 133JNIEXPORT 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 138JNF_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 167JNF_COCOA_EXIT(env); 168 169 return result; 170} 171 172/* 173 * Class: sun_lwawt_macosx_CImage 174 * Method: nativeCreateNSImageFromIconSelector 175 * Signature: (I)J 176 */ 177JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromIconSelector 178(JNIEnv *env, jclass klass, jint selector) 179{ 180 NSImage *image = nil; 181 182JNF_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 190JNF_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 */ 200JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromFileContents 201(JNIEnv *env, jclass klass, jstring file) 202{ 203 NSImage *image = nil; 204 205JNF_COCOA_ENTER(env); 206 207 NSString *path = JNFNormalizedNSStringForPath(env, file); 208 image = [[NSImage alloc] initByReferencingFile:path]; 209 210JNF_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 */ 220JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageOfFileFromLaunchServices 221(JNIEnv *env, jclass klass, jstring file) 222{ 223 __block NSImage *image = nil; 224 225JNF_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 233JNF_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 */ 243JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromImageName 244(JNIEnv *env, jclass klass, jstring name) 245{ 246 NSImage *image = nil; 247 248JNF_COCOA_ENTER(env); 249 250 image = [[NSImage imageNamed:JNFJavaToNSString(env, name)] retain]; 251 252JNF_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 */ 262JNIEXPORT 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{ 266JNF_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 277JNF_COCOA_EXIT(env); 278} 279 280/* 281 * Class: sun_lwawt_macosx_CImage 282 * Method: nativeGetNSImageSize 283 * Signature: (J)Ljava/awt/geom/Dimension2D; 284 */ 285JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CImage_nativeGetNSImageSize 286(JNIEnv *env, jclass klass, jlong nsImgPtr) 287{ 288 jobject size = NULL; 289 290JNF_COCOA_ENTER(env); 291 292 size = NSToJavaSize(env, [(NSImage *)jlong_to_ptr(nsImgPtr) size]); 293 294JNF_COCOA_EXIT(env); 295 296 return size; 297} 298 299/* 300 * Class: sun_lwawt_macosx_CImage 301 * Method: nativeSetNSImageSize 302 * Signature: (JDD)V 303 */ 304JNIEXPORT 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 310JNF_COCOA_ENTER(env); 311 312 [i setScalesWhenResized:TRUE]; 313 [i setSize:NSMakeSize(w, h)]; 314 315JNF_COCOA_EXIT(env); 316} 317 318/* 319 * Class: sun_lwawt_macosx_CImage 320 * Method: nativeResizeNSImageRepresentations 321 * Signature: (JDD)V 322 */ 323JNIEXPORT 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 329JNF_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 338JNF_COCOA_EXIT(env); 339} 340 341NSComparisonResult 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 */ 350JNIEXPORT 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 358JNF_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 420JNF_COCOA_EXIT(env); 421 422 return jreturnArray; 423} 424 425/* 426 * Class: sun_lwawt_macosx_CImage 427 * Method: nativeGetPlatformImageBytes 428 * Signature: ([III)[B 429 */ 430JNIEXPORT 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 */ 459JNIEXPORT 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} 483