Path: blob/master/src/java.desktop/macosx/native/libawt_lwawt/font/AWTStrike.m
41152 views
/*1* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#import "java_awt_geom_PathIterator.h"26#import "sun_font_CStrike.h"27#import "sun_font_CStrikeDisposer.h"28#import "CGGlyphImages.h"29#import "CGGlyphOutlines.h"30#import "CoreTextSupport.h"31#import "JNIUtilities.h"32#include "fontscalerdefs.h"3334@implementation AWTStrike3536static CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 };3738- (id) initWithFont:(AWTFont *)awtFont39tx:(CGAffineTransform)tx40invDevTx:(CGAffineTransform)invDevTx41style:(JRSFontRenderingStyle)style42aaStyle:(jint)aaStyle {4344self = [super init];45if (self) {46fAWTFont = [awtFont retain];47fStyle = style;48fAAStyle = aaStyle;4950fTx = tx; // composited glyph and device transform5152fAltTx = tx;53fAltTx.b *= -1;54fAltTx.d *= -1;5556invDevTx.b *= -1;57invDevTx.c *= -1;58fFontTx = CGAffineTransformConcat(CGAffineTransformConcat(tx, invDevTx), sInverseTX);59fDevTx = CGAffineTransformInvert(CGAffineTransformConcat(invDevTx, sInverseTX));6061// the "font size" is the square root of the determinant of the matrix62fSize = sqrt(fabs(fFontTx.a * fFontTx.d - fFontTx.b * fFontTx.c));63}64return self;65}6667- (void) dealloc {68[fAWTFont release];69fAWTFont = nil;7071[super dealloc];72}7374+ (AWTStrike *) awtStrikeForFont:(AWTFont *)awtFont75tx:(CGAffineTransform)tx76invDevTx:(CGAffineTransform)invDevTx77style:(JRSFontRenderingStyle)style78aaStyle:(jint)aaStyle {7980return [[[AWTStrike alloc] initWithFont:awtFont81tx:tx invDevTx:invDevTx82style:style83aaStyle:aaStyle] autorelease];84}8586@end878889#define AWT_FONT_CLEANUP_SETUP \90BOOL _fontThrowJavaException = NO;9192#define AWT_FONT_CLEANUP_CHECK(a) \93if ((a) == NULL) { \94_fontThrowJavaException = YES; \95goto cleanup; \96} \97if ((*env)->ExceptionCheck(env) == JNI_TRUE) { \98goto cleanup; \99}100101#define AWT_FONT_CLEANUP_FINISH \102if (_fontThrowJavaException == YES) { \103char s[512]; \104sprintf(s, "%s-%s:%d", __FILE__, __FUNCTION__, __LINE__); \105JNU_ThrowByName(env, "java/lang/RuntimeException", s); \106}107108109/*110* Creates an affine transform from the corresponding doubles sent111* from CStrike.getGlyphTx().112*/113static inline CGAffineTransform114GetTxFromDoubles(JNIEnv *env, jdoubleArray txArray)115{116if (txArray == NULL) {117return CGAffineTransformIdentity;118}119120jdouble *txPtr = (*env)->GetPrimitiveArrayCritical(env, txArray, NULL);121if (txPtr == NULL) {122return CGAffineTransformIdentity;123}124125CGAffineTransform tx =126CGAffineTransformMake(txPtr[0], txPtr[1], txPtr[2],127txPtr[3], txPtr[4], txPtr[5]);128tx = CGAffineTransformConcat(sInverseTX, tx);129130(*env)->ReleasePrimitiveArrayCritical(env, txArray, txPtr, JNI_ABORT);131132return tx;133}134135/*136* Class: sun_font_CStrike137* Method: getNativeGlyphAdvance138* Signature: (JI)F139*/140JNIEXPORT jfloat JNICALL141Java_sun_font_CStrike_getNativeGlyphAdvance142(JNIEnv *env, jclass clazz, jlong awtStrikePtr, jint glyphCode)143{144CGSize advance;145JNI_COCOA_ENTER(env);146AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);147AWTFont *awtFont = awtStrike->fAWTFont;148149// negative glyph codes are really unicodes, which were placed there by the mapper150// to indicate we should use CoreText to substitute the character151CGGlyph glyph;152const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);153CGGlyphImages_GetGlyphMetrics(fallback, &awtStrike->fAltTx, awtStrike->fStyle, &glyph, 1, NULL, &advance);154CFRelease(fallback);155advance = CGSizeApplyAffineTransform(advance, awtStrike->fFontTx);156if (!JRSFontStyleUsesFractionalMetrics(awtStrike->fStyle)) {157advance.width = round(advance.width);158}159160JNI_COCOA_EXIT(env);161return advance.width;162}163164/*165* Class: sun_font_CStrike166* Method: getNativeGlyphImageBounds167* Signature: (JJILjava/awt/geom/Rectangle2D/Float;DD)V168*/169JNIEXPORT void JNICALL170Java_sun_font_CStrike_getNativeGlyphImageBounds171(JNIEnv *env, jclass clazz,172jlong awtStrikePtr, jint glyphCode,173jobject result /*Rectangle*/, jdouble x, jdouble y)174{175JNI_COCOA_ENTER(env);176177AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);178AWTFont *awtFont = awtStrike->fAWTFont;179180CGAffineTransform tx = awtStrike->fAltTx;181tx.tx += x;182tx.ty += y;183184// negative glyph codes are really unicodes, which were placed there by the mapper185// to indicate we should use CoreText to substitute the character186CGGlyph glyph;187const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);188189CGRect bbox;190CGGlyphImages_GetGlyphMetrics(fallback, &tx, awtStrike->fStyle, &glyph, 1, &bbox, NULL);191CFRelease(fallback);192193// the origin of this bounding box is relative to the bottom-left corner baseline194CGFloat decender = -bbox.origin.y;195bbox.origin.y = -bbox.size.height + decender;196197// Rectangle2D.Float.setRect(float x, float y, float width, float height);198DECLARE_CLASS(sjc_Rectangle2D_Float, "java/awt/geom/Rectangle2D$Float"); // cache class id for Rectangle199DECLARE_METHOD(sjr_Rectangle2DFloat_setRect, sjc_Rectangle2D_Float, "setRect", "(FFFF)V");200(*env)->CallVoidMethod(env, result, sjr_Rectangle2DFloat_setRect,201(jfloat)bbox.origin.x, (jfloat)bbox.origin.y, (jfloat)bbox.size.width, (jfloat)bbox.size.height);202CHECK_EXCEPTION();203204JNI_COCOA_EXIT(env);205}206207/*208* Class: sun_font_CStrike209* Method: getNativeGlyphOutline210* Signature: (JJIDD)Ljava/awt/geom/GeneralPath;211*/212JNIEXPORT jobject JNICALL213Java_sun_font_CStrike_getNativeGlyphOutline214(JNIEnv *env, jclass clazz,215jlong awtStrikePtr, jint glyphCode, jdouble xPos, jdouble yPos)216{217jobject generalPath = NULL;218219JNI_COCOA_ENTER(env);220221AWTPathRef path = NULL;222jfloatArray pointCoords = NULL;223jbyteArray pointTypes = NULL;224225DECLARE_CLASS_RETURN(jc_GeneralPath, "java/awt/geom/GeneralPath", NULL);226DECLARE_METHOD_RETURN(jc_GeneralPath_ctor, jc_GeneralPath, "<init>", "(I[BI[FI)V", NULL);227228AWT_FONT_CLEANUP_SETUP;229230AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);231AWTFont *awtfont = awtStrike->fAWTFont;232233AWT_FONT_CLEANUP_CHECK(awtfont);234235// inverting the shear order and sign to compensate for the flipped coordinate system236CGAffineTransform tx = awtStrike->fTx;237tx.tx += xPos;238tx.ty += yPos;239240// get the right font and glyph for this "Java GlyphCode"241242CGGlyph glyph;243const CTFontRef font = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtfont, glyphCode, &glyph);244245// get the advance of this glyph246CGSize advance;247CTFontGetAdvancesForGlyphs(font, kCTFontDefaultOrientation, &glyph, &advance, 1);248249// Create AWTPath250path = AWTPathCreate(CGSizeMake(xPos, yPos));251AWT_FONT_CLEANUP_CHECK(path);252253// Get the paths254tx = awtStrike->fTx;255tx = CGAffineTransformConcat(tx, sInverseTX);256AWTGetGlyphOutline(&glyph, (NSFont *)font, &advance, &tx, 0, 1, &path);257CFRelease(font);258259pointCoords = (*env)->NewFloatArray(env, path->fNumberOfDataElements);260AWT_FONT_CLEANUP_CHECK(pointCoords);261262(*env)->SetFloatArrayRegion(env, pointCoords, 0, path->fNumberOfDataElements, (jfloat*)path->fSegmentData);263264// Copy the pointTypes to the general path265pointTypes = (*env)->NewByteArray(env, path->fNumberOfSegments);266AWT_FONT_CLEANUP_CHECK(pointTypes);267268(*env)->SetByteArrayRegion(env, pointTypes, 0, path->fNumberOfSegments, (jbyte*)path->fSegmentType);269270generalPath = (*env)->NewObject(env, jc_GeneralPath, jc_GeneralPath_ctor, java_awt_geom_PathIterator_WIND_NON_ZERO, pointTypes,271path->fNumberOfSegments, pointCoords, path->fNumberOfDataElements); // AWT_THREADING Safe (known object)272273// Cleanup274cleanup:275if (path != NULL) {276AWTPathFree(path);277path = NULL;278}279280if (pointCoords != NULL) {281(*env)->DeleteLocalRef(env, pointCoords);282pointCoords = NULL;283}284285if (pointTypes != NULL) {286(*env)->DeleteLocalRef(env, pointTypes);287pointTypes = NULL;288}289290AWT_FONT_CLEANUP_FINISH;291JNI_COCOA_EXIT(env);292return generalPath;293}294295/*296* Class: sun_font_CStrike297* Method: getGlyphImagePtrsNative298* Signature: (JJ[J[II)V299*/300JNIEXPORT void JNICALL301Java_sun_font_CStrike_getGlyphImagePtrsNative302(JNIEnv *env, jclass clazz,303jlong awtStrikePtr, jlongArray glyphInfoLongArray,304jintArray glyphCodes, jint len)305{306JNI_COCOA_ENTER(env);307308AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);309310jlong *glyphInfos =311(*env)->GetPrimitiveArrayCritical(env, glyphInfoLongArray, NULL);312313jint *rawGlyphCodes =314(*env)->GetPrimitiveArrayCritical(env, glyphCodes, NULL);315@try {316if (rawGlyphCodes != NULL && glyphInfos != NULL) {317CGGlyphImages_GetGlyphImagePtrs(glyphInfos, awtStrike,318rawGlyphCodes, len);319}320}321@finally {322if (rawGlyphCodes != NULL) {323(*env)->ReleasePrimitiveArrayCritical(env, glyphCodes,324rawGlyphCodes, JNI_ABORT);325}326if (glyphInfos != NULL) {327// Do not use JNI_COMMIT, as that will not free the buffer copy328// when +ProtectJavaHeap is on.329(*env)->ReleasePrimitiveArrayCritical(env, glyphInfoLongArray,330glyphInfos, 0);331}332}333334JNI_COCOA_EXIT(env);335}336337/*338* Class: sun_font_CStrike339* Method: createNativeStrikePtr340* Signature: (J[D[DII)J341*/342JNIEXPORT jlong JNICALL Java_sun_font_CStrike_createNativeStrikePtr343(JNIEnv *env, jclass clazz, jlong nativeFontPtr, jdoubleArray glyphTxArray, jdoubleArray invDevTxArray, jint aaStyle, jint fmHint)344{345AWTStrike *awtStrike = nil;346JNI_COCOA_ENTER(env);347348AWTFont *awtFont = (AWTFont *)jlong_to_ptr(nativeFontPtr);349JRSFontRenderingStyle style = JRSFontGetRenderingStyleForHints(fmHint, aaStyle);350351CGAffineTransform glyphTx = GetTxFromDoubles(env, glyphTxArray);352CGAffineTransform invDevTx = GetTxFromDoubles(env, invDevTxArray);353354awtStrike = [AWTStrike awtStrikeForFont:awtFont tx:glyphTx invDevTx:invDevTx style:style aaStyle:aaStyle]; // autoreleased355356if (awtStrike)357{358CFRetain(awtStrike); // GC359}360361JNI_COCOA_EXIT(env);362return ptr_to_jlong(awtStrike);363}364365/*366* Class: sun_font_CStrike367* Method: disposeNativeStrikePtr368* Signature: (J)V369*/370JNIEXPORT void JNICALL371Java_sun_font_CStrike_disposeNativeStrikePtr372(JNIEnv *env, jclass clazz, jlong awtStrike)373{374JNI_COCOA_ENTER(env);375376if (awtStrike) {377CFRelease((AWTStrike *)jlong_to_ptr(awtStrike)); // GC378}379380JNI_COCOA_EXIT(env);381}382383/*384* Class: sun_font_CStrike385* Method: getFontMetrics386* Signature: (J)Lsun/font/StrikeMetrics;387*/388JNIEXPORT jobject JNICALL389Java_sun_font_CStrike_getFontMetrics390(JNIEnv *env, jclass clazz, jlong awtStrikePtr)391{392jobject metrics = NULL;393394JNI_COCOA_ENTER(env);395AWT_FONT_CLEANUP_SETUP;396397AWTFont *awtfont = ((AWTStrike *)jlong_to_ptr(awtStrikePtr))->fAWTFont;398AWT_FONT_CLEANUP_CHECK(awtfont);399400CGFontRef cgFont = awtfont->fNativeCGFont;401402jfloat ay=0.0, dy=0.0, mx=0.0, ly=0.0;403int unitsPerEm = CGFontGetUnitsPerEm(cgFont);404CGFloat scaleX = (1.0 / unitsPerEm);405CGFloat scaleY = (1.0 / unitsPerEm);406407// Ascent408ay = -(CGFloat)CGFontGetAscent(cgFont) * scaleY;409410// Descent411dy = -(CGFloat)CGFontGetDescent(cgFont) * scaleY;412413// Leading414ly = (CGFloat)CGFontGetLeading(cgFont) * scaleY;415416// Max Advance for Font Direction (Strictly horizontal)417mx = [awtfont->fFont maximumAdvancement].width;418419/*420* ascent: no need to set ascentX - it will be zero.421* descent: no need to set descentX - it will be zero.422* baseline: old releases "made up" a number and also seemed to423* make it up for "X" and set "Y" to 0.424* leadingX: no need to set leadingX - it will be zero.425* leadingY: made-up number, but being compatible with what 1.4.x did.426* advance: no need to set yMaxLinearAdvanceWidth - it will be zero.427*/428429DECLARE_CLASS_RETURN(sjc_StrikeMetrics, "sun/font/StrikeMetrics", NULL);430DECLARE_METHOD_RETURN(strikeMetricsCtr, sjc_StrikeMetrics, "<init>", "(FFFFFFFFFF)V", NULL);431metrics = (*env)->NewObject(env, sjc_StrikeMetrics, strikeMetricsCtr,4320.0, ay, 0.0, dy, 1.0,4330.0, 0.0, ly, mx, 0.0);434435cleanup:436AWT_FONT_CLEANUP_FINISH;437JNI_COCOA_EXIT(env);438439return metrics;440}441442extern void AccelGlyphCache_RemoveAllInfos(GlyphInfo* glyph);443/*444* Class: sun_font_CStrikeDisposer445* Method: removeGlyphInfoFromCache446* Signature: (J)V447*/448JNIEXPORT void JNICALL Java_sun_font_CStrikeDisposer_removeGlyphInfoFromCache449(JNIEnv *env, jclass cls, jlong glyphInfo)450{451JNI_COCOA_ENTER(env);452453AccelGlyphCache_RemoveAllCellInfos((GlyphInfo*)jlong_to_ptr(glyphInfo));454455JNI_COCOA_EXIT(env);456}457458459