< prev index next >

src/java.desktop/share/classes/sun/font/SunFontManager.java

Print this page
rev 60064 : 8248802: Add log helper methods to FontUtilities.java


 303     }
 304 
 305     /* Initialise ptrs used by JNI methods */
 306     private static native void initIDs();
 307 
 308     protected SunFontManager() {
 309         AccessController.doPrivileged(new PrivilegedAction<Void>() {
 310             public Void run() {
 311                 File badFontFile =
 312                     new File(jreFontDirName + File.separator + "badfonts.txt");
 313                 if (badFontFile.exists()) {
 314                     badFonts = new ArrayList<>();
 315                     try (FileInputStream fis = new FileInputStream(badFontFile);
 316                          BufferedReader br = new BufferedReader(new InputStreamReader(fis))) {
 317                         while (true) {
 318                             String name = br.readLine();
 319                             if (name == null) {
 320                                 break;
 321                             } else {
 322                                 if (FontUtilities.debugFonts()) {
 323                                     FontUtilities.getLogger().warning("read bad font: " + name);
 324                                 }
 325                                 badFonts.add(name);
 326                             }
 327                         }
 328                     } catch (IOException e) {
 329                     }
 330                 }
 331 
 332                 /* Here we get the fonts in jre/lib/fonts and register
 333                  * them so they are always available and preferred over
 334                  * other fonts. This needs to be registered before the
 335                  * composite fonts as otherwise some native font that
 336                  * corresponds may be found as we don't have a way to
 337                  * handle two fonts of the same name, so the JRE one
 338                  * must be the first one registered. Pass "true" to
 339                  * registerFonts method as on-screen these JRE fonts
 340                  * always go through the JDK rasteriser.
 341                  */
 342                 if (FontUtilities.isLinux) {
 343                     /* Linux font configuration uses these fonts */
 344                     registerFontDir(jreFontDirName);
 345                 }
 346                 registerFontsInDir(jreFontDirName, true, Font2D.JRE_RANK,
 347                                    true, false);
 348 
 349                 /* Create the font configuration and get any font path
 350                  * that might be specified.
 351                  */
 352                 fontConfig = createFontConfiguration();
 353 
 354                 String[] fontInfo = getDefaultPlatformFont();
 355                 defaultFontName = fontInfo[0];
 356                 if (defaultFontName == null && FontUtilities.debugFonts()) {
 357                     FontUtilities.getLogger().warning("defaultFontName is null");
 358                 }
 359                 defaultFontFileName = fontInfo[1];
 360 
 361                 String extraFontPath = fontConfig.getExtraFontPath();
 362 
 363                 /* In prior releases the debugging font path replaced
 364                  * all normally located font directories except for the
 365                  * JRE fonts dir. This directory is still always located
 366                  * and placed at the head of the path but as an
 367                  * augmentation to the previous behaviour the
 368                  * changes below allow you to additionally append to
 369                  * the font path by starting with append: or prepend by
 370                  * starting with a prepend: sign. Eg: to append
 371                  * -Dsun.java2d.fontpath=append:/usr/local/myfonts
 372                  * and to prepend
 373                  * -Dsun.java2d.fontpath=prepend:/usr/local/myfonts Disp
 374                  *
 375                  * If there is an appendedfontpath it in the font
 376                  * configuration it is used instead of searching the
 377                  * system for dirs.


 386                  * locale-specific so its almost impossible to get
 387                  * right, so it should be used with caution.
 388                  */
 389                 boolean prependToPath = false;
 390                 boolean appendToPath = false;
 391                 String dbgFontPath = System.getProperty("sun.java2d.fontpath");
 392 
 393                 if (dbgFontPath != null) {
 394                     if (dbgFontPath.startsWith("prepend:")) {
 395                         prependToPath = true;
 396                         dbgFontPath =
 397                             dbgFontPath.substring("prepend:".length());
 398                     } else if (dbgFontPath.startsWith("append:")) {
 399                         appendToPath = true;
 400                         dbgFontPath =
 401                             dbgFontPath.substring("append:".length());
 402                     }
 403                 }
 404 
 405                 if (FontUtilities.debugFonts()) {
 406                     PlatformLogger logger = FontUtilities.getLogger();
 407                     logger.info("JRE font directory: " + jreFontDirName);
 408                     logger.info("Extra font path: " + extraFontPath);
 409                     logger.info("Debug font path: " + dbgFontPath);
 410                 }
 411 
 412                 if (dbgFontPath != null) {
 413                     /* In debugging mode we register all the paths
 414                      * Caution: this is a very expensive call on Solaris:-
 415                      */
 416                     fontPath = getPlatformFontPath(noType1Font);
 417 
 418                     if (extraFontPath != null) {
 419                         fontPath = extraFontPath + File.pathSeparator + fontPath;
 420                     }
 421                     if (appendToPath) {
 422                         fontPath += File.pathSeparator + dbgFontPath;
 423                     } else if (prependToPath) {
 424                         fontPath = dbgFontPath + File.pathSeparator + fontPath;
 425                     } else {
 426                         fontPath = dbgFontPath;
 427                     }
 428                     registerFontDirs(fontPath);
 429                 } else if (extraFontPath != null) {


 545          * its handle point to this new font.
 546          * This ensures that when the altNameCache that is passed in
 547          * is the global mapNameCache - ie we are running as an application -
 548          * that any statically created java.awt.Font instances which already
 549          * have a Font2D instance will have that re-directed to the new Font
 550          * on subsequent uses. This is particularly important for "the"
 551          * default font instance, or similar cases where a UI toolkit (eg
 552          * Swing) has cached a java.awt.Font. Note that if Swing is using
 553          * a custom composite APIs which update the standard composites have
 554          * no effect - this is typically the case only when using the Windows
 555          * L&F where these APIs would conflict with that L&F anyway.
 556          */
 557         Font2D oldFont =altNameCache.get(compositeName.toLowerCase(Locale.ENGLISH));
 558         if (oldFont instanceof CompositeFont) {
 559             oldFont.handle.font2D = cf;
 560         }
 561         altNameCache.put(compositeName.toLowerCase(Locale.ENGLISH), cf);
 562     }
 563 
 564     private void addCompositeToFontList(CompositeFont f, int rank) {
 565 
 566         if (FontUtilities.isLogging()) {
 567             FontUtilities.getLogger().info("Add to Family "+ f.familyName +
 568                         ", Font " + f.fullName + " rank="+rank);
 569         }
 570         f.setRank(rank);
 571         compositeFonts.put(f.fullName, f);
 572         fullNameToFont.put(f.fullName.toLowerCase(Locale.ENGLISH), f);
 573 
 574         FontFamily family = FontFamily.getFamily(f.familyName);
 575         if (family == null) {
 576             family = new FontFamily(f.familyName, true, rank);
 577         }
 578         family.setFont(f, f.style);
 579     }
 580 
 581     /*
 582      * Systems may have fonts with the same name.
 583      * We want to register only one of such fonts (at least until
 584      * such time as there might be APIs which can accommodate > 1).
 585      * Rank is 1) font configuration fonts, 2) JRE fonts, 3) OT/TT fonts,
 586      * 4) Type1 fonts, 5) native fonts.
 587      *
 588      * If the new font has the same name as the old font, the higher


 608      * and you should use that one.
 609      * If it returns null means this font was not registered and none
 610      * in that name is registered. The caller must find a substitute
 611      */
 612     // MACOSX begin -- need to access this in subclass
 613     protected PhysicalFont addToFontList(PhysicalFont f, int rank) {
 614     // MACOSX end
 615 
 616         String fontName = f.fullName;
 617         String familyName = f.familyName;
 618         if (fontName == null || fontName.isEmpty()) {
 619             return null;
 620         }
 621         if (compositeFonts.containsKey(fontName)) {
 622             /* Don't register any font that has the same name as a composite */
 623             return null;
 624         }
 625         f.setRank(rank);
 626         if (!physicalFonts.containsKey(fontName)) {
 627             if (FontUtilities.isLogging()) {
 628                 FontUtilities.getLogger().info("Add to Family "+familyName +
 629                             ", Font " + fontName + " rank="+rank);
 630             }
 631             physicalFonts.put(fontName, f);
 632             FontFamily family = FontFamily.getFamily(familyName);
 633             if (family == null) {
 634                 family = new FontFamily(familyName, false, rank);
 635                 family.setFont(f, f.style);
 636             } else {
 637                 family.setFont(f, f.style);
 638             }
 639             fullNameToFont.put(fontName.toLowerCase(Locale.ENGLISH), f);
 640             return f;
 641         } else {
 642             PhysicalFont newFont = f;
 643             PhysicalFont oldFont = physicalFonts.get(fontName);
 644             if (oldFont == null) {
 645                 return null;
 646             }
 647             /* If the new font is of an equal or higher rank, it is a
 648              * candidate to replace the current one, subject to further tests.
 649              */


 682                         TrueTypeFont oldTTFont = (TrueTypeFont)oldFont;
 683                         TrueTypeFont newTTFont = (TrueTypeFont)newFont;
 684                         if (oldTTFont.fileSize >= newTTFont.fileSize) {
 685                             return oldFont;
 686                         }
 687                     } else {
 688                         return oldFont;
 689                     }
 690                 }
 691                 /* Don't replace ever JRE fonts.
 692                  * This test is in case a font configuration references
 693                  * a Lucida font, which has been mapped to a Lucida
 694                  * from the host O/S. The assumption here is that any
 695                  * such font configuration file is probably incorrect, or
 696                  * the host O/S version is for the use of AWT.
 697                  * In other words if we reach here, there's a possible
 698                  * problem with our choice of font configuration fonts.
 699                  */
 700                 if (oldFont.platName.startsWith(jreFontDirName)) {
 701                     if (FontUtilities.isLogging()) {
 702                         FontUtilities.getLogger()
 703                               .warning("Unexpected attempt to replace a JRE " +
 704                                        " font " + fontName + " from " +
 705                                         oldFont.platName +
 706                                        " with " + newFont.platName);
 707                     }
 708                     return oldFont;
 709                 }
 710 
 711                 if (FontUtilities.isLogging()) {
 712                     FontUtilities.getLogger()
 713                           .info("Replace in Family " + familyName +
 714                                 ",Font " + fontName + " new rank="+rank +
 715                                 " from " + oldFont.platName +
 716                                 " with " + newFont.platName);
 717                 }
 718                 replaceFont(oldFont, newFont);
 719                 physicalFonts.put(fontName, newFont);
 720                 fullNameToFont.put(fontName.toLowerCase(Locale.ENGLISH),
 721                                    newFont);
 722 
 723                 FontFamily family = FontFamily.getFamily(familyName);
 724                 if (family == null) {
 725                     family = new FontFamily(familyName, false, rank);
 726                     family.setFont(newFont, newFont.style);
 727                 } else {
 728                     family.setFont(newFont, newFont.style);
 729                 }
 730                 return newFont;
 731             } else {
 732                 return oldFont;
 733             }


 886     public void registerDeferredFont(String fileNameKey,
 887                                      String fullPathName,
 888                                      String[] nativeNames,
 889                                      int fontFormat,
 890                                      boolean useJavaRasterizer,
 891                                      int fontRank) {
 892         FontRegistrationInfo regInfo =
 893             new FontRegistrationInfo(fullPathName, nativeNames, fontFormat,
 894                                      useJavaRasterizer, fontRank);
 895         deferredFontFiles.put(fileNameKey, regInfo);
 896     }
 897 
 898 
 899     public synchronized
 900          PhysicalFont initialiseDeferredFont(String fileNameKey) {
 901 
 902         if (fileNameKey == null) {
 903             return null;
 904         }
 905         if (FontUtilities.isLogging()) {
 906             FontUtilities.getLogger()
 907                             .info("Opening deferred font file " + fileNameKey);
 908         }
 909 
 910         PhysicalFont physicalFont = null;
 911         FontRegistrationInfo regInfo = deferredFontFiles.get(fileNameKey);
 912         if (regInfo != null) {
 913             deferredFontFiles.remove(fileNameKey);
 914             physicalFont = registerFontFile(regInfo.fontFilePath,
 915                                             regInfo.nativeNames,
 916                                             regInfo.fontFormat,
 917                                             regInfo.javaRasterizer,
 918                                             regInfo.fontRank);
 919 
 920             if (physicalFont != null) {
 921                 /* Store the handle, so that if a font is bad, we
 922                  * retrieve the substituted font.
 923                  */
 924                 initialisedFonts.put(fileNameKey, physicalFont.handle);
 925             } else {
 926                 initialisedFonts.put(fileNameKey, FONT_HANDLE_NULL);
 927             }


 974                     if (physicalFont == null) {
 975                         physicalFont = pf;
 976                     }
 977                 }
 978                 while (fn < ttf.getFontCount());
 979                 break;
 980 
 981             case FONTFORMAT_TYPE1:
 982                 Type1Font t1f = new Type1Font(fileName, nativeNames);
 983                 physicalFont = addToFontList(t1f, fontRank);
 984                 break;
 985 
 986             case FONTFORMAT_NATIVE:
 987                 NativeFont nf = new NativeFont(fileName, false);
 988                 physicalFont = addToFontList(nf, fontRank);
 989                 break;
 990             default:
 991 
 992             }
 993             if (FontUtilities.isLogging()) {
 994                 FontUtilities.getLogger()
 995                       .info("Registered file " + fileName + " as font " +
 996                             physicalFont + " rank="  + fontRank);
 997             }
 998         } catch (FontFormatException ffe) {
 999             if (FontUtilities.isLogging()) {
1000                 FontUtilities.getLogger().warning("Unusable font: " +
1001                                fileName + " " + ffe.toString());
1002             }
1003         }
1004         if (physicalFont != null &&
1005             fontFormat != FONTFORMAT_NATIVE) {
1006             registeredFonts.put(fileName, physicalFont);
1007         }
1008         return physicalFont;
1009     }
1010 
1011     public void registerFonts(String[] fileNames,
1012                               String[][] nativeNames,
1013                               int fontCount,
1014                               int fontFormat,
1015                               boolean useJavaRasterizer,
1016                               int fontRank, boolean defer) {
1017 
1018         for (int i=0; i < fontCount; i++) {
1019             if (defer) {
1020                 registerDeferredFont(fileNames[i],fileNames[i], nativeNames[i],
1021                                      fontFormat, useJavaRasterizer, fontRank);


1025             }
1026         }
1027     }
1028 
1029     /*
1030      * This is the Physical font used when some other font on the system
1031      * can't be located. There has to be at least one font or the font
1032      * system is not useful and the graphics environment cannot sustain
1033      * the Java platform.
1034      */
1035     public PhysicalFont getDefaultPhysicalFont() {
1036         if (defaultPhysicalFont == null) {
1037             String defaultFontName = getDefaultFontFaceName();
1038             // findFont2D will load all fonts
1039             Font2D font2d = findFont2D(defaultFontName, Font.PLAIN, NO_FALLBACK);
1040             if (font2d != null) {
1041                 if (font2d instanceof PhysicalFont) {
1042                     defaultPhysicalFont = (PhysicalFont)font2d;
1043                 } else {
1044                     if (FontUtilities.isLogging()) {
1045                         FontUtilities.getLogger()
1046                             .warning("Font returned by findFont2D for default font name " +
1047                                      defaultFontName + " is not a physical font: " + font2d.getFontName(null));
1048                     }
1049                 }
1050             }
1051             if (defaultPhysicalFont == null) {
1052                 /* Because of the findFont2D call above, if we reach here, we
1053                  * know all fonts have already been loaded, just accept any
1054                  * match at this point. If this fails we are in real trouble
1055                  * and I don't know how to recover from there being absolutely
1056                  * no fonts anywhere on the system.
1057                  */
1058                 defaultPhysicalFont = physicalFonts.values().stream().findFirst()
1059                     .orElseThrow(()->new Error("Probable fatal error: No physical fonts found."));
1060             }
1061         }
1062         return defaultPhysicalFont;
1063     }
1064 
1065     public Font2D getDefaultLogicalFont(int style) {
1066         return findFont2D("dialog", style, NO_FALLBACK);


1287             }
1288 
1289             /* remove from the set of names that will be returned to the
1290              * user any fonts that can't be mapped to files.
1291              */
1292             if (unmappedFontNames.size() > 0) {
1293                 int sz = unmappedFontNames.size();
1294                 for (int i=0; i<sz; i++) {
1295                     String name = unmappedFontNames.get(i);
1296                     String familyName = fontToFamilyNameMap.get(name);
1297                     if (familyName != null) {
1298                         ArrayList<String> family = familyToFontListMap.get(familyName);
1299                         if (family != null) {
1300                             if (family.size() <= 1) {
1301                                 familyToFontListMap.remove(familyName);
1302                             }
1303                         }
1304                     }
1305                     fontToFamilyNameMap.remove(name);
1306                     if (FontUtilities.isLogging()) {
1307                         FontUtilities.getLogger()
1308                                              .info("No file for font:" + name);
1309                     }
1310                 }
1311             }
1312         }
1313     }
1314 
1315     /**
1316      * In some cases windows may have fonts in the fonts folder that
1317      * don't show up in the registry or in the GDI calls to enumerate fonts.
1318      * The only way to find these is to list the directory. We invoke this
1319      * only in getAllFonts/Families, so most searches for a specific
1320      * font that is satisfied by the GDI/registry calls don't take the
1321      * additional hit of listing the directory. This hit is small enough
1322      * that its not significant in these 'enumerate all the fonts' cases.
1323      * The basic approach is to cross-reference the files windows found
1324      * with the ones in the directory listing approach, and for each
1325      * in the latter list that is missing from the former list, register it.
1326      */
1327     private synchronized void checkForUnreferencedFontFiles() {
1328         if (haveCheckedUnreferencedFontFiles) {


1338          */
1339         ArrayList<String> registryFiles = new ArrayList<>();
1340         for (String regFile : fontToFileMap.values()) {
1341             registryFiles.add(regFile.toLowerCase());
1342         }
1343 
1344         /* To avoid any issues with concurrent modification, create
1345          * copies of the existing maps, add the new fonts into these
1346          * and then replace the references to the old ones with the
1347          * new maps. ConcurrentHashmap is another option but its a lot
1348          * more changes and with this exception, these maps are intended
1349          * to be static.
1350          */
1351         HashMap<String,String> fontToFileMap2 = null;
1352         HashMap<String,String> fontToFamilyNameMap2 = null;
1353         HashMap<String,ArrayList<String>> familyToFontListMap2 = null;;
1354 
1355         for (String pathFile : getFontFilesFromPath(false)) {
1356             if (!registryFiles.contains(pathFile)) {
1357                 if (FontUtilities.isLogging()) {
1358                     FontUtilities.getLogger()
1359                                  .info("Found non-registry file : " + pathFile);
1360                 }
1361                 PhysicalFont f = registerFontFile(getPathName(pathFile));
1362                 if (f == null) {
1363                     continue;
1364                 }
1365                 if (fontToFileMap2 == null) {
1366                     fontToFileMap2 = new HashMap<>(fontToFileMap);
1367                     fontToFamilyNameMap2 = new HashMap<>(fontToFamilyNameMap);
1368                     familyToFontListMap2 = new HashMap<>(familyToFontListMap);
1369                 }
1370                 String fontName = f.getFontName(null);
1371                 String family = f.getFamilyName(null);
1372                 String familyLC = family.toLowerCase();
1373                 fontToFamilyNameMap2.put(fontName, family);
1374                 fontToFileMap2.put(fontName, pathFile);
1375                 ArrayList<String> fonts = familyToFontListMap2.get(familyLC);
1376                 if (fonts == null) {
1377                     fonts = new ArrayList<>();
1378                 } else {
1379                     fonts = new ArrayList<>(fonts);


1383             }
1384         }
1385         if (fontToFileMap2 != null) {
1386             fontToFileMap = fontToFileMap2;
1387             familyToFontListMap = familyToFontListMap2;
1388             fontToFamilyNameMap = fontToFamilyNameMap2;
1389         }
1390     }
1391 
1392     private void resolveFontFiles(HashSet<String> unmappedFiles,
1393                                   ArrayList<String> unmappedFonts) {
1394 
1395         Locale l = SunToolkit.getStartupLocale();
1396 
1397         for (String file : unmappedFiles) {
1398             try {
1399                 int fn = 0;
1400                 TrueTypeFont ttf;
1401                 String fullPath = getPathName(file);
1402                 if (FontUtilities.isLogging()) {
1403                     FontUtilities.getLogger()
1404                                    .info("Trying to resolve file " + fullPath);
1405                 }
1406                 do {
1407                     ttf = new TrueTypeFont(fullPath, null, fn++, false);
1408                     //  prefer the font's locale name.
1409                     String fontName = ttf.getFontName(l).toLowerCase();
1410                     if (unmappedFonts.contains(fontName)) {
1411                         fontToFileMap.put(fontName, file);
1412                         unmappedFonts.remove(fontName);
1413                         if (FontUtilities.isLogging()) {
1414                             FontUtilities.getLogger()
1415                                   .info("Resolved absent registry entry for " +
1416                                         fontName + " located in " + fullPath);
1417                         }
1418                     }
1419                 }
1420                 while (fn < ttf.getFontCount());
1421             } catch (Exception e) {
1422             }
1423         }
1424     }
1425 
1426     /* Hardwire the English names and expected file names of fonts
1427      * commonly used at start up. Avoiding until later even the small
1428      * cost of calling platform APIs to locate these can help.
1429      * The code that registers these fonts needs to "bail" if any
1430      * of the files do not exist, so it will verify the existence of
1431      * all non-null file names first.
1432      * They are added in to a map with nominally the first
1433      * word in the name of the family as the key. In all the cases
1434      * we are using the family name is a single word, and as is
1435      * more or less required the family name is the initial sequence


1521                 failure = true;
1522             }
1523         }
1524 
1525         if (fd.italicFileName != null) {
1526             italicFile = getPathName(fd.italicFileName);
1527             if (italicFile == null) {
1528                 failure = true;
1529             }
1530         }
1531 
1532         if (fd.boldItalicFileName != null) {
1533             boldItalicFile = getPathName(fd.boldItalicFileName);
1534             if (boldItalicFile == null) {
1535                 failure = true;
1536             }
1537         }
1538 
1539         if (failure) {
1540             if (FontUtilities.isLogging()) {
1541                 FontUtilities.getLogger().
1542                     info("Hardcoded file missing looking for " + lcName);
1543             }
1544             platformFontMap.remove(firstWord);
1545             return null;
1546         }
1547 
1548         /* Some of these may be null,as not all styles have to exist */
1549         final String[] files = {
1550             plainFile, boldFile, italicFile, boldItalicFile } ;
1551 
1552         failure = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
1553              public Boolean run() {
1554                  for (int i=0; i<files.length; i++) {
1555                      if (files[i] == null) {
1556                          continue;
1557                      }
1558                      File f = new File(files[i]);
1559                      if (!f.exists()) {
1560                          return Boolean.TRUE;
1561                      }
1562                  }
1563                  return Boolean.FALSE;
1564              }
1565          });
1566 
1567         if (failure) {
1568             if (FontUtilities.isLogging()) {
1569                 FontUtilities.getLogger().
1570                     info("Hardcoded file missing looking for " + lcName);
1571             }
1572             platformFontMap.remove(firstWord);
1573             return null;
1574         }
1575 
1576         /* If we reach here we know that we have all the files we
1577          * expect, so all should be fine so long as the contents
1578          * are what we'd expect. Now on to registering the fonts.
1579          * Currently this code only looks for TrueType fonts, so format
1580          * and rank can be specified without looking at the filename.
1581          */
1582         Font2D font = null;
1583         for (int f=0;f<files.length;f++) {
1584             if (files[f] == null) {
1585                 continue;
1586             }
1587             PhysicalFont pf =
1588                 registerFontFile(files[f], null,
1589                                  FONTFORMAT_TRUETYPE, false, Font2D.TTF_RANK);
1590             if (f == styleIndex) {


1817         if (fontList.length == 0) {
1818             return null;
1819         }
1820 
1821         /* first check that for every font in this family we can find
1822          * a font file. The specific reason for doing this is that
1823          * in at least one case on Windows a font has the face name "David"
1824          * but the registry entry is "David Regular". That is the "unique"
1825          * name of the font but in other cases the registry contains the
1826          * "full" name. See the specifications of name ids 3 and 4 in the
1827          * TrueType 'name' table.
1828          * In general this could cause a problem that we fail to register
1829          * if we all members of a family that we may end up mapping to
1830          * the wrong font member: eg return Bold when Plain is needed.
1831          */
1832         for (int f=0;f<fontList.length;f++) {
1833             String fontNameLC = fontList[f].toLowerCase(Locale.ENGLISH);
1834             String fileName = fontToFileMap.get(fontNameLC);
1835             if (fileName == null) {
1836                 if (FontUtilities.isLogging()) {
1837                     FontUtilities.getLogger()
1838                           .info("Platform lookup : No file for font " +
1839                                 fontList[f] + " in family " +familyName);
1840                 }
1841                 return null;
1842             }
1843         }
1844 
1845         /* Currently this code only looks for TrueType fonts, so format
1846          * and rank can be specified without looking at the filename.
1847          */
1848         PhysicalFont physicalFont = null;
1849         if (fontFile != null) {
1850             physicalFont = registerFontFile(getPathName(fontFile), null,
1851                                             FONTFORMAT_TRUETYPE, false,
1852                                             Font2D.TTF_RANK);
1853         }
1854         /* Register all fonts in this family. */
1855         for (int f=0;f<fontList.length;f++) {
1856             String fontNameLC = fontList[f].toLowerCase(Locale.ENGLISH);
1857             String fileName = fontToFileMap.get(fontNameLC);
1858             if (fontFile != null && fontFile.equals(fileName)) {


1888      * The name could be a family name, or a full name.
1889      * A font may exist with the specified style, or it may
1890      * exist only in some other style. For non-native fonts the scaler
1891      * may be able to emulate the required style.
1892      */
1893     public Font2D findFont2D(String name, int style, int fallback) {
1894         if (name == null) return null;
1895         String lowerCaseName = name.toLowerCase(Locale.ENGLISH);
1896         String mapName = lowerCaseName + dotStyleStr(style);
1897 
1898         /* If preferLocaleFonts() or preferProportionalFonts() has been
1899          * called we may be using an alternate set of composite fonts in this
1900          * app context. The presence of a pre-built name map indicates whether
1901          * this is so, and gives access to the alternate composite for the
1902          * name.
1903          */
1904         Font2D font = fontNameCache.get(mapName);
1905         if (font != null) {
1906             return font;
1907         }
1908 
1909         if (FontUtilities.isLogging()) {
1910             FontUtilities.getLogger().info("Search for font: " + name);
1911         }
1912 
1913         // The check below is just so that the bitmap fonts being set by
1914         // AWT and Swing thru the desktop properties do not trigger the
1915         // the load fonts case. The two bitmap fonts are now mapped to
1916         // appropriate equivalents for serif and sansserif.
1917         // Note that the cost of this comparison is only for the first
1918         // call until the map is filled.
1919         if (FontUtilities.isWindows) {
1920             if (lowerCaseName.equals("ms sans serif")) {
1921                 name = "sansserif";
1922             } else if (lowerCaseName.equals("ms serif")) {
1923                 name = "serif";
1924             }
1925         }
1926 
1927         /* This isn't intended to support a client passing in the
1928          * string default, but if a client passes in null for the name
1929          * the java.awt.Font class internally substitutes this name.
1930          * So we need to recognise it here to prevent a loadFonts


2004                              * that shouldn't be done. ie if we get this
2005                              * far we have probably as close a match as we
2006                              * are going to get. We could load all fonts to
2007                              * see if somehow some parts of the family are
2008                              * loaded but not all of it.
2009                              */
2010                             if (familyFont.canDoStyle(style|font.style)) {
2011                                 fontNameCache.put(mapName, familyFont);
2012                                 return familyFont;
2013                             }
2014                         }
2015                     }
2016                 }
2017             }
2018         }
2019 
2020         if (FontUtilities.isWindows) {
2021 
2022             font = findFontFromPlatformMap(lowerCaseName, style);
2023             if (FontUtilities.isLogging()) {
2024                 FontUtilities.getLogger()
2025                     .info("findFontFromPlatformMap returned " + font);
2026             }

2027             if (font != null) {
2028                 fontNameCache.put(mapName, font);
2029                 return font;
2030             }
2031             /* Don't want Windows to return a font from C:\Windows\Fonts
2032              * if someone has installed a font with the same name
2033              * in the JRE.
2034              */
2035             if (deferredFontFiles.size() > 0) {
2036                 font = findJREDeferredFont(lowerCaseName, style);
2037                 if (font != null) {
2038                     fontNameCache.put(mapName, font);
2039                     return font;
2040                 }
2041             }
2042             font = findFontFromPlatform(lowerCaseName, style);
2043             if (font != null) {
2044                 if (FontUtilities.isLogging()) {
2045                     FontUtilities.getLogger()
2046                           .info("Found font via platform API for request:\"" +
2047                                 name + "\":, style="+style+
2048                                 " found font: " + font);
2049                 }
2050                 fontNameCache.put(mapName, font);
2051                 return font;
2052             }
2053         }
2054 
2055         /* If reach here and no match has been located, then if there are
2056          * uninitialised deferred fonts, load as many of those as needed
2057          * to find the deferred font. If none is found through that
2058          * search continue on.
2059          * There is possibly a minor issue when more than one
2060          * deferred font implements the same font face. Since deferred
2061          * fonts are only those in font configuration files, this is a
2062          * controlled situation, the known case being Solaris euro_fonts
2063          * versions of Arial, Times New Roman, Courier New. However
2064          * the larger font will transparently replace the smaller one
2065          *  - see addToFontList() - when it is needed by the composite font.
2066          */


