Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/native_NOTIOS/sun/awt/CTextPipe.m
38829 views
1
/*
2
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
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
/* Use THIS_FILE when it is available. */
40
#ifndef THIS_FILE
41
#define THIS_FILE __FILE__
42
#endif
43
44
static const CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 };
45
46
47
#pragma mark --- CoreText Support ---
48
49
50
// Translates a Unicode into a CGGlyph/CTFontRef pair
51
// Returns the substituted font, and places the appropriate glyph into "glyphRef"
52
CTFontRef JavaCT_CopyCTFallbackFontAndGlyphForUnicode
53
(const AWTFont *font, const UTF16Char *charRef, CGGlyph *glyphRef, int count) {
54
CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, charRef, count);
55
if (fallback == NULL)
56
{
57
// use the original font if we somehow got duped into trying to fallback something we can't
58
fallback = (CTFontRef)font->fFont;
59
CFRetain(fallback);
60
}
61
62
CTFontGetGlyphsForCharacters(fallback, charRef, glyphRef, count);
63
return fallback;
64
}
65
66
// Translates a Java glyph code int (might be a negative unicode value) into a CGGlyph/CTFontRef pair
67
// Returns the substituted font, and places the appropriate glyph into "glyph"
68
CTFontRef JavaCT_CopyCTFallbackFontAndGlyphForJavaGlyphCode
69
(const AWTFont *font, const jint glyphCode, CGGlyph *glyphRef)
70
{
71
// negative glyph codes are really unicodes, which were placed there by the mapper
72
// to indicate we should use CoreText to substitute the character
73
if (glyphCode >= 0)
74
{
75
*glyphRef = glyphCode;
76
CFRetain(font->fFont);
77
return (CTFontRef)font->fFont;
78
}
79
80
UTF16Char character = -glyphCode;
81
return JavaCT_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
82
}
83
84
// Breakup a 32 bit unicode value into the component surrogate pairs
85
void JavaCT_BreakupUnicodeIntoSurrogatePairs(int uniChar, UTF16Char charRef[]) {
86
int value = uniChar - 0x10000;
87
UTF16Char low_surrogate = (value & 0x3FF) | LO_SURROGATE_START;
88
UTF16Char high_surrogate = (((int)(value & 0xFFC00)) >> 10) | HI_SURROGATE_START;
89
charRef[0] = high_surrogate;
90
charRef[1] = low_surrogate;
91
}
92
93
94
95
/*
96
* Callback for CoreText which uses the CoreTextProviderStruct to feed CT UniChars
97
* We only use it for one-off lines, and don't attempt to fragment our strings
98
*/
99
const UniChar *Java_CTProvider
100
(CFIndex stringIndex, CFIndex *charCount, CFDictionaryRef *attributes, void *refCon)
101
{
102
// if we have a zero length string we can just return NULL for the string
103
// or if the index anything other than 0 we are not using core text
104
// correctly since we only have one run.
105
if (stringIndex != 0)
106
{
107
return NULL;
108
}
109
110
CTS_ProviderStruct *ctps = (CTS_ProviderStruct *)refCon;
111
*charCount = ctps->length;
112
*attributes = ctps->attributes;
113
return ctps->unicodes;
114
}
115
116
117
/*
118
* Gets a Dictionary filled with common details we want to use for CoreText when we are interacting
119
* with it from Java.
120
*/
121
static NSDictionary* ctsDictionaryFor(const NSFont *font, BOOL useFractionalMetrics)
122
{
123
NSNumber *gZeroNumber = [NSNumber numberWithInt:0];
124
NSNumber *gOneNumber = [NSNumber numberWithInt:1];
125
126
return [NSDictionary dictionaryWithObjectsAndKeys:
127
font, NSFontAttributeName,
128
gOneNumber, (id)kCTForegroundColorFromContextAttributeName,
129
useFractionalMetrics ? gZeroNumber : gOneNumber, @"CTIntegerMetrics", // force integer hack in CoreText to help with Java's integer assumptions
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) {
171
const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
172
CFRelease(fallback);
173
174
if (cgFallback) {
175
if (!saved) {
176
CGContextSaveGState(cgRef);
177
saved = true;
178
}
179
CGContextSetFont(cgRef, cgFallback);
180
CFRelease(cgFallback);
181
}
182
}
183
} else {
184
if (saved) {
185
CGContextRestoreGState(cgRef);
186
saved = false;
187
}
188
}
189
190
// if we have per-glyph transformations
191
int tin = (g_gvTXIndicesAsInts == NULL) ? -1 : (g_gvTXIndicesAsInts[i] - 1) * 6;
192
if (tin < 0)
193
{
194
CGContextShowGlyphsAtPoint(cgRef, pt.x, pt.y, &glyph, 1);
195
}
196
else
197
{
198
CGAffineTransform tx = CGAffineTransformMake(
199
(CGFloat)g_gvTransformsAsDoubles[tin + 0], (CGFloat)g_gvTransformsAsDoubles[tin + 2],
200
(CGFloat)g_gvTransformsAsDoubles[tin + 1], (CGFloat)g_gvTransformsAsDoubles[tin + 3],
201
0, 0);
202
203
CGPoint txOffset = { (CGFloat)g_gvTransformsAsDoubles[tin + 4], (CGFloat)g_gvTransformsAsDoubles[tin + 5] };
204
205
txOffset = CGPointApplyAffineTransform(txOffset, invTx);
206
207
// apply the transform, strike the glyph, can change the transform back
208
CGContextSetTextMatrix(cgRef, CGAffineTransformConcat(ctmText, tx));
209
CGContextShowGlyphsAtPoint(cgRef, txOffset.x + pt.x, txOffset.y + pt.y, &glyph, 1);
210
CGContextSetTextMatrix(cgRef, ctmText);
211
212
// transform the measured advance for this strike
213
advances[i] = CGSizeApplyAffineTransform(advances[i], tx);
214
advances[i].width += txOffset.x;
215
advances[i].height += txOffset.y;
216
}
217
218
// move our next x,y
219
pt.x += advances[i].width;
220
pt.y += advances[i].height;
221
222
}
223
// reset the font on the context after striking a unicode with CoreText
224
if (saved) {
225
CGContextRestoreGState(cgRef);
226
}
227
}
228
229
// Using the Quartz Surface Data context, draw a hot-substituted character run
230
void JavaCT_DrawTextUsingQSD(JNIEnv *env, const QuartzSDOps *qsdo, const AWTStrike *strike, const jchar *chars, const jsize length)
231
{
232
CGContextRef cgRef = qsdo->cgRef;
233
234
AWTFont *awtFont = strike->fAWTFont;
235
CGFloat ptSize = strike->fSize;
236
CGAffineTransform tx = strike->fFontTx;
237
238
NSFont *nsFont = [NSFont fontWithName:[awtFont->fFont fontName] size:ptSize];
239
240
if (ptSize != 0) {
241
CGFloat invScale = 1 / ptSize;
242
tx = CGAffineTransformConcat(tx, CGAffineTransformMakeScale(invScale, invScale));
243
CGContextConcatCTM(cgRef, tx);
244
}
245
246
CGContextSetTextMatrix(cgRef, CGAffineTransformIdentity); // resets the damage from CoreText
247
248
NSString *string = [NSString stringWithCharacters:chars length:length];
249
/*
250
The calls below were used previously but for unknown reason did not
251
render using the right font (see bug 7183516) when attribString is not
252
initialized with font dictionary attributes. It seems that "options"
253
in CTTypesetterCreateWithAttributedStringAndOptions which contains the
254
font dictionary is ignored.
255
256
NSAttributedString *attribString = [[NSAttributedString alloc] initWithString:string];
257
258
CTTypesetterRef typeSetterRef = CTTypesetterCreateWithAttributedStringAndOptions((CFAttributedStringRef) attribString, (CFDictionaryRef) ctsDictionaryFor(nsFont, JRSFontStyleUsesFractionalMetrics(strike->fStyle)));
259
*/
260
NSAttributedString *attribString = [[NSAttributedString alloc]
261
initWithString:string
262
attributes:ctsDictionaryFor(nsFont, JRSFontStyleUsesFractionalMetrics(strike->fStyle))];
263
264
CTTypesetterRef typeSetterRef = CTTypesetterCreateWithAttributedString((CFAttributedStringRef) attribString);
265
266
CFRange range = {0, length};
267
CTLineRef lineRef = CTTypesetterCreateLine(typeSetterRef, range);
268
269
CTLineDraw(lineRef, cgRef);
270
271
[attribString release];
272
CFRelease(lineRef);
273
CFRelease(typeSetterRef);
274
}
275
276
277
/*----------------------
278
DrawTextContext is the funnel for all of our CoreText drawing.
279
All three JNI apis call through this method.
280
----------------------*/
281
static void DrawTextContext
282
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, const jchar *chars, const jsize length, const jdouble x, const jdouble y)
283
{
284
if (length == 0)
285
{
286
return;
287
}
288
289
qsdo->BeginSurface(env, qsdo, SD_Text);
290
if (qsdo->cgRef == NULL)
291
{
292
qsdo->FinishSurface(env, qsdo);
293
return;
294
}
295
296
CGContextRef cgRef = qsdo->cgRef;
297
298
299
CGContextSaveGState(cgRef);
300
JRSFontSetRenderingStyleOnContext(cgRef, strike->fStyle);
301
302
// we want to translate before we transform (scale or rotate) <rdar://4042541> (vm)
303
CGContextTranslateCTM(cgRef, x, y);
304
305
AWTFont *awtfont = strike->fAWTFont; //(AWTFont *)(qsdo->fontInfo.awtfont);
306
NSCharacterSet *charSet = [awtfont->fFont coveredCharacterSet];
307
308
JavaCT_DrawTextUsingQSD(env, qsdo, strike, chars, length); // Draw with CoreText
309
310
CGContextRestoreGState(cgRef);
311
312
qsdo->FinishSurface(env, qsdo);
313
}
314
315
#pragma mark --- Glyph Vector Pipeline ---
316
317
/*-----------------------------------
318
Glyph Vector Pipeline
319
320
doDrawGlyphs() has been separated into several pipelined functions to increase performance,
321
and improve accountability for JNI resources, malloc'd memory, and error handling.
322
323
Each stage of the pipeline is responsible for doing only one major thing, like allocating buffers,
324
aquiring transform arrays from JNI, filling buffers, or striking glyphs. All resources or memory
325
acquired at a given stage, must be released in that stage. Any error that occurs (like a failed malloc)
326
is to be handled in the stage it occurs in, and is to return immediatly after freeing it's resources.
327
328
-----------------------------------*/
329
330
static JNF_CLASS_CACHE(jc_StandardGlyphVector, "sun/font/StandardGlyphVector");
331
332
// Checks the GlyphVector Java object for any transforms that were applied to individual characters. If none are present,
333
// strike the glyphs immediately in Core Graphics. Otherwise, obtain the arrays, and defer to above.
334
static inline void doDrawGlyphsPipe_checkForPerGlyphTransforms
335
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, BOOL useSubstituion, int *uniChars, CGGlyph *glyphs, CGSize *advances, size_t length)
336
{
337
// if we have no character substitution, and no per-glyph transformations - strike now!
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
476
prev.x = pt.x;
477
prev.y = pt.y;
478
}
479
480
(*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, JNI_ABORT);
481
(*env)->DeleteLocalRef(env, posArray);
482
}
483
else
484
{
485
// in this case, we have to go and calculate the positions ourselves
486
// there were no pre-calculated positions from the glyph buffer on the Java side
487
AWTFont *awtFont = strike->fAWTFont;
488
CTFontGetAdvancesForGlyphs((CTFontRef)awtFont->fFont, kCTFontDefaultOrientation, glyphs, advances, length);
489
490
if (complex)
491
{
492
JavaCT_GetAdvancesForUnichars(awtFont->fFont, uniChars, glyphs, length, advances);
493
}
494
}
495
496
// continue on to the next stage of the pipe
497
doDrawGlyphsPipe_checkForPerGlyphTransforms(env, qsdo, strike, gVector, complex, uniChars, glyphs, advances, length);
498
}
499
500
// Obtains the glyph array to determine the number of glyphs we are dealing with. If we are dealing a large number of glyphs,
501
// we malloc a buffer to hold the glyphs and their advances, otherwise we use stack allocated buffers.
502
static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc
503
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector)
504
{
505
static JNF_MEMBER_CACHE(jm_StandardGlyphVector_glyphs, jc_StandardGlyphVector, "glyphs", "[I");
506
jintArray glyphsArray = JNFGetObjectField(env, gVector, jm_StandardGlyphVector_glyphs);
507
jsize length = (*env)->GetArrayLength(env, glyphsArray);
508
509
if (length == 0)
510
{
511
// nothing to draw
512
(*env)->DeleteLocalRef(env, glyphsArray);
513
return;
514
}
515
516
if (length < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE)
517
{
518
// if we are small enough, fit everything onto the stack
519
CGGlyph glyphs[length];
520
int uniChars[length];
521
CGSize advances[length];
522
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
523
}
524
else
525
{
526
// otherwise, we should malloc and free buffers for this large run
527
CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * length);
528
int *uniChars = (int *)malloc(sizeof(int) * length);
529
CGSize *advances = (CGSize *)malloc(sizeof(CGSize) * length);
530
531
if (glyphs == NULL || uniChars == NULL || advances == NULL)
532
{
533
(*env)->DeleteLocalRef(env, glyphsArray);
534
[NSException raise:NSMallocException format:@"%s-%s:%d", THIS_FILE, __FUNCTION__, __LINE__];
535
if (glyphs)
536
{
537
free(glyphs);
538
}
539
if (uniChars)
540
{
541
free(uniChars);
542
}
543
if (advances)
544
{
545
free(advances);
546
}
547
return;
548
}
549
550
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
551
552
free(glyphs);
553
free(uniChars);
554
free(advances);
555
}
556
557
(*env)->DeleteLocalRef(env, glyphsArray);
558
}
559
560
// Setup and save the state of the CGContext, and apply any java.awt.Font transforms to the context.
561
static inline void doDrawGlyphsPipe_applyFontTransforms
562
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, const jfloat x, const jfloat y)
563
{
564
CGContextRef cgRef = qsdo->cgRef;
565
CGContextSetFontSize(cgRef, 1.0);
566
CGContextSetFont(cgRef, strike->fAWTFont->fNativeCGFont);
567
CGContextSetTextMatrix(cgRef, CGAffineTransformIdentity);
568
569
CGAffineTransform tx = strike->fFontTx;
570
tx.tx += x;
571
tx.ty += y;
572
CGContextConcatCTM(cgRef, tx);
573
574
doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc(env, qsdo, strike, gVector);
575
}
576
577
578
#pragma mark --- CTextPipe JNI ---
579
580
581
/*
582
* Class: sun_lwawt_macosx_CTextPipe
583
* Method: doDrawString
584
* Signature: (Lsun/java2d/SurfaceData;JLjava/lang/String;DD)V
585
*/
586
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doDrawString
587
(JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jstring str, jdouble x, jdouble y)
588
{
589
QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
590
AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
591
592
JNF_COCOA_ENTER(env);
593
594
jsize len = (*env)->GetStringLength(env, str);
595
596
if (len < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE) // optimized for stack allocation <rdar://problem/4285041>
597
{
598
jchar unichars[len];
599
(*env)->GetStringRegion(env, str, 0, len, unichars);
600
JNF_CHECK_AND_RETHROW_EXCEPTION(env);
601
602
// Draw the text context
603
DrawTextContext(env, qsdo, awtStrike, unichars, len, x, y);
604
}
605
else
606
{
607
// Get string to draw and the length
608
const jchar *unichars = JNFGetStringUTF16UniChars(env, str);
609
610
// Draw the text context
611
DrawTextContext(env, qsdo, awtStrike, unichars, len, x, y);
612
613
JNFReleaseStringUTF16UniChars(env, str, unichars);
614
}
615
616
JNF_COCOA_RENDERER_EXIT(env);
617
}
618
619
620
/*
621
* Class: sun_lwawt_macosx_CTextPipe
622
* Method: doUnicodes
623
* Signature: (Lsun/java2d/SurfaceData;J[CIIFF)V
624
*/
625
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doUnicodes
626
(JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jcharArray unicodes, jint offset, jint length, jfloat x, jfloat y)
627
{
628
QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
629
AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
630
631
JNF_COCOA_ENTER(env);
632
633
// Setup the text context
634
if (length < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE) // optimized for stack allocation
635
{
636
jchar copyUnichars[length];
637
(*env)->GetCharArrayRegion(env, unicodes, offset, length, copyUnichars);
638
JNF_CHECK_AND_RETHROW_EXCEPTION(env);
639
DrawTextContext(env, qsdo, awtStrike, copyUnichars, length, x, y);
640
}
641
else
642
{
643
jchar *copyUnichars = malloc(length * sizeof(jchar));
644
if (!copyUnichars) {
645
[JNFException raise:env as:kOutOfMemoryError reason:"Failed to malloc memory to create the glyphs for string drawing"];
646
}
647
648
@try {
649
(*env)->GetCharArrayRegion(env, unicodes, offset, length, copyUnichars);
650
JNF_CHECK_AND_RETHROW_EXCEPTION(env);
651
DrawTextContext(env, qsdo, awtStrike, copyUnichars, length, x, y);
652
} @finally {
653
free(copyUnichars);
654
}
655
}
656
657
JNF_COCOA_RENDERER_EXIT(env);
658
}
659
660
/*
661
* Class: sun_lwawt_macosx_CTextPipe
662
* Method: doOneUnicode
663
* Signature: (Lsun/java2d/SurfaceData;JCFF)V
664
*/
665
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doOneUnicode
666
(JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jchar aUnicode, jfloat x, jfloat y)
667
{
668
QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
669
AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
670
671
JNF_COCOA_ENTER(env);
672
673
DrawTextContext(env, qsdo, awtStrike, &aUnicode, 1, x, y);
674
675
JNF_COCOA_RENDERER_EXIT(env);
676
}
677
678
/*
679
* Class: sun_lwawt_macosx_CTextPipe
680
* Method: doDrawGlyphs
681
* Signature: (Lsun/java2d/SurfaceData;JLjava/awt/font/GlyphVector;FF)V
682
*/
683
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doDrawGlyphs
684
(JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jobject gVector, jfloat x, jfloat y)
685
{
686
QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
687
AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
688
689
JNF_COCOA_ENTER(env);
690
691
qsdo->BeginSurface(env, qsdo, SD_Text);
692
if (qsdo->cgRef == NULL)
693
{
694
qsdo->FinishSurface(env, qsdo);
695
return;
696
}
697
698
CGContextSaveGState(qsdo->cgRef);
699
JRSFontSetRenderingStyleOnContext(qsdo->cgRef, JRSFontGetRenderingStyleForHints(sun_awt_SunHints_INTVAL_FRACTIONALMETRICS_ON, sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON));
700
701
doDrawGlyphsPipe_applyFontTransforms(env, qsdo, awtStrike, gVector, x, y);
702
703
CGContextRestoreGState(qsdo->cgRef);
704
705
qsdo->FinishSurface(env, qsdo);
706
707
JNF_COCOA_RENDERER_EXIT(env);
708
}
709
710