Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/macosx/native/libawt_lwawt/awt/CTextPipe.m
41152 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 "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);
57
return fallback;
58
}
59
60
// Translates a Java glyph code int (might be a negative unicode value) into a CGGlyph/CTFontRef pair
61
// Returns the substituted font, and places the appropriate glyph into "glyph"
62
CTFontRef JavaCT_CopyCTFallbackFontAndGlyphForJavaGlyphCode
63
(const AWTFont *font, const jint glyphCode, CGGlyph *glyphRef)
64
{
65
// negative glyph codes are really unicodes, which were placed there by the mapper
66
// to indicate we should use CoreText to substitute the character
67
if (glyphCode >= 0)
68
{
69
*glyphRef = glyphCode;
70
CFRetain(font->fFont);
71
return (CTFontRef)font->fFont;
72
}
73
74
UTF16Char character = -glyphCode;
75
return JavaCT_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
76
}
77
78
// Breakup a 32 bit unicode value into the component surrogate pairs
79
void JavaCT_BreakupUnicodeIntoSurrogatePairs(int uniChar, UTF16Char charRef[]) {
80
int value = uniChar - 0x10000;
81
UTF16Char low_surrogate = (value & 0x3FF) | LO_SURROGATE_START;
82
UTF16Char high_surrogate = (((int)(value & 0xFFC00)) >> 10) | HI_SURROGATE_START;
83
charRef[0] = high_surrogate;
84
charRef[1] = low_surrogate;
85
}
86
87
88
89
/*
90
* Callback for CoreText which uses the CoreTextProviderStruct to feed CT UniChars
91
* We only use it for one-off lines, and don't attempt to fragment our strings
92
*/
93
const UniChar *Java_CTProvider
94
(CFIndex stringIndex, CFIndex *charCount, CFDictionaryRef *attributes, void *refCon)
95
{
96
// if we have a zero length string we can just return NULL for the string
97
// or if the index anything other than 0 we are not using core text
98
// correctly since we only have one run.
99
if (stringIndex != 0)
100
{
101
return NULL;
102
}
103
104
CTS_ProviderStruct *ctps = (CTS_ProviderStruct *)refCon;
105
*charCount = ctps->length;
106
*attributes = ctps->attributes;
107
return ctps->unicodes;
108
}
109
110
111
/*
112
* Gets a Dictionary filled with common details we want to use for CoreText when we are interacting
113
* with it from Java.
114
*/
115
static NSDictionary* ctsDictionaryFor(const NSFont *font, BOOL useFractionalMetrics)
116
{
117
NSNumber *gZeroNumber = [NSNumber numberWithInt:0];
118
NSNumber *gOneNumber = [NSNumber numberWithInt:1];
119
120
return [NSDictionary dictionaryWithObjectsAndKeys:
121
font, NSFontAttributeName,
122
gOneNumber, (id)kCTForegroundColorFromContextAttributeName,
123
useFractionalMetrics ? gZeroNumber : gOneNumber, @"CTIntegerMetrics", // force integer hack in CoreText to help with Java's integer assumptions
124
gZeroNumber, NSLigatureAttributeName,
125
gZeroNumber, NSKernAttributeName,
126
nil];
127
}
128
129
// Itterates though each glyph, and if a transform is present for that glyph, apply it to the CGContext, and strike the glyph.
130
// If there is no per-glyph transform, just strike the glyph. Advances must also be transformed on-the-spot as well.
131
void JavaCT_DrawGlyphVector
132
(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)
133
{
134
CGPoint pt = { 0, 0 };
135
136
// get our baseline transform and font
137
CGContextRef cgRef = qsdo->cgRef;
138
CGAffineTransform ctmText = CGContextGetTextMatrix(cgRef);
139
140
BOOL saved = false;
141
142
CGAffineTransform invTx = CGAffineTransformInvert(strike->fTx);
143
144
NSInteger i;
145
for (i = 0; i < length; i++)
146
{
147
CGGlyph glyph = glyphs[i];
148
int uniChar = uniChars[i];
149
// if we found a unichar instead of a glyph code, get the fallback font,
150
// find the glyph code for the fallback font, and set the font on the current context
151
if (uniChar != 0)
152
{
153
CTFontRef fallback;
154
if (uniChar > 0xFFFF) {
155
UTF16Char charRef[2];
156
JavaCT_BreakupUnicodeIntoSurrogatePairs(uniChar, charRef);
157
CGGlyph glyphTmp[2];
158
fallback = JavaCT_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, (CGGlyph *)&glyphTmp, 2);
159
glyph = glyphTmp[0];
160
} else {
161
const UTF16Char u = uniChar;
162
fallback = JavaCT_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, &u, (CGGlyph *)&glyph, 1);
163
}
164
if (fallback) {
165
const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
166
CFRelease(fallback);
167
168
if (cgFallback) {
169
if (!saved) {
170
CGContextSaveGState(cgRef);
171
saved = true;
172
}
173
CGContextSetFont(cgRef, cgFallback);
174
CFRelease(cgFallback);
175
}
176
}
177
} else {
178
if (saved) {
179
CGContextRestoreGState(cgRef);
180
saved = false;
181
}
182
}
183
184
// if we have per-glyph transformations
185
int tin = (g_gvTXIndicesAsInts == NULL) ? -1 : (g_gvTXIndicesAsInts[i] - 1) * 6;
186
if (tin < 0)
187
{
188
CGContextShowGlyphsAtPoint(cgRef, pt.x, pt.y, &glyph, 1);
189
}
190
else
191
{
192
CGAffineTransform tx = CGAffineTransformMake(
193
(CGFloat)g_gvTransformsAsDoubles[tin + 0], (CGFloat)g_gvTransformsAsDoubles[tin + 2],
194
(CGFloat)g_gvTransformsAsDoubles[tin + 1], (CGFloat)g_gvTransformsAsDoubles[tin + 3],
195
0, 0);
196
197
CGPoint txOffset = { (CGFloat)g_gvTransformsAsDoubles[tin + 4], (CGFloat)g_gvTransformsAsDoubles[tin + 5] };
198
199
txOffset = CGPointApplyAffineTransform(txOffset, invTx);
200
201
// apply the transform, strike the glyph, can change the transform back
202
CGContextSetTextMatrix(cgRef, CGAffineTransformConcat(ctmText, tx));
203
CGContextShowGlyphsAtPoint(cgRef, txOffset.x + pt.x, txOffset.y + pt.y, &glyph, 1);
204
CGContextSetTextMatrix(cgRef, ctmText);
205
206
// transform the measured advance for this strike
207
advances[i] = CGSizeApplyAffineTransform(advances[i], tx);
208
advances[i].width += txOffset.x;
209
advances[i].height += txOffset.y;
210
}
211
212
// move our next x,y
213
pt.x += advances[i].width;
214
pt.y += advances[i].height;
215
216
}
217
// reset the font on the context after striking a unicode with CoreText
218
if (saved) {
219
CGContextRestoreGState(cgRef);
220
}
221
}
222
223
// Using the Quartz Surface Data context, draw a hot-substituted character run
224
void JavaCT_DrawTextUsingQSD(JNIEnv *env, const QuartzSDOps *qsdo, const AWTStrike *strike, const jchar *chars, const jsize length)
225
{
226
CGContextRef cgRef = qsdo->cgRef;
227
228
AWTFont *awtFont = strike->fAWTFont;
229
CGFloat ptSize = strike->fSize;
230
CGAffineTransform tx = strike->fFontTx;
231
232
NSFont *nsFont = [NSFont fontWithName:[awtFont->fFont fontName] size:ptSize];
233
234
if (ptSize != 0) {
235
CGFloat invScale = 1 / ptSize;
236
tx = CGAffineTransformConcat(tx, CGAffineTransformMakeScale(invScale, invScale));
237
CGContextConcatCTM(cgRef, tx);
238
}
239
240
CGContextSetTextMatrix(cgRef, CGAffineTransformIdentity); // resets the damage from CoreText
241
242
NSString *string = [NSString stringWithCharacters:chars length:length];
243
/*
244
The calls below were used previously but for unknown reason did not
245
render using the right font (see bug 7183516) when attribString is not
246
initialized with font dictionary attributes. It seems that "options"
247
in CTTypesetterCreateWithAttributedStringAndOptions which contains the
248
font dictionary is ignored.
249
250
NSAttributedString *attribString = [[NSAttributedString alloc] initWithString:string];
251
252
CTTypesetterRef typeSetterRef = CTTypesetterCreateWithAttributedStringAndOptions((CFAttributedStringRef) attribString, (CFDictionaryRef) ctsDictionaryFor(nsFont, JRSFontStyleUsesFractionalMetrics(strike->fStyle)));
253
*/
254
NSAttributedString *attribString = [[NSAttributedString alloc]
255
initWithString:string
256
attributes:ctsDictionaryFor(nsFont, JRSFontStyleUsesFractionalMetrics(strike->fStyle))];
257
258
CTTypesetterRef typeSetterRef = CTTypesetterCreateWithAttributedString((CFAttributedStringRef) attribString);
259
260
CFRange range = {0, length};
261
CTLineRef lineRef = CTTypesetterCreateLine(typeSetterRef, range);
262
263
CTLineDraw(lineRef, cgRef);
264
265
[attribString release];
266
CFRelease(lineRef);
267
CFRelease(typeSetterRef);
268
}
269
270
271
/*----------------------
272
DrawTextContext is the funnel for all of our CoreText drawing.
273
All three JNI apis call through this method.
274
----------------------*/
275
static void DrawTextContext
276
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, const jchar *chars, const jsize length, const jdouble x, const jdouble y)
277
{
278
if (length == 0)
279
{
280
return;
281
}
282
283
qsdo->BeginSurface(env, qsdo, SD_Text);
284
if (qsdo->cgRef == NULL)
285
{
286
qsdo->FinishSurface(env, qsdo);
287
return;
288
}
289
290
CGContextRef cgRef = qsdo->cgRef;
291
292
293
CGContextSaveGState(cgRef);
294
JRSFontSetRenderingStyleOnContext(cgRef, strike->fStyle);
295
296
// we want to translate before we transform (scale or rotate) <rdar://4042541> (vm)
297
CGContextTranslateCTM(cgRef, x, y);
298
299
AWTFont *awtfont = strike->fAWTFont; //(AWTFont *)(qsdo->fontInfo.awtfont);
300
NSCharacterSet *charSet = [awtfont->fFont coveredCharacterSet];
301
302
JavaCT_DrawTextUsingQSD(env, qsdo, strike, chars, length); // Draw with CoreText
303
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
385
(const NSFont *font, const int uniChars[], CGGlyph glyphs[], const size_t length, CGSize advances[])
386
{
387
// cycle over each spot, and if we discovered a unicode to substitute, we have to calculate the advance for it
388
size_t i;
389
for (i = 0; i < length; i++)
390
{
391
UniChar uniChar = uniChars[i];
392
if (uniChar == 0) continue;
393
394
CGGlyph glyph = 0;
395
const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font, &uniChar, 1);
396
if (fallback) {
397
CTFontGetGlyphsForCharacters(fallback, &uniChar, &glyph, 1);
398
CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &(advances[i]), 1);
399
CFRelease(fallback);
400
}
401
402
glyphs[i] = glyph;
403
}
404
}
405
406
// Fills the glyph buffer with glyphs from the GlyphVector object. Also checks to see if the glyph's positions have been
407
// already caculated from GlyphVector, or we simply ask Core Graphics to make some advances for us. Pre-calculated positions
408
// are translated into advances, since CG only understands advances.
409
static inline void doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers
410
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, CGGlyph *glyphs, int *uniChars, CGSize *advances, size_t length, jintArray glyphsArray)
411
{
412
// fill the glyph buffer
413
jint *glyphsAsInts = (*env)->GetPrimitiveArrayCritical(env, glyphsArray, NULL);
414
if (glyphsAsInts == NULL) {
415
return;
416
}
417
418
// if a glyph code from Java is negative, that means it is really a unicode value
419
// which we can use in CoreText to strike the character in another font
420
size_t i;
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;
464
for (i = 0; i < length - 1; i++)
465
{
466
size_t i2 = (i+1) * 2;
467
CGPoint pt;
468
pt.x = positions[i2];
469
pt.y = positions[i2+1];
470
pt = CGPointApplyAffineTransform(pt, invTx);
471
advances[i].width = pt.x - prev.x;
472
advances[i].height = -(pt.y - prev.y); // negative to translate to device space
473
prev.x = pt.x;
474
prev.y = pt.y;
475
}
476
477
(*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, JNI_ABORT);
478
(*env)->DeleteLocalRef(env, posArray);
479
}
480
else
481
{
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
525
CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * length);
526
int *uniChars = (int *)malloc(sizeof(int) * length);
527
CGSize *advances = (CGSize *)malloc(sizeof(CGSize) * length);
528
529
if (glyphs == NULL || uniChars == NULL || advances == NULL)
530
{
531
(*env)->DeleteLocalRef(env, glyphsArray);
532
[NSException raise:NSMallocException format:@"%s-%s:%d", __FILE__, __FUNCTION__, __LINE__];
533
if (glyphs)
534
{
535
free(glyphs);
536
}
537
if (uniChars)
538
{
539
free(uniChars);
540
}
541
if (advances)
542
{
543
free(advances);
544
}
545
return;
546
}
547
548
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
549
550
free(glyphs);
551
free(uniChars);
552
free(advances);
553
}
554
555
(*env)->DeleteLocalRef(env, glyphsArray);
556
}
557
558
// Setup and save the state of the CGContext, and apply any java.awt.Font transforms to the context.
559
static inline void doDrawGlyphsPipe_applyFontTransforms
560
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, const jfloat x, const jfloat y)
561
{
562
CGContextRef cgRef = qsdo->cgRef;
563
CGContextSetFontSize(cgRef, 1.0);
564
CGContextSetFont(cgRef, strike->fAWTFont->fNativeCGFont);
565
CGContextSetTextMatrix(cgRef, CGAffineTransformIdentity);
566
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
}
715
716