1 /* 2 * Copyright (c) 1997, 2014, 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 private static GraphicsEnvironment localEnv; 58 59 /** 60 * The headless state of the Toolkit and GraphicsEnvironment 61 */ 62 private static Boolean headless; 63 64 /** 65 * The headless state assumed by default 66 */ 67 private static Boolean defaultHeadless; 68 69 /** 70 * This is an abstract class and cannot be instantiated directly. 71 * Instances must be obtained from a suitable factory or query method. 72 */ 73 protected GraphicsEnvironment() { 74 } 75 76 /** 77 * Returns the local {@code GraphicsEnvironment}. 78 * @return the local {@code GraphicsEnvironment} 79 */ 80 public static synchronized GraphicsEnvironment getLocalGraphicsEnvironment() { 81 if (localEnv == null) { 82 localEnv = createGE(); 83 } 84 85 return localEnv; 86 } 87 88 /** 89 * Creates and returns the GraphicsEnvironment, according to the 90 * system property 'java.awt.graphicsenv'. 91 * 92 * @return the graphics environment 93 */ 94 private static GraphicsEnvironment createGE() { 95 GraphicsEnvironment ge; 96 String nm = AccessController.doPrivileged(new GetPropertyAction("java.awt.graphicsenv", null)); 97 try { 98 // long t0 = System.currentTimeMillis(); 99 Class<?> geCls; 100 try { 101 // First we try if the bootstrap class loader finds the 102 // requested class. This way we can avoid to run in a privileged 103 // block. 104 geCls = Class.forName(nm); 105 } catch (ClassNotFoundException ex) { 106 // If the bootstrap class loader fails, we try again with the 107 // application class loader. 108 ClassLoader cl = ClassLoader.getSystemClassLoader(); 109 geCls = Class.forName(nm, true, cl); 110 } 111 ge = (GraphicsEnvironment)geCls.getConstructor().newInstance(); 112 // long t1 = System.currentTimeMillis(); 113 // System.out.println("GE creation took " + (t1-t0)+ "ms."); 114 if (isHeadless()) { 115 ge = new HeadlessGraphicsEnvironment(ge); 116 } 117 } catch (ClassNotFoundException e) { 118 throw new Error("Could not find class: "+nm); 119 } catch (ReflectiveOperationException | IllegalArgumentException e) { 120 throw new Error("Could not instantiate Graphics Environment: " 121 + nm); 122 } 123 return ge; 124 } 125 126 /** 127 * Tests whether or not a display, keyboard, and mouse can be 128 * supported in this environment. If this method returns true, 129 * a HeadlessException is thrown from areas of the Toolkit 130 * and GraphicsEnvironment that are dependent on a display, 131 * keyboard, or mouse. 132 * @return {@code true} if this environment cannot support 133 * a display, keyboard, and mouse; {@code false} 134 * otherwise 135 * @see java.awt.HeadlessException 136 * @since 1.4 137 */ 138 public static boolean isHeadless() { 139 return getHeadlessProperty(); 140 } 141 142 /** 143 * @return warning message if headless state is assumed by default; 144 * null otherwise 145 * @since 1.5 146 */ 147 static String getHeadlessMessage() { 148 if (headless == null) { 149 getHeadlessProperty(); // initialize the values 150 } 151 return defaultHeadless != Boolean.TRUE ? null : 152 "\nNo X11 DISPLAY variable was set, " + 153 "but this program performed an operation which requires it."; 154 } 155 156 /** 157 * @return the value of the property "java.awt.headless" 158 * @since 1.4 159 */ 160 private static boolean getHeadlessProperty() { 161 if (headless == null) { 162 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 163 String nm = System.getProperty("java.awt.headless"); 164 165 if (nm == null) { 166 /* No need to ask for DISPLAY when run in a browser */ 167 if (System.getProperty("javaplugin.version") != null) { 168 headless = defaultHeadless = Boolean.FALSE; 169 } else { 170 String osName = System.getProperty("os.name"); 171 if (osName.contains("OS X") && "sun.awt.HToolkit".equals( 172 System.getProperty("awt.toolkit"))) 173 { 174 headless = defaultHeadless = Boolean.TRUE; 175 } else { 176 final String display = System.getenv("DISPLAY"); 177 headless = defaultHeadless = 178 ("Linux".equals(osName) || 179 "SunOS".equals(osName) || 180 "FreeBSD".equals(osName) || 181 "NetBSD".equals(osName) || 182 "OpenBSD".equals(osName) || 183 "AIX".equals(osName)) && 184 (display == null || display.trim().isEmpty()); 185 } 186 } 187 } else { 188 headless = Boolean.valueOf(nm); 189 } 190 return null; 191 }); 192 } 193 return headless; 194 } 195 196 /** 197 * Check for headless state and throw HeadlessException if headless 198 * @since 1.4 199 */ 200 static void checkHeadless() throws HeadlessException { 201 if (isHeadless()) { 202 throw new HeadlessException(); 203 } 204 } 205 206 /** 207 * Returns whether or not a display, keyboard, and mouse can be 208 * supported in this graphics environment. If this returns true, 209 * {@code HeadlessException} will be thrown from areas of the 210 * graphics environment that are dependent on a display, keyboard, or 211 * mouse. 212 * @return {@code true} if a display, keyboard, and mouse 213 * can be supported in this environment; {@code false} 214 * otherwise 215 * @see java.awt.HeadlessException 216 * @see #isHeadless 217 * @since 1.4 218 */ 219 public boolean isHeadlessInstance() { 220 // By default (local graphics environment), simply check the 221 // headless property. 222 return getHeadlessProperty(); 223 } 224 225 /** 226 * Returns an array of all of the screen {@code GraphicsDevice} 227 * objects. 228 * @return an array containing all the {@code GraphicsDevice} 229 * objects that represent screen devices 230 * @exception HeadlessException if isHeadless() returns true 231 * @see #isHeadless() 232 */ 233 public abstract GraphicsDevice[] getScreenDevices() 234 throws HeadlessException; 235 236 /** 237 * Returns the default screen {@code GraphicsDevice}. 238 * @return the {@code GraphicsDevice} that represents the 239 * default screen device 240 * @exception HeadlessException if isHeadless() returns true 241 * @see #isHeadless() 242 */ 243 public abstract GraphicsDevice getDefaultScreenDevice() 244 throws HeadlessException; 245 246 /** 247 * Returns a {@code Graphics2D} object for rendering into the 248 * specified {@link BufferedImage}. 249 * @param img the specified {@code BufferedImage} 250 * @return a {@code Graphics2D} to be used for rendering into 251 * the specified {@code BufferedImage} 252 * @throws NullPointerException if {@code img} is null 253 */ 254 public abstract Graphics2D createGraphics(BufferedImage img); 255 256 /** 257 * Returns an array containing a one-point size instance of all fonts 258 * available in this {@code GraphicsEnvironment}. Typical usage 259 * would be to allow a user to select a particular font. Then, the 260 * application can size the font and set various font attributes by 261 * calling the {@code deriveFont} method on the chosen instance. 262 * <p> 263 * This method provides for the application the most precise control 264 * over which {@code Font} instance is used to render text. 265 * If a font in this {@code GraphicsEnvironment} has multiple 266 * programmable variations, only one 267 * instance of that {@code Font} is returned in the array, and 268 * other variations must be derived by the application. 269 * <p> 270 * If a font in this environment has multiple programmable variations, 271 * such as Multiple-Master fonts, only one instance of that font is 272 * returned in the {@code Font} array. The other variations 273 * must be derived by the application. 274 * 275 * @return an array of {@code Font} objects 276 * @see #getAvailableFontFamilyNames 277 * @see java.awt.Font 278 * @see java.awt.Font#deriveFont 279 * @see java.awt.Font#getFontName 280 * @since 1.2 281 */ 282 public abstract Font[] getAllFonts(); 283 284 /** 285 * Returns an array containing the names of all font families in this 286 * {@code GraphicsEnvironment} localized for the default locale, 287 * as returned by {@code Locale.getDefault()}. 288 * <p> 289 * Typical usage would be for presentation to a user for selection of 290 * a particular family name. An application can then specify this name 291 * when creating a font, in conjunction with a style, such as bold or 292 * italic, giving the font system flexibility in choosing its own best 293 * match among multiple fonts in the same font family. 294 * 295 * @return an array of {@code String} containing font family names 296 * localized for the default locale, or a suitable alternative 297 * name if no name exists for this locale. 298 * @see #getAllFonts 299 * @see java.awt.Font 300 * @see java.awt.Font#getFamily 301 * @since 1.2 302 */ 303 public abstract String[] getAvailableFontFamilyNames(); 304 305 /** 306 * Returns an array containing the names of all font families in this 307 * {@code GraphicsEnvironment} localized for the specified locale. 308 * <p> 309 * Typical usage would be for presentation to a user for selection of 310 * a particular family name. An application can then specify this name 311 * when creating a font, in conjunction with a style, such as bold or 312 * italic, giving the font system flexibility in choosing its own best 313 * match among multiple fonts in the same font family. 314 * 315 * @param l a {@link Locale} object that represents a 316 * particular geographical, political, or cultural region. 317 * Specifying {@code null} is equivalent to 318 * specifying {@code Locale.getDefault()}. 319 * @return an array of {@code String} containing font family names 320 * localized for the specified {@code Locale}, or a 321 * suitable alternative name if no name exists for the specified locale. 322 * @see #getAllFonts 323 * @see java.awt.Font 324 * @see java.awt.Font#getFamily 325 * @since 1.2 326 */ 327 public abstract String[] getAvailableFontFamilyNames(Locale l); 328 329 /** 330 * Registers a <i>created</i> {@code Font} in this 331 * {@code GraphicsEnvironment}. 332 * A created font is one that was returned from calling 333 * {@link Font#createFont}, or derived from a created font by 334 * calling {@link Font#deriveFont}. 335 * After calling this method for such a font, it is available to 336 * be used in constructing new {@code Font}s by name or family name, 337 * and is enumerated by {@link #getAvailableFontFamilyNames} and 338 * {@link #getAllFonts} within the execution context of this 339 * application or applet. This means applets cannot register fonts in 340 * a way that they are visible to other applets. 341 * <p> 342 * Reasons that this method might not register the font and therefore 343 * return {@code false} are: 344 * <ul> 345 * <li>The font is not a <i>created</i> {@code Font}. 346 * <li>The font conflicts with a non-created {@code Font} already 347 * in this {@code GraphicsEnvironment}. For example if the name 348 * is that of a system font, or a logical font as described in the 349 * documentation of the {@link Font} class. It is implementation dependent 350 * whether a font may also conflict if it has the same family name 351 * as a system font. 352 * <p>Notice that an application can supersede the registration 353 * of an earlier created font with a new one. 354 * </ul> 355 * 356 * @param font the font to be registered 357 * @return true if the {@code font} is successfully 358 * registered in this {@code GraphicsEnvironment}. 359 * @throws NullPointerException if {@code font} is null 360 * @since 1.6 361 */ 362 public boolean registerFont(Font font) { 363 if (font == null) { 364 throw new NullPointerException("font cannot be null."); 365 } 366 FontManager fm = FontManagerFactory.getInstance(); 367 return fm.registerFont(font); 368 } 369 370 /** 371 * Indicates a preference for locale-specific fonts in the mapping of 372 * logical fonts to physical fonts. Calling this method indicates that font 373 * rendering should primarily use fonts specific to the primary writing 374 * system (the one indicated by the default encoding and the initial 375 * default locale). For example, if the primary writing system is 376 * Japanese, then characters should be rendered using a Japanese font 377 * if possible, and other fonts should only be used for characters for 378 * which the Japanese font doesn't have glyphs. 379 * <p> 380 * The actual change in font rendering behavior resulting from a call 381 * to this method is implementation dependent; it may have no effect at 382 * all, or the requested behavior may already match the default behavior. 383 * The behavior may differ between font rendering in lightweight 384 * and peered components. Since calling this method requests a 385 * different font, clients should expect different metrics, and may need 386 * to recalculate window sizes and layout. Therefore this method should 387 * be called before user interface initialisation. 388 * @since 1.5 389 */ 390 public void preferLocaleFonts() { 391 FontManager fm = FontManagerFactory.getInstance(); 392 fm.preferLocaleFonts(); 393 } 394 395 /** 396 * Indicates a preference for proportional over non-proportional (e.g. 397 * dual-spaced CJK fonts) fonts in the mapping of logical fonts to 398 * physical fonts. If the default mapping contains fonts for which 399 * proportional and non-proportional variants exist, then calling 400 * this method indicates the mapping should use a proportional variant. 401 * <p> 402 * The actual change in font rendering behavior resulting from a call to 403 * this method is implementation dependent; it may have no effect at all. 404 * The behavior may differ between font rendering in lightweight and 405 * peered components. Since calling this method requests a 406 * different font, clients should expect different metrics, and may need 407 * to recalculate window sizes and layout. Therefore this method should 408 * be called before user interface initialisation. 409 * @since 1.5 410 */ 411 public void preferProportionalFonts() { 412 FontManager fm = FontManagerFactory.getInstance(); 413 fm.preferProportionalFonts(); 414 } 415 416 /** 417 * Returns the Point where Windows should be centered. 418 * It is recommended that centered Windows be checked to ensure they fit 419 * within the available display area using getMaximumWindowBounds(). 420 * @return the point where Windows should be centered 421 * 422 * @exception HeadlessException if isHeadless() returns true 423 * @see #getMaximumWindowBounds 424 * @since 1.4 425 */ 426 public Point getCenterPoint() throws HeadlessException { 427 // Default implementation: return the center of the usable bounds of the 428 // default screen device. 429 Rectangle usableBounds = 430 SunGraphicsEnvironment.getUsableBounds(getDefaultScreenDevice()); 431 return new Point((usableBounds.width / 2) + usableBounds.x, 432 (usableBounds.height / 2) + usableBounds.y); 433 } 434 435 /** 436 * Returns the maximum bounds for centered Windows. 437 * These bounds account for objects in the native windowing system such as 438 * task bars and menu bars. The returned bounds will reside on a single 439 * display with one exception: on multi-screen systems where Windows should 440 * be centered across all displays, this method returns the bounds of the 441 * entire display area. 442 * <p> 443 * To get the usable bounds of a single display, use 444 * {@code GraphicsConfiguration.getBounds()} and 445 * {@code Toolkit.getScreenInsets()}. 446 * @return the maximum bounds for centered Windows 447 * 448 * @exception HeadlessException if isHeadless() returns true 449 * @see #getCenterPoint 450 * @see GraphicsConfiguration#getBounds 451 * @see Toolkit#getScreenInsets 452 * @since 1.4 453 */ 454 public Rectangle getMaximumWindowBounds() throws HeadlessException { 455 // Default implementation: return the usable bounds of the default screen 456 // device. This is correct for Microsoft Windows and non-Xinerama X11. 457 return SunGraphicsEnvironment.getUsableBounds(getDefaultScreenDevice()); 458 } 459 }