Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/macosx/classes/sun/font/CCharToGlyphMapper.java
41153 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.util.HashMap;
29
30
public class CCharToGlyphMapper extends CharToGlyphMapper {
31
private static native int countGlyphs(final long nativeFontPtr);
32
33
private Cache cache = new Cache();
34
CFont fFont;
35
int numGlyphs = -1;
36
37
public CCharToGlyphMapper(CFont font) {
38
fFont = font;
39
missingGlyph = 0; // for getMissingGlyphCode()
40
}
41
42
public int getNumGlyphs() {
43
if (numGlyphs == -1) {
44
numGlyphs = countGlyphs(fFont.getNativeFontPtr());
45
}
46
return numGlyphs;
47
}
48
49
public boolean canDisplay(char ch) {
50
int glyph = charToGlyph(ch);
51
return glyph != missingGlyph;
52
}
53
54
public boolean canDisplay(int cp) {
55
int glyph = charToGlyph(cp);
56
return glyph != missingGlyph;
57
}
58
59
public synchronized boolean charsToGlyphsNS(int count,
60
char[] unicodes, int[] glyphs)
61
{
62
charsToGlyphs(count, unicodes, glyphs);
63
64
// The following shaping checks are from either
65
// TrueTypeGlyphMapper or Type1GlyphMapper
66
for (int i = 0; i < count; i++) {
67
int code = unicodes[i];
68
69
if (code >= HI_SURROGATE_START && code <= HI_SURROGATE_END && i < count - 1) {
70
char low = unicodes[i + 1];
71
72
if (low >= LO_SURROGATE_START && low <= LO_SURROGATE_END) {
73
code = (code - HI_SURROGATE_START) * 0x400 + low - LO_SURROGATE_START + 0x10000;
74
glyphs[i + 1] = INVISIBLE_GLYPH_ID;
75
}
76
}
77
78
if (code < FontUtilities.MIN_LAYOUT_CHARCODE) {
79
continue;
80
} else if (FontUtilities.isComplexCharCode(code)) {
81
return true;
82
} else if (code >= 0x10000) {
83
i += 1; // Empty glyph slot after surrogate
84
continue;
85
}
86
}
87
88
return false;
89
}
90
91
public synchronized int charToGlyph(char unicode) {
92
final int glyph = cache.get(unicode);
93
if (glyph != 0) return glyph;
94
95
final char[] unicodeArray = new char[] { unicode };
96
final int[] glyphArray = new int[1];
97
98
nativeCharsToGlyphs(fFont.getNativeFontPtr(), 1, unicodeArray, glyphArray);
99
cache.put(unicode, glyphArray[0]);
100
101
return glyphArray[0];
102
}
103
104
public synchronized int charToGlyph(int unicode) {
105
if (unicode >= 0x10000) {
106
int[] glyphs = new int[2];
107
char[] surrogates = new char[2];
108
int base = unicode - 0x10000;
109
surrogates[0] = (char)((base >>> 10) + HI_SURROGATE_START);
110
surrogates[1] = (char)((base % 0x400) + LO_SURROGATE_START);
111
charsToGlyphs(2, surrogates, glyphs);
112
return glyphs[0];
113
} else {
114
return charToGlyph((char)unicode);
115
}
116
}
117
118
public synchronized void charsToGlyphs(int count, char[] unicodes, int[] glyphs) {
119
cache.get(count, unicodes, glyphs);
120
}
121
122
public synchronized void charsToGlyphs(int count, int[] unicodes, int[] glyphs) {
123
for (int i = 0; i < count; i++) {
124
glyphs[i] = charToGlyph(unicodes[i]);
125
};
126
}
127
128
// This mapper returns either the glyph code, or if the character can be
129
// replaced on-the-fly using CoreText substitution; the negative unicode
130
// value. If this "glyph code int" is treated as an opaque code, it will
131
// strike and measure exactly as a real glyph code - whether the character
132
// is present or not. Missing characters for any font on the system will
133
// be returned as 0, as the getMissingGlyphCode() function above indicates.
134
private static native void nativeCharsToGlyphs(final long nativeFontPtr,
135
int count, char[] unicodes,
136
int[] glyphs);
137
138
private class Cache {
139
private static final int FIRST_LAYER_SIZE = 256;
140
private static final int SECOND_LAYER_SIZE = 16384; // 16384 = 128x128
141
142
private final int[] firstLayerCache = new int[FIRST_LAYER_SIZE];
143
private SparseBitShiftingTwoLayerArray secondLayerCache;
144
private HashMap<Integer, Integer> generalCache;
145
146
Cache() {
147
// <rdar://problem/5331678> need to prevent getting '-1' stuck in the cache
148
firstLayerCache[1] = 1;
149
}
150
151
public synchronized int get(final int index) {
152
if (index < FIRST_LAYER_SIZE) {
153
// catch common glyphcodes
154
return firstLayerCache[index];
155
}
156
157
if (index < SECOND_LAYER_SIZE) {
158
// catch common unicodes
159
if (secondLayerCache == null) return 0;
160
return secondLayerCache.get(index);
161
}
162
163
if (generalCache == null) return 0;
164
final Integer value = generalCache.get(index);
165
if (value == null) return 0;
166
return value.intValue();
167
}
168
169
public synchronized void put(final int index, final int value) {
170
if (index < FIRST_LAYER_SIZE) {
171
// catch common glyphcodes
172
firstLayerCache[index] = value;
173
return;
174
}
175
176
if (index < SECOND_LAYER_SIZE) {
177
// catch common unicodes
178
if (secondLayerCache == null) {
179
secondLayerCache = new SparseBitShiftingTwoLayerArray(SECOND_LAYER_SIZE, 7); // 128x128
180
}
181
secondLayerCache.put(index, value);
182
return;
183
}
184
185
if (generalCache == null) {
186
generalCache = new HashMap<Integer, Integer>();
187
}
188
189
generalCache.put(index, value);
190
}
191
192
private class SparseBitShiftingTwoLayerArray {
193
final int[][] cache;
194
final int shift;
195
final int secondLayerLength;
196
197
public SparseBitShiftingTwoLayerArray(final int size,
198
final int shift)
199
{
200
this.shift = shift;
201
this.cache = new int[1 << shift][];
202
this.secondLayerLength = size >> shift;
203
}
204
205
public int get(final int index) {
206
final int firstIndex = index >> shift;
207
final int[] firstLayerRow = cache[firstIndex];
208
if (firstLayerRow == null) return 0;
209
return firstLayerRow[index - (firstIndex * (1 << shift))];
210
}
211
212
public void put(final int index, final int value) {
213
final int firstIndex = index >> shift;
214
int[] firstLayerRow = cache[firstIndex];
215
if (firstLayerRow == null) {
216
cache[firstIndex] = firstLayerRow = new int[secondLayerLength];
217
}
218
firstLayerRow[index - (firstIndex * (1 << shift))] = value;
219
}
220
}
221
222
public synchronized void get(int count, char[] indicies, int[] values)
223
{
224
// "missed" is the count of 'char' that are not mapped.
225
// Surrogates count for 2.
226
// unmappedChars is the unique list of these chars.
227
// unmappedCharIndices is the location in the original array
228
int missed = 0;
229
char[] unmappedChars = null;
230
int [] unmappedCharIndices = null;
231
232
for (int i = 0; i < count; i++){
233
int code = indicies[i];
234
if (code >= HI_SURROGATE_START &&
235
code <= HI_SURROGATE_END && i < count - 1)
236
{
237
char low = indicies[i + 1];
238
if (low >= LO_SURROGATE_START && low <= LO_SURROGATE_END) {
239
code = (code - HI_SURROGATE_START) * 0x400 +
240
low - LO_SURROGATE_START + 0x10000;
241
}
242
}
243
244
final int value = get(code);
245
if (value != 0 && value != -1) {
246
values[i] = value;
247
if (code >= 0x10000) {
248
values[i+1] = INVISIBLE_GLYPH_ID;
249
i++;
250
}
251
} else {
252
values[i] = 0;
253
put(code, -1);
254
if (unmappedChars == null) {
255
// This is likely to be longer than we need,
256
// but is the simplest and cheapest option.
257
unmappedChars = new char[indicies.length];
258
unmappedCharIndices = new int[indicies.length];
259
}
260
unmappedChars[missed] = indicies[i];
261
unmappedCharIndices[missed] = i;
262
if (code >= 0x10000) { // was a surrogate pair
263
unmappedChars[++missed] = indicies[++i];
264
}
265
missed++;
266
}
267
}
268
269
if (missed == 0) {
270
return;
271
}
272
273
final int[] glyphCodes = new int[missed];
274
275
// bulk call to fill in the unmapped code points.
276
nativeCharsToGlyphs(fFont.getNativeFontPtr(),
277
missed, unmappedChars, glyphCodes);
278
279
for (int m = 0; m < missed; m++){
280
int i = unmappedCharIndices[m];
281
int code = unmappedChars[m];
282
if (code >= HI_SURROGATE_START &&
283
code <= HI_SURROGATE_END && m < missed - 1)
284
{
285
char low = unmappedChars[m + 1];
286
if (low >= LO_SURROGATE_START && low <= LO_SURROGATE_END) {
287
code = (code - HI_SURROGATE_START) * 0x400 +
288
low - LO_SURROGATE_START + 0x10000;
289
}
290
}
291
values[i] = glyphCodes[m];
292
put(code, values[i]);
293
if (code >= 0x10000) {
294
m++;
295
values[i + 1] = INVISIBLE_GLYPH_ID;
296
}
297
}
298
}
299
}
300
}
301
302