Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/font/GlyphList.java
38829 views
1
/*
2
* Copyright (c) 2000, 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.Font;
29
import java.awt.font.GlyphVector;
30
import java.awt.font.FontRenderContext;
31
import sun.java2d.loops.FontInfo;
32
33
/*
34
* This class represents a list of actual renderable glyphs.
35
* It can be constructed from a number of text sources, representing
36
* the various ways in which a programmer can ask a Graphics2D object
37
* to render some text. Once constructed, it provides a way of iterating
38
* through the device metrics and graybits of the individual glyphs that
39
* need to be rendered to the screen.
40
*
41
* Note that this class holds pointers to native data which must be
42
* disposed. It is not marked as finalizable since it is intended
43
* to be very lightweight and finalization is a comparitively expensive
44
* procedure. The caller must specifically use try{} finally{} to
45
* manually ensure that the object is disposed after use, otherwise
46
* native data structures might be leaked.
47
*
48
* Here is a code sample for using this class:
49
*
50
* public void drawString(String str, FontInfo info, float x, float y) {
51
* GlyphList gl = GlyphList.getInstance();
52
* try {
53
* gl.setFromString(info, str, x, y);
54
* int strbounds[] = gl.getBounds();
55
* int numglyphs = gl.getNumGlyphs();
56
* for (int i = 0; i < numglyphs; i++) {
57
* gl.setGlyphIndex(i);
58
* int metrics[] = gl.getMetrics();
59
* byte bits[] = gl.getGrayBits();
60
* int glyphx = metrics[0];
61
* int glyphy = metrics[1];
62
* int glyphw = metrics[2];
63
* int glyphh = metrics[3];
64
* int off = 0;
65
* for (int j = 0; j < glyphh; j++) {
66
* for (int i = 0; i < glyphw; i++) {
67
* int dx = glyphx + i;
68
* int dy = glyphy + j;
69
* int alpha = bits[off++];
70
* drawPixel(alpha, dx, dy);
71
* }
72
* }
73
* }
74
* } finally {
75
* gl.dispose();
76
* }
77
* }
78
*/
79
public final class GlyphList {
80
private static final int MINGRAYLENGTH = 1024;
81
private static final int MAXGRAYLENGTH = 8192;
82
private static final int DEFAULT_LENGTH = 32;
83
84
int glyphindex;
85
int metrics[];
86
byte graybits[];
87
88
/* A reference to the strike is needed for the case when the GlyphList
89
* may be added to a queue for batch processing, (e.g. OpenGL) and we need
90
* to be completely certain that the strike is still valid when the glyphs
91
* images are later referenced. This does mean that if such code discards
92
* GlyphList and places only the data it contains on the queue, that the
93
* strike needs to be part of that data held by a strong reference.
94
* In the cases of drawString() and drawChars(), this is a single strike,
95
* although it may be a composite strike. In the case of
96
* drawGlyphVector() it may be a single strike, or a list of strikes.
97
*/
98
Object strikelist; // hold multiple strikes during rendering of complex gv
99
100
/* In normal usage, the same GlyphList will get recycled, so
101
* it makes sense to allocate arrays that will get reused along with
102
* it, rather than generating garbage. Garbage will be generated only
103
* in MP envts where multiple threads are executing. Throughput should
104
* still be higher in those cases.
105
*/
106
int len = 0;
107
int maxLen = 0;
108
int maxPosLen = 0;
109
int glyphData[];
110
char chData[];
111
long images[];
112
float positions[];
113
float x, y;
114
float gposx, gposy;
115
boolean usePositions;
116
117
/* lcdRGBOrder is used only by LCD text rendering. Its here because
118
* the Graphics may have a different hint value than the one used
119
* by a GlyphVector, so it has to be stored here - and is obtained
120
* from the right FontInfo. Another approach would have been to have
121
* install a separate pipe for that case but that's a lot of extra
122
* code when a simple boolean will suffice. The overhead to non-LCD
123
* text is a redundant boolean assign per call.
124
*/
125
boolean lcdRGBOrder;
126
127
/*
128
* lcdSubPixPos is used only by LCD text rendering. Its here because
129
* the Graphics may have a different hint value than the one used
130
* by a GlyphVector, so it has to be stored here - and is obtained
131
* from the right FontInfo. Its also needed by the code which
132
* calculates glyph positions which already needs to access this
133
* GlyphList and would otherwise need the FontInfo.
134
* This is true only if LCD text and fractional metrics hints
135
* are selected on the graphics.
136
* When this is true and the glyph positions as determined by the
137
* advances are non-integral, it requests adjustment of the positions.
138
* Setting this for surfaces which do not support it through accelerated
139
* loops may cause a slow-down as software loops are invoked instead.
140
*/
141
boolean lcdSubPixPos;
142
143
/* This scheme creates a singleton GlyphList which is checked out
144
* for use. Callers who find its checked out create one that after use
145
* is discarded. This means that in a MT-rendering environment,
146
* there's no need to synchronise except for that one instance.
147
* Fewer threads will then need to synchronise, perhaps helping
148
* throughput on a MP system. If for some reason the reusable
149
* GlyphList is checked out for a long time (or never returned?) then
150
* we would end up always creating new ones. That situation should not
151
* occur and if if did, it would just lead to some extra garbage being
152
* created.
153
*/
154
private static GlyphList reusableGL = new GlyphList();
155
private static boolean inUse;
156
157
158
void ensureCapacity(int len) {
159
/* Note len must not be -ve! only setFromChars should be capable
160
* of passing down a -ve len, and this guards against it.
161
*/
162
if (len < 0) {
163
len = 0;
164
}
165
if (usePositions && len > maxPosLen) {
166
positions = new float[len * 2 + 2];
167
maxPosLen = len;
168
}
169
170
if (maxLen == 0 || len > maxLen) {
171
glyphData = new int[len];
172
chData = new char[len];
173
images = new long[len];
174
maxLen = len;
175
}
176
}
177
178
private GlyphList() {
179
// ensureCapacity(DEFAULT_LENGTH);
180
}
181
182
// private GlyphList(int arraylen) {
183
// ensureCapacity(arraylen);
184
// }
185
186
public static GlyphList getInstance() {
187
/* The following heuristic is that if the reusable instance is
188
* in use, it probably still will be in a micro-second, so avoid
189
* synchronising on the class and just allocate a new instance.
190
* The cost is one extra boolean test for the normal case, and some
191
* small number of cases where we allocate an extra object when
192
* in fact the reusable one would be freed very soon.
193
*/
194
if (inUse) {
195
return new GlyphList();
196
} else {
197
synchronized(GlyphList.class) {
198
if (inUse) {
199
return new GlyphList();
200
} else {
201
inUse = true;
202
return reusableGL;
203
}
204
}
205
}
206
}
207
208
/* In some cases the caller may be able to estimate the size of
209
* array needed, and it will usually be long enough. This avoids
210
* the unnecessary reallocation that occurs if our default
211
* values are too small. This is useful because this object
212
* will be discarded so the re-allocation overhead is high.
213
*/
214
// public static GlyphList getInstance(int sz) {
215
// if (inUse) {
216
// return new GlyphList(sz);
217
// } else {
218
// synchronized(GlyphList.class) {
219
// if (inUse) {
220
// return new GlyphList();
221
// } else {
222
// inUse = true;
223
// return reusableGL;
224
// }
225
// }
226
// }
227
// }
228
229
/* GlyphList is in an invalid state until setFrom* method is called.
230
* After obtaining a new GlyphList it is the caller's responsibility
231
* that one of these methods is executed before handing off the
232
* GlyphList
233
*/
234
235
public boolean setFromString(FontInfo info, String str, float x, float y) {
236
this.x = x;
237
this.y = y;
238
this.strikelist = info.fontStrike;
239
this.lcdRGBOrder = info.lcdRGBOrder;
240
this.lcdSubPixPos = info.lcdSubPixPos;
241
len = str.length();
242
ensureCapacity(len);
243
str.getChars(0, len, chData, 0);
244
return mapChars(info, len);
245
}
246
247
public boolean setFromChars(FontInfo info, char[] chars, int off, int alen,
248
float x, float y) {
249
this.x = x;
250
this.y = y;
251
this.strikelist = info.fontStrike;
252
this.lcdRGBOrder = info.lcdRGBOrder;
253
this.lcdSubPixPos = info.lcdSubPixPos;
254
len = alen;
255
if (alen < 0) {
256
len = 0;
257
} else {
258
len = alen;
259
}
260
ensureCapacity(len);
261
System.arraycopy(chars, off, chData, 0, len);
262
return mapChars(info, len);
263
}
264
265
private final boolean mapChars(FontInfo info, int len) {
266
/* REMIND.Is it worthwhile for the iteration to convert
267
* chars to glyph ids to directly map to images?
268
*/
269
if (info.font2D.getMapper().charsToGlyphsNS(len, chData, glyphData)) {
270
return false;
271
}
272
info.fontStrike.getGlyphImagePtrs(glyphData, images, len);
273
glyphindex = -1;
274
return true;
275
}
276
277
278
public void setFromGlyphVector(FontInfo info, GlyphVector gv,
279
float x, float y) {
280
this.x = x;
281
this.y = y;
282
this.lcdRGBOrder = info.lcdRGBOrder;
283
this.lcdSubPixPos = info.lcdSubPixPos;
284
/* A GV may be rendered in different Graphics. It is possible it is
285
* used for one case where LCD text is available, and another where
286
* it is not. Pass in the "info". to ensure get a suitable one.
287
*/
288
StandardGlyphVector sgv = StandardGlyphVector.getStandardGV(gv, info);
289
// call before ensureCapacity :-
290
usePositions = sgv.needsPositions(info.devTx);
291
len = sgv.getNumGlyphs();
292
ensureCapacity(len);
293
strikelist = sgv.setupGlyphImages(images,
294
usePositions ? positions : null,
295
info.devTx);
296
glyphindex = -1;
297
}
298
299
public int[] getBounds() {
300
/* We co-opt the 5 element array that holds per glyph metrics in order
301
* to return the bounds. So a caller must copy the data out of the
302
* array before calling any other methods on this GlyphList
303
*/
304
if (glyphindex >= 0) {
305
throw new InternalError("calling getBounds after setGlyphIndex");
306
}
307
if (metrics == null) {
308
metrics = new int[5];
309
}
310
/* gposx and gposy are used to accumulate the advance.
311
* Add 0.5f for consistent rounding to pixel position. */
312
gposx = x + 0.5f;
313
gposy = y + 0.5f;
314
fillBounds(metrics);
315
return metrics;
316
}
317
318
/* This method now assumes "state", so must be called 0->len
319
* The metrics it returns are accumulated on the fly
320
* So it could be renamed "nextGlyph()".
321
* Note that a laid out GlyphVector which has assigned glyph positions
322
* doesn't have this stricture..
323
*/
324
public void setGlyphIndex(int i) {
325
glyphindex = i;
326
if (images[i] == 0L) {
327
metrics[0] = (int)gposx;
328
metrics[1] = (int)gposy;
329
metrics[2] = 0;
330
metrics[3] = 0;
331
metrics[4] = 0;
332
return;
333
}
334
float gx =
335
StrikeCache.unsafe.getFloat(images[i]+StrikeCache.topLeftXOffset);
336
float gy =
337
StrikeCache.unsafe.getFloat(images[i]+StrikeCache.topLeftYOffset);
338
339
if (usePositions) {
340
metrics[0] = (int)Math.floor(positions[(i<<1)] + gposx + gx);
341
metrics[1] = (int)Math.floor(positions[(i<<1)+1] + gposy + gy);
342
} else {
343
metrics[0] = (int)Math.floor(gposx + gx);
344
metrics[1] = (int)Math.floor(gposy + gy);
345
/* gposx and gposy are used to accumulate the advance */
346
gposx += StrikeCache.unsafe.getFloat
347
(images[i]+StrikeCache.xAdvanceOffset);
348
gposy += StrikeCache.unsafe.getFloat
349
(images[i]+StrikeCache.yAdvanceOffset);
350
}
351
metrics[2] =
352
StrikeCache.unsafe.getChar(images[i]+StrikeCache.widthOffset);
353
metrics[3] =
354
StrikeCache.unsafe.getChar(images[i]+StrikeCache.heightOffset);
355
metrics[4] =
356
StrikeCache.unsafe.getChar(images[i]+StrikeCache.rowBytesOffset);
357
}
358
359
public int[] getMetrics() {
360
return metrics;
361
}
362
363
public byte[] getGrayBits() {
364
int len = metrics[4] * metrics[3];
365
if (graybits == null) {
366
graybits = new byte[Math.max(len, MINGRAYLENGTH)];
367
} else {
368
if (len > graybits.length) {
369
graybits = new byte[len];
370
}
371
}
372
if (images[glyphindex] == 0L) {
373
return graybits;
374
}
375
long pixelDataAddress =
376
StrikeCache.unsafe.getAddress(images[glyphindex] +
377
StrikeCache.pixelDataOffset);
378
379
if (pixelDataAddress == 0L) {
380
return graybits;
381
}
382
/* unsafe is supposed to be fast, but I doubt if this loop can beat
383
* a native call which does a getPrimitiveArrayCritical and a
384
* memcpy for the typical amount of image data (30-150 bytes)
385
* Consider a native method if there is a performance problem (which
386
* I haven't seen so far).
387
*/
388
for (int i=0; i<len; i++) {
389
graybits[i] = StrikeCache.unsafe.getByte(pixelDataAddress+i);
390
}
391
return graybits;
392
}
393
394
public long[] getImages() {
395
return images;
396
}
397
398
public boolean usePositions() {
399
return usePositions;
400
}
401
402
public float[] getPositions() {
403
return positions;
404
}
405
406
public float getX() {
407
return x;
408
}
409
410
public float getY() {
411
return y;
412
}
413
414
public Object getStrike() {
415
return strikelist;
416
}
417
418
public boolean isSubPixPos() {
419
return lcdSubPixPos;
420
}
421
422
public boolean isRGBOrder() {
423
return lcdRGBOrder;
424
}
425
426
/* There's a reference equality test overhead here, but it allows us
427
* to avoid synchronizing for GL's that will just be GC'd. This
428
* helps MP throughput.
429
*/
430
public void dispose() {
431
if (this == reusableGL) {
432
if (graybits != null && graybits.length > MAXGRAYLENGTH) {
433
graybits = null;
434
}
435
usePositions = false;
436
strikelist = null; // remove reference to the strike list
437
inUse = false;
438
}
439
}
440
441
/* The value here is for use by the rendering engine as it reflects
442
* the number of glyphs in the array to be blitted. Surrogates pairs
443
* may have two slots (the second of these being a dummy entry of the
444
* invisible glyph), whereas an application client would expect only
445
* one glyph. In other words don't propagate this value up to client code.
446
*
447
* {dlf} an application client should have _no_ expectations about the
448
* number of glyphs per char. This ultimately depends on the font
449
* technology and layout process used, which in general clients will
450
* know nothing about.
451
*/
452
public int getNumGlyphs() {
453
return len;
454
}
455
456
/* We re-do all this work as we iterate through the glyphs
457
* but it seems unavoidable without re-working the Java TextRenderers.
458
*/
459
private void fillBounds(int[] bounds) {
460
/* Faster to access local variables in the for loop? */
461
int xOffset = StrikeCache.topLeftXOffset;
462
int yOffset = StrikeCache.topLeftYOffset;
463
int wOffset = StrikeCache.widthOffset;
464
int hOffset = StrikeCache.heightOffset;
465
int xAdvOffset = StrikeCache.xAdvanceOffset;
466
int yAdvOffset = StrikeCache.yAdvanceOffset;
467
468
if (len == 0) {
469
bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0;
470
return;
471
}
472
float bx0, by0, bx1, by1;
473
bx0 = by0 = Float.POSITIVE_INFINITY;
474
bx1 = by1 = Float.NEGATIVE_INFINITY;
475
476
int posIndex = 0;
477
float glx = x + 0.5f;
478
float gly = y + 0.5f;
479
char gw, gh;
480
float gx, gy, gx0, gy0, gx1, gy1;
481
for (int i=0; i<len; i++) {
482
if (images[i] == 0L) {
483
continue;
484
}
485
gx = StrikeCache.unsafe.getFloat(images[i]+xOffset);
486
gy = StrikeCache.unsafe.getFloat(images[i]+yOffset);
487
gw = StrikeCache.unsafe.getChar(images[i]+wOffset);
488
gh = StrikeCache.unsafe.getChar(images[i]+hOffset);
489
490
if (usePositions) {
491
gx0 = positions[posIndex++] + gx + glx;
492
gy0 = positions[posIndex++] + gy + gly;
493
} else {
494
gx0 = glx + gx;
495
gy0 = gly + gy;
496
glx += StrikeCache.unsafe.getFloat(images[i]+xAdvOffset);
497
gly += StrikeCache.unsafe.getFloat(images[i]+yAdvOffset);
498
}
499
gx1 = gx0 + gw;
500
gy1 = gy0 + gh;
501
if (bx0 > gx0) bx0 = gx0;
502
if (by0 > gy0) by0 = gy0;
503
if (bx1 < gx1) bx1 = gx1;
504
if (by1 < gy1) by1 = gy1;
505
}
506
/* floor is safe and correct because all glyph widths, heights
507
* and offsets are integers
508
*/
509
bounds[0] = (int)Math.floor(bx0);
510
bounds[1] = (int)Math.floor(by0);
511
bounds[2] = (int)Math.floor(bx1);
512
bounds[3] = (int)Math.floor(by1);
513
}
514
}
515
516