alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (AWTStrike.m)

This example Java source code file (AWTStrike.m) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

awt_font_cleanup_check, awtfont, awtstrike, cfrelease, cgaffinetransform, cgfloat, cgglyph, jnf_cocoa_enter, jnf_cocoa_exit, jnicall, jnienv, jniexport, null, this_file

The AWTStrike.m Java example source code

/*
 * Copyright (c) 2011, 2013, 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.
 */

#import <JavaNativeFoundation/JavaNativeFoundation.h>
#import "java_awt_geom_PathIterator.h"
#import "sun_awt_SunHints.h"
#import "sun_font_CStrike.h"
#import "sun_font_CStrikeDisposer.h"
#import "CGGlyphImages.h"
#import "CGGlyphOutlines.h"
#import "AWTStrike.h"
#import "CoreTextSupport.h"
//#import "jni_util.h"
#include "fontscalerdefs.h"

/* Use THIS_FILE when it is available. */
#ifndef THIS_FILE
    #define THIS_FILE __FILE__
#endif

@implementation AWTStrike

static CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 };

- (id) initWithFont:(AWTFont *)awtFont
                 tx:(CGAffineTransform)tx
           invDevTx:(CGAffineTransform)invDevTx
              style:(JRSFontRenderingStyle)style
            aaStyle:(jint)aaStyle {

    self = [super init];
    if (self) {
        fAWTFont = [awtFont retain];
        fStyle = style;
        fAAStyle = aaStyle;

        fTx = tx; // composited glyph and device transform

        fAltTx = tx;
        fAltTx.b *= -1;
        fAltTx.d *= -1;

        invDevTx.b *= -1;
        invDevTx.c *= -1;
        fFontTx = CGAffineTransformConcat(CGAffineTransformConcat(tx, invDevTx), sInverseTX);
        fDevTx = CGAffineTransformInvert(invDevTx);

        // the "font size" is the square root of the determinant of the matrix
        fSize = sqrt(abs(fFontTx.a * fFontTx.d - fFontTx.b * fFontTx.c));
    }
    return self;
}

- (void) dealloc {
    [fAWTFont release];
    fAWTFont = nil;

    [super dealloc];
}

+ (AWTStrike *) awtStrikeForFont:(AWTFont *)awtFont
                              tx:(CGAffineTransform)tx
                        invDevTx:(CGAffineTransform)invDevTx
                           style:(JRSFontRenderingStyle)style
                         aaStyle:(jint)aaStyle {

    return [[[AWTStrike alloc] initWithFont:awtFont
                                         tx:tx invDevTx:invDevTx
                                      style:style
                                    aaStyle:aaStyle] autorelease];
}

@end


#define AWT_FONT_CLEANUP_SETUP \
    BOOL _fontThrowJavaException = NO;

#define AWT_FONT_CLEANUP_CHECK(a)                                       \
    if ((a) == NULL) {                                                  \
        _fontThrowJavaException = YES;                                  \
        goto cleanup;                                                   \
    }                                                                   \
    if ((*env)->ExceptionCheck(env) == JNI_TRUE) {                      \
        goto cleanup;                                                   \
    }

#define AWT_FONT_CLEANUP_FINISH                                         \
    if (_fontThrowJavaException == YES) {                               \
        char s[512];                                                    \
        sprintf(s, "%s-%s:%d", THIS_FILE, __FUNCTION__, __LINE__);       \
        [JNFException raise:env as:kRuntimeException reason:s];         \
    }


/*
 * Creates an affine transform from the corresponding doubles sent
 * from CStrike.getGlyphTx().
 */
static inline CGAffineTransform
GetTxFromDoubles(JNIEnv *env, jdoubleArray txArray)
{
    if (txArray == NULL) {
        return CGAffineTransformIdentity;
    }

    jdouble *txPtr = (*env)->GetPrimitiveArrayCritical(env, txArray, NULL);

    CGAffineTransform tx =
        CGAffineTransformMake(txPtr[0], txPtr[1], txPtr[2],
                              txPtr[3], txPtr[4], txPtr[5]);
    tx = CGAffineTransformConcat(sInverseTX, tx);

    (*env)->ReleasePrimitiveArrayCritical(env, txArray, txPtr, JNI_ABORT);

    return tx;
}

