1 /* 2 * Copyright (c) 2009, 2020, 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.awt; 27 28 import java.awt.GraphicsEnvironment; 29 import java.io.BufferedReader; 30 import java.io.File; 31 import java.io.FileReader; 32 import java.io.IOException; 33 import java.io.StreamTokenizer; 34 import java.util.HashMap; 35 import java.util.HashSet; 36 import java.util.Locale; 37 import java.util.Map; 38 import java.util.NoSuchElementException; 39 import java.util.StringTokenizer; 40 import java.util.Vector; 41 42 import javax.swing.plaf.FontUIResource; 43 import sun.font.MFontConfiguration; 44 import sun.font.CompositeFont; 45 import sun.font.FontManager; 46 import sun.font.SunFontManager; 47 import sun.font.FcFontConfiguration; 48 import sun.font.FontAccess; 49 import sun.font.FontUtilities; 50 import sun.font.NativeFont; 51 import sun.util.logging.PlatformLogger; 52 53 /** 54 * The X11 implementation of {@link FontManager}. 55 */ 56 public final class X11FontManager extends FcFontManager { 57 58 // constants identifying XLFD and font ID fields 59 private static final int FOUNDRY_FIELD = 1; 60 private static final int FAMILY_NAME_FIELD = 2; 61 private static final int WEIGHT_NAME_FIELD = 3; 62 private static final int SLANT_FIELD = 4; 63 private static final int SETWIDTH_NAME_FIELD = 5; 64 private static final int ADD_STYLE_NAME_FIELD = 6; 65 private static final int PIXEL_SIZE_FIELD = 7; 66 private static final int POINT_SIZE_FIELD = 8; 67 private static final int RESOLUTION_X_FIELD = 9; 68 private static final int RESOLUTION_Y_FIELD = 10; 69 private static final int SPACING_FIELD = 11; 70 private static final int AVERAGE_WIDTH_FIELD = 12; 71 private static final int CHARSET_REGISTRY_FIELD = 13; 72 private static final int CHARSET_ENCODING_FIELD = 14; 73 74 /* 75 * fontNameMap is a map from a fontID (which is a substring of an XLFD like 76 * "-monotype-arial-bold-r-normal-iso8859-7") 77 * to font file path like 78 * /usr/openwin/lib/locale/iso_8859_7/X11/fonts/TrueType/ArialBoldItalic.ttf 79 * It's used in a couple of methods like 80 * getFileNameFomPlatformName(..) to help locate the font file. 81 * We use this substring of a full XLFD because the font configuration files 82 * define the XLFDs in a way that's easier to make into a request. 83 * E.g., the -0-0-0-0-p-0- reported by X is -*-%d-*-*-p-*- in the font 84 * configuration files. We need to remove that part for comparisons. 85 */ 86 private static Map<String, String> fontNameMap = new HashMap<>(); 87 88 /* 89 * xlfdMap is a map from a platform path like 90 * /usr/openwin/lib/locale/ja/X11/fonts/TT/HG-GothicB.ttf to an XLFD like 91 * "-ricoh-hg gothic b-medium-r-normal--0-0-0-0-m-0-jisx0201.1976-0" 92 * Because there may be multiple native names, because the font is used 93 * to support multiple X encodings for example, the value of an entry in 94 * this map is always a vector where we store all the native names. 95 * For fonts which we don't understand the key isn't a pathname, its 96 * the full XLFD string like :- 97 * "-ricoh-hg gothic b-medium-r-normal--0-0-0-0-m-0-jisx0201.1976-0" 98 */ 99 private static Map<String, Vector<String>> xlfdMap = new HashMap<>(); 100 101 /* xFontDirsMap is also a map from a font ID to a font filepath. 102 * The difference from fontNameMap is just that it does not have 103 * resolved symbolic links. Normally this is not interesting except 104 * that we need to know the directory in which a font was found to 105 * add it to the X font server path, since although the files may 106 * be linked, the fonts.dir is different and specific to the encoding 107 * handled by that directory. This map is nulled out after use to free 108 * heap space. If the optimal path is taken, such that all fonts in 109 * font configuration files are referenced by filename, then the font 110 * dir can be directly derived as its parent directory. 111 * If a font is used by two XLFDs, each corresponding to a different 112 * X11 font directory, then precautions must be taken to include both 113 * directories. 114 */ 115 private static Map<String, String> xFontDirsMap; 116 117 /* 118 * This is the set of font directories needed to be on the X font path 119 * to enable AWT heavyweights to find all of the font configuration fonts. 120 * It is populated by : 121 * - awtfontpath entries in the fontconfig.properties 122 * - parent directories of "core" fonts used in the fontconfig.properties 123 * - looking up font dirs in the xFontDirsMap where the key is a fontID 124 * (cut down version of the XLFD read from the font configuration file). 125 * This set is nulled out after use to free heap space. 126 */ 127 private static HashSet<String> fontConfigDirs = null; 128 129 /* 130 * Used to eliminate redundant work. When a font directory is 131 * registered it added to this list. Subsequent registrations for the 132 * same directory can then be skipped by checking this Map. 133 * Access to this map is not synchronised here since creation 134 * of the singleton GE instance is already synchronised and that is 135 * the only code path that accesses this map. 136 */ 137 private static HashMap<String, Object> registeredDirs = new HashMap<>(); 138 139 /* Array of directories to be added to the X11 font path. 140 * Used by static method called from Toolkits which use X11 fonts. 141 * Specifically this means MToolkit 142 */ 143 private static String[] fontdirs = null; 144 145 public static X11FontManager getInstance() { 146 return (X11FontManager) SunFontManager.getInstance(); 147 } 148 149 /** 150 * Takes family name property in the following format: 151 * "-linotype-helvetica-medium-r-normal-sans-*-%d-*-*-p-*-iso8859-1" 152 * and returns the name of the corresponding physical font. 153 * This code is used to resolve font configuration fonts, and expects 154 * only to get called for these fonts. 155 */ 156 @Override 157 public String getFileNameFromPlatformName(String platName) { 158 159 /* If the FontConfig file doesn't use xlfds, or its 160 * FcFontConfiguration, this may be already a file name. 161 */ 162 if (platName.startsWith("/")) { 163 return platName; 164 } 165 166 String fileName = null; 167 String fontID = specificFontIDForName(platName); 168 169 /* If the font filename has been explicitly assigned in the 170 * font configuration file, use it. This avoids accessing 171 * the wrong fonts on Linux, where different fonts (some 172 * of which may not be usable by 2D) may share the same 173 * specific font ID. It may also speed up the lookup. 174 */ 175 fileName = super.getFileNameFromPlatformName(platName); 176 if (fileName != null) { 177 if (isHeadless() && fileName.startsWith("-")) { 178 /* if it's headless, no xlfd should be used */ 179 return null; 180 } 181 if (fileName.startsWith("/")) { 182 /* If a path is assigned in the font configuration file, 183 * it is required that the config file also specify using the 184 * new awtfontpath key the X11 font directories 185 * which must be added to the X11 font path to support 186 * AWT access to that font. For that reason we no longer 187 * have code here to add the parent directory to the list 188 * of font config dirs, since the parent directory may not 189 * be sufficient if fonts are symbolically linked to a 190 * different directory. 191 * 192 * Add this XLFD (platform name) to the list of known 193 * ones for this file. 194 */ 195 Vector<String> xVal = xlfdMap.get(fileName); 196 if (xVal == null) { 197 /* Try to be robust on Linux distros which move fonts 198 * around by verifying that the fileName represents a 199 * file that exists. If it doesn't, set it to null 200 * to trigger a search. 201 */ 202 if (getFontConfiguration().needToSearchForFile(fileName)) { 203 fileName = null; 204 } 205 if (fileName != null) { 206 xVal = new Vector<>(); 207 xVal.add(platName); 208 xlfdMap.put(fileName, xVal); 209 } 210 } else { 211 if (!xVal.contains(platName)) { 212 xVal.add(platName); 213 } 214 } 215 } 216 if (fileName != null) { 217 fontNameMap.put(fontID, fileName); 218 return fileName; 219 } 220 } 221 222 if (fontID != null) { 223 fileName = fontNameMap.get(fontID); 224 if (fontPath == null && 225 (fileName == null || !fileName.startsWith("/"))) { 226 if (FontUtilities.debugFonts()) { 227 FontUtilities.getLogger() 228 .warning("** Registering all font paths because " + 229 "can't find file for " + platName); 230 } 231 fontPath = getPlatformFontPath(noType1Font); 232 registerFontDirs(fontPath); 233 if (FontUtilities.debugFonts()) { 234 FontUtilities.getLogger() 235 .warning("** Finished registering all font paths"); 236 } 237 fileName = fontNameMap.get(fontID); 238 } 239 if (fileName == null && !isHeadless()) { 240 /* Query X11 directly to see if this font is available 241 * as a native font. 242 */ 243 fileName = getX11FontName(platName); 244 } 245 if (fileName == null) { 246 fontID = switchFontIDForName(platName); 247 fileName = fontNameMap.get(fontID); 248 } 249 if (fileName != null) { 250 fontNameMap.put(fontID, fileName); 251 } 252 } 253 return fileName; 254 } 255 256 @Override 257 protected String[] getNativeNames(String fontFileName, 258 String platformName) { 259 Vector<String> nativeNames; 260 if ((nativeNames=xlfdMap.get(fontFileName))==null) { 261 if (platformName == null) { 262 return null; 263 } else { 264 /* back-stop so that at least the name used in the 265 * font configuration file is known as a native name 266 */ 267 String []natNames = new String[1]; 268 natNames[0] = platformName; 269 return natNames; 270 } 271 } else { 272 int len = nativeNames.size(); 273 return nativeNames.toArray(new String[len]); 274 } 275 } 276 277 /* NOTE: this method needs to be executed in a privileged context. 278 * The superclass constructor which is the primary caller of 279 * this method executes entirely in such a context. Additionally 280 * the loadFonts() method does too. So all should be well. 281 282 */ 283 @Override 284 protected void registerFontDir(String path) { 285 /* fonts.dir file format looks like :- 286 * 47 287 * Arial.ttf -monotype-arial-regular-r-normal--0-0-0-0-p-0-iso8859-1 288 * Arial-Bold.ttf -monotype-arial-bold-r-normal--0-0-0-0-p-0-iso8859-1 289 * ... 290 */ 291 if (FontUtilities.debugFonts()) { 292 FontUtilities.getLogger().info("ParseFontDir " + path); 293 } 294 File fontsDotDir = new File(path + File.separator + "fonts.dir"); 295 FileReader fr = null; 296 try { 297 if (fontsDotDir.canRead()) { 298 fr = new FileReader(fontsDotDir); 299 BufferedReader br = new BufferedReader(fr, 8192); 300 StreamTokenizer st = new StreamTokenizer(br); 301 st.eolIsSignificant(true); 302 int ttype = st.nextToken(); 303 if (ttype == StreamTokenizer.TT_NUMBER) { 304 int numEntries = (int)st.nval; 305 ttype = st.nextToken(); 306 if (ttype == StreamTokenizer.TT_EOL) { 307 st.resetSyntax(); 308 st.wordChars(32, 127); 309 st.wordChars(128 + 32, 255); 310 st.whitespaceChars(0, 31); 311 312 for (int i=0; i < numEntries; i++) { 313 ttype = st.nextToken(); 314 if (ttype == StreamTokenizer.TT_EOF) { 315 break; 316 } 317 if (ttype != StreamTokenizer.TT_WORD) { 318 break; 319 } 320 int breakPos = st.sval.indexOf(' '); 321 if (breakPos <= 0) { 322 /* On TurboLinux 8.0 a fonts.dir file had 323 * a line with integer value "24" which 324 * appeared to be the number of remaining 325 * entries in the file. This didn't add to 326 * the value on the first line of the file. 327 * Seemed like XFree86 didn't like this line 328 * much either. It failed to parse the file. 329 * Ignore lines like this completely, and 330 * don't let them count as an entry. 331 */ 332 numEntries++; 333 ttype = st.nextToken(); 334 if (ttype != StreamTokenizer.TT_EOL) { 335 break; 336 } 337 338 continue; 339 } 340 if (st.sval.charAt(0) == '!') { 341 /* TurboLinux 8.0 comment line: ignore. 342 * can't use st.commentChar('!') to just 343 * skip because this line mustn't count 344 * against numEntries. 345 */ 346 numEntries++; 347 ttype = st.nextToken(); 348 if (ttype != StreamTokenizer.TT_EOL) { 349 break; 350 } 351 continue; 352 } 353 String fileName = st.sval.substring(0, breakPos); 354 /* TurboLinux 8.0 uses some additional syntax to 355 * indicate algorithmic styling values. 356 * Ignore ':' separated files at the beginning 357 * of the fileName 358 */ 359 int lastColon = fileName.lastIndexOf(':'); 360 if (lastColon > 0) { 361 if (lastColon+1 >= fileName.length()) { 362 continue; 363 } 364 fileName = fileName.substring(lastColon+1); 365 } 366 String fontPart = st.sval.substring(breakPos+1); 367 String fontID = specificFontIDForName(fontPart); 368 String sVal = fontNameMap.get(fontID); 369 370 if (FontUtilities.debugFonts()) { 371 PlatformLogger logger = FontUtilities.getLogger(); 372 logger.info("file=" + fileName + 373 " xlfd=" + fontPart); 374 logger.info("fontID=" + fontID + 375 " sVal=" + sVal); 376 } 377 String fullPath = null; 378 try { 379 File file = new File(path,fileName); 380 /* we may have a resolved symbolic link 381 * this becomes important for an xlfd we 382 * still need to know the location it was 383 * found to update the X server font path 384 * for use by AWT heavyweights - and when 2D 385 * wants to use the native rasteriser. 386 */ 387 if (xFontDirsMap == null) { 388 xFontDirsMap = new HashMap<>(); 389 } 390 xFontDirsMap.put(fontID, path); 391 fullPath = file.getCanonicalPath(); 392 } catch (IOException e) { 393 fullPath = path + File.separator + fileName; 394 } 395 Vector<String> xVal = xlfdMap.get(fullPath); 396 if (FontUtilities.debugFonts()) { 397 FontUtilities.getLogger() 398 .info("fullPath=" + fullPath + 399 " xVal=" + xVal); 400 } 401 if ((xVal == null || !xVal.contains(fontPart)) && 402 (sVal == null) || !sVal.startsWith("/")) { 403 if (FontUtilities.debugFonts()) { 404 FontUtilities.getLogger() 405 .info("Map fontID:"+fontID + 406 "to file:" + fullPath); 407 } 408 fontNameMap.put(fontID, fullPath); 409 if (xVal == null) { 410 xVal = new Vector<>(); 411 xlfdMap.put (fullPath, xVal); 412 } 413 xVal.add(fontPart); 414 } 415 416 ttype = st.nextToken(); 417 if (ttype != StreamTokenizer.TT_EOL) { 418 break; 419 } 420 } 421 } 422 } 423 fr.close(); 424 } 425 } catch (IOException ioe1) { 426 } finally { 427 if (fr != null) { 428 try { 429 fr.close(); 430 } catch (IOException ioe2) { 431 } 432 } 433 } 434 } 435 436 @Override 437 public void loadFonts() { 438 super.loadFonts(); 439 /* These maps are greatly expanded during a loadFonts but 440 * can be reset to their initial state afterwards. 441 * Since preferLocaleFonts() and preferProportionalFonts() will 442 * trigger a partial repopulating from the FontConfiguration 443 * it has to be the inital (empty) state for the latter two, not 444 * simply nulling out. 445 * xFontDirsMap is a special case in that the implementation 446 * will typically not ever need to initialise it so it can be null. 447 */ 448 xFontDirsMap = null; 449 xlfdMap = new HashMap<>(1); 450 fontNameMap = new HashMap<>(1); 451 } 452 453 private static String getX11FontName(String platName) { 454 String xlfd = platName.replaceAll("%d", "*"); 455 if (NativeFont.fontExists(xlfd)) { 456 return xlfd; 457 } else { 458 return null; 459 } 460 } 461 462 private boolean isHeadless() { 463 GraphicsEnvironment ge = 464 GraphicsEnvironment.getLocalGraphicsEnvironment(); 465 return GraphicsEnvironment.isHeadless(); 466 } 467 468 private String specificFontIDForName(String name) { 469 470 int[] hPos = new int[14]; 471 int hyphenCnt = 1; 472 int pos = 1; 473 474 while (pos != -1 && hyphenCnt < 14) { 475 pos = name.indexOf('-', pos); 476 if (pos != -1) { 477 hPos[hyphenCnt++] = pos; 478 pos++; 479 } 480 } 481 482 if (hyphenCnt != 14) { 483 if (FontUtilities.debugFonts()) { 484 FontUtilities.getLogger() 485 .severe("Font Configuration Font ID is malformed:" + name); 486 } 487 return name; // what else can we do? 488 } 489 490 StringBuffer sb = 491 new StringBuffer(name.substring(hPos[FAMILY_NAME_FIELD-1], 492 hPos[SETWIDTH_NAME_FIELD])); 493 sb.append(name.substring(hPos[CHARSET_REGISTRY_FIELD-1])); 494 String retval = sb.toString().toLowerCase (Locale.ENGLISH); 495 return retval; 496 } 497 498 private String switchFontIDForName(String name) { 499 500 int[] hPos = new int[14]; 501 int hyphenCnt = 1; 502 int pos = 1; 503 504 while (pos != -1 && hyphenCnt < 14) { 505 pos = name.indexOf('-', pos); 506 if (pos != -1) { 507 hPos[hyphenCnt++] = pos; 508 pos++; 509 } 510 } 511 512 if (hyphenCnt != 14) { 513 if (FontUtilities.debugFonts()) { 514 FontUtilities.getLogger() 515 .severe("Font Configuration Font ID is malformed:" + name); 516 } 517 return name; // what else can we do? 518 } 519 520 String slant = name.substring(hPos[SLANT_FIELD-1]+1, 521 hPos[SLANT_FIELD]); 522 String family = name.substring(hPos[FAMILY_NAME_FIELD-1]+1, 523 hPos[FAMILY_NAME_FIELD]); 524 String registry = name.substring(hPos[CHARSET_REGISTRY_FIELD-1]+1, 525 hPos[CHARSET_REGISTRY_FIELD]); 526 String encoding = name.substring(hPos[CHARSET_ENCODING_FIELD-1]+1); 527 528 if (slant.equals("i")) { 529 slant = "o"; 530 } else if (slant.equals("o")) { 531 slant = "i"; 532 } 533 // workaround for #4471000 534 if (family.equals("itc zapfdingbats") 535 && registry.equals("sun") 536 && encoding.equals("fontspecific")){ 537 registry = "adobe"; 538 } 539 StringBuffer sb = 540 new StringBuffer(name.substring(hPos[FAMILY_NAME_FIELD-1], 541 hPos[SLANT_FIELD-1]+1)); 542 sb.append(slant); 543 sb.append(name.substring(hPos[SLANT_FIELD], 544 hPos[SETWIDTH_NAME_FIELD]+1)); 545 sb.append(registry); 546 sb.append(name.substring(hPos[CHARSET_ENCODING_FIELD-1])); 547 String retval = sb.toString().toLowerCase (Locale.ENGLISH); 548 return retval; 549 } 550 551 /** 552 * Returns the face name for the given XLFD. 553 */ 554 public String getFileNameFromXLFD(String name) { 555 String fileName = null; 556 String fontID = specificFontIDForName(name); 557 if (fontID != null) { 558 fileName = fontNameMap.get(fontID); 559 if (fileName == null) { 560 fontID = switchFontIDForName(name); 561 fileName = fontNameMap.get(fontID); 562 } 563 if (fileName == null) { 564 fileName = getDefaultFontFile(); 565 } 566 } 567 return fileName; 568 } 569 570 /* Register just the paths, (it doesn't register the fonts). 571 * If a font configuration file has specified a baseFontPath 572 * fontPath is just those directories, unless on usage we 573 * find it doesn't contain what we need for the logical fonts. 574 * Otherwise, we register all the paths on Solaris, because 575 * the fontPath we have here is the complete one from 576 * parsing /var/sadm/install/contents, not just 577 * what's on the X font path (may be this should be 578 * changed). 579 * But for now what it means is that if we didn't do 580 * this then if the font weren't listed anywhere on the 581 * less complete font path we'd trigger loadFonts which 582 * actually registers the fonts. This may actually be 583 * the right thing tho' since that would also set up 584 * the X font path without which we wouldn't be able to 585 * display some "native" fonts. 586 * So something to revisit is that probably fontPath 587 * here ought to be only the X font path + jre font dir. 588 * loadFonts should have a separate native call to 589 * get the rest of the platform font path. 590 * 591 * Registering the directories can now be avoided in the 592 * font configuration initialisation when filename entries 593 * exist in the font configuration file for all fonts. 594 * (Perhaps a little confusingly a filename entry is 595 * actually keyed using the XLFD used in the font entries, 596 * and it maps *to* a real filename). 597 * In the event any are missing, registration of all 598 * directories will be invoked to find the real files. 599 * 600 * But registering the directory performed other 601 * functions such as filling in the map of all native names 602 * for the font. So when this method isn't invoked, they still 603 * must be found. This is mitigated by getNativeNames now 604 * being able to return at least the platform name, but mostly 605 * by ensuring that when a filename key is found, that 606 * xlfd key is stored as one of the set of platform names 607 * for the font. Its a set because typical font configuration 608 * files reference the same CJK font files using multiple 609 * X11 encodings. For the code that adds this to the map 610 * see X11GE.getFileNameFromPlatformName(..) 611 * If you don't get all of these then some code points may 612 * not use the Xserver, and will not get the PCF bitmaps 613 * that are available for some point sizes. 614 * So, in the event that there is such a problem, 615 * unconditionally making this call may be necessary, at 616 * some cost to JRE start-up 617 */ 618 @Override 619 protected void registerFontDirs(String pathName) { 620 621 StringTokenizer parser = new StringTokenizer(pathName, 622 File.pathSeparator); 623 try { 624 while (parser.hasMoreTokens()) { 625 String dirPath = parser.nextToken(); 626 if (dirPath != null && !registeredDirs.containsKey(dirPath)) { 627 registeredDirs.put(dirPath, null); 628 registerFontDir(dirPath); 629 } 630 } 631 } catch (NoSuchElementException e) { 632 } 633 } 634 635 // An X font spec (xlfd) includes an encoding. The same TrueType font file 636 // may be referenced from different X font directories in font.dir files 637 // to support use in multiple encodings by X apps. 638 // So for the purposes of font configuration logical fonts where AWT 639 // heavyweights need to access the font via X APIs we need to ensure that 640 // the directory for precisely the encodings needed by this are added to 641 // the x font path. This requires that we note the platform names 642 // specified in font configuration files and use that to identify the 643 // X font directory that contains a font.dir file for that platform name 644 // and add it to the X font path (if display is local) 645 // Here we make use of an already built map of xlfds to font locations 646 // to add the font location to the set of those required to build the 647 // x font path needed by AWT. 648 // These are added to the x font path later. 649 // All this is necessary because on Solaris the font.dir directories 650 // may contain not real font files, but symbolic links to the actual 651 // location but that location is not suitable for the x font path, since 652 // it probably doesn't have a font.dir at all and certainly not one 653 // with the required encodings 654 // If the fontconfiguration file is properly set up so that all fonts 655 // are mapped to files then we will never trigger initialising 656 // xFontDirsMap (it will be null). In this case the awtfontpath entries 657 // must specify all the X11 directories needed by AWT. 658 @Override 659 protected void addFontToPlatformFontPath(String platformName) { 660 // Lazily initialize fontConfigDirs. 661 getPlatformFontPathFromFontConfig(); 662 if (xFontDirsMap != null) { 663 String fontID = specificFontIDForName(platformName); 664 String dirName = xFontDirsMap.get(fontID); 665 if (dirName != null) { 666 fontConfigDirs.add(dirName); 667 } 668 } 669 return; 670 } 671 672 private void getPlatformFontPathFromFontConfig() { 673 if (fontConfigDirs == null) { 674 fontConfigDirs = getFontConfiguration().getAWTFontPathSet(); 675 if (FontUtilities.debugFonts() && fontConfigDirs != null) { 676 String[] names = fontConfigDirs.toArray(new String[0]); 677 for (int i=0;i<names.length;i++) { 678 FontUtilities.getLogger().info("awtfontpath : " + names[i]); 679 } 680 } 681 } 682 } 683 684 @Override 685 protected void registerPlatformFontsUsedByFontConfiguration() { 686 // Lazily initialize fontConfigDirs. 687 getPlatformFontPathFromFontConfig(); 688 if (fontConfigDirs == null) { 689 return; 690 } 691 if (FontUtilities.isLinux) { 692 fontConfigDirs.add(jreLibDirName+File.separator+"oblique-fonts"); 693 } 694 fontdirs = fontConfigDirs.toArray(new String[0]); 695 } 696 697 // Implements SunGraphicsEnvironment.createFontConfiguration. 698 protected FontConfiguration createFontConfiguration() { 699 /* The logic here decides whether to use a preconfigured 700 * fontconfig.properties file, or synthesise one using platform APIs. 701 * On Solaris we try to use the 702 * pre-configured ones, but if the files it specifies are missing 703 * we fail-safe to synthesising one. This might happen if Solaris 704 * changes its fonts. 705 * For Linux we require an exact match of distro and version to 706 * use the preconfigured file. 707 * If synthesising fails, we fall back to any preconfigured file 708 * and do the best we can. 709 */ 710 FontConfiguration mFontConfig = new MFontConfiguration(this); 711 if ((FontUtilities.isLinux && !mFontConfig.foundOsSpecificFile())) { 712 FcFontConfiguration fcFontConfig = 713 new FcFontConfiguration(this); 714 if (fcFontConfig.init()) { 715 return fcFontConfig; 716 } 717 } 718 mFontConfig.init(); 719 return mFontConfig; 720 } 721 722 public FontConfiguration 723 createFontConfiguration(boolean preferLocaleFonts, 724 boolean preferPropFonts) { 725 726 return new MFontConfiguration(this, 727 preferLocaleFonts, preferPropFonts); 728 } 729 730 protected synchronized String getFontPath(boolean noType1Fonts) { 731 isHeadless(); // make sure GE is inited, as its the X11 lock. 732 return getFontPathNative(noType1Fonts, true); 733 } 734 735 @Override 736 protected FontUIResource getFontConfigFUIR(String family, int style, int size) { 737 738 CompositeFont font2D = getFontConfigManager().getFontConfigFont(family, style); 739 740 if (font2D == null) { // Not expected, just a precaution. 741 return new FontUIResource(family, style, size); 742 } 743 744 /* The name of the font will be that of the physical font in slot, 745 * but by setting the handle to that of the CompositeFont it 746 * renders as that CompositeFont. 747 * It also needs to be marked as a created font which is the 748 * current mechanism to signal that deriveFont etc must copy 749 * the handle from the original font. 750 */ 751 FontUIResource fuir = 752 new FontUIResource(font2D.getFamilyName(null), style, size); 753 FontAccess.getFontAccess().setFont2D(fuir, font2D.handle); 754 FontAccess.getFontAccess().setCreatedFont(fuir); 755 return fuir; 756 } 757 }