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 true} if 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 true} if 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