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/classes/sun/font/CStrike.java
38827 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
package sun.font;
27
28
import java.awt.Rectangle;
29
import java.awt.geom.*;
30
import java.util.*;
31
32
import sun.awt.SunHints;
33
34
public final class CStrike extends PhysicalStrike {
35
36
// Creates the native strike
37
private static native long createNativeStrikePtr(long nativeFontPtr,
38
double[] glyphTx,
39
double[] invDevTxMatrix,
40
int aaHint,
41
int fmHint);
42
43
// Disposes the native strike
44
private static native void disposeNativeStrikePtr(long nativeStrikePtr);
45
46
// Creates a StrikeMetrics from the underlying native system fonts
47
private static native StrikeMetrics getFontMetrics(long nativeStrikePtr);
48
49
// Returns native struct pointers used by the Sun 2D Renderer
50
private static native void getGlyphImagePtrsNative(long nativeStrikePtr,
51
long[] glyphInfos,
52
int[] uniCodes, int len);
53
54
// Returns the advance give a glyph code. It should be used only
55
// when the glyph code belongs to the CFont passed in.
56
private static native float getNativeGlyphAdvance(long nativeStrikePtr,
57
int glyphCode);
58
59
// Returns the outline shape of a glyph
60
private static native GeneralPath getNativeGlyphOutline(long nativeStrikePtr,
61
int glyphCode,
62
double x,
63
double y);
64
65
// returns the bounding rect for a glyph
66
private static native void getNativeGlyphImageBounds(long nativeStrikePtr,
67
int glyphCode,
68
Rectangle2D.Float result,
69
double x, double y);
70
71
private final CFont nativeFont;
72
private AffineTransform invDevTx;
73
private final GlyphInfoCache glyphInfoCache;
74
private final GlyphAdvanceCache glyphAdvanceCache;
75
private long nativeStrikePtr;
76
77
CStrike(final CFont font, final FontStrikeDesc inDesc) {
78
nativeFont = font;
79
desc = inDesc;
80
glyphInfoCache = new GlyphInfoCache(font, desc);
81
glyphAdvanceCache = new GlyphAdvanceCache();
82
disposer = glyphInfoCache;
83
84
// Normally the device transform should be the identity transform
85
// for screen operations. The device transform only becomes
86
// interesting when we are outputting between different dpi surfaces,
87
// like when we are printing to postscript or use retina.
88
if (inDesc.devTx != null && !inDesc.devTx.isIdentity()) {
89
try {
90
invDevTx = inDesc.devTx.createInverse();
91
} catch (NoninvertibleTransformException ignored) {
92
// ignored, since device transforms should not be that
93
// complicated, and if they are - there is nothing we can do,
94
// so we won't worry about it.
95
}
96
}
97
}
98
99
public long getNativeStrikePtr() {
100
if (nativeStrikePtr != 0) {
101
return nativeStrikePtr;
102
}
103
104
final double[] glyphTx = new double[6];
105
desc.glyphTx.getMatrix(glyphTx);
106
107
final double[] invDevTxMatrix = new double[6];
108
if (invDevTx == null) {
109
invDevTxMatrix[0] = 1;
110
invDevTxMatrix[3] = 1;
111
} else {
112
invDevTx.getMatrix(invDevTxMatrix);
113
}
114
115
final int aaHint = desc.aaHint;
116
final int fmHint = desc.fmHint;
117
118
synchronized (this) {
119
if (nativeStrikePtr != 0) {
120
return nativeStrikePtr;
121
}
122
nativeStrikePtr =
123
createNativeStrikePtr(nativeFont.getNativeFontPtr(),
124
glyphTx, invDevTxMatrix, aaHint, fmHint);
125
}
126
127
return nativeStrikePtr;
128
}
129
130
protected synchronized void finalize() throws Throwable {
131
if (nativeStrikePtr != 0) {
132
disposeNativeStrikePtr(nativeStrikePtr);
133
}
134
nativeStrikePtr = 0;
135
}
136
137
138
@Override
139
public int getNumGlyphs() {
140
return nativeFont.getNumGlyphs();
141
}
142
143
@Override
144
StrikeMetrics getFontMetrics() {
145
if (strikeMetrics == null) {
146
StrikeMetrics metrics = getFontMetrics(getNativeStrikePtr());
147
if (invDevTx != null) {
148
metrics.convertToUserSpace(invDevTx);
149
}
150
metrics.convertToUserSpace(desc.glyphTx);
151
strikeMetrics = metrics;
152
}
153
return strikeMetrics;
154
}
155
156
@Override
157
float getGlyphAdvance(final int glyphCode) {
158
return getCachedNativeGlyphAdvance(glyphCode);
159
}
160
161
@Override
162
float getCodePointAdvance(final int cp) {
163
return getGlyphAdvance(nativeFont.getMapper().charToGlyph(cp));
164
}
165
166
@Override
167
Point2D.Float getCharMetrics(final char ch) {
168
return getGlyphMetrics(nativeFont.getMapper().charToGlyph(ch));
169
}
170
171
@Override
172
Point2D.Float getGlyphMetrics(final int glyphCode) {
173
return new Point2D.Float(getGlyphAdvance(glyphCode), 0.0f);
174
}
175
176
Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) {
177
GeneralPath gp = getGlyphOutline(glyphCode, 0f, 0f);
178
Rectangle2D r2d = gp.getBounds2D();
179
Rectangle2D.Float r2df;
180
if (r2d instanceof Rectangle2D.Float) {
181
r2df = (Rectangle2D.Float)r2d;
182
} else {
183
float x = (float)r2d.getX();
184
float y = (float)r2d.getY();
185
float w = (float)r2d.getWidth();
186
float h = (float)r2d.getHeight();
187
r2df = new Rectangle2D.Float(x, y, w, h);
188
}
189
return r2df;
190
}
191
192
// pt, result in device space
193
void getGlyphImageBounds(int glyphCode, Point2D.Float pt, Rectangle result) {
194
Rectangle2D.Float floatRect = new Rectangle2D.Float();
195
196
if (invDevTx != null) {
197
invDevTx.transform(pt, pt);
198
}
199
200
getGlyphImageBounds(glyphCode, pt.x, pt.y, floatRect);
201
202
if (floatRect.width == 0 && floatRect.height == 0) {
203
result.setRect(0, 0, -1, -1);
204
return;
205
}
206
207
result.setRect(floatRect.x + pt.x, floatRect.y + pt.y, floatRect.width, floatRect.height);
208
}
209
210
private void getGlyphImageBounds(int glyphCode, float x, float y, Rectangle2D.Float floatRect) {
211
getNativeGlyphImageBounds(getNativeStrikePtr(), glyphCode, floatRect, x, y);
212
}
213
214
GeneralPath getGlyphOutline(int glyphCode, float x, float y) {
215
return getNativeGlyphOutline(getNativeStrikePtr(), glyphCode, x, y);
216
}
217
218
// should implement, however not called though any path that is publicly exposed
219
GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) {
220
throw new Error("not implemented yet");
221
}
222
223
// called from the Sun2D renderer
224
long getGlyphImagePtr(int glyphCode) {
225
synchronized (glyphInfoCache) {
226
long ptr = glyphInfoCache.get(glyphCode);
227
if (ptr != 0L) return ptr;
228
229
long[] ptrs = new long[1];
230
int[] codes = new int[1];
231
codes[0] = glyphCode;
232
233
getGlyphImagePtrs(codes, ptrs, 1);
234
235
ptr = ptrs[0];
236
glyphInfoCache.put(glyphCode, ptr);
237
238
return ptr;
239
}
240
}
241
242
// called from the Sun2D renderer
243
void getGlyphImagePtrs(int[] glyphCodes, long[] images, int len) {
244
synchronized (glyphInfoCache) {
245
// fill the image pointer array with existing pointers
246
// from the cache
247
int missed = 0;
248
for (int i = 0; i < len; i++) {
249
int code = glyphCodes[i];
250
251
final long ptr = glyphInfoCache.get(code);
252
if (ptr != 0L) {
253
images[i] = ptr;
254
} else {
255
// zero this element out, because the caller does not
256
// promise to keep it clean
257
images[i] = 0L;
258
missed++;
259
}
260
}
261
262
if (missed == 0) {
263
return; // horray! we got away without touching native!
264
}
265
266
// all distinct glyph codes requested (partially filled)
267
final int[] filteredCodes = new int[missed];
268
// indices into filteredCodes array (totally filled)
269
final int[] filteredIndicies = new int[missed];
270
271
// scan, mark, and store the requested glyph codes again to
272
// send into native
273
int j = 0;
274
int dupes = 0;
275
for (int i = 0; i < len; i++) {
276
if (images[i] != 0L) continue; // already filled
277
278
final int code = glyphCodes[i];
279
280
// we have already promised to strike this glyph - this is
281
// a dupe
282
if (glyphInfoCache.get(code) == -1L) {
283
filteredIndicies[j] = -1;
284
dupes++;
285
j++;
286
continue;
287
}
288
289
// this is a distinct glyph we have not struck before, or
290
// promised to strike mark this one as "promise to strike"
291
// in the global cache with a -1L
292
final int k = j - dupes;
293
filteredCodes[k] = code;
294
glyphInfoCache.put(code, -1L);
295
filteredIndicies[j] = k;
296
j++;
297
}
298
299
final int filteredRunLen = j - dupes;
300
final long[] filteredImages = new long[filteredRunLen];
301
302
// bulk call to fill in the distinct glyph pointers from native
303
getFilteredGlyphImagePtrs(filteredImages, filteredCodes, filteredRunLen);
304
305
// scan the requested glyph list, and fill in pointers from our
306
// distinct glyph list which has been filled from native
307
j = 0;
308
for (int i = 0; i < len; i++) {
309
if (images[i] != 0L && images[i] != -1L) {
310
continue; // already placed
311
}
312
313
// index into filteredImages array
314
final int k = filteredIndicies[j];
315
final int code = glyphCodes[i];
316
if (k == -1L) {
317
// we should have already filled the cache with this pointer
318
images[i] = glyphInfoCache.get(code);
319
} else {
320
// fill the particular glyph code request, and store
321
// in the cache
322
final long ptr = filteredImages[k];
323
images[i] = ptr;
324
glyphInfoCache.put(code, ptr);
325
}
326
327
j++;
328
}
329
}
330
}
331
332
private void getFilteredGlyphImagePtrs(long[] glyphInfos,
333
int[] uniCodes, int len)
334
{
335
getGlyphImagePtrsNative(getNativeStrikePtr(), glyphInfos, uniCodes, len);
336
}
337
338
private float getCachedNativeGlyphAdvance(int glyphCode) {
339
synchronized(glyphAdvanceCache) {
340
float advance = glyphAdvanceCache.get(glyphCode);
341
if (advance != 0) {
342
return advance;
343
}
344
345
advance = getNativeGlyphAdvance(getNativeStrikePtr(), glyphCode);
346
glyphAdvanceCache.put(glyphCode, advance);
347
return advance;
348
}
349
}
350
351
// This class stores glyph pointers, and is indexed based on glyph codes,
352
// and negative unicode values. See the comments in
353
// CCharToGlyphMapper for more details on our glyph code strategy.
354
private static class GlyphInfoCache extends CStrikeDisposer {
355
private static final int FIRST_LAYER_SIZE = 256;
356
private static final int SECOND_LAYER_SIZE = 16384; // 16384 = 128x128
357
358
// rdar://problem/5204197
359
private boolean disposed = false;
360
361
private final long[] firstLayerCache;
362
private SparseBitShiftingTwoLayerArray secondLayerCache;
363
private HashMap<Integer, Long> generalCache;
364
365
GlyphInfoCache(final Font2D nativeFont, final FontStrikeDesc desc) {
366
super(nativeFont, desc);
367
firstLayerCache = new long[FIRST_LAYER_SIZE];
368
}
369
370
public synchronized long get(final int index) {
371
if (index < 0) {
372
if (-index < SECOND_LAYER_SIZE) {
373
// catch common unicodes
374
if (secondLayerCache == null) {
375
return 0L;
376
}
377
return secondLayerCache.get(-index);
378
}
379
} else {
380
if (index < FIRST_LAYER_SIZE) {
381
// catch common glyphcodes
382
return firstLayerCache[index];
383
}
384
}
385
386
if (generalCache == null) {
387
return 0L;
388
}
389
final Long value = generalCache.get(new Integer(index));
390
if (value == null) {
391
return 0L;
392
}
393
return value.longValue();
394
}
395
396
public synchronized void put(final int index, final long value) {
397
if (index < 0) {
398
if (-index < SECOND_LAYER_SIZE) {
399
// catch common unicodes
400
if (secondLayerCache == null) {
401
secondLayerCache = new SparseBitShiftingTwoLayerArray(SECOND_LAYER_SIZE, 7); // 128x128
402
}
403
secondLayerCache.put(-index, value);
404
return;
405
}
406
} else {
407
if (index < FIRST_LAYER_SIZE) {
408
// catch common glyphcodes
409
firstLayerCache[index] = value;
410
return;
411
}
412
}
413
414
if (generalCache == null) {
415
generalCache = new HashMap<Integer, Long>();
416
}
417
418
generalCache.put(new Integer(index), new Long(value));
419
}
420
421
public synchronized void dispose() {
422
// rdar://problem/5204197
423
// Note that sun.font.Font2D.getStrike() actively disposes
424
// cleared strikeRef. We need to check the disposed flag to
425
// prevent double frees of native resources.
426
if (disposed) {
427
return;
428
}
429
430
super.dispose();
431
432
// clean out the first array
433
disposeLongArray(firstLayerCache);
434
435
// clean out the two layer arrays
436
if (secondLayerCache != null) {
437
final long[][] secondLayerLongArrayArray = secondLayerCache.cache;
438
for (int i = 0; i < secondLayerLongArrayArray.length; i++) {
439
final long[] longArray = secondLayerLongArrayArray[i];
440
if (longArray != null) disposeLongArray(longArray);
441
}
442
}
443
444
// clean up everyone else
445
if (generalCache != null) {
446
final Iterator<Long> i = generalCache.values().iterator();
447
while (i.hasNext()) {
448
final long longValue = i.next().longValue();
449
if (longValue != -1 && longValue != 0) {
450
removeGlyphInfoFromCache(longValue);
451
StrikeCache.freeLongPointer(longValue);
452
}
453
}
454
}
455
456
// rdar://problem/5204197
457
// Finally, set the flag.
458
disposed = true;
459
}
460
461
private static void disposeLongArray(final long[] longArray) {
462
for (int i = 0; i < longArray.length; i++) {
463
final long ptr = longArray[i];
464
if (ptr != 0 && ptr != -1) {
465
removeGlyphInfoFromCache(ptr);
466
StrikeCache.freeLongPointer(ptr); // free's the native struct pointer
467
}
468
}
469
}
470
471
private static class SparseBitShiftingTwoLayerArray {
472
final long[][] cache;
473
final int shift;
474
final int secondLayerLength;
475
476
SparseBitShiftingTwoLayerArray(final int size, final int shift) {
477
this.shift = shift;
478
this.cache = new long[1 << shift][];
479
this.secondLayerLength = size >> shift;
480
}
481
482
public long get(final int index) {
483
final int firstIndex = index >> shift;
484
final long[] firstLayerRow = cache[firstIndex];
485
if (firstLayerRow == null) return 0L;
486
return firstLayerRow[index - (firstIndex * (1 << shift))];
487
}
488
489
public void put(final int index, final long value) {
490
final int firstIndex = index >> shift;
491
long[] firstLayerRow = cache[firstIndex];
492
if (firstLayerRow == null) {
493
cache[firstIndex] = firstLayerRow = new long[secondLayerLength];
494
}
495
firstLayerRow[index - (firstIndex * (1 << shift))] = value;
496
}
497
}
498
}
499
500
private static class GlyphAdvanceCache {
501
private static final int FIRST_LAYER_SIZE = 256;
502
private static final int SECOND_LAYER_SIZE = 16384; // 16384 = 128x128
503
504
private final float[] firstLayerCache = new float[FIRST_LAYER_SIZE];
505
private SparseBitShiftingTwoLayerArray secondLayerCache;
506
private HashMap<Integer, Float> generalCache;
507
508
// Empty non private constructor was added because access to this
509
// class shouldn't be emulated by a synthetic accessor method.
510
GlyphAdvanceCache() {
511
super();
512
}
513
514
public synchronized float get(final int index) {
515
if (index < 0) {
516
if (-index < SECOND_LAYER_SIZE) {
517
// catch common unicodes
518
if (secondLayerCache == null) return 0;
519
return secondLayerCache.get(-index);
520
}
521
} else {
522
if (index < FIRST_LAYER_SIZE) {
523
// catch common glyphcodes
524
return firstLayerCache[index];
525
}
526
}
527
528
if (generalCache == null) return 0;
529
final Float value = generalCache.get(new Integer(index));
530
if (value == null) return 0;
531
return value.floatValue();
532
}
533
534
public synchronized void put(final int index, final float value) {
535
if (index < 0) {
536
if (-index < SECOND_LAYER_SIZE) {
537
// catch common unicodes
538
if (secondLayerCache == null) {
539
secondLayerCache = new SparseBitShiftingTwoLayerArray(SECOND_LAYER_SIZE, 7); // 128x128
540
}
541
secondLayerCache.put(-index, value);
542
return;
543
}
544
} else {
545
if (index < FIRST_LAYER_SIZE) {
546
// catch common glyphcodes
547
firstLayerCache[index] = value;
548
return;
549
}
550
}
551
552
if (generalCache == null) {
553
generalCache = new HashMap<Integer, Float>();
554
}
555
556
generalCache.put(new Integer(index), new Float(value));
557
}
558
559
private static class SparseBitShiftingTwoLayerArray {
560
final float[][] cache;
561
final int shift;
562
final int secondLayerLength;
563
564
SparseBitShiftingTwoLayerArray(final int size, final int shift) {
565
this.shift = shift;
566
this.cache = new float[1 << shift][];
567
this.secondLayerLength = size >> shift;
568
}
569
570
public float get(final int index) {
571
final int firstIndex = index >> shift;
572
final float[] firstLayerRow = cache[firstIndex];
573
if (firstLayerRow == null) return 0L;
574
return firstLayerRow[index - (firstIndex * (1 << shift))];
575
}
576
577
public void put(final int index, final float value) {
578
final int firstIndex = index >> shift;
579
float[] firstLayerRow = cache[firstIndex];
580
if (firstLayerRow == null) {
581
cache[firstIndex] = firstLayerRow =
582
new float[secondLayerLength];
583
}
584
firstLayerRow[index - (firstIndex * (1 << shift))] = value;
585
}
586
}
587
}
588
}
589
590