/* * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #ifdef __APPLE__ #include #if TARGET_OS_MAC #include #include #import #if TARGET_OS_IPHONE #import #import #else #import #endif #define OS_NATIVE(func) Java_com_sun_javafx_font_coretext_OS_##func extern jboolean checkAndClearException(JNIEnv *env); jboolean checkAndClearException(JNIEnv *env) { jthrowable t = (*env)->ExceptionOccurred(env); if (!t) { return JNI_FALSE; } (*env)->ExceptionClear(env); return JNI_TRUE; } /**************************************************************************/ /* */ /* Structs */ /* */ /**************************************************************************/ typedef struct CGAffineTransform_FID_CACHE { int cached; jclass clazz; jfieldID a, b, c, d, tx, ty; jmethodID init; } CGAffineTransform_FID_CACHE; CGAffineTransform_FID_CACHE CGAffineTransformFc; void cacheCGAffineTransformFields(JNIEnv *env) { if (CGAffineTransformFc.cached) return; jclass tmpClass = (*env)->FindClass(env, "com/sun/javafx/font/coretext/CGAffineTransform"); if (checkAndClearException(env) || !tmpClass) { fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or tmpClass == NULL"); return; } CGAffineTransformFc.clazz = (jclass)(*env)->NewGlobalRef(env, tmpClass); CGAffineTransformFc.a = (*env)->GetFieldID(env, CGAffineTransformFc.clazz, "a", "D"); if (checkAndClearException(env) || !CGAffineTransformFc.a) { fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or a == NULL"); return; } CGAffineTransformFc.b = (*env)->GetFieldID(env, CGAffineTransformFc.clazz, "b", "D"); if (checkAndClearException(env) || !CGAffineTransformFc.b) { fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or b == NULL"); return; } CGAffineTransformFc.c = (*env)->GetFieldID(env, CGAffineTransformFc.clazz, "c", "D"); if (checkAndClearException(env) || !CGAffineTransformFc.c) { fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or c == NULL"); return; } CGAffineTransformFc.d = (*env)->GetFieldID(env, CGAffineTransformFc.clazz, "d", "D"); if (checkAndClearException(env) || !CGAffineTransformFc.d) { fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or d == NULL"); return; } CGAffineTransformFc.tx = (*env)->GetFieldID(env, CGAffineTransformFc.clazz, "tx", "D"); if (checkAndClearException(env) || !CGAffineTransformFc.tx) { fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or tx == NULL"); return; } CGAffineTransformFc.ty = (*env)->GetFieldID(env, CGAffineTransformFc.clazz, "ty", "D"); if (checkAndClearException(env) || !CGAffineTransformFc.ty) { fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or ty == NULL"); return; } CGAffineTransformFc.init = (*env)->GetMethodID(env, CGAffineTransformFc.clazz, "", "()V"); if (checkAndClearException(env) || !CGAffineTransformFc.init) { fprintf(stderr, "cacheCGAffineTransformFields error: JNI exception or init == NULL"); return; } CGAffineTransformFc.cached = 1; } CGAffineTransform *getCGAffineTransformFields(JNIEnv *env, jobject lpObject, CGAffineTransform *lpStruct) { if (!CGAffineTransformFc.cached) cacheCGAffineTransformFields(env); lpStruct->a = (*env)->GetDoubleField(env, lpObject, CGAffineTransformFc.a); lpStruct->b = (*env)->GetDoubleField(env, lpObject, CGAffineTransformFc.b); lpStruct->c = (*env)->GetDoubleField(env, lpObject, CGAffineTransformFc.c); lpStruct->d = (*env)->GetDoubleField(env, lpObject, CGAffineTransformFc.d); lpStruct->tx = (*env)->GetDoubleField(env, lpObject, CGAffineTransformFc.tx); lpStruct->ty = (*env)->GetDoubleField(env, lpObject, CGAffineTransformFc.ty); return lpStruct; } void setCGAffineTransformFields(JNIEnv *env, jobject lpObject, CGAffineTransform *lpStruct) { if (!CGAffineTransformFc.cached) cacheCGAffineTransformFields(env); (*env)->SetDoubleField(env, lpObject, CGAffineTransformFc.a, (jdouble)lpStruct->a); (*env)->SetDoubleField(env, lpObject, CGAffineTransformFc.b, (jdouble)lpStruct->b); (*env)->SetDoubleField(env, lpObject, CGAffineTransformFc.c, (jdouble)lpStruct->c); (*env)->SetDoubleField(env, lpObject, CGAffineTransformFc.d, (jdouble)lpStruct->d); (*env)->SetDoubleField(env, lpObject, CGAffineTransformFc.tx, (jdouble)lpStruct->tx); (*env)->SetDoubleField(env, lpObject, CGAffineTransformFc.ty, (jdouble)lpStruct->ty); } jobject newCGAffineTransform(JNIEnv *env, CGAffineTransform *lpStruct) { jobject lpObject = NULL; if (!CGAffineTransformFc.cached) cacheCGAffineTransformFields(env); lpObject = (*env)->NewObject(env, CGAffineTransformFc.clazz, CGAffineTransformFc.init); if (lpObject && lpStruct) setCGAffineTransformFields(env, lpObject, lpStruct); return lpObject; } typedef struct CGPoint_FID_CACHE { int cached; jclass clazz; jfieldID x, y; jmethodID init; } CGPoint_FID_CACHE; CGPoint_FID_CACHE CGPointFc; void cacheCGPointFields(JNIEnv *env) { if (CGPointFc.cached) return; jclass tmpClass = (*env)->FindClass(env, "com/sun/javafx/font/coretext/CGPoint"); if (checkAndClearException(env) || !tmpClass) { fprintf(stderr, "cacheCGPointFields error: JNI exception or tmpClass == NULL"); return; } CGPointFc.clazz = (jclass)(*env)->NewGlobalRef(env, tmpClass); CGPointFc.x = (*env)->GetFieldID(env, CGPointFc.clazz, "x", "D"); if (checkAndClearException(env) || !CGPointFc.x) { fprintf(stderr, "cacheCGPointFields error: JNI exception or x == NULL"); return; } CGPointFc.y = (*env)->GetFieldID(env, CGPointFc.clazz, "y", "D"); if (checkAndClearException(env) || !CGPointFc.y) { fprintf(stderr, "cacheCGPointFields error: JNI exception or y == NULL"); return; } CGPointFc.init = (*env)->GetMethodID(env, CGPointFc.clazz, "", "()V"); if (checkAndClearException(env) || !CGPointFc.init) { fprintf(stderr, "cacheCGPointFields error: JNI exception or init == NULL"); return; } CGPointFc.cached = 1; } CGPoint *getCGPointFields(JNIEnv *env, jobject lpObject, CGPoint *lpStruct) { if (!CGPointFc.cached) cacheCGPointFields(env); lpStruct->x = (*env)->GetDoubleField(env, lpObject, CGPointFc.x); lpStruct->y = (*env)->GetDoubleField(env, lpObject, CGPointFc.y); return lpStruct; } void setCGPointFields(JNIEnv *env, jobject lpObject, CGPoint *lpStruct) { if (!CGPointFc.cached) cacheCGPointFields(env); (*env)->SetDoubleField(env, lpObject, CGPointFc.x, (jdouble)lpStruct->x); (*env)->SetDoubleField(env, lpObject, CGPointFc.y, (jdouble)lpStruct->y); } jobject newCGPoint(JNIEnv *env, CGPoint *lpStruct) { jobject lpObject = NULL; if (!CGPointFc.cached) cacheCGPointFields(env); lpObject = (*env)->NewObject(env, CGPointFc.clazz, CGPointFc.init); if (lpObject && lpStruct) setCGPointFields(env, lpObject, lpStruct); return lpObject; } typedef struct CGSize_FID_CACHE { int cached; jclass clazz; jfieldID width, height; jmethodID init; } CGSize_FID_CACHE; CGSize_FID_CACHE CGSizeFc; void cacheCGSizeFields(JNIEnv *env) { if (CGSizeFc.cached) return; jclass tmpClass = (*env)->FindClass(env, "com/sun/javafx/font/coretext/CGSize"); if (checkAndClearException(env) || !tmpClass) { fprintf(stderr, "cacheCGSizeFields error: JNI exception or tmpClass == NULL"); return; } CGSizeFc.clazz = (jclass)(*env)->NewGlobalRef(env, tmpClass); CGSizeFc.width = (*env)->GetFieldID(env, CGSizeFc.clazz, "width", "D"); if (checkAndClearException(env) || !CGSizeFc.width) { fprintf(stderr, "cacheCGSizeFields error: JNI exception or width == NULL"); return; } CGSizeFc.height = (*env)->GetFieldID(env, CGSizeFc.clazz, "height", "D"); if (checkAndClearException(env) || !CGSizeFc.height) { fprintf(stderr, "cacheCGSizeFields error: JNI exception or height == NULL"); return; } CGSizeFc.init = (*env)->GetMethodID(env, CGSizeFc.clazz, "", "()V"); if (checkAndClearException(env) || !CGSizeFc.init) { fprintf(stderr, "cacheCGSizeFields error: JNI exception or init == NULL"); return; } CGSizeFc.cached = 1; } CGSize *getCGSizeFields(JNIEnv *env, jobject lpObject, CGSize *lpStruct) { if (!CGSizeFc.cached) cacheCGSizeFields(env); lpStruct->width = (*env)->GetDoubleField(env, lpObject, CGSizeFc.width); lpStruct->height = (*env)->GetDoubleField(env, lpObject, CGSizeFc.height); return lpStruct; } void setCGSizeFields(JNIEnv *env, jobject lpObject, CGSize *lpStruct) { if (!CGSizeFc.cached) cacheCGSizeFields(env); (*env)->SetDoubleField(env, lpObject, CGSizeFc.width, (jdouble)lpStruct->width); (*env)->SetDoubleField(env, lpObject, CGSizeFc.height, (jdouble)lpStruct->height); } jobject newCGSize(JNIEnv *env, CGSize *lpStruct) { jobject lpObject = NULL; if (!CGSizeFc.cached) cacheCGSizeFields(env); lpObject = (*env)->NewObject(env, CGSizeFc.clazz, CGSizeFc.init); if (lpObject && lpStruct) setCGSizeFields(env, lpObject, lpStruct); return lpObject; } typedef struct CGRect_FID_CACHE { int cached; jclass clazz; jfieldID origin, size; jmethodID init; } CGRect_FID_CACHE; CGRect_FID_CACHE CGRectFc; void cacheCGRectFields(JNIEnv *env) { if (CGRectFc.cached) return; jclass tmpClass = (*env)->FindClass(env, "com/sun/javafx/font/coretext/CGRect"); if (checkAndClearException(env) || !tmpClass) { fprintf(stderr, "cacheCGRectFields error: JNI exception or tmpClass == NULL"); return; } CGRectFc.clazz = (jclass)(*env)->NewGlobalRef(env, tmpClass); CGRectFc.origin = (*env)->GetFieldID(env, CGRectFc.clazz, "origin", "Lcom/sun/javafx/font/coretext/CGPoint;"); if (checkAndClearException(env) || !CGRectFc.origin) { fprintf(stderr, "cacheCGRectFields error: JNI exception or origin == NULL"); return; } CGRectFc.size = (*env)->GetFieldID(env, CGRectFc.clazz, "size", "Lcom/sun/javafx/font/coretext/CGSize;"); if (checkAndClearException(env) || !CGRectFc.size) { fprintf(stderr, "cacheCGRectFields error: JNI exception or size == NULL"); return; } CGRectFc.init = (*env)->GetMethodID(env, CGRectFc.clazz, "", "()V"); if (checkAndClearException(env) || !CGRectFc.init) { fprintf(stderr, "cacheCGRectFields error: JNI exception or init == NULL"); return; } CGRectFc.cached = 1; } CGRect *getCGRectFields(JNIEnv *env, jobject lpObject, CGRect *lpStruct) { if (!CGRectFc.cached) cacheCGRectFields(env); { jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CGRectFc.origin); if (lpObject1 != NULL) getCGPointFields(env, lpObject1, &lpStruct->origin); } { jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CGRectFc.size); if (lpObject1 != NULL) getCGSizeFields(env, lpObject1, &lpStruct->size); } return lpStruct; } void setCGRectFields(JNIEnv *env, jobject lpObject, CGRect *lpStruct) { if (!CGRectFc.cached) cacheCGRectFields(env); { jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CGRectFc.origin); if (lpObject1 != NULL) setCGPointFields(env, lpObject1, &lpStruct->origin); } { jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CGRectFc.size); if (lpObject1 != NULL) setCGSizeFields(env, lpObject1, &lpStruct->size); } } jobject newCGRect(JNIEnv *env, CGRect *lpStruct) { jobject lpObject = NULL; if (!CGRectFc.cached) cacheCGRectFields(env); lpObject = (*env)->NewObject(env, CGRectFc.clazz, CGRectFc.init); if (lpObject && lpStruct) setCGRectFields(env, lpObject, lpStruct); return lpObject; } /**************************************************************************/ /* */ /* Functions */ /* */ /**************************************************************************/ JNIEXPORT jlong JNICALL OS_NATIVE(kCFAllocatorDefault) (JNIEnv *env, jclass that) { return (jlong)kCFAllocatorDefault; } JNIEXPORT jlong JNICALL OS_NATIVE(CFStringCreateWithCharacters__J_3CJ) (JNIEnv *env, jclass that, jlong arg0, jcharArray arg1, jlong arg2) { jchar *lparg1=NULL; jlong rc = 0; if (arg1) if ((lparg1 = (*env)->GetCharArrayElements(env, arg1, NULL)) == NULL) goto fail; rc = (jlong)CFStringCreateWithCharacters((CFAllocatorRef)arg0, (UniChar*)lparg1, (CFIndex)arg2); fail: if (arg1 && lparg1) (*env)->ReleaseCharArrayElements(env, arg1, lparg1, 0); return rc; } JNIEXPORT void JNICALL OS_NATIVE(CFRelease) (JNIEnv *env, jclass that, jlong arg0) { CFRelease((CFTypeRef)arg0); } JNIEXPORT jlong JNICALL OS_NATIVE(CTFontCreateWithGraphicsFont) (JNIEnv *env, jclass that, jlong cgFont, jdouble size, jobject matrix, jlong attributes) { CGAffineTransform transform; if (matrix) { getCGAffineTransformFields(env, matrix, &transform); } else { transform = CGAffineTransformIdentity; } return (jlong)CTFontCreateWithGraphicsFont((CGFontRef)cgFont, (CGFloat)size, &transform, (CTFontDescriptorRef)attributes); } JNIEXPORT jlong JNICALL OS_NATIVE(CTFontCreateWithName) (JNIEnv *env, jclass that, jlong arg0, jdouble arg1, jobject arg2) { CGAffineTransform _arg2, *lparg2=NULL; jlong rc = 0; if (arg2) if ((lparg2 = getCGAffineTransformFields(env, arg2, &_arg2)) == NULL) goto fail; rc = (jlong)CTFontCreateWithName((CFStringRef)arg0, (CGFloat)arg1, (CGAffineTransform*)lparg2); fail: /* In only */ // if (arg2 && lparg2) setCGAffineTransformFields(env, arg2, lparg2); return rc; } JNIEXPORT jlong JNICALL OS_NATIVE(CFURLCreateWithFileSystemPath) (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2, jboolean arg3) { return (jlong)CFURLCreateWithFileSystemPath((CFAllocatorRef)arg0, (CFStringRef)arg1, (CFURLPathStyle)arg2, (Boolean)arg3); } JNIEXPORT jboolean JNICALL OS_NATIVE(CTFontManagerRegisterFontsForURL) (JNIEnv *env, jclass that, jlong arg0, jint arg1, jlong arg2) { return (jboolean)CTFontManagerRegisterFontsForURL((CFURLRef)arg0, (CTFontManagerScope)arg1, (CFErrorRef*)arg2); } JNIEXPORT jlong JNICALL OS_NATIVE(CTFontCreatePathForGlyph) (JNIEnv *env, jclass that, jlong arg0, jshort arg1, jobject arg2) { CGAffineTransform _arg2, *lparg2=NULL; jlong rc = 0; if (arg2) if ((lparg2 = getCGAffineTransformFields(env, arg2, &_arg2)) == NULL) goto fail; rc = (jlong)CTFontCreatePathForGlyph((CTFontRef)arg0, (CGGlyph)arg1, (CGAffineTransform*)lparg2); fail: /* In Only */ // if (arg2 && lparg2) setCGAffineTransformFields(env, arg2, lparg2); return rc; } JNIEXPORT jlong JNICALL OS_NATIVE(CGFontCreateWithDataProvider) (JNIEnv *env, jclass that, jlong dataProvider) { return (jlong)CGFontCreateWithDataProvider((CGDataProviderRef)dataProvider); } JNIEXPORT void JNICALL OS_NATIVE(CGPathRelease) (JNIEnv *env, jclass that, jlong arg0) { CGPathRelease((CGPathRef)arg0); } JNIEXPORT jlong JNICALL OS_NATIVE(CGColorSpaceCreateDeviceRGB) (JNIEnv *env, jclass that) { return (jlong)CGColorSpaceCreateDeviceRGB(); } JNIEXPORT jlong JNICALL OS_NATIVE(CGColorSpaceCreateDeviceGray) (JNIEnv *env, jclass that) { return (jlong)CGColorSpaceCreateDeviceGray(); } JNIEXPORT jlong JNICALL OS_NATIVE(CGBitmapContextCreate) (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2, jlong arg3, jlong arg4, jlong arg5, jint arg6) { return (jlong)CGBitmapContextCreate((void*)arg0, (size_t)arg1, (size_t)arg2, (size_t)arg3, (size_t)arg4, (CGColorSpaceRef)arg5, (CGBitmapInfo)arg6); } JNIEXPORT void JNICALL OS_NATIVE(CGContextSetAllowsFontSmoothing) (JNIEnv *env, jclass that, jlong arg0, jboolean arg1) { CGContextSetAllowsFontSmoothing((CGContextRef)arg0, (_Bool)arg1); } JNIEXPORT void JNICALL OS_NATIVE(CGContextSetAllowsAntialiasing) (JNIEnv *env, jclass that, jlong arg0, jboolean arg1) { CGContextSetAllowsAntialiasing((CGContextRef)arg0, (_Bool)arg1); } JNIEXPORT void JNICALL OS_NATIVE(CGContextSetAllowsFontSubpixelPositioning) (JNIEnv *env, jclass that, jlong arg0, jboolean arg1) { CGContextSetAllowsFontSubpixelPositioning((CGContextRef)arg0, (_Bool)arg1); } JNIEXPORT void JNICALL OS_NATIVE(CGContextSetAllowsFontSubpixelQuantization) (JNIEnv *env, jclass that, jlong arg0, jboolean arg1) { CGContextSetAllowsFontSubpixelQuantization((CGContextRef)arg0, (_Bool)arg1); } JNIEXPORT void JNICALL OS_NATIVE(CGContextSetRGBFillColor) (JNIEnv *env, jclass that, jlong arg0, jdouble arg1, jdouble arg2, jdouble arg3, jdouble arg4) { CGContextSetRGBFillColor((CGContextRef)arg0, (CGFloat)arg1, (CGFloat)arg2, (CGFloat)arg3, (CGFloat)arg4); } JNIEXPORT void JNICALL OS_NATIVE(CGContextFillRect) (JNIEnv *env, jclass that, jlong arg0, jobject arg1) { CGRect _arg1, *lparg1=NULL; /* In Only */ if (arg1) if ((lparg1 = getCGRectFields(env, arg1, &_arg1)) == NULL) return; CGContextFillRect((CGContextRef)arg0, *lparg1); } JNIEXPORT void JNICALL OS_NATIVE(CGContextTranslateCTM) (JNIEnv *env, jclass that, jlong arg0, jdouble arg1, jdouble arg2) { CGContextTranslateCTM((CGContextRef)arg0, (CGFloat)arg1, (CGFloat)arg2); } JNIEXPORT void JNICALL OS_NATIVE(CGContextRelease) (JNIEnv *env, jclass that, jlong arg0) { CGContextRelease((CGContextRef)arg0); } JNIEXPORT void JNICALL OS_NATIVE(CGColorSpaceRelease) (JNIEnv *env, jclass that, jlong arg0) { CGColorSpaceRelease((CGColorSpaceRef)arg0); } JNIEXPORT jlong JNICALL OS_NATIVE(CGDataProviderCreateWithURL) (JNIEnv *env, jclass that, jlong cfURL) { return (jlong)CGDataProviderCreateWithURL((CFURLRef)cfURL); } JNIEXPORT jlong JNICALL OS_NATIVE(kCFTypeDictionaryKeyCallBacks) (JNIEnv *env, jclass that) { return (jlong)&kCFTypeDictionaryKeyCallBacks; } JNIEXPORT jlong JNICALL OS_NATIVE(kCFTypeDictionaryValueCallBacks) (JNIEnv *env, jclass that) { return (jlong)&kCFTypeDictionaryValueCallBacks; } JNIEXPORT jlong JNICALL OS_NATIVE(CFDictionaryCreateMutable) (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2, jlong arg3) { return (jlong)CFDictionaryCreateMutable((CFAllocatorRef)arg0, (CFIndex)arg1, (CFDictionaryKeyCallBacks*)arg2, (CFDictionaryValueCallBacks*)arg3); } JNIEXPORT void JNICALL OS_NATIVE(CFDictionaryAddValue) (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2) { CFDictionaryAddValue((CFMutableDictionaryRef)arg0, (void*)arg1, (void*)arg2); } JNIEXPORT jlong JNICALL OS_NATIVE(CFDictionaryGetValue) (JNIEnv *env, jclass that, jlong arg0, jlong arg1) { return (jlong)CFDictionaryGetValue((CFDictionaryRef)arg0, (void*)arg1); } JNIEXPORT jlong JNICALL OS_NATIVE(kCTFontAttributeName) (JNIEnv *env, jclass that) { return (jlong)kCTFontAttributeName; } JNIEXPORT jlong JNICALL OS_NATIVE(kCTParagraphStyleAttributeName) (JNIEnv *env, jclass that) { return (jlong)kCTParagraphStyleAttributeName; } JNIEXPORT jlong JNICALL OS_NATIVE(CFAttributedStringCreate) (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2) { return (jlong)CFAttributedStringCreate((CFAllocatorRef)arg0, (CFStringRef)arg1, (CFDictionaryRef)arg2); } JNIEXPORT jlong JNICALL OS_NATIVE(CTLineCreateWithAttributedString) (JNIEnv *env, jclass that, jlong arg0) { return (jlong)CTLineCreateWithAttributedString((CFAttributedStringRef)arg0); } JNIEXPORT jlong JNICALL OS_NATIVE(CTLineGetGlyphRuns) (JNIEnv *env, jclass that, jlong arg0) { return (jlong)CTLineGetGlyphRuns((CTLineRef)arg0); } JNIEXPORT jdouble JNICALL OS_NATIVE(CTLineGetTypographicBounds) (JNIEnv *env, jclass that, jlong arg0) { return (jdouble)CTLineGetTypographicBounds((CTLineRef)arg0, NULL, NULL, NULL); } JNIEXPORT jlong JNICALL OS_NATIVE(CTLineGetGlyphCount) (JNIEnv *env, jclass that, jlong arg0) { return (jlong)CTLineGetGlyphCount((CTLineRef)arg0); } JNIEXPORT jlong JNICALL OS_NATIVE(CFArrayGetCount) (JNIEnv *env, jclass that, jlong arg0) { return (jlong)CFArrayGetCount((CFArrayRef)arg0); } JNIEXPORT jlong JNICALL OS_NATIVE(CFArrayGetValueAtIndex) (JNIEnv *env, jclass that, jlong arg0, jlong arg1) { return (jlong)CFArrayGetValueAtIndex((CFArrayRef)arg0, (CFIndex)arg1); } JNIEXPORT jlong JNICALL OS_NATIVE(CTRunGetGlyphCount) (JNIEnv *env, jclass that, jlong arg0) { return (jlong)CTRunGetGlyphCount((CTRunRef)arg0); } JNIEXPORT jlong JNICALL OS_NATIVE(CTRunGetAttributes) (JNIEnv *env, jclass that, jlong arg0) { return (jlong)CTRunGetAttributes((CTRunRef)arg0); } /**************************************************************************/ /* */ /* Custom Functions */ /* */ /**************************************************************************/ JNIEXPORT jlong JNICALL OS_NATIVE(CFStringCreateWithCharacters__J_3CJJ) (JNIEnv *env, jclass that, jlong arg0, jcharArray arg1, jlong arg2, jlong arg3) { jchar *lparg1=NULL; jlong rc = 0; if (arg1) if ((lparg1 = (*env)->GetPrimitiveArrayCritical(env, arg1, NULL)) == NULL) goto fail; UniChar* str = lparg1 + arg2; rc = (jlong)CFStringCreateWithCharacters((CFAllocatorRef)arg0, str, (CFIndex)arg3); fail: if (arg1 && lparg1) (*env)->ReleasePrimitiveArrayCritical(env, arg1, lparg1, 0); return rc; } JNIEXPORT jint JNICALL OS_NATIVE(CTRunGetGlyphs) (JNIEnv *env, jclass that, jlong runRef, jint slotMask, jint start, jintArray bufferRef) { CTRunRef run = (CTRunRef)runRef; const CGGlyph * glyphs = CTRunGetGlyphsPtr(run); int i = 0; if (glyphs) { jint* buffer = (*env)->GetPrimitiveArrayCritical(env, bufferRef, NULL); if (buffer) { CFIndex count = CTRunGetGlyphCount(run); while(i < count) { buffer[start + i] = slotMask | (glyphs[i] & 0xFFFF); i++; } (*env)->ReleasePrimitiveArrayCritical(env, bufferRef, buffer, 0); } } return i; } JNIEXPORT jint JNICALL OS_NATIVE(CTRunGetPositions) (JNIEnv *env, jclass that, jlong runRef, jint start, jfloatArray bufferRef) { CTRunRef run = (CTRunRef)runRef; const CGPoint* positions = CTRunGetPositionsPtr(run); int j = 0; if (positions) { jfloat* buffer = (*env)->GetPrimitiveArrayCritical(env, bufferRef, NULL); if (buffer) { CFIndex count = CTRunGetGlyphCount(run); int i = 0; while (i < count) { CGPoint pos = positions[i++]; buffer[start + j++] = pos.x; buffer[start + j++] = pos.y; } (*env)->ReleasePrimitiveArrayCritical(env, bufferRef, buffer, 0); } } return j; } JNIEXPORT jint JNICALL OS_NATIVE(CTRunGetStringIndices) (JNIEnv *env, jclass that, jlong runRef, jint start, jintArray bufferRef) { CTRunRef run = (CTRunRef)runRef; const CFIndex* indices = CTRunGetStringIndicesPtr(run); int i = 0; if (indices) { jint* buffer = (*env)->GetPrimitiveArrayCritical(env, bufferRef, NULL); if (buffer) { CFIndex count = CTRunGetGlyphCount(run); while(i < count) { buffer[start + i] = indices[i]; i++; } (*env)->ReleasePrimitiveArrayCritical(env, bufferRef, buffer, 0); } } return i; } JNIEXPORT jstring JNICALL OS_NATIVE(CTFontCopyAttributeDisplayName) (JNIEnv *env, jclass that, jlong arg0) { CFStringRef stringRef = CTFontCopyAttribute((CTFontRef)arg0, kCTFontDisplayNameAttribute); if (stringRef == NULL) return NULL; CFIndex length = CFStringGetLength(stringRef); UniChar buffer[length]; CFStringGetCharacters(stringRef, CFRangeMake(0, length), buffer); CFRelease(stringRef); return (*env)->NewString(env, (jchar *)buffer, length); } JNIEXPORT jbyteArray JNICALL OS_NATIVE(CGBitmapContextGetData) (JNIEnv *env, jclass that, jlong arg0, jint dstWidth, jint dstHeight, jint bpp) { jbyteArray result = NULL; if (dstWidth < 0) return NULL; if (dstHeight < 0) return NULL; if (bpp != 8 && bpp != 24) return NULL; CGContextRef context = (CGContextRef)arg0; if (context == NULL) return NULL; jbyte *srcData = (jbyte*)CGBitmapContextGetData(context); if (srcData) { /* Use one byte per pixel for grayscale */ size_t srcWidth = CGBitmapContextGetWidth(context); if (srcWidth < dstWidth) return NULL; size_t srcHeight = CGBitmapContextGetHeight(context); if (srcHeight < dstHeight) return NULL; size_t srcBytesPerRow = CGBitmapContextGetBytesPerRow(context); size_t srcStep = CGBitmapContextGetBitsPerPixel(context) / 8; int srcOffset = (srcHeight - dstHeight) * srcBytesPerRow; //bits per pixel, either 8 for gray or 24 for LCD. int dstStep = bpp / 8; size_t size = dstWidth * dstHeight * dstStep; jbyte* data = (jbyte*)calloc(size, sizeof(jbyte)); if (data == NULL) return NULL; int x, y, sx; int dstOffset = 0; for (y = 0; y < dstHeight; y++) { for (x = 0, sx = 0; x < dstWidth; x++, dstOffset += dstStep, sx += srcStep) { if (dstStep == 1) { /* BGRA or Gray to Gray */ data[dstOffset] = 0xFF - srcData[srcOffset + sx]; } else { /* BGRA to RGB */ data[dstOffset] = 0xFF - srcData[srcOffset + sx + 2]; data[dstOffset + 1] = 0xFF - srcData[srcOffset + sx + 1]; data[dstOffset + 2] = 0xFF - srcData[srcOffset + sx]; } } srcOffset += srcBytesPerRow; } result = (*env)->NewByteArray(env, size); if (result) { (*env)->SetByteArrayRegion(env, result, 0, size, data); } free(data); } return result; } JNIEXPORT void JNICALL OS_NATIVE(CGRectApplyAffineTransform) (JNIEnv *env, jclass that, jobject arg0, jobject arg1) { CGRect _arg0, *lparg0=NULL; CGAffineTransform _arg1, *lparg1=NULL; if (arg0) if ((lparg0 = getCGRectFields(env, arg0, &_arg0)) == NULL) goto fail; if (arg1) if ((lparg1 = getCGAffineTransformFields(env, arg1, &_arg1)) == NULL) goto fail; _arg0 = CGRectApplyAffineTransform(*lparg0, *lparg1); fail: /* In Only */ // if (arg1 && lparg1) setCGAffineTransformFields(env, arg1, lparg1); if (arg0 && lparg0) setCGRectFields(env, arg0, lparg0); } JNIEXPORT void JNICALL OS_NATIVE(CTFontDrawGlyphs) (JNIEnv *env, jclass that, jlong arg0, jshort arg1, jdouble arg2, jdouble arg3, jlong contextRef) { /* Custom: only takes one glyph at the time */ CGGlyph glyphs[] = {arg1}; CGPoint pos[] = {CGPointMake(arg2, arg3)}; CTFontDrawGlyphs((CTFontRef)arg0, glyphs, pos, 1, (CGContextRef)contextRef); } JNIEXPORT jboolean JNICALL OS_NATIVE(CTFontGetBoundingRectForGlyphUsingTables) (JNIEnv *env, jclass that, jlong arg1, jshort arg2, jshort arg3, jintArray arg4) { /* The following code is based on scalerMethods.c#getGlyphBoundingBoxNative */ CTFontRef fontRef = (CTFontRef)arg1; CTFontTableOptions options = kCTFontTableOptionNoOptions; CFDataRef tableData; CFIndex length; /* indexToLocFormat is stored in Java for performance */ // tableData = CTFontCopyTable(fontRef, kCTFontTableHead, options); // const UInt8 * head = CFDataGetBytePtr(tableData); // UInt16 indexToLocFormat = CFSwapInt16BigToHost(*((SInt16*)(head + 50))); // printf("here0 indexToLocFormat=%u \n", indexToLocFormat); fflush(stdout); // CFRelease(tableData); UInt16 indexToLocFormat = arg3; tableData = CTFontCopyTable(fontRef, kCTFontTableLoca, options); if (tableData == NULL) return FALSE; length = CFDataGetLength(tableData); UInt32 offset1 = 0, offset2 = 0; UInt32 index = arg2 & 0xFFFF; if (indexToLocFormat) { const UInt32 * loca = (const UInt32 *)CFDataGetBytePtr(tableData); if (loca != NULL && (index + 1) < (length / 4)) { offset1 = CFSwapInt32BigToHost(loca[index]); offset2 = CFSwapInt32BigToHost(loca[index + 1]); } } else { const UInt16 * loca = (const UInt16 *)CFDataGetBytePtr(tableData); if (loca != NULL && (index + 1) < (length / 2)) { offset1 = CFSwapInt16BigToHost(loca[index]) << 1; offset2 = CFSwapInt16BigToHost(loca[index + 1]) << 1; } } CFRelease(tableData); jboolean result = FALSE; if (offset2 > offset1 && (offset2 - offset1) >= 10) { tableData = CTFontCopyTable(fontRef, kCTFontTableGlyf, options); if (tableData == NULL) return FALSE; length = CFDataGetLength(tableData); const UInt8 * ptr = CFDataGetBytePtr(tableData); if (ptr != NULL && (offset1 + 10) < length) { const SInt16 * glyf = (const SInt16 *)(ptr + offset1); /* * CFSwapInt16BigToHost returns an unsigned short, need * to cast back to signed short before assigning to jint. */ jint data[] = { (SInt16)CFSwapInt16BigToHost(glyf[1]), (SInt16)CFSwapInt16BigToHost(glyf[2]), (SInt16)CFSwapInt16BigToHost(glyf[3]), (SInt16)CFSwapInt16BigToHost(glyf[4]), }; (*env)->SetIntArrayRegion(env, arg4, 0, 4, data); result = TRUE; } CFRelease(tableData); } return result; } JNIEXPORT jdouble JNICALL OS_NATIVE(CTFontGetAdvancesForGlyphs) (JNIEnv *env, jclass that, jlong arg0, jint arg1, jshort arg2, jobject arg3) { /* Custom: only takes one glyph at the time */ jdouble rc = 0; CGGlyph glyphs[] = {arg2}; CGSize _arg3, *lparg3=NULL; if (arg3) if ((lparg3 = getCGSizeFields(env, arg3, &_arg3)) == NULL) goto fail; rc = (jdouble)CTFontGetAdvancesForGlyphs((CTFontRef)arg0, (CTFontOrientation)arg1, glyphs, lparg3, 1); fail: if (arg3 && lparg3) setCGSizeFields(env, arg3, &_arg3); return rc; } JNIEXPORT jobject JNICALL OS_NATIVE(CGPathGetPathBoundingBox) (JNIEnv *env, jclass that, jlong arg0) { CGRect result = CGPathGetPathBoundingBox((CGPathRef)arg0); return newCGRect(env, &result); } JNIEXPORT jlong JNICALL OS_NATIVE(CTParagraphStyleCreate) (JNIEnv *env, jclass that, jint arg0) { CTWritingDirection dir = (CTWritingDirection)arg0; CTParagraphStyleSetting settings[] = { {kCTParagraphStyleSpecifierBaseWritingDirection, sizeof(dir), &dir} }; return (jlong)CTParagraphStyleCreate(settings, sizeof(settings) / sizeof(settings[0])); } /***********************************************/ /* Glyph Outline */ /***********************************************/ static const int DEFAULT_LEN_TYPES = 10; static const int DEFAULT_LEN_COORDS = 50; typedef struct _PathData { jbyte* pointTypes; int numTypes; int lenTypes; jfloat* pointCoords; int numCoords; int lenCoords; } PathData; void pathApplierFunctionFast(void *i, const CGPathElement *e) { PathData *info = (PathData *)i; if (info->numTypes == info->lenTypes) { info->lenTypes += DEFAULT_LEN_TYPES; info->pointTypes = (jbyte*)realloc(info->pointTypes, info->lenTypes * sizeof(jbyte)); } jint type; int coordCount = 0; switch (e->type) { case kCGPathElementMoveToPoint: type = 0; coordCount = 1; break; case kCGPathElementAddLineToPoint: type = 1; coordCount = 1; break; case kCGPathElementAddQuadCurveToPoint: type = 2; coordCount = 2; break; case kCGPathElementAddCurveToPoint: type = 3; coordCount = 3; break; case kCGPathElementCloseSubpath: type = 4; coordCount = 0; break; } info->pointTypes[info->numTypes++] = type; if (info->numCoords + (coordCount * 2) > info->lenCoords) { info->lenCoords += DEFAULT_LEN_COORDS; info->pointCoords = (jfloat*)realloc(info->pointCoords, info->lenCoords * sizeof(jfloat)); } int j; for (j = 0; j < coordCount; j++) { CGPoint pt = e->points[j]; info->pointCoords[info->numCoords++] = pt.x; info->pointCoords[info->numCoords++] = pt.y; } } JNIEXPORT jobject JNICALL OS_NATIVE(CGPathApply) (JNIEnv *env, jclass that, jlong arg0) { jobject path2D = NULL; PathData data; data.pointTypes = (jbyte*)malloc(sizeof(jbyte) * DEFAULT_LEN_TYPES); data.numTypes = 0; data.lenTypes = DEFAULT_LEN_TYPES; data.pointCoords = (jfloat*)malloc(sizeof(jfloat) * DEFAULT_LEN_COORDS); data.numCoords = 0; data.lenCoords = DEFAULT_LEN_COORDS; CGPathApply((CGPathRef)arg0, &data, pathApplierFunctionFast); static jclass path2DClass = NULL; static jmethodID path2DCtr = NULL; if (path2DClass == NULL) { jclass tmpClass = (*env)->FindClass(env, "com/sun/javafx/geom/Path2D"); if ((*env)->ExceptionOccurred(env) || !tmpClass) { fprintf(stderr, "OS_NATIVE error: JNI exception or tmpClass == NULL"); goto fail; } path2DClass = (jclass)(*env)->NewGlobalRef(env, tmpClass); path2DCtr = (*env)->GetMethodID(env, path2DClass, "", "(I[BI[FI)V"); if ((*env)->ExceptionOccurred(env) || !path2DCtr) { fprintf(stderr, "OS_NATIVE error: JNI exception or path2DCtr == NULL"); goto fail; } } jbyteArray types = (*env)->NewByteArray(env, data.numTypes); jfloatArray coords = (*env)->NewFloatArray(env, data.numCoords); if (types && coords) { (*env)->SetByteArrayRegion(env, types, 0, data.numTypes, data.pointTypes); if ((*env)->ExceptionOccurred(env)) { fprintf(stderr, "OS_NATIVE error: JNI exception"); goto fail; } (*env)->SetFloatArrayRegion(env, coords, 0, data.numCoords, data.pointCoords); if ((*env)->ExceptionOccurred(env)) { fprintf(stderr, "OS_NATIVE error: JNI exception"); goto fail; } path2D = (*env)->NewObject(env, path2DClass, path2DCtr, 0 /*winding rule*/, types, data.numTypes, coords, data.numCoords); if ((*env)->ExceptionOccurred(env) || !path2D) { goto fail; } } fail: free(data.pointTypes); free(data.pointCoords); return path2D; } #endif /* TARGET_OS_MAC */ #endif /* __APPLE__ */