1 /*
2  * Copyright (c) 1997, 2017, 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
27 package java.awt;
28
29 import java.awt.image.BufferedImage;
30 import java.security.AccessController;
31 import java.security.PrivilegedAction;
32 import java.util.Locale;
33
34 import sun.font.FontManager;
35 import sun.font.FontManagerFactory;
36 import sun.java2d.HeadlessGraphicsEnvironment;
37 import sun.java2d.SunGraphicsEnvironment;
38 import sun.security.action.GetPropertyAction;
39
40 /**
41  *
42  * The {@code GraphicsEnvironment} class describes the collection
43  * of {@link GraphicsDevice} objects and {@link java.awt.Font} objects
44  * available to a Java(tm) application on a particular platform.
45  * The resources in this {@code GraphicsEnvironment} might be local
46  * or on a remote machine.  {@code GraphicsDevice} objects can be
47  * screens, printers or image buffers and are the destination of
48  * {@link Graphics2D} drawing methods.  Each {@code GraphicsDevice}
49  * has a number of {@link GraphicsConfiguration} objects associated with
50  * it.  These objects specify the different configurations in which the
51  * {@code GraphicsDevice} can be used.
52  * @see GraphicsDevice
53  * @see GraphicsConfiguration
54  */

55
56 public abstract class GraphicsEnvironment {
57
58     /**
59      * The headless state of the Toolkit and GraphicsEnvironment
60      */

61     private static Boolean headless;
62
63     /**
64      * The headless state assumed by default
65      */

66     private static Boolean defaultHeadless;
67
68     /**
69      * This is an abstract class and cannot be instantiated directly.
70      * Instances must be obtained from a suitable factory or query method.
71      */

72     protected GraphicsEnvironment() {
73     }
74
75     /**
76      * Lazy initialization of local graphics environment using holder idiom.
77      */

78     private static final class LocalGE {
79
80         /**
81          * The instance of the local {@code GraphicsEnvironment}.
82          */

83         static final GraphicsEnvironment INSTANCE = createGE();
84
85         /**
86          * Creates and returns the GraphicsEnvironment, according to the
87          * system property 'java.awt.graphicsenv'.
88          *
89          * @return the graphics environment
90          */

91         private static GraphicsEnvironment createGE() {
92             GraphicsEnvironment ge;
93             String nm = AccessController.doPrivileged(new GetPropertyAction("java.awt.graphicsenv"null));
94             try {
95 //              long t0 = System.currentTimeMillis();
96                 Class<?> geCls;
97                 try {
98                     // First we try if the bootstrap class loader finds the
99                     // requested class. This way we can avoid to run in a privileged
100                     // block.
101                     geCls = Class.forName(nm);
102                 } catch (ClassNotFoundException ex) {
103                     // If the bootstrap class loader fails, we try again with the
104                     // application class loader.
105                     ClassLoader cl = ClassLoader.getSystemClassLoader();
106                     geCls = Class.forName(nm, true, cl);
107                 }
108                 ge = (GraphicsEnvironment)geCls.getConstructor().newInstance();
109 //              long t1 = System.currentTimeMillis();
110 //              System.out.println("GE creation took " + (t1-t0)+ "ms.");
111                 if (isHeadless()) {
112                     ge = new HeadlessGraphicsEnvironment(ge);
113                 }
114             } catch (ClassNotFoundException e) {
115                 throw new Error("Could not find class: "+nm);
116             } catch (ReflectiveOperationException | IllegalArgumentException e) {
117                 throw new Error("Could not instantiate Graphics Environment: "
118                         + nm);
119             }
120             return ge;
121         }
122     }
123
124     /**
125      * Returns the local {@code GraphicsEnvironment}.
126      * @return the local {@code GraphicsEnvironment}
127      */

128     public static GraphicsEnvironment getLocalGraphicsEnvironment() {
129         return LocalGE.INSTANCE;
130     }
131
132     /**
133      * Tests whether or not a display, keyboard, and mouse can be
134      * supported in this environment.  If this method returns true,
135      * a HeadlessException is thrown from areas of the Toolkit
136      * and GraphicsEnvironment that are dependent on a display,
137      * keyboard, or mouse.
138      * @return {@code trueif this environment cannot support
139      * a display, keyboard, and mouse; {@code false}
140      * otherwise
141      * @see java.awt.HeadlessException
142      * @since 1.4
143      */

144     public static boolean isHeadless() {
145         return getHeadlessProperty();
146     }
147
148     /**
149      * @return warning message if headless state is assumed by default;
150      * null otherwise
151      * @since 1.5
152      */

153     static String getHeadlessMessage() {
154         if (headless == null) {
155             getHeadlessProperty(); // initialize the values
156         }
157         return defaultHeadless != Boolean.TRUE ? null :
158             "\nNo X11 DISPLAY variable was set, " +
159             "but this program performed an operation which requires it.";
160     }
161
162     /**
163      * @return the value of the property "java.awt.headless"
164      * @since 1.4
165      */

166     private static boolean getHeadlessProperty() {
167         if (headless == null) {
168             AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
169                 String nm = System.getProperty("java.awt.headless");
170
171                 if (nm == null) {
172                     /* No need to ask for DISPLAY when run in a browser */
173                     if (System.getProperty("javaplugin.version") != null) {
174                         headless = defaultHeadless = Boolean.FALSE;
175                     } else {
176                         String osName = System.getProperty("os.name");
177                         if (osName.contains("OS X") && "sun.awt.HToolkit".equals(
178                                 System.getProperty("awt.toolkit")))
179                         {
180                             headless = defaultHeadless = Boolean.TRUE;
181                         } else {
182                             final String display = System.getenv("DISPLAY");
183                             headless = defaultHeadless =
184                                 ("Linux".equals(osName) ||
185                                  "SunOS".equals(osName) ||
186                                  "FreeBSD".equals(osName) ||
187                                  "NetBSD".equals(osName) ||
188                                  "OpenBSD".equals(osName) ||
189                                  "AIX".equals(osName)) &&
190                                  (display == null || display.trim().isEmpty());
191                         }
192                     }
193                 } else {
194                     headless = Boolean.valueOf(nm);
195                 }
196                 return null;
197             });
198         }
199         return headless;
200     }
201
202     /**
203      * Check for headless state and throw HeadlessException if headless
204      * @since 1.4
205      */