/*
 * Class:     sun_font_CStrike
 * Method:    getNativeGlyphAdvance
 * Signature: (JI)F
 */
JNIEXPORT jfloat JNICALL
Java_sun_font_CStrike_getNativeGlyphAdvance
    (JNIEnv *env, jclass clazz, jlong awtStrikePtr, jint glyphCode)
{
    CGSize advance;
JNF_COCOA_ENTER(env);
    AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
    AWTFont *awtFont = awtStrike->fAWTFont;

    // negative glyph codes are really unicodes, which were placed there by the mapper
    // to indicate we should use CoreText to substitute the character
    CGGlyph glyph;
    const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);
    CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &advance, 1);
    CFRelease(fallback);
    advance = CGSizeApplyAffineTransform(advance, awtStrike->fFontTx);
    if (!JRSFontStyleUsesFractionalMetrics(awtStrike->fStyle)) {
        advance.width = round(advance.width);
    }

JNF_COCOA_EXIT(env);
    return advance.width;
}

/*
 * Class:     sun_font_CStrike
 * Method:    getNativeGlyphImageBounds
 * Signature: (JJILjava/awt/geom/Rectangle2D/Float;DD)V
 */
JNIEXPORT void JNICALL
Java_sun_font_CStrike_getNativeGlyphImageBounds
    (JNIEnv *env, jclass clazz,
     jlong awtStrikePtr, jint glyphCode,
     jobject result /*Rectangle*/, jdouble x, jdouble y)
{
JNF_COCOA_ENTER(env);

    AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
    AWTFont *awtFont = awtStrike->fAWTFont;

    CGAffineTransform tx = awtStrike->fAltTx;
    tx.tx += x;
    tx.ty += y;

    // negative glyph codes are really unicodes, which were placed there by the mapper
    // to indicate we should use CoreText to substitute the character
    CGGlyph glyph;
    const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);

    CGRect bbox;
    JRSFontGetBoundingBoxesForGlyphsAndStyle(fallback, &tx, awtStrike->fStyle, &glyph, 1, &bbox);
    CFRelease(fallback);

    // the origin of this bounding box is relative to the bottom-left corner baseline
    CGFloat decender = -bbox.origin.y;
    bbox.origin.y = -bbox.size.height + decender;

    // Rectangle2D.Float.setRect(float x, float y, float width, float height);
    static JNF_CLASS_CACHE(sjc_Rectangle2D_Float, "java/awt/geom/Rectangle2D$Float");    // cache class id for Rectangle
    static JNF_MEMBER_CACHE(sjr_Rectangle2DFloat_setRect, sjc_Rectangle2D_Float, "setRect", "(FFFF)V");
    JNFCallVoidMethod(env, result, sjr_Rectangle2DFloat_setRect, (jfloat)bbox.origin.x, (jfloat)bbox.origin.y, (jfloat)bbox.size.width, (jfloat)bbox.size.height);

JNF_COCOA_EXIT(env);
}

/*
 * Class:     sun_font_CStrike
 * Method:    getNativeGlyphOutline
 * Signature: (JJIDD)Ljava/awt/geom/GeneralPath;
 */
JNIEXPORT jobject JNICALL
Java_sun_font_CStrike_getNativeGlyphOutline
    (JNIEnv *env, jclass clazz,
     jlong awtStrikePtr, jint glyphCode, jdouble xPos, jdouble yPos)
{
    jobject generalPath = NULL;

JNF_COCOA_ENTER(env);

    AWTPathRef path = NULL;
    jfloatArray pointCoords = NULL;
    jbyteArray pointTypes = NULL;

AWT_FONT_CLEANUP_SETUP;

    AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
    AWTFont *awtfont = awtStrike->fAWTFont;

AWT_FONT_CLEANUP_CHECK(awtfont);

    // inverting the shear order and sign to compensate for the flipped coordinate system
    CGAffineTransform tx = awtStrike->fTx;
    tx.tx += xPos;
    tx.ty += yPos;

    // get the right font and glyph for this "Java GlyphCode"

    CGGlyph glyph;
    const CTFontRef font = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtfont, glyphCode, &glyph);

    // get the advance of this glyph
    CGSize advance;
    CTFontGetAdvancesForGlyphs(font, kCTFontDefaultOrientation, &glyph, &advance, 1);

    // Create AWTPath
    path = AWTPathCreate(CGSizeMake(xPos, yPos));
