View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.java2d;
27  
28  import java.awt.AWTError;
29  import java.awt.Color;
30  import java.awt.Font;
31  import java.awt.Graphics2D;
32  import java.awt.GraphicsConfiguration;
33  import java.awt.GraphicsDevice;
34  import java.awt.GraphicsEnvironment;
35  import java.awt.Insets;
36  import java.awt.Rectangle;
37  import java.awt.Toolkit;
38  import java.awt.font.TextAttribute;
39  import java.awt.image.BufferedImage;
40  import java.awt.peer.ComponentPeer;
41  import java.io.BufferedReader;
42  import java.io.File;
43  import java.io.FileInputStream;
44  import java.io.FilenameFilter;
45  import java.io.InputStreamReader;
46  import java.io.IOException;
47  import java.text.AttributedCharacterIterator;
48  import java.util.ArrayList;
49  import java.util.HashSet;
50  import java.util.Iterator;
51  import java.util.Locale;
52  import java.util.Map;
53  import java.util.NoSuchElementException;
54  import java.util.Set;
55  import java.util.StringTokenizer;
56  import java.util.TreeMap;
57  import java.util.Vector;
58  import java.util.concurrent.ConcurrentHashMap;
59  import sun.awt.AppContext;
60  import sun.awt.DisplayChangedListener;
61  import sun.awt.FontConfiguration;
62  import sun.awt.SunDisplayChanger;
63  import sun.font.CompositeFontDescriptor;
64  import sun.font.Font2D;
65  import sun.font.FontManager;
66  import sun.font.FontManagerFactory;
67  import sun.font.FontManagerForSGE;
68  import sun.font.NativeFont;
69  
70  /**
71   * This is an implementation of a GraphicsEnvironment object for the
72   * default local GraphicsEnvironment.
73   *
74   * @see GraphicsDevice
75   * @see GraphicsConfiguration
76   */
77  public abstract class SunGraphicsEnvironment extends GraphicsEnvironment
78      implements DisplayChangedListener {
79  
80      public static boolean isOpenSolaris;
81      private static Font defaultFont;
82  
83      public SunGraphicsEnvironment() {
84          java.security.AccessController.doPrivileged(
85                                      new java.security.PrivilegedAction() {
86              public Object run() {
87                      String version = System.getProperty("os.version", "0.0");
88                      try {
89                          float ver = Float.parseFloat(version);
90                          if (ver > 5.10f) {
91                              File f = new File("/etc/release");
92                              FileInputStream fis = new FileInputStream(f);
93                              InputStreamReader isr
94                                  = new InputStreamReader(fis, "ISO-8859-1");
95                              BufferedReader br = new BufferedReader(isr);
96                              String line = br.readLine();
97                              if (line.indexOf("OpenSolaris") >= 0) {
98                                  isOpenSolaris = true;
99                              } else {
100                                 /* We are using isOpenSolaris as meaning
101                                  * we know the Solaris commercial fonts aren't
102                                  * present. "Solaris Next" (03/10) did not
103                                  * include these even though its was not
104                                  * OpenSolaris. Need to revisit how this is
105                                  * handled but for now as in 6ux, we'll use
106                                  * the test for a standard font resource as
107                                  * being an indicator as to whether we need
108                                  * to treat this as OpenSolaris from a font
109                                  * config perspective.
110                                  */
111                                 String courierNew =
112                                     "/usr/openwin/lib/X11/fonts/TrueType/CourierNew.ttf";
113                                 File courierFile = new File(courierNew);
114                                 isOpenSolaris = !courierFile.exists();
115                             }
116                             fis.close();
117                         }
118                     } catch (Exception e) {
119                     }
120 
121                 /* Establish the default font to be used by SG2D etc */
122                 defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12);
123 
124                 return null;
125             }
126         });
127     }
128 
129     protected GraphicsDevice[] screens;
130 
131     /**
132      * Returns an array of all of the screen devices.
133      */
134     public synchronized GraphicsDevice[] getScreenDevices() {
135         GraphicsDevice[] ret = screens;
136         if (ret == null) {
137             int num = getNumScreens();
138             ret = new GraphicsDevice[num];
139             for (int i = 0; i < num; i++) {
140                 ret[i] = makeScreenDevice(i);
141             }
142             screens = ret;
143         }
144         return ret;
145     }
146 
147     /**
148      * Returns the number of screen devices of this graphics environment.
149      *
150      * @return the number of screen devices of this graphics environment
151      */
152     protected abstract int getNumScreens();
153 
154     /**
155      * Create and return the screen device with the specified number. The
156      * device with number <code>0</code> will be the default device (returned
157      * by {@link #getDefaultScreenDevice()}.
158      *
159      * @param screennum the number of the screen to create
160      *
161      * @return the created screen device
162      */
163     protected abstract GraphicsDevice makeScreenDevice(int screennum);
164 
165     /**
166      * Returns the default screen graphics device.
167      */
168     public GraphicsDevice getDefaultScreenDevice() {
169         GraphicsDevice[] screens = getScreenDevices();
170         if (screens.length == 0) {
171             throw new AWTError("no screen devices");
172         }
173         return screens[0];
174     }
175 
176     /**
177      * Returns a Graphics2D object for rendering into the
178      * given BufferedImage.
179      * @throws NullPointerException if BufferedImage argument is null
180      */
181     public Graphics2D createGraphics(BufferedImage img) {
182         if (img == null) {
183             throw new NullPointerException("BufferedImage cannot be null");
184         }
185         SurfaceData sd = SurfaceData.getPrimarySurfaceData(img);
186         return new SunGraphics2D(sd, Color.white, Color.black, defaultFont);
187     }
188 
189     public static FontManagerForSGE getFontManagerForSGE() {
190         FontManager fm = FontManagerFactory.getInstance();
191         return (FontManagerForSGE) fm;
192     }
193 
194     /* Modifies the behaviour of a subsequent call to preferLocaleFonts()
195      * to use Mincho instead of Gothic for dialoginput in JA locales
196      * on windows. Not needed on other platforms.
197      *
198      * DO NOT MOVE OR RENAME OR OTHERWISE ALTER THIS METHOD.
199      * ITS USED BY SOME NON-JRE INTERNAL CODE.
200      */
201     public static void useAlternateFontforJALocales() {
202         getFontManagerForSGE().useAlternateFontforJALocales();
203     }
204 
205      /**
206      * Returns all fonts available in this environment.
207      */
208     public Font[] getAllFonts() {
209         FontManagerForSGE fm = getFontManagerForSGE();
210         Font[] installedFonts = fm.getAllInstalledFonts();
211         Font[] created = fm.getCreatedFonts();
212         if (created == null || created.length == 0) {
213             return installedFonts;
214         } else {
215             int newlen = installedFonts.length + created.length;
216             Font [] fonts = java.util.Arrays.copyOf(installedFonts, newlen);
217             System.arraycopy(created, 0, fonts,
218                              installedFonts.length, created.length);
219             return fonts;
220         }
221     }
222 
223     public String[] getAvailableFontFamilyNames(Locale requestedLocale) {
224         FontManagerForSGE fm = getFontManagerForSGE();
225         String[] installed = fm.getInstalledFontFamilyNames(requestedLocale);
226         /* Use a new TreeMap as used in getInstalledFontFamilyNames
227          * and insert all the keys in lower case, so that the sort order
228          * is the same as the installed families. This preserves historical
229          * behaviour and inserts new families in the right place.
230          * It would have been marginally more efficient to directly obtain
231          * the tree map and just insert new entries, but not so much as
232          * to justify the extra internal interface.
233          */
234         TreeMap<String, String> map = fm.getCreatedFontFamilyNames();
235         if (map == null || map.size() == 0) {
236             return installed;
237         } else {
238             for (int i=0; i<installed.length; i++) {
239                 map.put(installed[i].toLowerCase(requestedLocale),
240                         installed[i]);
241             }
242             String[] retval =  new String[map.size()];
243             Object [] keyNames = map.keySet().toArray();
244             for (int i=0; i < keyNames.length; i++) {
245                 retval[i] = (String)map.get(keyNames[i]);
246             }
247             return retval;
248         }
249     }
250 
251     public String[] getAvailableFontFamilyNames() {
252         return getAvailableFontFamilyNames(Locale.getDefault());
253     }
254 
255     /**
256      * Return the bounds of a GraphicsDevice, less its screen insets.
257      * See also java.awt.GraphicsEnvironment.getUsableBounds();
258      */
259     public static Rectangle getUsableBounds(GraphicsDevice gd) {
260         GraphicsConfiguration gc = gd.getDefaultConfiguration();
261         Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
262         Rectangle usableBounds = gc.getBounds();
263 
264         usableBounds.x += insets.left;
265         usableBounds.y += insets.top;
266         usableBounds.width -= (insets.left + insets.right);
267         usableBounds.height -= (insets.top + insets.bottom);
268 
269         return usableBounds;
270     }
271 
272     /**
273      * From the DisplayChangedListener interface; called
274      * when the display mode has been changed.
275      */
276     public void displayChanged() {
277         // notify screens in device array to do display update stuff
278         for (GraphicsDevice gd : getScreenDevices()) {
279             if (gd instanceof DisplayChangedListener) {
280                 ((DisplayChangedListener) gd).displayChanged();
281             }
282         }
283 
284         // notify SunDisplayChanger list (e.g. VolatileSurfaceManagers and
285         // SurfaceDataProxies) about the display change event
286         displayChanger.notifyListeners();
287     }
288 
289     /**
290      * Part of the DisplayChangedListener interface:
291      * propagate this event to listeners
292      */
293     public void paletteChanged() {
294         displayChanger.notifyPaletteChanged();
295     }
296 
297     /**
298      * Returns true when the display is local, false for remote displays.
299      *
300      * @return true when the display is local, false for remote displays
301      */
302     public abstract boolean isDisplayLocal();
303 
304     /*
305      * ----DISPLAY CHANGE SUPPORT----
306      */
307 
308     protected SunDisplayChanger displayChanger = new SunDisplayChanger();
309 
310     /**
311      * Add a DisplayChangeListener to be notified when the display settings
312      * are changed.
313      */
314     public void addDisplayChangedListener(DisplayChangedListener client) {
315         displayChanger.add(client);
316     }
317 
318     /**
319      * Remove a DisplayChangeListener from Win32GraphicsEnvironment
320      */
321     public void removeDisplayChangedListener(DisplayChangedListener client) {
322         displayChanger.remove(client);
323     }
324 
325     /*
326      * ----END DISPLAY CHANGE SUPPORT----
327      */
328 
329     /**
330      * Returns true if FlipBufferStrategy with COPIED buffer contents
331      * is preferred for this peer's GraphicsConfiguration over
332      * BlitBufferStrategy, false otherwise.
333      *
334      * The reason FlipBS could be preferred is that in some configurations
335      * an accelerated copy to the screen is supported (like Direct3D 9)
336      *
337      * @return true if flip strategy should be used, false otherwise
338      */
339     public boolean isFlipStrategyPreferred(ComponentPeer peer) {
340         return false;
341     }
342 }