62 import sun.awt.FontConfiguration; |
62 import sun.awt.FontConfiguration; |
63 import sun.awt.SunDisplayChanger; |
63 import sun.awt.SunDisplayChanger; |
64 import sun.font.CompositeFontDescriptor; |
64 import sun.font.CompositeFontDescriptor; |
65 import sun.font.Font2D; |
65 import sun.font.Font2D; |
66 import sun.font.FontManager; |
66 import sun.font.FontManager; |
|
67 import sun.font.FontManagerFactory; |
|
68 import sun.font.FontManagerForSGE; |
67 import sun.font.NativeFont; |
69 import sun.font.NativeFont; |
68 |
70 |
69 /** |
71 /** |
70 * This is an implementation of a GraphicsEnvironment object for the |
72 * This is an implementation of a GraphicsEnvironment object for the |
71 * default local GraphicsEnvironment. |
73 * default local GraphicsEnvironment. |
72 * |
74 * |
73 * @see GraphicsDevice |
75 * @see GraphicsDevice |
74 * @see GraphicsConfiguration |
76 * @see GraphicsConfiguration |
75 */ |
77 */ |
76 |
|
77 public abstract class SunGraphicsEnvironment extends GraphicsEnvironment |
78 public abstract class SunGraphicsEnvironment extends GraphicsEnvironment |
78 implements FontSupport, DisplayChangedListener { |
79 implements DisplayChangedListener { |
79 |
80 |
80 public static boolean isLinux; |
|
81 public static boolean isSolaris; |
|
82 public static boolean isOpenSolaris; |
81 public static boolean isOpenSolaris; |
83 public static boolean isWindows; |
|
84 public static boolean noType1Font; |
|
85 private static Font defaultFont; |
82 private static Font defaultFont; |
86 private static String defaultFontFileName; |
|
87 private static String defaultFontName; |
|
88 public static final String lucidaFontName = "Lucida Sans Regular"; |
|
89 public static final String lucidaFileName = "LucidaSansRegular.ttf"; |
|
90 public static boolean debugFonts = false; |
|
91 protected static Logger logger = null; |
83 protected static Logger logger = null; |
92 private static ArrayList badFonts; |
|
93 public static String jreLibDirName; |
|
94 public static String jreFontDirName; |
|
95 private static HashSet<String> missingFontFiles = null; |
|
96 |
|
97 private FontConfiguration fontConfig; |
|
98 |
|
99 /* fontPath is the location of all fonts on the system, excluding the |
|
100 * JRE's own font directory but including any path specified using the |
|
101 * sun.java2d.fontpath property. Together with that property, it is |
|
102 * initialised by the getPlatformFontPath() method |
|
103 * This call must be followed by a call to registerFontDirs(fontPath) |
|
104 * once any extra debugging path has been appended. |
|
105 */ |
|
106 protected String fontPath; |
|
107 |
|
108 /* discoveredAllFonts is set to true when all fonts on the font path are |
|
109 * discovered. This usually also implies opening, validating and |
|
110 * registering, but an implementation may be optimized to avold this. |
|
111 * So see also "loadedAllFontFiles" |
|
112 */ |
|
113 private boolean discoveredAllFonts = false; |
|
114 |
|
115 /* loadedAllFontFiles is set to true when all fonts on the font path are |
|
116 * actually opened, validated and registered. This always implies |
|
117 * discoveredAllFonts is true. |
|
118 */ |
|
119 private boolean loadedAllFontFiles = false; |
|
120 |
|
121 protected HashSet registeredFontFiles = new HashSet(); |
|
122 public static String eudcFontFileName; /* Initialised only on windows */ |
|
123 |
|
124 private static boolean isOpenJDK; |
|
125 /** |
|
126 * A few things in Java 2D code are different in OpenJDK, |
|
127 * so need a way to tell which implementation this is. |
|
128 * The absence of Lucida Sans Regular is the simplest way for now. |
|
129 */ |
|
130 public static boolean isOpenJDK() { |
|
131 return isOpenJDK; |
|
132 } |
|
133 |
|
134 static { |
|
135 java.security.AccessController.doPrivileged( |
|
136 new java.security.PrivilegedAction() { |
|
137 public Object run() { |
|
138 |
|
139 jreLibDirName = System.getProperty("java.home","") + |
|
140 File.separator + "lib"; |
|
141 jreFontDirName = jreLibDirName + File.separator + "fonts"; |
|
142 File lucidaFile = |
|
143 new File(jreFontDirName + File.separator + lucidaFileName); |
|
144 isOpenJDK = !lucidaFile.exists(); |
|
145 |
|
146 String debugLevel = |
|
147 System.getProperty("sun.java2d.debugfonts"); |
|
148 |
|
149 if (debugLevel != null && !debugLevel.equals("false")) { |
|
150 debugFonts = true; |
|
151 logger = Logger.getLogger("sun.java2d"); |
|
152 if (debugLevel.equals("warning")) { |
|
153 logger.setLevel(Level.WARNING); |
|
154 } else if (debugLevel.equals("severe")) { |
|
155 logger.setLevel(Level.SEVERE); |
|
156 } |
|
157 } |
|
158 return null; |
|
159 } |
|
160 }); |
|
161 }; |
|
162 |
84 |
163 public SunGraphicsEnvironment() { |
85 public SunGraphicsEnvironment() { |
164 java.security.AccessController.doPrivileged( |
86 java.security.AccessController.doPrivileged( |
165 new java.security.PrivilegedAction() { |
87 new java.security.PrivilegedAction() { |
166 public Object run() { |
88 public Object run() { |
167 String osName = System.getProperty("os.name"); |
|
168 if ("Linux".equals(osName)) { |
|
169 isLinux = true; |
|
170 } else if ("SunOS".equals(osName)) { |
|
171 isSolaris = true; |
|
172 String version = System.getProperty("os.version", "0.0"); |
89 String version = System.getProperty("os.version", "0.0"); |
173 try { |
90 try { |
174 float ver = Float.parseFloat(version); |
91 float ver = Float.parseFloat(version); |
175 if (ver > 5.10f) { |
92 if (ver > 5.10f) { |
176 File f = new File("/etc/release"); |
93 File f = new File("/etc/release"); |
184 } |
101 } |
185 fis.close(); |
102 fis.close(); |
186 } |
103 } |
187 } catch (Exception e) { |
104 } catch (Exception e) { |
188 } |
105 } |
189 } else if ("Windows".equals(osName)) { |
|
190 isWindows = true; |
|
191 } |
|
192 |
|
193 noType1Font = "true". |
|
194 equals(System.getProperty("sun.java2d.noType1Font")); |
|
195 |
|
196 if (!isOpenJDK()) { |
|
197 defaultFontName = lucidaFontName; |
|
198 if (useAbsoluteFontFileNames()) { |
|
199 defaultFontFileName = |
|
200 jreFontDirName + File.separator + lucidaFileName; |
|
201 } else { |
|
202 defaultFontFileName = lucidaFileName; |
|
203 } |
|
204 } |
|
205 |
|
206 File badFontFile = |
|
207 new File(jreFontDirName + File.separator + "badfonts.txt"); |
|
208 if (badFontFile.exists()) { |
|
209 FileInputStream fis = null; |
|
210 try { |
|
211 badFonts = new ArrayList(); |
|
212 fis = new FileInputStream(badFontFile); |
|
213 InputStreamReader isr = new InputStreamReader(fis); |
|
214 BufferedReader br = new BufferedReader(isr); |
|
215 while (true) { |
|
216 String name = br.readLine(); |
|
217 if (name == null) { |
|
218 break; |
|
219 } else { |
|
220 if (debugFonts) { |
|
221 logger.warning("read bad font: " + name); |
|
222 } |
|
223 badFonts.add(name); |
|
224 } |
|
225 } |
|
226 } catch (IOException e) { |
|
227 try { |
|
228 if (fis != null) { |
|
229 fis.close(); |
|
230 } |
|
231 } catch (IOException ioe) { |
|
232 } |
|
233 } |
|
234 } |
|
235 |
|
236 /* Here we get the fonts in jre/lib/fonts and register them |
|
237 * so they are always available and preferred over other fonts. |
|
238 * This needs to be registered before the composite fonts as |
|
239 * otherwise some native font that corresponds may be found |
|
240 * as we don't have a way to handle two fonts of the same |
|
241 * name, so the JRE one must be the first one registered. |
|
242 * Pass "true" to registerFonts method as on-screen these |
|
243 * JRE fonts always go through the T2K rasteriser. |
|
244 */ |
|
245 if (isLinux) { |
|
246 /* Linux font configuration uses these fonts */ |
|
247 registerFontDir(jreFontDirName); |
|
248 } |
|
249 registerFontsInDir(jreFontDirName, true, Font2D.JRE_RANK, |
|
250 true, false); |
|
251 |
|
252 /* Register the JRE fonts so that the native platform can |
|
253 * access them. This is used only on Windows so that when |
|
254 * printing the printer driver can access the fonts. |
|
255 */ |
|
256 registerJREFontsWithPlatform(jreFontDirName); |
|
257 |
|
258 /* Create the font configuration and get any font path |
|
259 * that might be specified. |
|
260 */ |
|
261 fontConfig = createFontConfiguration(); |
|
262 if (isOpenJDK()) { |
|
263 String[] fontInfo = FontManager.getDefaultPlatformFont(); |
|
264 defaultFontName = fontInfo[0]; |
|
265 defaultFontFileName = fontInfo[1]; |
|
266 } |
|
267 getPlatformFontPathFromFontConfig(); |
|
268 |
|
269 String extraFontPath = fontConfig.getExtraFontPath(); |
|
270 |
|
271 /* In prior releases the debugging font path replaced |
|
272 * all normally located font directories except for the |
|
273 * JRE fonts dir. This directory is still always located and |
|
274 * placed at the head of the path but as an augmentation |
|
275 * to the previous behaviour the |
|
276 * changes below allow you to additionally append to |
|
277 * the font path by starting with append: or prepend by |
|
278 * starting with a prepend: sign. Eg: to append |
|
279 * -Dsun.java2d.fontpath=append:/usr/local/myfonts |
|
280 * and to prepend |
|
281 * -Dsun.java2d.fontpath=prepend:/usr/local/myfonts Disp |
|
282 * |
|
283 * If there is an appendedfontpath it in the font configuration |
|
284 * it is used instead of searching the system for dirs. |
|
285 * The behaviour of append and prepend is then similar |
|
286 * to the normal case. ie it goes after what |
|
287 * you prepend and * before what you append. If the |
|
288 * sun.java2d.fontpath property is used, but it |
|
289 * neither the append or prepend syntaxes is used then as |
|
290 * except for the JRE dir the path is replaced and it is |
|
291 * up to you to make sure that all the right directories |
|
292 * are located. This is platform and locale-specific so |
|
293 * its almost impossible to get right, so it should be |
|
294 * used with caution. |
|
295 */ |
|
296 boolean prependToPath = false; |
|
297 boolean appendToPath = false; |
|
298 String dbgFontPath = System.getProperty("sun.java2d.fontpath"); |
|
299 |
|
300 if (dbgFontPath != null) { |
|
301 if (dbgFontPath.startsWith("prepend:")) { |
|
302 prependToPath = true; |
|
303 dbgFontPath = |
|
304 dbgFontPath.substring("prepend:".length()); |
|
305 } else if (dbgFontPath.startsWith("append:")) { |
|
306 appendToPath = true; |
|
307 dbgFontPath = |
|
308 dbgFontPath.substring("append:".length()); |
|
309 } |
|
310 } |
|
311 |
|
312 if (debugFonts) { |
|
313 logger.info("JRE font directory: " + jreFontDirName); |
|
314 logger.info("Extra font path: " + extraFontPath); |
|
315 logger.info("Debug font path: " + dbgFontPath); |
|
316 } |
|
317 |
|
318 if (dbgFontPath != null) { |
|
319 /* In debugging mode we register all the paths |
|
320 * Caution: this is a very expensive call on Solaris:- |
|
321 */ |
|
322 fontPath = getPlatformFontPath(noType1Font); |
|
323 |
|
324 if (extraFontPath != null) { |
|
325 fontPath = |
|
326 extraFontPath + File.pathSeparator + fontPath; |
|
327 } |
|
328 if (appendToPath) { |
|
329 fontPath = fontPath + File.pathSeparator + dbgFontPath; |
|
330 } else if (prependToPath) { |
|
331 fontPath = dbgFontPath + File.pathSeparator + fontPath; |
|
332 } else { |
|
333 fontPath = dbgFontPath; |
|
334 } |
|
335 registerFontDirs(fontPath); |
|
336 } else if (extraFontPath != null) { |
|
337 /* If the font configuration contains an "appendedfontpath" |
|
338 * entry, it is interpreted as a set of locations that |
|
339 * should always be registered. |
|
340 * It may be additional to locations normally found for |
|
341 * that place, or it may be locations that need to have |
|
342 * all their paths registered to locate all the needed |
|
343 * platform names. |
|
344 * This is typically when the same .TTF file is referenced |
|
345 * from multiple font.dir files and all of these must be |
|
346 * read to find all the native (XLFD) names for the font, |
|
347 * so that X11 font APIs can be used for as many code |
|
348 * points as possible. |
|
349 */ |
|
350 registerFontDirs(extraFontPath); |
|
351 } |
|
352 |
|
353 /* On Solaris, we need to register the Japanese TrueType |
|
354 * directory so that we can find the corresponding bitmap |
|
355 * fonts. This could be done by listing the directory in |
|
356 * the font configuration file, but we don't want to |
|
357 * confuse users with this quirk. There are no bitmap fonts |
|
358 * for other writing systems that correspond to TrueType |
|
359 * fonts and have matching XLFDs. We need to register the |
|
360 * bitmap fonts only in environments where they're on the |
|
361 * X font path, i.e., in the Japanese locale. |
|
362 * Note that if the X Toolkit is in use the font path isn't |
|
363 * set up by JDK, but users of a JA locale should have it |
|
364 * set up already by their login environment. |
|
365 */ |
|
366 if (isSolaris && Locale.JAPAN.equals(Locale.getDefault())) { |
|
367 registerFontDir("/usr/openwin/lib/locale/ja/X11/fonts/TT"); |
|
368 } |
|
369 |
|
370 initCompositeFonts(fontConfig, null); |
|
371 |
106 |
372 /* Establish the default font to be used by SG2D etc */ |
107 /* Establish the default font to be used by SG2D etc */ |
373 defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12); |
108 defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12); |
374 |
109 |
375 return null; |
110 return null; |
416 } |
166 } |
417 SurfaceData sd = SurfaceData.getPrimarySurfaceData(img); |
167 SurfaceData sd = SurfaceData.getPrimarySurfaceData(img); |
418 return new SunGraphics2D(sd, Color.white, Color.black, defaultFont); |
168 return new SunGraphics2D(sd, Color.white, Color.black, defaultFont); |
419 } |
169 } |
420 |
170 |
421 /* A call to this method should be followed by a call to |
171 private static FontManagerForSGE getFontManagerForSGE() { |
422 * registerFontDirs(..) |
172 FontManager fm = FontManagerFactory.getInstance(); |
423 */ |
173 return (FontManagerForSGE) fm; |
424 protected String getPlatformFontPath(boolean noType1Font) { |
174 } |
425 if (fontPath == null) { |
|
426 fontPath = FontManager.getFontPath(noType1Font); |
|
427 } |
|
428 return fontPath; |
|
429 } |
|
430 |
|
431 private String[] platformFontDirs; |
|
432 /** |
|
433 * Get all directories which contain installed fonts. |
|
434 */ |
|
435 public String[] getPlatformFontDirs() { |
|
436 if (platformFontDirs == null) { |
|
437 String path = getPlatformFontPath(noType1Font); |
|
438 StringTokenizer parser = |
|
439 new StringTokenizer(path, File.pathSeparator);; |
|
440 ArrayList<String> pathList = new ArrayList<String>(); |
|
441 try { |
|
442 while (parser.hasMoreTokens()) { |
|
443 pathList.add(parser.nextToken()); |
|
444 } |
|
445 } catch (NoSuchElementException e) { |
|
446 } |
|
447 platformFontDirs = pathList.toArray(new String[0]); |
|
448 } |
|
449 return platformFontDirs; |
|
450 } |
|
451 |
|
452 /** |
|
453 * Whether registerFontFile expects absolute or relative |
|
454 * font file names. |
|
455 */ |
|
456 protected boolean useAbsoluteFontFileNames() { |
|
457 return true; |
|
458 } |
|
459 |
|
460 /** |
|
461 * Returns file name for default font, either absolute |
|
462 * or relative as needed by registerFontFile. |
|
463 */ |
|
464 public String getDefaultFontFile() { |
|
465 return defaultFontFileName; |
|
466 } |
|
467 |
|
468 /** |
|
469 * Returns face name for default font, or null if |
|
470 * no face names are used for CompositeFontDescriptors |
|
471 * for this platform. |
|
472 */ |
|
473 public String getDefaultFontFaceName() { |
|
474 return defaultFontName; |
|
475 } |
|
476 |
|
477 public void loadFonts() { |
|
478 if (discoveredAllFonts) { |
|
479 return; |
|
480 } |
|
481 /* Use lock specific to the font system */ |
|
482 synchronized (lucidaFontName) { |
|
483 if (debugFonts) { |
|
484 Thread.dumpStack(); |
|
485 logger.info("SunGraphicsEnvironment.loadFonts() called"); |
|
486 } |
|
487 FontManager.initialiseDeferredFonts(); |
|
488 |
|
489 java.security.AccessController.doPrivileged( |
|
490 new java.security.PrivilegedAction() { |
|
491 public Object run() { |
|
492 if (fontPath == null) { |
|
493 fontPath = getPlatformFontPath(noType1Font); |
|
494 registerFontDirs(fontPath); |
|
495 } |
|
496 if (fontPath != null) { |
|
497 // this will find all fonts including those already |
|
498 // registered. But we have checks in place to prevent |
|
499 // double registration. |
|
500 if (!FontManager.gotFontsFromPlatform()) { |
|
501 registerFontsOnPath(fontPath, false, |
|
502 Font2D.UNKNOWN_RANK, |
|
503 false, true); |
|
504 loadedAllFontFiles = true; |
|
505 } |
|
506 } |
|
507 FontManager.registerOtherFontFiles(registeredFontFiles); |
|
508 discoveredAllFonts = true; |
|
509 return null; |
|
510 } |
|
511 }); |
|
512 } |
|
513 } |
|
514 |
|
515 |
|
516 public void loadFontFiles() { |
|
517 loadFonts(); |
|
518 if (loadedAllFontFiles) { |
|
519 return; |
|
520 } |
|
521 /* Use lock specific to the font system */ |
|
522 synchronized (lucidaFontName) { |
|
523 if (debugFonts) { |
|
524 Thread.dumpStack(); |
|
525 logger.info("loadAllFontFiles() called"); |
|
526 } |
|
527 java.security.AccessController.doPrivileged( |
|
528 new java.security.PrivilegedAction() { |
|
529 public Object run() { |
|
530 if (fontPath == null) { |
|
531 fontPath = getPlatformFontPath(noType1Font); |
|
532 } |
|
533 if (fontPath != null) { |
|
534 // this will find all fonts including those already |
|
535 // registered. But we have checks in place to prevent |
|
536 // double registration. |
|
537 registerFontsOnPath(fontPath, false, |
|
538 Font2D.UNKNOWN_RANK, |
|
539 false, true); |
|
540 } |
|
541 loadedAllFontFiles = true; |
|
542 return null; |
|
543 } |
|
544 }); |
|
545 } |
|
546 } |
|
547 |
|
548 /* |
|
549 * This is for use only within getAllFonts(). |
|
550 * Fonts listed in the fontconfig files for windows were all |
|
551 * on the "deferred" initialisation list. They were registered |
|
552 * either in the course of the application, or in the call to |
|
553 * loadFonts() within getAllFonts(). The fontconfig file specifies |
|
554 * the names of the fonts using the English names. If there's a |
|
555 * different name in the execution locale, then the platform will |
|
556 * report that, and we will construct the font with both names, and |
|
557 * thereby enumerate it twice. This happens for Japanese fonts listed |
|
558 * in the windows fontconfig, when run in the JA locale. The solution |
|
559 * is to rely (in this case) on the platform's font->file mapping to |
|
560 * determine that this name corresponds to a file we already registered. |
|
561 * This works because |
|
562 * - we know when we get here all deferred fonts are already initialised |
|
563 * - when we register a font file, we register all fonts in it. |
|
564 * - we know the fontconfig fonts are all in the windows registry |
|
565 */ |
|
566 private boolean isNameForRegisteredFile(String fontName) { |
|
567 String fileName = FontManager.getFileNameForFontName(fontName); |
|
568 if (fileName == null) { |
|
569 return false; |
|
570 } |
|
571 return registeredFontFiles.contains(fileName); |
|
572 } |
|
573 |
|
574 private Font[] allFonts; |
|
575 |
|
576 /** |
|
577 * Returns all fonts installed in this environment. |
|
578 */ |
|
579 public Font[] getAllInstalledFonts() { |
|
580 if (allFonts == null) { |
|
581 loadFonts(); |
|
582 TreeMap fontMapNames = new TreeMap(); |
|
583 /* warning: the number of composite fonts could change dynamically |
|
584 * if applications are allowed to create them. "allfonts" could |
|
585 * then be stale. |
|
586 */ |
|
587 |
|
588 Font2D[] allfonts = FontManager.getRegisteredFonts(); |
|
589 for (int i=0; i < allfonts.length; i++) { |
|
590 if (!(allfonts[i] instanceof NativeFont)) { |
|
591 fontMapNames.put(allfonts[i].getFontName(null), |
|
592 allfonts[i]); |
|
593 } |
|
594 } |
|
595 |
|
596 String[] platformNames = FontManager.getFontNamesFromPlatform(); |
|
597 if (platformNames != null) { |
|
598 for (int i=0; i<platformNames.length; i++) { |
|
599 if (!isNameForRegisteredFile(platformNames[i])) { |
|
600 fontMapNames.put(platformNames[i], null); |
|
601 } |
|
602 } |
|
603 } |
|
604 |
|
605 String[] fontNames = null; |
|
606 if (fontMapNames.size() > 0) { |
|
607 fontNames = new String[fontMapNames.size()]; |
|
608 Object [] keyNames = fontMapNames.keySet().toArray(); |
|
609 for (int i=0; i < keyNames.length; i++) { |
|
610 fontNames[i] = (String)keyNames[i]; |
|
611 } |
|
612 } |
|
613 Font[] fonts = new Font[fontNames.length]; |
|
614 for (int i=0; i < fontNames.length; i++) { |
|
615 fonts[i] = new Font(fontNames[i], Font.PLAIN, 1); |
|
616 Font2D f2d = (Font2D)fontMapNames.get(fontNames[i]); |
|
617 if (f2d != null) { |
|
618 FontManager.setFont2D(fonts[i], f2d.handle); |
|
619 } |
|
620 } |
|
621 allFonts = fonts; |
|
622 } |
|
623 |
|
624 Font []copyFonts = new Font[allFonts.length]; |
|
625 System.arraycopy(allFonts, 0, copyFonts, 0, allFonts.length); |
|
626 return copyFonts; |
|
627 } |
|
628 |
|
629 /** |
175 /** |
630 * Returns all fonts available in this environment. |
176 * Returns all fonts available in this environment. |
631 */ |
177 */ |
632 public Font[] getAllFonts() { |
178 public Font[] getAllFonts() { |
633 Font[] installedFonts = getAllInstalledFonts(); |
179 FontManagerForSGE fm = getFontManagerForSGE(); |
634 Font[] created = FontManager.getCreatedFonts(); |
180 Font[] installedFonts = fm.getAllInstalledFonts(); |
|
181 Font[] created = fm.getCreatedFonts(); |
635 if (created == null || created.length == 0) { |
182 if (created == null || created.length == 0) { |
636 return installedFonts; |
183 return installedFonts; |
637 } else { |
184 } else { |
638 int newlen = installedFonts.length + created.length; |
185 int newlen = installedFonts.length + created.length; |
639 Font [] fonts = java.util.Arrays.copyOf(installedFonts, newlen); |
186 Font [] fonts = java.util.Arrays.copyOf(installedFonts, newlen); |
641 installedFonts.length, created.length); |
188 installedFonts.length, created.length); |
642 return fonts; |
189 return fonts; |
643 } |
190 } |
644 } |
191 } |
645 |
192 |
646 /** |
|
647 * Default locale can be changed but we need to know the initial locale |
|
648 * as that is what is used by native code. Changing Java default locale |
|
649 * doesn't affect that. |
|
650 * Returns the locale in use when using native code to communicate |
|
651 * with platform APIs. On windows this is known as the "system" locale, |
|
652 * and it is usually the same as the platform locale, but not always, |
|
653 * so this method also checks an implementation property used only |
|
654 * on windows and uses that if set. |
|
655 */ |
|
656 private static Locale systemLocale = null; |
|
657 public static Locale getSystemStartupLocale() { |
|
658 if (systemLocale == null) { |
|
659 systemLocale = (Locale) |
|
660 java.security.AccessController.doPrivileged( |
|
661 new java.security.PrivilegedAction() { |
|
662 public Object run() { |
|
663 /* On windows the system locale may be different than the |
|
664 * user locale. This is an unsupported configuration, but |
|
665 * in that case we want to return a dummy locale that will |
|
666 * never cause a match in the usage of this API. This is |
|
667 * important because Windows documents that the family |
|
668 * names of fonts are enumerated using the language of |
|
669 * the system locale. BY returning a dummy locale in that |
|
670 * case we do not use the platform API which would not |
|
671 * return us the names we want. |
|
672 */ |
|
673 String fileEncoding = System.getProperty("file.encoding", ""); |
|
674 String sysEncoding = System.getProperty("sun.jnu.encoding"); |
|
675 if (sysEncoding != null && !sysEncoding.equals(fileEncoding)) { |
|
676 return Locale.ROOT; |
|
677 } |
|
678 |
|
679 String language = System.getProperty("user.language", "en"); |
|
680 String country = System.getProperty("user.country",""); |
|
681 String variant = System.getProperty("user.variant",""); |
|
682 return new Locale(language, country, variant); |
|
683 } |
|
684 }); |
|
685 } |
|
686 return systemLocale; |
|
687 } |
|
688 |
|
689 /* Really we need only the JRE fonts family names, but there's little |
|
690 * overhead in doing this the easy way by adding all the currently |
|
691 * known fonts. |
|
692 */ |
|
693 protected void getJREFontFamilyNames(TreeMap<String,String> familyNames, |
|
694 Locale requestedLocale) { |
|
695 FontManager.registerDeferredJREFonts(jreFontDirName); |
|
696 Font2D[] physicalfonts = FontManager.getPhysicalFonts(); |
|
697 for (int i=0; i < physicalfonts.length; i++) { |
|
698 if (!(physicalfonts[i] instanceof NativeFont)) { |
|
699 String name = |
|
700 physicalfonts[i].getFamilyName(requestedLocale); |
|
701 familyNames.put(name.toLowerCase(requestedLocale), name); |
|
702 } |
|
703 } |
|
704 } |
|
705 |
|
706 private String[] allFamilies; // cache for default locale only |
|
707 private Locale lastDefaultLocale; |
|
708 |
|
709 public String[] getInstalledFontFamilyNames(Locale requestedLocale) { |
|
710 if (requestedLocale == null) { |
|
711 requestedLocale = Locale.getDefault(); |
|
712 } |
|
713 if (allFamilies != null && lastDefaultLocale != null && |
|
714 requestedLocale.equals(lastDefaultLocale)) { |
|
715 String[] copyFamilies = new String[allFamilies.length]; |
|
716 System.arraycopy(allFamilies, 0, copyFamilies, |
|
717 0, allFamilies.length); |
|
718 return copyFamilies; |
|
719 } |
|
720 |
|
721 TreeMap<String,String> familyNames = new TreeMap<String,String>(); |
|
722 // these names are always there and aren't localised |
|
723 String str; |
|
724 str = Font.SERIF; familyNames.put(str.toLowerCase(), str); |
|
725 str = Font.SANS_SERIF; familyNames.put(str.toLowerCase(), str); |
|
726 str = Font.MONOSPACED; familyNames.put(str.toLowerCase(), str); |
|
727 str = Font.DIALOG; familyNames.put(str.toLowerCase(), str); |
|
728 str = Font.DIALOG_INPUT; familyNames.put(str.toLowerCase(), str); |
|
729 |
|
730 /* Platform APIs may be used to get the set of available family |
|
731 * names for the current default locale so long as it is the same |
|
732 * as the start-up system locale, rather than loading all fonts. |
|
733 */ |
|
734 if (requestedLocale.equals(getSystemStartupLocale()) && |
|
735 FontManager.getFamilyNamesFromPlatform(familyNames, |
|
736 requestedLocale)) { |
|
737 /* Augment platform names with JRE font family names */ |
|
738 getJREFontFamilyNames(familyNames, requestedLocale); |
|
739 } else { |
|
740 loadFontFiles(); |
|
741 Font2D[] physicalfonts = FontManager.getPhysicalFonts(); |
|
742 for (int i=0; i < physicalfonts.length; i++) { |
|
743 if (!(physicalfonts[i] instanceof NativeFont)) { |
|
744 String name = |
|
745 physicalfonts[i].getFamilyName(requestedLocale); |
|
746 familyNames.put(name.toLowerCase(requestedLocale), name); |
|
747 } |
|
748 } |
|
749 } |
|
750 |
|
751 String[] retval = new String[familyNames.size()]; |
|
752 Object [] keyNames = familyNames.keySet().toArray(); |
|
753 for (int i=0; i < keyNames.length; i++) { |
|
754 retval[i] = (String)familyNames.get(keyNames[i]); |
|
755 } |
|
756 if (requestedLocale.equals(Locale.getDefault())) { |
|
757 lastDefaultLocale = requestedLocale; |
|
758 allFamilies = new String[retval.length]; |
|
759 System.arraycopy(retval, 0, allFamilies, 0, allFamilies.length); |
|
760 } |
|
761 return retval; |
|
762 } |
|
763 |
|
764 public String[] getAvailableFontFamilyNames(Locale requestedLocale) { |
193 public String[] getAvailableFontFamilyNames(Locale requestedLocale) { |
765 String[] installed = getInstalledFontFamilyNames(requestedLocale); |
194 FontManagerForSGE fm = getFontManagerForSGE(); |
|
195 String[] installed = fm.getInstalledFontFamilyNames(requestedLocale); |
766 /* Use a new TreeMap as used in getInstalledFontFamilyNames |
196 /* Use a new TreeMap as used in getInstalledFontFamilyNames |
767 * and insert all the keys in lower case, so that the sort order |
197 * and insert all the keys in lower case, so that the sort order |
768 * is the same as the installed families. This preserves historical |
198 * is the same as the installed families. This preserves historical |
769 * behaviour and inserts new families in the right place. |
199 * behaviour and inserts new families in the right place. |
770 * It would have been marginally more efficient to directly obtain |
200 * It would have been marginally more efficient to directly obtain |
771 * the tree map and just insert new entries, but not so much as |
201 * the tree map and just insert new entries, but not so much as |
772 * to justify the extra internal interface. |
202 * to justify the extra internal interface. |
773 */ |
203 */ |
774 TreeMap<String, String> map = FontManager.getCreatedFontFamilyNames(); |
204 TreeMap<String, String> map = fm.getCreatedFontFamilyNames(); |
775 if (map == null || map.size() == 0) { |
205 if (map == null || map.size() == 0) { |
776 return installed; |
206 return installed; |
777 } else { |
207 } else { |
778 for (int i=0; i<installed.length; i++) { |
208 for (int i=0; i<installed.length; i++) { |
779 map.put(installed[i].toLowerCase(requestedLocale), |
209 map.put(installed[i].toLowerCase(requestedLocale), |
791 public String[] getAvailableFontFamilyNames() { |
221 public String[] getAvailableFontFamilyNames() { |
792 return getAvailableFontFamilyNames(Locale.getDefault()); |
222 return getAvailableFontFamilyNames(Locale.getDefault()); |
793 } |
223 } |
794 |
224 |
795 /** |
225 /** |
796 * Returns a file name for the physical font represented by this platform |
|
797 * font name. The default implementation tries to obtain the file name |
|
798 * from the font configuration. |
|
799 * Subclasses may override to provide information from other sources. |
|
800 */ |
|
801 protected String getFileNameFromPlatformName(String platformFontName) { |
|
802 return fontConfig.getFileNameFromPlatformName(platformFontName); |
|
803 } |
|
804 |
|
805 public static class TTFilter implements FilenameFilter { |
|
806 public boolean accept(File dir,String name) { |
|
807 /* all conveniently have the same suffix length */ |
|
808 int offset = name.length()-4; |
|
809 if (offset <= 0) { /* must be at least A.ttf */ |
|
810 return false; |
|
811 } else { |
|
812 return(name.startsWith(".ttf", offset) || |
|
813 name.startsWith(".TTF", offset) || |
|
814 name.startsWith(".ttc", offset) || |
|
815 name.startsWith(".TTC", offset) || |
|
816 name.startsWith(".otf", offset) || |
|
817 name.startsWith(".OTF", offset)); |
|
818 } |
|
819 } |
|
820 } |
|
821 |
|
822 public static class T1Filter implements FilenameFilter { |
|
823 public boolean accept(File dir,String name) { |
|
824 if (noType1Font) { |
|
825 return false; |
|
826 } |
|
827 /* all conveniently have the same suffix length */ |
|
828 int offset = name.length()-4; |
|
829 if (offset <= 0) { /* must be at least A.pfa */ |
|
830 return false; |
|
831 } else { |
|
832 return(name.startsWith(".pfa", offset) || |
|
833 name.startsWith(".pfb", offset) || |
|
834 name.startsWith(".PFA", offset) || |
|
835 name.startsWith(".PFB", offset)); |
|
836 } |
|
837 } |
|
838 } |
|
839 |
|
840 public static class TTorT1Filter implements FilenameFilter { |
|
841 public boolean accept(File dir, String name) { |
|
842 return SunGraphicsEnvironment.ttFilter.accept(dir, name) || |
|
843 SunGraphicsEnvironment.t1Filter.accept(dir, name); |
|
844 } |
|
845 } |
|
846 |
|
847 /* No need to keep consing up new instances - reuse a singleton. |
|
848 * The trade-off is that these objects don't get GC'd. |
|
849 */ |
|
850 public static final TTFilter ttFilter = new TTFilter(); |
|
851 public static final T1Filter t1Filter = new T1Filter(); |
|
852 |
|
853 /* The majority of the register functions in this class are |
|
854 * registering platform fonts in the JRE's font maps. |
|
855 * The next one is opposite in function as it registers the JRE |
|
856 * fonts as platform fonts. If subsequent to calling this |
|
857 * your implementation enumerates platform fonts in a way that |
|
858 * would return these fonts too you may get duplicates. |
|
859 * This function is primarily used to install the JRE fonts |
|
860 * so that the native platform can access them. |
|
861 * It is intended to be overridden by platform subclasses |
|
862 * Currently minimal use is made of this as generally |
|
863 * Java 2D doesn't need the platform to be able to |
|
864 * use its fonts and platforms which already have matching |
|
865 * fonts registered (possibly even from other different JRE |
|
866 * versions) generally can't be guaranteed to use the |
|
867 * one registered by this JRE version in response to |
|
868 * requests from this JRE. |
|
869 */ |
|
870 protected void registerJREFontsWithPlatform(String pathName) { |
|
871 return; |
|
872 } |
|
873 |
|
874 /* Called from FontManager - has Solaris specific implementation */ |
|
875 public void register1dot0Fonts() { |
|
876 java.security.AccessController.doPrivileged( |
|
877 new java.security.PrivilegedAction() { |
|
878 public Object run() { |
|
879 String type1Dir = "/usr/openwin/lib/X11/fonts/Type1"; |
|
880 registerFontsInDir(type1Dir, true, Font2D.TYPE1_RANK, |
|
881 false, false); |
|
882 return null; |
|
883 } |
|
884 }); |
|
885 } |
|
886 |
|
887 protected void registerFontDirs(String pathName) { |
|
888 return; |
|
889 } |
|
890 |
|
891 /* Called to register fall back fonts */ |
|
892 public void registerFontsInDir(String dirName) { |
|
893 registerFontsInDir(dirName, true, Font2D.JRE_RANK, true, false); |
|
894 } |
|
895 |
|
896 private void registerFontsInDir(String dirName, boolean useJavaRasterizer, |
|
897 int fontRank, |
|
898 boolean defer, boolean resolveSymLinks) { |
|
899 File pathFile = new File(dirName); |
|
900 addDirFonts(dirName, pathFile, ttFilter, |
|
901 FontManager.FONTFORMAT_TRUETYPE, useJavaRasterizer, |
|
902 fontRank==Font2D.UNKNOWN_RANK ? |
|
903 Font2D.TTF_RANK : fontRank, |
|
904 defer, resolveSymLinks); |
|
905 addDirFonts(dirName, pathFile, t1Filter, |
|
906 FontManager.FONTFORMAT_TYPE1, useJavaRasterizer, |
|
907 fontRank==Font2D.UNKNOWN_RANK ? |
|
908 Font2D.TYPE1_RANK : fontRank, |
|
909 defer, resolveSymLinks); |
|
910 } |
|
911 |
|
912 private void registerFontsOnPath(String pathName, |
|
913 boolean useJavaRasterizer, int fontRank, |
|
914 boolean defer, boolean resolveSymLinks) { |
|
915 |
|
916 StringTokenizer parser = new StringTokenizer(pathName, |
|
917 File.pathSeparator); |
|
918 try { |
|
919 while (parser.hasMoreTokens()) { |
|
920 registerFontsInDir(parser.nextToken(), |
|
921 useJavaRasterizer, fontRank, |
|
922 defer, resolveSymLinks); |
|
923 } |
|
924 } catch (NoSuchElementException e) { |
|
925 } |
|
926 } |
|
927 |
|
928 protected void registerFontFile(String fontFileName, String[] nativeNames, |
|
929 int fontRank, boolean defer) { |
|
930 // REMIND: case compare depends on platform |
|
931 if (registeredFontFiles.contains(fontFileName)) { |
|
932 return; |
|
933 } |
|
934 int fontFormat; |
|
935 if (ttFilter.accept(null, fontFileName)) { |
|
936 fontFormat = FontManager.FONTFORMAT_TRUETYPE; |
|
937 } else if (t1Filter.accept(null, fontFileName)) { |
|
938 fontFormat = FontManager.FONTFORMAT_TYPE1; |
|
939 } else { |
|
940 fontFormat = FontManager.FONTFORMAT_NATIVE; |
|
941 } |
|
942 registeredFontFiles.add(fontFileName); |
|
943 if (defer) { |
|
944 FontManager.registerDeferredFont(fontFileName, |
|
945 fontFileName, nativeNames, |
|
946 fontFormat, false, fontRank); |
|
947 } else { |
|
948 FontManager.registerFontFile(fontFileName, nativeNames, |
|
949 fontFormat, false, fontRank); |
|
950 } |
|
951 } |
|
952 |
|
953 protected void registerFontDir(String path) { |
|
954 } |
|
955 |
|
956 protected String[] getNativeNames(String fontFileName, |
|
957 String platformName) { |
|
958 return null; |
|
959 } |
|
960 |
|
961 /* |
|
962 * helper function for registerFonts |
|
963 */ |
|
964 private void addDirFonts(String dirName, File dirFile, |
|
965 FilenameFilter filter, |
|
966 int fontFormat, boolean useJavaRasterizer, |
|
967 int fontRank, |
|
968 boolean defer, boolean resolveSymLinks) { |
|
969 String[] ls = dirFile.list(filter); |
|
970 if (ls == null || ls.length == 0) { |
|
971 return; |
|
972 } |
|
973 String[] fontNames = new String[ls.length]; |
|
974 String[][] nativeNames = new String[ls.length][]; |
|
975 int fontCount = 0; |
|
976 |
|
977 for (int i=0; i < ls.length; i++ ) { |
|
978 File theFile = new File(dirFile, ls[i]); |
|
979 String fullName = null; |
|
980 if (resolveSymLinks) { |
|
981 try { |
|
982 fullName = theFile.getCanonicalPath(); |
|
983 } catch (IOException e) { |
|
984 } |
|
985 } |
|
986 if (fullName == null) { |
|
987 fullName = dirName + File.separator + ls[i]; |
|
988 } |
|
989 |
|
990 // REMIND: case compare depends on platform |
|
991 if (registeredFontFiles.contains(fullName)) { |
|
992 continue; |
|
993 } |
|
994 |
|
995 if (badFonts != null && badFonts.contains(fullName)) { |
|
996 if (debugFonts) { |
|
997 logger.warning("skip bad font " + fullName); |
|
998 } |
|
999 continue; // skip this font file. |
|
1000 } |
|
1001 |
|
1002 registeredFontFiles.add(fullName); |
|
1003 |
|
1004 if (debugFonts && logger.isLoggable(Level.INFO)) { |
|
1005 String message = "Registering font " + fullName; |
|
1006 String[] natNames = getNativeNames(fullName, null); |
|
1007 if (natNames == null) { |
|
1008 message += " with no native name"; |
|
1009 } else { |
|
1010 message += " with native name(s) " + natNames[0]; |
|
1011 for (int nn = 1; nn < natNames.length; nn++) { |
|
1012 message += ", " + natNames[nn]; |
|
1013 } |
|
1014 } |
|
1015 logger.info(message); |
|
1016 } |
|
1017 fontNames[fontCount] = fullName; |
|
1018 nativeNames[fontCount++] = getNativeNames(fullName, null); |
|
1019 } |
|
1020 FontManager.registerFonts(fontNames, nativeNames, fontCount, |
|
1021 fontFormat, useJavaRasterizer, fontRank, |
|
1022 defer); |
|
1023 return; |
|
1024 } |
|
1025 |
|
1026 /* |
|
1027 * A GE may verify whether a font file used in a fontconfiguration |
|
1028 * exists. If it doesn't then either we may substitute the default |
|
1029 * font, or perhaps elide it altogether from the composite font. |
|
1030 * This makes some sense on windows where the font file is only |
|
1031 * likely to be in one place. But on other OSes, eg Linux, the file |
|
1032 * can move around depending. So there we probably don't want to assume |
|
1033 * its missing and so won't add it to this list. |
|
1034 * If this list - missingFontFiles - is non-null then the composite |
|
1035 * font initialisation logic tests to see if a font file is in that |
|
1036 * set. |
|
1037 * Only one thread should be able to add to this set so we don't |
|
1038 * synchronize. |
|
1039 */ |
|
1040 protected void addToMissingFontFileList(String fileName) { |
|
1041 if (missingFontFiles == null) { |
|
1042 missingFontFiles = new HashSet<String>(); |
|
1043 } |
|
1044 missingFontFiles.add(fileName); |
|
1045 } |
|
1046 |
|
1047 /** |
|
1048 * Creates this environment's FontConfiguration. |
|
1049 */ |
|
1050 protected abstract FontConfiguration createFontConfiguration(); |
|
1051 |
|
1052 public abstract FontConfiguration |
|
1053 createFontConfiguration(boolean preferLocaleFonts, |
|
1054 boolean preferPropFonts); |
|
1055 |
|
1056 /* |
|
1057 * This method asks the font configuration API for all platform names |
|
1058 * used as components of composite/logical fonts and iterates over these |
|
1059 * looking up their corresponding file name and registers these fonts. |
|
1060 * It also ensures that the fonts are accessible via platform APIs. |
|
1061 * The composites themselves are then registered. |
|
1062 */ |
|
1063 private void |
|
1064 initCompositeFonts(FontConfiguration fontConfig, |
|
1065 ConcurrentHashMap<String, Font2D> altNameCache) { |
|
1066 |
|
1067 int numCoreFonts = fontConfig.getNumberCoreFonts(); |
|
1068 String[] fcFonts = fontConfig.getPlatformFontNames(); |
|
1069 for (int f=0; f<fcFonts.length; f++) { |
|
1070 String platformFontName = fcFonts[f]; |
|
1071 String fontFileName = |
|
1072 getFileNameFromPlatformName(platformFontName); |
|
1073 String[] nativeNames = null; |
|
1074 if (fontFileName == null || fontFileName.equals(platformFontName)){ |
|
1075 /* No file located, so register using the platform name, |
|
1076 * i.e. as a native font. |
|
1077 */ |
|
1078 fontFileName = platformFontName; |
|
1079 } else { |
|
1080 if (f < numCoreFonts) { |
|
1081 /* If platform APIs also need to access the font, add it |
|
1082 * to a set to be registered with the platform too. |
|
1083 * This may be used to add the parent directory to the X11 |
|
1084 * font path if its not already there. See the docs for the |
|
1085 * subclass implementation. |
|
1086 * This is now mainly for the benefit of X11-based AWT |
|
1087 * But for historical reasons, 2D initialisation code |
|
1088 * makes these calls. |
|
1089 * If the fontconfiguration file is properly set up |
|
1090 * so that all fonts are mapped to files and all their |
|
1091 * appropriate directories are specified, then this |
|
1092 * method will be low cost as it will return after |
|
1093 * a test that finds a null lookup map. |
|
1094 */ |
|
1095 addFontToPlatformFontPath(platformFontName); |
|
1096 } |
|
1097 nativeNames = getNativeNames(fontFileName, platformFontName); |
|
1098 } |
|
1099 /* Uncomment these two lines to "generate" the XLFD->filename |
|
1100 * mappings needed to speed start-up on Solaris. |
|
1101 * Augment this with the appendedpathname and the mappings |
|
1102 * for native (F3) fonts |
|
1103 */ |
|
1104 //String platName = platformFontName.replaceAll(" ", "_"); |
|
1105 //System.out.println("filename."+platName+"="+fontFileName); |
|
1106 registerFontFile(fontFileName, nativeNames, |
|
1107 Font2D.FONT_CONFIG_RANK, true); |
|
1108 |
|
1109 |
|
1110 } |
|
1111 /* This registers accumulated paths from the calls to |
|
1112 * addFontToPlatformFontPath(..) and any specified by |
|
1113 * the font configuration. Rather than registering |
|
1114 * the fonts it puts them in a place and form suitable for |
|
1115 * the Toolkit to pick up and use if a toolkit is initialised, |
|
1116 * and if it uses X11 fonts. |
|
1117 */ |
|
1118 registerPlatformFontsUsedByFontConfiguration(); |
|
1119 |
|
1120 CompositeFontDescriptor[] compositeFontInfo |
|
1121 = fontConfig.get2DCompositeFontInfo(); |
|
1122 for (int i = 0; i < compositeFontInfo.length; i++) { |
|
1123 CompositeFontDescriptor descriptor = compositeFontInfo[i]; |
|
1124 String[] componentFileNames = descriptor.getComponentFileNames(); |
|
1125 String[] componentFaceNames = descriptor.getComponentFaceNames(); |
|
1126 |
|
1127 /* It would be better eventually to handle this in the |
|
1128 * FontConfiguration code which should also remove duplicate slots |
|
1129 */ |
|
1130 if (missingFontFiles != null) { |
|
1131 for (int ii=0; ii<componentFileNames.length; ii++) { |
|
1132 if (missingFontFiles.contains(componentFileNames[ii])) { |
|
1133 componentFileNames[ii] = getDefaultFontFile(); |
|
1134 componentFaceNames[ii] = getDefaultFontFaceName(); |
|
1135 } |
|
1136 } |
|
1137 } |
|
1138 |
|
1139 /* FontConfiguration needs to convey how many fonts it has added |
|
1140 * as fallback component fonts which should not affect metrics. |
|
1141 * The core component count will be the number of metrics slots. |
|
1142 * This does not preclude other mechanisms for adding |
|
1143 * fall back component fonts to the composite. |
|
1144 */ |
|
1145 if (altNameCache != null) { |
|
1146 FontManager.registerCompositeFont( |
|
1147 descriptor.getFaceName(), |
|
1148 componentFileNames, componentFaceNames, |
|
1149 descriptor.getCoreComponentCount(), |
|
1150 descriptor.getExclusionRanges(), |
|
1151 descriptor.getExclusionRangeLimits(), |
|
1152 true, |
|
1153 altNameCache); |
|
1154 } else { |
|
1155 FontManager.registerCompositeFont( |
|
1156 descriptor.getFaceName(), |
|
1157 componentFileNames, componentFaceNames, |
|
1158 descriptor.getCoreComponentCount(), |
|
1159 descriptor.getExclusionRanges(), |
|
1160 descriptor.getExclusionRangeLimits(), |
|
1161 true); |
|
1162 } |
|
1163 if (debugFonts) { |
|
1164 logger.info("registered " + descriptor.getFaceName()); |
|
1165 } |
|
1166 } |
|
1167 } |
|
1168 |
|
1169 /** |
|
1170 * Notifies graphics environment that the logical font configuration |
|
1171 * uses the given platform font name. The graphics environment may |
|
1172 * use this for platform specific initialization. |
|
1173 */ |
|
1174 protected void addFontToPlatformFontPath(String platformFontName) { |
|
1175 } |
|
1176 |
|
1177 protected void registerPlatformFontsUsedByFontConfiguration() { |
|
1178 } |
|
1179 |
|
1180 /** |
|
1181 * Determines whether the given font is a logical font. |
|
1182 */ |
|
1183 public static boolean isLogicalFont(Font f) { |
|
1184 return FontConfiguration.isLogicalFontFamilyName(f.getFamily()); |
|
1185 } |
|
1186 |
|
1187 /** |
|
1188 * Return the default font configuration. |
|
1189 */ |
|
1190 public FontConfiguration getFontConfiguration() { |
|
1191 return fontConfig; |
|
1192 } |
|
1193 |
|
1194 /** |
|
1195 * Return the bounds of a GraphicsDevice, less its screen insets. |
226 * Return the bounds of a GraphicsDevice, less its screen insets. |
1196 * See also java.awt.GraphicsEnvironment.getUsableBounds(); |
227 * See also java.awt.GraphicsEnvironment.getUsableBounds(); |
1197 */ |
228 */ |
1198 public static Rectangle getUsableBounds(GraphicsDevice gd) { |
229 public static Rectangle getUsableBounds(GraphicsDevice gd) { |
1199 GraphicsConfiguration gc = gd.getDefaultConfiguration(); |
230 GraphicsConfiguration gc = gd.getDefaultConfiguration(); |