src/macosx/native/sun/awt/CTextPipe.m

Print this page




 130              gZeroNumber, NSLigatureAttributeName,
 131              gZeroNumber, NSKernAttributeName,
 132              nil];
 133 }
 134 
 135 // Itterates though each glyph, and if a transform is present for that glyph, apply it to the CGContext, and strike the glyph.
 136 // If there is no per-glyph transform, just strike the glyph. Advances must also be transformed on-the-spot as well.
 137 void JavaCT_DrawGlyphVector
 138 (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)
 139 {
 140     CGPoint pt = { 0, 0 };
 141 
 142     // get our baseline transform and font
 143     CGContextRef cgRef = qsdo->cgRef;
 144     CGAffineTransform ctmText = CGContextGetTextMatrix(cgRef);
 145 
 146     BOOL saved = false;
 147 
 148     CGAffineTransform invTx = CGAffineTransformInvert(strike->fTx);
 149 
 150     NSUInteger i;
 151     for (i = 0; i < length; i++)
 152     {
 153         CGGlyph glyph = glyphs[i];
 154         int uniChar = uniChars[i];
 155         // if we found a unichar instead of a glyph code, get the fallback font,
 156         // find the glyph code for the fallback font, and set the font on the current context
 157         if (uniChar != 0)
 158         {
 159             CTFontRef fallback;
 160             if (uniChar > 0xFFFF) {
 161                 UTF16Char charRef[2];
 162                 JavaCT_BreakupUnicodeIntoSurrogatePairs(uniChar, charRef);
 163                 CGGlyph glyphTmp[2];
 164                 fallback = JavaCT_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, (CGGlyph *)&glyphTmp, 2);
 165                 glyph = glyphTmp[0];
 166             } else {
 167                 const UTF16Char u = uniChar;
 168                 fallback = JavaCT_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, &u, (CGGlyph *)&glyph, 1);
 169             }
 170             if (fallback) {


 338     static JNF_MEMBER_CACHE(jm_StandardGlyphVector_gti, jc_StandardGlyphVector, "gti", "Lsun/font/StandardGlyphVector$GlyphTransformInfo;");
 339     jobject gti = JNFGetObjectField(env, gVector, jm_StandardGlyphVector_gti);
 340     if (gti == 0)
 341     {
 342         if (useSubstituion)
 343         {
 344             // quasi-simple case, substitution, but no per-glyph transforms
 345             JavaCT_DrawGlyphVector(qsdo, strike, TRUE, uniChars, glyphs, advances, NULL, NULL, length);
 346         }
 347         else
 348         {
 349             // fast path, straight to CG without per-glyph transforms
 350             CGContextShowGlyphsWithAdvances(qsdo->cgRef, glyphs, advances, length);
 351         }
 352         return;
 353     }
 354 
 355     static JNF_CLASS_CACHE(jc_StandardGlyphVector_GlyphTransformInfo, "sun/font/StandardGlyphVector$GlyphTransformInfo");
 356     static JNF_MEMBER_CACHE(jm_StandardGlyphVector_GlyphTransformInfo_transforms, jc_StandardGlyphVector_GlyphTransformInfo, "transforms", "[D");
 357     jdoubleArray g_gtiTransformsArray = JNFGetObjectField(env, gti, jm_StandardGlyphVector_GlyphTransformInfo_transforms); //(*env)->GetObjectField(env, gti, g_gtiTransforms);



 358     jdouble *g_gvTransformsAsDoubles = (*env)->GetPrimitiveArrayCritical(env, g_gtiTransformsArray, NULL);




 359 
 360     static JNF_MEMBER_CACHE(jm_StandardGlyphVector_GlyphTransformInfo_indices, jc_StandardGlyphVector_GlyphTransformInfo, "indices", "[I");
 361     jintArray g_gtiTXIndicesArray = JNFGetObjectField(env, gti, jm_StandardGlyphVector_GlyphTransformInfo_indices);
 362     jint *g_gvTXIndicesAsInts = (*env)->GetPrimitiveArrayCritical(env, g_gtiTXIndicesArray, NULL);
 363 





 364     // slowest case, we have per-glyph transforms, and possibly glyph substitution as well
 365     JavaCT_DrawGlyphVector(qsdo, strike, useSubstituion, uniChars, glyphs, advances, g_gvTXIndicesAsInts, g_gvTransformsAsDoubles, length);
 366 
 367     (*env)->ReleasePrimitiveArrayCritical(env, g_gtiTransformsArray, g_gvTransformsAsDoubles, JNI_ABORT);
 368     (*env)->DeleteLocalRef(env, g_gtiTransformsArray);
 369 
 370     (*env)->ReleasePrimitiveArrayCritical(env, g_gtiTXIndicesArray, g_gvTXIndicesAsInts, JNI_ABORT);


 371     (*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);
 372 }
 373 
 374 // Retrieves advances for translated unicodes
 375 // Uses "glyphs" as a temporary buffer for the glyph-to-unicode translation
 376 void JavaCT_GetAdvancesForUnichars
 377 (const NSFont *font, const int uniChars[], CGGlyph glyphs[], const size_t length, CGSize advances[])
 378 {
 379     // cycle over each spot, and if we discovered a unicode to substitute, we have to calculate the advance for it
 380     size_t i;
 381     for (i = 0; i < length; i++)
 382     {
 383         UniChar uniChar = uniChars[i];
 384         if (uniChar == 0) continue;
 385 
 386         CGGlyph glyph = 0;
 387         const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font, &uniChar, 1);
 388         if (fallback) {
 389             CTFontGetGlyphsForCharacters(fallback, &uniChar, &glyph, 1);
 390             CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &(advances[i]), 1);
 391             CFRelease(fallback);
 392         }
 393 
 394         glyphs[i] = glyph;
 395     }
 396 }
 397 
 398 // Fills the glyph buffer with glyphs from the GlyphVector object. Also checks to see if the glyph's positions have been
 399 // already caculated from GlyphVector, or we simply ask Core Graphics to make some advances for us. Pre-calculated positions
 400 // are translated into advances, since CG only understands advances.
 401 static inline void doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers
 402 (JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, CGGlyph *glyphs, int *uniChars, CGSize *advances, size_t length, jintArray glyphsArray)
 403 {
 404     // fill the glyph buffer
 405     jint *glyphsAsInts = (*env)->GetPrimitiveArrayCritical(env, glyphsArray, NULL);



 406 
 407     // if a glyph code from Java is negative, that means it is really a unicode value
 408     // which we can use in CoreText to strike the character in another font
 409     size_t i;
 410     BOOL complex = NO;
 411     for (i = 0; i < length; i++)
 412     {
 413         jint code = glyphsAsInts[i];
 414         if (code < 0)
 415         {
 416             complex = YES;
 417             uniChars[i] = -code;
 418             glyphs[i] = 0;
 419         }
 420         else
 421         {
 422             uniChars[i] = 0;
 423             glyphs[i] = code;
 424         }
 425     }
 426 
 427     (*env)->ReleasePrimitiveArrayCritical(env, glyphsArray, glyphsAsInts, JNI_ABORT);
 428 
 429     // fill the advance buffer
 430     static JNF_MEMBER_CACHE(jm_StandardGlyphVector_positions, jc_StandardGlyphVector, "positions", "[F");
 431     jfloatArray posArray = JNFGetObjectField(env, gVector, jm_StandardGlyphVector_positions);
 432     if (posArray != NULL)
 433     {
 434         // in this case, the positions have already been pre-calculated for us on the Java side
 435 
 436         jfloat *positions = (*env)->GetPrimitiveArrayCritical(env, posArray, NULL);




 437         CGPoint prev;
 438         prev.x = positions[0];
 439         prev.y = positions[1];
 440 
 441         // <rdar://problem/4294061> take the first point, and move the context to that location
 442         CGContextTranslateCTM(qsdo->cgRef, prev.x, prev.y);
 443 
 444         CGAffineTransform invTx = CGAffineTransformInvert(strike->fFontTx);
 445 
 446         // for each position, figure out the advance (since CG won't take positions directly)
 447         size_t i;
 448         for (i = 0; i < length - 1; i++)
 449         {
 450             size_t i2 = (i+1) * 2;
 451             CGPoint pt;
 452             pt.x = positions[i2];
 453             pt.y = positions[i2+1];
 454             pt = CGPointApplyAffineTransform(pt, invTx);
 455             advances[i].width = pt.x - prev.x;
 456             advances[i].height = -(pt.y - prev.y); // negative to translate to device space




 130              gZeroNumber, NSLigatureAttributeName,
 131              gZeroNumber, NSKernAttributeName,
 132              nil];
 133 }
 134 
 135 // Itterates though each glyph, and if a transform is present for that glyph, apply it to the CGContext, and strike the glyph.
 136 // If there is no per-glyph transform, just strike the glyph. Advances must also be transformed on-the-spot as well.
 137 void JavaCT_DrawGlyphVector
 138 (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)
 139 {
 140     CGPoint pt = { 0, 0 };
 141 
 142     // get our baseline transform and font
 143     CGContextRef cgRef = qsdo->cgRef;
 144     CGAffineTransform ctmText = CGContextGetTextMatrix(cgRef);
 145 
 146     BOOL saved = false;
 147 
 148     CGAffineTransform invTx = CGAffineTransformInvert(strike->fTx);
 149 
 150     NSInteger i;
 151     for (i = 0; i < length; i++)
 152     {
 153         CGGlyph glyph = glyphs[i];
 154         int uniChar = uniChars[i];
 155         // if we found a unichar instead of a glyph code, get the fallback font,
 156         // find the glyph code for the fallback font, and set the font on the current context
 157         if (uniChar != 0)
 158         {
 159             CTFontRef fallback;
 160             if (uniChar > 0xFFFF) {
 161                 UTF16Char charRef[2];
 162                 JavaCT_BreakupUnicodeIntoSurrogatePairs(uniChar, charRef);
 163                 CGGlyph glyphTmp[2];
 164                 fallback = JavaCT_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, (CGGlyph *)&glyphTmp, 2);
 165                 glyph = glyphTmp[0];
 166             } else {
 167                 const UTF16Char u = uniChar;
 168                 fallback = JavaCT_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, &u, (CGGlyph *)&glyph, 1);
 169             }
 170             if (fallback) {


 338     static JNF_MEMBER_CACHE(jm_StandardGlyphVector_gti, jc_StandardGlyphVector, "gti", "Lsun/font/StandardGlyphVector$GlyphTransformInfo;");
 339     jobject gti = JNFGetObjectField(env, gVector, jm_StandardGlyphVector_gti);
 340     if (gti == 0)
 341     {
 342         if (useSubstituion)
 343         {
 344             // quasi-simple case, substitution, but no per-glyph transforms
 345             JavaCT_DrawGlyphVector(qsdo, strike, TRUE, uniChars, glyphs, advances, NULL, NULL, length);
 346         }
 347         else
 348         {
 349             // fast path, straight to CG without per-glyph transforms
 350             CGContextShowGlyphsWithAdvances(qsdo->cgRef, glyphs, advances, length);
 351         }
 352         return;
 353     }
 354 
 355     static JNF_CLASS_CACHE(jc_StandardGlyphVector_GlyphTransformInfo, "sun/font/StandardGlyphVector$GlyphTransformInfo");
 356     static JNF_MEMBER_CACHE(jm_StandardGlyphVector_GlyphTransformInfo_transforms, jc_StandardGlyphVector_GlyphTransformInfo, "transforms", "[D");
 357     jdoubleArray g_gtiTransformsArray = JNFGetObjectField(env, gti, jm_StandardGlyphVector_GlyphTransformInfo_transforms); //(*env)->GetObjectField(env, gti, g_gtiTransforms);
 358     if (g_gtiTransformsArray == NULL) {
 359         return;
 360     } 
 361     jdouble *g_gvTransformsAsDoubles = (*env)->GetPrimitiveArrayCritical(env, g_gtiTransformsArray, NULL);
 362     if (g_gvTransformsAsDoubles == NULL) {
 363         (*env)->DeleteLocalRef(env, g_gtiTransformsArray);
 364         return;
 365     } 
 366 
 367     static JNF_MEMBER_CACHE(jm_StandardGlyphVector_GlyphTransformInfo_indices, jc_StandardGlyphVector_GlyphTransformInfo, "indices", "[I");
 368     jintArray g_gtiTXIndicesArray = JNFGetObjectField(env, gti, jm_StandardGlyphVector_GlyphTransformInfo_indices);
 369     jint *g_gvTXIndicesAsInts = (*env)->GetPrimitiveArrayCritical(env, g_gtiTXIndicesArray, NULL);
 370     if (g_gvTXIndicesAsInts == NULL) {
 371         (*env)->ReleasePrimitiveArrayCritical(env, g_gtiTransformsArray, g_gvTransformsAsDoubles, JNI_ABORT);
 372         (*env)->DeleteLocalRef(env, g_gtiTransformsArray);
 373         (*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);
 374         return;
 375     }
 376     // slowest case, we have per-glyph transforms, and possibly glyph substitution as well
 377     JavaCT_DrawGlyphVector(qsdo, strike, useSubstituion, uniChars, glyphs, advances, g_gvTXIndicesAsInts, g_gvTransformsAsDoubles, length);
 378 
 379     (*env)->ReleasePrimitiveArrayCritical(env, g_gtiTransformsArray, g_gvTransformsAsDoubles, JNI_ABORT);


 380     (*env)->ReleasePrimitiveArrayCritical(env, g_gtiTXIndicesArray, g_gvTXIndicesAsInts, JNI_ABORT);
 381 
 382     (*env)->DeleteLocalRef(env, g_gtiTransformsArray);
 383     (*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);
 384 }
 385 
 386 // Retrieves advances for translated unicodes
 387 // Uses "glyphs" as a temporary buffer for the glyph-to-unicode translation
 388 void JavaCT_GetAdvancesForUnichars
 389 (const NSFont *font, const int uniChars[], CGGlyph glyphs[], const size_t length, CGSize advances[])
 390 {
 391     // cycle over each spot, and if we discovered a unicode to substitute, we have to calculate the advance for it
 392     size_t i;
 393     for (i = 0; i < length; i++)
 394     {
 395         UniChar uniChar = uniChars[i];
 396         if (uniChar == 0) continue;
 397 
 398         CGGlyph glyph = 0;
 399         const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font, &uniChar, 1);
 400         if (fallback) {
 401             CTFontGetGlyphsForCharacters(fallback, &uniChar, &glyph, 1);
 402             CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &(advances[i]), 1);
 403             CFRelease(fallback);
 404         }
 405 
 406         glyphs[i] = glyph;
 407     }
 408 }
 409 
 410 // Fills the glyph buffer with glyphs from the GlyphVector object. Also checks to see if the glyph's positions have been
 411 // already caculated from GlyphVector, or we simply ask Core Graphics to make some advances for us. Pre-calculated positions
 412 // are translated into advances, since CG only understands advances.
 413 static inline void doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers
 414 (JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, CGGlyph *glyphs, int *uniChars, CGSize *advances, size_t length, jintArray glyphsArray)
 415 {
 416     // fill the glyph buffer
 417     jint *glyphsAsInts = (*env)->GetPrimitiveArrayCritical(env, glyphsArray, NULL);
 418     if (glyphsAsInts == NULL) {
 419         return;
 420     }
 421 
 422     // if a glyph code from Java is negative, that means it is really a unicode value
 423     // which we can use in CoreText to strike the character in another font
 424     size_t i;
 425     BOOL complex = NO;
 426     for (i = 0; i < length; i++)
 427     {
 428         jint code = glyphsAsInts[i];
 429         if (code < 0)
 430         {
 431             complex = YES;
 432             uniChars[i] = -code;
 433             glyphs[i] = 0;
 434         }
 435         else
 436         {
 437             uniChars[i] = 0;
 438             glyphs[i] = code;
 439         }
 440     }
 441 
 442     (*env)->ReleasePrimitiveArrayCritical(env, glyphsArray, glyphsAsInts, JNI_ABORT);
 443 
 444     // fill the advance buffer
 445     static JNF_MEMBER_CACHE(jm_StandardGlyphVector_positions, jc_StandardGlyphVector, "positions", "[F");
 446     jfloatArray posArray = JNFGetObjectField(env, gVector, jm_StandardGlyphVector_positions);
 447     jfloat *positions = NULL;
 448     if (posArray != NULL) {
 449         // in this case, the positions have already been pre-calculated for us on the Java side
 450         positions = (*env)->GetPrimitiveArrayCritical(env, posArray, NULL);
 451         if (positions == NULL) {
 452             (*env)->DeleteLocalRef(env, posArray);
 453         }
 454     }
 455     if (positions != NULL) {
 456         CGPoint prev;
 457         prev.x = positions[0];
 458         prev.y = positions[1];
 459 
 460         // <rdar://problem/4294061> take the first point, and move the context to that location
 461         CGContextTranslateCTM(qsdo->cgRef, prev.x, prev.y);
 462 
 463         CGAffineTransform invTx = CGAffineTransformInvert(strike->fFontTx);
 464 
 465         // for each position, figure out the advance (since CG won't take positions directly)
 466         size_t i;
 467         for (i = 0; i < length - 1; i++)
 468         {
 469             size_t i2 = (i+1) * 2;
 470             CGPoint pt;
 471             pt.x = positions[i2];
 472             pt.y = positions[i2+1];
 473             pt = CGPointApplyAffineTransform(pt, invTx);
 474             advances[i].width = pt.x - prev.x;
 475             advances[i].height = -(pt.y - prev.y); // negative to translate to device space