1 /*
   2  * Copyright (c) 2011, 2013, 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 <JavaNativeFoundation/JavaNativeFoundation.h>
  27 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
  28 
  29 #import "apple_laf_JRSUIControl.h"
  30 #import "apple_laf_JRSUIConstants_DoubleValue.h"
  31 #import "apple_laf_JRSUIConstants_Hit.h"
  32 
  33 #import "JRSUIConstantSync.h"
  34 
  35 
  36 static JRSUIRendererRef gRenderer;
  37 
  38 /*
  39  * Class:     apple_laf_JRSUIControl
  40  * Method:    initNativeJRSUI
  41  * Signature: ()I
  42  */
  43 JNIEXPORT jint JNICALL Java_apple_laf_JRSUIControl_initNativeJRSUI
  44 (JNIEnv *env, jclass clazz)
  45 {
  46     BOOL coherent = _InitializeJRSProperties();
  47     if (!coherent) return apple_laf_JRSUIControl_INCOHERENT;
  48 
  49     gRenderer = JRSUIRendererCreate();
  50     if (gRenderer == NULL) return apple_laf_JRSUIControl_NULL_PTR;
  51 
  52     return apple_laf_JRSUIControl_SUCCESS;
  53 }
  54 
  55 /*
  56  * Class:     apple_laf_JRSUIControl
  57  * Method:    getPtrOfBuffer
  58  * Signature: (Ljava/nio/ByteBuffer;)J
  59  */
  60 JNIEXPORT jlong JNICALL Java_apple_laf_JRSUIControl_getPtrOfBuffer
  61 (JNIEnv *env, jclass clazz, jobject byteBuffer)
  62 {
  63     char *byteBufferPtr = (*env)->GetDirectBufferAddress(env, byteBuffer);
  64     if (byteBufferPtr == NULL) return 0L;
  65     return ptr_to_jlong(byteBufferPtr); // GC
  66 }
  67 
  68 /*
  69  * Class:     apple_laf_JRSUIControl
  70  * Method:    getCFDictionary
  71  * Signature: (Z)J
  72  */
  73 JNIEXPORT jlong JNICALL Java_apple_laf_JRSUIControl_getCFDictionary
  74 (JNIEnv *env, jclass clazz, jboolean isFlipped)
  75 {
  76     return ptr_to_jlong(JRSUIControlCreate(isFlipped));
  77 }
  78 
  79 /*
  80  * Class:     apple_laf_JRSUIControl
  81  * Method:    disposeCFDictionary
  82  * Signature: (J)V
  83  */
  84 JNIEXPORT void JNICALL Java_apple_laf_JRSUIControl_disposeCFDictionary
  85 (JNIEnv *env, jclass clazz, jlong controlPtr)
  86 {
  87     void *ptr = jlong_to_ptr(controlPtr);
  88     if (!ptr) return;
  89     JRSUIControlRelease((JRSUIControlRef)ptr);
  90 }
  91 
  92 
  93 static inline void *getValueFor
  94 (jbyte code, UInt8 *changeBuffer, size_t *dataSizePtr)
  95 {
  96     switch (code)
  97     {
  98         case apple_laf_JRSUIConstants_DoubleValue_TYPE_CODE:
  99             *dataSizePtr = sizeof(jdouble);
 100             jdouble doubleValue = (*(jdouble *)changeBuffer);
 101             return (void *)CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &doubleValue);
 102     }
 103 
 104     return NULL;
 105 }
 106 
 107 static inline jint syncChangesToControl
 108 (JRSUIControlRef control, UInt8 *changeBuffer)
 109 {
 110     UInt8 *endOfBuffer = changeBuffer + apple_laf_JRSUIControl_NIO_BUFFER_SIZE;
 111 
 112     while (changeBuffer < endOfBuffer)
 113     {
 114         // dereference the pointer to the constant that was stored as a jlong in the byte buffer
 115         CFStringRef key = (CFStringRef)jlong_to_ptr(*((jlong *)changeBuffer));
 116         if (key == NULL) return apple_laf_JRSUIControl_SUCCESS;
 117         changeBuffer += sizeof(jlong);
 118 
 119         jbyte code = *((jbyte *)changeBuffer);
 120         changeBuffer += sizeof(jbyte);
 121 
 122         size_t dataSize;
 123         void *value = (void *)getValueFor(code, changeBuffer, &dataSize);
 124         if (value == NULL) {
 125             NSLog(@"null pointer for %@ for value %d", key, (int)code);
 126 
 127             return apple_laf_JRSUIControl_NULL_PTR;
 128         }
 129 
 130         changeBuffer += dataSize;
 131         JRSUIControlSetValueByKey(control, key, value);
 132         CFRelease(value);
 133     }
 134 
 135     return apple_laf_JRSUIControl_SUCCESS;
 136 }
 137 
 138 static inline jint doSyncChanges
 139 (JNIEnv *env, jlong controlPtr, jlong byteBufferPtr)
 140 {
 141     JRSUIControlRef control = (JRSUIControlRef)jlong_to_ptr(controlPtr);
 142     UInt8 *changeBuffer = (UInt8 *)jlong_to_ptr(byteBufferPtr);
 143 
 144     return syncChangesToControl(control, changeBuffer);
 145 }
 146 
 147 /*
 148  * Class:     apple_laf_JRSUIControl
 149  * Method:    syncChanges
 150  * Signature: (JJ)I
 151  */
 152 JNIEXPORT jint JNICALL Java_apple_laf_JRSUIControl_syncChanges
 153 (JNIEnv *env, jclass clazz, jlong controlPtr, jlong byteBufferPtr)
 154 {
 155     return doSyncChanges(env, controlPtr, byteBufferPtr);
 156 }
 157 
 158 static inline jint doPaintCGContext(CGContextRef cgRef, jlong controlPtr, jlong oldProperties, jlong newProperties, jdouble x, jdouble y, jdouble w, jdouble h)
 159 {
 160     JRSUIControlRef control = (JRSUIControlRef)jlong_to_ptr(controlPtr);
 161     _SyncEncodedProperties(control, oldProperties, newProperties);
 162     CGRect bounds = CGRectMake(x, y, w, h);
 163     JRSUIControlDraw(gRenderer, control, cgRef, bounds);
 164     return 0;
 165 }
 166 
 167 /*
 168  * Class:     apple_laf_JRSUIControl
 169  * Method:    paintToCGContext
 170  * Signature: (JJJJDDDD)I
 171  */
 172 JNIEXPORT jint JNICALL Java_apple_laf_JRSUIControl_paintToCGContext
 173 (JNIEnv *env, jclass clazz, jlong cgContextPtr, jlong controlPtr, jlong oldProperties, jlong newProperties, jdouble x, jdouble y, jdouble w, jdouble h)
 174 {
 175     return doPaintCGContext((CGContextRef)jlong_to_ptr(cgContextPtr), controlPtr, oldProperties, newProperties, x, y, w, h);
 176 }
 177 
 178 /*
 179  * Class:     apple_laf_JRSUIControl
 180  * Method:    paintChangesToCGContext
 181  * Signature: (JJJJDDDDJ)I
 182  */
 183 JNIEXPORT jint JNICALL Java_apple_laf_JRSUIControl_paintChangesToCGContext
 184 (JNIEnv *env, jclass clazz, jlong cgContextPtr, jlong controlPtr, jlong oldProperties, jlong newProperties, jdouble x, jdouble y, jdouble w, jdouble h, jlong changes)
 185 {
 186     int syncStatus = doSyncChanges(env, controlPtr, changes);
 187     if (syncStatus != apple_laf_JRSUIControl_SUCCESS) return syncStatus;
 188 
 189     return doPaintCGContext((CGContextRef)jlong_to_ptr(cgContextPtr), controlPtr, oldProperties, newProperties, x, y, w, h);
 190 }
 191 
 192 static inline jint doPaintImage
 193 (JNIEnv *env, jlong controlPtr, jlong oldProperties, jlong newProperties, jintArray data, jint imgW, jint imgH, jdouble x, jdouble y, jdouble w, jdouble h)
 194 {
 195     jboolean isCopy = JNI_FALSE;
 196     void *rawPixelData = (*env)->GetPrimitiveArrayCritical(env, data, &isCopy);
 197     if (!rawPixelData) return apple_laf_JRSUIControl_NULL_PTR;
 198 
 199     CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
 200     CGContextRef cgRef = CGBitmapContextCreate(rawPixelData, imgW, imgH, 8, imgW * 4, colorspace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
 201     CGColorSpaceRelease(colorspace);
 202     CGContextScaleCTM(cgRef, imgW/w , imgH/h);
 203 
 204     jint status = doPaintCGContext(cgRef, controlPtr, oldProperties, newProperties, x, y, w, h);
 205     CGContextRelease(cgRef);
 206 
 207     (*env)->ReleasePrimitiveArrayCritical(env, data, rawPixelData, 0);
 208 
 209     return status == noErr ? apple_laf_JRSUIControl_SUCCESS : status;
 210 }
 211 
 212 /*
 213  * Class:     apple_laf_JRSUIControl
 214  * Method:    paintImage
 215  * Signature: ([IIIJJJDDDD)I
 216  */
 217 JNIEXPORT jint JNICALL Java_apple_laf_JRSUIControl_paintImage
 218 (JNIEnv *env, jclass clazz, jintArray data, jint imgW, jint imgH, jlong controlPtr, jlong oldProperties, jlong newProperties, jdouble x, jdouble y, jdouble w, jdouble h)
 219 {
 220     return doPaintImage(env, controlPtr, oldProperties, newProperties, data, imgW, imgH, x, y, w, h);
 221 }
 222 
 223 /*
 224  * Class:     apple_laf_JRSUIControl
 225  * Method:    paintChangesImage
 226  * Signature: ([IIIJJJDDDDJ)I
 227  */
 228 JNIEXPORT jint JNICALL Java_apple_laf_JRSUIControl_paintChangesImage
 229 (JNIEnv *env, jclass clazz, jintArray data, jint imgW, jint imgH, jlong controlPtr, jlong oldProperties, jlong newProperties, jdouble x, jdouble y, jdouble w, jdouble h, jlong changes)
 230 {
 231     int syncStatus = doSyncChanges(env, controlPtr, changes);
 232     if (syncStatus != apple_laf_JRSUIControl_SUCCESS) return syncStatus;
 233 
 234     return doPaintImage(env, controlPtr, oldProperties, newProperties, data, imgW, imgH, x, y, w, h);
 235 }
 236 
 237 /*
 238  * Class:     apple_laf_JRSUIControl
 239  * Method:    getNativeHitPart
 240  * Signature: (JJJDDDDDD)I
 241  */
 242 JNIEXPORT jint JNICALL Java_apple_laf_JRSUIControl_getNativeHitPart
 243 (JNIEnv *env, jclass clazz, jlong controlPtr, jlong oldProperties, jlong newProperties, jdouble x, jdouble y, jdouble w, jdouble h, jdouble pointX, jdouble pointY)
 244 {
 245     JRSUIControlRef control = (JRSUIControlRef)jlong_to_ptr(controlPtr);
 246     _SyncEncodedProperties(control, oldProperties, newProperties);
 247 
 248     CGRect bounds = CGRectMake(x, y, w, h);
 249     CGPoint point = CGPointMake(pointX, pointY);
 250 
 251     return JRSUIControlGetHitPart(gRenderer, control, bounds, point);
 252 }
 253 
 254 /*
 255  * Class:     apple_laf_JRSUIUtils_ScrollBar
 256  * Method:    shouldUseScrollToClick
 257  * Signature: ()Z
 258  */
 259 JNIEXPORT jboolean JNICALL Java_apple_laf_JRSUIUtils_00024ScrollBar_shouldUseScrollToClick
 260 (JNIEnv *env, jclass clazz)
 261 {
 262     return JRSUIControlShouldScrollToClick();
 263 }
 264 
 265 /*
 266  * Class:     apple_laf_JRSUIControl
 267  * Method:    getNativePartBounds
 268  * Signature: ([DJJJDDDDI)V
 269  */
 270 JNIEXPORT void JNICALL Java_apple_laf_JRSUIControl_getNativePartBounds
 271 (JNIEnv *env, jclass clazz, jdoubleArray rectArray, jlong controlPtr, jlong oldProperties, jlong newProperties, jdouble x, jdouble y, jdouble w, jdouble h, jint part)
 272 {
 273     JRSUIControlRef control = (JRSUIControlRef)jlong_to_ptr(controlPtr);
 274     _SyncEncodedProperties(control, oldProperties, newProperties);
 275 
 276     CGRect frame = CGRectMake(x, y, w, h);
 277     CGRect partBounds = JRSUIControlGetScrollBarPartBounds(control, frame, part);
 278 
 279     jdouble *rect = (*env)->GetPrimitiveArrayCritical(env, rectArray, NULL);
 280     rect[0] = partBounds.origin.x;
 281     rect[1] = partBounds.origin.y;
 282     rect[2] = partBounds.size.width;
 283     rect[3] = partBounds.size.height;
 284     (*env)->ReleasePrimitiveArrayCritical(env, rectArray, rect, 0);
 285 }
 286 
 287 /*
 288  * Class:     apple_laf_JRSUIControl
 289  * Method:    getNativeScrollBarOffsetChange
 290  * Signature: (JJJDDDDIII)D
 291  */
 292 JNIEXPORT jdouble JNICALL Java_apple_laf_JRSUIControl_getNativeScrollBarOffsetChange
 293 (JNIEnv *env, jclass clazz, jlong controlPtr, jlong oldProperties, jlong newProperties, jdouble x, jdouble y, jdouble w, jdouble h, jint offset, jint visibleAmount, jint extent)
 294 {
 295     JRSUIControlRef control = (JRSUIControlRef)jlong_to_ptr(controlPtr);
 296     _SyncEncodedProperties(control, oldProperties, newProperties);
 297 
 298     CGRect frame = CGRectMake(x, y, w, h);
 299     return (jdouble)JRSUIControlGetScrollBarOffsetFor(control, frame, offset, visibleAmount, extent);
 300 }