SunGraphicsEnvironment.java revision 13220:a8e9ad77ac81
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 26package sun.java2d; 27 28import java.awt.AWTError; 29import java.awt.Color; 30import java.awt.Font; 31import java.awt.Graphics2D; 32import java.awt.GraphicsConfiguration; 33import java.awt.GraphicsDevice; 34import java.awt.GraphicsEnvironment; 35import java.awt.Insets; 36import java.awt.Rectangle; 37import java.awt.Toolkit; 38import java.awt.font.TextAttribute; 39import java.awt.image.BufferedImage; 40import java.awt.peer.ComponentPeer; 41import java.io.BufferedReader; 42import java.io.File; 43import java.io.FileInputStream; 44import java.io.FilenameFilter; 45import java.io.InputStreamReader; 46import java.io.IOException; 47import java.text.AttributedCharacterIterator; 48import java.util.ArrayList; 49import java.util.HashSet; 50import java.util.Iterator; 51import java.util.Locale; 52import java.util.Map; 53import java.util.NoSuchElementException; 54import java.util.Set; 55import java.util.StringTokenizer; 56import java.util.TreeMap; 57import java.util.Vector; 58import java.util.concurrent.ConcurrentHashMap; 59import sun.awt.AppContext; 60import sun.awt.DisplayChangedListener; 61import sun.awt.FontConfiguration; 62import sun.awt.SunDisplayChanger; 63import sun.font.CompositeFontDescriptor; 64import sun.font.Font2D; 65import sun.font.FontManager; 66import sun.font.FontManagerFactory; 67import sun.font.FontManagerForSGE; 68import sun.font.NativeFont; 69import java.security.AccessController; 70import sun.security.action.GetPropertyAction; 71 72/** 73 * This is an implementation of a GraphicsEnvironment object for the 74 * default local GraphicsEnvironment. 75 * 76 * @see GraphicsDevice 77 * @see GraphicsConfiguration 78 */ 79public abstract class SunGraphicsEnvironment extends GraphicsEnvironment 80 implements DisplayChangedListener { 81 82 public static boolean isOpenSolaris; 83 private static Font defaultFont; 84 85 private static final boolean uiScaleEnabled; 86 private static final double debugScale; 87 88 static { 89 uiScaleEnabled = "true".equals(AccessController.doPrivileged( 90 new GetPropertyAction("sun.java2d.uiScale.enabled", "true"))); 91 debugScale = uiScaleEnabled ? getScaleFactor("sun.java2d.uiScale") : -1; 92 } 93 94 public SunGraphicsEnvironment() { 95 java.security.AccessController.doPrivileged( 96 new java.security.PrivilegedAction<Object>() { 97 public Object run() { 98 String osName = System.getProperty("os.name"); 99 if ("SunOS".equals(osName)) { 100 String version = System.getProperty("os.version", "0.0"); 101 try { 102 float ver = Float.parseFloat(version); 103 if (ver > 5.10f) { 104 File f = new File("/etc/release"); 105 FileInputStream fis = new FileInputStream(f); 106 InputStreamReader isr 107 = new InputStreamReader(fis, "ISO-8859-1"); 108 BufferedReader br = new BufferedReader(isr); 109 String line = br.readLine(); 110 if (line.indexOf("OpenSolaris") >= 0) { 111 isOpenSolaris = true; 112 } else { 113 /* We are using isOpenSolaris as meaning 114 * we know the Solaris commercial fonts aren't 115 * present. "Solaris Next" (03/10) did not 116 * include these even though its was not 117 * OpenSolaris. Need to revisit how this is 118 * handled but for now as in 6ux, we'll use 119 * the test for a standard font resource as 120 * being an indicator as to whether we need 121 * to treat this as OpenSolaris from a font 122 * config perspective. 123 */ 124 String courierNew = 125 "/usr/openwin/lib/X11/fonts/TrueType/CourierNew.ttf"; 126 File courierFile = new File(courierNew); 127 isOpenSolaris = !courierFile.exists(); 128 } 129 fis.close(); 130 } 131 } catch (Exception e) { 132 } 133 } 134 /* Establish the default font to be used by SG2D etc */ 135 defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12); 136 137 return null; 138 } 139 }); 140 } 141 142 protected GraphicsDevice[] screens; 143 144 /** 145 * Returns an array of all of the screen devices. 146 */ 147 public synchronized GraphicsDevice[] getScreenDevices() { 148 GraphicsDevice[] ret = screens; 149 if (ret == null) { 150 int num = getNumScreens(); 151 ret = new GraphicsDevice[num]; 152 for (int i = 0; i < num; i++) { 153 ret[i] = makeScreenDevice(i); 154 } 155 screens = ret; 156 } 157 return ret; 158 } 159 160 /** 161 * Returns the number of screen devices of this graphics environment. 162 * 163 * @return the number of screen devices of this graphics environment 164 */ 165 protected abstract int getNumScreens(); 166 167 /** 168 * Create and return the screen device with the specified number. The 169 * device with number <code>0</code> will be the default device (returned 170 * by {@link #getDefaultScreenDevice()}. 171 * 172 * @param screennum the number of the screen to create 173 * 174 * @return the created screen device 175 */ 176 protected abstract GraphicsDevice makeScreenDevice(int screennum); 177 178 /** 179 * Returns the default screen graphics device. 180 */ 181 public GraphicsDevice getDefaultScreenDevice() { 182 GraphicsDevice[] screens = getScreenDevices(); 183 if (screens.length == 0) { 184 throw new AWTError("no screen devices"); 185 } 186 return screens[0]; 187 } 188 189 /** 190 * Returns a Graphics2D object for rendering into the 191 * given BufferedImage. 192 * @throws NullPointerException if BufferedImage argument is null 193 */ 194 public Graphics2D createGraphics(BufferedImage img) { 195 if (img == null) { 196 throw new NullPointerException("BufferedImage cannot be null"); 197 } 198 SurfaceData sd = SurfaceData.getPrimarySurfaceData(img); 199 return new SunGraphics2D(sd, Color.white, Color.black, defaultFont); 200 } 201 202 public static FontManagerForSGE getFontManagerForSGE() { 203 FontManager fm = FontManagerFactory.getInstance(); 204 return (FontManagerForSGE) fm; 205 } 206 207 /* Modifies the behaviour of a subsequent call to preferLocaleFonts() 208 * to use Mincho instead of Gothic for dialoginput in JA locales 209 * on windows. Not needed on other platforms. 210 * 211 * DO NOT MOVE OR RENAME OR OTHERWISE ALTER THIS METHOD. 212 * ITS USED BY SOME NON-JRE INTERNAL CODE. 213 */ 214 public static void useAlternateFontforJALocales() { 215 getFontManagerForSGE().useAlternateFontforJALocales(); 216 } 217 218 /** 219 * Returns all fonts available in this environment. 220 */ 221 public Font[] getAllFonts() { 222 FontManagerForSGE fm = getFontManagerForSGE(); 223 Font[] installedFonts = fm.getAllInstalledFonts(); 224 Font[] created = fm.getCreatedFonts(); 225 if (created == null || created.length == 0) { 226 return installedFonts; 227 } else { 228 int newlen = installedFonts.length + created.length; 229 Font [] fonts = java.util.Arrays.copyOf(installedFonts, newlen); 230 System.arraycopy(created, 0, fonts, 231 installedFonts.length, created.length); 232 return fonts; 233 } 234 } 235 236 public String[] getAvailableFontFamilyNames(Locale requestedLocale) { 237 FontManagerForSGE fm = getFontManagerForSGE(); 238 String[] installed = fm.getInstalledFontFamilyNames(requestedLocale); 239 /* Use a new TreeMap as used in getInstalledFontFamilyNames 240 * and insert all the keys in lower case, so that the sort order 241 * is the same as the installed families. This preserves historical 242 * behaviour and inserts new families in the right place. 243 * It would have been marginally more efficient to directly obtain 244 * the tree map and just insert new entries, but not so much as 245 * to justify the extra internal interface. 246 */ 247 TreeMap<String, String> map = fm.getCreatedFontFamilyNames(); 248 if (map == null || map.size() == 0) { 249 return installed; 250 } else { 251 for (int i=0; i<installed.length; i++) { 252 map.put(installed[i].toLowerCase(requestedLocale), 253 installed[i]); 254 } 255 String[] retval = new String[map.size()]; 256 Object [] keyNames = map.keySet().toArray(); 257 for (int i=0; i < keyNames.length; i++) { 258 retval[i] = map.get(keyNames[i]); 259 } 260 return retval; 261 } 262 } 263 264 public String[] getAvailableFontFamilyNames() { 265 return getAvailableFontFamilyNames(Locale.getDefault()); 266 } 267 268 /** 269 * Return the bounds of a GraphicsDevice, less its screen insets. 270 * See also java.awt.GraphicsEnvironment.getUsableBounds(); 271 */ 272 public static Rectangle getUsableBounds(GraphicsDevice gd) { 273 GraphicsConfiguration gc = gd.getDefaultConfiguration(); 274 Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc); 275 Rectangle usableBounds = gc.getBounds(); 276 277 usableBounds.x += insets.left; 278 usableBounds.y += insets.top; 279 usableBounds.width -= (insets.left + insets.right); 280 usableBounds.height -= (insets.top + insets.bottom); 281 282 return usableBounds; 283 } 284 285 /** 286 * From the DisplayChangedListener interface; called 287 * when the display mode has been changed. 288 */ 289 public void displayChanged() { 290 // notify screens in device array to do display update stuff 291 for (GraphicsDevice gd : getScreenDevices()) { 292 if (gd instanceof DisplayChangedListener) { 293 ((DisplayChangedListener) gd).displayChanged(); 294 } 295 } 296 297 // notify SunDisplayChanger list (e.g. VolatileSurfaceManagers and 298 // SurfaceDataProxies) about the display change event 299 displayChanger.notifyListeners(); 300 } 301 302 /** 303 * Part of the DisplayChangedListener interface: 304 * propagate this event to listeners 305 */ 306 public void paletteChanged() { 307 displayChanger.notifyPaletteChanged(); 308 } 309 310 /** 311 * Returns true when the display is local, false for remote displays. 312 * 313 * @return true when the display is local, false for remote displays 314 */ 315 public abstract boolean isDisplayLocal(); 316 317 /* 318 * ----DISPLAY CHANGE SUPPORT---- 319 */ 320 321 protected SunDisplayChanger displayChanger = new SunDisplayChanger(); 322 323 /** 324 * Add a DisplayChangeListener to be notified when the display settings 325 * are changed. 326 */ 327 public void addDisplayChangedListener(DisplayChangedListener client) { 328 displayChanger.add(client); 329 } 330 331 /** 332 * Remove a DisplayChangeListener from Win32GraphicsEnvironment 333 */ 334 public void removeDisplayChangedListener(DisplayChangedListener client) { 335 displayChanger.remove(client); 336 } 337 338 /* 339 * ----END DISPLAY CHANGE SUPPORT---- 340 */ 341 342 /** 343 * Returns true if FlipBufferStrategy with COPIED buffer contents 344 * is preferred for this peer's GraphicsConfiguration over 345 * BlitBufferStrategy, false otherwise. 346 * 347 * The reason FlipBS could be preferred is that in some configurations 348 * an accelerated copy to the screen is supported (like Direct3D 9) 349 * 350 * @return true if flip strategy should be used, false otherwise 351 */ 352 public boolean isFlipStrategyPreferred(ComponentPeer peer) { 353 return false; 354 } 355 356 public static boolean isUIScaleEnabled() { 357 return uiScaleEnabled; 358 } 359 360 public static double getDebugScale() { 361 return debugScale; 362 } 363 364 public static double getScaleFactor(String propertyName) { 365 366 String scaleFactor = AccessController.doPrivileged( 367 new GetPropertyAction(propertyName, "-1")); 368 369 if (scaleFactor == null || scaleFactor.equals("-1")) { 370 return -1; 371 } 372 373 try { 374 double units = 1.0; 375 376 if (scaleFactor.endsWith("x")) { 377 scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 1); 378 } else if (scaleFactor.endsWith("dpi")) { 379 units = 96; 380 scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 3); 381 } else if (scaleFactor.endsWith("%")) { 382 units = 100; 383 scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 1); 384 } 385 386 double scale = Double.parseDouble(scaleFactor); 387 return scale <= 0 ? -1 : scale / units; 388 } catch (NumberFormatException ignored) { 389 return -1; 390 } 391 } 392} 393