1 /* 2 * Copyright (c) 2013, 2018, 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 #ifdef __APPLE__ 27 #include <TargetConditionals.h> 28 29 #if TARGET_OS_MAC 30 31 #include <jni.h> 32 #include <com_sun_javafx_font_coretext_OS.h> 33 34 #import <CoreFoundation/CoreFoundation.h> 35 36 #if TARGET_OS_IPHONE 37 #import <CoreGraphics/CoreGraphics.h> 38 #import <CoreText/CoreText.h> 39 #else 40 #import <ApplicationServices/ApplicationServices.h> 41 #endif 42 43 44 #define OS_NATIVE(func) Java_com_sun_javafx_font_coretext_OS_##func 45 46 extern jboolean checkAndClearException(JNIEnv *env); 47 48 jboolean checkAndClearException(JNIEnv *env) 49 { 50 jthrowable t = (*env)->ExceptionOccurred(env); 51 if (!t) { 52 return JNI_FALSE; 53 } 54 (*env)->ExceptionClear(env); 55 return JNI_TRUE; 56 } 57 58 /**************************************************************************/ 59 /* */ 60 /* Structs */ 61 /* */ 62 /**************************************************************************/ 63 typedef struct CGAffineTransform_FID_CACHE { 64 int cached; 65 jclass clazz; 66 jfieldID a, b, c, d, tx, ty; 67 jmethodID init; 68 } CGAffineTransform_FID_CACHE; 69 70 CGAffineTransform_FID_CACHE CGAffineTransformFc; 71 72 void cacheCGAffineTransformFields(JNIEnv *env) 73 { 74 if (CGAffineTransformFc.cached) return; 75 jclass tmpClass = (*env)->FindClass(env, "com/sun/javafx/font/coretext/CGAffineTransform"); 76 if (checkAndClearException(env) || !tmpClass) { 77 fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or tmpClass == NULL"); 78 return; 79 } 80 CGAffineTransformFc.clazz = (jclass)(*env)->NewGlobalRef(env, tmpClass); 81 CGAffineTransformFc.a = (*env)->GetFieldID(env, CGAffineTransformFc.clazz, "a", "D"); 82 if (checkAndClearException(env) || !CGAffineTransformFc.a) { 83 fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or a == NULL"); 84 return; 85 } 86 CGAffineTransformFc.b = (*env)->GetFieldID(env, CGAffineTransformFc.clazz, "b", "D"); 87 if (checkAndClearException(env) || !CGAffineTransformFc.b) { 88 fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or b == NULL"); 89 return; 90 } 91 CGAffineTransformFc.c = (*env)->GetFieldID(env, CGAffineTransformFc.clazz, "c", "D"); 92 if (checkAndClearException(env) || !CGAffineTransformFc.c) { 93 fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or c == NULL"); 94 return; 95 } 96 CGAffineTransformFc.d = (*env)->GetFieldID(env, CGAffineTransformFc.clazz, "d", "D"); 97 if (checkAndClearException(env) || !CGAffineTransformFc.d) { 98 fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or d == NULL"); 99 return; 100 } 101 CGAffineTransformFc.tx = (*env)->GetFieldID(env, CGAffineTransformFc.clazz, "tx", "D"); 102 if (checkAndClearException(env) || !CGAffineTransformFc.tx) { 103 fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or tx == NULL"); 104 return; 105 } 106 CGAffineTransformFc.ty = (*env)->GetFieldID(env, CGAffineTransformFc.clazz, "ty", "D"); 107 if (checkAndClearException(env) || !CGAffineTransformFc.ty) { 108 fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or ty == NULL"); 109 return; 110 } 111 CGAffineTransformFc.init = (*env)->GetMethodID(env, CGAffineTransformFc.clazz, "<init>", "()V"); 112 if (checkAndClearException(env) || !CGAffineTransformFc.init) { 113 fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or init == NULL"); 114 return; 115 } 116 CGAffineTransformFc.cached = 1; 117 } 118 119 CGAffineTransform *getCGAffineTransformFields(JNIEnv *env, jobject lpObject, CGAffineTransform *lpStruct) 120 { 121 if (!CGAffineTransformFc.cached) cacheCGAffineTransformFields(env); 122 lpStruct->a = (*env)->GetDoubleField(env, lpObject, CGAffineTransformFc.a); 123 lpStruct->b = (*env)->GetDoubleField(env, lpObject, CGAffineTransformFc.b); 124 lpStruct->c = (*env)->GetDoubleField(env, lpObject, CGAffineTransformFc.c); 125 lpStruct->d = (*env)->GetDoubleField(env, lpObject, CGAffineTransformFc.d); 126 lpStruct->tx = (*env)->GetDoubleField(env, lpObject, CGAffineTransformFc.tx); 127 lpStruct->ty = (*env)->GetDoubleField(env, lpObject, CGAffineTransformFc.ty); 128 return lpStruct; 129 } 130 131 void setCGAffineTransformFields(JNIEnv *env, jobject lpObject, CGAffineTransform *lpStruct) 132 { 133 if (!CGAffineTransformFc.cached) cacheCGAffineTransformFields(env); 134 (*env)->SetDoubleField(env, lpObject, CGAffineTransformFc.a, (jdouble)lpStruct->a); 135 (*env)->SetDoubleField(env, lpObject, CGAffineTransformFc.b, (jdouble)lpStruct->b); 136 (*env)->SetDoubleField(env, lpObject, CGAffineTransformFc.c, (jdouble)lpStruct->c); 137 (*env)->SetDoubleField(env, lpObject, CGAffineTransformFc.d, (jdouble)lpStruct->d); 138 (*env)->SetDoubleField(env, lpObject, CGAffineTransformFc.tx, (jdouble)lpStruct->tx); 139 (*env)->SetDoubleField(env, lpObject, CGAffineTransformFc.ty, (jdouble)lpStruct->ty); 140 } 141 142 jobject newCGAffineTransform(JNIEnv *env, CGAffineTransform *lpStruct) 143 { 144 jobject lpObject = NULL; 145 if (!CGAffineTransformFc.cached) cacheCGAffineTransformFields(env); 146 lpObject = (*env)->NewObject(env, CGAffineTransformFc.clazz, CGAffineTransformFc.init); 147 if (lpObject && lpStruct) setCGAffineTransformFields(env, lpObject, lpStruct); 148 return lpObject; 149 } 150 151 typedef struct CGPoint_FID_CACHE { 152 int cached; 153 jclass clazz; 154 jfieldID x, y; 155 jmethodID init; 156 } CGPoint_FID_CACHE; 157 158 CGPoint_FID_CACHE CGPointFc; 159 160 void cacheCGPointFields(JNIEnv *env) 161 { 162 if (CGPointFc.cached) return; 163 jclass tmpClass = (*env)->FindClass(env, "com/sun/javafx/font/coretext/CGPoint"); 164 if (checkAndClearException(env) || !tmpClass) { 165 fprintf(stderr, "cacheCGPointFields error: JNI exception or tmpClass == NULL"); 166 return; 167 } 168 CGPointFc.clazz = (jclass)(*env)->NewGlobalRef(env, tmpClass); 169 CGPointFc.x = (*env)->GetFieldID(env, CGPointFc.clazz, "x", "D"); 170 if (checkAndClearException(env) || !CGPointFc.x) { 171 fprintf(stderr, "cacheCGPointFields error: JNI exception or x == NULL"); 172 return; 173 } 174 CGPointFc.y = (*env)->GetFieldID(env, CGPointFc.clazz, "y", "D"); 175 if (checkAndClearException(env) || !CGPointFc.y) { 176 fprintf(stderr, "cacheCGPointFields error: JNI exception or y == NULL"); 177 return; 178 } 179 CGPointFc.init = (*env)->GetMethodID(env, CGPointFc.clazz, "<init>", "()V"); 180 if (checkAndClearException(env) || !CGPointFc.init) { 181 fprintf(stderr, "cacheCGPointFields error: JNI exception or init == NULL"); 182 return; 183 } 184 CGPointFc.cached = 1; 185 } 186 187 CGPoint *getCGPointFields(JNIEnv *env, jobject lpObject, CGPoint *lpStruct) 188 { 189 if (!CGPointFc.cached) cacheCGPointFields(env); 190 lpStruct->x = (*env)->GetDoubleField(env, lpObject, CGPointFc.x); 191 lpStruct->y = (*env)->GetDoubleField(env, lpObject, CGPointFc.y); 192 return lpStruct; 193 } 194 195 void setCGPointFields(JNIEnv *env, jobject lpObject, CGPoint *lpStruct) 196 { 197 if (!CGPointFc.cached) cacheCGPointFields(env); 198 (*env)->SetDoubleField(env, lpObject, CGPointFc.x, (jdouble)lpStruct->x); 199 (*env)->SetDoubleField(env, lpObject, CGPointFc.y, (jdouble)lpStruct->y); 200 } 201 202 jobject newCGPoint(JNIEnv *env, CGPoint *lpStruct) 203 { 204 jobject lpObject = NULL; 205 if (!CGPointFc.cached) cacheCGPointFields(env); 206 lpObject = (*env)->NewObject(env, CGPointFc.clazz, CGPointFc.init); 207 if (lpObject && lpStruct) setCGPointFields(env, lpObject, lpStruct); 208 return lpObject; 209 } 210 211 typedef struct CGSize_FID_CACHE { 212 int cached; 213 jclass clazz; 214 jfieldID width, height; 215 jmethodID init; 216 } CGSize_FID_CACHE; 217 218 CGSize_FID_CACHE CGSizeFc; 219 220 void cacheCGSizeFields(JNIEnv *env) 221 { 222 if (CGSizeFc.cached) return; 223 jclass tmpClass = (*env)->FindClass(env, "com/sun/javafx/font/coretext/CGSize"); 224 if (checkAndClearException(env) || !tmpClass) { 225 fprintf(stderr, "cacheCGSizeFields error: JNI exception or tmpClass == NULL"); 226 return; 227 } 228 CGSizeFc.clazz = (jclass)(*env)->NewGlobalRef(env, tmpClass); 229 CGSizeFc.width = (*env)->GetFieldID(env, CGSizeFc.clazz, "width", "D"); 230 if (checkAndClearException(env) || !CGSizeFc.width) { 231 fprintf(stderr, "cacheCGSizeFields error: JNI exception or width == NULL"); 232 return; 233 } 234 CGSizeFc.height = (*env)->GetFieldID(env, CGSizeFc.clazz, "height", "D"); 235 if (checkAndClearException(env) || !CGSizeFc.height) { 236 fprintf(stderr, "cacheCGSizeFields error: JNI exception or height == NULL"); 237 return; 238 } 239 CGSizeFc.init = (*env)->GetMethodID(env, CGSizeFc.clazz, "<init>", "()V"); 240 if (checkAndClearException(env) || !CGSizeFc.init) { 241 fprintf(stderr, "cacheCGSizeFields error: JNI exception or init == NULL"); 242 return; 243 } 244 CGSizeFc.cached = 1; 245 } 246 247 CGSize *getCGSizeFields(JNIEnv *env, jobject lpObject, CGSize *lpStruct) 248 { 249 if (!CGSizeFc.cached) cacheCGSizeFields(env); 250 lpStruct->width = (*env)->GetDoubleField(env, lpObject, CGSizeFc.width); 251 lpStruct->height = (*env)->GetDoubleField(env, lpObject, CGSizeFc.height); 252 return lpStruct; 253 } 254 255 void setCGSizeFields(JNIEnv *env, jobject lpObject, CGSize *lpStruct) 256 { 257 if (!CGSizeFc.cached) cacheCGSizeFields(env); 258 (*env)->SetDoubleField(env, lpObject, CGSizeFc.width, (jdouble)lpStruct->width); 259 (*env)->SetDoubleField(env, lpObject, CGSizeFc.height, (jdouble)lpStruct->height); 260 } 261 262 jobject newCGSize(JNIEnv *env, CGSize *lpStruct) 263 { 264 jobject lpObject = NULL; 265 if (!CGSizeFc.cached) cacheCGSizeFields(env); 266 lpObject = (*env)->NewObject(env, CGSizeFc.clazz, CGSizeFc.init); 267 if (lpObject && lpStruct) setCGSizeFields(env, lpObject, lpStruct); 268 return lpObject; 269 } 270 271 typedef struct CGRect_FID_CACHE { 272 int cached; 273 jclass clazz; 274 jfieldID origin, size; 275 jmethodID init; 276 } CGRect_FID_CACHE; 277 278 CGRect_FID_CACHE CGRectFc; 279 280 void cacheCGRectFields(JNIEnv *env) 281 { 282 if (CGRectFc.cached) return; 283 jclass tmpClass = (*env)->FindClass(env, "com/sun/javafx/font/coretext/CGRect"); 284 if (checkAndClearException(env) || !tmpClass) { 285 fprintf(stderr, "cacheCGRectFields error: JNI exception or tmpClass == NULL"); 286 return; 287 } 288 CGRectFc.clazz = (jclass)(*env)->NewGlobalRef(env, tmpClass); 289 CGRectFc.origin = (*env)->GetFieldID(env, CGRectFc.clazz, "origin", "Lcom/sun/javafx/font/coretext/CGPoint;"); 290 if (checkAndClearException(env) || !CGRectFc.origin) { 291 fprintf(stderr, "cacheCGRectFields error: JNI exception or origin == NULL"); 292 return; 293 } 294 CGRectFc.size = (*env)->GetFieldID(env, CGRectFc.clazz, "size", "Lcom/sun/javafx/font/coretext/CGSize;"); 295 if (checkAndClearException(env) || !CGRectFc.size) { 296 fprintf(stderr, "cacheCGRectFields error: JNI exception or size == NULL"); 297 return; 298 } 299 CGRectFc.init = (*env)->GetMethodID(env, CGRectFc.clazz, "<init>", "()V"); 300 if (checkAndClearException(env) || !CGRectFc.init) { 301 fprintf(stderr, "cacheCGRectFields error: JNI exception or init == NULL"); 302 return; 303 } 304 CGRectFc.cached = 1; 305 } 306 307 CGRect *getCGRectFields(JNIEnv *env, jobject lpObject, CGRect *lpStruct) 308 { 309 if (!CGRectFc.cached) cacheCGRectFields(env); 310 { 311 jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CGRectFc.origin); 312 if (lpObject1 != NULL) getCGPointFields(env, lpObject1, &lpStruct->origin); 313 } 314 { 315 jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CGRectFc.size); 316 if (lpObject1 != NULL) getCGSizeFields(env, lpObject1, &lpStruct->size); 317 } 318 return lpStruct; 319 } 320 321 void setCGRectFields(JNIEnv *env, jobject lpObject, CGRect *lpStruct) 322 { 323 if (!CGRectFc.cached) cacheCGRectFields(env); 324 { 325 jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CGRectFc.origin); 326 if (lpObject1 != NULL) setCGPointFields(env, lpObject1, &lpStruct->origin); 327 } 328 { 329 jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CGRectFc.size); 330 if (lpObject1 != NULL) setCGSizeFields(env, lpObject1, &lpStruct->size); 331 } 332 } 333 334 jobject newCGRect(JNIEnv *env, CGRect *lpStruct) 335 { 336 jobject lpObject = NULL; 337 if (!CGRectFc.cached) cacheCGRectFields(env); 338 lpObject = (*env)->NewObject(env, CGRectFc.clazz, CGRectFc.init); 339 if (lpObject && lpStruct) setCGRectFields(env, lpObject, lpStruct); 340 return lpObject; 341 } 342 343 /**************************************************************************/ 344 /* */ 345 /* Functions */ 346 /* */ 347 /**************************************************************************/ 348 349 JNIEXPORT jlong JNICALL OS_NATIVE(kCFAllocatorDefault) 350 (JNIEnv *env, jclass that) 351 { 352 return (jlong)kCFAllocatorDefault; 353 } 354 355 JNIEXPORT jlong JNICALL OS_NATIVE(CFStringCreateWithCharacters__J_3CJ) 356 (JNIEnv *env, jclass that, jlong arg0, jcharArray arg1, jlong arg2) 357 { 358 jchar *lparg1=NULL; 359 jlong rc = 0; 360 if (arg1) if ((lparg1 = (*env)->GetCharArrayElements(env, arg1, NULL)) == NULL) goto fail; 361 rc = (jlong)CFStringCreateWithCharacters((CFAllocatorRef)arg0, (UniChar*)lparg1, (CFIndex)arg2); 362 fail: 363 if (arg1 && lparg1) (*env)->ReleaseCharArrayElements(env, arg1, lparg1, 0); 364 return rc; 365 } 366 367 JNIEXPORT void JNICALL OS_NATIVE(CFRelease) 368 (JNIEnv *env, jclass that, jlong arg0) 369 { 370 CFRelease((CFTypeRef)arg0); 371 } 372 373 JNIEXPORT jlong JNICALL OS_NATIVE(CTFontCreateWithGraphicsFont) 374 (JNIEnv *env, jclass that, jlong cgFont, jdouble size, jobject matrix, jlong attributes) 375 { 376 CGAffineTransform transform; 377 if (matrix) { 378 getCGAffineTransformFields(env, matrix, &transform); 379 } else { 380 transform = CGAffineTransformIdentity; 381 } 382 return (jlong)CTFontCreateWithGraphicsFont((CGFontRef)cgFont, (CGFloat)size, &transform, (CTFontDescriptorRef)attributes); 383 } 384 385 JNIEXPORT jlong JNICALL OS_NATIVE(CTFontCreateWithName) 386 (JNIEnv *env, jclass that, jlong arg0, jdouble arg1, jobject arg2) 387 { 388 CGAffineTransform _arg2, *lparg2=NULL; 389 jlong rc = 0; 390 if (arg2) if ((lparg2 = getCGAffineTransformFields(env, arg2, &_arg2)) == NULL) goto fail; 391 rc = (jlong)CTFontCreateWithName((CFStringRef)arg0, (CGFloat)arg1, (CGAffineTransform*)lparg2); 392 fail: 393 /* In only */ 394 // if (arg2 && lparg2) setCGAffineTransformFields(env, arg2, lparg2); 395 return rc; 396 } 397 398 399 JNIEXPORT jlong JNICALL OS_NATIVE(CFURLCreateWithFileSystemPath) 400 (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2, jboolean arg3) 401 { 402 return (jlong)CFURLCreateWithFileSystemPath((CFAllocatorRef)arg0, (CFStringRef)arg1, (CFURLPathStyle)arg2, (Boolean)arg3); 403 } 404 405 JNIEXPORT jboolean JNICALL OS_NATIVE(CTFontManagerRegisterFontsForURL) 406 (JNIEnv *env, jclass that, jlong arg0, jint arg1, jlong arg2) 407 { 408 return (jboolean)CTFontManagerRegisterFontsForURL((CFURLRef)arg0, (CTFontManagerScope)arg1, (CFErrorRef*)arg2); 409 } 410 411 JNIEXPORT jlong JNICALL OS_NATIVE(CTFontCreatePathForGlyph) 412 (JNIEnv *env, jclass that, jlong arg0, jshort arg1, jobject arg2) 413 { 414 CGAffineTransform _arg2, *lparg2=NULL; 415 jlong rc = 0; 416 if (arg2) if ((lparg2 = getCGAffineTransformFields(env, arg2, &_arg2)) == NULL) goto fail; 417 rc = (jlong)CTFontCreatePathForGlyph((CTFontRef)arg0, (CGGlyph)arg1, (CGAffineTransform*)lparg2); 418 fail: 419 /* In Only */ 420 // if (arg2 && lparg2) setCGAffineTransformFields(env, arg2, lparg2); 421 return rc; 422 } 423 424 JNIEXPORT jlong JNICALL OS_NATIVE(CGFontCreateWithDataProvider) 425 (JNIEnv *env, jclass that, jlong dataProvider) 426 { 427 return (jlong)CGFontCreateWithDataProvider((CGDataProviderRef)dataProvider); 428 } 429 430 JNIEXPORT void JNICALL OS_NATIVE(CGPathRelease) 431 (JNIEnv *env, jclass that, jlong arg0) 432 { 433 CGPathRelease((CGPathRef)arg0); 434 } 435 436 JNIEXPORT jlong JNICALL OS_NATIVE(CGColorSpaceCreateDeviceRGB) 437 (JNIEnv *env, jclass that) 438 { 439 return (jlong)CGColorSpaceCreateDeviceRGB(); 440 } 441 442 JNIEXPORT jlong JNICALL OS_NATIVE(CGColorSpaceCreateDeviceGray) 443 (JNIEnv *env, jclass that) 444 { 445 return (jlong)CGColorSpaceCreateDeviceGray(); 446 } 447 448 JNIEXPORT jlong JNICALL OS_NATIVE(CGBitmapContextCreate) 449 (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2, jlong arg3, jlong arg4, jlong arg5, jint arg6) 450 { 451 return (jlong)CGBitmapContextCreate((void*)arg0, (size_t)arg1, (size_t)arg2, (size_t)arg3, (size_t)arg4, (CGColorSpaceRef)arg5, (CGBitmapInfo)arg6); 452 } 453 454 JNIEXPORT void JNICALL OS_NATIVE(CGContextSetAllowsFontSmoothing) 455 (JNIEnv *env, jclass that, jlong arg0, jboolean arg1) 456 { 457 CGContextSetAllowsFontSmoothing((CGContextRef)arg0, (_Bool)arg1); 458 } 459 460 JNIEXPORT void JNICALL OS_NATIVE(CGContextSetAllowsAntialiasing) 461 (JNIEnv *env, jclass that, jlong arg0, jboolean arg1) 462 { 463 CGContextSetAllowsAntialiasing((CGContextRef)arg0, (_Bool)arg1); 464 } 465 466 JNIEXPORT void JNICALL OS_NATIVE(CGContextSetAllowsFontSubpixelPositioning) 467 (JNIEnv *env, jclass that, jlong arg0, jboolean arg1) 468 { 469 CGContextSetAllowsFontSubpixelPositioning((CGContextRef)arg0, (_Bool)arg1); 470 } 471 472 JNIEXPORT void JNICALL OS_NATIVE(CGContextSetAllowsFontSubpixelQuantization) 473 (JNIEnv *env, jclass that, jlong arg0, jboolean arg1) 474 { 475 CGContextSetAllowsFontSubpixelQuantization((CGContextRef)arg0, (_Bool)arg1); 476 } 477 478 JNIEXPORT void JNICALL OS_NATIVE(CGContextSetRGBFillColor) 479 (JNIEnv *env, jclass that, jlong arg0, jdouble arg1, jdouble arg2, jdouble arg3, jdouble arg4) 480 { 481 CGContextSetRGBFillColor((CGContextRef)arg0, (CGFloat)arg1, (CGFloat)arg2, (CGFloat)arg3, (CGFloat)arg4); 482 } 483 484 JNIEXPORT void JNICALL OS_NATIVE(CGContextFillRect) 485 (JNIEnv *env, jclass that, jlong arg0, jobject arg1) 486 { 487 CGRect _arg1, *lparg1=NULL; 488 /* In Only */ 489 if (arg1) if ((lparg1 = getCGRectFields(env, arg1, &_arg1)) == NULL) return; 490 CGContextFillRect((CGContextRef)arg0, *lparg1); 491 } 492 493 JNIEXPORT void JNICALL OS_NATIVE(CGContextTranslateCTM) 494 (JNIEnv *env, jclass that, jlong arg0, jdouble arg1, jdouble arg2) 495 { 496 CGContextTranslateCTM((CGContextRef)arg0, (CGFloat)arg1, (CGFloat)arg2); 497 } 498 499 JNIEXPORT void JNICALL OS_NATIVE(CGContextRelease) 500 (JNIEnv *env, jclass that, jlong arg0) 501 { 502 CGContextRelease((CGContextRef)arg0); 503 } 504 505 JNIEXPORT void JNICALL OS_NATIVE(CGColorSpaceRelease) 506 (JNIEnv *env, jclass that, jlong arg0) 507 { 508 CGColorSpaceRelease((CGColorSpaceRef)arg0); 509 } 510 511 JNIEXPORT jlong JNICALL OS_NATIVE(CGDataProviderCreateWithURL) 512 (JNIEnv *env, jclass that, jlong cfURL) { 513 return (jlong)CGDataProviderCreateWithURL((CFURLRef)cfURL); 514 } 515 516 JNIEXPORT jlong JNICALL OS_NATIVE(kCFTypeDictionaryKeyCallBacks) 517 (JNIEnv *env, jclass that) 518 { 519 return (jlong)&kCFTypeDictionaryKeyCallBacks; 520 } 521 522 JNIEXPORT jlong JNICALL OS_NATIVE(kCFTypeDictionaryValueCallBacks) 523 (JNIEnv *env, jclass that) 524 { 525 return (jlong)&kCFTypeDictionaryValueCallBacks; 526 } 527 528 JNIEXPORT jlong JNICALL OS_NATIVE(CFDictionaryCreateMutable) 529 (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2, jlong arg3) 530 { 531 return (jlong)CFDictionaryCreateMutable((CFAllocatorRef)arg0, (CFIndex)arg1, (CFDictionaryKeyCallBacks*)arg2, (CFDictionaryValueCallBacks*)arg3); 532 } 533 534 JNIEXPORT void JNICALL OS_NATIVE(CFDictionaryAddValue) 535 (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2) 536 { 537 CFDictionaryAddValue((CFMutableDictionaryRef)arg0, (void*)arg1, (void*)arg2); 538 } 539 540 JNIEXPORT jlong JNICALL OS_NATIVE(CFDictionaryGetValue) 541 (JNIEnv *env, jclass that, jlong arg0, jlong arg1) 542 { 543 return (jlong)CFDictionaryGetValue((CFDictionaryRef)arg0, (void*)arg1); 544 } 545 546 JNIEXPORT jlong JNICALL OS_NATIVE(kCTFontAttributeName) 547 (JNIEnv *env, jclass that) 548 { 549 return (jlong)kCTFontAttributeName; 550 } 551 552 JNIEXPORT jlong JNICALL OS_NATIVE(kCTParagraphStyleAttributeName) 553 (JNIEnv *env, jclass that) 554 { 555 return (jlong)kCTParagraphStyleAttributeName; 556 } 557 558 JNIEXPORT jlong JNICALL OS_NATIVE(CFAttributedStringCreate) 559 (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2) 560 { 561 return (jlong)CFAttributedStringCreate((CFAllocatorRef)arg0, (CFStringRef)arg1, (CFDictionaryRef)arg2); 562 } 563 564 JNIEXPORT jlong JNICALL OS_NATIVE(CTLineCreateWithAttributedString) 565 (JNIEnv *env, jclass that, jlong arg0) 566 { 567 return (jlong)CTLineCreateWithAttributedString((CFAttributedStringRef)arg0); 568 } 569 570 JNIEXPORT jlong JNICALL OS_NATIVE(CTLineGetGlyphRuns) 571 (JNIEnv *env, jclass that, jlong arg0) 572 { 573 return (jlong)CTLineGetGlyphRuns((CTLineRef)arg0); 574 } 575 576 JNIEXPORT jdouble JNICALL OS_NATIVE(CTLineGetTypographicBounds) 577 (JNIEnv *env, jclass that, jlong arg0) 578 { 579 return (jdouble)CTLineGetTypographicBounds((CTLineRef)arg0, NULL, NULL, NULL); 580 } 581 582 JNIEXPORT jlong JNICALL OS_NATIVE(CTLineGetGlyphCount) 583 (JNIEnv *env, jclass that, jlong arg0) 584 { 585 return (jlong)CTLineGetGlyphCount((CTLineRef)arg0); 586 } 587 588 JNIEXPORT jlong JNICALL OS_NATIVE(CFArrayGetCount) 589 (JNIEnv *env, jclass that, jlong arg0) 590 { 591 return (jlong)CFArrayGetCount((CFArrayRef)arg0); 592 } 593 594 JNIEXPORT jlong JNICALL OS_NATIVE(CFArrayGetValueAtIndex) 595 (JNIEnv *env, jclass that, jlong arg0, jlong arg1) 596 { 597 return (jlong)CFArrayGetValueAtIndex((CFArrayRef)arg0, (CFIndex)arg1); 598 } 599 600 JNIEXPORT jlong JNICALL OS_NATIVE(CTRunGetGlyphCount) 601 (JNIEnv *env, jclass that, jlong arg0) 602 { 603 return (jlong)CTRunGetGlyphCount((CTRunRef)arg0); 604 } 605 606 JNIEXPORT jlong JNICALL OS_NATIVE(CTRunGetAttributes) 607 (JNIEnv *env, jclass that, jlong arg0) 608 { 609 return (jlong)CTRunGetAttributes((CTRunRef)arg0); 610 } 611 612 /**************************************************************************/ 613 /* */ 614 /* Custom Functions */ 615 /* */ 616 /**************************************************************************/ 617 618 619 JNIEXPORT jlong JNICALL OS_NATIVE(CFStringCreateWithCharacters__J_3CJJ) 620 (JNIEnv *env, jclass that, jlong arg0, jcharArray arg1, jlong arg2, jlong arg3) 621 { 622 jchar *lparg1=NULL; 623 jlong rc = 0; 624 if (arg1) if ((lparg1 = (*env)->GetPrimitiveArrayCritical(env, arg1, NULL)) == NULL) goto fail; 625 UniChar* str = lparg1 + arg2; 626 rc = (jlong)CFStringCreateWithCharacters((CFAllocatorRef)arg0, str, (CFIndex)arg3); 627 fail: 628 if (arg1 && lparg1) (*env)->ReleasePrimitiveArrayCritical(env, arg1, lparg1, 0); 629 return rc; 630 } 631 632 JNIEXPORT jint JNICALL OS_NATIVE(CTRunGetGlyphs) 633 (JNIEnv *env, jclass that, jlong runRef, jint slotMask, jint start, jintArray bufferRef) 634 { 635 CTRunRef run = (CTRunRef)runRef; 636 const CGGlyph * glyphs = CTRunGetGlyphsPtr(run); 637 CFIndex count = CTRunGetGlyphCount(run); 638 if (count == 0) { 639 return 0; 640 } 641 642 CGGlyph* tempGlyphs = NULL; 643 if (!glyphs) { 644 tempGlyphs = (CGGlyph*) malloc(count * sizeof(CGGlyph)); 645 if (!tempGlyphs) { 646 return 0; 647 } 648 649 CTRunGetGlyphs(run, CFRangeMake(0, 0), tempGlyphs); 650 glyphs = tempGlyphs; 651 } 652 653 int i = 0; 654 if (glyphs) { 655 jint* buffer = (*env)->GetPrimitiveArrayCritical(env, bufferRef, NULL); 656 if (buffer) { 657 while(i < count) { 658 buffer[start + i] = slotMask | (glyphs[i] & 0xFFFF); 659 i++; 660 } 661 (*env)->ReleasePrimitiveArrayCritical(env, bufferRef, buffer, 0); 662 } 663 } 664 665 if (tempGlyphs) { 666 free(tempGlyphs); 667 } 668 return i; 669 } 670 671 JNIEXPORT jint JNICALL OS_NATIVE(CTRunGetPositions) 672 (JNIEnv *env, jclass that, jlong runRef, jint start, jfloatArray bufferRef) 673 { 674 CTRunRef run = (CTRunRef)runRef; 675 const CGPoint* positions = CTRunGetPositionsPtr(run); 676 CFIndex count = CTRunGetGlyphCount(run); 677 if (count == 0) { 678 return 0; 679 } 680 681 CGPoint* tempPositions = NULL; 682 if (!positions) { 683 tempPositions = (CGPoint*) malloc(count * sizeof(CGPoint)); 684 if (!tempPositions) { 685 return 0; 686 } 687 688 CTRunGetPositions(run, CFRangeMake(0, 0), tempPositions); 689 positions = tempPositions; 690 } 691 692 int j = 0; 693 if (positions) { 694 jfloat* buffer = (*env)->GetPrimitiveArrayCritical(env, bufferRef, NULL); 695 if (buffer) { 696 int i = 0; 697 while (i < count) { 698 CGPoint pos = positions[i++]; 699 buffer[start + j++] = pos.x; 700 buffer[start + j++] = pos.y; 701 } 702 (*env)->ReleasePrimitiveArrayCritical(env, bufferRef, buffer, 0); 703 } 704 } 705 706 if (tempPositions) { 707 free(tempPositions); 708 } 709 return j; 710 } 711 712 JNIEXPORT jint JNICALL OS_NATIVE(CTRunGetStringIndices) 713 (JNIEnv *env, jclass that, jlong runRef, jint start, jintArray bufferRef) 714 { 715 CTRunRef run = (CTRunRef)runRef; 716 const CFIndex* indices = CTRunGetStringIndicesPtr(run); 717 CFIndex count = CTRunGetGlyphCount(run); 718 if (count == 0) { 719 return 0; 720 } 721 722 CFIndex* tempIndices = NULL; 723 if (!indices) { 724 tempIndices = (CFIndex*) malloc(count * sizeof(CFIndex)); 725 if (!tempIndices) { 726 return 0; 727 } 728 729 CTRunGetStringIndices(run, CFRangeMake(0, 0), tempIndices); 730 indices = tempIndices; 731 } 732 733 int i = 0; 734 if (indices) { 735 jint* buffer = (*env)->GetPrimitiveArrayCritical(env, bufferRef, NULL); 736 if (buffer) { 737 while(i < count) { 738 buffer[start + i] = indices[i]; 739 i++; 740 } 741 (*env)->ReleasePrimitiveArrayCritical(env, bufferRef, buffer, 0); 742 } 743 744 if (tempIndices) { 745 free(tempIndices); 746 } 747 } 748 return i; 749 } 750 751 JNIEXPORT jstring JNICALL OS_NATIVE(CTFontCopyAttributeDisplayName) 752 (JNIEnv *env, jclass that, jlong arg0) 753 { 754 CFStringRef stringRef = CTFontCopyAttribute((CTFontRef)arg0, kCTFontDisplayNameAttribute); 755 if (stringRef == NULL) return NULL; 756 CFIndex length = CFStringGetLength(stringRef); 757 UniChar buffer[length]; 758 CFStringGetCharacters(stringRef, CFRangeMake(0, length), buffer); 759 CFRelease(stringRef); 760 return (*env)->NewString(env, (jchar *)buffer, length); 761 } 762 763 JNIEXPORT jbyteArray JNICALL OS_NATIVE(CGBitmapContextGetData) 764 (JNIEnv *env, jclass that, jlong arg0, jint dstWidth, jint dstHeight, jint bpp) 765 { 766 jbyteArray result = NULL; 767 if (dstWidth < 0) return NULL; 768 if (dstHeight < 0) return NULL; 769 if (bpp != 8 && bpp != 24) return NULL; 770 CGContextRef context = (CGContextRef)arg0; 771 if (context == NULL) return NULL; 772 jbyte *srcData = (jbyte*)CGBitmapContextGetData(context); 773 774 if (srcData) { 775 /* Use one byte per pixel for grayscale */ 776 size_t srcWidth = CGBitmapContextGetWidth(context); 777 if (srcWidth < dstWidth) return NULL; 778 size_t srcHeight = CGBitmapContextGetHeight(context); 779 if (srcHeight < dstHeight) return NULL; 780 size_t srcBytesPerRow = CGBitmapContextGetBytesPerRow(context); 781 size_t srcStep = CGBitmapContextGetBitsPerPixel(context) / 8; 782 int srcOffset = (srcHeight - dstHeight) * srcBytesPerRow; 783 784 785 //bits per pixel, either 8 for gray or 24 for LCD. 786 int dstStep = bpp / 8; 787 size_t size = dstWidth * dstHeight * dstStep; 788 jbyte* data = (jbyte*)calloc(size, sizeof(jbyte)); 789 if (data == NULL) return NULL; 790 791 int x, y, sx; 792 int dstOffset = 0; 793 for (y = 0; y < dstHeight; y++) { 794 for (x = 0, sx = 0; x < dstWidth; x++, dstOffset += dstStep, sx += srcStep) { 795 if (dstStep == 1) { 796 /* BGRA or Gray to Gray */ 797 data[dstOffset] = 0xFF - srcData[srcOffset + sx]; 798 } else { 799 /* BGRA to RGB */ 800 data[dstOffset] = 0xFF - srcData[srcOffset + sx + 2]; 801 data[dstOffset + 1] = 0xFF - srcData[srcOffset + sx + 1]; 802 data[dstOffset + 2] = 0xFF - srcData[srcOffset + sx]; 803 } 804 } 805 srcOffset += srcBytesPerRow; 806 } 807 808 result = (*env)->NewByteArray(env, size); 809 if (result) { 810 (*env)->SetByteArrayRegion(env, result, 0, size, data); 811 } 812 free(data); 813 } 814 return result; 815 } 816 817 JNIEXPORT void JNICALL OS_NATIVE(CGRectApplyAffineTransform) 818 (JNIEnv *env, jclass that, jobject arg0, jobject arg1) 819 { 820 CGRect _arg0, *lparg0=NULL; 821 CGAffineTransform _arg1, *lparg1=NULL; 822 if (arg0) if ((lparg0 = getCGRectFields(env, arg0, &_arg0)) == NULL) goto fail; 823 if (arg1) if ((lparg1 = getCGAffineTransformFields(env, arg1, &_arg1)) == NULL) goto fail; 824 _arg0 = CGRectApplyAffineTransform(*lparg0, *lparg1); 825 fail: 826 /* In Only */ 827 // if (arg1 && lparg1) setCGAffineTransformFields(env, arg1, lparg1); 828 if (arg0 && lparg0) setCGRectFields(env, arg0, lparg0); 829 } 830 831 JNIEXPORT void JNICALL OS_NATIVE(CTFontDrawGlyphs) 832 (JNIEnv *env, jclass that, jlong arg0, jshort arg1, jdouble arg2, jdouble arg3, jlong contextRef) 833 { 834 /* Custom: only takes one glyph at the time */ 835 CGGlyph glyphs[] = {arg1}; 836 CGPoint pos[] = {CGPointMake(arg2, arg3)}; 837 CTFontDrawGlyphs((CTFontRef)arg0, glyphs, pos, 1, (CGContextRef)contextRef); 838 } 839 840 JNIEXPORT jboolean JNICALL OS_NATIVE(CTFontGetBoundingRectForGlyphUsingTables) 841 (JNIEnv *env, jclass that, jlong arg1, jshort arg2, jshort arg3, jintArray arg4) 842 { 843 /* The following code is based on scalerMethods.c#getGlyphBoundingBoxNative */ 844 CTFontRef fontRef = (CTFontRef)arg1; 845 CTFontTableOptions options = kCTFontTableOptionNoOptions; 846 CFDataRef tableData; 847 CFIndex length; 848 849 /* indexToLocFormat is stored in Java for performance */ 850 // tableData = CTFontCopyTable(fontRef, kCTFontTableHead, options); 851 // const UInt8 * head = CFDataGetBytePtr(tableData); 852 // UInt16 indexToLocFormat = CFSwapInt16BigToHost(*((SInt16*)(head + 50))); 853 // printf("here0 indexToLocFormat=%u \n", indexToLocFormat); fflush(stdout); 854 // CFRelease(tableData); 855 UInt16 indexToLocFormat = arg3; 856 857 tableData = CTFontCopyTable(fontRef, kCTFontTableLoca, options); 858 if (tableData == NULL) return FALSE; 859 length = CFDataGetLength(tableData); 860 UInt32 offset1 = 0, offset2 = 0; 861 UInt32 index = arg2 & 0xFFFF; 862 if (indexToLocFormat) { 863 const UInt32 * loca = (const UInt32 *)CFDataGetBytePtr(tableData); 864 if (loca != NULL && (index + 1) < (length / 4)) { 865 offset1 = CFSwapInt32BigToHost(loca[index]); 866 offset2 = CFSwapInt32BigToHost(loca[index + 1]); 867 } 868 } else { 869 const UInt16 * loca = (const UInt16 *)CFDataGetBytePtr(tableData); 870 if (loca != NULL && (index + 1) < (length / 2)) { 871 offset1 = CFSwapInt16BigToHost(loca[index]) << 1; 872 offset2 = CFSwapInt16BigToHost(loca[index + 1]) << 1; 873 } 874 } 875 CFRelease(tableData); 876 jboolean result = FALSE; 877 if (offset2 > offset1 && (offset2 - offset1) >= 10) { 878 tableData = CTFontCopyTable(fontRef, kCTFontTableGlyf, options); 879 if (tableData == NULL) return FALSE; 880 length = CFDataGetLength(tableData); 881 const UInt8 * ptr = CFDataGetBytePtr(tableData); 882 if (ptr != NULL && (offset1 + 10) < length) { 883 const SInt16 * glyf = (const SInt16 *)(ptr + offset1); 884 /* 885 * CFSwapInt16BigToHost returns an unsigned short, need 886 * to cast back to signed short before assigning to jint. 887 */ 888 jint data[] = { 889 (SInt16)CFSwapInt16BigToHost(glyf[1]), 890 (SInt16)CFSwapInt16BigToHost(glyf[2]), 891 (SInt16)CFSwapInt16BigToHost(glyf[3]), 892 (SInt16)CFSwapInt16BigToHost(glyf[4]), 893 }; 894 (*env)->SetIntArrayRegion(env, arg4, 0, 4, data); 895 result = TRUE; 896 } 897 CFRelease(tableData); 898 } 899 return result; 900 } 901 902 JNIEXPORT jdouble JNICALL OS_NATIVE(CTFontGetAdvancesForGlyphs) 903 (JNIEnv *env, jclass that, jlong arg0, jint arg1, jshort arg2, jobject arg3) 904 { 905 /* Custom: only takes one glyph at the time */ 906 jdouble rc = 0; 907 CGGlyph glyphs[] = {arg2}; 908 CGSize _arg3, *lparg3=NULL; 909 if (arg3) if ((lparg3 = getCGSizeFields(env, arg3, &_arg3)) == NULL) goto fail; 910 rc = (jdouble)CTFontGetAdvancesForGlyphs((CTFontRef)arg0, (CTFontOrientation)arg1, glyphs, lparg3, 1); 911 fail: 912 if (arg3 && lparg3) setCGSizeFields(env, arg3, &_arg3); 913 return rc; 914 } 915 916 JNIEXPORT jobject JNICALL OS_NATIVE(CGPathGetPathBoundingBox) 917 (JNIEnv *env, jclass that, jlong arg0) 918 { 919 CGRect result = CGPathGetPathBoundingBox((CGPathRef)arg0); 920 return newCGRect(env, &result); 921 } 922 923 JNIEXPORT jlong JNICALL OS_NATIVE(CTParagraphStyleCreate) 924 (JNIEnv *env, jclass that, jint arg0) 925 { 926 CTWritingDirection dir = (CTWritingDirection)arg0; 927 CTParagraphStyleSetting settings[] = { 928 {kCTParagraphStyleSpecifierBaseWritingDirection, sizeof(dir), &dir} 929 }; 930 return (jlong)CTParagraphStyleCreate(settings, sizeof(settings) / sizeof(settings[0])); 931 } 932 933 /***********************************************/ 934 /* Glyph Outline */ 935 /***********************************************/ 936 937 static const int DEFAULT_LEN_TYPES = 10; 938 static const int DEFAULT_LEN_COORDS = 50; 939 typedef struct _PathData { 940 jbyte* pointTypes; 941 int numTypes; 942 int lenTypes; 943 jfloat* pointCoords; 944 int numCoords; 945 int lenCoords; 946 } PathData; 947 948 void pathApplierFunctionFast(void *i, const CGPathElement *e) { 949 PathData *info = (PathData *)i; 950 if (info->numTypes == info->lenTypes) { 951 info->lenTypes += DEFAULT_LEN_TYPES; 952 info->pointTypes = (jbyte*)realloc(info->pointTypes, info->lenTypes * sizeof(jbyte)); 953 } 954 jint type; 955 int coordCount = 0; 956 switch (e->type) { 957 case kCGPathElementMoveToPoint: 958 type = 0; 959 coordCount = 1; 960 break; 961 case kCGPathElementAddLineToPoint: 962 type = 1; 963 coordCount = 1; 964 break; 965 case kCGPathElementAddQuadCurveToPoint: 966 type = 2; 967 coordCount = 2; 968 break; 969 case kCGPathElementAddCurveToPoint: 970 type = 3; 971 coordCount = 3; 972 break; 973 case kCGPathElementCloseSubpath: 974 type = 4; 975 coordCount = 0; 976 break; 977 } 978 info->pointTypes[info->numTypes++] = type; 979 980 if (info->numCoords + (coordCount * 2) > info->lenCoords) { 981 info->lenCoords += DEFAULT_LEN_COORDS; 982 info->pointCoords = (jfloat*)realloc(info->pointCoords, info->lenCoords * sizeof(jfloat)); 983 } 984 int j; 985 for (j = 0; j < coordCount; j++) { 986 CGPoint pt = e->points[j]; 987 info->pointCoords[info->numCoords++] = pt.x; 988 info->pointCoords[info->numCoords++] = pt.y; 989 } 990 } 991 992 JNIEXPORT jobject JNICALL OS_NATIVE(CGPathApply) 993 (JNIEnv *env, jclass that, jlong arg0) 994 { 995 jobject path2D = NULL; 996 PathData data; 997 data.pointTypes = (jbyte*)malloc(sizeof(jbyte) * DEFAULT_LEN_TYPES); 998 data.numTypes = 0; 999 data.lenTypes = DEFAULT_LEN_TYPES; 1000 data.pointCoords = (jfloat*)malloc(sizeof(jfloat) * DEFAULT_LEN_COORDS); 1001 data.numCoords = 0; 1002 data.lenCoords = DEFAULT_LEN_COORDS; 1003 1004 CGPathApply((CGPathRef)arg0, &data, pathApplierFunctionFast); 1005 1006 static jclass path2DClass = NULL; 1007 static jmethodID path2DCtr = NULL; 1008 if (path2DClass == NULL) { 1009 jclass tmpClass = (*env)->FindClass(env, "com/sun/javafx/geom/Path2D"); 1010 if ((*env)->ExceptionOccurred(env) || !tmpClass) { 1011 fprintf(stderr, "OS_NATIVE error: JNI exception or tmpClass == NULL"); 1012 goto fail; 1013 } 1014 path2DClass = (jclass)(*env)->NewGlobalRef(env, tmpClass); 1015 path2DCtr = (*env)->GetMethodID(env, path2DClass, "<init>", "(I[BI[FI)V"); 1016 if ((*env)->ExceptionOccurred(env) || !path2DCtr) { 1017 fprintf(stderr, "OS_NATIVE error: JNI exception or path2DCtr == NULL"); 1018 goto fail; 1019 } 1020 } 1021 1022 jbyteArray types = (*env)->NewByteArray(env, data.numTypes); 1023 jfloatArray coords = (*env)->NewFloatArray(env, data.numCoords); 1024 if (types && coords) { 1025 (*env)->SetByteArrayRegion(env, types, 0, data.numTypes, data.pointTypes); 1026 if ((*env)->ExceptionOccurred(env)) { 1027 fprintf(stderr, "OS_NATIVE error: JNI exception"); 1028 goto fail; 1029 } 1030 (*env)->SetFloatArrayRegion(env, coords, 0, data.numCoords, data.pointCoords); 1031 if ((*env)->ExceptionOccurred(env)) { 1032 fprintf(stderr, "OS_NATIVE error: JNI exception"); 1033 goto fail; 1034 } 1035 path2D = (*env)->NewObject(env, path2DClass, path2DCtr, 1036 0 /*winding rule*/, 1037 types, data.numTypes, 1038 coords, data.numCoords); 1039 if ((*env)->ExceptionOccurred(env) || !path2D) { 1040 goto fail; 1041 } 1042 } 1043 fail: 1044 free(data.pointTypes); 1045 free(data.pointCoords); 1046 return path2D; 1047 } 1048 1049 #endif /* TARGET_OS_MAC */ 1050 #endif /* __APPLE__ */ 1051