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
26#import "JNIUtilities.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
36static JRSUIRendererRef gRenderer;
37
38/*
39 * Class:     apple_laf_JRSUIControl
40 * Method:    initNativeJRSUI
41 * Signature: ()I
42 */
43JNIEXPORT 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 */
60JNIEXPORT 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 */
73JNIEXPORT 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 */
84JNIEXPORT 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
93static 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
107static 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
138static 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 */
152JNIEXPORT 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
158static 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 */
172JNIEXPORT 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 */
183JNIEXPORT 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
192static 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 + x + x) , imgH/(h + y + y));
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 */
217JNIEXPORT 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 */
228JNIEXPORT 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 */
242JNIEXPORT 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 */
259JNIEXPORT 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 */
270JNIEXPORT 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 */
292JNIEXPORT 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}
301