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