1 /*
   2  * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package sun.java2d;
  27 
  28 import java.awt.Color;
  29 import java.awt.Font;
  30 import java.awt.Graphics2D;
  31 import java.awt.GraphicsConfiguration;
  32 import java.awt.GraphicsDevice;
  33 import java.awt.GraphicsEnvironment;
  34 import java.awt.Insets;
  35 import java.awt.Rectangle;
  36 import java.awt.Toolkit;
  37 import java.awt.font.TextAttribute;
  38 import java.awt.image.BufferedImage;
  39 import java.awt.peer.ComponentPeer;
  40 import java.io.BufferedReader;
  41 import java.io.File;
  42 import java.io.FileInputStream;
  43 import java.io.FilenameFilter;
  44 import java.io.InputStreamReader;
  45 import java.io.IOException;
  46 import java.text.AttributedCharacterIterator;
  47 import java.util.ArrayList;
  48 import java.util.HashSet;
  49 import java.util.Iterator;
  50 import java.util.Locale;
  51 import java.util.Map;
  52 import java.util.NoSuchElementException;
  53 import java.util.Set;
  54 import java.util.StringTokenizer;
  55 import java.util.TreeMap;
  56 import java.util.Vector;
  57 import java.util.concurrent.ConcurrentHashMap;
  58 import java.util.logging.Level;
  59 import java.util.logging.Logger;
  60 import sun.awt.AppContext;
  61 import sun.awt.DisplayChangedListener;
  62 import sun.awt.FontConfiguration;
  63 import sun.awt.SunDisplayChanger;
  64 import sun.font.CompositeFontDescriptor;
  65 import sun.font.Font2D;
  66 import sun.font.FontManager;
  67 import sun.font.FontManagerFactory;
  68 import sun.font.FontManagerForSGE;
  69 import sun.font.NativeFont;
  70 
  71 /**
  72  * This is an implementation of a GraphicsEnvironment object for the
  73  * default local GraphicsEnvironment.
  74  *
  75  * @see GraphicsDevice
  76  * @see GraphicsConfiguration
  77  */
  78 public abstract class SunGraphicsEnvironment extends GraphicsEnvironment
  79     implements DisplayChangedListener {
  80 
  81     public static boolean isOpenSolaris;
  82     private static Font defaultFont;
  83     protected static Logger logger = null;
  84 
  85     public SunGraphicsEnvironment() {
  86         java.security.AccessController.doPrivileged(
  87                                     new java.security.PrivilegedAction() {
  88             public Object run() {
  89                     String version = System.getProperty("os.version", "0.0");
  90                     try {
  91                         float ver = Float.parseFloat(version);
  92                         if (ver > 5.10f) {
  93                             File f = new File("/etc/release");
  94                             FileInputStream fis = new FileInputStream(f);
  95                             InputStreamReader isr
  96                                 = new InputStreamReader(fis, "ISO-8859-1");
  97                             BufferedReader br = new BufferedReader(isr);
  98                             String line = br.readLine();
  99                             if (line.indexOf("OpenSolaris") >= 0) {
 100                                 isOpenSolaris = true;
 101                             }
 102                             fis.close();
 103                         }
 104                     } catch (Exception e) {
 105                     }
 106 
 107                 /* Establish the default font to be used by SG2D etc */
 108                 defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12);
 109 
 110                 return null;
 111             }
 112         });
 113     }
 114 
 115     protected GraphicsDevice[] screens;
 116 
 117     /**
 118      * Returns an array of all of the screen devices.
 119      */
 120     public synchronized GraphicsDevice[] getScreenDevices() {
 121         GraphicsDevice[] ret = screens;
 122         if (ret == null) {
 123             int num = getNumScreens();
 124             ret = new GraphicsDevice[num];
 125             for (int i = 0; i < num; i++) {
 126                 ret[i] = makeScreenDevice(i);
 127             }
 128             screens = ret;
 129         }
 130         return ret;
 131     }
 132 
 133     /**
 134      * Returns the number of screen devices of this graphics environment.
 135      *
 136      * @return the number of screen devices of this graphics environment
 137      */
 138     protected abstract int getNumScreens();
 139 
 140     /**
 141      * Create and return the screen device with the specified number. The
 142      * device with number <code>0</code> will be the default device (returned
 143      * by {@link #getDefaultScreenDevice()}.
 144      *
 145      * @param screennum the number of the screen to create
 146      *
 147      * @return the created screen device
 148      */
 149     protected abstract GraphicsDevice makeScreenDevice(int screennum);
 150 
 151     /**
 152      * Returns the default screen graphics device.
 153      */
 154     public GraphicsDevice getDefaultScreenDevice() {
 155         return getScreenDevices()[0];
 156     }
 157 
 158     /**
 159      * Returns a Graphics2D object for rendering into the
 160      * given BufferedImage.
 161      * @throws NullPointerException if BufferedImage argument is null
 162      */
 163     public Graphics2D createGraphics(BufferedImage img) {
 164         if (img == null) {
 165             throw new NullPointerException("BufferedImage cannot be null");
 166         }
 167         SurfaceData sd = SurfaceData.getPrimarySurfaceData(img);
 168         return new SunGraphics2D(sd, Color.white, Color.black, defaultFont);
 169     }
 170 
 171     private static FontManagerForSGE getFontManagerForSGE() {
 172         FontManager fm = FontManagerFactory.getInstance();
 173         return (FontManagerForSGE) fm;
 174     }
 175      /**
 176      * Returns all fonts available in this environment.
 177      */
 178     public Font[] getAllFonts() {
 179         FontManagerForSGE fm = getFontManagerForSGE();
 180         Font[] installedFonts = fm.getAllInstalledFonts();
 181         Font[] created = fm.getCreatedFonts();
 182         if (created == null || created.length == 0) {
 183             return installedFonts;
 184         } else {
 185             int newlen = installedFonts.length + created.length;
 186             Font [] fonts = java.util.Arrays.copyOf(installedFonts, newlen);
 187             System.arraycopy(created, 0, fonts,
 188                              installedFonts.length, created.length);
 189             return fonts;
 190         }
 191     }
 192 
 193     public String[] getAvailableFontFamilyNames(Locale requestedLocale) {
 194         FontManagerForSGE fm = getFontManagerForSGE();
 195         String[] installed = fm.getInstalledFontFamilyNames(requestedLocale);
 196         /* Use a new TreeMap as used in getInstalledFontFamilyNames
 197          * and insert all the keys in lower case, so that the sort order
 198          * is the same as the installed families. This preserves historical
 199          * behaviour and inserts new families in the right place.
 200          * It would have been marginally more efficient to directly obtain
 201          * the tree map and just insert new entries, but not so much as
 202          * to justify the extra internal interface.
 203          */
 204         TreeMap<String, String> map = fm.getCreatedFontFamilyNames();
 205         if (map == null || map.size() == 0) {
 206             return installed;
 207         } else {
 208             for (int i=0; i<installed.length; i++) {
 209                 map.put(installed[i].toLowerCase(requestedLocale),
 210                         installed[i]);
 211             }
 212             String[] retval =  new String[map.size()];
 213             Object [] keyNames = map.keySet().toArray();
 214             for (int i=0; i < keyNames.length; i++) {
 215                 retval[i] = (String)map.get(keyNames[i]);
 216             }
 217             return retval;
 218         }
 219     }
 220 
 221     public String[] getAvailableFontFamilyNames() {
 222         return getAvailableFontFamilyNames(Locale.getDefault());
 223     }
 224 
 225     /**
 226      * Return the bounds of a GraphicsDevice, less its screen insets.
 227      * See also java.awt.GraphicsEnvironment.getUsableBounds();
 228      */
 229     public static Rectangle getUsableBounds(GraphicsDevice gd) {
 230         GraphicsConfiguration gc = gd.getDefaultConfiguration();
 231         Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
 232         Rectangle usableBounds = gc.getBounds();
 233 
 234         usableBounds.x += insets.left;
 235         usableBounds.y += insets.top;
 236         usableBounds.width -= (insets.left + insets.right);
 237         usableBounds.height -= (insets.top + insets.bottom);
 238 
 239         return usableBounds;
 240     }
 241 
 242     /**
 243      * From the DisplayChangedListener interface; called
 244      * when the display mode has been changed.
 245      */
 246     public void displayChanged() {
 247         // notify screens in device array to do display update stuff
 248         for (GraphicsDevice gd : getScreenDevices()) {
 249             if (gd instanceof DisplayChangedListener) {
 250                 ((DisplayChangedListener) gd).displayChanged();
 251             }
 252         }
 253 
 254         // notify SunDisplayChanger list (e.g. VolatileSurfaceManagers and
 255         // SurfaceDataProxies) about the display change event
 256         displayChanger.notifyListeners();
 257     }
 258 
 259     /**
 260      * Part of the DisplayChangedListener interface:
 261      * propagate this event to listeners
 262      */
 263     public void paletteChanged() {
 264         displayChanger.notifyPaletteChanged();
 265     }
 266 
 267     /**
 268      * Returns true when the display is local, false for remote displays.
 269      *
 270      * @return true when the display is local, false for remote displays
 271      */
 272     public abstract boolean isDisplayLocal();
 273 
 274     /*
 275      * ----DISPLAY CHANGE SUPPORT----
 276      */
 277 
 278     protected SunDisplayChanger displayChanger = new SunDisplayChanger();
 279 
 280     /**
 281      * Add a DisplayChangeListener to be notified when the display settings
 282      * are changed.
 283      */
 284     public void addDisplayChangedListener(DisplayChangedListener client) {
 285         displayChanger.add(client);
 286     }
 287 
 288     /**
 289      * Remove a DisplayChangeListener from Win32GraphicsEnvironment
 290      */
 291     public void removeDisplayChangedListener(DisplayChangedListener client) {
 292         displayChanger.remove(client);
 293     }
 294 
 295     /*
 296      * ----END DISPLAY CHANGE SUPPORT----
 297      */
 298 
 299     /**
 300      * Returns true if FlipBufferStrategy with COPIED buffer contents
 301      * is preferred for this peer's GraphicsConfiguration over
 302      * BlitBufferStrategy, false otherwise.
 303      *
 304      * The reason FlipBS could be preferred is that in some configurations
 305      * an accelerated copy to the screen is supported (like Direct3D 9)
 306      *
 307      * @return true if flip strategy should be used, false otherwise
 308      */
 309     public boolean isFlipStrategyPreferred(ComponentPeer peer) {
 310         return false;
 311     }
 312 }