Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/sun/font/Font2D.java
41154 views
1
/*
2
* Copyright (c) 2003, 2018, 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.FontRenderContext;
30
import java.awt.geom.AffineTransform;
31
import java.lang.ref.Reference;
32
import java.lang.ref.SoftReference;
33
import java.lang.ref.WeakReference;
34
import java.util.concurrent.ConcurrentHashMap;
35
import java.util.Locale;
36
import java.util.Set;
37
38
public abstract class Font2D {
39
40
/* Note: JRE and FONT_CONFIG ranks are identical. I don't know of a reason
41
* to distingish these. Possibly if a user adds fonts to the JRE font
42
* directory that are the same font as the ones specified in the font
43
* configuration but that is more likely to be the legitimate intention
44
* than a problem. One reason why these should be the same is that on
45
* Linux the JRE fonts ARE the font configuration fonts, and although I
46
* believe all are assigned FONT_CONFIG rank, it is conceivable that if
47
* this were not so, that some JRE font would not be allowed to joint the
48
* family of its siblings which were assigned FONT_CONFIG rank. Giving
49
* them the same rank is the easy solution for now at least.
50
*/
51
public static final int FONT_CONFIG_RANK = 2;
52
public static final int JRE_RANK = 2;
53
public static final int TTF_RANK = 3;
54
public static final int TYPE1_RANK = 4;
55
public static final int NATIVE_RANK = 5;
56
public static final int UNKNOWN_RANK = 6;
57
public static final int DEFAULT_RANK = 4;
58
59
private static final String[] boldNames = {
60
"bold", "demibold", "demi-bold", "demi bold", "negreta", "demi", };
61
62
private static final String[] italicNames = {
63
"italic", "cursiva", "oblique", "inclined", };
64
65
private static final String[] boldItalicNames = {
66
"bolditalic", "bold-italic", "bold italic",
67
"boldoblique", "bold-oblique", "bold oblique",
68
"demibold italic", "negreta cursiva","demi oblique", };
69
70
private static final FontRenderContext DEFAULT_FRC =
71
new FontRenderContext(null, false, false);
72
73
public Font2DHandle handle;
74
protected String familyName; /* Family font name (english) */
75
protected String fullName; /* Full font name (english) */
76
protected int style = Font.PLAIN;
77
protected FontFamily family;
78
protected int fontRank = DEFAULT_RANK;
79
80
/*
81
* A mapper can be independent of the strike.
82
* Perhaps the reference to the mapper ought to be held on the
83
* scaler, as it may be implemented via scaler functionality anyway
84
* and so the mapper would be useless if its native portion was
85
* freed when the scaler was GC'd.
86
*/
87
protected CharToGlyphMapper mapper;
88
89
/*
90
* The strike cache is maintained per "Font2D" as that is the
91
* principal object by which you look up fonts.
92
* It means more Hashmaps, but look ups can be quicker because
93
* the map will have fewer entries, and there's no need to try to
94
* make the Font2D part of the key.
95
*/
96
protected ConcurrentHashMap<FontStrikeDesc, Reference<FontStrike>>
97
strikeCache = new ConcurrentHashMap<>();
98
99
/* Store the last Strike in a Reference object.
100
* Similarly to the strike that was stored on a C++ font object,
101
* this is an optimisation which helps if multiple clients (ie
102
* typically SunGraphics2D instances) are using the same font, then
103
* as may be typical of many UIs, they are probably using it in the
104
* same style, so it can be a win to first quickly check if the last
105
* strike obtained from this Font2D satifies the needs of the next
106
* client too.
107
* This pre-supposes that a FontStrike is a shareable object, which
108
* it should.
109
*/
110
protected Reference<FontStrike> lastFontStrike = new WeakReference<>(null);
111
112
/*
113
* if useWeak is true, proactively clear the cache after this
114
* many strikes are present. 0 means leave it alone.
115
*/
116
private int strikeCacheMax = 0;
117
/*
118
* Whether to use weak refs for this font, even if soft refs is the default.
119
*/
120
private boolean useWeak;
121
122
void setUseWeakRefs(boolean weak, int maxStrikes) {
123
this.useWeak = weak;
124
this.strikeCacheMax = weak && maxStrikes > 0 ? maxStrikes : 0;
125
}
126
127
/*
128
* POSSIBLE OPTIMISATION:
129
* Array of length 1024 elements of 64 bits indicating if a font
130
* contains these. This kind of information can be shared between
131
* all point sizes.
132
* if corresponding bit in knownBitmaskMap is set then canDisplayBitmaskMap
133
* is valid. This is 16Kbytes of data per composite font style.
134
* What about UTF-32 and surrogates?
135
* REMIND: This is too much storage. Probably can only cache this
136
* information for latin range, although possibly OK to store all
137
* for just the "logical" fonts.
138
* Or instead store arrays of subranges of 1024 bits (128 bytes) in
139
* the range below surrogate pairs.
140
*/
141
// protected long[] knownBitmaskMap;
142
// protected long[] canDisplayBitmaskMap;
143
144
/* Returns the "real" style of this Font2D. Eg the font face
145
* Lucida Sans Bold" has a real style of Font.BOLD, even though
146
* it may be able to used to simulate bold italic
147
*/
148
public int getStyle() {
149
return style;
150
}
151
protected void setStyle() {
152
153
String fName = fullName.toLowerCase();
154
155
for (int i=0; i < boldItalicNames.length; i++) {
156
if (fName.indexOf(boldItalicNames[i]) != -1) {
157
style = Font.BOLD|Font.ITALIC;
158
return;
159
}
160
}
161
162
for (int i=0; i < italicNames.length; i++) {
163
if (fName.indexOf(italicNames[i]) != -1) {
164
style = Font.ITALIC;
165
return;
166
}
167
}
168
169
for (int i=0; i < boldNames.length; i++) {
170
if (fName.indexOf(boldNames[i]) != -1 ) {
171
style = Font.BOLD;
172
return;
173
}
174
}
175
}
176
177
public static final int FWIDTH_NORMAL = 5; // OS/2 usWidthClass
178
public static final int FWEIGHT_NORMAL = 400; // OS/2 usWeightClass
179
public static final int FWEIGHT_BOLD = 700; // OS/2 usWeightClass
180
181
public int getWidth() {
182
return FWIDTH_NORMAL;
183
}
184
185
public int getWeight() {
186
if ((style & Font.BOLD) !=0) {
187
return FWEIGHT_BOLD;
188
} else {
189
return FWEIGHT_NORMAL;
190
}
191
}
192
193
int getRank() {
194
return fontRank;
195
}
196
197
void setRank(int rank) {
198
fontRank = rank;
199
}
200
201
abstract CharToGlyphMapper getMapper();
202
203
204
205
/* This isn't very efficient but its infrequently used.
206
* StandardGlyphVector uses it when the client assigns the glyph codes.
207
* These may not be valid. This validates them substituting the missing
208
* glyph elsewhere.
209
*/
210
protected int getValidatedGlyphCode(int glyphCode) {
211
if (glyphCode < 0 || glyphCode >= getMapper().getNumGlyphs()) {
212
glyphCode = getMapper().getMissingGlyphCode();
213
}
214
return glyphCode;
215
}
216
217
/*
218
* Creates an appropriate strike for the Font2D subclass
219
*/
220
abstract FontStrike createStrike(FontStrikeDesc desc);
221
222
/* this may be useful for APIs like canDisplay where the answer
223
* is dependent on the font and its scaler, but not the strike.
224
* If no strike has ever been returned, then create a one that matches
225
* this font with the default FRC. It will become the lastStrike and
226
* there's a good chance that the next call will be to get exactly that
227
* strike.
228
*/
229
public FontStrike getStrike(Font font) {
230
FontStrike strike = lastFontStrike.get();
231
if (strike != null) {
232
return strike;
233
} else {
234
return getStrike(font, DEFAULT_FRC);
235
}
236
}
237
238
/* SunGraphics2D has font, tx, aa and fm. From this info
239
* can get a Strike object from the cache, creating it if necessary.
240
* This code is designed for multi-threaded access.
241
* For that reason it creates a local FontStrikeDesc rather than filling
242
* in a shared one. Up to two AffineTransforms and one FontStrikeDesc will
243
* be created by every lookup. This appears to perform more than
244
* adequately. But it may make sense to expose FontStrikeDesc
245
* as a parameter so a caller can use its own.
246
* In such a case if a FontStrikeDesc is stored as a key then
247
* we would need to use a private copy.
248
*
249
* Note that this code doesn't prevent two threads from creating
250
* two different FontStrike instances and having one of the threads
251
* overwrite the other in the map. This is likely to be a rare
252
* occurrence and the only consequence is that these callers will have
253
* different instances of the strike, and there'd be some duplication of
254
* population of the strikes. However since users of these strikes are
255
* transient, then the one that was overwritten would soon be freed.
256
* If there is any problem then a small synchronized block would be
257
* required with its attendant consequences for MP scaleability.
258
*/
259
public FontStrike getStrike(Font font, AffineTransform devTx,
260
int aa, int fm) {
261
262
/* Create the descriptor which is used to identify a strike
263
* in the strike cache/map. A strike is fully described by
264
* the attributes of this descriptor.
265
*/
266
/* REMIND: generating garbage and doing computation here in order
267
* to include pt size in the tx just for a lookup! Figure out a
268
* better way.
269
*/
270
double ptSize = font.getSize2D();
271
AffineTransform glyphTx = (AffineTransform)devTx.clone();
272
glyphTx.scale(ptSize, ptSize);
273
if (font.isTransformed()) {
274
glyphTx.concatenate(font.getTransform());
275
}
276
if (glyphTx.getTranslateX() != 0 || glyphTx.getTranslateY() != 0) {
277
glyphTx.setTransform(glyphTx.getScaleX(),
278
glyphTx.getShearY(),
279
glyphTx.getShearX(),
280
glyphTx.getScaleY(),
281
0.0, 0.0);
282
}
283
FontStrikeDesc desc = new FontStrikeDesc(devTx, glyphTx,
284
font.getStyle(), aa, fm);
285
return getStrike(desc, false);
286
}
287
288
public FontStrike getStrike(Font font, AffineTransform devTx,
289
AffineTransform glyphTx,
290
int aa, int fm) {
291
292
/* Create the descriptor which is used to identify a strike
293
* in the strike cache/map. A strike is fully described by
294
* the attributes of this descriptor.
295
*/
296
FontStrikeDesc desc = new FontStrikeDesc(devTx, glyphTx,
297
font.getStyle(), aa, fm);
298
return getStrike(desc, false);
299
}
300
301
public FontStrike getStrike(Font font, FontRenderContext frc) {
302
303
AffineTransform at = frc.getTransform();
304
double ptSize = font.getSize2D();
305
at.scale(ptSize, ptSize);
306
if (font.isTransformed()) {
307
at.concatenate(font.getTransform());
308
if (at.getTranslateX() != 0 || at.getTranslateY() != 0) {
309
at.setTransform(at.getScaleX(),
310
at.getShearY(),
311
at.getShearX(),
312
at.getScaleY(),
313
0.0, 0.0);
314
}
315
}
316
int aa = FontStrikeDesc.getAAHintIntVal(this, font, frc);
317
int fm = FontStrikeDesc.getFMHintIntVal(frc.getFractionalMetricsHint());
318
FontStrikeDesc desc = new FontStrikeDesc(frc.getTransform(),
319
at, font.getStyle(),
320
aa, fm);
321
return getStrike(desc, false);
322
}
323
324
void updateLastStrikeRef(FontStrike strike) {
325
lastFontStrike.clear();
326
if (useWeak) {
327
lastFontStrike = new WeakReference<>(strike);
328
} else {
329
lastFontStrike = new SoftReference<>(strike);
330
}
331
}
332
333
FontStrike getStrike(FontStrikeDesc desc) {
334
return getStrike(desc, true);
335
}
336
337
private FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
338
/* Before looking in the map, see if the descriptor matches the
339
* last strike returned from this Font2D. This should often be a win
340
* since its common for the same font, in the same size to be
341
* used frequently, for example in many parts of a UI.
342
*
343
* If its not the same then we use the descriptor to locate a
344
* Reference to the strike. If it exists and points to a strike,
345
* then we update the last strike to refer to that and return it.
346
*
347
* If the key isn't in the map, or its reference object has been
348
* collected, then we create a new strike, put it in the map and
349
* set it to be the last strike.
350
*/
351
FontStrike strike = lastFontStrike.get();
352
if (strike != null && desc.equals(strike.desc)) {
353
return strike;
354
} else {
355
Reference<FontStrike> strikeRef = strikeCache.get(desc);
356
if (strikeRef != null) {
357
strike = strikeRef.get();
358
if (strike != null) {
359
updateLastStrikeRef(strike);
360
StrikeCache.refStrike(strike);
361
return strike;
362
}
363
}
364
/* When we create a new FontStrike instance, we *must*
365
* ask the StrikeCache for a reference. We must then ensure
366
* this reference remains reachable, by storing it in the
367
* Font2D's strikeCache map.
368
* So long as the Reference is there (reachable) then if the
369
* reference is cleared, it will be enqueued for disposal.
370
* If for some reason we explicitly remove this reference, it
371
* must only be done when holding a strong reference to the
372
* referent (the FontStrike), or if the reference is cleared,
373
* then we must explicitly "dispose" of the native resources.
374
* The only place this currently happens is in this same method,
375
* where we find a cleared reference and need to overwrite it
376
* here with a new reference.
377
* Clearing the whilst holding a strong reference, should only
378
* be done if the
379
*/
380
if (copy) {
381
desc = new FontStrikeDesc(desc);
382
}
383
strike = createStrike(desc);
384
//StrikeCache.addStrike();
385
/* If we are creating many strikes on this font which
386
* involve non-quadrant rotations, or more general
387
* transforms which include shears, then force the use
388
* of weak references rather than soft references.
389
* This means that it won't live much beyond the next GC,
390
* which is what we want for what is likely a transient strike.
391
*/
392
int txType = desc.glyphTx.getType();
393
if (useWeak ||
394
txType == AffineTransform.TYPE_GENERAL_TRANSFORM ||
395
(txType & AffineTransform.TYPE_GENERAL_ROTATION) != 0 &&
396
strikeCache.size() > 10) {
397
strikeRef = StrikeCache.getStrikeRef(strike, true);
398
} else {
399
strikeRef = StrikeCache.getStrikeRef(strike, useWeak);
400
}
401
strikeCache.put(desc, strikeRef);
402
updateLastStrikeRef(strike);
403
StrikeCache.refStrike(strike);
404
return strike;
405
}
406
}
407
408
/**
409
* The length of the metrics array must be >= 8. This method will
410
* store the following elements in that array before returning:
411
* metrics[0]: ascent
412
* metrics[1]: descent
413
* metrics[2]: leading
414
* metrics[3]: max advance
415
* metrics[4]: strikethrough offset
416
* metrics[5]: strikethrough thickness
417
* metrics[6]: underline offset
418
* metrics[7]: underline thickness
419
*/
420
public void getFontMetrics(Font font, AffineTransform at,
421
Object aaHint, Object fmHint,
422
float[] metrics) {
423
/* This is called in just one place in Font with "at" == identity.
424
* Perhaps this can be eliminated.
425
*/
426
int aa = FontStrikeDesc.getAAHintIntVal(aaHint, this, font.getSize());
427
int fm = FontStrikeDesc.getFMHintIntVal(fmHint);
428
FontStrike strike = getStrike(font, at, aa, fm);
429
StrikeMetrics strikeMetrics = strike.getFontMetrics();
430
metrics[0] = strikeMetrics.getAscent();
431
metrics[1] = strikeMetrics.getDescent();
432
metrics[2] = strikeMetrics.getLeading();
433
metrics[3] = strikeMetrics.getMaxAdvance();
434
435
getStyleMetrics(font.getSize2D(), metrics, 4);
436
}
437
438
/**
439
* The length of the metrics array must be >= offset+4, and offset must be
440
* >= 0. Typically offset is 4. This method will
441
* store the following elements in that array before returning:
442
* metrics[off+0]: strikethrough offset
443
* metrics[off+1]: strikethrough thickness
444
* metrics[off+2]: underline offset
445
* metrics[off+3]: underline thickness
446
*
447
* Note that this implementation simply returns default values;
448
* subclasses can override this method to provide more accurate values.
449
*/
450
public void getStyleMetrics(float pointSize, float[] metrics, int offset) {
451
metrics[offset] = -metrics[0] / 2.5f;
452
metrics[offset+1] = pointSize / 12;
453
metrics[offset+2] = metrics[offset+1] / 1.5f;
454
metrics[offset+3] = metrics[offset+1];
455
}
456
457
/**
458
* The length of the metrics array must be >= 4. This method will
459
* store the following elements in that array before returning:
460
* metrics[0]: ascent
461
* metrics[1]: descent
462
* metrics[2]: leading
463
* metrics[3]: max advance
464
*/
465
public void getFontMetrics(Font font, FontRenderContext frc,
466
float[] metrics) {
467
StrikeMetrics strikeMetrics = getStrike(font, frc).getFontMetrics();
468
metrics[0] = strikeMetrics.getAscent();
469
metrics[1] = strikeMetrics.getDescent();
470
metrics[2] = strikeMetrics.getLeading();
471
metrics[3] = strikeMetrics.getMaxAdvance();
472
}
473
474
/* Currently the layout code calls this. May be better for layout code
475
* to check the font class before attempting to run, rather than needing
476
* to promote this method up from TrueTypeFont
477
*/
478
protected byte[] getTableBytes(int tag) {
479
return null;
480
}
481
482
/* Used only on OS X.
483
*/
484
protected long getPlatformNativeFontPtr() {
485
return 0L;
486
}
487
488
/* for layout code */
489
protected long getUnitsPerEm() {
490
return 2048;
491
}
492
493
boolean supportsEncoding(String encoding) {
494
return false;
495
}
496
497
public boolean canDoStyle(int style) {
498
return (style == this.style);
499
}
500
501
/*
502
* All the important subclasses override this which is principally for
503
* the TrueType 'gasp' table.
504
*/
505
public boolean useAAForPtSize(int ptsize) {
506
return true;
507
}
508
509
public boolean hasSupplementaryChars() {
510
return false;
511
}
512
513
/* The following methods implement public methods on java.awt.Font */
514
public String getPostscriptName() {
515
return fullName;
516
}
517
518
public String getFontName(Locale l) {
519
return fullName;
520
}
521
522
public String getFamilyName(Locale l) {
523
return familyName;
524
}
525
526
public int getNumGlyphs() {
527
return getMapper().getNumGlyphs();
528
}
529
530
public int charToGlyph(int wchar) {
531
return getMapper().charToGlyph(wchar);
532
}
533
534
public int charToVariationGlyph(int wchar, int variationSelector) {
535
return getMapper().charToVariationGlyph(wchar, variationSelector);
536
}
537
538
public int getMissingGlyphCode() {
539
return getMapper().getMissingGlyphCode();
540
}
541
542
public boolean canDisplay(char c) {
543
return getMapper().canDisplay(c);
544
}
545
546
public boolean canDisplay(int cp) {
547
return getMapper().canDisplay(cp);
548
}
549
550
public byte getBaselineFor(char c) {
551
return Font.ROMAN_BASELINE;
552
}
553
554
public float getItalicAngle(Font font, AffineTransform at,
555
Object aaHint, Object fmHint) {
556
/* hardwire psz=12 as that's typical and AA vs non-AA for 'gasp' mode
557
* isn't important for the caret slope of this rarely used API.
558
*/
559
int aa = FontStrikeDesc.getAAHintIntVal(aaHint, this, 12);
560
int fm = FontStrikeDesc.getFMHintIntVal(fmHint);
561
FontStrike strike = getStrike(font, at, aa, fm);
562
StrikeMetrics metrics = strike.getFontMetrics();
563
if (metrics.ascentY == 0 || metrics.ascentX == 0) {
564
return 0f;
565
} else {
566
/* ascent is "up" from the baseline so its typically
567
* a negative value, so we need to compensate
568
*/
569
return metrics.ascentX/-metrics.ascentY;
570
}
571
}
572
573
}
574
575