Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/sun/font/CompositeGlyphMapper.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
/* remember that the API requires a Font use a
29
* consistent glyph id. for a code point, and this is a
30
* problem if a particular strike uses native scaler sometimes
31
* and the JDK scaler others. That needs to be dealt with somewhere, but
32
* here we can just always get the same glyph code without
33
* needing a strike.
34
*
35
* The C implementation would cache the results of anything up
36
* to the maximum surrogate pair code point.
37
* This implementation will not cache as much, since the storage
38
* requirements are not justifiable. Even so it still can use up
39
* to 216*256*4 bytes of storage per composite font. If an app
40
* calls canDisplay on this range for all 20 composite fonts that's
41
* over 1Mb of cached data. May need to employ WeakReferences if
42
* this appears to cause problems.
43
*/
44
45
public class CompositeGlyphMapper extends CharToGlyphMapper {
46
47
public static final int SLOTMASK = 0xff000000;
48
public static final int GLYPHMASK = 0x00ffffff;
49
50
public static final int NBLOCKS = 216;
51
public static final int BLOCKSZ = 256;
52
public static final int MAXUNICODE = NBLOCKS*BLOCKSZ;
53
54
55
CompositeFont font;
56
CharToGlyphMapper[] slotMappers;
57
int[][] glyphMaps;
58
private boolean hasExcludes;
59
60
public CompositeGlyphMapper(CompositeFont compFont) {
61
font = compFont;
62
initMapper();
63
/* This is often false which saves the overhead of a
64
* per-mapped char method call.
65
*/
66
hasExcludes = compFont.exclusionRanges != null &&
67
compFont.maxIndices != null;
68
}
69
70
public int compositeGlyphCode(int slot, int glyphCode) {
71
return (slot << 24 | (glyphCode & GLYPHMASK));
72
}
73
74
private void initMapper() {
75
if (missingGlyph == CharToGlyphMapper.UNINITIALIZED_GLYPH) {
76
if (glyphMaps == null) {
77
glyphMaps = new int[NBLOCKS][];
78
}
79
slotMappers = new CharToGlyphMapper[font.numSlots];
80
/* This requires that slot 0 is never empty. */
81
missingGlyph = font.getSlotFont(0).getMissingGlyphCode();
82
missingGlyph = compositeGlyphCode(0, missingGlyph);
83
}
84
}
85
86
private int getCachedGlyphCode(int unicode) {
87
if (unicode >= MAXUNICODE) {
88
return UNINITIALIZED_GLYPH; // don't cache surrogates
89
}
90
int[] gmap;
91
if ((gmap = glyphMaps[unicode >> 8]) == null) {
92
return UNINITIALIZED_GLYPH;
93
}
94
return gmap[unicode & 0xff];
95
}
96
97
private void setCachedGlyphCode(int unicode, int glyphCode) {
98
if (unicode >= MAXUNICODE) {
99
return; // don't cache surrogates
100
}
101
int index0 = unicode >> 8;
102
if (glyphMaps[index0] == null) {
103
glyphMaps[index0] = new int[BLOCKSZ];
104
for (int i=0;i<BLOCKSZ;i++) {
105
glyphMaps[index0][i] = UNINITIALIZED_GLYPH;
106
}
107
}
108
glyphMaps[index0][unicode & 0xff] = glyphCode;
109
}
110
111
private CharToGlyphMapper getSlotMapper(int slot) {
112
CharToGlyphMapper mapper = slotMappers[slot];
113
if (mapper == null) {
114
mapper = font.getSlotFont(slot).getMapper();
115
slotMappers[slot] = mapper;
116
}
117
return mapper;
118
}
119
120
private int convertToGlyph(int unicode) {
121
122
for (int slot = 0; slot < font.numSlots; slot++) {
123
if (!hasExcludes || !font.isExcludedChar(slot, unicode)) {
124
CharToGlyphMapper mapper = getSlotMapper(slot);
125
int glyphCode = mapper.charToGlyph(unicode);
126
if (glyphCode != mapper.getMissingGlyphCode()) {
127
glyphCode = compositeGlyphCode(slot, glyphCode);
128
setCachedGlyphCode(unicode, glyphCode);
129
return glyphCode;
130
}
131
}
132
}
133
return missingGlyph;
134
}
135
136
public int getNumGlyphs() {
137
int numGlyphs = 0;
138
/* The number of glyphs in a composite is affected by
139
* exclusion ranges and duplicates (ie the same code point is
140
* mapped by two different fonts) and also whether or not to
141
* count fallback fonts. A nearly correct answer would be very
142
* expensive to generate. A rough ballpark answer would
143
* just count the glyphs in all the slots. However this would
144
* initialize mappers for all slots when they aren't necessarily
145
* needed. For now just use the first slot as JDK 1.4 did.
146
*/
147
for (int slot=0; slot<1 /*font.numSlots*/; slot++) {
148
CharToGlyphMapper mapper = slotMappers[slot];
149
if (mapper == null) {
150
mapper = font.getSlotFont(slot).getMapper();
151
slotMappers[slot] = mapper;
152
}
153
numGlyphs += mapper.getNumGlyphs();
154
}
155
return numGlyphs;
156
}
157
158
public int charToGlyph(int unicode) {
159
160
int glyphCode = getCachedGlyphCode(unicode);
161
if (glyphCode == UNINITIALIZED_GLYPH) {
162
glyphCode = convertToGlyph(unicode);
163
}
164
return glyphCode;
165
}
166
167
public int charToGlyph(int unicode, int prefSlot) {
168
if (prefSlot >= 0) {
169
CharToGlyphMapper mapper = getSlotMapper(prefSlot);
170
int glyphCode = mapper.charToGlyph(unicode);
171
if (glyphCode != mapper.getMissingGlyphCode()) {
172
return compositeGlyphCode(prefSlot, glyphCode);
173
}
174
}
175
return charToGlyph(unicode);
176
}
177
178
public int charToGlyph(char unicode) {
179
180
int glyphCode = getCachedGlyphCode(unicode);
181
if (glyphCode == UNINITIALIZED_GLYPH) {
182
glyphCode = convertToGlyph(unicode);
183
}
184
return glyphCode;
185
}
186
187
/* This variant checks if shaping is needed and immediately
188
* returns true if it does. A caller of this method should be expecting
189
* to check the return type because it needs to know how to handle
190
* the character data for display.
191
*/
192
public boolean charsToGlyphsNS(int count, char[] unicodes, int[] glyphs) {
193
194
for (int i=0; i<count; i++) {
195
int code = unicodes[i]; // char is unsigned.
196
197
if (code >= HI_SURROGATE_START &&
198
code <= HI_SURROGATE_END && i < count - 1) {
199
char low = unicodes[i + 1];
200
201
if (low >= LO_SURROGATE_START &&
202
low <= LO_SURROGATE_END) {
203
code = (code - HI_SURROGATE_START) *
204
0x400 + low - LO_SURROGATE_START + 0x10000;
205
glyphs[i + 1] = INVISIBLE_GLYPH_ID;
206
}
207
}
208
209
int gc = glyphs[i] = getCachedGlyphCode(code);
210
if (gc == UNINITIALIZED_GLYPH) {
211
glyphs[i] = convertToGlyph(code);
212
}
213
214
if (code < FontUtilities.MIN_LAYOUT_CHARCODE) {
215
continue;
216
}
217
else if (FontUtilities.isComplexCharCode(code) ||
218
CharToGlyphMapper.isVariationSelector(code)) {
219
return true;
220
}
221
else if (code >= 0x10000) {
222
i += 1; // Empty glyph slot after surrogate
223
continue;
224
}
225
}
226
227
return false;
228
}
229
230
/* The conversion is not very efficient - looping as it does, converting
231
* one char at a time. However the cache should fill very rapidly.
232
*/
233
public void charsToGlyphs(int count, char[] unicodes, int[] glyphs) {
234
for (int i=0; i<count; i++) {
235
int code = unicodes[i]; // char is unsigned.
236
237
if (code >= HI_SURROGATE_START &&
238
code <= HI_SURROGATE_END && i < count - 1) {
239
char low = unicodes[i + 1];
240
241
if (low >= LO_SURROGATE_START &&
242
low <= LO_SURROGATE_END) {
243
code = (code - HI_SURROGATE_START) *
244
0x400 + low - LO_SURROGATE_START + 0x10000;
245
246
int gc = glyphs[i] = getCachedGlyphCode(code);
247
if (gc == UNINITIALIZED_GLYPH) {
248
glyphs[i] = convertToGlyph(code);
249
}
250
i += 1; // Empty glyph slot after surrogate
251
glyphs[i] = INVISIBLE_GLYPH_ID;
252
continue;
253
}
254
}
255
256
int gc = glyphs[i] = getCachedGlyphCode(code);
257
if (gc == UNINITIALIZED_GLYPH) {
258
glyphs[i] = convertToGlyph(code);
259
}
260
}
261
}
262
263
public void charsToGlyphs(int count, int[] unicodes, int[] glyphs) {
264
for (int i=0; i<count; i++) {
265
int code = unicodes[i];
266
267
glyphs[i] = getCachedGlyphCode(code);
268
if (glyphs[i] == UNINITIALIZED_GLYPH) {
269
glyphs[i] = convertToGlyph(code);
270
}
271
}
272
}
273
274
}
275
276