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 int j = 0; 677 if (positions) { 678 jfloat* buffer = (*env)->GetPrimitiveArrayCritical(env, bufferRef, NULL); 679 if (buffer) { 680 CFIndex count = CTRunGetGlyphCount(run); 681 int i = 0; 682 while (i < count) { 683 CGPoint pos = positions[i++]; 684 buffer[start + j++] = pos.x; 685 buffer[start + j++] = pos.y; 686 } 687 (*env)->ReleasePrimitiveArrayCritical(env, bufferRef, buffer, 0); 688 } 689 } 690 return j; 691 } 692 693 JNIEXPORT jint JNICALL OS_NATIVE(CTRunGetStringIndices) 694 (JNIEnv *env, jclass that, jlong runRef, jint start, jintArray bufferRef) 695 { 696 CTRunRef run = (CTRunRef)runRef; 697 const CFIndex* indices = CTRunGetStringIndicesPtr(run); 698 CFIndex count = CTRunGetGlyphCount(run); 699 if (count == 0) { 700 return 0; 701 } 702 703 CFIndex* tempIndices = NULL; 704 if (!indices) { 705 tempIndices = (CFIndex*) malloc(count * sizeof(CFIndex)); 706 if (!tempIndices) { 707 return 0; 708 } 709 710 CTRunGetStringIndices(run, CFRangeMake(0, 0), tempIndices); 711 indices = tempIndices; 712 } 713 714 int i = 0; 715 if (indices) { 716 jint* buffer = (*env)->GetPrimitiveArrayCritical(env, bufferRef, NULL); 717 if (buffer) { 718 while(i < count) { 719 buffer[start + i] = indices[i]; 720 i++; 721 } 722 (*env)->ReleasePrimitiveArrayCritical(env, bufferRef, buffer, 0); 723 } 724 725 if (tempIndices) { 726 free(tempIndices); 727 } 728 } 729 return i; 730 } 731 732 JNIEXPORT jstring JNICALL OS_NATIVE(CTFontCopyAttributeDisplayName) 733 (JNIEnv *env, jclass that, jlong arg0) 734 { 735 CFStringRef stringRef = CTFontCopyAttribute((CTFontRef)arg0, kCTFontDisplayNameAttribute); 736 if (stringRef == NULL) return NULL; 737 CFIndex length = CFStringGetLength(stringRef); 738 UniChar buffer[length]; 739 CFStringGetCharacters(stringRef, CFRangeMake(0, length), buffer); 740 CFRelease(stringRef); 741 return (*env)->NewString(env, (jchar *)buffer, length); 742 } 743 744 JNIEXPORT jbyteArray JNICALL OS_NATIVE(CGBitmapContextGetData) 745 (JNIEnv *env, jclass that, jlong arg0, jint dstWidth, jint dstHeight, jint bpp) 746 { 747 jbyteArray result = NULL; 748 if (dstWidth < 0) return NULL; 749 if (dstHeight < 0) return NULL; 750 if (bpp != 8 && bpp != 24) return NULL; 751 CGContextRef context = (CGContextRef)arg0; 752 if (context == NULL) return NULL; 753 jbyte *srcData = (jbyte*)CGBitmapContextGetData(context); 754 755 if (srcData) { 756 /* Use one byte per pixel for grayscale */ 757 size_t srcWidth = CGBitmapContextGetWidth(context); 758 if (srcWidth < dstWidth) return NULL; 759 size_t srcHeight = CGBitmapContextGetHeight(context); 760 if (srcHeight < dstHeight) return NULL; 761 size_t srcBytesPerRow = CGBitmapContextGetBytesPerRow(context); 762 size_t srcStep = CGBitmapContextGetBitsPerPixel(context) / 8; 763 int srcOffset = (srcHeight - dstHeight) * srcBytesPerRow; 764 765 766 //bits per pixel, either 8 for gray or 24 for LCD. 767 int dstStep = bpp / 8; 768 size_t size = dstWidth * dstHeight * dstStep; 769 jbyte* data = (jbyte*)calloc(size, sizeof(jbyte)); 770 if (data == NULL) return NULL; 771 772 int x, y, sx; 773 int dstOffset = 0; 774 for (y = 0; y < dstHeight; y++) { 775 for (x = 0, sx = 0; x < dstWidth; x++, dstOffset += dstStep, sx += srcStep) { 776 if (dstStep == 1) { 777 /* BGRA or Gray to Gray */ 778 data[dstOffset] = 0xFF - srcData[srcOffset + sx]; 779 } else { 780 /* BGRA to RGB */ 781 data[dstOffset] = 0xFF - srcData[srcOffset + sx + 2]; 782 data[dstOffset + 1] = 0xFF - srcData[srcOffset + sx + 1]; 783 data[dstOffset + 2] = 0xFF - srcData[srcOffset + sx]; 784 } 785 } 786 srcOffset += srcBytesPerRow; 787 } 788 789 result = (*env)->NewByteArray(env, size); 790 if (result) { 791 (*env)->SetByteArrayRegion(env, result, 0, size, data); 792 } 793 free(data); 794 } 795 return result; 796 } 797 798 JNIEXPORT void JNICALL OS_NATIVE(CGRectApplyAffineTransform) 799 (JNIEnv *env, jclass that, jobject arg0, jobject arg1) 800 { 801 CGRect _arg0, *lparg0=NULL; 802 CGAffineTransform _arg1, *lparg1=NULL; 803 if (arg0) if ((lparg0 = getCGRectFields(env, arg0, &_arg0)) == NULL) goto fail; 804 if (arg1) if ((lparg1 = getCGAffineTransformFields(env, arg1, &_arg1)) == NULL) goto fail; 805 _arg0 = CGRectApplyAffineTransform(*lparg0, *lparg1); 806 fail: 807 /* In Only */ 808 // if (arg1 && lparg1) setCGAffineTransformFields(env, arg1, lparg1); 809 if (arg0 && lparg0) setCGRectFields(env, arg0, lparg0); 810 } 811 812 JNIEXPORT void JNICALL OS_NATIVE(CTFontDrawGlyphs) 813 (JNIEnv *env, jclass that, jlong arg0, jshort arg1, jdouble arg2, jdouble arg3, jlong contextRef) 814 { 815 /* Custom: only takes one glyph at the time */ 816 CGGlyph glyphs[] = {arg1}; 817 CGPoint pos[] = {CGPointMake(arg2, arg3)}; 818 CTFontDrawGlyphs((CTFontRef)arg0, glyphs, pos, 1, (CGContextRef)contextRef); 819 } 820 821 JNIEXPORT jboolean JNICALL OS_NATIVE(CTFontGetBoundingRectForGlyphUsingTables) 822 (JNIEnv *env, jclass that, jlong arg1, jshort arg2, jshort arg3, jintArray arg4) 823 { 824 /* The following code is based on scalerMethods.c#getGlyphBoundingBoxNative */ 825 CTFontRef fontRef = (CTFontRef)arg1; 826 CTFontTableOptions options = kCTFontTableOptionNoOptions; 827 CFDataRef tableData; 828 CFIndex length; 829 830 /* indexToLocFormat is stored in Java for performance */ 831 // tableData = CTFontCopyTable(fontRef, kCTFontTableHead, options); 832 // const UInt8 * head = CFDataGetBytePtr(tableData); 833 // UInt16 indexToLocFormat = CFSwapInt16BigToHost(*((SInt16*)(head + 50))); 834 // printf("here0 indexToLocFormat=%u \n", indexToLocFormat); fflush(stdout); 835 // CFRelease(tableData); 836 UInt16 indexToLocFormat = arg3; 837 838 tableData = CTFontCopyTable(fontRef, kCTFontTableLoca, options); 839 if (tableData == NULL) return FALSE; 840 length = CFDataGetLength(tableData); 841 UInt32 offset1 = 0, offset2 = 0; 842 UInt32 index = arg2 & 0xFFFF; 843 if (indexToLocFormat) { 844 const UInt32 * loca = (const UInt32 *)CFDataGetBytePtr(tableData); 845 if (loca != NULL && (index + 1) < (length / 4)) { 846 offset1 = CFSwapInt32BigToHost(loca[index]); 847 offset2 = CFSwapInt32BigToHost(loca[index + 1]); 848 } 849 } else { 850 const UInt16 * loca = (const UInt16 *)CFDataGetBytePtr(tableData); 851 if (loca != NULL && (index + 1) < (length / 2)) { 852 offset1 = CFSwapInt16BigToHost(loca[index]) << 1; 853 offset2 = CFSwapInt16BigToHost(loca[index + 1]) << 1; 854 } 855 } 856 CFRelease(tableData); 857 jboolean result = FALSE; 858 if (offset2 > offset1 && (offset2 - offset1) >= 10) { 859 tableData = CTFontCopyTable(fontRef, kCTFontTableGlyf, options); 860 if (tableData == NULL) return FALSE; 861 length = CFDataGetLength(tableData); 862 const UInt8 * ptr = CFDataGetBytePtr(tableData); 863 if (ptr != NULL && (offset1 + 10) < length) { 864 const SInt16 * glyf = (const SInt16 *)(ptr + offset1); 865 /* 866 * CFSwapInt16BigToHost returns an unsigned short, need 867 * to cast back to signed short before assigning to jint. 868 */ 869 jint data[] = { 870 (SInt16)CFSwapInt16BigToHost(glyf[1]), 871 (SInt16)CFSwapInt16BigToHost(glyf[2]), 872 (SInt16)CFSwapInt16BigToHost(glyf[3]), 873 (SInt16)CFSwapInt16BigToHost(glyf[4]), 874 }; 875 (*env)->SetIntArrayRegion(env, arg4, 0, 4, data); 876 result = TRUE; 877 } 878 CFRelease(tableData); 879 } 880 return result; 881 } 882 883 JNIEXPORT jdouble JNICALL OS_NATIVE(CTFontGetAdvancesForGlyphs) 884 (JNIEnv *env, jclass that, jlong arg0, jint arg1, jshort arg2, jobject arg3) 885 { 886 /* Custom: only takes one glyph at the time */ 887 jdouble rc = 0; 888 CGGlyph glyphs[] = {arg2}; 889 CGSize _arg3, *lparg3=NULL; 890 if (arg3) if ((lparg3 = getCGSizeFields(env, arg3, &_arg3)) == NULL) goto fail; 891 rc = (jdouble)CTFontGetAdvancesForGlyphs((CTFontRef)arg0, (CTFontOrientation)arg1, glyphs, lparg3, 1); 892 fail: 893 if (arg3 && lparg3) setCGSizeFields(env, arg3, &_arg3); 894 return rc; 895 } 896 897 JNIEXPORT jobject JNICALL OS_NATIVE(CGPathGetPathBoundingBox) 898 (JNIEnv *env, jclass that, jlong arg0) 899 { 900 CGRect result = CGPathGetPathBoundingBox((CGPathRef)arg0); 901 return newCGRect(env, &result); 902 } 903 904 JNIEXPORT jlong JNICALL OS_NATIVE(CTParagraphStyleCreate) 905 (JNIEnv *env, jclass that, jint arg0) 906 { 907 CTWritingDirection dir = (CTWritingDirection)arg0; 908 CTParagraphStyleSetting settings[] = { 909 {kCTParagraphStyleSpecifierBaseWritingDirection, sizeof(dir), &dir} 910 }; 911 return (jlong)CTParagraphStyleCreate(settings, sizeof(settings) / sizeof(settings[0])); 912 } 913 914 /***********************************************/ 915 /* Glyph Outline */ 916 /***********************************************/ 917 918 static const int DEFAULT_LEN_TYPES = 10; 919 static const int DEFAULT_LEN_COORDS = 50; 920 typedef struct _PathData { 921 jbyte* pointTypes; 922 int numTypes; 923 int lenTypes; 924 jfloat* pointCoords; 925 int numCoords; 926 int lenCoords; 927 } PathData; 928 929 void pathApplierFunctionFast(void *i, const CGPathElement *e) { 930 PathData *info = (PathData *)i; 931 if (info->numTypes == info->lenTypes) { 932 info->lenTypes += DEFAULT_LEN_TYPES; 933 info->pointTypes = (jbyte*)realloc(info->pointTypes, info->lenTypes * sizeof(jbyte)); 934 } 935 jint type; 936 int coordCount = 0; 937 switch (e->type) { 938 case kCGPathElementMoveToPoint: 939 type = 0; 940 coordCount = 1; 941 break; 942 case kCGPathElementAddLineToPoint: 943 type = 1; 944 coordCount = 1; 945 break; 946 case kCGPathElementAddQuadCurveToPoint: 947 type = 2; 948 coordCount = 2; 949 break; 950 case kCGPathElementAddCurveToPoint: 951 type = 3; 952 coordCount = 3; 953 break; 954 case kCGPathElementCloseSubpath: 955 type = 4; 956 coordCount = 0; 957 break; 958 } 959 info->pointTypes[info->numTypes++] = type; 960 961 if (info->numCoords + (coordCount * 2) > info->lenCoords) { 962 info->lenCoords += DEFAULT_LEN_COORDS; 963 info->pointCoords = (jfloat*)realloc(info->pointCoords, info->lenCoords * sizeof(jfloat)); 964 } 965 int j; 966 for (j = 0; j < coordCount; j++) { 967 CGPoint pt = e->points[j]; 968 info->pointCoords[info->numCoords++] = pt.x; 969 info->pointCoords[info->numCoords++] = pt.y; 970 } 971 } 972 973 JNIEXPORT jobject JNICALL OS_NATIVE(CGPathApply) 974 (JNIEnv *env, jclass that, jlong arg0) 975 { 976 jobject path2D = NULL; 977 PathData data; 978 data.pointTypes = (jbyte*)malloc(sizeof(jbyte) * DEFAULT_LEN_TYPES); 979 data.numTypes = 0; 980 data.lenTypes = DEFAULT_LEN_TYPES; 981 data.pointCoords = (jfloat*)malloc(sizeof(jfloat) * DEFAULT_LEN_COORDS); 982 data.numCoords = 0; 983 data.lenCoords = DEFAULT_LEN_COORDS; 984 985 CGPathApply((CGPathRef)arg0, &data, pathApplierFunctionFast); 986 987 static jclass path2DClass = NULL; 988 static jmethodID path2DCtr = NULL; 989 if (path2DClass == NULL) { 990 jclass tmpClass = (*env)->FindClass(env, "com/sun/javafx/geom/Path2D"); 991 if ((*env)->ExceptionOccurred(env) || !tmpClass) { 992 fprintf(stderr, "OS_NATIVE error: JNI exception or tmpClass == NULL"); 993 goto fail; 994 } 995 path2DClass = (jclass)(*env)->NewGlobalRef(env, tmpClass); 996 path2DCtr = (*env)->GetMethodID(env, path2DClass, "<init>", "(I[BI[FI)V"); 997 if ((*env)->ExceptionOccurred(env) || !path2DCtr) { 998 fprintf(stderr, "OS_NATIVE error: JNI exception or path2DCtr == NULL"); 999 goto fail; 1000 } 1001 } 1002 1003 jbyteArray types = (*env)->NewByteArray(env, data.numTypes); 1004 jfloatArray coords = (*env)->NewFloatArray(env, data.numCoords); 1005 if (types && coords) { 1006 (*env)->SetByteArrayRegion(env, types, 0, data.numTypes, data.pointTypes); 1007 if ((*env)->ExceptionOccurred(env)) { 1008 fprintf(stderr, "OS_NATIVE error: JNI exception"); 1009 goto fail; 1010 } 1011 (*env)->SetFloatArrayRegion(env, coords, 0, data.numCoords, data.pointCoords); 1012 if ((*env)->ExceptionOccurred(env)) { 1013 fprintf(stderr, "OS_NATIVE error: JNI exception"); 1014 goto fail; 1015 } 1016 path2D = (*env)->NewObject(env, path2DClass, path2DCtr, 1017 0 /*winding rule*/, 1018 types, data.numTypes, 1019 coords, data.numCoords); 1020 if ((*env)->ExceptionOccurred(env) || !path2D) { 1021 goto fail; 1022 } 1023 } 1024 fail: 1025 free(data.pointTypes); 1026 free(data.pointCoords); 1027 return path2D; 1028 } 1029 1030 #endif /* TARGET_OS_MAC */ 1031 #endif /* __APPLE__ */ 1032