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+
26+package sun.awt;
27+
28+import java.awt.peer.FontPeer;
29+import java.util.Locale;
30+import java.util.Vector;
31+import sun.font.SunFontManager;
32+import sun.java2d.FontSupport;
33+import java.nio.CharBuffer;
34+import java.nio.ByteBuffer;
35+
36+public 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+}