2099                     if (fontsAreRegistered) {
2100                         fontNameCache.put(mapName, font);
2101                     }
2102                     return font;
2103                 }
2104             }
2105             font = nameTable.get(lowerCaseName);
2106             if (font != null) {
2107                 if (fontsAreRegistered) {
2108                     fontNameCache.put(mapName, font);
2109                 }
2110                 return font;
2111             }
2112         }
2113 
2114         /* If reach here and no match has been located, then if all fonts
2115          * are not yet loaded, do so, and then recurse.
2116          */
2117         if (!loadedAllFonts) {
2118             if (FontUtilities.isLogging()) {
2119                 FontUtilities.getLogger()
2120                                        .info("Load fonts looking for:" + name);
2121             }
2122             loadFonts();
2123             loadedAllFonts = true;
2124             return findFont2D(name, style, fallback);
2125         }
2126 
2127         if (!loadedAllFontFiles) {
2128             if (FontUtilities.isLogging()) {
2129                 FontUtilities.getLogger()
2130                                   .info("Load font files looking for:" + name);
2131             }
2132             loadFontFiles();
2133             loadedAllFontFiles = true;
2134             return findFont2D(name, style, fallback);
2135         }
2136 
2137         /* The primary name is the locale default - ie not US/English but
2138          * whatever is the default in this locale. This is the way it always
2139          * has been but may be surprising to some developers if "Arial Regular"
2140          * were hard-coded in their app and yet "Arial Regular" was not the
2141          * default name. Fortunately for them, as a consequence of the JDK
2142          * supporting returning names and family names for arbitrary locales,
2143          * we also need to support searching all localised names for a match.
2144          * But because this case of the name used to reference a font is not
2145          * the same as the default for this locale is rare, it makes sense to
2146          * search a much shorter list of default locale names and only go to
2147          * a longer list of names in the event that no match was found.
2148          * So add here code which searches localised names too.
2149          * As in 1.4.x this happens only after loading all fonts, which
2150          * is probably the right order.


2168             String compatName =
2169                 getFontConfiguration().getFallbackFamilyName(name, null);
2170             if (compatName != null) {
2171                 font = findFont2D(compatName, style, fallback);
2172                 fontNameCache.put(mapName, font);
2173                 return font;
2174             }
2175         } else if (lowerCaseName.equals("timesroman")) {
2176             font = findFont2D("serif", style, fallback);
2177             fontNameCache.put(mapName, font);
2178             return font;
2179         } else if (lowerCaseName.equals("helvetica")) {
2180             font = findFont2D("sansserif", style, fallback);
2181             fontNameCache.put(mapName, font);
2182             return font;
2183         } else if (lowerCaseName.equals("courier")) {
2184             font = findFont2D("monospaced", style, fallback);
2185             fontNameCache.put(mapName, font);
2186             return font;
2187         }
2188 
2189         if (FontUtilities.isLogging()) {
2190             FontUtilities.getLogger().info("No font found for:" + name);
2191         }
2192 
2193         switch (fallback) {
2194         case PHYSICAL_FALLBACK: return getDefaultPhysicalFont();
2195         case LOGICAL_FALLBACK: return getDefaultLogicalFont(style);
2196         default: return null;
2197         }
2198     }
2199 
2200     /*
2201      * Workaround for apps which are dependent on a font metrics bug
2202      * in JDK 1.1. This is an unsupported win32 private setting.
2203      * Left in for a customer - do not remove.
2204      */
2205     public boolean usePlatformFontMetrics() {
2206         return usePlatformFontMetrics;
2207     }
2208 
2209     public int getNumFonts() {
2210         return physicalFonts.size()+maxCompFont;


2345     }
2346 
2347     /*
2348      * This is called when font is determined to be invalid/bad.
2349      * It designed to be called (for example) by the font scaler
2350      * when in processing a font file it is discovered to be incorrect.
2351      * This is different than the case where fonts are discovered to
2352      * be incorrect during initial verification, as such fonts are
2353      * never registered.
2354      * Handles to this font held are re-directed to a default font.
2355      * This default may not be an ideal substitute buts it better than
2356      * crashing This code assumes a PhysicalFont parameter as it doesn't
2357      * make sense for a Composite to be "bad".
2358      */
2359     public synchronized void deRegisterBadFont(Font2D font2D) {
2360         if (!(font2D instanceof PhysicalFont)) {
2361             /* We should never reach here, but just in case */
2362             return;
2363         } else {
2364             if (FontUtilities.isLogging()) {
2365                 FontUtilities.getLogger()
2366                                      .severe("Deregister bad font: " + font2D);
2367             }
2368             replaceFont((PhysicalFont)font2D, getDefaultPhysicalFont());
2369         }
2370     }
2371 
2372     /*
2373      * This encapsulates all the work that needs to be done when a
2374      * Font2D is replaced by a different Font2D.
2375      */
2376     public synchronized void replaceFont(PhysicalFont oldFont,
2377                                          PhysicalFont newFont) {
2378 
2379         if (oldFont.handle.font2D != oldFont) {
2380             /* already done */
2381             return;
2382         }
2383 
2384         /* If we try to replace the font with itself, that won't work,
2385          * so pick any alternative physical font
2386          */
2387         if (oldFont == newFont) {
2388             if (FontUtilities.isLogging()) {
2389                 FontUtilities.getLogger()
2390                       .severe("Can't replace bad font with itself " + oldFont);
2391             }
2392             PhysicalFont[] physFonts = getPhysicalFonts();
2393             for (int i=0; i<physFonts.length;i++) {
2394                 if (physFonts[i] != newFont) {
2395                     newFont = physFonts[i];
2396                     break;
2397                 }
2398             }
2399             if (oldFont == newFont) {
2400                 if (FontUtilities.isLogging()) {
2401                     FontUtilities.getLogger()
2402                            .severe("This is bad. No good physicalFonts found.");
2403                 }
2404                 return;
2405             }
2406         }
2407 
2408         /* eliminate references to this font, so it won't be located
2409          * by future callers, and will be eligible for GC when all
2410          * references are removed
2411          */
2412         oldFont.handle.font2D = newFont;
2413         physicalFonts.remove(oldFont.fullName);
2414         fullNameToFont.remove(oldFont.fullName.toLowerCase(Locale.ENGLISH));
2415         FontFamily.remove(oldFont);
2416         if (localeFullNamesToFont != null) {
2417             Map.Entry<?, ?>[] mapEntries = localeFullNamesToFont.entrySet().
2418                 toArray(new Map.Entry<?, ?>[0]);
2419             /* Should I be replacing these, or just I just remove
2420              * the names from the map?
2421              */
2422             for (int i=0; i<mapEntries.length;i++) {


2483                 String[] fullNames = ttf.getAllFullNames();
2484                 for (int n=0; n<fullNames.length; n++) {
2485                     localeFullNamesToFont.put(fullNames[n], ttf);
2486                 }
2487                 FontFamily family = FontFamily.getFamily(ttf.familyName);
2488                 if (family != null) {
2489                     FontFamily.addLocaleNames(family, ttf.getAllFamilyNames());
2490                 }
2491             }
2492         }
2493     }
2494 
2495     /* This replicate the core logic of findFont2D but operates on
2496      * all the locale names. This hasn't been merged into findFont2D to
2497      * keep the logic simpler and reduce overhead, since this case is
2498      * almost never used. The main case in which it is called is when
2499      * a bogus font name is used and we need to check all possible names
2500      * before returning the default case.
2501      */
2502     private Font2D findFont2DAllLocales(String name, int style) {
2503 
2504         if (FontUtilities.isLogging()) {
2505             FontUtilities.getLogger()
2506                            .info("Searching localised font names for:" + name);
2507         }
2508 
2509         /* If reach here and no match has been located, then if we have
2510          * not yet built the map of localeFullNamesToFont for TT fonts, do so
2511          * now. This method must be called after all fonts have been loaded.
2512          */
2513         if (localeFullNamesToFont == null) {
2514             loadLocaleNames();
2515         }
2516         String lowerCaseName = name.toLowerCase();
2517         Font2D font = null;
2518 
2519         /* First see if its a family name. */
2520         FontFamily family = FontFamily.getLocaleFamily(lowerCaseName);
2521         if (family != null) {
2522           font = family.getFont(style);
2523           if (font == null) {
2524             font = family.getClosestStyle(style);
2525           }
2526           if (font != null) {


2622      * the Font.equals() method since it needs to also check if the Font2D
2623      * is the same.
2624      * We also use non-standard composites for Swing native L&F fonts on
2625      * Windows. In that case the policy is that the metrics reported are
2626      * based solely on the physical font in the first slot which is the
2627      * visible java.awt.Font. So in that case the metrics cache which tests
2628      * the Font does what we want. In the near future when we expand the GTK
2629      * logical font definitions we may need to revisit this if GTK reports
2630      * combined metrics instead. For now though this test can be simple.
2631      */
2632     public boolean usingAlternateCompositeFonts() {
2633         return _usingAlternateComposites;
2634     }
2635 
2636     /* Modifies the behaviour of a subsequent call to preferLocaleFonts()
2637      * to use Mincho instead of Gothic for dialoginput in JA locales
2638      * on windows. Not needed on other platforms.
2639      */
2640     public synchronized void useAlternateFontforJALocales() {
2641         if (FontUtilities.isLogging()) {
2642             FontUtilities.getLogger()
2643                 .info("Entered useAlternateFontforJALocales().");
2644         }

2645         if (!FontUtilities.isWindows) {
2646             return;
2647         }
2648         gAltJAFont = true;
2649     }
2650 
2651     public boolean usingAlternateFontforJALocales() {
2652         return gAltJAFont;
2653     }
2654 
2655     public synchronized void preferLocaleFonts() {
2656         if (FontUtilities.isLogging()) {
2657             FontUtilities.getLogger().info("Entered preferLocaleFonts().");
2658         }

2659         /* Test if re-ordering will have any effect */
2660         if (!FontConfiguration.willReorderForStartupLocale()) {
2661             return;
2662         }
2663         if (gLocalePref == true) {
2664             return;
2665         }
2666         gLocalePref = true;
2667         createCompositeFonts(fontNameCache, gLocalePref, gPropPref);
2668         _usingAlternateComposites = true;
2669     }
2670 
2671     public synchronized void preferProportionalFonts() {
2672         if (FontUtilities.isLogging()) {
2673             FontUtilities.getLogger()
2674                 .info("Entered preferProportionalFonts().");
2675         }

2676         /* If no proportional fonts are configured, there's no need
2677          * to take any action.
2678          */
2679         if (!FontConfiguration.hasMonoToPropMap()) {
2680             return;
2681         }
2682         if (gPropPref == true) {
2683             return;
2684         }
2685         gPropPref = true;
2686         createCompositeFonts(fontNameCache, gLocalePref, gPropPref);
2687         _usingAlternateComposites = true;
2688     }
2689 
2690     private static HashSet<String> installedNames = null;
2691     private static HashSet<String> getInstalledNames() {
2692         if (installedNames == null) {
2693            Locale l = getSystemStartupLocale();
2694            SunFontManager fontManager = SunFontManager.getInstance();
2695            String[] installedFamilies =


2895         for (int i=0; i < ls.length; i++ ) {
2896             File theFile = new File(dirFile, ls[i]);
2897             String fullName = null;
2898             if (resolveSymLinks) {
2899                 try {
2900                     fullName = theFile.getCanonicalPath();
2901                 } catch (IOException e) {
2902                 }
2903             }
2904             if (fullName == null) {
2905                 fullName = dirName + File.separator + ls[i];
2906             }
2907 
2908             // REMIND: case compare depends on platform
2909             if (registeredFontFiles.contains(fullName)) {
2910                 continue;
2911             }
2912 
2913             if (badFonts != null && badFonts.contains(fullName)) {
2914                 if (FontUtilities.debugFonts()) {
2915                     FontUtilities.getLogger()
2916                                          .warning("skip bad font " + fullName);
2917                 }
2918                 continue; // skip this font file.
2919             }
2920 
2921             registeredFontFiles.add(fullName);
2922 
2923             if (FontUtilities.debugFonts()
2924                 && FontUtilities.getLogger().isLoggable(PlatformLogger.Level.INFO)) {
2925                 String message = "Registering font " + fullName;
2926                 String[] natNames = getNativeNames(fullName, null);
2927                 if (natNames == null) {
2928                     message += " with no native name";
2929                 } else {
2930                     message += " with native name(s) " + natNames[0];
2931                     for (int nn = 1; nn < natNames.length; nn++) {
2932                         message += ", " + natNames[nn];
2933                     }
2934                 }
2935                 FontUtilities.getLogger().info(message);
2936             }
2937             fontNames[fontCount] = fullName;
2938             nativeNames[fontCount++] = getNativeNames(fullName, null);
2939         }
2940         registerFonts(fontNames, nativeNames, fontCount, fontFormat,
2941                          useJavaRasterizer, fontRank, defer);
2942         return;
2943     }
2944 
2945     protected String[] getNativeNames(String fontFileName,
2946                                       String platformName) {
2947         return null;
2948     }
2949 
2950     /**
2951      * Returns a file name for the physical font represented by this platform
2952      * font name. The default implementation tries to obtain the file name
2953      * from the font configuration.
2954      * Subclasses may override to provide information from other sources.
2955      */


2965     }
2966 
2967     /* A call to this method should be followed by a call to
2968      * registerFontDirs(..)
2969      */
2970     public String getPlatformFontPath(boolean noType1Font) {
2971         if (fontPath == null) {
2972             fontPath = getFontPath(noType1Font);
2973         }
2974         return fontPath;
2975     }
2976 
2977     protected void loadFonts() {
2978         if (discoveredAllFonts) {
2979             return;
2980         }
2981         /* Use lock specific to the font system */
2982         synchronized (this) {
2983             if (FontUtilities.debugFonts()) {
2984                 Thread.dumpStack();
2985                 FontUtilities.getLogger()
2986                             .info("SunGraphicsEnvironment.loadFonts() called");
2987             }
2988             initialiseDeferredFonts();
2989 
2990             AccessController.doPrivileged(new PrivilegedAction<Void>() {
2991                 public Void run() {
2992                     if (fontPath == null) {
2993                         fontPath = getPlatformFontPath(noType1Font);
2994                         registerFontDirs(fontPath);
2995                     }
2996                     if (fontPath != null) {
2997                         // this will find all fonts including those already
2998                         // registered. But we have checks in place to prevent
2999                         // double registration.
3000                         if (! gotFontsFromPlatform()) {
3001                             registerFontsOnPath(fontPath, false,
3002                                                 Font2D.UNKNOWN_RANK,
3003                                                 false, true);
3004                             loadedAllFontFiles = true;
3005                         }
3006                     }


3084                             boolean preferPropFonts);
3085 
3086     /**
3087      * Returns face name for default font, or null if
3088      * no face names are used for CompositeFontDescriptors
3089      * for this platform.
3090      */
3091     public synchronized String getDefaultFontFaceName() {
3092         return defaultFontName;
3093     }
3094 
3095     public void loadFontFiles() {
3096         loadFonts();
3097         if (loadedAllFontFiles) {
3098             return;
3099         }
3100         /* Use lock specific to the font system */
3101         synchronized (this) {
3102             if (FontUtilities.debugFonts()) {
3103                 Thread.dumpStack();
3104                 FontUtilities.getLogger().info("loadAllFontFiles() called");
3105             }
3106             AccessController.doPrivileged(new PrivilegedAction<Void>() {
3107                 public Void run() {
3108                     if (fontPath == null) {
3109                         fontPath = getPlatformFontPath(noType1Font);
3110                     }
3111                     if (fontPath != null) {
3112                         // this will find all fonts including those already
3113                         // registered. But we have checks in place to prevent
3114                         // double registration.
3115                         registerFontsOnPath(fontPath, false,
3116                                             Font2D.UNKNOWN_RANK,
3117                                             false, true);
3118                     }
3119                     loadedAllFontFiles = true;
3120                     return null;
3121                 }
3122             });
3123         }
3124     }
3125 
3126     /*
3127      * This method asks the font configuration API for all platform names
3128      * used as components of composite/logical fonts and iterates over these
3129      * looking up their corresponding file name and registers these fonts.
3130      * It also ensures that the fonts are accessible via platform APIs.
3131      * The composites themselves are then registered.
3132      */
3133     private void
3134         initCompositeFonts(FontConfiguration fontConfig,
3135                            ConcurrentHashMap<String, Font2D>  altNameCache) {
3136 
3137         if (FontUtilities.isLogging()) {
3138             FontUtilities.getLogger()
3139                             .info("Initialising composite fonts");
3140         }
3141 
3142         int numCoreFonts = fontConfig.getNumberCoreFonts();
3143         String[] fcFonts = fontConfig.getPlatformFontNames();
3144         for (int f=0; f<fcFonts.length; f++) {
3145             String platformFontName = fcFonts[f];
3146             String fontFileName =
3147                 getFileNameFromPlatformName(platformFontName);
3148             String[] nativeNames = null;
3149             if (fontFileName == null
3150                 || fontFileName.equals(platformFontName)) {
3151                 /* No file located, so register using the platform name,
3152                  * i.e. as a native font.
3153                  */
3154                 fontFileName = platformFontName;
3155             } else {
3156                 if (f < numCoreFonts) {
3157                     /* If platform APIs also need to access the font, add it
3158                      * to a set to be registered with the platform too.
3159                      * This may be used to add the parent directory to the X11


3219              * fall back component fonts to the composite.
3220              */
3221             if (altNameCache != null) {
3222                 SunFontManager.registerCompositeFont(
3223                     descriptor.getFaceName(),
3224                     componentFileNames, componentFaceNames,
3225                     descriptor.getCoreComponentCount(),
3226                     descriptor.getExclusionRanges(),
3227                     descriptor.getExclusionRangeLimits(),
3228                     true,
3229                     altNameCache);
3230             } else {
3231                 registerCompositeFont(descriptor.getFaceName(),
3232                                       componentFileNames, componentFaceNames,
3233                                       descriptor.getCoreComponentCount(),
3234                                       descriptor.getExclusionRanges(),
3235                                       descriptor.getExclusionRangeLimits(),
3236                                       true);
3237             }
3238             if (FontUtilities.debugFonts()) {
3239                 FontUtilities.getLogger()
3240                                .info("registered " + descriptor.getFaceName());
3241             }
3242         }
3243     }
3244 
3245     /**
3246      * Notifies graphics environment that the logical font configuration
3247      * uses the given platform font name. The graphics environment may
3248      * use this for platform specific initialization.
3249      */
3250     protected void addFontToPlatformFontPath(String platformFontName) {
3251     }
3252 
3253     protected void registerFontFile(String fontFileName, String[] nativeNames,
3254                                     int fontRank, boolean defer) {
3255 //      REMIND: case compare depends on platform
3256         if (registeredFontFiles.contains(fontFileName)) {
3257             return;
3258         }
3259         int fontFormat;
3260         if (ttFilter.accept(null, fontFileName)) {




 303     }
 304 
 305     /* Initialise ptrs used by JNI methods */
 306     private static native void initIDs();
 307 
 308     protected SunFontManager() {
 309         AccessController.doPrivileged(new PrivilegedAction<Void>() {
 310             public Void run() {
 311                 File badFontFile =
 312                     new File(jreFontDirName + File.separator + "badfonts.txt");
 313                 if (badFontFile.exists()) {
 314                     badFonts = new ArrayList<>();
 315                     try (FileInputStream fis = new FileInputStream(badFontFile);
 316                          BufferedReader br = new BufferedReader(new InputStreamReader(fis))) {
 317                         while (true) {
 318                             String name = br.readLine();
 319                             if (name == null) {
 320                                 break;
 321                             } else {
 322                                 if (FontUtilities.debugFonts()) {
 323                                     FontUtilities.logWarning("read bad font: " + name);
 324                                 }
 325                                 badFonts.add(name);
 326                             }
 327                         }
 328                     } catch (IOException e) {
 329                     }
 330                 }
 331 
 332                 /* Here we get the fonts in jre/lib/fonts and register
 333                  * them so they are always available and preferred over
 334                  * other fonts. This needs to be registered before the
 335                  * composite fonts as otherwise some native font that
 336                  * corresponds may be found as we don't have a way to
 337                  * handle two fonts of the same name, so the JRE one
 338                  * must be the first one registered. Pass "true" to
 339                  * registerFonts method as on-screen these JRE fonts
 340                  * always go through the JDK rasteriser.
 341                  */
 342                 if (FontUtilities.isLinux) {
 343                     /* Linux font configuration uses these fonts */
 344                     registerFontDir(jreFontDirName);
 345                 }
 346                 registerFontsInDir(jreFontDirName, true, Font2D.JRE_RANK,
 347                                    true, false);
 348 
 349                 /* Create the font configuration and get any font path
 350                  * that might be specified.
 351                  */
 352                 fontConfig = createFontConfiguration();
 353 
 354                 String[] fontInfo = getDefaultPlatformFont();
 355                 defaultFontName = fontInfo[0];
 356                 if (defaultFontName == null && FontUtilities.debugFonts()) {
 357                     FontUtilities.logWarning("defaultFontName is null");
 358                 }
 359                 defaultFontFileName = fontInfo[1];
 360 
 361                 String extraFontPath = fontConfig.getExtraFontPath();
 362 
 363                 /* In prior releases the debugging font path replaced
 364                  * all normally located font directories except for the
 365                  * JRE fonts dir. This directory is still always located
 366                  * and placed at the head of the path but as an
 367                  * augmentation to the previous behaviour the
 368                  * changes below allow you to additionally append to
 369                  * the font path by starting with append: or prepend by
 370                  * starting with a prepend: sign. Eg: to append
 371                  * -Dsun.java2d.fontpath=append:/usr/local/myfonts
 372                  * and to prepend
 373                  * -Dsun.java2d.fontpath=prepend:/usr/local/myfonts Disp
 374                  *
 375                  * If there is an appendedfontpath it in the font
 376                  * configuration it is used instead of searching the
 377                  * system for dirs.


 386                  * locale-specific so its almost impossible to get
 387                  * right, so it should be used with caution.
 388                  */
 389                 boolean prependToPath = false;
 390                 boolean appendToPath = false;
 391                 String dbgFontPath = System.getProperty("sun.java2d.fontpath");
 392 
 393                 if (dbgFontPath != null) {
 394                     if (dbgFontPath.startsWith("prepend:")) {
 395                         prependToPath = true;
 396                         dbgFontPath =
 397                             dbgFontPath.substring("prepend:".length());
 398                     } else if (dbgFontPath.startsWith("append:")) {
 399                         appendToPath = true;
 400                         dbgFontPath =
 401                             dbgFontPath.substring("append:".length());
 402                     }
 403                 }
 404 
 405                 if (FontUtilities.debugFonts()) {
 406                     FontUtilities.logInfo("JRE font directory: " + jreFontDirName);
 407                     FontUtilities.logInfo("Extra font path: " + extraFontPath);
 408                     FontUtilities.logInfo("Debug font path: " + dbgFontPath);

 409                 }
 410 
 411                 if (dbgFontPath != null) {
 412                     /* In debugging mode we register all the paths
 413                      * Caution: this is a very expensive call on Solaris:-
 414                      */
 415                     fontPath = getPlatformFontPath(noType1Font);
 416 
 417                     if (extraFontPath != null) {
 418                         fontPath = extraFontPath + File.pathSeparator + fontPath;
 419                     }
 420                     if (appendToPath) {
 421                         fontPath += File.pathSeparator + dbgFontPath;
 422                     } else if (prependToPath) {
 423                         fontPath = dbgFontPath + File.pathSeparator + fontPath;
 424                     } else {
 425                         fontPath = dbgFontPath;
 426                     }
 427                     registerFontDirs(fontPath);
 428                 } else if (extraFontPath != null) {


 544          * its handle point to this new font.
 545          * This ensures that when the altNameCache that is passed in
 546          * is the global mapNameCache - ie we are running as an application -
 547          * that any statically created java.awt.Font instances which already
 548          * have a Font2D instance will have that re-directed to the new Font
 549          * on subsequent uses. This is particularly important for "the"
 550          * default font instance, or similar cases where a UI toolkit (eg
 551          * Swing) has cached a java.awt.Font. Note that if Swing is using
 552          * a custom composite APIs which update the standard composites have
 553          * no effect - this is typically the case only when using the Windows
 554          * L&F where these APIs would conflict with that L&F anyway.
 555          */
 556         Font2D oldFont =altNameCache.get(compositeName.toLowerCase(Locale.ENGLISH));
 557         if (oldFont instanceof CompositeFont) {
 558             oldFont.handle.font2D = cf;
 559         }
 560         altNameCache.put(compositeName.toLowerCase(Locale.ENGLISH), cf);
 561     }
 562 
 563     private void addCompositeToFontList(CompositeFont f, int rank) {

 564         if (FontUtilities.isLogging()) {
 565             FontUtilities.logInfo("Add to Family " + f.familyName +
 566                         ", Font " + f.fullName + " rank=" + rank);
 567         }
 568         f.setRank(rank);
 569         compositeFonts.put(f.fullName, f);
 570         fullNameToFont.put(f.fullName.toLowerCase(Locale.ENGLISH), f);
 571 
 572         FontFamily family = FontFamily.getFamily(f.familyName);
 573         if (family == null) {
 574             family = new FontFamily(f.familyName, true, rank);
 575         }
 576         family.setFont(f, f.style);
 577     }
 578 
 579     /*
 580      * Systems may have fonts with the same name.
 581      * We want to register only one of such fonts (at least until
 582      * such time as there might be APIs which can accommodate > 1).
 583      * Rank is 1) font configuration fonts, 2) JRE fonts, 3) OT/TT fonts,
 584      * 4) Type1 fonts, 5) native fonts.
 585      *
 586      * If the new font has the same name as the old font, the higher


 606      * and you should use that one.
 607      * If it returns null means this font was not registered and none
 608      * in that name is registered. The caller must find a substitute
 609      */
 610     // MACOSX begin -- need to access this in subclass
 611     protected PhysicalFont addToFontList(PhysicalFont f, int rank) {
 612     // MACOSX end
 613 
 614         String fontName = f.fullName;
 615         String familyName = f.familyName;
 616         if (fontName == null || fontName.isEmpty()) {
 617             return null;
 618         }
 619         if (compositeFonts.containsKey(fontName)) {
 620             /* Don't register any font that has the same name as a composite */
 621             return null;
 622         }
 623         f.setRank(rank);
 624         if (!physicalFonts.containsKey(fontName)) {
 625             if (FontUtilities.isLogging()) {
 626                 FontUtilities.logInfo("Add to Family " + familyName +
 627                             ", Font " + fontName + " rank=" + rank);
 628             }
 629             physicalFonts.put(fontName, f);
 630             FontFamily family = FontFamily.getFamily(familyName);
 631             if (family == null) {
 632                 family = new FontFamily(familyName, false, rank);
 633                 family.setFont(f, f.style);
 634             } else {
 635                 family.setFont(f, f.style);
 636             }
 637             fullNameToFont.put(fontName.toLowerCase(Locale.ENGLISH), f);
 638             return f;
 639         } else {
 640             PhysicalFont newFont = f;
 641             PhysicalFont oldFont = physicalFonts.get(fontName);
 642             if (oldFont == null) {
 643                 return null;
 644             }
 645             /* If the new font is of an equal or higher rank, it is a
 646              * candidate to replace the current one, subject to further tests.
 647              */


 680                         TrueTypeFont oldTTFont = (TrueTypeFont)oldFont;
 681                         TrueTypeFont newTTFont = (TrueTypeFont)newFont;
 682                         if (oldTTFont.fileSize >= newTTFont.fileSize) {
 683                             return oldFont;
 684                         }
 685                     } else {
 686                         return oldFont;
 687                     }
 688                 }
 689                 /* Don't replace ever JRE fonts.
 690                  * This test is in case a font configuration references
 691                  * a Lucida font, which has been mapped to a Lucida
 692                  * from the host O/S. The assumption here is that any
 693                  * such font configuration file is probably incorrect, or
 694                  * the host O/S version is for the use of AWT.
 695                  * In other words if we reach here, there's a possible
 696                  * problem with our choice of font configuration fonts.
 697                  */
 698                 if (oldFont.platName.startsWith(jreFontDirName)) {
 699                     if (FontUtilities.isLogging()) {
 700                         FontUtilities.logWarning("Unexpected attempt to replace a JRE " +
 701                                        " font " + fontName + " from " + oldFont.platName +


 702                                        " with " + newFont.platName);
 703                     }
 704                     return oldFont;
 705                 }
 706 
 707                 if (FontUtilities.isLogging()) {
 708                     FontUtilities.logInfo("Replace in Family " + familyName +

 709                                     ",Font " + fontName + " new rank="+rank +
 710                                     " from " + oldFont.platName +
 711                                     " with " + newFont.platName);
 712                 }
 713                 replaceFont(oldFont, newFont);
 714                 physicalFonts.put(fontName, newFont);
 715                 fullNameToFont.put(fontName.toLowerCase(Locale.ENGLISH),
 716                                    newFont);
 717 
 718                 FontFamily family = FontFamily.getFamily(familyName);
 719                 if (family == null) {
 720                     family = new FontFamily(familyName, false, rank);
 721                     family.setFont(newFont, newFont.style);
 722                 } else {
 723                     family.setFont(newFont, newFont.style);
 724                 }
 725                 return newFont;
 726             } else {
 727                 return oldFont;
 728             }


 881     public void registerDeferredFont(String fileNameKey,
 882                                      String fullPathName,
 883                                      String[] nativeNames,
 884                                      int fontFormat,
 885                                      boolean useJavaRasterizer,
 886                                      int fontRank) {
 887         FontRegistrationInfo regInfo =
 888             new FontRegistrationInfo(fullPathName, nativeNames, fontFormat,
 889                                      useJavaRasterizer, fontRank);
 890         deferredFontFiles.put(fileNameKey, regInfo);
 891     }
 892 
 893 
 894     public synchronized
 895          PhysicalFont initialiseDeferredFont(String fileNameKey) {
 896 
 897         if (fileNameKey == null) {
 898             return null;
 899         }
 900         if (FontUtilities.isLogging()) {
 901             FontUtilities.logInfo("Opening deferred font file " + fileNameKey);

 902         }
 903 
 904         PhysicalFont physicalFont = null;
 905         FontRegistrationInfo regInfo = deferredFontFiles.get(fileNameKey);
 906         if (regInfo != null) {
 907             deferredFontFiles.remove(fileNameKey);
 908             physicalFont = registerFontFile(regInfo.fontFilePath,
 909                                             regInfo.nativeNames,
 910                                             regInfo.fontFormat,
 911                                             regInfo.javaRasterizer,
 912                                             regInfo.fontRank);
 913 
 914             if (physicalFont != null) {
 915                 /* Store the handle, so that if a font is bad, we
 916                  * retrieve the substituted font.
 917                  */
 918                 initialisedFonts.put(fileNameKey, physicalFont.handle);
 919             } else {
 920                 initialisedFonts.put(fileNameKey, FONT_HANDLE_NULL);
 921             }


 968                     if (physicalFont == null) {
 969                         physicalFont = pf;
 970                     }
 971                 }
 972                 while (fn < ttf.getFontCount());
 973                 break;
 974 
 975             case FONTFORMAT_TYPE1:
 976                 Type1Font t1f = new Type1Font(fileName, nativeNames);
 977                 physicalFont = addToFontList(t1f, fontRank);
 978                 break;
 979 
 980             case FONTFORMAT_NATIVE:
 981                 NativeFont nf = new NativeFont(fileName, false);
 982                 physicalFont = addToFontList(nf, fontRank);
 983                 break;
 984             default:
 985 
 986             }
 987             if (FontUtilities.isLogging()) {
 988                 FontUtilities.logInfo("Registered file " + fileName + " as font " +

 989                                 physicalFont + " rank="  + fontRank);
 990             }
 991         } catch (FontFormatException ffe) {
 992             if (FontUtilities.isLogging()) {
 993                 FontUtilities.logInfo("Unusable font: " + fileName + " " + ffe.toString());

 994             }
 995         }
 996         if (physicalFont != null &&
 997             fontFormat != FONTFORMAT_NATIVE) {
 998             registeredFonts.put(fileName, physicalFont);
 999         }
1000         return physicalFont;
1001     }
1002 
1003     public void registerFonts(String[] fileNames,
1004                               String[][] nativeNames,
1005                               int fontCount,
1006                               int fontFormat,
1007                               boolean useJavaRasterizer,
1008                               int fontRank, boolean defer) {
1009 
1010         for (int i=0; i < fontCount; i++) {
1011             if (defer) {
1012                 registerDeferredFont(fileNames[i],fileNames[i], nativeNames[i],
1013                                      fontFormat, useJavaRasterizer, fontRank);


1017             }
1018         }
1019     }
1020 
1021     /*
1022      * This is the Physical font used when some other font on the system
1023      * can't be located. There has to be at least one font or the font
1024      * system is not useful and the graphics environment cannot sustain
1025      * the Java platform.
1026      */
1027     public PhysicalFont getDefaultPhysicalFont() {
1028         if (defaultPhysicalFont == null) {
1029             String defaultFontName = getDefaultFontFaceName();
1030             // findFont2D will load all fonts
1031             Font2D font2d = findFont2D(defaultFontName, Font.PLAIN, NO_FALLBACK);
1032             if (font2d != null) {
1033                 if (font2d instanceof PhysicalFont) {
1034                     defaultPhysicalFont = (PhysicalFont)font2d;
1035                 } else {
1036                     if (FontUtilities.isLogging()) {
1037                         FontUtilities.logWarning("Font returned by findFont2D for default font name " +

1038                                      defaultFontName + " is not a physical font: " + font2d.getFontName(null));
1039                     }
1040                 }
1041             }
1042             if (defaultPhysicalFont == null) {
1043                 /* Because of the findFont2D call above, if we reach here, we
1044                  * know all fonts have already been loaded, just accept any
1045                  * match at this point. If this fails we are in real trouble
1046                  * and I don't know how to recover from there being absolutely
1047                  * no fonts anywhere on the system.
1048                  */
1049                 defaultPhysicalFont = physicalFonts.values().stream().findFirst()
1050                     .orElseThrow(()->new Error("Probable fatal error: No physical fonts found."));
1051             }
1052         }
1053         return defaultPhysicalFont;
1054     }
1055 
1056     public Font2D getDefaultLogicalFont(int style) {
1057         return findFont2D("dialog", style, NO_FALLBACK);


1278             }
1279 
1280             /* remove from the set of names that will be returned to the
1281              * user any fonts that can't be mapped to files.
1282              */
1283             if (unmappedFontNames.size() > 0) {
1284                 int sz = unmappedFontNames.size();
1285                 for (int i=0; i<sz; i++) {
1286                     String name = unmappedFontNames.get(i);
1287                     String familyName = fontToFamilyNameMap.get(name);
1288                     if (familyName != null) {
1289                         ArrayList<String> family = familyToFontListMap.get(familyName);
1290                         if (family != null) {
1291                             if (family.size() <= 1) {
1292                                 familyToFontListMap.remove(familyName);
1293                             }
1294                         }
1295                     }
1296                     fontToFamilyNameMap.remove(name);
1297                     if (FontUtilities.isLogging()) {
1298                         FontUtilities.logInfo("No file for font:" + name);

1299                     }
1300                 }
1301             }
1302         }
1303     }
1304 
1305     /**
1306      * In some cases windows may have fonts in the fonts folder that
1307      * don't show up in the registry or in the GDI calls to enumerate fonts.
1308      * The only way to find these is to list the directory. We invoke this
1309      * only in getAllFonts/Families, so most searches for a specific
1310      * font that is satisfied by the GDI/registry calls don't take the
1311      * additional hit of listing the directory. This hit is small enough
1312      * that its not significant in these 'enumerate all the fonts' cases.
1313      * The basic approach is to cross-reference the files windows found
1314      * with the ones in the directory listing approach, and for each
1315      * in the latter list that is missing from the former list, register it.
1316      */
1317     private synchronized void checkForUnreferencedFontFiles() {
1318         if (haveCheckedUnreferencedFontFiles) {


1328          */
1329         ArrayList<String> registryFiles = new ArrayList<>();
1330         for (String regFile : fontToFileMap.values()) {
1331             registryFiles.add(regFile.toLowerCase());
1332         }
1333 
1334         /* To avoid any issues with concurrent modification, create
1335          * copies of the existing maps, add the new fonts into these
1336          * and then replace the references to the old ones with the
1337          * new maps. ConcurrentHashmap is another option but its a lot
1338          * more changes and with this exception, these maps are intended
1339          * to be static.
1340          */
1341         HashMap<String,String> fontToFileMap2 = null;
1342         HashMap<String,String> fontToFamilyNameMap2 = null;
1343         HashMap<String,ArrayList<String>> familyToFontListMap2 = null;;
1344 
1345         for (String pathFile : getFontFilesFromPath(false)) {
1346             if (!registryFiles.contains(pathFile)) {
1347                 if (FontUtilities.isLogging()) {
1348                     FontUtilities.logInfo("Found non-registry file : " + pathFile);

1349                 }
1350                 PhysicalFont f = registerFontFile(getPathName(pathFile));
1351                 if (f == null) {
1352                     continue;
1353                 }
1354                 if (fontToFileMap2 == null) {
1355                     fontToFileMap2 = new HashMap<>(fontToFileMap);
1356                     fontToFamilyNameMap2 = new HashMap<>(fontToFamilyNameMap);
1357                     familyToFontListMap2 = new HashMap<>(familyToFontListMap);
1358                 }
1359                 String fontName = f.getFontName(null);
1360                 String family = f.getFamilyName(null);
1361                 String familyLC = family.toLowerCase();
1362                 fontToFamilyNameMap2.put(fontName, family);
1363                 fontToFileMap2.put(fontName, pathFile);
1364                 ArrayList<String> fonts = familyToFontListMap2.get(familyLC);
1365                 if (fonts == null) {
1366                     fonts = new ArrayList<>();
1367                 } else {
1368                     fonts = new ArrayList<>(fonts);


1372             }
1373         }
1374         if (fontToFileMap2 != null) {
1375             fontToFileMap = fontToFileMap2;
1376             familyToFontListMap = familyToFontListMap2;
1377             fontToFamilyNameMap = fontToFamilyNameMap2;
1378         }
1379     }
1380 
1381     private void resolveFontFiles(HashSet<String> unmappedFiles,
1382                                   ArrayList<String> unmappedFonts) {
1383 
1384         Locale l = SunToolkit.getStartupLocale();
1385 
1386         for (String file : unmappedFiles) {
1387             try {
1388                 int fn = 0;
1389                 TrueTypeFont ttf;
1390                 String fullPath = getPathName(file);
1391                 if (FontUtilities.isLogging()) {
1392                     FontUtilities.logInfo("Trying to resolve file " + fullPath);

1393                 }
1394                 do {
1395                     ttf = new TrueTypeFont(fullPath, null, fn++, false);
1396                     //  prefer the font's locale name.
1397                     String fontName = ttf.getFontName(l).toLowerCase();
1398                     if (unmappedFonts.contains(fontName)) {
1399                         fontToFileMap.put(fontName, file);
1400                         unmappedFonts.remove(fontName);
1401                         if (FontUtilities.isLogging()) {
1402                             FontUtilities.logInfo("Resolved absent registry entry for " +

1403                                             fontName + " located in " + fullPath);
1404                         }
1405                     }
1406                 }
1407                 while (fn < ttf.getFontCount());
1408             } catch (Exception e) {
1409             }
1410         }
1411     }
1412 
1413     /* Hardwire the English names and expected file names of fonts
1414      * commonly used at start up. Avoiding until later even the small
1415      * cost of calling platform APIs to locate these can help.
1416      * The code that registers these fonts needs to "bail" if any
1417      * of the files do not exist, so it will verify the existence of
1418      * all non-null file names first.
1419      * They are added in to a map with nominally the first
1420      * word in the name of the family as the key. In all the cases
1421      * we are using the family name is a single word, and as is
1422      * more or less required the family name is the initial sequence


1508                 failure = true;
1509             }
1510         }
1511 
1512         if (fd.italicFileName != null) {
1513             italicFile = getPathName(fd.italicFileName);
1514             if (italicFile == null) {
1515                 failure = true;
1516             }
1517         }
1518 
1519         if (fd.boldItalicFileName != null) {
1520             boldItalicFile = getPathName(fd.boldItalicFileName);
1521             if (boldItalicFile == null) {
1522                 failure = true;
1523             }
1524         }
1525 
1526         if (failure) {
1527             if (FontUtilities.isLogging()) {
1528                 FontUtilities.logInfo("Hardcoded file missing looking for " + lcName);

1529             }
1530             platformFontMap.remove(firstWord);
1531             return null;
1532         }
1533 
1534         /* Some of these may be null,as not all styles have to exist */
1535         final String[] files = {
1536             plainFile, boldFile, italicFile, boldItalicFile } ;
1537 
1538         failure = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
1539              public Boolean run() {
1540                  for (int i=0; i<files.length; i++) {
1541                      if (files[i] == null) {
1542                          continue;
1543                      }
1544                      File f = new File(files[i]);
1545                      if (!f.exists()) {
1546                          return Boolean.TRUE;
1547                      }
1548                  }
1549                  return Boolean.FALSE;
1550              }
1551          });
1552 
1553         if (failure) {
1554             if (FontUtilities.isLogging()) {
1555                 FontUtilities.logInfo("Hardcoded file missing looking for " + lcName);

1556             }
1557             platformFontMap.remove(firstWord);
1558             return null;
1559         }
1560 
1561         /* If we reach here we know that we have all the files we
1562          * expect, so all should be fine so long as the contents
1563          * are what we'd expect. Now on to registering the fonts.
1564          * Currently this code only looks for TrueType fonts, so format
1565          * and rank can be specified without looking at the filename.
1566          */
1567         Font2D font = null;
1568         for (int f=0;f<files.length;f++) {
1569             if (files[f] == null) {
1570                 continue;
1571             }
1572             PhysicalFont pf =
1573                 registerFontFile(files[f], null,
1574                                  FONTFORMAT_TRUETYPE, false, Font2D.TTF_RANK);
1575             if (f == styleIndex) {


1802         if (fontList.length == 0) {
1803             return null;
1804         }
1805 
1806         /* first check that for every font in this family we can find
1807          * a font file. The specific reason for doing this is that
1808          * in at least one case on Windows a font has the face name "David"
1809          * but the registry entry is "David Regular". That is the "unique"
1810          * name of the font but in other cases the registry contains the
1811          * "full" name. See the specifications of name ids 3 and 4 in the
1812          * TrueType 'name' table.
1813          * In general this could cause a problem that we fail to register
1814          * if we all members of a family that we may end up mapping to
1815          * the wrong font member: eg return Bold when Plain is needed.
1816          */
1817         for (int f=0;f<fontList.length;f++) {
1818             String fontNameLC = fontList[f].toLowerCase(Locale.ENGLISH);
1819             String fileName = fontToFileMap.get(fontNameLC);
1820             if (fileName == null) {
1821                 if (FontUtilities.isLogging()) {
1822                     FontUtilities.logInfo("Platform lookup : No file for font " +

1823                                     fontList[f] + " in family " +familyName);
1824                 }
1825                 return null;
1826             }
1827         }
1828 
1829         /* Currently this code only looks for TrueType fonts, so format
1830          * and rank can be specified without looking at the filename.
1831          */
1832         PhysicalFont physicalFont = null;
1833         if (fontFile != null) {
1834             physicalFont = registerFontFile(getPathName(fontFile), null,
1835                                             FONTFORMAT_TRUETYPE, false,
1836                                             Font2D.TTF_RANK);
1837         }
1838         /* Register all fonts in this family. */
1839         for (int f=0;f<fontList.length;f++) {
1840             String fontNameLC = fontList[f].toLowerCase(Locale.ENGLISH);
1841             String fileName = fontToFileMap.get(fontNameLC);
1842             if (fontFile != null && fontFile.equals(fileName)) {


1872      * The name could be a family name, or a full name.
1873      * A font may exist with the specified style, or it may
1874      * exist only in some other style. For non-native fonts the scaler
1875      * may be able to emulate the required style.
1876      */
1877     public Font2D findFont2D(String name, int style, int fallback) {
1878         if (name == null) return null;
1879         String lowerCaseName = name.toLowerCase(Locale.ENGLISH);
1880         String mapName = lowerCaseName + dotStyleStr(style);
1881 
1882         /* If preferLocaleFonts() or preferProportionalFonts() has been
1883          * called we may be using an alternate set of composite fonts in this
1884          * app context. The presence of a pre-built name map indicates whether
1885          * this is so, and gives access to the alternate composite for the
1886          * name.
1887          */
1888         Font2D font = fontNameCache.get(mapName);
1889         if (font != null) {
1890             return font;
1891         }

1892         if (FontUtilities.isLogging()) {
1893             FontUtilities.logInfo("Search for font: " + name);
1894         }
1895 
1896         // The check below is just so that the bitmap fonts being set by
1897         // AWT and Swing thru the desktop properties do not trigger the
1898         // the load fonts case. The two bitmap fonts are now mapped to
1899         // appropriate equivalents for serif and sansserif.
1900         // Note that the cost of this comparison is only for the first
1901         // call until the map is filled.
1902         if (FontUtilities.isWindows) {
1903             if (lowerCaseName.equals("ms sans serif")) {
1904                 name = "sansserif";
1905             } else if (lowerCaseName.equals("ms serif")) {
1906                 name = "serif";
1907             }
1908         }
1909 
1910         /* This isn't intended to support a client passing in the
1911          * string default, but if a client passes in null for the name
1912          * the java.awt.Font class internally substitutes this name.
1913          * So we need to recognise it here to prevent a loadFonts


1987                              * that shouldn't be done. ie if we get this
1988                              * far we have probably as close a match as we
1989                              * are going to get. We could load all fonts to
1990                              * see if somehow some parts of the family are
1991                              * loaded but not all of it.
1992                              */
1993                             if (familyFont.canDoStyle(style|font.style)) {
1994                                 fontNameCache.put(mapName, familyFont);
1995                                 return familyFont;
1996                             }
1997                         }
1998                     }
1999                 }
2000             }
2001         }
2002 
2003         if (FontUtilities.isWindows) {
2004 
2005             font = findFontFromPlatformMap(lowerCaseName, style);
2006             if (FontUtilities.isLogging()) {
2007                 FontUtilities.logInfo("findFontFromPlatformMap returned " + font);

2008             }
2009 
2010             if (font != null) {
2011                 fontNameCache.put(mapName, font);
2012                 return font;
2013             }
2014             /* Don't want Windows to return a font from C:\Windows\Fonts
2015              * if someone has installed a font with the same name
2016              * in the JRE.
2017              */
2018             if (deferredFontFiles.size() > 0) {
2019                 font = findJREDeferredFont(lowerCaseName, style);
2020                 if (font != null) {
2021                     fontNameCache.put(mapName, font);
2022                     return font;
2023                 }
2024             }
2025             font = findFontFromPlatform(lowerCaseName, style);
2026             if (font != null) {
2027                 if (FontUtilities.isLogging()) {
2028                     FontUtilities.logInfo("Found font via platform API for request:\"" +

2029                                     name + "\":, style="+style+
2030                                     " found font: " + font);
2031                 }
2032                 fontNameCache.put(mapName, font);
2033                 return font;
2034             }
2035         }
2036 
2037         /* If reach here and no match has been located, then if there are
2038          * uninitialised deferred fonts, load as many of those as needed
2039          * to find the deferred font. If none is found through that
2040          * search continue on.
2041          * There is possibly a minor issue when more than one
2042          * deferred font implements the same font face. Since deferred
2043          * fonts are only those in font configuration files, this is a
2044          * controlled situation, the known case being Solaris euro_fonts
2045          * versions of Arial, Times New Roman, Courier New. However
2046          * the larger font will transparently replace the smaller one
2047          *  - see addToFontList() - when it is needed by the composite font.
2048          */


2081                     if (fontsAreRegistered) {
2082                         fontNameCache.put(mapName, font);
2083                     }
2084                     return font;
2085                 }
2086             }
2087             font = nameTable.get(lowerCaseName);
2088             if (font != null) {
2089                 if (fontsAreRegistered) {
2090                     fontNameCache.put(mapName, font);
2091                 }
2092                 return font;
2093             }
2094         }
2095 
2096         /* If reach here and no match has been located, then if all fonts
2097          * are not yet loaded, do so, and then recurse.
2098          */
2099         if (!loadedAllFonts) {
2100             if (FontUtilities.isLogging()) {
2101                 FontUtilities.logInfo("Load fonts looking for:" + name);

2102             }
2103             loadFonts();
2104             loadedAllFonts = true;
2105             return findFont2D(name, style, fallback);
2106         }
2107 
2108         if (!loadedAllFontFiles) {
2109             if (FontUtilities.isLogging()) {
2110                 FontUtilities.logInfo("Load font files looking for:" + name);

2111             }
2112             loadFontFiles();
2113             loadedAllFontFiles = true;
2114             return findFont2D(name, style, fallback);
2115         }
2116 
2117         /* The primary name is the locale default - ie not US/English but
2118          * whatever is the default in this locale. This is the way it always
2119          * has been but may be surprising to some developers if "Arial Regular"
2120          * were hard-coded in their app and yet "Arial Regular" was not the
2121          * default name. Fortunately for them, as a consequence of the JDK
2122          * supporting returning names and family names for arbitrary locales,
2123          * we also need to support searching all localised names for a match.
2124          * But because this case of the name used to reference a font is not
2125          * the same as the default for this locale is rare, it makes sense to
2126          * search a much shorter list of default locale names and only go to
2127          * a longer list of names in the event that no match was found.
2128          * So add here code which searches localised names too.
2129          * As in 1.4.x this happens only after loading all fonts, which
2130          * is probably the right order.


2148             String compatName =
2149                 getFontConfiguration().getFallbackFamilyName(name, null);
2150             if (compatName != null) {
2151                 font = findFont2D(compatName, style, fallback);
2152                 fontNameCache.put(mapName, font);
2153                 return font;
2154             }
2155         } else if (lowerCaseName.equals("timesroman")) {
2156             font = findFont2D("serif", style, fallback);
2157             fontNameCache.put(mapName, font);
2158             return font;
2159         } else if (lowerCaseName.equals("helvetica")) {
2160             font = findFont2D("sansserif", style, fallback);
2161             fontNameCache.put(mapName, font);
2162             return font;
2163         } else if (lowerCaseName.equals("courier")) {
2164             font = findFont2D("monospaced", style, fallback);
2165             fontNameCache.put(mapName, font);
2166             return font;
2167         }

2168         if (FontUtilities.isLogging()) {
2169             FontUtilities.logInfo("No font found for:" + name);
2170         }
2171 
2172         switch (fallback) {
2173         case PHYSICAL_FALLBACK: return getDefaultPhysicalFont();
2174         case LOGICAL_FALLBACK: return getDefaultLogicalFont(style);
2175         default: return null;
2176         }
2177     }
2178 
2179     /*
2180      * Workaround for apps which are dependent on a font metrics bug
2181      * in JDK 1.1. This is an unsupported win32 private setting.
2182      * Left in for a customer - do not remove.
2183      */
2184     public boolean usePlatformFontMetrics() {
2185         return usePlatformFontMetrics;
2186     }
2187 
2188     public int getNumFonts() {
2189         return physicalFonts.size()+maxCompFont;


2324     }
2325 
2326     /*
2327      * This is called when font is determined to be invalid/bad.
2328      * It designed to be called (for example) by the font scaler
2329      * when in processing a font file it is discovered to be incorrect.
2330      * This is different than the case where fonts are discovered to
2331      * be incorrect during initial verification, as such fonts are
2332      * never registered.
2333      * Handles to this font held are re-directed to a default font.
2334      * This default may not be an ideal substitute buts it better than
2335      * crashing This code assumes a PhysicalFont parameter as it doesn't
2336      * make sense for a Composite to be "bad".
2337      */
2338     public synchronized void deRegisterBadFont(Font2D font2D) {
2339         if (!(font2D instanceof PhysicalFont)) {
2340             /* We should never reach here, but just in case */
2341             return;
2342         } else {
2343             if (FontUtilities.isLogging()) {
2344                 FontUtilities.logSevere("Deregister bad font: " + font2D);

2345             }
2346             replaceFont((PhysicalFont)font2D, getDefaultPhysicalFont());
2347         }
2348     }
2349 
2350     /*
2351      * This encapsulates all the work that needs to be done when a
2352      * Font2D is replaced by a different Font2D.
2353      */
2354     public synchronized void replaceFont(PhysicalFont oldFont,
2355                                          PhysicalFont newFont) {
2356 
2357         if (oldFont.handle.font2D != oldFont) {
2358             /* already done */
2359             return;
2360         }
2361 
2362         /* If we try to replace the font with itself, that won't work,
2363          * so pick any alternative physical font
2364          */
2365         if (oldFont == newFont) {
2366             if (FontUtilities.isLogging()) {
2367                 FontUtilities.logSevere("Can't replace bad font with itself " + oldFont);

2368             }
2369             PhysicalFont[] physFonts = getPhysicalFonts();
2370             for (int i=0; i<physFonts.length;i++) {
2371                 if (physFonts[i] != newFont) {
2372                     newFont = physFonts[i];
2373                     break;
2374                 }
2375             }
2376             if (oldFont == newFont) {
2377                 if (FontUtilities.isLogging()) {
2378                     FontUtilities.logSevere("This is bad. No good physicalFonts found.");

2379                 }
2380                 return;
2381             }
2382         }
2383 
2384         /* eliminate references to this font, so it won't be located
2385          * by future callers, and will be eligible for GC when all
2386          * references are removed
2387          */
2388         oldFont.handle.font2D = newFont;
2389         physicalFonts.remove(oldFont.fullName);
2390         fullNameToFont.remove(oldFont.fullName.toLowerCase(Locale.ENGLISH));
2391         FontFamily.remove(oldFont);
2392         if (localeFullNamesToFont != null) {
2393             Map.Entry<?, ?>[] mapEntries = localeFullNamesToFont.entrySet().
2394                 toArray(new Map.Entry<?, ?>[0]);
2395             /* Should I be replacing these, or just I just remove
2396              * the names from the map?
2397              */
2398             for (int i=0; i<mapEntries.length;i++) {


2459                 String[] fullNames = ttf.getAllFullNames();
2460                 for (int n=0; n<fullNames.length; n++) {
2461                     localeFullNamesToFont.put(fullNames[n], ttf);
2462                 }
2463                 FontFamily family = FontFamily.getFamily(ttf.familyName);
2464                 if (family != null) {
2465                     FontFamily.addLocaleNames(family, ttf.getAllFamilyNames());
2466                 }
2467             }
2468         }
2469     }
2470 
2471     /* This replicate the core logic of findFont2D but operates on
2472      * all the locale names. This hasn't been merged into findFont2D to
2473      * keep the logic simpler and reduce overhead, since this case is
2474      * almost never used. The main case in which it is called is when
2475      * a bogus font name is used and we need to check all possible names
2476      * before returning the default case.
2477      */
2478     private Font2D findFont2DAllLocales(String name, int style) {

2479         if (FontUtilities.isLogging()) {
2480             FontUtilities.logInfo("Searching localised font names for:" + name);

2481         }
2482 
2483         /* If reach here and no match has been located, then if we have
2484          * not yet built the map of localeFullNamesToFont for TT fonts, do so
2485          * now. This method must be called after all fonts have been loaded.
2486          */
2487         if (localeFullNamesToFont == null) {
2488             loadLocaleNames();
2489         }
2490         String lowerCaseName = name.toLowerCase();
2491         Font2D font = null;
2492 
2493         /* First see if its a family name. */
2494         FontFamily family = FontFamily.getLocaleFamily(lowerCaseName);
2495         if (family != null) {
2496           font = family.getFont(style);
2497           if (font == null) {
2498             font = family.getClosestStyle(style);
2499           }
2500           if (font != null) {


2596      * the Font.equals() method since it needs to also check if the Font2D
2597      * is the same.
2598      * We also use non-standard composites for Swing native L&F fonts on
2599      * Windows. In that case the policy is that the metrics reported are
2600      * based solely on the physical font in the first slot which is the
2601      * visible java.awt.Font. So in that case the metrics cache which tests
2602      * the Font does what we want. In the near future when we expand the GTK
2603      * logical font definitions we may need to revisit this if GTK reports
2604      * combined metrics instead. For now though this test can be simple.
2605      */
2606     public boolean usingAlternateCompositeFonts() {
2607         return _usingAlternateComposites;
2608     }
2609 
2610     /* Modifies the behaviour of a subsequent call to preferLocaleFonts()
2611      * to use Mincho instead of Gothic for dialoginput in JA locales
2612      * on windows. Not needed on other platforms.
2613      */
2614     public synchronized void useAlternateFontforJALocales() {
2615         if (FontUtilities.isLogging()) {
2616             FontUtilities.logInfo("Entered useAlternateFontforJALocales().");

2617         }
2618 
2619         if (!FontUtilities.isWindows) {
2620             return;
2621         }
2622         gAltJAFont = true;
2623     }
2624 
2625     public boolean usingAlternateFontforJALocales() {
2626         return gAltJAFont;
2627     }
2628 
2629     public synchronized void preferLocaleFonts() {
2630         if (FontUtilities.isLogging()) {
2631             FontUtilities.logInfo("Entered preferLocaleFonts().");
2632         }
2633 
2634         /* Test if re-ordering will have any effect */
2635         if (!FontConfiguration.willReorderForStartupLocale()) {
2636             return;
2637         }
2638         if (gLocalePref == true) {
2639             return;
2640         }
2641         gLocalePref = true;
2642         createCompositeFonts(fontNameCache, gLocalePref, gPropPref);
2643         _usingAlternateComposites = true;
2644     }
2645 
2646     public synchronized void preferProportionalFonts() {
2647         if (FontUtilities.isLogging()) {
2648             FontUtilities.logInfo("Entered preferProportionalFonts().");

2649         }
2650 
2651         /* If no proportional fonts are configured, there's no need
2652          * to take any action.
2653          */
2654         if (!FontConfiguration.hasMonoToPropMap()) {
2655             return;
2656         }
2657         if (gPropPref == true) {
2658             return;
2659         }
2660         gPropPref = true;
2661         createCompositeFonts(fontNameCache, gLocalePref, gPropPref);
2662         _usingAlternateComposites = true;
2663     }
2664 
2665     private static HashSet<String> installedNames = null;
2666     private static HashSet<String> getInstalledNames() {
2667         if (installedNames == null) {
2668            Locale l = getSystemStartupLocale();
2669            SunFontManager fontManager = SunFontManager.getInstance();
2670            String[] installedFamilies =


2870         for (int i=0; i < ls.length; i++ ) {
2871             File theFile = new File(dirFile, ls[i]);
2872             String fullName = null;
2873             if (resolveSymLinks) {
2874                 try {
2875                     fullName = theFile.getCanonicalPath();
2876                 } catch (IOException e) {
2877                 }
2878             }
2879             if (fullName == null) {
2880                 fullName = dirName + File.separator + ls[i];
2881             }
2882 
2883             // REMIND: case compare depends on platform
2884             if (registeredFontFiles.contains(fullName)) {
2885                 continue;
2886             }
2887 
2888             if (badFonts != null && badFonts.contains(fullName)) {
2889                 if (FontUtilities.debugFonts()) {
2890                     FontUtilities.logWarning("skip bad font " + fullName);

2891                 }
2892                 continue; // skip this font file.
2893             }
2894 
2895             registeredFontFiles.add(fullName);
2896 
2897             if (FontUtilities.debugFonts()
2898                 && FontUtilities.getLogger().isLoggable(PlatformLogger.Level.INFO)) {
2899                 String message = "Registering font " + fullName;
2900                 String[] natNames = getNativeNames(fullName, null);
2901                 if (natNames == null) {
2902                     message += " with no native name";
2903                 } else {
2904                     message += " with native name(s) " + natNames[0];
2905                     for (int nn = 1; nn < natNames.length; nn++) {
2906                         message += ", " + natNames[nn];
2907                     }
2908                 }
2909                 FontUtilities.logInfo(message);
2910             }
2911             fontNames[fontCount] = fullName;
2912             nativeNames[fontCount++] = getNativeNames(fullName, null);
2913         }
2914         registerFonts(fontNames, nativeNames, fontCount, fontFormat,
2915                          useJavaRasterizer, fontRank, defer);
2916         return;
2917     }
2918 
2919     protected String[] getNativeNames(String fontFileName,
2920                                       String platformName) {
2921         return null;
2922     }
2923 
2924     /**
2925      * Returns a file name for the physical font represented by this platform
2926      * font name. The default implementation tries to obtain the file name
2927      * from the font configuration.
2928      * Subclasses may override to provide information from other sources.
2929      */


2939     }
2940 
2941     /* A call to this method should be followed by a call to
2942      * registerFontDirs(..)
2943      */
2944     public String getPlatformFontPath(boolean noType1Font) {
2945         if (fontPath == null) {
2946             fontPath = getFontPath(noType1Font);
2947         }
2948         return fontPath;
2949     }
2950 
2951     protected void loadFonts() {
2952         if (discoveredAllFonts) {
2953             return;
2954         }
2955         /* Use lock specific to the font system */
2956         synchronized (this) {
2957             if (FontUtilities.debugFonts()) {
2958                 Thread.dumpStack();
2959                 FontUtilities.logInfo("SunGraphicsEnvironment.loadFonts() called");

2960             }
2961             initialiseDeferredFonts();
2962 
2963             AccessController.doPrivileged(new PrivilegedAction<Void>() {
2964                 public Void run() {
2965                     if (fontPath == null) {
2966                         fontPath = getPlatformFontPath(noType1Font);
2967                         registerFontDirs(fontPath);
2968                     }
2969                     if (fontPath != null) {
2970                         // this will find all fonts including those already
2971                         // registered. But we have checks in place to prevent
2972                         // double registration.
2973                         if (! gotFontsFromPlatform()) {
2974                             registerFontsOnPath(fontPath, false,
2975                                                 Font2D.UNKNOWN_RANK,
2976                                                 false, true);
2977                             loadedAllFontFiles = true;
2978                         }
2979                     }


3057                             boolean preferPropFonts);
3058 
3059     /**
3060      * Returns face name for default font, or null if
3061      * no face names are used for CompositeFontDescriptors
3062      * for this platform.
3063      */
3064     public synchronized String getDefaultFontFaceName() {
3065         return defaultFontName;
3066     }
3067 
3068     public void loadFontFiles() {
3069         loadFonts();
3070         if (loadedAllFontFiles) {
3071             return;
3072         }
3073         /* Use lock specific to the font system */
3074         synchronized (this) {
3075             if (FontUtilities.debugFonts()) {
3076                 Thread.dumpStack();
3077                 FontUtilities.logInfo("loadAllFontFiles() called");
3078             }
3079             AccessController.doPrivileged(new PrivilegedAction<Void>() {
3080                 public Void run() {
3081                     if (fontPath == null) {
3082                         fontPath = getPlatformFontPath(noType1Font);
3083                     }
3084                     if (fontPath != null) {
3085                         // this will find all fonts including those already
3086                         // registered. But we have checks in place to prevent
3087                         // double registration.
3088                         registerFontsOnPath(fontPath, false,
3089                                             Font2D.UNKNOWN_RANK,
3090                                             false, true);
3091                     }
3092                     loadedAllFontFiles = true;
3093                     return null;
3094                 }
3095             });
3096         }
3097     }
3098 
3099     /*
3100      * This method asks the font configuration API for all platform names
3101      * used as components of composite/logical fonts and iterates over these
3102      * looking up their corresponding file name and registers these fonts.
3103      * It also ensures that the fonts are accessible via platform APIs.
3104      * The composites themselves are then registered.
3105      */
3106     private void
3107         initCompositeFonts(FontConfiguration fontConfig,
3108                            ConcurrentHashMap<String, Font2D>  altNameCache) {

3109         if (FontUtilities.isLogging()) {
3110             FontUtilities.logInfo("Initialising composite fonts");

3111         }
3112 
3113         int numCoreFonts = fontConfig.getNumberCoreFonts();
3114         String[] fcFonts = fontConfig.getPlatformFontNames();
3115         for (int f=0; f<fcFonts.length; f++) {
3116             String platformFontName = fcFonts[f];
3117             String fontFileName =
3118                 getFileNameFromPlatformName(platformFontName);
3119             String[] nativeNames = null;
3120             if (fontFileName == null
3121                 || fontFileName.equals(platformFontName)) {
3122                 /* No file located, so register using the platform name,
3123                  * i.e. as a native font.
3124                  */
3125                 fontFileName = platformFontName;
3126             } else {
3127                 if (f < numCoreFonts) {
3128                     /* If platform APIs also need to access the font, add it
3129                      * to a set to be registered with the platform too.
3130                      * This may be used to add the parent directory to the X11


3190              * fall back component fonts to the composite.
3191              */
3192             if (altNameCache != null) {
3193                 SunFontManager.registerCompositeFont(
3194                     descriptor.getFaceName(),
3195                     componentFileNames, componentFaceNames,
3196                     descriptor.getCoreComponentCount(),
3197                     descriptor.getExclusionRanges(),
3198                     descriptor.getExclusionRangeLimits(),
3199                     true,
3200                     altNameCache);
3201             } else {
3202                 registerCompositeFont(descriptor.getFaceName(),
3203                                       componentFileNames, componentFaceNames,
3204                                       descriptor.getCoreComponentCount(),
3205                                       descriptor.getExclusionRanges(),
3206                                       descriptor.getExclusionRangeLimits(),
3207                                       true);
3208             }
3209             if (FontUtilities.debugFonts()) {
3210                 FontUtilities.logInfo("registered " + descriptor.getFaceName());

3211             }
3212         }
3213     }
3214 
3215     /**
3216      * Notifies graphics environment that the logical font configuration
3217      * uses the given platform font name. The graphics environment may
3218      * use this for platform specific initialization.
3219      */
3220     protected void addFontToPlatformFontPath(String platformFontName) {
3221     }
3222 
3223     protected void registerFontFile(String fontFileName, String[] nativeNames,
3224                                     int fontRank, boolean defer) {
3225 //      REMIND: case compare depends on platform
3226         if (registeredFontFiles.contains(fontFileName)) {
3227             return;
3228         }
3229         int fontFormat;
3230         if (ttFilter.accept(null, fontFileName)) {


< prev index next >