13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 // Native side of the Quartz text pipe, paints on Quartz Surface Datas.
27 // Interesting Docs : /Developer/Documentation/Cocoa/TasksAndConcepts/ProgrammingTopics/FontHandling/FontHandling.html
28
29 #import "sun_awt_SunHints.h"
30 #import "sun_lwawt_macosx_CTextPipe.h"
31 #import "sun_java2d_OSXSurfaceData.h"
32
33 #import <JavaNativeFoundation/JavaNativeFoundation.h>
34
35 #import "CoreTextSupport.h"
36 #import "QuartzSurfaceData.h"
37 #include "AWTStrike.h"
38
39 static const CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 };
40
41
42 #pragma mark --- CoreText Support ---
43
44
45 // Translates a Unicode into a CGGlyph/CTFontRef pair
46 // Returns the substituted font, and places the appropriate glyph into "glyphRef"
47 CTFontRef JavaCT_CopyCTFallbackFontAndGlyphForUnicode
48 (const AWTFont *font, const UTF16Char *charRef, CGGlyph *glyphRef, int count) {
49 CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, charRef, count);
50 if (fallback == NULL)
51 {
52 // use the original font if we somehow got duped into trying to fallback something we can't
53 fallback = (CTFontRef)font->fFont;
54 CFRetain(fallback);
55 }
56
57 CTFontGetGlyphsForCharacters(fallback, charRef, glyphRef, count);
305 CGContextRestoreGState(cgRef);
306
307 qsdo->FinishSurface(env, qsdo);
308 }
309
310 #pragma mark --- Glyph Vector Pipeline ---
311
312 /*-----------------------------------
313 Glyph Vector Pipeline
314
315 doDrawGlyphs() has been separated into several pipelined functions to increase performance,
316 and improve accountability for JNI resources, malloc'd memory, and error handling.
317
318 Each stage of the pipeline is responsible for doing only one major thing, like allocating buffers,
319 aquiring transform arrays from JNI, filling buffers, or striking glyphs. All resources or memory
320 acquired at a given stage, must be released in that stage. Any error that occurs (like a failed malloc)
321 is to be handled in the stage it occurs in, and is to return immediatly after freeing it's resources.
322
323 -----------------------------------*/
324
325 static JNF_CLASS_CACHE(jc_StandardGlyphVector, "sun/font/StandardGlyphVector");
326
327 // Checks the GlyphVector Java object for any transforms that were applied to individual characters. If none are present,
328 // strike the glyphs immediately in Core Graphics. Otherwise, obtain the arrays, and defer to above.
329 static inline void doDrawGlyphsPipe_checkForPerGlyphTransforms
330 (JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, BOOL useSubstituion, int *uniChars, CGGlyph *glyphs, CGSize *advances, size_t length)
331 {
332 // if we have no character substitution, and no per-glyph transformations - strike now!
333 static JNF_MEMBER_CACHE(jm_StandardGlyphVector_gti, jc_StandardGlyphVector, "gti", "Lsun/font/StandardGlyphVector$GlyphTransformInfo;");
334 jobject gti = JNFGetObjectField(env, gVector, jm_StandardGlyphVector_gti);
335 if (gti == 0)
336 {
337 if (useSubstituion)
338 {
339 // quasi-simple case, substitution, but no per-glyph transforms
340 JavaCT_DrawGlyphVector(qsdo, strike, TRUE, uniChars, glyphs, advances, NULL, NULL, length);
341 }
342 else
343 {
344 // fast path, straight to CG without per-glyph transforms
345 CGContextShowGlyphsWithAdvances(qsdo->cgRef, glyphs, advances, length);
346 }
347 return;
348 }
349
350 static JNF_CLASS_CACHE(jc_StandardGlyphVector_GlyphTransformInfo, "sun/font/StandardGlyphVector$GlyphTransformInfo");
351 static JNF_MEMBER_CACHE(jm_StandardGlyphVector_GlyphTransformInfo_transforms, jc_StandardGlyphVector_GlyphTransformInfo, "transforms", "[D");
352 jdoubleArray g_gtiTransformsArray = JNFGetObjectField(env, gti, jm_StandardGlyphVector_GlyphTransformInfo_transforms); //(*env)->GetObjectField(env, gti, g_gtiTransforms);
353 if (g_gtiTransformsArray == NULL) {
354 return;
355 }
356 jdouble *g_gvTransformsAsDoubles = (*env)->GetPrimitiveArrayCritical(env, g_gtiTransformsArray, NULL);
357 if (g_gvTransformsAsDoubles == NULL) {
358 (*env)->DeleteLocalRef(env, g_gtiTransformsArray);
359 return;
360 }
361
362 static JNF_MEMBER_CACHE(jm_StandardGlyphVector_GlyphTransformInfo_indices, jc_StandardGlyphVector_GlyphTransformInfo, "indices", "[I");
363 jintArray g_gtiTXIndicesArray = JNFGetObjectField(env, gti, jm_StandardGlyphVector_GlyphTransformInfo_indices);
364 jint *g_gvTXIndicesAsInts = (*env)->GetPrimitiveArrayCritical(env, g_gtiTXIndicesArray, NULL);
365 if (g_gvTXIndicesAsInts == NULL) {
366 (*env)->ReleasePrimitiveArrayCritical(env, g_gtiTransformsArray, g_gvTransformsAsDoubles, JNI_ABORT);
367 (*env)->DeleteLocalRef(env, g_gtiTransformsArray);
368 (*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);
369 return;
370 }
371 // slowest case, we have per-glyph transforms, and possibly glyph substitution as well
372 JavaCT_DrawGlyphVector(qsdo, strike, useSubstituion, uniChars, glyphs, advances, g_gvTXIndicesAsInts, g_gvTransformsAsDoubles, length);
373
374 (*env)->ReleasePrimitiveArrayCritical(env, g_gtiTransformsArray, g_gvTransformsAsDoubles, JNI_ABORT);
375 (*env)->ReleasePrimitiveArrayCritical(env, g_gtiTXIndicesArray, g_gvTXIndicesAsInts, JNI_ABORT);
376
377 (*env)->DeleteLocalRef(env, g_gtiTransformsArray);
378 (*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);
379 }
380
381 // Retrieves advances for translated unicodes
382 // Uses "glyphs" as a temporary buffer for the glyph-to-unicode translation
383 void JavaCT_GetAdvancesForUnichars
420 BOOL complex = NO;
421 for (i = 0; i < length; i++)
422 {
423 jint code = glyphsAsInts[i];
424 if (code < 0)
425 {
426 complex = YES;
427 uniChars[i] = -code;
428 glyphs[i] = 0;
429 }
430 else
431 {
432 uniChars[i] = 0;
433 glyphs[i] = code;
434 }
435 }
436
437 (*env)->ReleasePrimitiveArrayCritical(env, glyphsArray, glyphsAsInts, JNI_ABORT);
438
439 // fill the advance buffer
440 static JNF_MEMBER_CACHE(jm_StandardGlyphVector_positions, jc_StandardGlyphVector, "positions", "[F");
441 jfloatArray posArray = JNFGetObjectField(env, gVector, jm_StandardGlyphVector_positions);
442 jfloat *positions = NULL;
443 if (posArray != NULL) {
444 // in this case, the positions have already been pre-calculated for us on the Java side
445 positions = (*env)->GetPrimitiveArrayCritical(env, posArray, NULL);
446 if (positions == NULL) {
447 (*env)->DeleteLocalRef(env, posArray);
448 }
449 }
450 if (positions != NULL) {
451 CGPoint prev;
452 prev.x = positions[0];
453 prev.y = positions[1];
454
455 // <rdar://problem/4294061> take the first point, and move the context to that location
456 CGContextTranslateCTM(qsdo->cgRef, prev.x, prev.y);
457
458 CGAffineTransform invTx = CGAffineTransformInvert(strike->fFontTx);
459
460 // for each position, figure out the advance (since CG won't take positions directly)
461 size_t i;
480 // in this case, we have to go and calculate the positions ourselves
481 // there were no pre-calculated positions from the glyph buffer on the Java side
482 AWTFont *awtFont = strike->fAWTFont;
483 CTFontGetAdvancesForGlyphs((CTFontRef)awtFont->fFont, kCTFontDefaultOrientation, glyphs, advances, length);
484
485 if (complex)
486 {
487 JavaCT_GetAdvancesForUnichars(awtFont->fFont, uniChars, glyphs, length, advances);
488 }
489 }
490
491 // continue on to the next stage of the pipe
492 doDrawGlyphsPipe_checkForPerGlyphTransforms(env, qsdo, strike, gVector, complex, uniChars, glyphs, advances, length);
493 }
494
495 // Obtains the glyph array to determine the number of glyphs we are dealing with. If we are dealing a large number of glyphs,
496 // we malloc a buffer to hold the glyphs and their advances, otherwise we use stack allocated buffers.
497 static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc
498 (JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector)
499 {
500 static JNF_MEMBER_CACHE(jm_StandardGlyphVector_glyphs, jc_StandardGlyphVector, "glyphs", "[I");
501 jintArray glyphsArray = JNFGetObjectField(env, gVector, jm_StandardGlyphVector_glyphs);
502 jsize length = (*env)->GetArrayLength(env, glyphsArray);
503
504 if (length == 0)
505 {
506 // nothing to draw
507 (*env)->DeleteLocalRef(env, glyphsArray);
508 return;
509 }
510
511 if (length < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE)
512 {
513 // if we are small enough, fit everything onto the stack
514 CGGlyph glyphs[length];
515 int uniChars[length];
516 CGSize advances[length];
517 doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
518 }
519 else
520 {
521 // otherwise, we should malloc and free buffers for this large run
564 CGAffineTransform tx = strike->fFontTx;
565 tx.tx += x;
566 tx.ty += y;
567 CGContextConcatCTM(cgRef, tx);
568
569 doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc(env, qsdo, strike, gVector);
570 }
571
572
573 #pragma mark --- CTextPipe JNI ---
574
575
576 /*
577 * Class: sun_lwawt_macosx_CTextPipe
578 * Method: doDrawString
579 * Signature: (Lsun/java2d/SurfaceData;JLjava/lang/String;DD)V
580 */
581 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doDrawString
582 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jstring str, jdouble x, jdouble y)
583 {
584 QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
585 AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
586
587 JNF_COCOA_ENTER(env);
588
589 jsize len = (*env)->GetStringLength(env, str);
590
591 if (len < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE) // optimized for stack allocation <rdar://problem/4285041>
592 {
593 jchar unichars[len];
594 (*env)->GetStringRegion(env, str, 0, len, unichars);
595 JNF_CHECK_AND_RETHROW_EXCEPTION(env);
596
597 // Draw the text context
598 DrawTextContext(env, qsdo, awtStrike, unichars, len, x, y);
599 }
600 else
601 {
602 // Get string to draw and the length
603 const jchar *unichars = JNFGetStringUTF16UniChars(env, str);
604
605 // Draw the text context
606 DrawTextContext(env, qsdo, awtStrike, unichars, len, x, y);
607
608 JNFReleaseStringUTF16UniChars(env, str, unichars);
609 }
610
611 JNF_COCOA_RENDERER_EXIT(env);
612 }
613
614
615 /*
616 * Class: sun_lwawt_macosx_CTextPipe
617 * Method: doUnicodes
618 * Signature: (Lsun/java2d/SurfaceData;J[CIIFF)V
619 */
620 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doUnicodes
621 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jcharArray unicodes, jint offset, jint length, jfloat x, jfloat y)
622 {
623 QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
624 AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
625
626 JNF_COCOA_ENTER(env);
627
628 // Setup the text context
629 if (length < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE) // optimized for stack allocation
630 {
631 jchar copyUnichars[length];
632 (*env)->GetCharArrayRegion(env, unicodes, offset, length, copyUnichars);
633 JNF_CHECK_AND_RETHROW_EXCEPTION(env);
634 DrawTextContext(env, qsdo, awtStrike, copyUnichars, length, x, y);
635 }
636 else
637 {
638 jchar *copyUnichars = malloc(length * sizeof(jchar));
639 if (!copyUnichars) {
640 [JNFException raise:env as:kOutOfMemoryError reason:"Failed to malloc memory to create the glyphs for string drawing"];
641 }
642
643 @try {
644 (*env)->GetCharArrayRegion(env, unicodes, offset, length, copyUnichars);
645 JNF_CHECK_AND_RETHROW_EXCEPTION(env);
646 DrawTextContext(env, qsdo, awtStrike, copyUnichars, length, x, y);
647 } @finally {
648 free(copyUnichars);
649 }
650 }
651
652 JNF_COCOA_RENDERER_EXIT(env);
653 }
654
655 /*
656 * Class: sun_lwawt_macosx_CTextPipe
657 * Method: doOneUnicode
658 * Signature: (Lsun/java2d/SurfaceData;JCFF)V
659 */
660 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doOneUnicode
661 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jchar aUnicode, jfloat x, jfloat y)
662 {
663 QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
664 AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
665
666 JNF_COCOA_ENTER(env);
667
668 DrawTextContext(env, qsdo, awtStrike, &aUnicode, 1, x, y);
669
670 JNF_COCOA_RENDERER_EXIT(env);
671 }
672
673 /*
674 * Class: sun_lwawt_macosx_CTextPipe
675 * Method: doDrawGlyphs
676 * Signature: (Lsun/java2d/SurfaceData;JLjava/awt/font/GlyphVector;FF)V
677 */
678 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doDrawGlyphs
679 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jobject gVector, jfloat x, jfloat y)
680 {
681 QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
682 AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
683
684 JNF_COCOA_ENTER(env);
685
686 qsdo->BeginSurface(env, qsdo, SD_Text);
687 if (qsdo->cgRef == NULL)
688 {
689 qsdo->FinishSurface(env, qsdo);
690 return;
691 }
692
693 CGContextSaveGState(qsdo->cgRef);
694 JRSFontSetRenderingStyleOnContext(qsdo->cgRef, JRSFontGetRenderingStyleForHints(sun_awt_SunHints_INTVAL_FRACTIONALMETRICS_ON, sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON));
695
696 doDrawGlyphsPipe_applyFontTransforms(env, qsdo, awtStrike, gVector, x, y);
697
698 CGContextRestoreGState(qsdo->cgRef);
699
700 qsdo->FinishSurface(env, qsdo);
701
702 JNF_COCOA_RENDERER_EXIT(env);
703 }
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 // Native side of the Quartz text pipe, paints on Quartz Surface Datas.
27 // Interesting Docs : /Developer/Documentation/Cocoa/TasksAndConcepts/ProgrammingTopics/FontHandling/FontHandling.html
28
29 #import "sun_awt_SunHints.h"
30 #import "sun_lwawt_macosx_CTextPipe.h"
31 #import "sun_java2d_OSXSurfaceData.h"
32
33 #import "CoreTextSupport.h"
34 #import "QuartzSurfaceData.h"
35 #include "AWTStrike.h"
36 #import "JNIUtilities.h"
37
38 static const CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 };
39
40
41 #pragma mark --- CoreText Support ---
42
43
44 // Translates a Unicode into a CGGlyph/CTFontRef pair
45 // Returns the substituted font, and places the appropriate glyph into "glyphRef"
46 CTFontRef JavaCT_CopyCTFallbackFontAndGlyphForUnicode
47 (const AWTFont *font, const UTF16Char *charRef, CGGlyph *glyphRef, int count) {
48 CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, charRef, count);
49 if (fallback == NULL)
50 {
51 // use the original font if we somehow got duped into trying to fallback something we can't
52 fallback = (CTFontRef)font->fFont;
53 CFRetain(fallback);
54 }
55
56 CTFontGetGlyphsForCharacters(fallback, charRef, glyphRef, count);
304 CGContextRestoreGState(cgRef);
305
306 qsdo->FinishSurface(env, qsdo);
307 }
308
309 #pragma mark --- Glyph Vector Pipeline ---
310
311 /*-----------------------------------
312 Glyph Vector Pipeline
313
314 doDrawGlyphs() has been separated into several pipelined functions to increase performance,
315 and improve accountability for JNI resources, malloc'd memory, and error handling.
316
317 Each stage of the pipeline is responsible for doing only one major thing, like allocating buffers,
318 aquiring transform arrays from JNI, filling buffers, or striking glyphs. All resources or memory
319 acquired at a given stage, must be released in that stage. Any error that occurs (like a failed malloc)
320 is to be handled in the stage it occurs in, and is to return immediatly after freeing it's resources.
321
322 -----------------------------------*/
323
324 static jclass jc_StandardGlyphVector = NULL;
325 #define GET_SGV_CLASS() GET_CLASS(jc_StandardGlyphVector, "sun/font/StandardGlyphVector");
326
327 // Checks the GlyphVector Java object for any transforms that were applied to individual characters. If none are present,
328 // strike the glyphs immediately in Core Graphics. Otherwise, obtain the arrays, and defer to above.
329 static inline void doDrawGlyphsPipe_checkForPerGlyphTransforms
330 (JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, BOOL useSubstituion, int *uniChars, CGGlyph *glyphs, CGSize *advances, size_t length)
331 {
332 // if we have no character substitution, and no per-glyph transformations - strike now!
333 GET_SGV_CLASS();
334 DECLARE_FIELD(jm_StandardGlyphVector_gti, jc_StandardGlyphVector, "gti", "Lsun/font/StandardGlyphVector$GlyphTransformInfo;");
335 jobject gti = (*env)->GetObjectField(env, gVector, jm_StandardGlyphVector_gti);
336 if (gti == 0)
337 {
338 if (useSubstituion)
339 {
340 // quasi-simple case, substitution, but no per-glyph transforms
341 JavaCT_DrawGlyphVector(qsdo, strike, TRUE, uniChars, glyphs, advances, NULL, NULL, length);
342 }
343 else
344 {
345 // fast path, straight to CG without per-glyph transforms
346 CGContextShowGlyphsWithAdvances(qsdo->cgRef, glyphs, advances, length);
347 }
348 return;
349 }
350
351 DECLARE_CLASS(jc_StandardGlyphVector_GlyphTransformInfo, "sun/font/StandardGlyphVector$GlyphTransformInfo");
352 DECLARE_FIELD(jm_StandardGlyphVector_GlyphTransformInfo_transforms, jc_StandardGlyphVector_GlyphTransformInfo, "transforms", "[D");
353 jdoubleArray g_gtiTransformsArray = (*env)->GetObjectField(env, gti, jm_StandardGlyphVector_GlyphTransformInfo_transforms); //(*env)->GetObjectField(env, gti, g_gtiTransforms);
354 if (g_gtiTransformsArray == NULL) {
355 return;
356 }
357 jdouble *g_gvTransformsAsDoubles = (*env)->GetPrimitiveArrayCritical(env, g_gtiTransformsArray, NULL);
358 if (g_gvTransformsAsDoubles == NULL) {
359 (*env)->DeleteLocalRef(env, g_gtiTransformsArray);
360 return;
361 }
362
363 DECLARE_FIELD(jm_StandardGlyphVector_GlyphTransformInfo_indices, jc_StandardGlyphVector_GlyphTransformInfo, "indices", "[I");
364 jintArray g_gtiTXIndicesArray = (*env)->GetObjectField(env, gti, jm_StandardGlyphVector_GlyphTransformInfo_indices);
365 jint *g_gvTXIndicesAsInts = (*env)->GetPrimitiveArrayCritical(env, g_gtiTXIndicesArray, NULL);
366 if (g_gvTXIndicesAsInts == NULL) {
367 (*env)->ReleasePrimitiveArrayCritical(env, g_gtiTransformsArray, g_gvTransformsAsDoubles, JNI_ABORT);
368 (*env)->DeleteLocalRef(env, g_gtiTransformsArray);
369 (*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);
370 return;
371 }
372 // slowest case, we have per-glyph transforms, and possibly glyph substitution as well
373 JavaCT_DrawGlyphVector(qsdo, strike, useSubstituion, uniChars, glyphs, advances, g_gvTXIndicesAsInts, g_gvTransformsAsDoubles, length);
374
375 (*env)->ReleasePrimitiveArrayCritical(env, g_gtiTransformsArray, g_gvTransformsAsDoubles, JNI_ABORT);
376 (*env)->ReleasePrimitiveArrayCritical(env, g_gtiTXIndicesArray, g_gvTXIndicesAsInts, JNI_ABORT);
377
378 (*env)->DeleteLocalRef(env, g_gtiTransformsArray);
379 (*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);
380 }
381
382 // Retrieves advances for translated unicodes
383 // Uses "glyphs" as a temporary buffer for the glyph-to-unicode translation
384 void JavaCT_GetAdvancesForUnichars
421 BOOL complex = NO;
422 for (i = 0; i < length; i++)
423 {
424 jint code = glyphsAsInts[i];
425 if (code < 0)
426 {
427 complex = YES;
428 uniChars[i] = -code;
429 glyphs[i] = 0;
430 }
431 else
432 {
433 uniChars[i] = 0;
434 glyphs[i] = code;
435 }
436 }
437
438 (*env)->ReleasePrimitiveArrayCritical(env, glyphsArray, glyphsAsInts, JNI_ABORT);
439
440 // fill the advance buffer
441 GET_SGV_CLASS();
442 DECLARE_FIELD(jm_StandardGlyphVector_positions, jc_StandardGlyphVector, "positions", "[F");
443 jfloatArray posArray = (*env)->GetObjectField(env, gVector, jm_StandardGlyphVector_positions);
444 jfloat *positions = NULL;
445 if (posArray != NULL) {
446 // in this case, the positions have already been pre-calculated for us on the Java side
447 positions = (*env)->GetPrimitiveArrayCritical(env, posArray, NULL);
448 if (positions == NULL) {
449 (*env)->DeleteLocalRef(env, posArray);
450 }
451 }
452 if (positions != NULL) {
453 CGPoint prev;
454 prev.x = positions[0];
455 prev.y = positions[1];
456
457 // <rdar://problem/4294061> take the first point, and move the context to that location
458 CGContextTranslateCTM(qsdo->cgRef, prev.x, prev.y);
459
460 CGAffineTransform invTx = CGAffineTransformInvert(strike->fFontTx);
461
462 // for each position, figure out the advance (since CG won't take positions directly)
463 size_t i;
482 // in this case, we have to go and calculate the positions ourselves
483 // there were no pre-calculated positions from the glyph buffer on the Java side
484 AWTFont *awtFont = strike->fAWTFont;
485 CTFontGetAdvancesForGlyphs((CTFontRef)awtFont->fFont, kCTFontDefaultOrientation, glyphs, advances, length);
486
487 if (complex)
488 {
489 JavaCT_GetAdvancesForUnichars(awtFont->fFont, uniChars, glyphs, length, advances);
490 }
491 }
492
493 // continue on to the next stage of the pipe
494 doDrawGlyphsPipe_checkForPerGlyphTransforms(env, qsdo, strike, gVector, complex, uniChars, glyphs, advances, length);
495 }
496
497 // Obtains the glyph array to determine the number of glyphs we are dealing with. If we are dealing a large number of glyphs,
498 // we malloc a buffer to hold the glyphs and their advances, otherwise we use stack allocated buffers.
499 static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc
500 (JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector)
501 {
502 GET_SGV_CLASS();
503 DECLARE_FIELD(jm_StandardGlyphVector_glyphs, jc_StandardGlyphVector, "glyphs", "[I");
504 jintArray glyphsArray = (*env)->GetObjectField(env, gVector, jm_StandardGlyphVector_glyphs);
505 jsize length = (*env)->GetArrayLength(env, glyphsArray);
506
507 if (length == 0)
508 {
509 // nothing to draw
510 (*env)->DeleteLocalRef(env, glyphsArray);
511 return;
512 }
513
514 if (length < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE)
515 {
516 // if we are small enough, fit everything onto the stack
517 CGGlyph glyphs[length];
518 int uniChars[length];
519 CGSize advances[length];
520 doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
521 }
522 else
523 {
524 // otherwise, we should malloc and free buffers for this large run
567 CGAffineTransform tx = strike->fFontTx;
568 tx.tx += x;
569 tx.ty += y;
570 CGContextConcatCTM(cgRef, tx);
571
572 doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc(env, qsdo, strike, gVector);
573 }
574
575
576 #pragma mark --- CTextPipe JNI ---
577
578
579 /*
580 * Class: sun_lwawt_macosx_CTextPipe
581 * Method: doDrawString
582 * Signature: (Lsun/java2d/SurfaceData;JLjava/lang/String;DD)V
583 */
584 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doDrawString
585 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jstring str, jdouble x, jdouble y)
586 {
587 if (str == NULL) {
588 return;
589 }
590 QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
591 AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
592
593 JNI_COCOA_ENTER(env);
594
595 jsize len = (*env)->GetStringLength(env, str);
596
597 if (len < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE) // optimized for stack allocation <rdar://problem/4285041>
598 {
599 jchar unichars[len];
600 (*env)->GetStringRegion(env, str, 0, len, unichars);
601 CHECK_EXCEPTION();
602
603 // Draw the text context
604 DrawTextContext(env, qsdo, awtStrike, unichars, len, x, y);
605 }
606 else
607 {
608 // Get string to draw and the length
609 const jchar *unichars = (*env)->GetStringChars(env, str, NULL);
610 if (unichars == NULL) {
611 JNU_ThrowOutOfMemoryError(env, "Could not get string chars");
612 return;
613 }
614
615 // Draw the text context
616 DrawTextContext(env, qsdo, awtStrike, unichars, len, x, y);
617
618 (*env)->ReleaseStringChars(env, str, unichars);
619 }
620
621 JNI_COCOA_RENDERER_EXIT(env);
622 }
623
624
625 /*
626 * Class: sun_lwawt_macosx_CTextPipe
627 * Method: doUnicodes
628 * Signature: (Lsun/java2d/SurfaceData;J[CIIFF)V
629 */
630 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doUnicodes
631 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jcharArray unicodes, jint offset, jint length, jfloat x, jfloat y)
632 {
633 QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
634 AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
635
636 JNI_COCOA_ENTER(env);
637
638 // Setup the text context
639 if (length < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE) // optimized for stack allocation
640 {
641 jchar copyUnichars[length];
642 (*env)->GetCharArrayRegion(env, unicodes, offset, length, copyUnichars);
643 CHECK_EXCEPTION();
644 DrawTextContext(env, qsdo, awtStrike, copyUnichars, length, x, y);
645 }
646 else
647 {
648 jchar *copyUnichars = malloc(length * sizeof(jchar));
649 if (!copyUnichars) {
650 JNU_ThrowOutOfMemoryError(env, "Failed to malloc memory to create the glyphs for string drawing");
651 return;
652 }
653
654 @try {
655 (*env)->GetCharArrayRegion(env, unicodes, offset, length, copyUnichars);
656 CHECK_EXCEPTION();
657 DrawTextContext(env, qsdo, awtStrike, copyUnichars, length, x, y);
658 } @finally {
659 free(copyUnichars);
660 }
661 }
662
663 JNI_COCOA_RENDERER_EXIT(env);
664 }
665
666 /*
667 * Class: sun_lwawt_macosx_CTextPipe
668 * Method: doOneUnicode
669 * Signature: (Lsun/java2d/SurfaceData;JCFF)V
670 */
671 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doOneUnicode
672 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jchar aUnicode, jfloat x, jfloat y)
673 {
674 QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
675 AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
676
677 JNI_COCOA_ENTER(env);
678
679 DrawTextContext(env, qsdo, awtStrike, &aUnicode, 1, x, y);
680
681 JNI_COCOA_RENDERER_EXIT(env);
682 }
683
684 /*
685 * Class: sun_lwawt_macosx_CTextPipe
686 * Method: doDrawGlyphs
687 * Signature: (Lsun/java2d/SurfaceData;JLjava/awt/font/GlyphVector;FF)V
688 */
689 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doDrawGlyphs
690 (JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jobject gVector, jfloat x, jfloat y)
691 {
692 QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
693 AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
694
695 JNI_COCOA_ENTER(env);
696
697 qsdo->BeginSurface(env, qsdo, SD_Text);
698 if (qsdo->cgRef == NULL)
699 {
700 qsdo->FinishSurface(env, qsdo);
701 return;
702 }
703
704 CGContextSaveGState(qsdo->cgRef);
705 JRSFontSetRenderingStyleOnContext(qsdo->cgRef, JRSFontGetRenderingStyleForHints(sun_awt_SunHints_INTVAL_FRACTIONALMETRICS_ON, sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON));
706
707 doDrawGlyphsPipe_applyFontTransforms(env, qsdo, awtStrike, gVector, x, y);
708
709 CGContextRestoreGState(qsdo->cgRef);
710
711 qsdo->FinishSurface(env, qsdo);
712
713 JNI_COCOA_RENDERER_EXIT(env);
714 }
|