001: /*
002: * @(#)PlatformFont.java 1.33 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027: package sun.awt;
028:
029: import java.awt.Font;
030: import sun.awt.peer.FontPeer;
031: import java.util.Properties;
032: import java.util.Hashtable;
033: import java.util.Vector;
034: import java.io.InputStream;
035: import java.io.BufferedInputStream;
036: import sun.io.CharToByteConverter;
037: import sun.io.CharacterEncoding;
038: import sun.io.FileIO;
039: import sun.io.FileIOFactory;
040:
041: public abstract class PlatformFont implements FontPeer {
042: protected FontDescriptor[] componentFonts;
043: protected char defaultChar;
044: protected Properties props;
045: protected FontDescriptor defaultFont;
046: protected static Hashtable charsetRegistry = new Hashtable(5);
047: protected String aliasName;
048: protected String styleString;
049:
050: public PlatformFont() {
051: /* This is a dummy holder ... used in very special cases */
052: }
053:
054: public PlatformFont(String name, int style) {
055: if (fprops == null) {
056: // there is no default font properties
057: this .props = null;
058: return;
059: }
060: this .props = fprops;
061: aliasName = props.getProperty("alias" + "."
062: + name.toLowerCase());
063: if (aliasName == null)
064: aliasName = name.toLowerCase();
065: // check this name is correct or not
066: if ((props.getProperty(aliasName + ".0") == null)
067: && (props.getProperty(aliasName + ".plain.0") == null))
068: aliasName = "sansserif";
069: styleString = styleStr(style);
070: Vector compFonts = new Vector(5);
071: int numOfFonts = 0;
072: for (;; numOfFonts++) {
073: String index = String.valueOf(numOfFonts);
074: // search native font name
075: //
076: String nativeName = props.getProperty(aliasName + "."
077: + styleString + "." + index);
078: if (nativeName == null) {
079: nativeName = props.getProperty(aliasName + "." + index);
080: if (nativeName == null) {
081: break;
082: }
083: }
084: // search font charset
085: //
086: String fcName = props.getProperty("fontcharset."
087: + aliasName + "." + styleString + "." + index);
088: if (fcName == null) {
089: fcName = props.getProperty("fontcharset." + aliasName
090: + "." + index);
091: if (fcName == null) {
092: fcName = "default";
093: }
094: }
095: CharToByteConverter fontCharset = getFontCharset(fcName
096: .trim(), nativeName);
097: // search exclusion range for this font
098: //
099: String exString = props.getProperty("exclusion."
100: + aliasName + "." + styleString + "." + index);
101: if (exString == null) {
102: exString = props.getProperty("exclusion." + aliasName
103: + "." + index);
104: if (exString == null) {
105: exString = "none";
106: }
107: }
108: int[] exRange;
109: if (exString.equals("none")) {
110: exRange = new int[0];
111: } else {
112: /*
113: * range format is xxxx-XXXX,yyyy-YYYY,.....
114: */
115: int numRange = 1, idx = 0;
116: for (;; numRange++) {
117: idx = exString.indexOf(',', idx);
118: if (idx == -1) {
119: break;
120: }
121: idx++;
122: }
123: exRange = new int[numRange];
124: for (int j = 0; j < numRange; j++) {
125: String lower, upper;
126: int lo = 0, up = 0;
127: try {
128: lower = exString.substring(j * 10, j * 10 + 4);
129: upper = exString.substring(j * 10 + 5,
130: j * 10 + 9);
131: } catch (StringIndexOutOfBoundsException e) {
132: exRange = new int[0];
133: break;
134: }
135: try {
136: lo = Integer.parseInt(lower, 16);
137: up = Integer.parseInt(upper, 16);
138: } catch (NumberFormatException e) {
139: exRange = new int[0];
140: break;
141: }
142: exRange[j] = lo << 16 | up;
143: }
144: }
145: compFonts.addElement(new FontDescriptor(nativeName,
146: fontCharset, exRange));
147: }
148: componentFonts = new FontDescriptor[numOfFonts];
149: for (int i = 0; i < numOfFonts; i++) {
150: componentFonts[i] = (FontDescriptor) compFonts.elementAt(i);
151: }
152: // search default character
153: //
154: int dfChar;
155: try {
156: dfChar = Integer.parseInt(props.getProperty("default.char",
157: "003f"), 16);
158: } catch (NumberFormatException e) {
159: dfChar = 0x3f;
160: }
161: defaultChar = 0x3f;
162: if (componentFonts.length > 0)
163: defaultFont = componentFonts[0];
164: for (int i = 0; i < componentFonts.length; i++) {
165: if (componentFonts[i].isExcluded((char) dfChar)) {
166: continue;
167: }
168: if (componentFonts[i].fontCharset.canConvert((char) dfChar)) {
169: defaultFont = componentFonts[i];
170: defaultChar = (char) dfChar;
171: break;
172: }
173: }
174: }
175:
176: /**
177: * Is it possible that this font's metrics require the multi-font calls?
178: * This might be true, for example, if the font supports kerning.
179: **/
180: public boolean mightHaveMultiFontMetrics() {
181: return props != null;
182: }
183:
184: /*
185: * make default font properties.
186: */
187: protected static Properties fprops;
188: static {
189: // initialize fprops
190:
191: // Find property file
192: fprops = (Properties) java.security.AccessController
193: .doPrivileged(new java.security.PrivilegedAction() {
194: public Object run() {
195: Properties fpr = null;
196: String jhome = System.getProperty("java.home");
197: String uhome = System.getProperty("user.home");
198: if (jhome == null) {
199: throw new Error(
200: "java.home property not set");
201: }
202: String language = System.getProperty(
203: "user.language", "en");
204: String region = System
205: .getProperty("user.region");
206: // Translate the raw encoding name returned by the VM to the canonical
207: // name from the alias table in CharacterEncoding. Map unlisted raw
208: // encoding names to themselves. - bug 4163038
209: String rawEncoding = System
210: .getProperty("file.encoding");
211: String encoding = CharacterEncoding
212: .aliasName(rawEncoding);
213: if (encoding == null) {
214: encoding = rawEncoding;
215: }
216: try {
217: FileIO f = null;
218: if (region != null) {
219: f = tryOpeningFontProp(f, uhome,
220: language, region + "_"
221: + encoding);
222: f = tryOpeningFontProp(f, jhome,
223: language, region + "_"
224: + encoding);
225: f = tryOpeningFontProp(f, uhome,
226: language, region);
227: f = tryOpeningFontProp(f, jhome,
228: language, region);
229: }
230: f = tryOpeningFontProp(f, uhome, language,
231: encoding);
232: f = tryOpeningFontProp(f, jhome, language,
233: encoding);
234: f = tryOpeningFontProp(f, uhome, language,
235: null);
236: f = tryOpeningFontProp(f, jhome, language,
237: null);
238: f = tryOpeningFontProp(f, uhome, encoding,
239: null);
240: f = tryOpeningFontProp(f, jhome, encoding,
241: null);
242: f = tryOpeningFontProp(f, uhome, null, null);
243: f = tryOpeningFontProp(f, jhome, null, null);
244: // set default props to prevent crashing
245: // with corrupted font.properties
246: Properties defaultProps = new Properties();
247: defaultProps.put("serif.0", "unknown");
248: defaultProps.put("sansserif.0", "unknown");
249: defaultProps.put("monospaced.0", "unknown");
250: defaultProps.put("dialog.0", "unknown");
251: defaultProps
252: .put("dialoginput.0", "unknown");
253: fpr = new Properties(defaultProps);
254: // Load property file
255: InputStream in = new BufferedInputStream(f
256: .getInputStream());
257: fpr.load(in);
258: in.close();
259: } catch (Exception e) {
260: }
261: return fpr;
262: }
263: });
264: }
265:
266: private static FileIO tryOpeningFontProp(FileIO f, String homedir,
267: String language, String ext) {
268: if (f != null) {
269: return f; // already validated
270: }
271: String filename = homedir + FileIO.separator + "lib"
272: + FileIO.separator + "font.properties";
273: if (language != null) {
274: filename += "." + language;
275: if (ext != null) {
276: filename += "_" + ext;
277: }
278: }
279: FileIO propsFile = FileIOFactory.newInstance(filename);
280: if ((propsFile != null) && propsFile.canRead()) {
281: return propsFile;
282: }
283: return null;
284: }
285:
286: /**
287: * make a array of CharsetString with given String.
288: */
289: public CharsetString[] makeMultiCharsetString(String str) {
290: return makeMultiCharsetString(str.toCharArray(), 0, str
291: .length());
292: }
293:
294: /**
295: * make a array of CharsetString with given char array.
296: * @param str The char array to convert.
297: * @param offset offset of first character of interest
298: * @param len number of characters to convert
299: */
300: public CharsetString[] makeMultiCharsetString(char str[],
301: int offset, int len) {
302: if (len < 1) {
303: return new CharsetString[0];
304: }
305: Vector mcs = null;
306: char[] tmpStr = new char[len];
307: char tmpChar = defaultChar;
308: FontDescriptor currentFont = defaultFont;
309: for (int i = 0; i < componentFonts.length; i++) {
310: if (componentFonts[i].isExcluded(str[offset])) {
311: continue;
312: }
313: if (componentFonts[i].fontCharset.canConvert(str[offset])) {
314: currentFont = componentFonts[i];
315: tmpChar = str[offset];
316: break;
317: }
318: }
319: tmpStr[0] = tmpChar;
320: int lastIndex = 0;
321: for (int i = 1; i < len; i++) {
322: char ch = str[offset + i];
323: FontDescriptor fd = defaultFont;
324: tmpChar = defaultChar;
325: for (int j = 0; j < componentFonts.length; j++) {
326: if (componentFonts[j].isExcluded(ch)) {
327: continue;
328: }
329: if (componentFonts[j].fontCharset.canConvert(ch)) {
330: fd = componentFonts[j];
331: tmpChar = ch;
332: break;
333: }
334: }
335: tmpStr[i] = tmpChar;
336: if (currentFont != fd) {
337: if (mcs == null) {
338: mcs = new Vector(3);
339: }
340: mcs.addElement(new CharsetString(tmpStr, lastIndex, i
341: - lastIndex, currentFont));
342: currentFont = fd;
343: fd = defaultFont;
344: lastIndex = i;
345: }
346: }
347: CharsetString[] result;
348: CharsetString cs = new CharsetString(tmpStr, lastIndex, len
349: - lastIndex, currentFont);
350: if (mcs == null) {
351: result = new CharsetString[1];
352: result[0] = cs;
353: } else {
354: mcs.addElement(cs);
355: result = new CharsetString[mcs.size()];
356: for (int i = 0; i < mcs.size(); i++) {
357: result[i] = (CharsetString) mcs.elementAt(i);
358: }
359: }
360: return result;
361: }
362:
363: protected abstract CharToByteConverter getFontCharset(
364: String charsetName, String fontName);
365:
366: /*
367: * return String representation of style
368: */
369: public static String styleStr(int num) {
370: switch (num) {
371: case Font.BOLD:
372: return "bold";
373:
374: case Font.ITALIC:
375: return "italic";
376:
377: case Font.ITALIC + Font.BOLD:
378: return "bolditalic";
379:
380: default:
381: return "plain";
382: }
383: }
384:
385: public String getNativeName(FontDescriptor fd) {
386: return fd.nativeName;
387: }
388: }
|