History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/awt/PlatformFont.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/awt/PlatformFont.java+440−0
@@ -0,0 +1,440 @@
1/*
2 * Copyright (c) 1996, 2010, 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
26package sun.awt;
27
28import java.awt.peer.FontPeer;
29import java.util.Locale;
30import java.util.Vector;
31import sun.font.SunFontManager;
32import sun.java2d.FontSupport;
33import java.nio.CharBuffer;
34import java.nio.ByteBuffer;
35
36public abstract class PlatformFont implements FontPeer {
37
38 static {
39 NativeLibLoader.loadLibraries();
40 initIDs();
41 }
42
43 protected FontDescriptor[] componentFonts;
44 protected char defaultChar;
45 protected FontConfiguration fontConfig;
46
47 protected FontDescriptor defaultFont;
48
49 protected String familyName;
50
51 private Object[] fontCache;
52
53 // Maybe this should be a property that is set based
54 // on the locale?
55 protected static int FONTCACHESIZE = 256;
56 protected static int FONTCACHEMASK = PlatformFont.FONTCACHESIZE - 1;
57 protected static String osVersion;
58
59 public PlatformFont(String name, int style){
60 SunFontManager sfm = SunFontManager.getInstance();
61 if (sfm instanceof FontSupport) {
62 fontConfig = ((FontSupport)sfm).getFontConfiguration();
63 }
64 if (fontConfig == null) {
65 return;
66 }
67
68 // map given font name to a valid logical font family name
69 familyName = name.toLowerCase(Locale.ENGLISH);
70 if (!FontConfiguration.isLogicalFontFamilyName(familyName)) {
71 familyName = fontConfig.getFallbackFamilyName(familyName, "sansserif");
72 }
73
74 componentFonts = fontConfig.getFontDescriptors(familyName, style);
75
76 // search default character
77 //
78 char missingGlyphCharacter = getMissingGlyphCharacter();
79
80 defaultChar = '?';
81 if (componentFonts.length > 0)
82 defaultFont = componentFonts[0];
83
84 for (int i = 0; i < componentFonts.length; i++){
85 if (componentFonts[i].isExcluded(missingGlyphCharacter)) {
86 continue;
87 }
88
89 if (componentFonts[i].encoder.canEncode(missingGlyphCharacter)) {
90 defaultFont = componentFonts[i];
91 defaultChar = missingGlyphCharacter;
92 break;
93 }
94 }
95 }
96
97 /**
98 * Returns the character that should be rendered when a glyph
99 * is missing.
100 */
101 protected abstract char getMissingGlyphCharacter();
102
103 /**
104 * make a array of CharsetString with given String.
105 */
106 public CharsetString[] makeMultiCharsetString(String str){
107 return makeMultiCharsetString(str.toCharArray(), 0, str.length(), true);
108 }
109
110 /**
111 * make a array of CharsetString with given String.
112 */
113 public CharsetString[] makeMultiCharsetString(String str, boolean allowdefault){
114 return makeMultiCharsetString(str.toCharArray(), 0, str.length(), allowdefault);
115 }
116
117 /**
118 * make a array of CharsetString with given char array.
119 * @param str The char array to convert.
120 * @param offset offset of first character of interest
121 * @param len number of characters to convert
122 */
123 public CharsetString[] makeMultiCharsetString(char str[], int offset, int len) {
124 return makeMultiCharsetString(str, offset, len, true);
125 }
126
127 /**
128 * make a array of CharsetString with given char array.
129 * @param str The char array to convert.
130 * @param offset offset of first character of interest
131 * @param len number of characters to convert
132 * @param allowDefault whether to allow the default char.
133 * Setting this to true overloads the meaning of this method to
134 * return non-null only if all chars can be converted.
135 * @return array of CharsetString or if allowDefault is false and any
136 * of the returned chars would have been converted to a default char,
137 * then return null.
138 * This is used to choose alternative means of displaying the text.
139 */
140 public CharsetString[] makeMultiCharsetString(char str[], int offset, int len,
141 boolean allowDefault) {
142
143 if (len < 1) {
144 return new CharsetString[0];
145 }
146 Vector mcs = null;
147 char[] tmpStr = new char[len];
148 char tmpChar = defaultChar;
149 boolean encoded = false;
150
151 FontDescriptor currentFont = defaultFont;
152
153
154 for (int i = 0; i < componentFonts.length; i++) {
155 if (componentFonts[i].isExcluded(str[offset])){
156 continue;
157 }
158
159 /* Need "encoded" variable to distinguish the case when
160 * the default char is the same as the encoded char.
161 * The defaultChar on Linux is '?' so it is needed there.
162 */
163 if (componentFonts[i].encoder.canEncode(str[offset])){
164 currentFont = componentFonts[i];
165 tmpChar = str[offset];
166 encoded = true;
167 break;
168 }
169 }
170 if (!allowDefault && !encoded) {
171 return null;
172 } else {
173 tmpStr[0] = tmpChar;
174 }
175
176 int lastIndex = 0;
177 for (int i = 1; i < len; i++){
178 char ch = str[offset + i];
179 FontDescriptor fd = defaultFont;
180 tmpChar = defaultChar;
181 encoded = false;
182 for (int j = 0; j < componentFonts.length; j++){
183 if (componentFonts[j].isExcluded(ch)){
184 continue;
185 }
186
187 if (componentFonts[j].encoder.canEncode(ch)){
188 fd = componentFonts[j];
189 tmpChar = ch;
190 encoded = true;
191 break;
192 }
193 }
194 if (!allowDefault && !encoded) {
195 return null;
196 } else {
197 tmpStr[i] = tmpChar;
198 }
199 if (currentFont != fd){
200 if (mcs == null) {
201 mcs = new Vector(3);
202 }
203 mcs.addElement(new CharsetString(tmpStr, lastIndex,
204 i-lastIndex, currentFont));
205 currentFont = fd;
206 fd = defaultFont;
207 lastIndex = i;
208 }
209 }
210 CharsetString[] result;
211 CharsetString cs = new CharsetString(tmpStr, lastIndex,
212 len-lastIndex, currentFont);
213 if (mcs == null) {
214 result = new CharsetString[1];
215 result[0] = cs;
216 } else {
217 mcs.addElement(cs);
218 result = new CharsetString[mcs.size()];
219 for (int i = 0; i < mcs.size(); i++){
220 result[i] = (CharsetString)mcs.elementAt(i);
221 }
222 }
223 return result;
224 }
225
226 /**
227 * Is it possible that this font's metrics require the multi-font calls?
228 * This might be true, for example, if the font supports kerning.
229 **/
230 public boolean mightHaveMultiFontMetrics() {
231 return fontConfig != null;
232 }
233
234 /**
235 * Specialized fast path string conversion for AWT.
236 */
237 public Object[] makeConvertedMultiFontString(String str)
238 {
239 return makeConvertedMultiFontChars(str.toCharArray(),0,str.length());
240 }
241
242 public Object[] makeConvertedMultiFontChars(char[] data,
243 int start, int len)
244 {
245 Object[] result = new Object[2];
246 Object[] workingCache;
247 byte[] convertedData = null;
248 int stringIndex = start;
249 int convertedDataIndex = 0;
250 int resultIndex = 0;
251 int cacheIndex;
252 FontDescriptor currentFontDescriptor = null;
253 FontDescriptor lastFontDescriptor = null;
254 char currentDefaultChar;
255 PlatformFontCache theChar;
256
257 // Simple bounds check
258 int end = start + len;
259 if (start < 0 || end > data.length) {
260 throw new ArrayIndexOutOfBoundsException();
261 }
262
263 if(stringIndex >= end) {
264 return null;
265 }
266
267 // coversion loop
268 while(stringIndex < end)
269 {
270 currentDefaultChar = data[stringIndex];
271
272 // Note that cache sizes must be a power of two!
273 cacheIndex = (int)(currentDefaultChar & this.FONTCACHEMASK);
274
275 theChar = (PlatformFontCache)getFontCache()[cacheIndex];
276
277 // Is the unicode char we want cached?
278 if(theChar == null || theChar.uniChar != currentDefaultChar)
279 {
280 /* find a converter that can convert the current character */
281 currentFontDescriptor = defaultFont;
282 currentDefaultChar = defaultChar;
283 char ch = (char)data[stringIndex];
284 int componentCount = componentFonts.length;
285
286 for (int j = 0; j < componentCount; j++) {
287 FontDescriptor fontDescriptor = componentFonts[j];
288
289 fontDescriptor.encoder.reset();
290 //fontDescriptor.encoder.onUnmappleCharacterAction(...);
291
292 if (fontDescriptor.isExcluded(ch)) {
293 continue;
294 }
295 if (fontDescriptor.encoder.canEncode(ch)) {
296 currentFontDescriptor = fontDescriptor;
297 currentDefaultChar = ch;
298 break;
299 }
300 }
301 try {
302 char[] input = new char[1];
303 input[0] = currentDefaultChar;
304
305 theChar = new PlatformFontCache();
306 if (currentFontDescriptor.useUnicode()) {
307 /*
308 currentFontDescriptor.unicodeEncoder.encode(CharBuffer.wrap(input),
309 theChar.bb,
310 true);
311 */
312 if (currentFontDescriptor.isLE) {
313 theChar.bb.put((byte)(input[0] & 0xff));
314 theChar.bb.put((byte)(input[0] >>8));
315 } else {
316 theChar.bb.put((byte)(input[0] >> 8));
317 theChar.bb.put((byte)(input[0] & 0xff));
318 }
319 }
320 else {
321 currentFontDescriptor.encoder.encode(CharBuffer.wrap(input),
322 theChar.bb,
323 true);
324 }
325 theChar.fontDescriptor = currentFontDescriptor;
326 theChar.uniChar = data[stringIndex];
327 getFontCache()[cacheIndex] = theChar;
328 } catch(Exception e){
329 // Should never happen!
330 System.err.println(e);
331 e.printStackTrace();
332 return null;
333 }
334 }
335
336 // Check to see if we've changed fonts.
337 if(lastFontDescriptor != theChar.fontDescriptor) {
338 if(lastFontDescriptor != null) {
339 result[resultIndex++] = lastFontDescriptor;
340 result[resultIndex++] = convertedData;
341 // Add the size to the converted data field.
342 if(convertedData != null) {
343 convertedDataIndex -= 4;
344 convertedData[0] = (byte)(convertedDataIndex >> 24);
345 convertedData[1] = (byte)(convertedDataIndex >> 16);
346 convertedData[2] = (byte)(convertedDataIndex >> 8);
347 convertedData[3] = (byte)convertedDataIndex;
348 }
349
350 if(resultIndex >= result.length) {
351 Object[] newResult = new Object[result.length * 2];
352
353 System.arraycopy(result, 0, newResult, 0,
354 result.length);
355 result = newResult;
356 }
357 }
358
359 if (theChar.fontDescriptor.useUnicode()) {
360 convertedData = new byte[(end - stringIndex + 1) *
361 (int)theChar.fontDescriptor.unicodeEncoder.maxBytesPerChar()
362 + 4];
363 }
364 else {
365 convertedData = new byte[(end - stringIndex + 1) *
366 (int)theChar.fontDescriptor.encoder.maxBytesPerChar()
367 + 4];
368 }
369
370 convertedDataIndex = 4;
371
372 lastFontDescriptor = theChar.fontDescriptor;
373 }
374
375 byte[] ba = theChar.bb.array();
376 int size = theChar.bb.position();
377 if(size == 1) {
378 convertedData[convertedDataIndex++] = ba[0];
379 }
380 else if(size == 2) {
381 convertedData[convertedDataIndex++] = ba[0];
382 convertedData[convertedDataIndex++] = ba[1];
383 } else if(size == 3) {
384 convertedData[convertedDataIndex++] = ba[0];
385 convertedData[convertedDataIndex++] = ba[1];
386 convertedData[convertedDataIndex++] = ba[2];
387 } else if(size == 4) {
388 convertedData[convertedDataIndex++] = ba[0];
389 convertedData[convertedDataIndex++] = ba[1];
390 convertedData[convertedDataIndex++] = ba[2];
391 convertedData[convertedDataIndex++] = ba[3];
392 }
393 stringIndex++;
394 }
395
396 result[resultIndex++] = lastFontDescriptor;
397 result[resultIndex] = convertedData;
398
399 // Add the size to the converted data field.
400 if(convertedData != null) {
401 convertedDataIndex -= 4;
402 convertedData[0] = (byte)(convertedDataIndex >> 24);
403 convertedData[1] = (byte)(convertedDataIndex >> 16);
404 convertedData[2] = (byte)(convertedDataIndex >> 8);
405 convertedData[3] = (byte)convertedDataIndex;
406 }
407 return result;
408 }
409
410 /*
411 * Create fontCache on demand instead of during construction to
412 * reduce overall memory consumption.
413 *
414 * This method is declared final so that its code can be inlined
415 * by the compiler.
416 */
417 protected final Object[] getFontCache() {
418 // This method is not MT-safe by design. Since this is just a
419 // cache anyways, it's okay if we occasionally allocate the array
420 // twice or return an array which will be dereferenced and gced
421 // right away.
422 if (fontCache == null) {
423 fontCache = new Object[this.FONTCACHESIZE];
424 }
425
426 return fontCache;
427 }
428
429 /**
430 * Initialize JNI field and method IDs
431 */
432 private static native void initIDs();
433
434 class PlatformFontCache
435 {
436 char uniChar;
437 FontDescriptor fontDescriptor;
438 ByteBuffer bb = ByteBuffer.allocate(4);
439 }
440}