206     static void checkHeadless() throws HeadlessException {
207         if (isHeadless()) {
208             throw new HeadlessException();
209         }
210     }
211
212     /**
213      * Returns whether or not a display, keyboard, and mouse can be
214      * supported in this graphics environment.  If this returns true,
215      * {@code HeadlessException} will be thrown from areas of the
216      * graphics environment that are dependent on a display, keyboard, or
217      * mouse.
218      * @return {@code trueif a display, keyboard, and mouse
219      * can be supported in this environment; {@code false}
220      * otherwise
221      * @see java.awt.HeadlessException
222      * @see #isHeadless
223      * @since 1.4
224      */

225     public boolean isHeadlessInstance() {
226         // By default (local graphics environment), simply check the
227         // headless property.
228         return getHeadlessProperty();
229     }
230
231     /**
232      * Returns an array of all of the screen {@code GraphicsDevice}
233      * objects.
234      * @return an array containing all the {@code GraphicsDevice}
235      * objects that represent screen devices
236      * @exception HeadlessException if isHeadless() returns true
237      * @see #isHeadless()
238      */

239     public abstract GraphicsDevice[] getScreenDevices()
240         throws HeadlessException;
241
242     /**
243      * Returns the default screen {@code GraphicsDevice}.
244      * @return the {@code GraphicsDevice} that represents the
245      * default screen device
246      * @exception HeadlessException if isHeadless() returns true
247      * @see #isHeadless()
248      */

249     public abstract GraphicsDevice getDefaultScreenDevice()
250         throws HeadlessException;
251
252     /**
253      * Returns a {@code Graphics2D} object for rendering into the
254      * specified {@link BufferedImage}.
255      * @param img the specified {@code BufferedImage}
256      * @return a {@code Graphics2D} to be used for rendering into
257      * the specified {@code BufferedImage}
258      * @throws NullPointerException if {@code img} is null
259      */

