/* * %W% - %E% */ /** * Inferno's Font peer * */ /* * If you're not using xemacs to view this file, you may find it's indentation * more ledgible if you set your tabstops to four spaces. */ package inferno.awt; import java.io.FileNotFoundException; import java.awt.Font; import java.util.Properties; import java.util.Hashtable; import java.util.Vector; import java.io.File; import java.io.InputStream; import java.io.FileInputStream; import java.io.BufferedInputStream; import java.util.StringTokenizer; public class iFontPeer implements java.awt.peer.FontPeer { // a default Inferno pathname to a font // "/fonts/lucidasans/latin1.7.font" is a popular default font private final static String defifpathname = "*default*"; /* An object to hold a Limbo reference of type ref Draw->Font the handle to Inferno platform font capabilities. Inferno JNI access as this.iFontRef. Pertinent size metrics are kept here in the peer for quicker text rendering. */ Object iFontRef; int iAscent = -1; // Inferno font's ascent value int iHeight = -1; // Inferno font's height value int fLeading = -1; // a fudged value for leading (none in Inferno fonts) String iName = ""; // Inferno font's name (should match ifpathname) private static Properties fprops; static { // Find property file String jhome = System.getProperty("java.home"); if (jhome == null){ throw new Error("java.home property not set"); } // trace("jhome=" + jhome); String language = System.getProperty("user.language", "en"); String region = System.getProperty("user.region"); // trace("language=" + language); // trace("region=" + region); // trace("File.separator=" + File.separator); try { File f = null; if (region != null) { f = new File(jhome + File.separator + "lib" + File.separator + "font.properties." + language + "_" + region); } if (f == null || !f.canRead()) { f = new File(jhome + File.separator + "lib" + File.separator + "font.properties." + language); if (!f.canRead()) { f = new File(jhome + File.separator + "lib" + File.separator + "font.properties"); if (!f.canRead()){ throw new Exception(); } } } fprops = new Properties(); // Load property file // trace("trying to load props at path " + f.getPath()); InputStream in = new BufferedInputStream(new FileInputStream(f.getPath())); fprops.load(in); in.close(); } catch (Exception e){ System.out.println("iFontPeer: can't load font.properties"); System.out.println("exception: " + e.getMessage()); e.printStackTrace(); } // end try } // end static // The do-nothing constructor public iFontPeer(String name, int style) { // Don't do anything with name and style, they're implementation // artifacts from a different (better?) world of scalable // platform fonts where size is a final argument to platform // dependant rendering libraries, but Inferno's are static bitmaps. // // a better (more general) signatures for this constructor would // have been FontPeer(Font font) or // FontPeer(String name,int style,int size) // but alas, Sun's API hasn't been quite general enough in that regard. } // Native method to actually create font in Inferno Display and // populate this object with reference to Draw->Font and some // font metrics. private native void initFontPeer(String ifpathname) throws FileNotFoundException; // // initializeFontPeer is called by java.awt.Font.java so this // method must, regretably, have public scope. // public String initializeFontPeer(String name, int style, int size) { String ifpn = ""; // pathname to Inferno font // trace("iFontPeer.initializeFontPeer(): name=" + name +" ,style=" // + style + ", size=" + size); boolean triedDefault = false; ifpn = mapifpath(name, style, size); if (ifpn == null) { ifpn = defifpathname; } retry: try { initFontPeer(ifpn); // sets iName, iAscent, iHeight, and fLeading } catch (FileNotFoundException e) { // case: properties maps to a file but font file doesn't // exist if (!triedDefault) { triedDefault = true; ifpn = defifpathname; // trace("initializeFontPeer: trying default"); break retry; } } if (debug) { trace("iFontPeer.initializeFontPeer():"); trace(" iName=" + iName); trace(" iAscent=" + iAscent + " iHeight=" + iHeight); } return ifpn; } // // map a Java font triple into the full pathname of an Inferno // font description file. // private static String mapifpath(String name, int style, int size) { if (fprops == null) { return defifpathname; } String aName = name.toLowerCase(); String aStyle = styleStr(style); String aSize = String.valueOf(size); //trace("mapifpath(" + aName + ", " + aStyle + ", " + aSize + ")"); String aStr = aName + "." + aStyle + "." + aSize; int idx; // perform face name substitution String rStr = fprops.getProperty("alias." + aName); if (rStr != null && rStr.indexOf('.') < 0) { aName = rStr; } //trace("gp1 rStr=" +rStr+ " aName=" +aName+ " aStyle=" +aStyle+ // " aSize=" + aSize); // perform style substitution on result of above rStr = fprops.getProperty("alias." + aName + "." + aStyle); if (rStr != null) { idx = rStr.indexOf('.'); if (idx > 0 && rStr.lastIndexOf('.') == idx && (idx+1 < rStr.length())) { aName = rStr.substring(0,idx); aStyle = rStr.substring(idx+1); } } //trace("gp2 rStr=" +rStr+ " aName=" +aName+ " aStyle=" +aStyle+ // " aSize=" + aSize); // Now see if there's a complete alias for this "font+style+size" rStr = fprops.getProperty("alias." + aName + "." + aStyle + "." + aSize); if (rStr != null) { StringTokenizer st = new StringTokenizer(rStr,".",false); if (st.countTokens() == 3) { aName = st.nextToken(); aStyle = st.nextToken(); aSize = st.nextToken(); } } //trace("gp3 rStr=" +rStr+ " aName=" +aName+ " aStyle=" +aStyle+ // " aSize=" + aSize); // after these substitutions, see if the font string has // a match, applying the followin heuristic. // if stlye isn't "plain", adjust size +-2, if no match // change style to "plain" and proceed per style is "plain" // if style is "plain" adjust size +-4 if need be. // while(true) { int nsize; boolean up = true; int range = (style != Font.PLAIN) ? 2 : 4; for (int i = 0; i <= range;) { nsize = Math.abs(size + ((up) ? i : -i)); // trace("nsize=" + nsize); aSize = String.valueOf(nsize); rStr = fprops.getProperty(aName +"."+ aStyle + "." + aSize); if (rStr != null) { //trace("***mapifpath: got it!"); break; } if (!up) { i++; } up = (!up); } if (rStr == null) { if (style != Font.PLAIN) { // retry with plain style style = Font.PLAIN; aStyle = styleStr(style); //trace("***mapifpath: retry w/plain font!, nsize=" + nsize); continue; } rStr = defifpathname; // no Match, returns default } break; } trace ("mapifpath: gp4 aName=" +aName+ " aStyle=" +aStyle+ " aSize=" + aSize + " rStr=" + rStr); return(rStr); } /* * return String representation of style */ private 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"; } } private static final boolean debug = false; private static void trace(String arg) { if (debug) { System.out.println(arg); } } }