diff options
author | duke <none@none> | 2007-12-01 00:00:00 +0000 |
---|---|---|
committer | duke <none@none> | 2007-12-01 00:00:00 +0000 |
commit | 6e45e10b03bafdc125c46a4864ba802c24d6bc78 (patch) | |
tree | 182810ab2fece13f57a928d026f93e9ede0827f9 /src/solaris/classes/sun/awt/X11GraphicsEnvironment.java | |
download | jdk8u_jdk-6e45e10b03bafdc125c46a4864ba802c24d6bc78.tar.gz |
Initial load
Diffstat (limited to 'src/solaris/classes/sun/awt/X11GraphicsEnvironment.java')
-rw-r--r-- | src/solaris/classes/sun/awt/X11GraphicsEnvironment.java | 1067 |
1 files changed, 1067 insertions, 0 deletions
diff --git a/src/solaris/classes/sun/awt/X11GraphicsEnvironment.java b/src/solaris/classes/sun/awt/X11GraphicsEnvironment.java new file mode 100644 index 0000000000..27ba044c27 --- /dev/null +++ b/src/solaris/classes/sun/awt/X11GraphicsEnvironment.java @@ -0,0 +1,1067 @@ +/* + * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 in the LICENSE file that + * accompanied this code). + * + * 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 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.awt; + +import java.awt.GraphicsDevice; +import java.awt.Point; +import java.awt.Rectangle; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.IOException; +import java.io.StreamTokenizer; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; + +import java.util.*; +import java.util.logging.*; + +import sun.awt.motif.MFontConfiguration; +import sun.font.Font2D; +import sun.font.FontManager; +import sun.font.NativeFont; +import sun.java2d.SunGraphicsEnvironment; + +/** + * This is an implementation of a GraphicsEnvironment object for the + * default local GraphicsEnvironment used by the Java Runtime Environment + * for X11 environments. + * + * @see GraphicsDevice + * @see GraphicsConfiguration + */ +public class X11GraphicsEnvironment + extends SunGraphicsEnvironment +{ + private static final Logger log = Logger.getLogger("sun.awt.X11GraphicsEnvironment"); + private static final Logger screenLog = Logger.getLogger("sun.awt.screen.X11GraphicsEnvironment"); + + private static Boolean xinerState; + + /* + * This is the set of font directories needed to be on the X font path + * to enable AWT heavyweights to find all of the font configuration fonts. + * It is populated by : + * - awtfontpath entries in the fontconfig.properties + * - parent directories of "core" fonts used in the fontconfig.properties + * - looking up font dirs in the xFontDirsMap where the key is a fontID + * (cut down version of the XLFD read from the font configuration file). + * This set is nulled out after use to free heap space. + */ + private static HashSet<String> fontConfigDirs = null; + + /* + * fontNameMap is a map from a fontID (which is a substring of an XLFD like + * "-monotype-arial-bold-r-normal-iso8859-7") + * to font file path like + * /usr/openwin/lib/locale/iso_8859_7/X11/fonts/TrueType/ArialBoldItalic.ttf + * It's used in a couple of methods like + * getFileNameFomPlatformName(..) to help locate the font file. + * We use this substring of a full XLFD because the font configuration files + * define the XLFDs in a way that's easier to make into a request. + * E.g., the -0-0-0-0-p-0- reported by X is -*-%d-*-*-p-*- in the font + * configuration files. We need to remove that part for comparisons. + */ + private static Map fontNameMap = new HashMap(); + + /* xFontDirsMap is also a map from a font ID to a font filepath. + * The difference from fontNameMap is just that it does not have + * resolved symbolic links. Normally this is not interesting except + * that we need to know the directory in which a font was found to + * add it to the X font server path, since although the files may + * be linked, the fonts.dir is different and specific to the encoding + * handled by that directory. This map is nulled out after use to free + * heap space. If the optimal path is taken, such that all fonts in + * font configuration files are referenced by filename, then the font + * dir can be directly derived as its parent directory. + * If a font is used by two XLFDs, each corresponding to a different + * X11 font directory, then precautions must be taken to include both + * directories. + */ + private static Map xFontDirsMap; + + /* + * xlfdMap is a map from a platform path like + * /usr/openwin/lib/locale/ja/X11/fonts/TT/HG-GothicB.ttf to an XLFD like + * "-ricoh-hg gothic b-medium-r-normal--0-0-0-0-m-0-jisx0201.1976-0" + * Because there may be multiple native names, because the font is used + * to support multiple X encodings for example, the value of an entry in + * this map is always a vector where we store all the native names. + * For fonts which we don't understand the key isn't a pathname, its + * the full XLFD string like :- + * "-ricoh-hg gothic b-medium-r-normal--0-0-0-0-m-0-jisx0201.1976-0" + */ + private static Map xlfdMap = new HashMap(); + + /* + * Used to eliminate redundant work. When a font directory is + * registered it added to this list. Subsequent registrations for the + * same directory can then be skipped by checking this Map. + * Access to this map is not synchronised here since creation + * of the singleton GE instance is already synchronised and that is + * the only code path that accesses this map. + */ + private static HashMap registeredDirs = new HashMap(); + + /* Array of directories to be added to the X11 font path. + * Used by static method called from Toolkits which use X11 fonts. + * Specifically this means MToolkit + */ + private static String[] fontdirs = null; + + static { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + System.loadLibrary("awt"); + + /* + * Note: The MToolkit object depends on the static initializer + * of X11GraphicsEnvironment to initialize the connection to + * the X11 server. + */ + if (!isHeadless()) { + // first check the OGL system property + boolean glxRequested = false; + String prop = System.getProperty("sun.java2d.opengl"); + if (prop != null) { + if (prop.equals("true") || prop.equals("t")) { + glxRequested = true; + } else if (prop.equals("True") || prop.equals("T")) { + glxRequested = true; + glxVerbose = true; + } + } + + // initialize the X11 display connection + initDisplay(glxRequested); + + // only attempt to initialize GLX if it was requested + if (glxRequested) { + glxAvailable = initGLX(); + if (glxVerbose && !glxAvailable) { + System.out.println( + "Could not enable OpenGL " + + "pipeline (GLX 1.3 not available)"); + } + } + } + + return null; + } + }); + } + + private static boolean glxAvailable; + private static boolean glxVerbose; + + private static native boolean initGLX(); + + public static boolean isGLXAvailable() { + return glxAvailable; + } + + public static boolean isGLXVerbose() { + return glxVerbose; + } + + /** + * Checks if Shared Memory extension can be used. + * Returns: + * -1 if server doesn't support MITShm + * 1 if server supports it and it can be used + * 0 otherwise + */ + private static native int checkShmExt(); + + private static native String getDisplayString(); + private static Boolean isDisplayLocal; + + /** + * This should only be called from the static initializer, so no need for + * the synchronized keyword. + */ + private static native void initDisplay(boolean glxRequested); + + public X11GraphicsEnvironment() { + } + + protected native int getNumScreens(); + + protected GraphicsDevice makeScreenDevice(int screennum) { + return new X11GraphicsDevice(screennum); + } + + protected native int getDefaultScreenNum(); + /** + * Returns the default screen graphics device. + */ + public GraphicsDevice getDefaultScreenDevice() { + return getScreenDevices()[getDefaultScreenNum()]; + } + + public static boolean isDisplayLocal() { + if (isDisplayLocal == null) { + SunToolkit.awtLock(); + try { + if (isDisplayLocal == null) { + isDisplayLocal = Boolean.valueOf(_isDisplayLocal()); + } + } finally { + SunToolkit.awtUnlock(); + } + } + return isDisplayLocal.booleanValue(); + } + + private static boolean _isDisplayLocal() { + if (isHeadless()) { + return true; + } + + String isRemote = (String)java.security.AccessController.doPrivileged( + new sun.security.action.GetPropertyAction("sun.java2d.remote")); + if (isRemote != null) { + return isRemote.equals("false"); + } + + int shm = checkShmExt(); + if (shm != -1) { + return (shm == 1); + } + + // If XServer doesn't support ShMem extension, + // try the other way + + String display = getDisplayString(); + int ind = display.indexOf(':'); + final String hostName = display.substring(0, ind); + if (ind <= 0) { + // ':0' case + return true; + } + + Boolean result = (Boolean)java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Object run() { + InetAddress remAddr[] = null; + Enumeration locals = null; + Enumeration interfaces = null; + try { + interfaces = NetworkInterface.getNetworkInterfaces(); + remAddr = InetAddress.getAllByName(hostName); + if (remAddr == null) { + return Boolean.FALSE; + } + } catch (UnknownHostException e) { + System.err.println("Unknown host: " + hostName); + return Boolean.FALSE; + } catch (SocketException e1) { + System.err.println(e1.getMessage()); + return Boolean.FALSE; + } + + for (; interfaces.hasMoreElements();) { + locals = ((NetworkInterface)interfaces.nextElement()).getInetAddresses(); + for (; locals.hasMoreElements();) { + for (int i = 0; i < remAddr.length; i++) { + if (locals.nextElement().equals(remAddr[i])) { + return Boolean.TRUE; + } + } + } + } + return Boolean.FALSE; + }}); + return result.booleanValue(); + } + + /* These maps are used on Linux where we reference the Lucida oblique + * fonts in fontconfig files even though they aren't in the standard + * font directory. This explicitly remaps the XLFDs for these to the + * correct base font. This is needed to prevent composite fonts from + * defaulting to the Lucida Sans which is a bad substitute for the + * monospaced Lucida Sans Typewriter. Also these maps prevent the + * JRE from doing wasted work at start up. + */ + HashMap<String, String> oblmap = null; + + private String getObliqueLucidaFontID(String fontID) { + if (fontID.startsWith("-lucidasans-medium-i-normal") || + fontID.startsWith("-lucidasans-bold-i-normal") || + fontID.startsWith("-lucidatypewriter-medium-i-normal") || + fontID.startsWith("-lucidatypewriter-bold-i-normal")) { + return fontID.substring(0, fontID.indexOf("-i-")); + } else { + return null; + } + } + + private void initObliqueLucidaFontMap() { + oblmap = new HashMap<String, String>(); + oblmap.put("-lucidasans-medium", + jreLibDirName+"/fonts/LucidaSansRegular.ttf"); + oblmap.put("-lucidasans-bold", + jreLibDirName+"/fonts/LucidaSansDemiBold.ttf"); + oblmap.put("-lucidatypewriter-medium", + jreLibDirName+"/fonts/LucidaTypewriterRegular.ttf"); + oblmap.put("-lucidatypewriter-bold", + jreLibDirName+"/fonts/LucidaTypewriterBold.ttf"); + } + + /** + * Takes family name property in the following format: + * "-linotype-helvetica-medium-r-normal-sans-*-%d-*-*-p-*-iso8859-1" + * and returns the name of the corresponding physical font. + * This code is used to resolve font configuration fonts, and expects + * only to get called for these fonts. + */ + public String getFileNameFromPlatformName(String platName) { + String fileName = null; + String fontID = specificFontIDForName(platName); + + /* If the font filename has been explicitly assigned in the + * font configuration file, use it. This avoids accessing + * the wrong fonts on Linux, where different fonts (some + * of which may not be usable by 2D) may share the same + * specific font ID. It may also speed up the lookup. + */ + fileName = super.getFileNameFromPlatformName(platName); + if (fileName != null) { + if (isHeadless() && fileName.startsWith("-")) { + /* if it's headless, no xlfd should be used */ + return null; + } + if (fileName.startsWith("/")) { + /* If a path is assigned in the font configuration file, + * it is required that the config file also specify using the + * new awtfontpath key the X11 font directories + * which must be added to the X11 font path to support + * AWT access to that font. For that reason we no longer + * have code here to add the parent directory to the list + * of font config dirs, since the parent directory may not + * be sufficient if fonts are symbolically linked to a + * different directory. + * + * Add this XLFD (platform name) to the list of known + * ones for this file. + */ + Vector xVal = (Vector) xlfdMap.get(fileName); + if (xVal == null) { + /* Try to be robust on Linux distros which move fonts + * around by verifying that the fileName represents a + * file that exists. If it doesn't, set it to null + * to trigger a search. + */ + if (getFontConfiguration().needToSearchForFile(fileName)) { + fileName = null; + } + if (fileName != null) { + xVal = new Vector(); + xVal.add(platName); + xlfdMap.put(fileName, xVal); + } + } else { + if (!xVal.contains(platName)) { + xVal.add(platName); + } + } + } + if (fileName != null) { + fontNameMap.put(fontID, fileName); + return fileName; + } + } + + if (fontID != null) { + fileName = (String)fontNameMap.get(fontID); + /* On Linux check for the Lucida Oblique fonts */ + if (fileName == null && isLinux && !isOpenJDK()) { + if (oblmap == null) { + initObliqueLucidaFontMap(); + } + String oblkey = getObliqueLucidaFontID(fontID); + if (oblkey != null) { + fileName = oblmap.get(oblkey); + } + } + if (fontPath == null && + (fileName == null || !fileName.startsWith("/"))) { + if (debugFonts) { + logger.warning("** Registering all font paths because " + + "can't find file for " + platName); + } + fontPath = getPlatformFontPath(noType1Font); + registerFontDirs(fontPath); + if (debugFonts) { + logger.warning("** Finished registering all font paths"); + } + fileName = (String)fontNameMap.get(fontID); + } + if (fileName == null && !isHeadless()) { + /* Query X11 directly to see if this font is available + * as a native font. + */ + fileName = getX11FontName(platName); + } + if (fileName == null) { + fontID = switchFontIDForName(platName); + fileName = (String)fontNameMap.get(fontID); + } + if (fileName != null) { + fontNameMap.put(fontID, fileName); + } + } + return fileName; + } + + private static String getX11FontName(String platName) { + String xlfd = platName.replaceAll("%d", "*"); + if (NativeFont.fontExists(xlfd)) { + return xlfd; + } else { + return null; + } + } + + /** + * Returns the face name for the given XLFD. + */ + public String getFileNameFromXLFD(String name) { + String fileName = null; + String fontID = specificFontIDForName(name); + if (fontID != null) { + fileName = (String)fontNameMap.get(fontID); + if (fileName == null) { + fontID = switchFontIDForName(name); + fileName = (String)fontNameMap.get(fontID); + } + if (fileName == null) { + fileName = getDefaultFontFile(); + } + } + return fileName; + } + + // constants identifying XLFD and font ID fields + private static final int FOUNDRY_FIELD = 1; + private static final int FAMILY_NAME_FIELD = 2; + private static final int WEIGHT_NAME_FIELD = 3; + private static final int SLANT_FIELD = 4; + private static final int SETWIDTH_NAME_FIELD = 5; + private static final int ADD_STYLE_NAME_FIELD = 6; + private static final int PIXEL_SIZE_FIELD = 7; + private static final int POINT_SIZE_FIELD = 8; + private static final int RESOLUTION_X_FIELD = 9; + private static final int RESOLUTION_Y_FIELD = 10; + private static final int SPACING_FIELD = 11; + private static final int AVERAGE_WIDTH_FIELD = 12; + private static final int CHARSET_REGISTRY_FIELD = 13; + private static final int CHARSET_ENCODING_FIELD = 14; + + private String switchFontIDForName(String name) { + + int[] hPos = new int[14]; + int hyphenCnt = 1; + int pos = 1; + + while (pos != -1 && hyphenCnt < 14) { + pos = name.indexOf('-', pos); + if (pos != -1) { + hPos[hyphenCnt++] = pos; + pos++; + } + } + + if (hyphenCnt != 14) { + if (debugFonts) { + logger.severe("Font Configuration Font ID is malformed:" + name); + } + return name; // what else can we do? + } + + String slant = name.substring(hPos[SLANT_FIELD-1]+1, + hPos[SLANT_FIELD]); + String family = name.substring(hPos[FAMILY_NAME_FIELD-1]+1, + hPos[FAMILY_NAME_FIELD]); + String registry = name.substring(hPos[CHARSET_REGISTRY_FIELD-1]+1, + hPos[CHARSET_REGISTRY_FIELD]); + String encoding = name.substring(hPos[CHARSET_ENCODING_FIELD-1]+1); + + if (slant.equals("i")) { + slant = "o"; + } else if (slant.equals("o")) { + slant = "i"; + } + // workaround for #4471000 + if (family.equals("itc zapfdingbats") + && registry.equals("sun") + && encoding.equals("fontspecific")){ + registry = "adobe"; + } + StringBuffer sb = + new StringBuffer(name.substring(hPos[FAMILY_NAME_FIELD-1], + hPos[SLANT_FIELD-1]+1)); + sb.append(slant); + sb.append(name.substring(hPos[SLANT_FIELD], + hPos[SETWIDTH_NAME_FIELD]+1)); + sb.append(registry); + sb.append(name.substring(hPos[CHARSET_ENCODING_FIELD-1])); + String retval = sb.toString().toLowerCase (Locale.ENGLISH); + return retval; + } + + + private String specificFontIDForName(String name) { + + int[] hPos = new int[14]; + int hyphenCnt = 1; + int pos = 1; + + while (pos != -1 && hyphenCnt < 14) { + pos = name.indexOf('-', pos); + if (pos != -1) { + hPos[hyphenCnt++] = pos; + pos++; + } + } + + if (hyphenCnt != 14) { + if (debugFonts) { + logger.severe("Font Configuration Font ID is malformed:" + name); + } + return name; // what else can we do? + } + + StringBuffer sb = + new StringBuffer(name.substring(hPos[FAMILY_NAME_FIELD-1], + hPos[SETWIDTH_NAME_FIELD])); + sb.append(name.substring(hPos[CHARSET_REGISTRY_FIELD-1])); + String retval = sb.toString().toLowerCase (Locale.ENGLISH); + return retval; + } + + protected String[] getNativeNames(String fontFileName, + String platformName) { + Vector nativeNames; + if ((nativeNames=(Vector)xlfdMap.get(fontFileName))==null) { + if (platformName == null) { + return null; + } else { + /* back-stop so that at least the name used in the + * font configuration file is known as a native name + */ + String []natNames = new String[1]; + natNames[0] = platformName; + return natNames; + } + } else { + int len = nativeNames.size(); + return (String[])nativeNames.toArray(new String[len]); + } + } + + + // An X font spec (xlfd) includes an encoding. The same TrueType font file + // may be referenced from different X font directories in font.dir files + // to support use in multiple encodings by X apps. + // So for the purposes of font configuration logical fonts where AWT + // heavyweights need to access the font via X APIs we need to ensure that + // the directory for precisely the encodings needed by this are added to + // the x font path. This requires that we note the platform names + // specified in font configuration files and use that to identify the + // X font directory that contains a font.dir file for that platform name + // and add it to the X font path (if display is local) + // Here we make use of an already built map of xlfds to font locations + // to add the font location to the set of those required to build the + // x font path needed by AWT. + // These are added to the x font path later. + // All this is necessary because on Solaris the font.dir directories + // may contain not real font files, but symbolic links to the actual + // location but that location is not suitable for the x font path, since + // it probably doesn't have a font.dir at all and certainly not one + // with the required encodings + // If the fontconfiguration file is properly set up so that all fonts + // are mapped to files then we will never trigger initialising + // xFontDirsMap (it will be null). In this case the awtfontpath entries + // must specify all the X11 directories needed by AWT. + protected void addFontToPlatformFontPath(String platformName) { + if (xFontDirsMap != null) { + String fontID = specificFontIDForName(platformName); + String dirName = (String)xFontDirsMap.get(fontID); + if (dirName != null) { + fontConfigDirs.add(dirName); + } + } + return; + } + + protected void getPlatformFontPathFromFontConfig() { + if (fontConfigDirs == null) { + fontConfigDirs = getFontConfiguration().getAWTFontPathSet(); + if (debugFonts && fontConfigDirs != null) { + String[] names = fontConfigDirs.toArray(new String[0]); + for (int i=0;i<names.length;i++) { + logger.info("awtfontpath : " + names[i]); + } + } + } + } + + protected void registerPlatformFontsUsedByFontConfiguration() { + if (fontConfigDirs == null) { + return; + } + if (isLinux) { + fontConfigDirs.add(jreLibDirName+File.separator+"oblique-fonts"); + } + fontdirs = (String[])fontConfigDirs.toArray(new String[0]); + } + + /* Called by MToolkit to set the X11 font path */ + public static void setNativeFontPath() { + if (fontdirs == null) { + return; + } + + // need to register these individually rather than by one call + // to ensure that one bad directory doesn't cause all to be rejected + for (int i=0; i<fontdirs.length; i++) { + if (debugFonts) { + logger.info("Add " + fontdirs[i] + " to X11 fontpath"); + } + FontManager.setNativeFontPath(fontdirs[i]); + } + } + + /* Register just the paths, (it doesn't register the fonts). + * If a font configuration file has specified a baseFontPath + * fontPath is just those directories, unless on usage we + * find it doesn't contain what we need for the logical fonts. + * Otherwise, we register all the paths on Solaris, because + * the fontPath we have here is the complete one from + * parsing /var/sadm/install/contents, not just + * what's on the X font path (may be this should be + * changed). + * But for now what it means is that if we didn't do + * this then if the font weren't listed anywhere on the + * less complete font path we'd trigger loadFonts which + * actually registers the fonts. This may actually be + * the right thing tho' since that would also set up + * the X font path without which we wouldn't be able to + * display some "native" fonts. + * So something to revisit is that probably fontPath + * here ought to be only the X font path + jre font dir. + * loadFonts should have a separate native call to + * get the rest of the platform font path. + * + * Registering the directories can now be avoided in the + * font configuration initialisation when filename entries + * exist in the font configuration file for all fonts. + * (Perhaps a little confusingly a filename entry is + * actually keyed using the XLFD used in the font entries, + * and it maps *to* a real filename). + * In the event any are missing, registration of all + * directories will be invoked to find the real files. + * + * But registering the directory performed other + * functions such as filling in the map of all native names + * for the font. So when this method isn't invoked, they still + * must be found. This is mitigated by getNativeNames now + * being able to return at least the platform name, but mostly + * by ensuring that when a filename key is found, that + * xlfd key is stored as one of the set of platform names + * for the font. Its a set because typical font configuration + * files reference the same CJK font files using multiple + * X11 encodings. For the code that adds this to the map + * see X11GE.getFileNameFromPlatformName(..) + * If you don't get all of these then some code points may + * not use the Xserver, and will not get the PCF bitmaps + * that are available for some point sizes. + * So, in the event that there is such a problem, + * unconditionally making this call may be necessary, at + * some cost to JRE start-up + */ + protected void registerFontDirs(String pathName) { + + StringTokenizer parser = new StringTokenizer(pathName, + File.pathSeparator); + try { + while (parser.hasMoreTokens()) { + String dirPath = parser.nextToken(); + if (dirPath != null && !registeredDirs.containsKey(dirPath)) { + registeredDirs.put(dirPath, null); + registerFontDir(dirPath); + } + } + } catch (NoSuchElementException e) { + } + } + + /* NOTE: this method needs to be executed in a privileged context. + * The superclass constructor which is the primary caller of + * this method executes entirely in such a context. Additionally + * the loadFonts() method does too. So all should be well. + + */ + protected void registerFontDir(String path) { + /* fonts.dir file format looks like :- + * 47 + * Arial.ttf -monotype-arial-regular-r-normal--0-0-0-0-p-0-iso8859-1 + * Arial-Bold.ttf -monotype-arial-bold-r-normal--0-0-0-0-p-0-iso8859-1 + * ... + */ + if (debugFonts) { + logger.info("ParseFontDir " + path); + } + File fontsDotDir = new File(path + File.separator + "fonts.dir"); + FileReader fr = null; + try { + if (fontsDotDir.canRead()) { + fr = new FileReader(fontsDotDir); + BufferedReader br = new BufferedReader(fr, 8192); + StreamTokenizer st = new StreamTokenizer(br); + st.eolIsSignificant(true); + int ttype = st.nextToken(); + if (ttype == StreamTokenizer.TT_NUMBER) { + int numEntries = (int)st.nval; + ttype = st.nextToken(); + if (ttype == StreamTokenizer.TT_EOL) { + st.resetSyntax(); + st.wordChars(32, 127); + st.wordChars(128 + 32, 255); + st.whitespaceChars(0, 31); + + for (int i=0; i < numEntries; i++) { + ttype = st.nextToken(); + if (ttype == StreamTokenizer.TT_EOF) { + break; + } + if (ttype != StreamTokenizer.TT_WORD) { + break; + } + int breakPos = st.sval.indexOf(' '); + if (breakPos <= 0) { + /* On TurboLinux 8.0 a fonts.dir file had + * a line with integer value "24" which + * appeared to be the number of remaining + * entries in the file. This didn't add to + * the value on the first line of the file. + * Seemed like XFree86 didn't like this line + * much either. It failed to parse the file. + * Ignore lines like this completely, and + * don't let them count as an entry. + */ + numEntries++; + ttype = st.nextToken(); + if (ttype != StreamTokenizer.TT_EOL) { + break; + } + + continue; + } + if (st.sval.charAt(0) == '!') { + /* TurboLinux 8.0 comment line: ignore. + * can't use st.commentChar('!') to just + * skip because this line mustn't count + * against numEntries. + */ + numEntries++; + ttype = st.nextToken(); + if (ttype != StreamTokenizer.TT_EOL) { + break; + } + continue; + } + String fileName = st.sval.substring(0, breakPos); + /* TurboLinux 8.0 uses some additional syntax to + * indicate algorithmic styling values. + * Ignore ':' separated files at the beginning + * of the fileName + */ + int lastColon = fileName.lastIndexOf(':'); + if (lastColon > 0) { + if (lastColon+1 >= fileName.length()) { + continue; + } + fileName = fileName.substring(lastColon+1); + } + String fontPart = st.sval.substring(breakPos+1); + String fontID = specificFontIDForName(fontPart); + String sVal = (String) fontNameMap.get(fontID); + + if (debugFonts) { + logger.info("file=" + fileName + + " xlfd=" + fontPart); + logger.info("fontID=" + fontID + + " sVal=" + sVal); + } + String fullPath = null; + try { + File file = new File(path,fileName); + /* we may have a resolved symbolic link + * this becomes important for an xlfd we + * still need to know the location it was + * found to update the X server font path + * for use by AWT heavyweights - and when 2D + * wants to use the native rasteriser. + */ + if (xFontDirsMap == null) { + xFontDirsMap = new HashMap(); + } + xFontDirsMap.put(fontID, path); + fullPath = file.getCanonicalPath(); + } catch (IOException e) { + fullPath = path + File.separator + fileName; + } + Vector xVal = (Vector) xlfdMap.get(fullPath); + if (debugFonts) { + logger.info("fullPath=" + fullPath + + " xVal=" + xVal); + } + if ((xVal == null || !xVal.contains(fontPart)) && + (sVal == null) || !sVal.startsWith("/")) { + if (debugFonts) { + logger.info("Map fontID:"+fontID + + "to file:" + fullPath); + } + fontNameMap.put(fontID, fullPath); + if (xVal == null) { + xVal = new Vector(); + xlfdMap.put (fullPath, xVal); + } + xVal.add(fontPart); + } + + ttype = st.nextToken(); + if (ttype != StreamTokenizer.TT_EOL) { + break; + } + } + } + } + fr.close(); + } + } catch (IOException ioe1) { + } finally { + if (fr != null) { + try { + fr.close(); + } catch (IOException ioe2) { + } + } + } + } + + @Override + public void loadFonts() { + super.loadFonts(); + /* These maps are greatly expanded during a loadFonts but + * can be reset to their initial state afterwards. + * Since preferLocaleFonts() and preferProportionalFonts() will + * trigger a partial repopulating from the FontConfiguration + * it has to be the inital (empty) state for the latter two, not + * simply nulling out. + * xFontDirsMap is a special case in that the implementation + * will typically not ever need to initialise it so it can be null. + */ + xFontDirsMap = null; + xlfdMap = new HashMap(1); + fontNameMap = new HashMap(1); + } + + // Implements SunGraphicsEnvironment.createFontConfiguration. + protected FontConfiguration createFontConfiguration() { + return new MFontConfiguration(this); + } + public FontConfiguration + createFontConfiguration(boolean preferLocaleFonts, + boolean preferPropFonts) { + + return new MFontConfiguration(this, + preferLocaleFonts, preferPropFonts); + } + + /** + * Returns face name for default font, or null if + * no face names are used for CompositeFontDescriptors + * for this platform. + */ + public String getDefaultFontFaceName() { + return null; + } + + private static native boolean pRunningXinerama(); + private static native Point getXineramaCenterPoint(); + + /** + * Override for Xinerama case: call new Solaris API for getting the correct + * centering point from the windowing system. + */ + public Point getCenterPoint() { + if (runningXinerama()) { + Point p = getXineramaCenterPoint(); + if (p != null) { + return p; + } + } + return super.getCenterPoint(); + } + + /** + * Override for Xinerama case + */ + public Rectangle getMaximumWindowBounds() { + if (runningXinerama()) { + return getXineramaWindowBounds(); + } else { + return super.getMaximumWindowBounds(); + } + } + + public boolean runningXinerama() { + if (xinerState == null) { + // pRunningXinerama() simply returns a global boolean variable, + // so there is no need to synchronize here + xinerState = Boolean.valueOf(pRunningXinerama()); + if (screenLog.isLoggable(Level.FINER)) { + screenLog.log(Level.FINER, "Running Xinerama: " + xinerState); + } + } + return xinerState.booleanValue(); + } + + /** + * Return the bounds for a centered Window on a system running in Xinerama + * mode. + * + * Calculations are based on the assumption of a perfectly rectangular + * display area (display edges line up with one another, and displays + * have consistent width and/or height). + * + * The bounds to return depend on the arrangement of displays and on where + * Windows are to be centered. There are two common situations: + * + * 1) The center point lies at the center of the combined area of all the + * displays. In this case, the combined area of all displays is + * returned. + * + * 2) The center point lies at the center of a single display. In this case + * the user most likely wants centered Windows to be constrained to that + * single display. The boundaries of the one display are returned. + * + * It is possible for the center point to be at both the center of the + * entire display space AND at the center of a single monitor (a square of + * 9 monitors, for instance). In this case, the entire display area is + * returned. + * + * Because the center point is arbitrarily settable by the user, it could + * fit neither of the cases above. The fallback case is to simply return + * the combined area for all screens. + */ + protected Rectangle getXineramaWindowBounds() { + Point center = getCenterPoint(); + Rectangle unionRect, tempRect; + GraphicsDevice[] gds = getScreenDevices(); + Rectangle centerMonitorRect = null; + int i; + + // if center point is at the center of all monitors + // return union of all bounds + // + // MM*MM MMM M + // M*M * + // MMM M + + // if center point is at center of a single monitor (but not of all + // monitors) + // return bounds of single monitor + // + // MMM MM + // MM* *M + + // else, center is in some strange spot (such as on the border between + // monitors), and we should just return the union of all monitors + // + // MM MMM + // MM MMM + + unionRect = getUsableBounds(gds[0]); + + for (i = 0; i < gds.length; i++) { + tempRect = getUsableBounds(gds[i]); + if (centerMonitorRect == null && + // add a pixel or two for fudge-factor + (tempRect.width / 2) + tempRect.x > center.x - 1 && + (tempRect.height / 2) + tempRect.y > center.y - 1 && + (tempRect.width / 2) + tempRect.x < center.x + 1 && + (tempRect.height / 2) + tempRect.y < center.y + 1) { + centerMonitorRect = tempRect; + } + unionRect = unionRect.union(tempRect); + } + + // first: check for center of all monitors (video wall) + // add a pixel or two for fudge-factor + if ((unionRect.width / 2) + unionRect.x > center.x - 1 && + (unionRect.height / 2) + unionRect.y > center.y - 1 && + (unionRect.width / 2) + unionRect.x < center.x + 1 && + (unionRect.height / 2) + unionRect.y < center.y + 1) { + + if (screenLog.isLoggable(Level.FINER)) { + screenLog.log(Level.FINER, "Video Wall: center point is at center of all displays."); + } + return unionRect; + } + + // next, check if at center of one monitor + if (centerMonitorRect != null) { + if (screenLog.isLoggable(Level.FINER)) { + screenLog.log(Level.FINER, "Center point at center of a particular " + + "monitor, but not of the entire virtual display."); + } + return centerMonitorRect; + } + + // otherwise, the center is at some weird spot: return unionRect + if (screenLog.isLoggable(Level.FINER)) { + screenLog.log(Level.FINER, "Center point is somewhere strange - return union of all bounds."); + } + return unionRect; + } + + /** + * From the DisplayChangedListener interface; devices do not need + * to react to this event. + */ + @Override + public void paletteChanged() { + } +} |