260     public abstract Graphics2D createGraphics(BufferedImage img);
261
262     /**
263      * Returns an array containing a one-point size instance of all fonts
264      * available in this {@code GraphicsEnvironment}.  Typical usage
265      * would be to allow a user to select a particular font.  Then, the
266      * application can size the font and set various font attributes by
267      * calling the {@code deriveFont} method on the chosen instance.
268      * <p>
269      * This method provides for the application the most precise control
270      * over which {@code Font} instance is used to render text.
271      * If a font in this {@code GraphicsEnvironment} has multiple
272      * programmable variations, only one
273      * instance of that {@code Font} is returned in the array, and
274      * other variations must be derived by the application.
275      * <p>
276      * If a font in this environment has multiple programmable variations,
277      * such as Multiple-Master fonts, only one instance of that font is
278      * returned in the {@code Font} array.  The other variations
279      * must be derived by the application.
280      *
281      * @return an array of {@code Font} objects
282      * @see #getAvailableFontFamilyNames
283      * @see java.awt.Font
284      * @see java.awt.Font#deriveFont
285      * @see java.awt.Font#getFontName
286      * @since 1.2
287      */

288     public abstract Font[] getAllFonts();
289
290     /**
291      * Returns an array containing the names of all font families in this
292      * {@code GraphicsEnvironment} localized for the default locale,
293      * as returned by {@code Locale.getDefault()}.
294      * <p>
295      * Typical usage would be for presentation to a user for selection of
296      * a particular family name. An application can then specify this name
297      * when creating a font, in conjunction with a style, such as bold or
298      * italic, giving the font system flexibility in choosing its own best
299      * match among multiple fonts in the same font family.
300      *
301      * @return an array of {@code String} containing font family names
302      * localized for the default locale, or a suitable alternative
303      * name if no name exists for this locale.
304      * @see #getAllFonts
305      * @see java.awt.Font
306      * @see java.awt.Font#getFamily
307      * @since 1.2
308      */

309     public abstract String[] getAvailableFontFamilyNames();
310
311     /**
312      * Returns an array containing the names of all font families in this
313      * {@code GraphicsEnvironment} localized for the specified locale.
314      * <p>
315      * Typical usage would be for presentation to a user for selection of
316      * a particular family name. An application can then specify this name
317      * when creating a font, in conjunction with a style, such as bold or
318      * italic, giving the font system flexibility in choosing its own best
319      * match among multiple fonts in the same font family.
320      *
321      * @param l a {@link Locale} object that represents a
322      * particular geographical, political, or cultural region.
323      * Specifying {@code null} is equivalent to
324      * specifying {@code Locale.getDefault()}.
325      * @return an array of {@code String} containing font family names
326      * localized for the specified {@code Locale}, or a
327      * suitable alternative name if no name exists for the specified locale.
328      * @see #getAllFonts
329      * @see java.awt.Font
330      * @see java.awt.Font#getFamily
331      * @since 1.2
332      */

333     public abstract String[] getAvailableFontFamilyNames(Locale l);
334
335     /**
336      * Registers a <i>created</i> {@code Font} in this
337      * {@code GraphicsEnvironment}.
338      * A created font is one that was returned from calling
339      * {@link Font#createFont}, or derived from a created font by
340      * calling {@link Font#deriveFont}.
341      * After calling this method for such a font, it is available to
342      * be used in constructing new {@code Font}s by name or family name,
343      * and is enumerated by {@link #getAvailableFontFamilyNames} and
344      * {@link #getAllFonts} within the execution context of this
345      * application or applet. This means applets cannot register fonts in
346      * a way that they are visible to other applets.
347      * <p>
348      * Reasons that this method might not register the font and therefore
349      * return {@code false} are:
350      * <ul>
351      * <li>The font is not a <i>created</i> {@code Font}.
352      * <li>The font conflicts with a non-created {@code Font} already
353      * in this {@code GraphicsEnvironment}. For example if the name
354      * is that of a system font, or a logical font as described in the
355      * documentation of the {@link Font} class. It is implementation dependent
356      * whether a font may also conflict if it has the same family name
357      * as a system font.
358      * <p>Notice that an application can supersede the registration
359      * of an earlier created font with a new one.
360      * </ul>
361      *
362      * @param  font the font to be registered
363      * @return true if the {@code font} is successfully
364      * registered in this {@code GraphicsEnvironment}.
365      * @throws NullPointerException if {@code font} is null
366      * @since 1.6
367      */