AWT_FONT_CLEANUP_CHECK(path);

    // Get the paths
    tx = awtStrike->fTx;
    tx = CGAffineTransformConcat(tx, sInverseTX);
    AWTGetGlyphOutline(&glyph, (NSFont *)font, &advance, &tx, 0, 1, &path);
    CFRelease(font);

    pointCoords = (*env)->NewFloatArray(env, path->fNumberOfDataElements);
AWT_FONT_CLEANUP_CHECK(pointCoords);

    (*env)->SetFloatArrayRegion(env, pointCoords, 0, path->fNumberOfDataElements, (jfloat*)path->fSegmentData);

    // Copy the pointTypes to the general path
    pointTypes = (*env)->NewByteArray(env, path->fNumberOfSegments);
AWT_FONT_CLEANUP_CHECK(pointTypes);

    (*env)->SetByteArrayRegion(env, pointTypes, 0, path->fNumberOfSegments, (jbyte*)path->fSegmentType);

    static JNF_CLASS_CACHE(jc_GeneralPath, "java/awt/geom/GeneralPath");
    static JNF_CTOR_CACHE(jc_GeneralPath_ctor, jc_GeneralPath, "(I[BI[FI)V");
    generalPath = JNFNewObject(env, jc_GeneralPath_ctor, java_awt_geom_PathIterator_WIND_NON_ZERO, pointTypes, path->fNumberOfSegments, pointCoords, path->fNumberOfDataElements); // AWT_THREADING Safe (known object)

    // Cleanup
cleanup:
    if (path != NULL) {
        AWTPathFree(path);
        path = NULL;
    }

    if (pointCoords != NULL) {
        (*env)->DeleteLocalRef(env, pointCoords);
        pointCoords = NULL;
    }

    if (pointTypes != NULL) {
        (*env)->DeleteLocalRef(env, pointTypes);
        pointTypes = NULL;
    }

    AWT_FONT_CLEANUP_FINISH;
JNF_COCOA_EXIT(env);
    return generalPath;
}

/*
 * Class:     sun_font_CStrike
 * Method:    getGlyphImagePtrsNative
 * Signature: (JJ[J[II)V
 */
JNIEXPORT void JNICALL
Java_sun_font_CStrike_getGlyphImagePtrsNative
    (JNIEnv *env, jclass clazz,
     jlong awtStrikePtr, jlongArray glyphInfoLongArray,
     jintArray glyphCodes, jint len)
{
JNF_COCOA_ENTER(env);

    AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);

    jlong *glyphInfos =
        (*env)->GetPrimitiveArrayCritical(env, glyphInfoLongArray, NULL);
    jint *rawGlyphCodes =
        (*env)->GetPrimitiveArrayCritical(env, glyphCodes, NULL);

    CGGlyphImages_GetGlyphImagePtrs(glyphInfos, awtStrike,
                                    rawGlyphCodes, len);

    (*env)->ReleasePrimitiveArrayCritical(env, glyphCodes,
                                          rawGlyphCodes, JNI_ABORT);
    // Do not use JNI_COMMIT, as that will not free the buffer copy
    // when +ProtectJavaHeap is on.
    (*env)->ReleasePrimitiveArrayCritical(env, glyphInfoLongArray,
                                          glyphInfos, 0);

JNF_COCOA_EXIT(env);
}

/*
 * Class:     sun_font_CStrike
 * Method:    createNativeStrikePtr
 * Signature: (J[D[DII)J
 */
