1 /* 2 * Copyright (c) 2013, 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 #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(CFURLCreateWithFileSystemPath) 374 (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2, jboolean arg3) 375 { 376 return (jlong)CFURLCreateWithFileSystemPath((CFAllocatorRef)arg0, (CFStringRef)arg1, (CFURLPathStyle)arg2, (Boolean)arg3); 377 } 378 379 JNIEXPORT jboolean JNICALL OS_NATIVE(CTFontManagerRegisterFontsForURL) 380 (JNIEnv *env, jclass that, jlong arg0, jint arg1, jlong arg2) 381 { 382 return (jboolean)CTFontManagerRegisterFontsForURL((CFURLRef)arg0, (CTFontManagerScope)arg1, (CFErrorRef*)arg2); 383 } 384 385 JNIEXPORT jlong JNICALL OS_NATIVE(CTFontCreatePathForGlyph) 386 (JNIEnv *env, jclass that, jlong arg0, jshort 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)CTFontCreatePathForGlyph((CTFontRef)arg0, (CGGlyph)arg1, (CGAffineTransform*)lparg2); 392 fail: 393 /* In Only */ 394 // if (arg2 && lparg2) setCGAffineTransformFields(env, arg2, lparg2); 395 return rc; 396 } 397 398 JNIEXPORT void JNICALL OS_NATIVE(CGPathRelease) 399 (JNIEnv *env, jclass that, jlong arg0) 400 { 401 CGPathRelease((CGPathRef)arg0); 402 } 403 404 JNIEXPORT jlong JNICALL OS_NATIVE(CGColorSpaceCreateDeviceRGB) 405 (JNIEnv *env, jclass that) 406 { 407 return (jlong)CGColorSpaceCreateDeviceRGB(); 408 } 409 410 JNIEXPORT jlong JNICALL OS_NATIVE(CGColorSpaceCreateDeviceGray) 411 (JNIEnv *env, jclass that) 412 { 413 return (jlong)CGColorSpaceCreateDeviceGray(); 414 } 415 416 JNIEXPORT jlong JNICALL OS_NATIVE(CGBitmapContextCreate) 417 (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2, jlong arg3, jlong arg4, jlong arg5, jint arg6) 418 { 419 return (jlong)CGBitmapContextCreate((void*)arg0, (size_t)arg1, (size_t)arg2, (size_t)arg3, (size_t)arg4, (CGColorSpaceRef)arg5, (CGBitmapInfo)arg6); 420 } 421 422 JNIEXPORT void JNICALL OS_NATIVE(CGContextSetAllowsFontSmoothing) 423 (JNIEnv *env, jclass that, jlong arg0, jboolean arg1) 424 { 425 CGContextSetAllowsFontSmoothing((CGContextRef)arg0, (_Bool)arg1); 426 } 427 428 JNIEXPORT void JNICALL OS_NATIVE(CGContextSetAllowsAntialiasing) 429 (JNIEnv *env, jclass that, jlong arg0, jboolean arg1) 430 { 431 CGContextSetAllowsAntialiasing((CGContextRef)arg0, (_Bool)arg1); 432 } 433 434 JNIEXPORT void JNICALL OS_NATIVE(CGContextSetAllowsFontSubpixelPositioning) 435 (JNIEnv *env, jclass that, jlong arg0, jboolean arg1) 436 { 437 CGContextSetAllowsFontSubpixelPositioning((CGContextRef)arg0, (_Bool)arg1); 438 } 439 440 JNIEXPORT void JNICALL OS_NATIVE(CGContextSetAllowsFontSubpixelQuantization) 441 (JNIEnv *env, jclass that, jlong arg0, jboolean arg1) 442 { 443 CGContextSetAllowsFontSubpixelQuantization((CGContextRef)arg0, (_Bool)arg1); 444 } 445 446 JNIEXPORT void JNICALL OS_NATIVE(CGContextSetRGBFillColor) 447 (JNIEnv *env, jclass that, jlong arg0, jdouble arg1, jdouble arg2, jdouble arg3, jdouble arg4) 448 { 449 CGContextSetRGBFillColor((CGContextRef)arg0, (CGFloat)arg1, (CGFloat)arg2, (CGFloat)arg3, (CGFloat)arg4); 450 } 451 452 JNIEXPORT void JNICALL OS_NATIVE(CGContextFillRect) 453 (JNIEnv *env, jclass that, jlong arg0, jobject arg1) 454 { 455 CGRect _arg1, *lparg1=NULL; 456 /* In Only */ 457 if (arg1) if ((lparg1 = getCGRectFields(env, arg1, &_arg1)) == NULL) return; 458 CGContextFillRect((CGContextRef)arg0, *lparg1); 459 } 460 461 JNIEXPORT void JNICALL OS_NATIVE(CGContextTranslateCTM) 462 (JNIEnv *env, jclass that, jlong arg0, jdouble arg1, jdouble arg2) 463 { 464 CGContextTranslateCTM((CGContextRef)arg0, (CGFloat)arg1, (CGFloat)arg2); 465 } 466 467 JNIEXPORT void JNICALL OS_NATIVE(CGContextRelease) 468 (JNIEnv *env, jclass that, jlong arg0) 469 { 470 CGContextRelease((CGContextRef)arg0); 471 } 472 473 JNIEXPORT void JNICALL OS_NATIVE(CGColorSpaceRelease) 474 (JNIEnv *env, jclass that, jlong arg0) 475 { 476 CGColorSpaceRelease((CGColorSpaceRef)arg0); 477 } 478 479 JNIEXPORT jlong JNICALL OS_NATIVE(kCFTypeDictionaryKeyCallBacks) 480 (JNIEnv *env, jclass that) 481 { 482 return (jlong)&kCFTypeDictionaryKeyCallBacks; 483 } 484 485 JNIEXPORT jlong JNICALL OS_NATIVE(kCFTypeDictionaryValueCallBacks) 486 (JNIEnv *env, jclass that) 487 { 488 return (jlong)&kCFTypeDictionaryValueCallBacks; 489 } 490 491 JNIEXPORT jlong JNICALL OS_NATIVE(CFDictionaryCreateMutable) 492 (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2, jlong arg3) 493 { 494 return (jlong)CFDictionaryCreateMutable((CFAllocatorRef)arg0, (CFIndex)arg1, (CFDictionaryKeyCallBacks*)arg2, (CFDictionaryValueCallBacks*)arg3); 495 } 496 497 JNIEXPORT void JNICALL OS_NATIVE(CFDictionaryAddValue) 498 (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2) 499 { 500 CFDictionaryAddValue((CFMutableDictionaryRef)arg0, (void*)arg1, (void*)arg2); 501 } 502 503 JNIEXPORT jlong JNICALL OS_NATIVE(CFDictionaryGetValue) 504 (JNIEnv *env, jclass that, jlong arg0, jlong arg1) 505 { 506 return (jlong)CFDictionaryGetValue((CFDictionaryRef)arg0, (void*)arg1); 507 } 508 509 JNIEXPORT jlong JNICALL OS_NATIVE(kCTFontAttributeName) 510 (JNIEnv *env, jclass that) 511 { 512 return (jlong)kCTFontAttributeName; 513 } 514 515 JNIEXPORT jlong JNICALL OS_NATIVE(kCTParagraphStyleAttributeName) 516 (JNIEnv *env, jclass that) 517 { 518 return (jlong)kCTParagraphStyleAttributeName; 519 } 520 521 JNIEXPORT jlong JNICALL OS_NATIVE(CFAttributedStringCreate) 522 (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2) 523 { 524 return (jlong)CFAttributedStringCreate((CFAllocatorRef)arg0, (CFStringRef)arg1, (CFDictionaryRef)arg2); 525 } 526 527 JNIEXPORT jlong JNICALL OS_NATIVE(CTLineCreateWithAttributedString) 528 (JNIEnv *env, jclass that, jlong arg0) 529 { 530 return (jlong)CTLineCreateWithAttributedString((CFAttributedStringRef)arg0); 531 } 532 533 JNIEXPORT jlong JNICALL OS_NATIVE(CTLineGetGlyphRuns) 534 (JNIEnv *env, jclass that, jlong arg0) 535 { 536 return (jlong)CTLineGetGlyphRuns((CTLineRef)arg0); 537 } 538 539 JNIEXPORT jdouble JNICALL OS_NATIVE(CTLineGetTypographicBounds) 540 (JNIEnv *env, jclass that, jlong arg0) 541 { 542 return (jdouble)CTLineGetTypographicBounds((CTLineRef)arg0, NULL, NULL, NULL); 543 } 544 545 JNIEXPORT jlong JNICALL OS_NATIVE(CTLineGetGlyphCount) 546 (JNIEnv *env, jclass that, jlong arg0) 547 { 548 return (jlong)CTLineGetGlyphCount((CTLineRef)arg0); 549 } 550 551 JNIEXPORT jlong JNICALL OS_NATIVE(CFArrayGetCount) 552 (JNIEnv *env, jclass that, jlong arg0) 553 { 554 return (jlong)CFArrayGetCount((CFArrayRef)arg0); 555 } 556 557 JNIEXPORT jlong JNICALL OS_NATIVE(CFArrayGetValueAtIndex) 558 (JNIEnv *env, jclass that, jlong arg0, jlong arg1) 559 { 560 return (jlong)CFArrayGetValueAtIndex((CFArrayRef)arg0, (CFIndex)arg1); 561 } 562 563 JNIEXPORT jlong JNICALL OS_NATIVE(CTRunGetGlyphCount) 564 (JNIEnv *env, jclass that, jlong arg0) 565 { 566 return (jlong)CTRunGetGlyphCount((CTRunRef)arg0); 567 } 568 569 JNIEXPORT jlong JNICALL OS_NATIVE(CTRunGetAttributes) 570 (JNIEnv *env, jclass that, jlong arg0) 571 { 572 return (jlong)CTRunGetAttributes((CTRunRef)arg0); 573 } 574 575 /**************************************************************************/ 576 /* */ 577 /* Custom Functions */ 578 /* */ 579 /**************************************************************************/ 580 581 582 JNIEXPORT jlong JNICALL OS_NATIVE(CFStringCreateWithCharacters__J_3CJJ) 583 (JNIEnv *env, jclass that, jlong arg0, jcharArray arg1, jlong arg2, jlong arg3) 584 { 585 jchar *lparg1=NULL; 586 jlong rc = 0; 587 if (arg1) if ((lparg1 = (*env)->GetPrimitiveArrayCritical(env, arg1, NULL)) == NULL) goto fail; 588 UniChar* str = lparg1 + arg2; 589 rc = (jlong)CFStringCreateWithCharacters((CFAllocatorRef)arg0, str, (CFIndex)arg3); 590 fail: 591 if (arg1 && lparg1) (*env)->ReleasePrimitiveArrayCritical(env, arg1, lparg1, 0); 592 return rc; 593 } 594 595 JNIEXPORT jint JNICALL OS_NATIVE(CTRunGetGlyphs) 596 (JNIEnv *env, jclass that, jlong runRef, jint slotMask, jint start, jintArray bufferRef) 597 { 598 CTRunRef run = (CTRunRef)runRef; 599 const CGGlyph * glyphs = CTRunGetGlyphsPtr(run); 600 int i = 0; 601 if (glyphs) { 602 jint* buffer = (*env)->GetPrimitiveArrayCritical(env, bufferRef, NULL); 603 if (buffer) { 604 CFIndex count = CTRunGetGlyphCount(run); 605 while(i < count) { 606 buffer[start + i] = slotMask | (glyphs[i] & 0xFFFF); 607 i++; 608 } 609 (*env)->ReleasePrimitiveArrayCritical(env, bufferRef, buffer, 0); 610 } 611 } 612 return i; 613 } 614 615 JNIEXPORT jint JNICALL OS_NATIVE(CTRunGetPositions) 616 (JNIEnv *env, jclass that, jlong runRef, jint start, jfloatArray bufferRef) 617 { 618 CTRunRef run = (CTRunRef)runRef; 619 const CGPoint* positions = CTRunGetPositionsPtr(run); 620 int j = 0; 621 if (positions) { 622 jfloat* buffer = (*env)->GetPrimitiveArrayCritical(env, bufferRef, NULL); 623 if (buffer) { 624 CFIndex count = CTRunGetGlyphCount(run); 625 int i = 0; 626 while (i < count) { 627 CGPoint pos = positions[i++]; 628 buffer[start + j++] = pos.x; 629 buffer[start + j++] = pos.y; 630 } 631 (*env)->ReleasePrimitiveArrayCritical(env, bufferRef, buffer, 0); 632 } 633 } 634 return j; 635 } 636 637 JNIEXPORT jint JNICALL OS_NATIVE(CTRunGetStringIndices) 638 (JNIEnv *env, jclass that, jlong runRef, jint start, jintArray bufferRef) 639 { 640 CTRunRef run = (CTRunRef)runRef; 641 const CFIndex* indices = CTRunGetStringIndicesPtr(run); 642 int i = 0; 643 if (indices) { 644 jint* buffer = (*env)->GetPrimitiveArrayCritical(env, bufferRef, NULL); 645 if (buffer) { 646 CFIndex count = CTRunGetGlyphCount(run); 647 while(i < count) { 648 buffer[start + i] = indices[i]; 649 i++; 650 } 651 (*env)->ReleasePrimitiveArrayCritical(env, bufferRef, buffer, 0); 652 } 653 } 654 return i; 655 } 656 657 JNIEXPORT jstring JNICALL OS_NATIVE(CTFontCopyAttributeDisplayName) 658 (JNIEnv *env, jclass that, jlong arg0) 659 { 660 CFStringRef stringRef = CTFontCopyAttribute((CTFontRef)arg0, kCTFontDisplayNameAttribute); 661 if (stringRef == NULL) return NULL; 662 CFIndex length = CFStringGetLength(stringRef); 663 UniChar buffer[length]; 664 CFStringGetCharacters(stringRef, CFRangeMake(0, length), buffer); 665 CFRelease(stringRef); 666 return (*env)->NewString(env, (jchar *)buffer, length); 667 } 668 669 JNIEXPORT jlong JNICALL OS_NATIVE(CTFontCreate) 670 (JNIEnv *env, jclass that, jlong fileName, jlong psName, jdouble size, jobject matrix) 671 { 672 CGAffineTransform transform, *transformPtr = NULL; 673 CTFontRef fontRef = NULL; 674 675 if (matrix) if ((transformPtr = getCGAffineTransformFields(env, matrix, &transform)) == NULL) goto fail; 676 677 CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)fileName, kCFURLPOSIXPathStyle, false); 678 CGDataProviderRef dataProvider = CGDataProviderCreateWithURL(url); 679 CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider); 680 if (cgFont) { 681 fontRef = CTFontCreateWithGraphicsFont(cgFont, (CGFloat)size, (CGAffineTransform*)transformPtr, 0); 682 CFRelease(cgFont); 683 } else { 684 // TTC files are supported by CGFontCreateWithDataProvider, fallback to CTFontCreateWithName. 685 fontRef = CTFontCreateWithName((CFStringRef)psName, (CGFloat)size, (CGAffineTransform*)transformPtr); 686 } 687 CFRelease(dataProvider); 688 CFRelease(url); 689 fail: 690 /* In only */ 691 // if (arg2 && lparg2) setCGAffineTransformFields(env, arg2, lparg2); 692 return (jlong)fontRef; 693 } 694 695 JNIEXPORT jbyteArray JNICALL OS_NATIVE(CGBitmapContextGetData) 696 (JNIEnv *env, jclass that, jlong arg0, jint dstWidth, jint dstHeight, jint bpp) 697 { 698 jbyteArray result = NULL; 699 if (dstWidth < 0) return NULL; 700 if (dstHeight < 0) return NULL; 701 if (bpp != 8 && bpp != 24) return NULL; 702 CGContextRef context = (CGContextRef)arg0; 703 if (context == NULL) return NULL; 704 jbyte *srcData = (jbyte*)CGBitmapContextGetData(context); 705 706 if (srcData) { 707 /* Use one byte per pixel for grayscale */ 708 size_t srcWidth = CGBitmapContextGetWidth(context); 709 if (srcWidth < dstWidth) return NULL; 710 size_t srcHeight = CGBitmapContextGetHeight(context); 711 if (srcHeight < dstHeight) return NULL; 712 size_t srcBytesPerRow = CGBitmapContextGetBytesPerRow(context); 713 size_t srcStep = CGBitmapContextGetBitsPerPixel(context) / 8; 714 int srcOffset = (srcHeight - dstHeight) * srcBytesPerRow; 715 716 717 //bits per pixel, either 8 for gray or 24 for LCD. 718 int dstStep = bpp / 8; 719 size_t size = dstWidth * dstHeight * dstStep; 720 jbyte* data = (jbyte*)calloc(size, sizeof(jbyte)); 721 if (data == NULL) return NULL; 722 723 int x, y, sx; 724 int dstOffset = 0; 725 for (y = 0; y < dstHeight; y++) { 726 for (x = 0, sx = 0; x < dstWidth; x++, dstOffset += dstStep, sx += srcStep) { 727 if (dstStep == 1) { 728 /* BGRA or Gray to Gray */ 729 data[dstOffset] = 0xFF - srcData[srcOffset + sx]; 730 } else { 731 /* BGRA to RGB */ 732 data[dstOffset] = 0xFF - srcData[srcOffset + sx + 2]; 733 data[dstOffset + 1] = 0xFF - srcData[srcOffset + sx + 1]; 734 data[dstOffset + 2] = 0xFF - srcData[srcOffset + sx]; 735 } 736 } 737 srcOffset += srcBytesPerRow; 738 } 739 740 result = (*env)->NewByteArray(env, size); 741 if (result) { 742 (*env)->SetByteArrayRegion(env, result, 0, size, data); 743 } 744 free(data); 745 } 746 return result; 747 } 748 749 JNIEXPORT void JNICALL OS_NATIVE(CGRectApplyAffineTransform) 750 (JNIEnv *env, jclass that, jobject arg0, jobject arg1) 751 { 752 CGRect _arg0, *lparg0=NULL; 753 CGAffineTransform _arg1, *lparg1=NULL; 754 if (arg0) if ((lparg0 = getCGRectFields(env, arg0, &_arg0)) == NULL) goto fail; 755 if (arg1) if ((lparg1 = getCGAffineTransformFields(env, arg1, &_arg1)) == NULL) goto fail; 756 _arg0 = CGRectApplyAffineTransform(*lparg0, *lparg1); 757 fail: 758 /* In Only */ 759 // if (arg1 && lparg1) setCGAffineTransformFields(env, arg1, lparg1); 760 if (arg0 && lparg0) setCGRectFields(env, arg0, lparg0); 761 } 762 763 JNIEXPORT void JNICALL OS_NATIVE(CTFontDrawGlyphs) 764 (JNIEnv *env, jclass that, jlong arg0, jshort arg1, jdouble arg2, jdouble arg3, jlong contextRef) 765 { 766 /* Custom: only takes one glyph at the time */ 767 CGGlyph glyphs[] = {arg1}; 768 CGPoint pos[] = {CGPointMake(arg2, arg3)}; 769 CTFontDrawGlyphs((CTFontRef)arg0, glyphs, pos, 1, (CGContextRef)contextRef); 770 } 771 772 JNIEXPORT jboolean JNICALL OS_NATIVE(CTFontGetBoundingRectForGlyphUsingTables) 773 (JNIEnv *env, jclass that, jlong arg1, jshort arg2, jshort arg3, jintArray arg4) 774 { 775 /* The following code is based on scalerMethods.c#getGlyphBoundingBoxNative */ 776 CTFontRef fontRef = (CTFontRef)arg1; 777 CTFontTableOptions options = kCTFontTableOptionNoOptions; 778 CFDataRef tableData; 779 CFIndex length; 780 781 /* indexToLocFormat is stored in Java for performance */ 782 // tableData = CTFontCopyTable(fontRef, kCTFontTableHead, options); 783 // const UInt8 * head = CFDataGetBytePtr(tableData); 784 // UInt16 indexToLocFormat = CFSwapInt16BigToHost(*((SInt16*)(head + 50))); 785 // printf("here0 indexToLocFormat=%u \n", indexToLocFormat); fflush(stdout); 786 // CFRelease(tableData); 787 UInt16 indexToLocFormat = arg3; 788 789 tableData = CTFontCopyTable(fontRef, kCTFontTableLoca, options); 790 if (tableData == NULL) return FALSE; 791 length = CFDataGetLength(tableData); 792 UInt32 offset1 = 0, offset2 = 0; 793 UInt32 index = arg2 & 0xFFFF; 794 if (indexToLocFormat) { 795 const UInt32 * loca = (const UInt32 *)CFDataGetBytePtr(tableData); 796 if (loca != NULL && (index + 1) < (length / 4)) { 797 offset1 = CFSwapInt32BigToHost(loca[index]); 798 offset2 = CFSwapInt32BigToHost(loca[index + 1]); 799 } 800 } else { 801 const UInt16 * loca = (const UInt16 *)CFDataGetBytePtr(tableData); 802 if (loca != NULL && (index + 1) < (length / 2)) { 803 offset1 = CFSwapInt16BigToHost(loca[index]) << 1; 804 offset2 = CFSwapInt16BigToHost(loca[index + 1]) << 1; 805 } 806 } 807 CFRelease(tableData); 808 jboolean result = FALSE; 809 if (offset2 > offset1 && (offset2 - offset1) >= 10) { 810 tableData = CTFontCopyTable(fontRef, kCTFontTableGlyf, options); 811 if (tableData == NULL) return FALSE; 812 length = CFDataGetLength(tableData); 813 const UInt8 * ptr = CFDataGetBytePtr(tableData); 814 if (ptr != NULL && (offset1 + 10) < length) { 815 const SInt16 * glyf = (const SInt16 *)(ptr + offset1); 816 /* 817 * CFSwapInt16BigToHost returns an unsigned short, need 818 * to cast back to signed short before assigning to jint. 819 */ 820 jint data[] = { 821 (SInt16)CFSwapInt16BigToHost(glyf[1]), 822 (SInt16)CFSwapInt16BigToHost(glyf[2]), 823 (SInt16)CFSwapInt16BigToHost(glyf[3]), 824 (SInt16)CFSwapInt16BigToHost(glyf[4]), 825 }; 826 (*env)->SetIntArrayRegion(env, arg4, 0, 4, data); 827 result = TRUE; 828 } 829 CFRelease(tableData); 830 } 831 return result; 832 } 833 834 JNIEXPORT jdouble JNICALL OS_NATIVE(CTFontGetAdvancesForGlyphs) 835 (JNIEnv *env, jclass that, jlong arg0, jint arg1, jshort arg2, jobject arg3) 836 { 837 /* Custom: only takes one glyph at the time */ 838 jdouble rc = 0; 839 CGGlyph glyphs[] = {arg2}; 840 CGSize _arg3, *lparg3=NULL; 841 if (arg3) if ((lparg3 = getCGSizeFields(env, arg3, &_arg3)) == NULL) goto fail; 842 rc = (jdouble)CTFontGetAdvancesForGlyphs((CTFontRef)arg0, (CTFontOrientation)arg1, glyphs, lparg3, 1); 843 fail: 844 if (arg3 && lparg3) setCGSizeFields(env, arg3, &_arg3); 845 return rc; 846 } 847 848 JNIEXPORT jobject JNICALL OS_NATIVE(CGPathGetPathBoundingBox) 849 (JNIEnv *env, jclass that, jlong arg0) 850 { 851 CGRect result = CGPathGetPathBoundingBox((CGPathRef)arg0); 852 return newCGRect(env, &result); 853 } 854 855 JNIEXPORT jlong JNICALL OS_NATIVE(CTParagraphStyleCreate) 856 (JNIEnv *env, jclass that, jint arg0) 857 { 858 CTWritingDirection dir = (CTWritingDirection)arg0; 859 CTParagraphStyleSetting settings[] = { 860 {kCTParagraphStyleSpecifierBaseWritingDirection, sizeof(dir), &dir} 861 }; 862 return (jlong)CTParagraphStyleCreate(settings, sizeof(settings) / sizeof(settings[0])); 863 } 864 865 /***********************************************/ 866 /* Glyph Outline */ 867 /***********************************************/ 868 869 static const int DEFAULT_LEN_TYPES = 10; 870 static const int DEFAULT_LEN_COORDS = 50; 871 typedef struct _PathData { 872 jbyte* pointTypes; 873 int numTypes; 874 int lenTypes; 875 jfloat* pointCoords; 876 int numCoords; 877 int lenCoords; 878 } PathData; 879 880 void pathApplierFunctionFast(void *i, const CGPathElement *e) { 881 PathData *info = (PathData *)i; 882 if (info->numTypes == info->lenTypes) { 883 info->lenTypes += DEFAULT_LEN_TYPES; 884 info->pointTypes = (jbyte*)realloc(info->pointTypes, info->lenTypes * sizeof(jbyte)); 885 } 886 jint type; 887 int coordCount = 0; 888 switch (e->type) { 889 case kCGPathElementMoveToPoint: 890 type = 0; 891 coordCount = 1; 892 break; 893 case kCGPathElementAddLineToPoint: 894 type = 1; 895 coordCount = 1; 896 break; 897 case kCGPathElementAddQuadCurveToPoint: 898 type = 2; 899 coordCount = 2; 900 break; 901 case kCGPathElementAddCurveToPoint: 902 type = 3; 903 coordCount = 3; 904 break; 905 case kCGPathElementCloseSubpath: 906 type = 4; 907 coordCount = 0; 908 break; 909 } 910 info->pointTypes[info->numTypes++] = type; 911 912 if (info->numCoords + (coordCount * 2) > info->lenCoords) { 913 info->lenCoords += DEFAULT_LEN_COORDS; 914 info->pointCoords = (jfloat*)realloc(info->pointCoords, info->lenCoords * sizeof(jfloat)); 915 } 916 int j; 917 for (j = 0; j < coordCount; j++) { 918 CGPoint pt = e->points[j]; 919 info->pointCoords[info->numCoords++] = pt.x; 920 info->pointCoords[info->numCoords++] = pt.y; 921 } 922 } 923 924 JNIEXPORT jobject JNICALL OS_NATIVE(CGPathApply) 925 (JNIEnv *env, jclass that, jlong arg0) 926 { 927 jobject path2D = NULL; 928 PathData data; 929 data.pointTypes = (jbyte*)malloc(sizeof(jbyte) * DEFAULT_LEN_TYPES); 930 data.numTypes = 0; 931 data.lenTypes = DEFAULT_LEN_TYPES; 932 data.pointCoords = (jfloat*)malloc(sizeof(jfloat) * DEFAULT_LEN_COORDS); 933 data.numCoords = 0; 934 data.lenCoords = DEFAULT_LEN_COORDS; 935 936 CGPathApply((CGPathRef)arg0, &data, pathApplierFunctionFast); 937 938 static jclass path2DClass = NULL; 939 static jmethodID path2DCtr = NULL; 940 if (path2DClass == NULL) { 941 jclass tmpClass = (*env)->FindClass(env, "com/sun/javafx/geom/Path2D"); 942 if ((*env)->ExceptionOccurred(env) || !tmpClass) { 943 fprintf(stderr, "OS_NATIVE error: JNI exception or tmpClass == NULL"); 944 goto fail; 945 } 946 path2DClass = (jclass)(*env)->NewGlobalRef(env, tmpClass); 947 path2DCtr = (*env)->GetMethodID(env, path2DClass, "<init>", "(I[BI[FI)V"); 948 if ((*env)->ExceptionOccurred(env) || !path2DCtr) { 949 fprintf(stderr, "OS_NATIVE error: JNI exception or path2DCtr == NULL"); 950 goto fail; 951 } 952 } 953 954 jbyteArray types = (*env)->NewByteArray(env, data.numTypes); 955 jfloatArray coords = (*env)->NewFloatArray(env, data.numCoords); 956 if (types && coords) { 957 (*env)->SetByteArrayRegion(env, types, 0, data.numTypes, data.pointTypes); 958 if ((*env)->ExceptionOccurred(env)) { 959 fprintf(stderr, "OS_NATIVE error: JNI exception"); 960 goto fail; 961 } 962 (*env)->SetFloatArrayRegion(env, coords, 0, data.numCoords, data.pointCoords); 963 if ((*env)->ExceptionOccurred(env)) { 964 fprintf(stderr, "OS_NATIVE error: JNI exception"); 965 goto fail; 966 } 967 path2D = (*env)->NewObject(env, path2DClass, path2DCtr, 968 0 /*winding rule*/, 969 types, data.numTypes, 970 coords, data.numCoords); 971 if ((*env)->ExceptionOccurred(env) || !path2D) { 972 goto fail; 973 } 974 } 975 fail: 976 free(data.pointTypes); 977 free(data.pointCoords); 978 return path2D; 979 } 980 981 #endif /* TARGET_OS_MAC */ 982 #endif /* __APPLE__ */ 983