368     public boolean registerFont(Font font) {
369         if (font == null) {
370             throw new NullPointerException("font cannot be null.");
371         }
372         FontManager fm = FontManagerFactory.getInstance();
373         return fm.registerFont(font);
374     }
375
376     /**
377      * Indicates a preference for locale-specific fonts in the mapping of
378      * logical fonts to physical fonts. Calling this method indicates that font
379      * rendering should primarily use fonts specific to the primary writing
380      * system (the one indicated by the default encoding and the initial
381      * default locale). For example, if the primary writing system is
382      * Japanese, then characters should be rendered using a Japanese font
383      * if possible, and other fonts should only be used for characters for
384      * which the Japanese font doesn't have glyphs.
385      * <p>
386      * The actual change in font rendering behavior resulting from a call
387      * to this method is implementation dependent; it may have no effect at
388      * all, or the requested behavior may already match the default behavior.
389      * The behavior may differ between font rendering in lightweight
390      * and peered components.  Since calling this method requests a
391      * different font, clients should expect different metrics, and may need
392      * to recalculate window sizes and layout. Therefore this method should
393      * be called before user interface initialisation.
394      * @since 1.5
395      */

396     public void preferLocaleFonts() {
397         FontManager fm = FontManagerFactory.getInstance();
398         fm.preferLocaleFonts();
399     }
400
401     /**
402      * Indicates a preference for proportional over non-proportional (e.g.
403      * dual-spaced CJK fonts) fonts in the mapping of logical fonts to
404      * physical fonts. If the default mapping contains fonts for which
405      * proportional and non-proportional variants exist, then calling
406      * this method indicates the mapping should use a proportional variant.
407      * <p>
408      * The actual change in font rendering behavior resulting from a call to
409      * this method is implementation dependent; it may have no effect at all.
410      * The behavior may differ between font rendering in lightweight and
411      * peered components. Since calling this method requests a
412      * different font, clients should expect different metrics, and may need
413      * to recalculate window sizes and layout. Therefore this method should
414      * be called before user interface initialisation.
415      * @since 1.5
416      */

417     public void preferProportionalFonts() {
418         FontManager fm = FontManagerFactory.getInstance();
419         fm.preferProportionalFonts();
420     }
421
422     /**
423      * Returns the Point where Windows should be centered.
424      * It is recommended that centered Windows be checked to ensure they fit
425      * within the available display area using getMaximumWindowBounds().
426      * @return the point where Windows should be centered
427      *
428      * @exception HeadlessException if isHeadless() returns true
429      * @see #getMaximumWindowBounds
430      * @since 1.4
431      */

432     public Point getCenterPoint() throws HeadlessException {
433     // Default implementation: return the center of the usable bounds of the
434     // default screen device.
435         Rectangle usableBounds =
436          SunGraphicsEnvironment.getUsableBounds(getDefaultScreenDevice());
437         return new Point((usableBounds.width / 2) + usableBounds.x,
438                          (usableBounds.height / 2) + usableBounds.y);
439     }
440
441     /**
442      * Returns the maximum bounds for centered Windows.
443      * These bounds account for objects in the native windowing system such as
444      * task bars and menu bars.  The returned bounds will reside on a single
445      * display with one exception: on multi-screen systems where Windows should
446      * be centered across all displays, this method returns the bounds of the
447      * entire display area.
448      * <p>
449      * To get the usable bounds of a single display, use
450      * {@code GraphicsConfiguration.getBounds()} and
451      * {@code Toolkit.getScreenInsets()}.
452      * @return  the maximum bounds for centered Windows
453      *
454      * @exception HeadlessException if isHeadless() returns true
455      * @see #getCenterPoint
456      * @see GraphicsConfiguration#getBounds
457      * @see Toolkit#getScreenInsets
458      * @since 1.4
459      */

460     public Rectangle getMaximumWindowBounds() throws HeadlessException {
461     // Default implementation: return the usable bounds of the default screen
462     // device.  This is correct for Microsoft Windows and non-Xinerama X11.
463         return SunGraphicsEnvironment.getUsableBounds(getDefaultScreenDevice());
464     }
465 }
466