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 27package java.awt; 28 29import java.awt.image.BufferedImage; 30import java.security.AccessController; 31import java.security.PrivilegedAction; 32import java.util.Locale; 33 34import sun.font.FontManager; 35import sun.font.FontManagerFactory; 36import sun.java2d.HeadlessGraphicsEnvironment; 37import sun.java2d.SunGraphicsEnvironment; 38import 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 56public 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