JNIEXPORT jlong JNICALL Java_sun_font_CStrike_createNativeStrikePtr
(JNIEnv *env, jclass clazz, jlong nativeFontPtr, jdoubleArray glyphTxArray, jdoubleArray invDevTxArray, jint aaStyle, jint fmHint)
{
    AWTStrike *awtStrike = nil;
JNF_COCOA_ENTER(env);

    AWTFont *awtFont = (AWTFont *)jlong_to_ptr(nativeFontPtr);
    JRSFontRenderingStyle style = JRSFontGetRenderingStyleForHints(fmHint, aaStyle);

    CGAffineTransform glyphTx = GetTxFromDoubles(env, glyphTxArray);
    CGAffineTransform invDevTx = GetTxFromDoubles(env, invDevTxArray);

    awtStrike = [AWTStrike awtStrikeForFont:awtFont tx:glyphTx invDevTx:invDevTx style:style aaStyle:aaStyle]; // autoreleased

    if (awtStrike)
    {
        CFRetain(awtStrike); // GC
    }

JNF_COCOA_EXIT(env);
    return ptr_to_jlong(awtStrike);
}

/*
 * Class:     sun_font_CStrike
 * Method:    disposeNativeStrikePtr
 * Signature: (J)V
 */
JNIEXPORT void JNICALL
Java_sun_font_CStrike_disposeNativeStrikePtr
    (JNIEnv *env, jclass clazz, jlong awtStrike)
{
JNF_COCOA_ENTER(env);

    if (awtStrike) {
        CFRelease((AWTStrike *)jlong_to_ptr(awtStrike)); // GC
    }

JNF_COCOA_EXIT(env);
}

/*
 * Class:     sun_font_CStrike
 * Method:    getFontMetrics
 * Signature: (J)Lsun/font/StrikeMetrics;
 */
JNIEXPORT jobject JNICALL
Java_sun_font_CStrike_getFontMetrics
    (JNIEnv *env, jclass clazz, jlong awtStrikePtr)
{
    jobject metrics = NULL;

JNF_COCOA_ENTER(env);
    AWT_FONT_CLEANUP_SETUP;

    AWTFont *awtfont = ((AWTStrike *)jlong_to_ptr(awtStrikePtr))->fAWTFont;
    AWT_FONT_CLEANUP_CHECK(awtfont);

    CGFontRef cgFont = awtfont->fNativeCGFont;

    jfloat ay=0.0, dy=0.0, mx=0.0, ly=0.0;
    int unitsPerEm = CGFontGetUnitsPerEm(cgFont);
    CGFloat scaleX = (1.0 / unitsPerEm);
    CGFloat scaleY = (1.0 / unitsPerEm);

    // Ascent
    ay = -(CGFloat)CGFontGetAscent(cgFont) * scaleY;

    // Descent
    dy = -(CGFloat)CGFontGetDescent(cgFont) * scaleY;

    // Leading
    ly = (CGFloat)CGFontGetLeading(cgFont) * scaleY;

    // Max Advance for Font Direction (Strictly horizontal)
    mx = [awtfont->fFont maximumAdvancement].width;

    /*
     * ascent:   no need to set ascentX - it will be zero.
     * descent:  no need to set descentX - it will be zero.
     * baseline: old releases "made up" a number and also seemed to
     *           make it up for "X" and set "Y" to 0.
     * leadingX: no need to set leadingX - it will be zero.
     * leadingY: made-up number, but being compatible with what 1.4.x did.
     * advance:  no need to set yMaxLinearAdvanceWidth - it will be zero.
     */

    JNF_CLASS_CACHE(sjc_StrikeMetrics, "sun/font/StrikeMetrics");
    JNF_CTOR_CACHE(strikeMetricsCtr, sjc_StrikeMetrics, "(FFFFFFFFFF)V");
    metrics = JNFNewObject(env, strikeMetricsCtr,
                           0.0, ay, 0.0, dy, 1.0,
                           0.0, 0.0, ly, mx, 0.0);

cleanup:
    AWT_FONT_CLEANUP_FINISH;
JNF_COCOA_EXIT(env);

    return metrics;
}

extern void AccelGlyphCache_RemoveAllInfos(GlyphInfo* glyph);
/*
 * Class:     sun_font_CStrikeDisposer
 * Method:    removeGlyphInfoFromCache
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_sun_font_CStrikeDisposer_removeGlyphInfoFromCache
(JNIEnv *env, jclass cls, jlong glyphInfo)
{
    JNF_COCOA_ENTER(env);

    AccelGlyphCache_RemoveAllCellInfos((GlyphInfo*)jlong_to_ptr(glyphInfo));

    JNF_COCOA_EXIT(env);
}

Other Java examples (source code examples)

Here is a short list of links related to this Java AWTStrike.m source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.