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
|