Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/native_NOTIOS/sun/awt/CTextPipe.m
38829 views
/*1* Copyright (c) 2011, 2013, 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// Native side of the Quartz text pipe, paints on Quartz Surface Datas.26// Interesting Docs : /Developer/Documentation/Cocoa/TasksAndConcepts/ProgrammingTopics/FontHandling/FontHandling.html2728#import "sun_awt_SunHints.h"29#import "sun_lwawt_macosx_CTextPipe.h"30#import "sun_java2d_OSXSurfaceData.h"3132#import <JavaNativeFoundation/JavaNativeFoundation.h>3334#import "CoreTextSupport.h"35#import "QuartzSurfaceData.h"36#include "AWTStrike.h"3738/* Use THIS_FILE when it is available. */39#ifndef THIS_FILE40#define THIS_FILE __FILE__41#endif4243static const CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 };444546#pragma mark --- CoreText Support ---474849// Translates a Unicode into a CGGlyph/CTFontRef pair50// Returns the substituted font, and places the appropriate glyph into "glyphRef"51CTFontRef JavaCT_CopyCTFallbackFontAndGlyphForUnicode52(const AWTFont *font, const UTF16Char *charRef, CGGlyph *glyphRef, int count) {53CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, charRef, count);54if (fallback == NULL)55{56// use the original font if we somehow got duped into trying to fallback something we can't57fallback = (CTFontRef)font->fFont;58CFRetain(fallback);59}6061CTFontGetGlyphsForCharacters(fallback, charRef, glyphRef, count);62return fallback;63}6465// Translates a Java glyph code int (might be a negative unicode value) into a CGGlyph/CTFontRef pair66// Returns the substituted font, and places the appropriate glyph into "glyph"67CTFontRef JavaCT_CopyCTFallbackFontAndGlyphForJavaGlyphCode68(const AWTFont *font, const jint glyphCode, CGGlyph *glyphRef)69{70// negative glyph codes are really unicodes, which were placed there by the mapper71// to indicate we should use CoreText to substitute the character72if (glyphCode >= 0)73{74*glyphRef = glyphCode;75CFRetain(font->fFont);76return (CTFontRef)font->fFont;77}7879UTF16Char character = -glyphCode;80return JavaCT_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);81}8283// Breakup a 32 bit unicode value into the component surrogate pairs84void JavaCT_BreakupUnicodeIntoSurrogatePairs(int uniChar, UTF16Char charRef[]) {85int value = uniChar - 0x10000;86UTF16Char low_surrogate = (value & 0x3FF) | LO_SURROGATE_START;87UTF16Char high_surrogate = (((int)(value & 0xFFC00)) >> 10) | HI_SURROGATE_START;88charRef[0] = high_surrogate;89charRef[1] = low_surrogate;90}91929394/*95* Callback for CoreText which uses the CoreTextProviderStruct to feed CT UniChars96* We only use it for one-off lines, and don't attempt to fragment our strings97*/98const UniChar *Java_CTProvider99(CFIndex stringIndex, CFIndex *charCount, CFDictionaryRef *attributes, void *refCon)100{101// if we have a zero length string we can just return NULL for the string102// or if the index anything other than 0 we are not using core text103// correctly since we only have one run.104if (stringIndex != 0)105{106return NULL;107}108109CTS_ProviderStruct *ctps = (CTS_ProviderStruct *)refCon;110*charCount = ctps->length;111*attributes = ctps->attributes;112return ctps->unicodes;113}114115116/*117* Gets a Dictionary filled with common details we want to use for CoreText when we are interacting118* with it from Java.119*/120static NSDictionary* ctsDictionaryFor(const NSFont *font, BOOL useFractionalMetrics)121{122NSNumber *gZeroNumber = [NSNumber numberWithInt:0];123NSNumber *gOneNumber = [NSNumber numberWithInt:1];124125return [NSDictionary dictionaryWithObjectsAndKeys:126font, NSFontAttributeName,127gOneNumber, (id)kCTForegroundColorFromContextAttributeName,128useFractionalMetrics ? gZeroNumber : gOneNumber, @"CTIntegerMetrics", // force integer hack in CoreText to help with Java's integer assumptions129gZeroNumber, NSLigatureAttributeName,130gZeroNumber, NSKernAttributeName,131nil];132}133134// Itterates though each glyph, and if a transform is present for that glyph, apply it to the CGContext, and strike the glyph.135// If there is no per-glyph transform, just strike the glyph. Advances must also be transformed on-the-spot as well.136void JavaCT_DrawGlyphVector137(const QuartzSDOps *qsdo, const AWTStrike *strike, const BOOL useSubstituion, const int uniChars[], const CGGlyph glyphs[], CGSize advances[], const jint g_gvTXIndicesAsInts[], const jdouble g_gvTransformsAsDoubles[], const CFIndex length)138{139CGPoint pt = { 0, 0 };140141// get our baseline transform and font142CGContextRef cgRef = qsdo->cgRef;143CGAffineTransform ctmText = CGContextGetTextMatrix(cgRef);144145BOOL saved = false;146147CGAffineTransform invTx = CGAffineTransformInvert(strike->fTx);148149NSInteger i;150for (i = 0; i < length; i++)151{152CGGlyph glyph = glyphs[i];153int uniChar = uniChars[i];154// if we found a unichar instead of a glyph code, get the fallback font,155// find the glyph code for the fallback font, and set the font on the current context156if (uniChar != 0)157{158CTFontRef fallback;159if (uniChar > 0xFFFF) {160UTF16Char charRef[2];161JavaCT_BreakupUnicodeIntoSurrogatePairs(uniChar, charRef);162CGGlyph glyphTmp[2];163fallback = JavaCT_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, (CGGlyph *)&glyphTmp, 2);164glyph = glyphTmp[0];165} else {166const UTF16Char u = uniChar;167fallback = JavaCT_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, &u, (CGGlyph *)&glyph, 1);168}169if (fallback) {170const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);171CFRelease(fallback);172173if (cgFallback) {174if (!saved) {175CGContextSaveGState(cgRef);176saved = true;177}178CGContextSetFont(cgRef, cgFallback);179CFRelease(cgFallback);180}181}182} else {183if (saved) {184CGContextRestoreGState(cgRef);185saved = false;186}187}188189// if we have per-glyph transformations190int tin = (g_gvTXIndicesAsInts == NULL) ? -1 : (g_gvTXIndicesAsInts[i] - 1) * 6;191if (tin < 0)192{193CGContextShowGlyphsAtPoint(cgRef, pt.x, pt.y, &glyph, 1);194}195else196{197CGAffineTransform tx = CGAffineTransformMake(198(CGFloat)g_gvTransformsAsDoubles[tin + 0], (CGFloat)g_gvTransformsAsDoubles[tin + 2],199(CGFloat)g_gvTransformsAsDoubles[tin + 1], (CGFloat)g_gvTransformsAsDoubles[tin + 3],2000, 0);201202CGPoint txOffset = { (CGFloat)g_gvTransformsAsDoubles[tin + 4], (CGFloat)g_gvTransformsAsDoubles[tin + 5] };203204txOffset = CGPointApplyAffineTransform(txOffset, invTx);205206// apply the transform, strike the glyph, can change the transform back207CGContextSetTextMatrix(cgRef, CGAffineTransformConcat(ctmText, tx));208CGContextShowGlyphsAtPoint(cgRef, txOffset.x + pt.x, txOffset.y + pt.y, &glyph, 1);209CGContextSetTextMatrix(cgRef, ctmText);210211// transform the measured advance for this strike212advances[i] = CGSizeApplyAffineTransform(advances[i], tx);213advances[i].width += txOffset.x;214advances[i].height += txOffset.y;215}216217// move our next x,y218pt.x += advances[i].width;219pt.y += advances[i].height;220221}222// reset the font on the context after striking a unicode with CoreText223if (saved) {224CGContextRestoreGState(cgRef);225}226}227228// Using the Quartz Surface Data context, draw a hot-substituted character run229void JavaCT_DrawTextUsingQSD(JNIEnv *env, const QuartzSDOps *qsdo, const AWTStrike *strike, const jchar *chars, const jsize length)230{231CGContextRef cgRef = qsdo->cgRef;232233AWTFont *awtFont = strike->fAWTFont;234CGFloat ptSize = strike->fSize;235CGAffineTransform tx = strike->fFontTx;236237NSFont *nsFont = [NSFont fontWithName:[awtFont->fFont fontName] size:ptSize];238239if (ptSize != 0) {240CGFloat invScale = 1 / ptSize;241tx = CGAffineTransformConcat(tx, CGAffineTransformMakeScale(invScale, invScale));242CGContextConcatCTM(cgRef, tx);243}244245CGContextSetTextMatrix(cgRef, CGAffineTransformIdentity); // resets the damage from CoreText246247NSString *string = [NSString stringWithCharacters:chars length:length];248/*249The calls below were used previously but for unknown reason did not250render using the right font (see bug 7183516) when attribString is not251initialized with font dictionary attributes. It seems that "options"252in CTTypesetterCreateWithAttributedStringAndOptions which contains the253font dictionary is ignored.254255NSAttributedString *attribString = [[NSAttributedString alloc] initWithString:string];256257CTTypesetterRef typeSetterRef = CTTypesetterCreateWithAttributedStringAndOptions((CFAttributedStringRef) attribString, (CFDictionaryRef) ctsDictionaryFor(nsFont, JRSFontStyleUsesFractionalMetrics(strike->fStyle)));258*/259NSAttributedString *attribString = [[NSAttributedString alloc]260initWithString:string261attributes:ctsDictionaryFor(nsFont, JRSFontStyleUsesFractionalMetrics(strike->fStyle))];262263CTTypesetterRef typeSetterRef = CTTypesetterCreateWithAttributedString((CFAttributedStringRef) attribString);264265CFRange range = {0, length};266CTLineRef lineRef = CTTypesetterCreateLine(typeSetterRef, range);267268CTLineDraw(lineRef, cgRef);269270[attribString release];271CFRelease(lineRef);272CFRelease(typeSetterRef);273}274275276/*----------------------277DrawTextContext is the funnel for all of our CoreText drawing.278All three JNI apis call through this method.279----------------------*/280static void DrawTextContext281(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, const jchar *chars, const jsize length, const jdouble x, const jdouble y)282{283if (length == 0)284{285return;286}287288qsdo->BeginSurface(env, qsdo, SD_Text);289if (qsdo->cgRef == NULL)290{291qsdo->FinishSurface(env, qsdo);292return;293}294295CGContextRef cgRef = qsdo->cgRef;296297298CGContextSaveGState(cgRef);299JRSFontSetRenderingStyleOnContext(cgRef, strike->fStyle);300301// we want to translate before we transform (scale or rotate) <rdar://4042541> (vm)302CGContextTranslateCTM(cgRef, x, y);303304AWTFont *awtfont = strike->fAWTFont; //(AWTFont *)(qsdo->fontInfo.awtfont);305NSCharacterSet *charSet = [awtfont->fFont coveredCharacterSet];306307JavaCT_DrawTextUsingQSD(env, qsdo, strike, chars, length); // Draw with CoreText308309CGContextRestoreGState(cgRef);310311qsdo->FinishSurface(env, qsdo);312}313314#pragma mark --- Glyph Vector Pipeline ---315316/*-----------------------------------317Glyph Vector Pipeline318319doDrawGlyphs() has been separated into several pipelined functions to increase performance,320and improve accountability for JNI resources, malloc'd memory, and error handling.321322Each stage of the pipeline is responsible for doing only one major thing, like allocating buffers,323aquiring transform arrays from JNI, filling buffers, or striking glyphs. All resources or memory324acquired at a given stage, must be released in that stage. Any error that occurs (like a failed malloc)325is to be handled in the stage it occurs in, and is to return immediatly after freeing it's resources.326327-----------------------------------*/328329static JNF_CLASS_CACHE(jc_StandardGlyphVector, "sun/font/StandardGlyphVector");330331// Checks the GlyphVector Java object for any transforms that were applied to individual characters. If none are present,332// strike the glyphs immediately in Core Graphics. Otherwise, obtain the arrays, and defer to above.333static inline void doDrawGlyphsPipe_checkForPerGlyphTransforms334(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, BOOL useSubstituion, int *uniChars, CGGlyph *glyphs, CGSize *advances, size_t length)335{336// if we have no character substitution, and no per-glyph transformations - strike now!337static JNF_MEMBER_CACHE(jm_StandardGlyphVector_gti, jc_StandardGlyphVector, "gti", "Lsun/font/StandardGlyphVector$GlyphTransformInfo;");338jobject gti = JNFGetObjectField(env, gVector, jm_StandardGlyphVector_gti);339if (gti == 0)340{341if (useSubstituion)342{343// quasi-simple case, substitution, but no per-glyph transforms344JavaCT_DrawGlyphVector(qsdo, strike, TRUE, uniChars, glyphs, advances, NULL, NULL, length);345}346else347{348// fast path, straight to CG without per-glyph transforms349CGContextShowGlyphsWithAdvances(qsdo->cgRef, glyphs, advances, length);350}351return;352}353354static JNF_CLASS_CACHE(jc_StandardGlyphVector_GlyphTransformInfo, "sun/font/StandardGlyphVector$GlyphTransformInfo");355static JNF_MEMBER_CACHE(jm_StandardGlyphVector_GlyphTransformInfo_transforms, jc_StandardGlyphVector_GlyphTransformInfo, "transforms", "[D");356jdoubleArray g_gtiTransformsArray = JNFGetObjectField(env, gti, jm_StandardGlyphVector_GlyphTransformInfo_transforms); //(*env)->GetObjectField(env, gti, g_gtiTransforms);357if (g_gtiTransformsArray == NULL) {358return;359}360jdouble *g_gvTransformsAsDoubles = (*env)->GetPrimitiveArrayCritical(env, g_gtiTransformsArray, NULL);361if (g_gvTransformsAsDoubles == NULL) {362(*env)->DeleteLocalRef(env, g_gtiTransformsArray);363return;364}365366static JNF_MEMBER_CACHE(jm_StandardGlyphVector_GlyphTransformInfo_indices, jc_StandardGlyphVector_GlyphTransformInfo, "indices", "[I");367jintArray g_gtiTXIndicesArray = JNFGetObjectField(env, gti, jm_StandardGlyphVector_GlyphTransformInfo_indices);368jint *g_gvTXIndicesAsInts = (*env)->GetPrimitiveArrayCritical(env, g_gtiTXIndicesArray, NULL);369if (g_gvTXIndicesAsInts == NULL) {370(*env)->ReleasePrimitiveArrayCritical(env, g_gtiTransformsArray, g_gvTransformsAsDoubles, JNI_ABORT);371(*env)->DeleteLocalRef(env, g_gtiTransformsArray);372(*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);373return;374}375// slowest case, we have per-glyph transforms, and possibly glyph substitution as well376JavaCT_DrawGlyphVector(qsdo, strike, useSubstituion, uniChars, glyphs, advances, g_gvTXIndicesAsInts, g_gvTransformsAsDoubles, length);377378(*env)->ReleasePrimitiveArrayCritical(env, g_gtiTransformsArray, g_gvTransformsAsDoubles, JNI_ABORT);379(*env)->ReleasePrimitiveArrayCritical(env, g_gtiTXIndicesArray, g_gvTXIndicesAsInts, JNI_ABORT);380381(*env)->DeleteLocalRef(env, g_gtiTransformsArray);382(*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);383}384385// Retrieves advances for translated unicodes386// Uses "glyphs" as a temporary buffer for the glyph-to-unicode translation387void JavaCT_GetAdvancesForUnichars388(const NSFont *font, const int uniChars[], CGGlyph glyphs[], const size_t length, CGSize advances[])389{390// cycle over each spot, and if we discovered a unicode to substitute, we have to calculate the advance for it391size_t i;392for (i = 0; i < length; i++)393{394UniChar uniChar = uniChars[i];395if (uniChar == 0) continue;396397CGGlyph glyph = 0;398const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font, &uniChar, 1);399if (fallback) {400CTFontGetGlyphsForCharacters(fallback, &uniChar, &glyph, 1);401CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &(advances[i]), 1);402CFRelease(fallback);403}404405glyphs[i] = glyph;406}407}408409// Fills the glyph buffer with glyphs from the GlyphVector object. Also checks to see if the glyph's positions have been410// already caculated from GlyphVector, or we simply ask Core Graphics to make some advances for us. Pre-calculated positions411// are translated into advances, since CG only understands advances.412static inline void doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers413(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, CGGlyph *glyphs, int *uniChars, CGSize *advances, size_t length, jintArray glyphsArray)414{415// fill the glyph buffer416jint *glyphsAsInts = (*env)->GetPrimitiveArrayCritical(env, glyphsArray, NULL);417if (glyphsAsInts == NULL) {418return;419}420421// if a glyph code from Java is negative, that means it is really a unicode value422// which we can use in CoreText to strike the character in another font423size_t i;424BOOL complex = NO;425for (i = 0; i < length; i++)426{427jint code = glyphsAsInts[i];428if (code < 0)429{430complex = YES;431uniChars[i] = -code;432glyphs[i] = 0;433}434else435{436uniChars[i] = 0;437glyphs[i] = code;438}439}440441(*env)->ReleasePrimitiveArrayCritical(env, glyphsArray, glyphsAsInts, JNI_ABORT);442443// fill the advance buffer444static JNF_MEMBER_CACHE(jm_StandardGlyphVector_positions, jc_StandardGlyphVector, "positions", "[F");445jfloatArray posArray = JNFGetObjectField(env, gVector, jm_StandardGlyphVector_positions);446jfloat *positions = NULL;447if (posArray != NULL) {448// in this case, the positions have already been pre-calculated for us on the Java side449positions = (*env)->GetPrimitiveArrayCritical(env, posArray, NULL);450if (positions == NULL) {451(*env)->DeleteLocalRef(env, posArray);452}453}454if (positions != NULL) {455CGPoint prev;456prev.x = positions[0];457prev.y = positions[1];458459// <rdar://problem/4294061> take the first point, and move the context to that location460CGContextTranslateCTM(qsdo->cgRef, prev.x, prev.y);461462CGAffineTransform invTx = CGAffineTransformInvert(strike->fFontTx);463464// for each position, figure out the advance (since CG won't take positions directly)465size_t i;466for (i = 0; i < length - 1; i++)467{468size_t i2 = (i+1) * 2;469CGPoint pt;470pt.x = positions[i2];471pt.y = positions[i2+1];472pt = CGPointApplyAffineTransform(pt, invTx);473advances[i].width = pt.x - prev.x;474advances[i].height = -(pt.y - prev.y); // negative to translate to device space475prev.x = pt.x;476prev.y = pt.y;477}478479(*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, JNI_ABORT);480(*env)->DeleteLocalRef(env, posArray);481}482else483{484// in this case, we have to go and calculate the positions ourselves485// there were no pre-calculated positions from the glyph buffer on the Java side486AWTFont *awtFont = strike->fAWTFont;487CTFontGetAdvancesForGlyphs((CTFontRef)awtFont->fFont, kCTFontDefaultOrientation, glyphs, advances, length);488489if (complex)490{491JavaCT_GetAdvancesForUnichars(awtFont->fFont, uniChars, glyphs, length, advances);492}493}494495// continue on to the next stage of the pipe496doDrawGlyphsPipe_checkForPerGlyphTransforms(env, qsdo, strike, gVector, complex, uniChars, glyphs, advances, length);497}498499// Obtains the glyph array to determine the number of glyphs we are dealing with. If we are dealing a large number of glyphs,500// we malloc a buffer to hold the glyphs and their advances, otherwise we use stack allocated buffers.501static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc502(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector)503{504static JNF_MEMBER_CACHE(jm_StandardGlyphVector_glyphs, jc_StandardGlyphVector, "glyphs", "[I");505jintArray glyphsArray = JNFGetObjectField(env, gVector, jm_StandardGlyphVector_glyphs);506jsize length = (*env)->GetArrayLength(env, glyphsArray);507508if (length == 0)509{510// nothing to draw511(*env)->DeleteLocalRef(env, glyphsArray);512return;513}514515if (length < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE)516{517// if we are small enough, fit everything onto the stack518CGGlyph glyphs[length];519int uniChars[length];520CGSize advances[length];521doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);522}523else524{525// otherwise, we should malloc and free buffers for this large run526CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * length);527int *uniChars = (int *)malloc(sizeof(int) * length);528CGSize *advances = (CGSize *)malloc(sizeof(CGSize) * length);529530if (glyphs == NULL || uniChars == NULL || advances == NULL)531{532(*env)->DeleteLocalRef(env, glyphsArray);533[NSException raise:NSMallocException format:@"%s-%s:%d", THIS_FILE, __FUNCTION__, __LINE__];534if (glyphs)535{536free(glyphs);537}538if (uniChars)539{540free(uniChars);541}542if (advances)543{544free(advances);545}546return;547}548549doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);550551free(glyphs);552free(uniChars);553free(advances);554}555556(*env)->DeleteLocalRef(env, glyphsArray);557}558559// Setup and save the state of the CGContext, and apply any java.awt.Font transforms to the context.560static inline void doDrawGlyphsPipe_applyFontTransforms561(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, const jfloat x, const jfloat y)562{563CGContextRef cgRef = qsdo->cgRef;564CGContextSetFontSize(cgRef, 1.0);565CGContextSetFont(cgRef, strike->fAWTFont->fNativeCGFont);566CGContextSetTextMatrix(cgRef, CGAffineTransformIdentity);567568CGAffineTransform tx = strike->fFontTx;569tx.tx += x;570tx.ty += y;571CGContextConcatCTM(cgRef, tx);572573doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc(env, qsdo, strike, gVector);574}575576577#pragma mark --- CTextPipe JNI ---578579580/*581* Class: sun_lwawt_macosx_CTextPipe582* Method: doDrawString583* Signature: (Lsun/java2d/SurfaceData;JLjava/lang/String;DD)V584*/585JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doDrawString586(JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jstring str, jdouble x, jdouble y)587{588QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);589AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);590591JNF_COCOA_ENTER(env);592593jsize len = (*env)->GetStringLength(env, str);594595if (len < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE) // optimized for stack allocation <rdar://problem/4285041>596{597jchar unichars[len];598(*env)->GetStringRegion(env, str, 0, len, unichars);599JNF_CHECK_AND_RETHROW_EXCEPTION(env);600601// Draw the text context602DrawTextContext(env, qsdo, awtStrike, unichars, len, x, y);603}604else605{606// Get string to draw and the length607const jchar *unichars = JNFGetStringUTF16UniChars(env, str);608609// Draw the text context610DrawTextContext(env, qsdo, awtStrike, unichars, len, x, y);611612JNFReleaseStringUTF16UniChars(env, str, unichars);613}614615JNF_COCOA_RENDERER_EXIT(env);616}617618619/*620* Class: sun_lwawt_macosx_CTextPipe621* Method: doUnicodes622* Signature: (Lsun/java2d/SurfaceData;J[CIIFF)V623*/624JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doUnicodes625(JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jcharArray unicodes, jint offset, jint length, jfloat x, jfloat y)626{627QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);628AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);629630JNF_COCOA_ENTER(env);631632// Setup the text context633if (length < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE) // optimized for stack allocation634{635jchar copyUnichars[length];636(*env)->GetCharArrayRegion(env, unicodes, offset, length, copyUnichars);637JNF_CHECK_AND_RETHROW_EXCEPTION(env);638DrawTextContext(env, qsdo, awtStrike, copyUnichars, length, x, y);639}640else641{642jchar *copyUnichars = malloc(length * sizeof(jchar));643if (!copyUnichars) {644[JNFException raise:env as:kOutOfMemoryError reason:"Failed to malloc memory to create the glyphs for string drawing"];645}646647@try {648(*env)->GetCharArrayRegion(env, unicodes, offset, length, copyUnichars);649JNF_CHECK_AND_RETHROW_EXCEPTION(env);650DrawTextContext(env, qsdo, awtStrike, copyUnichars, length, x, y);651} @finally {652free(copyUnichars);653}654}655656JNF_COCOA_RENDERER_EXIT(env);657}658659/*660* Class: sun_lwawt_macosx_CTextPipe661* Method: doOneUnicode662* Signature: (Lsun/java2d/SurfaceData;JCFF)V663*/664JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doOneUnicode665(JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jchar aUnicode, jfloat x, jfloat y)666{667QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);668AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);669670JNF_COCOA_ENTER(env);671672DrawTextContext(env, qsdo, awtStrike, &aUnicode, 1, x, y);673674JNF_COCOA_RENDERER_EXIT(env);675}676677/*678* Class: sun_lwawt_macosx_CTextPipe679* Method: doDrawGlyphs680* Signature: (Lsun/java2d/SurfaceData;JLjava/awt/font/GlyphVector;FF)V681*/682JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doDrawGlyphs683(JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jobject gVector, jfloat x, jfloat y)684{685QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);686AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);687688JNF_COCOA_ENTER(env);689690qsdo->BeginSurface(env, qsdo, SD_Text);691if (qsdo->cgRef == NULL)692{693qsdo->FinishSurface(env, qsdo);694return;695}696697CGContextSaveGState(qsdo->cgRef);698JRSFontSetRenderingStyleOnContext(qsdo->cgRef, JRSFontGetRenderingStyleForHints(sun_awt_SunHints_INTVAL_FRACTIONALMETRICS_ON, sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON));699700doDrawGlyphsPipe_applyFontTransforms(env, qsdo, awtStrike, gVector, x, y);701702CGContextRestoreGState(qsdo->cgRef);703704qsdo->FinishSurface(env, qsdo);705706JNF_COCOA_RENDERER_EXIT(env);707}708709710