aboutsummaryrefslogtreecommitdiff
path: root/src/solaris/classes/sun/awt/X11GraphicsEnvironment.java
diff options
context:
space:
mode:
authorduke <none@none>2007-12-01 00:00:00 +0000
committerduke <none@none>2007-12-01 00:00:00 +0000
commit6e45e10b03bafdc125c46a4864ba802c24d6bc78 (patch)
tree182810ab2fece13f57a928d026f93e9ede0827f9 /src/solaris/classes/sun/awt/X11GraphicsEnvironment.java
downloadjdk8u_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.java1067
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() {
+ }
+}