4632N/A/*
4632N/A * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
4632N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4632N/A *
4632N/A * This code is free software; you can redistribute it and/or modify it
4632N/A * under the terms of the GNU General Public License version 2 only, as
4632N/A * published by the Free Software Foundation. Oracle designates this
4632N/A * particular file as subject to the "Classpath" exception as provided
4632N/A * by Oracle in the LICENSE file that accompanied this code.
4632N/A *
4632N/A * This code is distributed in the hope that it will be useful, but WITHOUT
4632N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4632N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
4632N/A * version 2 for more details (a copy is included in the LICENSE file that
4632N/A * accompanied this code).
4632N/A *
4632N/A * You should have received a copy of the GNU General Public License version
4632N/A * 2 along with this work; if not, write to the Free Software Foundation,
4632N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
4632N/A *
4632N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
4632N/A * or visit www.oracle.com if you need additional information or have any
4632N/A * questions.
4632N/A */
4632N/A
4632N/A#import <JavaNativeFoundation/JavaNativeFoundation.h>
4632N/A#import "java_awt_geom_PathIterator.h"
4632N/A#import "sun_awt_SunHints.h"
4632N/A#import "sun_font_CStrike.h"
4877N/A#import "sun_font_CStrikeDisposer.h"
4632N/A#import "CGGlyphImages.h"
4632N/A#import "CGGlyphOutlines.h"
4632N/A#import "AWTStrike.h"
4632N/A#import "CoreTextSupport.h"
4632N/A//#import "jni_util.h"
4877N/A#include "fontscalerdefs.h"
4632N/A
4632N/A@implementation AWTStrike
4632N/A
4632N/Astatic CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 };
4632N/A
4632N/A- (id) initWithFont:(AWTFont *)awtFont
4632N/A tx:(CGAffineTransform)tx
4632N/A invDevTx:(CGAffineTransform)invDevTx
4632N/A style:(JRSFontRenderingStyle)style
4632N/A aaStyle:(jint)aaStyle {
4632N/A
4632N/A self = [super init];
4632N/A if (self) {
4632N/A fAWTFont = [awtFont retain];
4632N/A fStyle = style;
4632N/A fAAStyle = aaStyle;
4632N/A
4632N/A fTx = tx; // composited glyph and device transform
4632N/A
4632N/A fAltTx = tx;
4632N/A fAltTx.b *= -1;
4632N/A fAltTx.d *= -1;
4632N/A
4632N/A invDevTx.b *= -1;
4632N/A invDevTx.c *= -1;
4632N/A fFontTx = CGAffineTransformConcat(CGAffineTransformConcat(tx, invDevTx), sInverseTX);
4632N/A
4632N/A // the "font size" is the square root of the determinant of the matrix
4632N/A fSize = sqrt(abs(fFontTx.a * fFontTx.d - fFontTx.b * fFontTx.c));
4632N/A }
4632N/A return self;
4632N/A}
4632N/A
4632N/A- (void) dealloc {
4632N/A [fAWTFont release];
4632N/A fAWTFont = nil;
4632N/A
4632N/A [super dealloc];
4632N/A}
4632N/A
4632N/A+ (AWTStrike *) awtStrikeForFont:(AWTFont *)awtFont
4632N/A tx:(CGAffineTransform)tx
4632N/A invDevTx:(CGAffineTransform)invDevTx
4632N/A style:(JRSFontRenderingStyle)style
4632N/A aaStyle:(jint)aaStyle {
4632N/A
4632N/A return [[[AWTStrike alloc] initWithFont:awtFont
4632N/A tx:tx invDevTx:invDevTx
4632N/A style:style
4632N/A aaStyle:aaStyle] autorelease];
4632N/A}
4632N/A
4632N/A@end
4632N/A
4632N/A
4632N/A#define AWT_FONT_CLEANUP_SETUP \
4632N/A BOOL _fontThrowJavaException = NO;
4632N/A
4632N/A#define AWT_FONT_CLEANUP_CHECK(a) \
4632N/A if ((a) == NULL) { \
4632N/A _fontThrowJavaException = YES; \
4632N/A goto cleanup; \
4632N/A } \
4632N/A if ((*env)->ExceptionCheck(env) == JNI_TRUE) { \
4632N/A goto cleanup; \
4632N/A }
4632N/A
4632N/A#define AWT_FONT_CLEANUP_FINISH \
4632N/A if (_fontThrowJavaException == YES) { \
4632N/A char s[512]; \
4632N/A sprintf(s, "%s-%s:%d", __FILE__, __FUNCTION__, __LINE__); \
4632N/A [JNFException raise:env as:kRuntimeException reason:s]; \
4632N/A }
4632N/A
4632N/A
4632N/A/*
4632N/A * Creates an affine transform from the corresponding doubles sent
4632N/A * from CStrike.getGlyphTx().
4632N/A */
4632N/Astatic inline CGAffineTransform
4632N/AGetTxFromDoubles(JNIEnv *env, jdoubleArray txArray)
4632N/A{
4632N/A if (txArray == NULL) {
4632N/A return CGAffineTransformIdentity;
4632N/A }
4632N/A
4632N/A jdouble *txPtr = (*env)->GetPrimitiveArrayCritical(env, txArray, NULL);
4632N/A
4632N/A CGAffineTransform tx =
4632N/A CGAffineTransformMake(txPtr[0], txPtr[1], txPtr[2],
4632N/A txPtr[3], txPtr[4], txPtr[5]);
4632N/A tx = CGAffineTransformConcat(sInverseTX, tx);
4632N/A
4632N/A (*env)->ReleasePrimitiveArrayCritical(env, txArray, txPtr, JNI_ABORT);
4632N/A
4632N/A return tx;
4632N/A}
4632N/A
4632N/A/*
4632N/A * Class: sun_font_CStrike
4632N/A * Method: getNativeGlyphAdvance
4632N/A * Signature: (JI)F
4632N/A */
4632N/AJNIEXPORT jfloat JNICALL
4632N/AJava_sun_font_CStrike_getNativeGlyphAdvance
4632N/A (JNIEnv *env, jclass clazz, jlong awtStrikePtr, jint glyphCode)
4632N/A{
4632N/A CGSize advance;
4632N/AJNF_COCOA_ENTER(env);
4632N/A AWTFont *awtFont = ((AWTStrike *)jlong_to_ptr(awtStrikePtr))->fAWTFont;
4632N/A
4632N/A // negative glyph codes are really unicodes, which were placed there by the mapper
4632N/A // to indicate we should use CoreText to substitute the character
4632N/A CGGlyph glyph;
4632N/A const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);
4632N/A CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &advance, 1);
4632N/A CFRelease(fallback);
4632N/A
4632N/AJNF_COCOA_EXIT(env);
4632N/A return advance.width;
4632N/A}
4632N/A
4632N/A/*
4632N/A * Class: sun_font_CStrike
4632N/A * Method: getNativeGlyphImageBounds
4632N/A * Signature: (JJILjava/awt/geom/Rectangle2D/Float;DD)V
4632N/A */
4632N/AJNIEXPORT void JNICALL
4632N/AJava_sun_font_CStrike_getNativeGlyphImageBounds
4632N/A (JNIEnv *env, jclass clazz,
4632N/A jlong awtStrikePtr, jint glyphCode,
4632N/A jobject result /*Rectangle*/, jdouble x, jdouble y)
4632N/A{
4632N/AJNF_COCOA_ENTER(env);
4632N/A
4632N/A AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
4632N/A AWTFont *awtFont = awtStrike->fAWTFont;
4632N/A
4632N/A CGAffineTransform tx = awtStrike->fAltTx;
4632N/A tx.tx += x;
4632N/A tx.ty += y;
4632N/A
4632N/A // negative glyph codes are really unicodes, which were placed there by the mapper
4632N/A // to indicate we should use CoreText to substitute the character
4632N/A CGGlyph glyph;
4632N/A const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);
4632N/A
4632N/A CGRect bbox;
4632N/A JRSFontGetBoundingBoxesForGlyphsAndStyle(fallback, &tx, awtStrike->fStyle, &glyph, 1, &bbox);
4632N/A CFRelease(fallback);
4632N/A
4632N/A // the origin of this bounding box is relative to the bottom-left corner baseline
4632N/A CGFloat decender = -bbox.origin.y;
4632N/A bbox.origin.y = -bbox.size.height + decender;
4632N/A
4632N/A // Rectangle2D.Float.setRect(float x, float y, float width, float height);
4632N/A static JNF_CLASS_CACHE(sjc_Rectangle2D_Float, "java/awt/geom/Rectangle2D$Float"); // cache class id for Rectangle
4632N/A static JNF_MEMBER_CACHE(sjr_Rectangle2DFloat_setRect, sjc_Rectangle2D_Float, "setRect", "(FFFF)V");
4632N/A JNFCallVoidMethod(env, result, sjr_Rectangle2DFloat_setRect, (jfloat)bbox.origin.x, (jfloat)bbox.origin.y, (jfloat)bbox.size.width, (jfloat)bbox.size.height);
4632N/A
4632N/AJNF_COCOA_EXIT(env);
4632N/A}
4632N/A
4632N/A/*
4632N/A * Class: sun_font_CStrike
4632N/A * Method: getNativeGlyphOutline
4632N/A * Signature: (JJIDD)Ljava/awt/geom/GeneralPath;
4632N/A */
4632N/AJNIEXPORT jobject JNICALL
4632N/AJava_sun_font_CStrike_getNativeGlyphOutline
4632N/A (JNIEnv *env, jclass clazz,
4632N/A jlong awtStrikePtr, jint glyphCode, jdouble xPos, jdouble yPos)
4632N/A{
4632N/A jobject generalPath = NULL;
4632N/A
4632N/AJNF_COCOA_ENTER(env);
4632N/A
4632N/A AWTPathRef path = NULL;
4632N/A jfloatArray pointCoords = NULL;
4632N/A jbyteArray pointTypes = NULL;
4632N/A
4632N/AAWT_FONT_CLEANUP_SETUP;
4632N/A
4632N/A AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
4632N/A AWTFont *awtfont = awtStrike->fAWTFont;
4632N/A
4632N/AAWT_FONT_CLEANUP_CHECK(awtfont);
4632N/A
4632N/A // inverting the shear order and sign to compensate for the flipped coordinate system
4632N/A CGAffineTransform tx = awtStrike->fTx;
4632N/A tx.tx += xPos;
4632N/A tx.ty += yPos;
4632N/A
4632N/A // get the right font and glyph for this "Java GlyphCode"
4632N/A
4632N/A CGGlyph glyph;
4632N/A const CTFontRef font = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtfont, glyphCode, &glyph);
4632N/A
4632N/A // get the advance of this glyph
4632N/A CGSize advance;
4632N/A CTFontGetAdvancesForGlyphs(font, kCTFontDefaultOrientation, &glyph, &advance, 1);
4632N/A
4632N/A // Create AWTPath
4632N/A path = AWTPathCreate(CGSizeMake(xPos, yPos));
4632N/AAWT_FONT_CLEANUP_CHECK(path);
4632N/A
4632N/A // Get the paths
4632N/A tx = awtStrike->fTx;
4632N/A tx = CGAffineTransformConcat(tx, sInverseTX);
4632N/A AWTGetGlyphOutline(&glyph, (NSFont *)font, &advance, &tx, 0, 1, &path);
4632N/A CFRelease(font);
4632N/A
4632N/A pointCoords = (*env)->NewFloatArray(env, path->fNumberOfDataElements);
4632N/AAWT_FONT_CLEANUP_CHECK(pointCoords);
4632N/A
4632N/A (*env)->SetFloatArrayRegion(env, pointCoords, 0, path->fNumberOfDataElements, (jfloat*)path->fSegmentData);
4632N/A
4632N/A // Copy the pointTypes to the general path
4632N/A pointTypes = (*env)->NewByteArray(env, path->fNumberOfSegments);
4632N/AAWT_FONT_CLEANUP_CHECK(pointTypes);
4632N/A
4632N/A (*env)->SetByteArrayRegion(env, pointTypes, 0, path->fNumberOfSegments, (jbyte*)path->fSegmentType);
4632N/A
4632N/A static JNF_CLASS_CACHE(jc_GeneralPath, "java/awt/geom/GeneralPath");
4632N/A static JNF_CTOR_CACHE(jc_GeneralPath_ctor, jc_GeneralPath, "(I[BI[FI)V");
4632N/A generalPath = JNFNewObject(env, jc_GeneralPath_ctor, java_awt_geom_PathIterator_WIND_NON_ZERO, pointTypes, path->fNumberOfSegments, pointCoords, path->fNumberOfDataElements); // AWT_THREADING Safe (known object)
4632N/A
4632N/A // Cleanup
4632N/Acleanup:
4632N/A if (path != NULL) {
4632N/A AWTPathFree(path);
4632N/A path = NULL;
4632N/A }
4632N/A
4632N/A if (pointCoords != NULL) {
4632N/A (*env)->DeleteLocalRef(env, pointCoords);
4632N/A pointCoords = NULL;
4632N/A }
4632N/A
4632N/A if (pointTypes != NULL) {
4632N/A (*env)->DeleteLocalRef(env, pointTypes);
4632N/A pointTypes = NULL;
4632N/A }
4632N/A
4632N/A AWT_FONT_CLEANUP_FINISH;
4632N/AJNF_COCOA_EXIT(env);
4632N/A return generalPath;
4632N/A}
4632N/A
4632N/A/*
4632N/A * Class: sun_font_CStrike
4632N/A * Method: getGlyphImagePtrsNative
4632N/A * Signature: (JJ[J[II)V
4632N/A */
4632N/AJNIEXPORT void JNICALL
4632N/AJava_sun_font_CStrike_getGlyphImagePtrsNative
4632N/A (JNIEnv *env, jclass clazz,
4632N/A jlong awtStrikePtr, jlongArray glyphInfoLongArray,
4632N/A jintArray glyphCodes, jint len)
4632N/A{
4632N/AJNF_COCOA_ENTER(env);
4632N/A
4632N/A AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
4632N/A
4632N/A jlong *glyphInfos =
4632N/A (*env)->GetPrimitiveArrayCritical(env, glyphInfoLongArray, NULL);
4632N/A jint *rawGlyphCodes =
4632N/A (*env)->GetPrimitiveArrayCritical(env, glyphCodes, NULL);
4632N/A
4632N/A CGGlyphImages_GetGlyphImagePtrs(glyphInfos, awtStrike,
4632N/A rawGlyphCodes, len);
4632N/A
4632N/A (*env)->ReleasePrimitiveArrayCritical(env, glyphCodes,
4632N/A rawGlyphCodes, JNI_ABORT);
4632N/A // Do not use JNI_COMMIT, as that will not free the buffer copy
4632N/A // when +ProtectJavaHeap is on.
4632N/A (*env)->ReleasePrimitiveArrayCritical(env, glyphInfoLongArray,
4632N/A glyphInfos, 0);
4632N/A
4632N/AJNF_COCOA_EXIT(env);
4632N/A}
4632N/A
4632N/A/*
4632N/A * Class: sun_font_CStrike
4632N/A * Method: createNativeStrikePtr
4632N/A * Signature: (J[D[DII)J
4632N/A */
4632N/AJNIEXPORT jlong JNICALL Java_sun_font_CStrike_createNativeStrikePtr
4632N/A(JNIEnv *env, jclass clazz, jlong nativeFontPtr, jdoubleArray glyphTxArray, jdoubleArray invDevTxArray, jint aaStyle, jint fmHint)
4632N/A{
4632N/A AWTStrike *awtStrike = nil;
4632N/AJNF_COCOA_ENTER(env);
4632N/A
4632N/A AWTFont *awtFont = (AWTFont *)jlong_to_ptr(nativeFontPtr);
4632N/A JRSFontRenderingStyle style = JRSFontGetRenderingStyleForHints(fmHint, aaStyle);
4632N/A
4632N/A CGAffineTransform glyphTx = GetTxFromDoubles(env, glyphTxArray);
4632N/A CGAffineTransform invDevTx = GetTxFromDoubles(env, invDevTxArray);
4632N/A
4632N/A awtStrike = [AWTStrike awtStrikeForFont:awtFont tx:glyphTx invDevTx:invDevTx style:style aaStyle:aaStyle]; // autoreleased
4632N/A
4632N/A if (awtStrike)
4632N/A {
4632N/A CFRetain(awtStrike); // GC
4632N/A }
4632N/A
4632N/AJNF_COCOA_EXIT(env);
4632N/A return ptr_to_jlong(awtStrike);
4632N/A}
4632N/A
4632N/A/*
4632N/A * Class: sun_font_CStrike
4632N/A * Method: disposeNativeStrikePtr
4632N/A * Signature: (J)V
4632N/A */
4632N/AJNIEXPORT void JNICALL
4632N/AJava_sun_font_CStrike_disposeNativeStrikePtr
4632N/A (JNIEnv *env, jclass clazz, jlong awtStrike)
4632N/A{
4632N/AJNF_COCOA_ENTER(env);
4632N/A
4632N/A if (awtStrike) {
4632N/A CFRelease((AWTStrike *)jlong_to_ptr(awtStrike)); // GC
4632N/A }
4632N/A
4632N/AJNF_COCOA_EXIT(env);
4632N/A}
4632N/A
4632N/A/*
4632N/A * Class: sun_font_CStrike
4632N/A * Method: getFontMetrics
4632N/A * Signature: (J)Lsun/font/StrikeMetrics;
4632N/A */
4632N/AJNIEXPORT jobject JNICALL
4632N/AJava_sun_font_CStrike_getFontMetrics
4632N/A (JNIEnv *env, jclass clazz, jlong awtStrikePtr)
4632N/A{
4632N/A jobject metrics = NULL;
4632N/A
4632N/AJNF_COCOA_ENTER(env);
4632N/A AWT_FONT_CLEANUP_SETUP;
4632N/A
4632N/A AWTFont *awtfont = ((AWTStrike *)jlong_to_ptr(awtStrikePtr))->fAWTFont;
4632N/A AWT_FONT_CLEANUP_CHECK(awtfont);
4632N/A
4632N/A CGFontRef cgFont = awtfont->fNativeCGFont;
4632N/A
4632N/A jfloat ay=0.0, dy=0.0, mx=0.0, ly=0.0;
4632N/A int unitsPerEm = CGFontGetUnitsPerEm(cgFont);
4632N/A CGFloat scaleX = (1.0 / unitsPerEm);
4632N/A CGFloat scaleY = (1.0 / unitsPerEm);
4632N/A
4632N/A // Ascent
4632N/A ay = -(CGFloat)CGFontGetAscent(cgFont) * scaleY;
4632N/A
4632N/A // Descent
4632N/A dy = -(CGFloat)CGFontGetDescent(cgFont) * scaleY;
4632N/A
4632N/A // Leading
4632N/A ly = (CGFloat)CGFontGetLeading(cgFont) * scaleY;
4632N/A
4632N/A // Max Advance for Font Direction (Strictly horizontal)
4632N/A mx = [awtfont->fFont maximumAdvancement].width;
4632N/A
4632N/A /*
4632N/A * ascent: no need to set ascentX - it will be zero.
4632N/A * descent: no need to set descentX - it will be zero.
4632N/A * baseline: old releases "made up" a number and also seemed to
4632N/A * make it up for "X" and set "Y" to 0.
4632N/A * leadingX: no need to set leadingX - it will be zero.
4632N/A * leadingY: made-up number, but being compatible with what 1.4.x did.
4632N/A * advance: no need to set yMaxLinearAdvanceWidth - it will be zero.
4632N/A */
4632N/A
4632N/A JNF_CLASS_CACHE(sjc_StrikeMetrics, "sun/font/StrikeMetrics");
4632N/A JNF_CTOR_CACHE(strikeMetricsCtr, sjc_StrikeMetrics, "(FFFFFFFFFF)V");
4632N/A metrics = JNFNewObject(env, strikeMetricsCtr,
4632N/A 0.0, ay, 0.0, dy, 1.0,
4632N/A 0.0, 0.0, ly, mx, 0.0);
4632N/A
4632N/Acleanup:
4632N/A AWT_FONT_CLEANUP_FINISH;
4632N/AJNF_COCOA_EXIT(env);
4632N/A
4632N/A return metrics;
4632N/A}
4877N/A
4877N/Aextern void AccelGlyphCache_RemoveAllInfos(GlyphInfo* glyph);
4877N/A/*
4877N/A * Class: sun_font_CStrikeDisposer
4877N/A * Method: removeGlyphInfoFromCache
4877N/A * Signature: (J)V
4877N/A */
4877N/AJNIEXPORT void JNICALL Java_sun_font_CStrikeDisposer_removeGlyphInfoFromCache
4877N/A(JNIEnv *env, jclass cls, jlong glyphInfo)
4877N/A{
4877N/A JNF_COCOA_ENTER(env);
4877N/A
4877N/A AccelGlyphCache_RemoveAllCellInfos((GlyphInfo*)jlong_to_ptr(glyphInfo));
4877N/A
4877N/A JNF_COCOA_EXIT(env);
4877N/A}