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 getInstance()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 getFileNameFromPlatformName(String platName)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.logWarning("** Registering all font paths because " + 228 "can't find file for " + platName); 229 } 230 fontPath = getPlatformFontPath(noType1Font); 231 registerFontDirs(fontPath); 232 if (FontUtilities.debugFonts()) { 233 FontUtilities.logWarning("** Finished registering all font paths"); 234 } 235 fileName = fontNameMap.get(fontID); 236 } 237 if (fileName == null && !isHeadless()) { 238 /* Query X11 directly to see if this font is available 239 * as a native font. 240 */ 241 fileName = getX11FontName(platName); 242 } 243 if (fileName == null) { 244 fontID = switchFontIDForName(platName); 245 fileName = fontNameMap.get(fontID); 246 } 247 if (fileName != null) { 248 fontNameMap.put(fontID, fileName); 249 } 250 } 251 return fileName; 252 } 253 254 @Override getNativeNames(String fontFileName, String platformName)255 protected String[] getNativeNames(String fontFileName, 256 String platformName) { 257 Vector<String> nativeNames; 258 if ((nativeNames=xlfdMap.get(fontFileName))==null) { 259 if (platformName == null) { 260 return null; 261 } else { 262 /* back-stop so that at least the name used in the 263 * font configuration file is known as a native name 264 */ 265 String []natNames = new String[1]; 266 natNames[0] = platformName; 267 return natNames; 268 } 269 } else { 270 int len = nativeNames.size(); 271 return nativeNames.toArray(new String[len]); 272 } 273 } 274 275 /* NOTE: this method needs to be executed in a privileged context. 276 * The superclass constructor which is the primary caller of 277 * this method executes entirely in such a context. Additionally 278 * the loadFonts() method does too. So all should be well. 279 280 */ 281 @Override registerFontDir(String path)282 protected void registerFontDir(String path) { 283 /* fonts.dir file format looks like :- 284 * 47 285 * Arial.ttf -monotype-arial-regular-r-normal--0-0-0-0-p-0-iso8859-1 286 * Arial-Bold.ttf -monotype-arial-bold-r-normal--0-0-0-0-p-0-iso8859-1 287 * ... 288 */ 289 if (FontUtilities.debugFonts()) { 290 FontUtilities.logInfo("ParseFontDir " + path); 291 } 292 File fontsDotDir = new File(path + File.separator + "fonts.dir"); 293 FileReader fr = null; 294 try { 295 if (fontsDotDir.canRead()) { 296 fr = new FileReader(fontsDotDir); 297 BufferedReader br = new BufferedReader(fr, 8192); 298 StreamTokenizer st = new StreamTokenizer(br); 299 st.eolIsSignificant(true); 300 int ttype = st.nextToken(); 301 if (ttype == StreamTokenizer.TT_NUMBER) { 302 int numEntries = (int)st.nval; 303 ttype = st.nextToken(); 304 if (ttype == StreamTokenizer.TT_EOL) { 305 st.resetSyntax(); 306 st.wordChars(32, 127); 307 st.wordChars(128 + 32, 255); 308 st.whitespaceChars(0, 31); 309 310 for (int i=0; i < numEntries; i++) { 311 ttype = st.nextToken(); 312 if (ttype == StreamTokenizer.TT_EOF) { 313 break; 314 } 315 if (ttype != StreamTokenizer.TT_WORD) { 316 break; 317 } 318 int breakPos = st.sval.indexOf(' '); 319 if (breakPos <= 0) { 320 /* On TurboLinux 8.0 a fonts.dir file had 321 * a line with integer value "24" which 322 * appeared to be the number of remaining 323 * entries in the file. This didn't add to 324 * the value on the first line of the file. 325 * Seemed like XFree86 didn't like this line 326 * much either. It failed to parse the file. 327 * Ignore lines like this completely, and 328 * don't let them count as an entry. 329 */ 330 numEntries++; 331 ttype = st.nextToken(); 332 if (ttype != StreamTokenizer.TT_EOL) { 333 break; 334 } 335 336 continue; 337 } 338 if (st.sval.charAt(0) == '!') { 339 /* TurboLinux 8.0 comment line: ignore. 340 * can't use st.commentChar('!') to just 341 * skip because this line mustn't count 342 * against numEntries. 343 */ 344 numEntries++; 345 ttype = st.nextToken(); 346 if (ttype != StreamTokenizer.TT_EOL) { 347 break; 348 } 349 continue; 350 } 351 String fileName = st.sval.substring(0, breakPos); 352 /* TurboLinux 8.0 uses some additional syntax to 353 * indicate algorithmic styling values. 354 * Ignore ':' separated files at the beginning 355 * of the fileName 356 */ 357 int lastColon = fileName.lastIndexOf(':'); 358 if (lastColon > 0) { 359 if (lastColon+1 >= fileName.length()) { 360 continue; 361 } 362 fileName = fileName.substring(lastColon+1); 363 } 364 String fontPart = st.sval.substring(breakPos+1); 365 String fontID = specificFontIDForName(fontPart); 366 String sVal = fontNameMap.get(fontID); 367 368 if (FontUtilities.debugFonts()) { 369 FontUtilities.logInfo("file=" + fileName + 370 " xlfd=" + fontPart); 371 FontUtilities.logInfo("fontID=" + fontID + 372 " sVal=" + sVal); 373 } 374 String fullPath = null; 375 try { 376 File file = new File(path,fileName); 377 /* we may have a resolved symbolic link 378 * this becomes important for an xlfd we 379 * still need to know the location it was 380 * found to update the X server font path 381 * for use by AWT heavyweights - and when 2D 382 * wants to use the native rasteriser. 383 */ 384 if (xFontDirsMap == null) { 385 xFontDirsMap = new HashMap<>(); 386 } 387 xFontDirsMap.put(fontID, path); 388 fullPath = file.getCanonicalPath(); 389 } catch (IOException e) { 390 fullPath = path + File.separator + fileName; 391 } 392 Vector<String> xVal = xlfdMap.get(fullPath); 393 if (FontUtilities.debugFonts()) { 394 FontUtilities.logInfo("fullPath=" + fullPath + 395 " xVal=" + xVal); 396 } 397 if ((xVal == null || !xVal.contains(fontPart)) && 398 (sVal == null) || !sVal.startsWith("/")) { 399 if (FontUtilities.debugFonts()) { 400 FontUtilities.logInfo("Map fontID:"+fontID + 401 "to file:" + fullPath); 402 } 403 fontNameMap.put(fontID, fullPath); 404 if (xVal == null) { 405 xVal = new Vector<>(); 406 xlfdMap.put (fullPath, xVal); 407 } 408 xVal.add(fontPart); 409 } 410 411 ttype = st.nextToken(); 412 if (ttype != StreamTokenizer.TT_EOL) { 413 break; 414 } 415 } 416 } 417 } 418 fr.close(); 419 } 420 } catch (IOException ioe1) { 421 } finally { 422 if (fr != null) { 423 try { 424 fr.close(); 425 } catch (IOException ioe2) { 426 } 427 } 428 } 429 } 430 431 @Override loadFonts()432 public void loadFonts() { 433 super.loadFonts(); 434 /* These maps are greatly expanded during a loadFonts but 435 * can be reset to their initial state afterwards. 436 * Since preferLocaleFonts() and preferProportionalFonts() will 437 * trigger a partial repopulating from the FontConfiguration 438 * it has to be the inital (empty) state for the latter two, not 439 * simply nulling out. 440 * xFontDirsMap is a special case in that the implementation 441 * will typically not ever need to initialise it so it can be null. 442 */ 443 xFontDirsMap = null; 444 xlfdMap = new HashMap<>(1); 445 fontNameMap = new HashMap<>(1); 446 } 447 getX11FontName(String platName)448 private static String getX11FontName(String platName) { 449 String xlfd = platName.replaceAll("%d", "*"); 450 if (NativeFont.fontExists(xlfd)) { 451 return xlfd; 452 } else { 453 return null; 454 } 455 } 456 isHeadless()457 private boolean isHeadless() { 458 GraphicsEnvironment ge = 459 GraphicsEnvironment.getLocalGraphicsEnvironment(); 460 return GraphicsEnvironment.isHeadless(); 461 } 462 specificFontIDForName(String name)463 private String specificFontIDForName(String name) { 464 465 int[] hPos = new int[14]; 466 int hyphenCnt = 1; 467 int pos = 1; 468 469 while (pos != -1 && hyphenCnt < 14) { 470 pos = name.indexOf('-', pos); 471 if (pos != -1) { 472 hPos[hyphenCnt++] = pos; 473 pos++; 474 } 475 } 476 477 if (hyphenCnt != 14) { 478 if (FontUtilities.debugFonts()) { 479 FontUtilities.logSevere("Font Configuration Font ID is malformed:" + name); 480 } 481 return name; // what else can we do? 482 } 483 484 StringBuffer sb = 485 new StringBuffer(name.substring(hPos[FAMILY_NAME_FIELD-1], 486 hPos[SETWIDTH_NAME_FIELD])); 487 sb.append(name.substring(hPos[CHARSET_REGISTRY_FIELD-1])); 488 String retval = sb.toString().toLowerCase (Locale.ENGLISH); 489 return retval; 490 } 491 switchFontIDForName(String name)492 private String switchFontIDForName(String name) { 493 494 int[] hPos = new int[14]; 495 int hyphenCnt = 1; 496 int pos = 1; 497 498 while (pos != -1 && hyphenCnt < 14) { 499 pos = name.indexOf('-', pos); 500 if (pos != -1) { 501 hPos[hyphenCnt++] = pos; 502 pos++; 503 } 504 } 505 506 if (hyphenCnt != 14) { 507 if (FontUtilities.debugFonts()) { 508 FontUtilities.logSevere("Font Configuration Font ID is malformed:" + name); 509 } 510 return name; // what else can we do? 511 } 512 513 String slant = name.substring(hPos[SLANT_FIELD-1]+1, 514 hPos[SLANT_FIELD]); 515 String family = name.substring(hPos[FAMILY_NAME_FIELD-1]+1, 516 hPos[FAMILY_NAME_FIELD]); 517 String registry = name.substring(hPos[CHARSET_REGISTRY_FIELD-1]+1, 518 hPos[CHARSET_REGISTRY_FIELD]); 519 String encoding = name.substring(hPos[CHARSET_ENCODING_FIELD-1]+1); 520 521 if (slant.equals("i")) { 522 slant = "o"; 523 } else if (slant.equals("o")) { 524 slant = "i"; 525 } 526 // workaround for #4471000 527 if (family.equals("itc zapfdingbats") 528 && registry.equals("sun") 529 && encoding.equals("fontspecific")){ 530 registry = "adobe"; 531 } 532 StringBuffer sb = 533 new StringBuffer(name.substring(hPos[FAMILY_NAME_FIELD-1], 534 hPos[SLANT_FIELD-1]+1)); 535 sb.append(slant); 536 sb.append(name.substring(hPos[SLANT_FIELD], 537 hPos[SETWIDTH_NAME_FIELD]+1)); 538 sb.append(registry); 539 sb.append(name.substring(hPos[CHARSET_ENCODING_FIELD-1])); 540 String retval = sb.toString().toLowerCase (Locale.ENGLISH); 541 return retval; 542 } 543 544 /** 545 * Returns the face name for the given XLFD. 546 */ getFileNameFromXLFD(String name)547 public String getFileNameFromXLFD(String name) { 548 String fileName = null; 549 String fontID = specificFontIDForName(name); 550 if (fontID != null) { 551 fileName = fontNameMap.get(fontID); 552 if (fileName == null) { 553 fontID = switchFontIDForName(name); 554 fileName = fontNameMap.get(fontID); 555 } 556 if (fileName == null) { 557 fileName = getDefaultFontFile(); 558 } 559 } 560 return fileName; 561 } 562 563 /* Register just the paths, (it doesn't register the fonts). 564 * If a font configuration file has specified a baseFontPath 565 * fontPath is just those directories, unless on usage we 566 * find it doesn't contain what we need for the logical fonts. 567 * Otherwise, we register all the paths on Solaris, because 568 * the fontPath we have here is the complete one from 569 * parsing /var/sadm/install/contents, not just 570 * what's on the X font path (may be this should be 571 * changed). 572 * But for now what it means is that if we didn't do 573 * this then if the font weren't listed anywhere on the 574 * less complete font path we'd trigger loadFonts which 575 * actually registers the fonts. This may actually be 576 * the right thing tho' since that would also set up 577 * the X font path without which we wouldn't be able to 578 * display some "native" fonts. 579 * So something to revisit is that probably fontPath 580 * here ought to be only the X font path + jre font dir. 581 * loadFonts should have a separate native call to 582 * get the rest of the platform font path. 583 * 584 * Registering the directories can now be avoided in the 585 * font configuration initialisation when filename entries 586 * exist in the font configuration file for all fonts. 587 * (Perhaps a little confusingly a filename entry is 588 * actually keyed using the XLFD used in the font entries, 589 * and it maps *to* a real filename). 590 * In the event any are missing, registration of all 591 * directories will be invoked to find the real files. 592 * 593 * But registering the directory performed other 594 * functions such as filling in the map of all native names 595 * for the font. So when this method isn't invoked, they still 596 * must be found. This is mitigated by getNativeNames now 597 * being able to return at least the platform name, but mostly 598 * by ensuring that when a filename key is found, that 599 * xlfd key is stored as one of the set of platform names 600 * for the font. Its a set because typical font configuration 601 * files reference the same CJK font files using multiple 602 * X11 encodings. For the code that adds this to the map 603 * see X11GE.getFileNameFromPlatformName(..) 604 * If you don't get all of these then some code points may 605 * not use the Xserver, and will not get the PCF bitmaps 606 * that are available for some point sizes. 607 * So, in the event that there is such a problem, 608 * unconditionally making this call may be necessary, at 609 * some cost to JRE start-up 610 */ 611 @Override registerFontDirs(String pathName)612 protected void registerFontDirs(String pathName) { 613 614 StringTokenizer parser = new StringTokenizer(pathName, 615 File.pathSeparator); 616 try { 617 while (parser.hasMoreTokens()) { 618 String dirPath = parser.nextToken(); 619 if (dirPath != null && !registeredDirs.containsKey(dirPath)) { 620 registeredDirs.put(dirPath, null); 621 registerFontDir(dirPath); 622 } 623 } 624 } catch (NoSuchElementException e) { 625 } 626 } 627 628 // An X font spec (xlfd) includes an encoding. The same TrueType font file 629 // may be referenced from different X font directories in font.dir files 630 // to support use in multiple encodings by X apps. 631 // So for the purposes of font configuration logical fonts where AWT 632 // heavyweights need to access the font via X APIs we need to ensure that 633 // the directory for precisely the encodings needed by this are added to 634 // the x font path. This requires that we note the platform names 635 // specified in font configuration files and use that to identify the 636 // X font directory that contains a font.dir file for that platform name 637 // and add it to the X font path (if display is local) 638 // Here we make use of an already built map of xlfds to font locations 639 // to add the font location to the set of those required to build the 640 // x font path needed by AWT. 641 // These are added to the x font path later. 642 // All this is necessary because on Solaris the font.dir directories 643 // may contain not real font files, but symbolic links to the actual 644 // location but that location is not suitable for the x font path, since 645 // it probably doesn't have a font.dir at all and certainly not one 646 // with the required encodings 647 // If the fontconfiguration file is properly set up so that all fonts 648 // are mapped to files then we will never trigger initialising 649 // xFontDirsMap (it will be null). In this case the awtfontpath entries 650 // must specify all the X11 directories needed by AWT. 651 @Override addFontToPlatformFontPath(String platformName)652 protected void addFontToPlatformFontPath(String platformName) { 653 // Lazily initialize fontConfigDirs. 654 getPlatformFontPathFromFontConfig(); 655 if (xFontDirsMap != null) { 656 String fontID = specificFontIDForName(platformName); 657 String dirName = xFontDirsMap.get(fontID); 658 if (dirName != null) { 659 fontConfigDirs.add(dirName); 660 } 661 } 662 return; 663 } 664 getPlatformFontPathFromFontConfig()665 private void getPlatformFontPathFromFontConfig() { 666 if (fontConfigDirs == null) { 667 fontConfigDirs = getFontConfiguration().getAWTFontPathSet(); 668 if (FontUtilities.debugFonts() && fontConfigDirs != null) { 669 String[] names = fontConfigDirs.toArray(new String[0]); 670 for (int i=0;i<names.length;i++) { 671 FontUtilities.logInfo("awtfontpath : " + names[i]); 672 } 673 } 674 } 675 } 676 677 @Override registerPlatformFontsUsedByFontConfiguration()678 protected void registerPlatformFontsUsedByFontConfiguration() { 679 // Lazily initialize fontConfigDirs. 680 getPlatformFontPathFromFontConfig(); 681 if (fontConfigDirs == null) { 682 return; 683 } 684 if (FontUtilities.isLinux || FontUtilities.isBSD) { 685 fontConfigDirs.add(jreLibDirName+File.separator+"oblique-fonts"); 686 } 687 fontdirs = fontConfigDirs.toArray(new String[0]); 688 } 689 690 // Implements SunGraphicsEnvironment.createFontConfiguration. createFontConfiguration()691 protected FontConfiguration createFontConfiguration() { 692 /* The logic here decides whether to use a preconfigured 693 * fontconfig.properties file, or synthesise one using platform APIs. 694 * On Solaris we try to use the 695 * pre-configured ones, but if the files it specifies are missing 696 * we fail-safe to synthesising one. This might happen if Solaris 697 * changes its fonts. 698 * For Linux we require an exact match of distro and version to 699 * use the preconfigured file. 700 * If synthesising fails, we fall back to any preconfigured file 701 * and do the best we can. 702 */ 703 FontConfiguration mFontConfig = new MFontConfiguration(this); 704 if ((FontUtilities.isLinux && !mFontConfig.foundOsSpecificFile()) || 705 (FontUtilities.isBSD && !mFontConfig.foundOsSpecificFile())) { 706 FcFontConfiguration fcFontConfig = 707 new FcFontConfiguration(this); 708 if (fcFontConfig.init()) { 709 return fcFontConfig; 710 } 711 } 712 mFontConfig.init(); 713 return mFontConfig; 714 } 715 716 public FontConfiguration createFontConfiguration(boolean preferLocaleFonts, boolean preferPropFonts)717 createFontConfiguration(boolean preferLocaleFonts, 718 boolean preferPropFonts) { 719 720 return new MFontConfiguration(this, 721 preferLocaleFonts, preferPropFonts); 722 } 723 getFontPath(boolean noType1Fonts)724 protected synchronized String getFontPath(boolean noType1Fonts) { 725 isHeadless(); // make sure GE is inited, as its the X11 lock. 726 return getFontPathNative(noType1Fonts, true); 727 } 728 729 @Override getFontConfigFUIR(String family, int style, int size)730 protected FontUIResource getFontConfigFUIR(String family, int style, int size) { 731 732 CompositeFont font2D = getFontConfigManager().getFontConfigFont(family, style); 733 734 if (font2D == null) { // Not expected, just a precaution. 735 return new FontUIResource(family, style, size); 736 } 737 738 /* The name of the font will be that of the physical font in slot, 739 * but by setting the handle to that of the CompositeFont it 740 * renders as that CompositeFont. 741 * It also needs to be marked as a created font which is the 742 * current mechanism to signal that deriveFont etc must copy 743 * the handle from the original font. 744 */ 745 FontUIResource fuir = 746 new FontUIResource(font2D.getFamilyName(null), style, size); 747 FontAccess.getFontAccess().setFont2D(fuir, font2D.handle); 748 FontAccess.getFontAccess().setCreatedFont(fuir); 749 return fuir; 750 } 751 } 752