Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/sun/font/CompositeFont.java
41154 views
1
/*
2
* Copyright (c) 2003, 2014, 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
30
/* Remind: need to enhance to extend component list with a fallback
31
* list, which is not used in metrics or queries on the composite, but
32
* is used in drawing primitives and queries which supply an actual string.
33
* ie for a codepoint that is only in a fallback, font-wide queries such
34
* as FontMetrics.getHeight() will not take it into account.
35
* But getStringBounds(..) would take it into account.
36
* Its fuzzier for queries such as "canDisplay". If this does not include
37
* the fallback, then we probably want to add "canDisplayFallback()"
38
* But its probably OK to include it so long as only composites include
39
* fallbacks. If physicals do then it would be really confusing ..
40
*/
41
public final class CompositeFont extends Font2D {
42
43
private boolean[] deferredInitialisation;
44
String[] componentFileNames;
45
String[] componentNames;
46
/* because components can be lazily initialised the components field is
47
* private, to ensure all clients call getSlotFont()
48
*/
49
private PhysicalFont[] components;
50
int numSlots;
51
int numMetricsSlots;
52
int[] exclusionRanges;
53
int[] maxIndices;
54
int numGlyphs = 0;
55
int localeSlot = -1; // primary slot for this locale.
56
57
/* See isStdComposite() for when/how this is used */
58
boolean isStdComposite = true;
59
60
public CompositeFont(String name, String[] compFileNames,
61
String[] compNames, int metricsSlotCnt,
62
int[] exclRanges, int[] maxIndexes,
63
boolean defer, SunFontManager fm) {
64
65
handle = new Font2DHandle(this);
66
fullName = name;
67
componentFileNames = compFileNames;
68
componentNames = compNames;
69
if (compNames == null) {
70
numSlots = componentFileNames.length;
71
} else {
72
numSlots = componentNames.length;
73
}
74
/* We will limit the number of slots to 254.
75
* We store the slot for a glyph id in a byte and we may use one slot
76
* for an EUDC font, and we may also create a composite
77
* using this composite as a backup for a physical font.
78
* So we want to leave space for the two additional slots.
79
*/
80
numSlots = (numSlots <= 254) ? numSlots : 254;
81
82
/* Only the first "numMetricsSlots" slots are used for font metrics.
83
* the rest are considered "fallback" slots".
84
*/
85
numMetricsSlots = metricsSlotCnt;
86
exclusionRanges = exclRanges;
87
maxIndices = maxIndexes;
88
89
/*
90
* See if this is a windows locale which has a system EUDC font.
91
* If so add it as the final fallback component of the composite.
92
* The caller could be responsible for this, but for now it seems
93
* better that it is handled internally to the CompositeFont class.
94
*/
95
if (fm.getEUDCFont() != null) {
96
int msCnt = numMetricsSlots;
97
int fbCnt = numSlots - msCnt;
98
numSlots++;
99
if (componentNames != null) {
100
componentNames = new String[numSlots];
101
System.arraycopy(compNames, 0, componentNames, 0, msCnt);
102
componentNames[msCnt] = fm.getEUDCFont().getFontName(null);
103
System.arraycopy(compNames, msCnt,
104
componentNames, msCnt+1, fbCnt);
105
}
106
if (componentFileNames != null) {
107
componentFileNames = new String[numSlots];
108
System.arraycopy(compFileNames, 0,
109
componentFileNames, 0, msCnt);
110
System.arraycopy(compFileNames, msCnt,
111
componentFileNames, msCnt+1, fbCnt);
112
}
113
components = new PhysicalFont[numSlots];
114
components[msCnt] = fm.getEUDCFont();
115
deferredInitialisation = new boolean[numSlots];
116
if (defer) {
117
for (int i=0; i<numSlots-1; i++) {
118
deferredInitialisation[i] = true;
119
}
120
}
121
} else {
122
components = new PhysicalFont[numSlots];
123
deferredInitialisation = new boolean[numSlots];
124
if (defer) {
125
for (int i=0; i<numSlots; i++) {
126
deferredInitialisation[i] = true;
127
}
128
}
129
}
130
131
fontRank = Font2D.FONT_CONFIG_RANK;
132
133
int index = fullName.indexOf('.');
134
if (index>0) {
135
familyName = fullName.substring(0, index);
136
/* composites don't call setStyle() as parsing the style
137
* takes place at the same time as parsing the family name.
138
* Do I really have to parse the style from the name?
139
* Need to look into having the caller provide this. */
140
if (index+1 < fullName.length()) {
141
String styleStr = fullName.substring(index+1);
142
if ("plain".equals(styleStr)) {
143
style = Font.PLAIN;
144
} else if ("bold".equals(styleStr)) {
145
style = Font.BOLD;
146
} else if ("italic".equals(styleStr)) {
147
style = Font.ITALIC;
148
} else if ("bolditalic".equals(styleStr)) {
149
style = Font.BOLD | Font.ITALIC;
150
}
151
}
152
} else {
153
familyName = fullName;
154
}
155
}
156
157
/*
158
* Build a composite from a set of individual slot fonts.
159
*/
160
CompositeFont(PhysicalFont[] slotFonts) {
161
162
isStdComposite = false;
163
handle = new Font2DHandle(this);
164
fullName = slotFonts[0].fullName;
165
familyName = slotFonts[0].familyName;
166
style = slotFonts[0].style;
167
168
numMetricsSlots = 1; /* Only the physical Font */
169
numSlots = slotFonts.length;
170
171
components = new PhysicalFont[numSlots];
172
System.arraycopy(slotFonts, 0, components, 0, numSlots);
173
deferredInitialisation = new boolean[numSlots]; // all false.
174
}
175
176
/* This method is currently intended to be called only from
177
* FontManager.getCompositeFontUIResource(Font)
178
* It creates a new CompositeFont with the contents of the Physical
179
* one pre-pended as slot 0.
180
*/
181
CompositeFont(PhysicalFont physFont, CompositeFont compFont) {
182
183
isStdComposite = false;
184
handle = new Font2DHandle(this);
185
fullName = physFont.fullName;
186
familyName = physFont.familyName;
187
style = physFont.style;
188
189
numMetricsSlots = 1; /* Only the physical Font */
190
numSlots = compFont.numSlots+1;
191
192
/* Ugly though it is, we synchronize here on the FontManager class
193
* because it is the lock used to do deferred initialisation.
194
* We need to ensure that the arrays have consistent information.
195
* But it may be possible to dispense with the synchronisation if
196
* it is harmless that we do not know a slot is already initialised
197
* and just need to discover that and mark it so.
198
*/
199
synchronized (FontManagerFactory.getInstance()) {
200
components = new PhysicalFont[numSlots];
201
components[0] = physFont;
202
System.arraycopy(compFont.components, 0,
203
components, 1, compFont.numSlots);
204
205
if (compFont.componentNames != null) {
206
componentNames = new String[numSlots];
207
componentNames[0] = physFont.fullName;
208
System.arraycopy(compFont.componentNames, 0,
209
componentNames, 1, compFont.numSlots);
210
}
211
if (compFont.componentFileNames != null) {
212
componentFileNames = new String[numSlots];
213
componentFileNames[0] = null;
214
System.arraycopy(compFont.componentFileNames, 0,
215
componentFileNames, 1, compFont.numSlots);
216
}
217
deferredInitialisation = new boolean[numSlots];
218
deferredInitialisation[0] = false;
219
System.arraycopy(compFont.deferredInitialisation, 0,
220
deferredInitialisation, 1, compFont.numSlots);
221
}
222
}
223
224
/* This is used for deferred initialisation, so that the components of
225
* a logical font are initialised only when the font is used.
226
* This can have a positive impact on start-up of most UI applications.
227
* Note that this technique cannot be used with a TTC font as it
228
* doesn't know which font in the collection is needed. The solution to
229
* this is that the initialisation checks if the returned font is
230
* really the one it wants by comparing the name against the name that
231
* was passed in (if none was passed in then you aren't using a TTC
232
* as you would have to specify the name in such a case).
233
* Assuming there's only two or three fonts in a collection then it
234
* may be sufficient to verify the returned name is the expected one.
235
* But half the time it won't be. However since initialisation of the
236
* TTC will initialise all its components then just do a findFont2D call
237
* to locate the right one.
238
* This code allows for initialisation of each slot on demand.
239
* There are two issues with this.
240
* 1) All metrics slots probably may be initialised anyway as many
241
* apps will query the overall font metrics. However this is not an
242
* absolute requirement
243
* 2) Some font configuration files on Solaris reference two versions
244
* of a TT font: a Latin-1 version, then a Pan-European version.
245
* One from /usr/openwin/lib/X11/fonts/TrueType, the other from
246
* a euro_fonts directory which is symlinked from numerous locations.
247
* This is difficult to avoid because the two do not share XLFDs so
248
* both will be consequently mapped by separate XLFDs needed by AWT.
249
* The difficulty this presents for lazy initialisation is that if
250
* all the components are not mapped at once, the smaller version may
251
* have been used only to be replaced later, and what is the consequence
252
* for a client that displayed the contents of this font already.
253
* After some thought I think this will not be a problem because when
254
* client tries to display a glyph only in the Euro font, the composite
255
* will ask all components of this font for that glyph and will get
256
* the euro one. Subsequent uses will all come from the 100% compatible
257
* euro one.
258
*/
259
private void doDeferredInitialisation(int slot) {
260
if (deferredInitialisation[slot] == false) {
261
return;
262
}
263
264
/* Synchronize on FontManager so that is the global lock
265
* to update its static set of deferred fonts.
266
* This global lock is rarely likely to be an issue as there
267
* are only going to be a few calls into this code.
268
*/
269
SunFontManager fm = SunFontManager.getInstance();
270
synchronized (fm) {
271
if (componentNames == null) {
272
componentNames = new String[numSlots];
273
}
274
if (components[slot] == null) {
275
/* Warning: it is possible that the returned component is
276
* not derived from the file name argument, this can happen if:
277
* - the file can't be found
278
* - the file has a bad font
279
* - the font in the file is superseded by a more complete one
280
* This should not be a problem for composite font as it will
281
* make no further use of this file, but code debuggers/
282
* maintainers need to be conscious of this possibility.
283
*/
284
if (componentFileNames != null &&
285
componentFileNames[slot] != null) {
286
components[slot] =
287
fm.initialiseDeferredFont(componentFileNames[slot]);
288
}
289
290
if (components[slot] == null) {
291
components[slot] = fm.getDefaultPhysicalFont();
292
}
293
String name = components[slot].getFontName(null);
294
if (componentNames[slot] == null) {
295
componentNames[slot] = name;
296
} else if (!componentNames[slot].equalsIgnoreCase(name)) {
297
/* If a component specifies the file with a bad font,
298
* the corresponding slot will be initialized by
299
* default physical font. In such case findFont2D may
300
* return composite font which cannot be casted to
301
* physical font.
302
*/
303
try {
304
components[slot] =
305
(PhysicalFont) fm.findFont2D(componentNames[slot],
306
style,
307
FontManager.PHYSICAL_FALLBACK);
308
} catch (ClassCastException cce) {
309
/* Assign default physical font to the slot */
310
components[slot] = fm.getDefaultPhysicalFont();
311
}
312
}
313
}
314
deferredInitialisation[slot] = false;
315
}
316
}
317
318
/* To called only by FontManager.replaceFont */
319
void replaceComponentFont(PhysicalFont oldFont, PhysicalFont newFont) {
320
if (components == null) {
321
return;
322
}
323
for (int slot=0; slot<numSlots; slot++) {
324
if (components[slot] == oldFont) {
325
components[slot] = newFont;
326
if (componentNames != null) {
327
componentNames[slot] = newFont.getFontName(null);
328
}
329
}
330
}
331
}
332
333
public boolean isExcludedChar(int slot, int charcode) {
334
335
if (exclusionRanges == null || maxIndices == null ||
336
slot >= numMetricsSlots) {
337
return false;
338
}
339
340
int minIndex = 0;
341
int maxIndex = maxIndices[slot];
342
if (slot > 0) {
343
minIndex = maxIndices[slot - 1];
344
}
345
int curIndex = minIndex;
346
while (maxIndex > curIndex) {
347
if ((charcode >= exclusionRanges[curIndex])
348
&& (charcode <= exclusionRanges[curIndex+1])) {
349
return true; // excluded
350
}
351
curIndex += 2;
352
}
353
return false;
354
}
355
356
public void getStyleMetrics(float pointSize, float[] metrics, int offset) {
357
PhysicalFont font = getSlotFont(0);
358
if (font == null) { // possible?
359
super.getStyleMetrics(pointSize, metrics, offset);
360
} else {
361
font.getStyleMetrics(pointSize, metrics, offset);
362
}
363
}
364
365
public int getNumSlots() {
366
return numSlots;
367
}
368
369
public PhysicalFont getSlotFont(int slot) {
370
/* This is essentially the runtime overhead for deferred font
371
* initialisation: a boolean test on obtaining a slot font,
372
* which will happen per slot, on initialisation of a strike
373
* (as that is the only frequent call site of this method.
374
*/
375
if (deferredInitialisation[slot]) {
376
doDeferredInitialisation(slot);
377
}
378
SunFontManager fm = SunFontManager.getInstance();
379
try {
380
PhysicalFont font = components[slot];
381
if (font == null) {
382
try {
383
font = (PhysicalFont) fm.
384
findFont2D(componentNames[slot], style,
385
FontManager.PHYSICAL_FALLBACK);
386
components[slot] = font;
387
} catch (ClassCastException cce) {
388
font = fm.getDefaultPhysicalFont();
389
}
390
}
391
return font;
392
} catch (Exception e) {
393
return fm.getDefaultPhysicalFont();
394
}
395
}
396
397
FontStrike createStrike(FontStrikeDesc desc) {
398
return new CompositeStrike(this, desc);
399
}
400
401
/* This is set false when the composite is created using a specified
402
* physical font as the first slot and called by code which
403
* selects composites by locale preferences to know that this
404
* isn't a font which should be adjusted.
405
*/
406
public boolean isStdComposite() {
407
return isStdComposite;
408
}
409
410
/* This isn't very efficient but its infrequently used.
411
* StandardGlyphVector uses it when the client assigns the glyph codes.
412
* These may not be valid. This validates them substituting the missing
413
* glyph elsewhere.
414
*/
415
protected int getValidatedGlyphCode(int glyphCode) {
416
int slot = glyphCode >>> 24;
417
if (slot >= numSlots) {
418
return getMapper().getMissingGlyphCode();
419
}
420
421
int slotglyphCode = glyphCode & CompositeStrike.SLOTMASK;
422
PhysicalFont slotFont = getSlotFont(slot);
423
if (slotFont.getValidatedGlyphCode(slotglyphCode) ==
424
slotFont.getMissingGlyphCode()) {
425
return getMapper().getMissingGlyphCode();
426
} else {
427
return glyphCode;
428
}
429
}
430
431
public CharToGlyphMapper getMapper() {
432
if (mapper == null) {
433
mapper = new CompositeGlyphMapper(this);
434
}
435
return mapper;
436
}
437
438
public boolean hasSupplementaryChars() {
439
for (int i=0; i<numSlots; i++) {
440
if (getSlotFont(i).hasSupplementaryChars()) {
441
return true;
442
}
443
}
444
return false;
445
}
446
447
public int getNumGlyphs() {
448
if (numGlyphs == 0) {
449
numGlyphs = getMapper().getNumGlyphs();
450
}
451
return numGlyphs;
452
}
453
454
public int getMissingGlyphCode() {
455
return getMapper().getMissingGlyphCode();
456
}
457
458
public boolean canDisplay(char c) {
459
return getMapper().canDisplay(c);
460
}
461
462
public boolean useAAForPtSize(int ptsize) {
463
/* Find the first slot that supports the default encoding and use
464
* that to decide the "gasp" behaviour of the composite font.
465
* REMIND "default encoding" isn't applicable to a Unicode locale
466
* and we need to replace this with a better mechanism for deciding
467
* if a font "supports" the user's language. See TrueTypeFont.java
468
*/
469
if (localeSlot == -1) {
470
/* Ordinarily check numMetricsSlots, but non-standard composites
471
* set that to "1" whilst not necessarily supporting the default
472
* encoding with that first slot. In such a case check all slots.
473
*/
474
int numCoreSlots = numMetricsSlots;
475
if (numCoreSlots == 1 && !isStdComposite()) {
476
numCoreSlots = numSlots;
477
}
478
for (int slot=0; slot<numCoreSlots; slot++) {
479
if (getSlotFont(slot).supportsEncoding(null)) {
480
localeSlot = slot;
481
break;
482
}
483
}
484
if (localeSlot == -1) {
485
localeSlot = 0;
486
}
487
}
488
return getSlotFont(localeSlot).useAAForPtSize(ptsize);
489
}
490
491
public String toString() {
492
String ls = System.lineSeparator();
493
String componentsStr = "";
494
for (int i=0; i<numSlots; i++) {
495
componentsStr += " Slot["+i+"]="+getSlotFont(i)+ls;
496
}
497
return "** Composite Font: Family=" + familyName +
498
" Name=" + fullName + " style=" + style + ls + componentsStr;
499
}
500
}
501
502