/*
* @(#)PlatformFont.java 1.33 06/10/10
*
* Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*
*/
package sun.awt;
import java.awt.Font;
import sun.awt.peer.FontPeer;
import java.util.Properties;
import java.util.Hashtable;
import java.util.Vector;
import java.io.InputStream;
import java.io.BufferedInputStream;
import sun.io.CharToByteConverter;
import sun.io.CharacterEncoding;
import sun.io.FileIO;
import sun.io.FileIOFactory;
public abstract class PlatformFont implements FontPeer {
protected FontDescriptor[] componentFonts;
protected char defaultChar;
protected Properties props;
protected FontDescriptor defaultFont;
protected static Hashtable charsetRegistry = new Hashtable(5);
protected String aliasName;
protected String styleString;
public PlatformFont() {
/* This is a dummy holder ... used in very special cases */
}
public PlatformFont(String name, int style) {
if (fprops == null) {
// there is no default font properties
this.props = null;
return;
}
this.props = fprops;
aliasName = props.getProperty("alias" + "." +
name.toLowerCase());
if (aliasName == null)
aliasName = name.toLowerCase();
// check this name is correct or not
if ((props.getProperty(aliasName + ".0") == null) &&
(props.getProperty(aliasName + ".plain.0") == null))
aliasName = "sansserif";
styleString = styleStr(style);
Vector compFonts = new Vector(5);
int numOfFonts = 0;
for (;; numOfFonts++) {
String index = String.valueOf(numOfFonts);
// search native font name
//
String nativeName = props.getProperty
(aliasName + "." + styleString + "." + index);
if (nativeName == null) {
nativeName = props.getProperty(aliasName + "." + index);
if (nativeName == null) {
break;
}
}
// search font charset
//
String fcName = props.getProperty
("fontcharset." + aliasName + "." + styleString + "." + index);
if (fcName == null) {
fcName = props.getProperty
("fontcharset." + aliasName + "." + index);
if (fcName == null) {
fcName = "default";
}
}
CharToByteConverter
fontCharset = getFontCharset(fcName.trim(), nativeName);
// search exclusion range for this font
//
String exString = props.getProperty
("exclusion." + aliasName + "." + styleString + "." + index);
if (exString == null) {
exString = props.getProperty
("exclusion." + aliasName + "." + index);
if (exString == null) {
exString = "none";
}
}
int[] exRange;
if (exString.equals("none")) {
exRange = new int[0];
} else {
/*
* range format is xxxx-XXXX,yyyy-YYYY,.....
*/
int numRange = 1, idx = 0;
for (;; numRange++) {
idx = exString.indexOf(',', idx);
if (idx == -1) {
break;
}
idx++;
}
exRange = new int[numRange];
for (int j = 0; j < numRange; j++) {
String lower, upper;
int lo = 0, up = 0;
try {
lower = exString.substring(j * 10, j * 10 + 4);
upper = exString.substring(j * 10 + 5, j * 10 + 9);
} catch (StringIndexOutOfBoundsException e) {
exRange = new int[0];
break;
}
try {
lo = Integer.parseInt(lower, 16);
up = Integer.parseInt(upper, 16);
} catch (NumberFormatException e) {
exRange = new int[0];
break;
}
exRange[j] = lo << 16 | up;
}
}
compFonts.addElement(new FontDescriptor(nativeName,
fontCharset,
exRange));
}
componentFonts = new FontDescriptor[numOfFonts];
for (int i = 0; i < numOfFonts; i++) {
componentFonts[i] = (FontDescriptor) compFonts.elementAt(i);
}
// search default character
//
int dfChar;
try {
dfChar = Integer.parseInt
(props.getProperty("default.char", "003f"), 16);
} catch (NumberFormatException e) {
dfChar = 0x3f;
}
defaultChar = 0x3f;
if (componentFonts.length > 0)
defaultFont = componentFonts[0];
for (int i = 0; i < componentFonts.length; i++) {
if (componentFonts[i].isExcluded((char) dfChar)) {
continue;
}
if (componentFonts[i].fontCharset.canConvert((char) dfChar)) {
defaultFont = componentFonts[i];
defaultChar = (char) dfChar;
break;
}
}
}
/**
* Is it possible that this font's metrics require the multi-font calls?
* This might be true, for example, if the font supports kerning.
**/
public boolean mightHaveMultiFontMetrics() {
return props != null;
}
/*
* make default font properties.
*/
protected static Properties fprops;
static {
// initialize fprops
// Find property file
fprops = (Properties) java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
Properties fpr = null;
String jhome = System.getProperty("java.home");
String uhome = System.getProperty("user.home");
if (jhome == null) {
throw new Error("java.home property not set");
}
String language = System.getProperty("user.language", "en");
String region = System.getProperty("user.region");
// Translate the raw encoding name returned by the VM to the canonical
// name from the alias table in CharacterEncoding. Map unlisted raw
// encoding names to themselves. - bug 4163038
String rawEncoding = System.getProperty("file.encoding");
String encoding = CharacterEncoding.aliasName(rawEncoding);
if (encoding == null) {
encoding = rawEncoding;
}
try {
FileIO f = null;
if (region != null) {
f = tryOpeningFontProp(
f, uhome, language, region + "_" + encoding);
f = tryOpeningFontProp(
f, jhome, language, region + "_" + encoding);
f = tryOpeningFontProp(f, uhome, language, region);
f = tryOpeningFontProp(f, jhome, language, region);
}
f = tryOpeningFontProp(f, uhome, language, encoding);
f = tryOpeningFontProp(f, jhome, language, encoding);
f = tryOpeningFontProp(f, uhome, language, null);
f = tryOpeningFontProp(f, jhome, language, null);
f = tryOpeningFontProp(f, uhome, encoding, null);
f = tryOpeningFontProp(f, jhome, encoding, null);
f = tryOpeningFontProp(f, uhome, null, null);
f = tryOpeningFontProp(f, jhome, null, null);
// set default props to prevent crashing
// with corrupted font.properties
Properties defaultProps = new Properties();
defaultProps.put("serif.0", "unknown");
defaultProps.put("sansserif.0", "unknown");
defaultProps.put("monospaced.0", "unknown");
defaultProps.put("dialog.0", "unknown");
defaultProps.put("dialoginput.0", "unknown");
fpr = new Properties(defaultProps);
// Load property file
InputStream in = new BufferedInputStream(f.getInputStream());
fpr.load(in);
in.close();
} catch (Exception e) {}
return fpr;
}
}
);
}
private static FileIO tryOpeningFontProp(
FileIO f, String homedir,
String language, String ext) {
if (f != null) {
return f; // already validated
}
String filename = homedir + FileIO.separator
+ "lib" + FileIO.separator
+ "font.properties";
if (language != null) {
filename += "." + language;
if (ext != null) {
filename += "_" + ext;
}
}
FileIO propsFile = FileIOFactory.newInstance(filename);
if ((propsFile != null) && propsFile.canRead()) {
return propsFile;
}
return null;
}
/**
* make a array of CharsetString with given String.
*/
public CharsetString[] makeMultiCharsetString(String str) {
return makeMultiCharsetString(str.toCharArray(), 0, str.length());
}
/**
* make a array of CharsetString with given char array.
* @param str The char array to convert.
* @param offset offset of first character of interest
* @param len number of characters to convert
*/
public CharsetString[] makeMultiCharsetString(char str[], int offset, int len) {
if (len < 1) {
return new CharsetString[0];
}
Vector mcs = null;
char[] tmpStr = new char[len];
char tmpChar = defaultChar;
FontDescriptor currentFont = defaultFont;
for (int i = 0; i < componentFonts.length; i++) {
if (componentFonts[i].isExcluded(str[offset])) {
continue;
}
if (componentFonts[i].fontCharset.canConvert(str[offset])) {
currentFont = componentFonts[i];
tmpChar = str[offset];
break;
}
}
tmpStr[0] = tmpChar;
int lastIndex = 0;
for (int i = 1; i < len; i++) {
char ch = str[offset + i];
FontDescriptor fd = defaultFont;
tmpChar = defaultChar;
for (int j = 0; j < componentFonts.length; j++) {
if (componentFonts[j].isExcluded(ch)) {
continue;
}
if (componentFonts[j].fontCharset.canConvert(ch)) {
fd = componentFonts[j];
tmpChar = ch;
break;
}
}
tmpStr[i] = tmpChar;
if (currentFont != fd) {
if (mcs == null) {
mcs = new Vector(3);
}
mcs.addElement(new CharsetString(tmpStr, lastIndex,
i - lastIndex, currentFont));
currentFont = fd;
fd = defaultFont;
lastIndex = i;
}
}
CharsetString[] result;
CharsetString cs = new CharsetString(tmpStr, lastIndex,
len - lastIndex, currentFont);
if (mcs == null) {
result = new CharsetString[1];
result[0] = cs;
} else {
mcs.addElement(cs);
result = new CharsetString[mcs.size()];
for (int i = 0; i < mcs.size(); i++) {
result[i] = (CharsetString) mcs.elementAt(i);
}
}
return result;
}
protected abstract CharToByteConverter getFontCharset(String charsetName,
String fontName);
/*
* return String representation of style
*/
public static String styleStr(int num) {
switch (num) {
case Font.BOLD:
return "bold";
case Font.ITALIC:
return "italic";
case Font.ITALIC + Font.BOLD:
return "bolditalic";
default:
return "plain";
}
}
public String getNativeName(FontDescriptor fd) {
return fd.nativeName;
}
}