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 
SunGraphicsEnvironment()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      */
getScreenDevices()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      */
getNumScreens()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      */
makeScreenDevice(int screennum)163     protected abstract GraphicsDevice makeScreenDevice(int screennum);
164 
165     /**
166      * Returns the default screen graphics device.
167      */
getDefaultScreenDevice()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      */
createGraphics(BufferedImage img)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 
getFontManagerForSGE()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      */
useAlternateFontforJALocales()201     public static void useAlternateFontforJALocales() {
202         getFontManagerForSGE().useAlternateFontforJALocales();
203     }
204 
205      /**
206      * Returns all fonts available in this environment.
207      */
getAllFonts()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 
getAvailableFontFamilyNames(Locale requestedLocale)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 
getAvailableFontFamilyNames()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      */
getUsableBounds(GraphicsDevice gd)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      */
displayChanged()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      */
paletteChanged()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      */
isDisplayLocal()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      */
addDisplayChangedListener(DisplayChangedListener client)314     public void addDisplayChangedListener(DisplayChangedListener client) {
315         displayChanger.add(client);
316     }
317 
318     /**
319      * Remove a DisplayChangeListener from Win32GraphicsEnvironment
320      */
removeDisplayChangedListener(DisplayChangedListener client)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      */
isFlipStrategyPreferred(ComponentPeer peer)339     public boolean isFlipStrategyPreferred(ComponentPeer peer) {
340         return false;
341     }
342 }
343