blob: 9467e173f7c48428a484604949f3aad9a95af9cd [file] [log] [blame]
/*
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "jni_util.h"
#import <Cocoa/Cocoa.h>
#import <JavaNativeFoundation/JavaNativeFoundation.h>
#import "GeomUtilities.h"
#import "ThreadUtilities.h"
#import "sun_lwawt_macosx_CImage.h"
static void CImage_CopyArrayIntoNSImageRep
(jint *srcPixels, jint *dstPixels, int width, int height)
{
int x, y;
// TODO: test this on big endian systems (not sure if its correct)...
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
jint pix = srcPixels[x];
jint a = (pix >> 24) & 0xff;
jint r = (pix >> 16) & 0xff;
jint g = (pix >> 8) & 0xff;
jint b = (pix ) & 0xff;
dstPixels[x] = (b << 24) | (g << 16) | (r << 8) | a;
}
srcPixels += width; // TODO: use explicit scanStride
dstPixels += width;
}
}
static void CImage_CopyNSImageIntoArray
(NSImage *srcImage, jint *dstPixels, NSRect fromRect, NSRect toRect)
{
int width = toRect.size.width;
int height = toRect.size.height;
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGContextRef cgRef = CGBitmapContextCreate(dstPixels, width, height,
8, width * 4, colorspace,
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
CGColorSpaceRelease(colorspace);
NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:cgRef flipped:NO];
CGContextRelease(cgRef);
NSGraphicsContext *oldContext = [[NSGraphicsContext currentContext] retain];
[NSGraphicsContext setCurrentContext:context];
[srcImage drawInRect:toRect
fromRect:fromRect
operation:NSCompositeSourceOver
fraction:1.0];
[NSGraphicsContext setCurrentContext:oldContext];
[oldContext release];
}
static NSBitmapImageRep* CImage_CreateImageRep(JNIEnv *env, jintArray buffer, jint width, jint height)
{
NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:width
pixelsHigh:height
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bitmapFormat:NSAlphaFirstBitmapFormat
bytesPerRow:width*4 // TODO: use explicit scanStride
bitsPerPixel:32];
jint *imgData = (jint *)[imageRep bitmapData];
if (imgData == NULL) return 0L;
jint *src = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL);
if (src == NULL) return 0L;
CImage_CopyArrayIntoNSImageRep(src, imgData, width, height);
(*env)->ReleasePrimitiveArrayCritical(env, buffer, src, JNI_ABORT);
return imageRep;
}
/*
* Class: sun_lwawt_macosx_CImage
* Method: nativeCreateNSImageFromArray
* Signature: ([III)J
*/
JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromArray
(JNIEnv *env, jclass klass, jintArray buffer, jint width, jint height)
{
jlong result = 0L;
JNF_COCOA_ENTER(env);
NSBitmapImageRep* imageRep = CImage_CreateImageRep(env, buffer, width, height);
if (imageRep) {
NSImage *nsImage = [[[NSImage alloc] initWithSize:NSMakeSize(width, height)] retain];
[nsImage addRepresentation:imageRep];
[imageRep release];
result = ptr_to_jlong(nsImage);
}
JNF_COCOA_EXIT(env);
return result;
}
/*
* Class: sun_lwawt_macosx_CImage
* Method: nativeCreateNSImageFromArrays
* Signature: ([[I[I[I)J
*/
JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromArrays
(JNIEnv *env, jclass klass, jobjectArray buffers, jintArray widths, jintArray heights)
{
jlong result = 0L;
JNF_COCOA_ENTER(env);
jsize num = (*env)->GetArrayLength(env, buffers);
NSMutableArray * reps = [NSMutableArray arrayWithCapacity: num];
jint * ws = (*env)->GetIntArrayElements(env, widths, NULL);
if (ws != NULL) {
jint * hs = (*env)->GetIntArrayElements(env, heights, NULL);
if (hs != NULL) {
jsize i;
for (i = 0; i < num; i++) {
jintArray buffer = (*env)->GetObjectArrayElement(env, buffers, i);
NSBitmapImageRep* imageRep = CImage_CreateImageRep(env, buffer, ws[i], hs[i]);
if (imageRep) {
[reps addObject: imageRep];
}
}
(*env)->ReleaseIntArrayElements(env, heights, hs, JNI_ABORT);
}
(*env)->ReleaseIntArrayElements(env, widths, ws, JNI_ABORT);
}
if ([reps count]) {
NSImage *nsImage = [[[NSImage alloc] initWithSize:NSMakeSize(0, 0)] retain];
[nsImage addRepresentations: reps];
result = ptr_to_jlong(nsImage);
}
JNF_COCOA_EXIT(env);
return result;
}
/*
* Class: sun_lwawt_macosx_CImage
* Method: nativeCreateNSImageFromIconSelector
* Signature: (I)J
*/
JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromIconSelector
(JNIEnv *env, jclass klass, jint selector)
{
NSImage *image = nil;
JNF_COCOA_ENTER(env);
IconRef iconRef;
if (noErr == GetIconRef(kOnSystemDisk, kSystemIconsCreator, selector, &iconRef)) {
image = [[[NSImage alloc] initWithIconRef:iconRef] retain];
ReleaseIconRef(iconRef);
}
JNF_COCOA_EXIT(env);
return ptr_to_jlong(image);
}
/*
* Class: sun_lwawt_macosx_CImage
* Method: nativeCreateNSImageFromFileContents
* Signature: (Ljava/lang/String;)J
*/
JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromFileContents
(JNIEnv *env, jclass klass, jstring file)
{
NSImage *image = nil;
JNF_COCOA_ENTER(env);
NSString *path = JNFNormalizedNSStringForPath(env, file);
image = [[[NSImage alloc] initByReferencingFile:path] retain];
JNF_COCOA_EXIT(env);
return ptr_to_jlong(image);
}
/*
* Class: sun_lwawt_macosx_CImage
* Method: nativeCreateNSImageOfFileFromLaunchServices
* Signature: (Ljava/lang/String;)J
*/
JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageOfFileFromLaunchServices
(JNIEnv *env, jclass klass, jstring file)
{
__block NSImage *image = nil;
JNF_COCOA_ENTER(env);
NSString *path = JNFNormalizedNSStringForPath(env, file);
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
image = [[[NSWorkspace sharedWorkspace] iconForFile:path] retain];
[image setScalesWhenResized:TRUE];
}];
JNF_COCOA_EXIT(env);
return ptr_to_jlong(image);
}
/*
* Class: sun_lwawt_macosx_CImage
* Method: nativeCreateNSImageFromImageName
* Signature: (Ljava/lang/String;)J
*/
JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromImageName
(JNIEnv *env, jclass klass, jstring name)
{
NSImage *image = nil;
JNF_COCOA_ENTER(env);
image = [[NSImage imageNamed:JNFJavaToNSString(env, name)] retain];
JNF_COCOA_EXIT(env);
return ptr_to_jlong(image);
}
/*
* Class: sun_lwawt_macosx_CImage
* Method: nativeCopyNSImageIntoArray
* Signature: (J[III)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeCopyNSImageIntoArray
(JNIEnv *env, jclass klass, jlong nsImgPtr, jintArray buffer, jint dw, jint dh)
{
JNF_COCOA_ENTER(env);
NSImage *img = (NSImage *)jlong_to_ptr(nsImgPtr);
jint *dst = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL);
if (dst) {
NSSize size = [(NSImage *)jlong_to_ptr(nsImgPtr) size];
NSRect fromRect = NSMakeRect(0, 0, size.width, size.height);
NSRect toRect = NSMakeRect(0, 0, dw, dh);
CImage_CopyNSImageIntoArray(img, dst, fromRect, toRect);
(*env)->ReleasePrimitiveArrayCritical(env, buffer, dst, JNI_ABORT);
}
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CImage
* Method: nativeGetNSImageSize
* Signature: (J)Ljava/awt/geom/Dimension2D;
*/
JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CImage_nativeGetNSImageSize
(JNIEnv *env, jclass klass, jlong nsImgPtr)
{
jobject size = NULL;
JNF_COCOA_ENTER(env);
size = NSToJavaSize(env, [(NSImage *)jlong_to_ptr(nsImgPtr) size]);
JNF_COCOA_EXIT(env);
return size;
}
/*
* Class: sun_lwawt_macosx_CImage
* Method: nativeSetNSImageSize
* Signature: (JDD)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeSetNSImageSize
(JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h)
{
if (!image) return;
NSImage *i = (NSImage *)jlong_to_ptr(image);
JNF_COCOA_ENTER(env);
[i setScalesWhenResized:TRUE];
[i setSize:NSMakeSize(w, h)];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CImage
* Method: nativeResizeNSImageRepresentations
* Signature: (JDD)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CImage_nativeResizeNSImageRepresentations
(JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h)
{
if (!image) return;
NSImage *i = (NSImage *)jlong_to_ptr(image);
JNF_COCOA_ENTER(env);
NSImageRep *imageRep = nil;
NSArray *imageRepresentations = [i representations];
NSEnumerator *imageEnumerator = [imageRepresentations objectEnumerator];
while ((imageRep = [imageEnumerator nextObject]) != nil) {
[imageRep setSize:NSMakeSize(w, h)];
}
JNF_COCOA_EXIT(env);
}
NSComparisonResult getOrder(BOOL order){
return (NSComparisonResult) (order ? NSOrderedAscending : NSOrderedDescending);
}
/*
* Class: sun_lwawt_macosx_CImage
* Method: nativeGetNSImageRepresentationsCount
* Signature: (JDD)[Ljava/awt/geom/Dimension2D;
*/
JNIEXPORT jobjectArray JNICALL
Java_sun_lwawt_macosx_CImage_nativeGetNSImageRepresentationSizes
(JNIEnv *env, jclass clazz, jlong image, jdouble w, jdouble h)
{
if (!image) return NULL;
jobjectArray jreturnArray = NULL;
NSImage *img = (NSImage *)jlong_to_ptr(image);
JNF_COCOA_ENTER(env);
NSArray *imageRepresentations = [img representations];
if([imageRepresentations count] == 0){
return NULL;
}
NSArray *sortedImageRepresentations = [imageRepresentations
sortedArrayUsingComparator: ^(id obj1, id obj2) {
NSImageRep *imageRep1 = (NSImageRep *) obj1;
NSImageRep *imageRep2 = (NSImageRep *) obj2;
NSSize size1 = [imageRep1 size];
NSSize size2 = [imageRep2 size];
if (NSEqualSizes(size1, size2)) {
return getOrder([imageRep1 pixelsWide] <= [imageRep2 pixelsWide] &&
[imageRep1 pixelsHigh] <= [imageRep2 pixelsHigh]);
}
return getOrder(size1.width <= size2.width && size1.height <= size2.height);
}];
NSMutableArray *sortedPixelSizes = [[[NSMutableArray alloc] init] autorelease];
NSSize lastSize = [[sortedImageRepresentations lastObject] size];
NSUInteger i = [sortedImageRepresentations indexOfObjectPassingTest:
^BOOL(id obj, NSUInteger idx, BOOL *stop) {
NSSize imageRepSize = [obj size];
return (w <= imageRepSize.width && h <= imageRepSize.height)
|| NSEqualSizes(imageRepSize, lastSize);
}];
NSUInteger count = [sortedImageRepresentations count];
i = (i == NSNotFound) ? count - 1 : i;
NSSize bestFitSize = [[sortedImageRepresentations objectAtIndex: i] size];
for(; i < count; i++){
NSImageRep *imageRep = [sortedImageRepresentations objectAtIndex: i];
if (!NSEqualSizes([imageRep size], bestFitSize)) {
break;
}
NSSize pixelSize = NSMakeSize(
[imageRep pixelsWide], [imageRep pixelsHigh]);
[sortedPixelSizes addObject: [NSValue valueWithSize: pixelSize]];
}
count = [sortedPixelSizes count];
static JNF_CLASS_CACHE(jc_Dimension, "java/awt/Dimension");
jreturnArray = JNFNewObjectArray(env, &jc_Dimension, count);
CHECK_NULL_RETURN(jreturnArray, NULL);
for(i = 0; i < count; i++){
NSSize pixelSize = [[sortedPixelSizes objectAtIndex: i] sizeValue];
(*env)->SetObjectArrayElement(env, jreturnArray, i,
NSToJavaSize(env, pixelSize));
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
}
JNF_COCOA_EXIT(env);
return jreturnArray;
}
/*
* Class: sun_lwawt_macosx_CImage
* Method: nativeGetPlatformImageBytes
* Signature: ([III)[B
*/
JNIEXPORT jbyteArray JNICALL Java_sun_lwawt_macosx_CImage_nativeGetPlatformImageBytes
(JNIEnv *env, jclass klass, jintArray buffer, jint width, jint height)
{
jbyteArray result = 0L;
JNF_COCOA_ENTER(env);
NSBitmapImageRep* imageRep = [CImage_CreateImageRep(env, buffer, width, height) autorelease];
if (imageRep) {
NSData *tiffImage = [imageRep TIFFRepresentation];
jsize tiffSize = (jsize)[tiffImage length];
result = (*env)->NewByteArray(env, tiffSize);
CHECK_NULL_RETURN(result, nil);
jbyte *tiffData = (jbyte *)(*env)->GetPrimitiveArrayCritical(env, result, 0);
CHECK_NULL_RETURN(tiffData, nil);
[tiffImage getBytes:tiffData];
(*env)->ReleasePrimitiveArrayCritical(env, result, tiffData, 0);
}
JNF_COCOA_EXIT(env);
return result;
}
/*
* Class: sun_lwawt_macosx_CImage
* Method: nativeCreateNSImageFromBytes
* Signature: ([B)J
*/
JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CImage_nativeCreateNSImageFromBytes
(JNIEnv *env, jclass klass, jbyteArray sourceData)
{
jlong result = 0L;
CHECK_NULL_RETURN(sourceData, 0L);
JNF_COCOA_ENTER(env);
jsize sourceSize = (*env)->GetArrayLength(env, sourceData);
if (sourceSize == 0) return 0L;
jbyte *sourceBytes = (*env)->GetPrimitiveArrayCritical(env, sourceData, NULL);
CHECK_NULL_RETURN(sourceBytes, 0L);
NSData *rawData = [NSData dataWithBytes:sourceBytes length:sourceSize];
NSImage *newImage = [[NSImage alloc] initWithData:rawData];
(*env)->ReleasePrimitiveArrayCritical(env, sourceData, sourceBytes, JNI_ABORT);
CHECK_NULL_RETURN(newImage, 0L);
result = ptr_to_jlong(newImage);
JNF_COCOA_EXIT(env);
return result;
}