< prev index next >

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

Print this page
rev 60042 : 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
 589      * ranked font gets added, replacing the lower ranked one.


 607      * If it returns a different object it means this font already exists,
 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              */
 650             if (oldFont.getRank() >= rank) {


 681                         newFont instanceof TrueTypeFont) {
 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             }
 734         }
 735     }
 736 
 737     public Font2D[] getRegisteredFonts() {


 885 
 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             }
 928         } else {


 973                     PhysicalFont pf = addToFontList(ttf, fontRank);
 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);
1022             } else {


1024                                  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);
1067     }
1068 
1069     /*
1070      * return String representation of style prepended with "."


1286                 resolveFontFiles(unmappedFontFiles, unmappedFontNames);
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) {
1329             return;


1337          * versions of the names from the registry.
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);
1380                 }


1382                 familyToFontListMap2.put(familyLC, 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
1436      * in a full name. So lookup first finds the matching description,
1437      * then registers the whole family, returning the right font.
1438      */
1439     public static class FamilyDescription {


1520             if (boldFile == null) {
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) {
1591                 font = pf;


1816         String [] fontList = family.toArray(STR_ARRAY);
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)) {
1859                 continue;
1860             }


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
1931          * on the unrecognised name. The only potential problem with


2003                             /* The next check is perhaps one
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          */
2067         if (deferredFontFiles.size() > 0) {
2068             font = findDeferredFont(name, style);
2069             if (font != null) {


2098                 if (font != null) {
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.
2151          */


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;
2211     }


2344         return null;
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++) {
2423                 if (mapEntries[i].getValue() == oldFont) {


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) {
2527               return font;


2621      * a case cannot retrieve a cached metrics solely on the basis of
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
3160                      * font path if its not already there. See the docs for the


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         FontUtilities.logInfo("Add to Family "+ f.familyName +


 565                     ", Font " + f.fullName + " rank="+rank);

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


 603      * If it returns a different object it means this font already exists,
 604      * and you should use that one.
 605      * If it returns null means this font was not registered and none
 606      * in that name is registered. The caller must find a substitute
 607      */
 608     // MACOSX begin -- need to access this in subclass
 609     protected PhysicalFont addToFontList(PhysicalFont f, int rank) {
 610     // MACOSX end
 611 
 612         String fontName = f.fullName;
 613         String familyName = f.familyName;
 614         if (fontName == null || fontName.isEmpty()) {
 615             return null;
 616         }
 617         if (compositeFonts.containsKey(fontName)) {
 618             /* Don't register any font that has the same name as a composite */
 619             return null;
 620         }
 621         f.setRank(rank);
 622         if (!physicalFonts.containsKey(fontName)) {
 623             FontUtilities.logInfo("Add to Family "+familyName +

 624                         ", Font " + fontName + " rank="+rank);

 625             physicalFonts.put(fontName, f);
 626             FontFamily family = FontFamily.getFamily(familyName);
 627             if (family == null) {
 628                 family = new FontFamily(familyName, false, rank);
 629                 family.setFont(f, f.style);
 630             } else {
 631                 family.setFont(f, f.style);
 632             }
 633             fullNameToFont.put(fontName.toLowerCase(Locale.ENGLISH), f);
 634             return f;
 635         } else {
 636             PhysicalFont newFont = f;
 637             PhysicalFont oldFont = physicalFonts.get(fontName);
 638             if (oldFont == null) {
 639                 return null;
 640             }
 641             /* If the new font is of an equal or higher rank, it is a
 642              * candidate to replace the current one, subject to further tests.
 643              */
 644             if (oldFont.getRank() >= rank) {


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



 697                                    " with " + newFont.platName);

 698                     return oldFont;
 699                 }
 700 
 701                 FontUtilities.logInfo("Replace in Family " + familyName +


 702                                 ",Font " + fontName + " new rank="+rank +
 703                                 " from " + oldFont.platName +
 704                                 " with " + newFont.platName);

 705                 replaceFont(oldFont, newFont);
 706                 physicalFonts.put(fontName, newFont);
 707                 fullNameToFont.put(fontName.toLowerCase(Locale.ENGLISH),
 708                                    newFont);
 709 
 710                 FontFamily family = FontFamily.getFamily(familyName);
 711                 if (family == null) {
 712                     family = new FontFamily(familyName, false, rank);
 713                     family.setFont(newFont, newFont.style);
 714                 } else {
 715                     family.setFont(newFont, newFont.style);
 716                 }
 717                 return newFont;
 718             } else {
 719                 return oldFont;
 720             }
 721         }
 722     }
 723 
 724     public Font2D[] getRegisteredFonts() {


 872 
 873     public void registerDeferredFont(String fileNameKey,
 874                                      String fullPathName,
 875                                      String[] nativeNames,
 876                                      int fontFormat,
 877                                      boolean useJavaRasterizer,
 878                                      int fontRank) {
 879         FontRegistrationInfo regInfo =
 880             new FontRegistrationInfo(fullPathName, nativeNames, fontFormat,
 881                                      useJavaRasterizer, fontRank);
 882         deferredFontFiles.put(fileNameKey, regInfo);
 883     }
 884 
 885 
 886     public synchronized
 887          PhysicalFont initialiseDeferredFont(String fileNameKey) {
 888 
 889         if (fileNameKey == null) {
 890             return null;
 891         }
 892         FontUtilities.logInfo("Opening deferred font file " + fileNameKey);



 893 
 894         PhysicalFont physicalFont = null;
 895         FontRegistrationInfo regInfo = deferredFontFiles.get(fileNameKey);
 896         if (regInfo != null) {
 897             deferredFontFiles.remove(fileNameKey);
 898             physicalFont = registerFontFile(regInfo.fontFilePath,
 899                                             regInfo.nativeNames,
 900                                             regInfo.fontFormat,
 901                                             regInfo.javaRasterizer,
 902                                             regInfo.fontRank);
 903 
 904             if (physicalFont != null) {
 905                 /* Store the handle, so that if a font is bad, we
 906                  * retrieve the substituted font.
 907                  */
 908                 initialisedFonts.put(fileNameKey, physicalFont.handle);
 909             } else {
 910                 initialisedFonts.put(fileNameKey, FONT_HANDLE_NULL);
 911             }
 912         } else {


 957                     PhysicalFont pf = addToFontList(ttf, fontRank);
 958                     if (physicalFont == null) {
 959                         physicalFont = pf;
 960                     }
 961                 }
 962                 while (fn < ttf.getFontCount());
 963                 break;
 964 
 965             case FONTFORMAT_TYPE1:
 966                 Type1Font t1f = new Type1Font(fileName, nativeNames);
 967                 physicalFont = addToFontList(t1f, fontRank);
 968                 break;
 969 
 970             case FONTFORMAT_NATIVE:
 971                 NativeFont nf = new NativeFont(fileName, false);
 972                 physicalFont = addToFontList(nf, fontRank);
 973                 break;
 974             default:
 975 
 976             }
 977             FontUtilities.logInfo("Registered file " + fileName + " as font " +


 978                             physicalFont + " rank="  + fontRank);

 979         } catch (FontFormatException ffe) {
 980             FontUtilities.logInfo("Unusable font: " + fileName + " " + ffe.toString());



 981         }
 982         if (physicalFont != null &&
 983             fontFormat != FONTFORMAT_NATIVE) {
 984             registeredFonts.put(fileName, physicalFont);
 985         }
 986         return physicalFont;
 987     }
 988 
 989     public void registerFonts(String[] fileNames,
 990                               String[][] nativeNames,
 991                               int fontCount,
 992                               int fontFormat,
 993                               boolean useJavaRasterizer,
 994                               int fontRank, boolean defer) {
 995 
 996         for (int i=0; i < fontCount; i++) {
 997             if (defer) {
 998                 registerDeferredFont(fileNames[i],fileNames[i], nativeNames[i],
 999                                      fontFormat, useJavaRasterizer, fontRank);
1000             } else {


1002                                  fontFormat, useJavaRasterizer, fontRank);
1003             }
1004         }
1005     }
1006 
1007     /*
1008      * This is the Physical font used when some other font on the system
1009      * can't be located. There has to be at least one font or the font
1010      * system is not useful and the graphics environment cannot sustain
1011      * the Java platform.
1012      */
1013     public PhysicalFont getDefaultPhysicalFont() {
1014         if (defaultPhysicalFont == null) {
1015             String defaultFontName = getDefaultFontFaceName();
1016             // findFont2D will load all fonts
1017             Font2D font2d = findFont2D(defaultFontName, Font.PLAIN, NO_FALLBACK);
1018             if (font2d != null) {
1019                 if (font2d instanceof PhysicalFont) {
1020                     defaultPhysicalFont = (PhysicalFont)font2d;
1021                 } else {
1022                     FontUtilities.logWarning("Font returned by findFont2D for default font name " +


1023                                      defaultFontName + " is not a physical font: " + font2d.getFontName(null));
1024                 }
1025             }

1026             if (defaultPhysicalFont == null) {
1027                 /* Because of the findFont2D call above, if we reach here, we
1028                  * know all fonts have already been loaded, just accept any
1029                  * match at this point. If this fails we are in real trouble
1030                  * and I don't know how to recover from there being absolutely
1031                  * no fonts anywhere on the system.
1032                  */
1033                 defaultPhysicalFont = physicalFonts.values().stream().findFirst()
1034                     .orElseThrow(()->new Error("Probable fatal error: No physical fonts found."));
1035             }
1036         }
1037         return defaultPhysicalFont;
1038     }
1039 
1040     public Font2D getDefaultLogicalFont(int style) {
1041         return findFont2D("dialog", style, NO_FALLBACK);
1042     }
1043 
1044     /*
1045      * return String representation of style prepended with "."


1261                 resolveFontFiles(unmappedFontFiles, unmappedFontNames);
1262             }
1263 
1264             /* remove from the set of names that will be returned to the
1265              * user any fonts that can't be mapped to files.
1266              */
1267             if (unmappedFontNames.size() > 0) {
1268                 int sz = unmappedFontNames.size();
1269                 for (int i=0; i<sz; i++) {
1270                     String name = unmappedFontNames.get(i);
1271                     String familyName = fontToFamilyNameMap.get(name);
1272                     if (familyName != null) {
1273                         ArrayList<String> family = familyToFontListMap.get(familyName);
1274                         if (family != null) {
1275                             if (family.size() <= 1) {
1276                                 familyToFontListMap.remove(familyName);
1277                             }
1278                         }
1279                     }
1280                     fontToFamilyNameMap.remove(name);
1281                     FontUtilities.logInfo("No file for font:" + name);



1282                 }
1283             }
1284         }
1285     }
1286 
1287     /**
1288      * In some cases windows may have fonts in the fonts folder that
1289      * don't show up in the registry or in the GDI calls to enumerate fonts.
1290      * The only way to find these is to list the directory. We invoke this
1291      * only in getAllFonts/Families, so most searches for a specific
1292      * font that is satisfied by the GDI/registry calls don't take the
1293      * additional hit of listing the directory. This hit is small enough
1294      * that its not significant in these 'enumerate all the fonts' cases.
1295      * The basic approach is to cross-reference the files windows found
1296      * with the ones in the directory listing approach, and for each
1297      * in the latter list that is missing from the former list, register it.
1298      */
1299     private synchronized void checkForUnreferencedFontFiles() {
1300         if (haveCheckedUnreferencedFontFiles) {
1301             return;


1309          * versions of the names from the registry.
1310          */
1311         ArrayList<String> registryFiles = new ArrayList<>();
1312         for (String regFile : fontToFileMap.values()) {
1313             registryFiles.add(regFile.toLowerCase());
1314         }
1315 
1316         /* To avoid any issues with concurrent modification, create
1317          * copies of the existing maps, add the new fonts into these
1318          * and then replace the references to the old ones with the
1319          * new maps. ConcurrentHashmap is another option but its a lot
1320          * more changes and with this exception, these maps are intended
1321          * to be static.
1322          */
1323         HashMap<String,String> fontToFileMap2 = null;
1324         HashMap<String,String> fontToFamilyNameMap2 = null;
1325         HashMap<String,ArrayList<String>> familyToFontListMap2 = null;;
1326 
1327         for (String pathFile : getFontFilesFromPath(false)) {
1328             if (!registryFiles.contains(pathFile)) {
1329                 FontUtilities.logInfo("Found non-registry file : " + pathFile);



1330                 PhysicalFont f = registerFontFile(getPathName(pathFile));
1331                 if (f == null) {
1332                     continue;
1333                 }
1334                 if (fontToFileMap2 == null) {
1335                     fontToFileMap2 = new HashMap<>(fontToFileMap);
1336                     fontToFamilyNameMap2 = new HashMap<>(fontToFamilyNameMap);
1337                     familyToFontListMap2 = new HashMap<>(familyToFontListMap);
1338                 }
1339                 String fontName = f.getFontName(null);
1340                 String family = f.getFamilyName(null);
1341                 String familyLC = family.toLowerCase();
1342                 fontToFamilyNameMap2.put(fontName, family);
1343                 fontToFileMap2.put(fontName, pathFile);
1344                 ArrayList<String> fonts = familyToFontListMap2.get(familyLC);
1345                 if (fonts == null) {
1346                     fonts = new ArrayList<>();
1347                 } else {
1348                     fonts = new ArrayList<>(fonts);
1349                 }


1351                 familyToFontListMap2.put(familyLC, fonts);
1352             }
1353         }
1354         if (fontToFileMap2 != null) {
1355             fontToFileMap = fontToFileMap2;
1356             familyToFontListMap = familyToFontListMap2;
1357             fontToFamilyNameMap = fontToFamilyNameMap2;
1358         }
1359     }
1360 
1361     private void resolveFontFiles(HashSet<String> unmappedFiles,
1362                                   ArrayList<String> unmappedFonts) {
1363 
1364         Locale l = SunToolkit.getStartupLocale();
1365 
1366         for (String file : unmappedFiles) {
1367             try {
1368                 int fn = 0;
1369                 TrueTypeFont ttf;
1370                 String fullPath = getPathName(file);
1371                 FontUtilities.logInfo("Trying to resolve file " + fullPath);



1372                 do {
1373                     ttf = new TrueTypeFont(fullPath, null, fn++, false);
1374                     //  prefer the font's locale name.
1375                     String fontName = ttf.getFontName(l).toLowerCase();
1376                     if (unmappedFonts.contains(fontName)) {
1377                         fontToFileMap.put(fontName, file);
1378                         unmappedFonts.remove(fontName);
1379                         FontUtilities.logInfo("Resolved absent registry entry for " +


1380                                         fontName + " located in " + fullPath);
1381                     }
1382                 }

1383                 while (fn < ttf.getFontCount());
1384             } catch (Exception e) {
1385             }
1386         }
1387     }
1388 
1389     /* Hardwire the English names and expected file names of fonts
1390      * commonly used at start up. Avoiding until later even the small
1391      * cost of calling platform APIs to locate these can help.
1392      * The code that registers these fonts needs to "bail" if any
1393      * of the files do not exist, so it will verify the existence of
1394      * all non-null file names first.
1395      * They are added in to a map with nominally the first
1396      * word in the name of the family as the key. In all the cases
1397      * we are using the family name is a single word, and as is
1398      * more or less required the family name is the initial sequence
1399      * in a full name. So lookup first finds the matching description,
1400      * then registers the whole family, returning the right font.
1401      */
1402     public static class FamilyDescription {


1483             if (boldFile == null) {
1484                 failure = true;
1485             }
1486         }
1487 
1488         if (fd.italicFileName != null) {
1489             italicFile = getPathName(fd.italicFileName);
1490             if (italicFile == null) {
1491                 failure = true;
1492             }
1493         }
1494 
1495         if (fd.boldItalicFileName != null) {
1496             boldItalicFile = getPathName(fd.boldItalicFileName);
1497             if (boldItalicFile == null) {
1498                 failure = true;
1499             }
1500         }
1501 
1502         if (failure) {
1503             FontUtilities.logInfo("Hardcoded file missing looking for " + lcName);



1504             platformFontMap.remove(firstWord);
1505             return null;
1506         }
1507 
1508         /* Some of these may be null,as not all styles have to exist */
1509         final String[] files = {
1510             plainFile, boldFile, italicFile, boldItalicFile } ;
1511 
1512         failure = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
1513              public Boolean run() {
1514                  for (int i=0; i<files.length; i++) {
1515                      if (files[i] == null) {
1516                          continue;
1517                      }
1518                      File f = new File(files[i]);
1519                      if (!f.exists()) {
1520                          return Boolean.TRUE;
1521                      }
1522                  }
1523                  return Boolean.FALSE;
1524              }
1525          });
1526 
1527         if (failure) {
1528             FontUtilities.logInfo("Hardcoded file missing looking for " + lcName);



1529             platformFontMap.remove(firstWord);
1530             return null;
1531         }
1532 
1533         /* If we reach here we know that we have all the files we
1534          * expect, so all should be fine so long as the contents
1535          * are what we'd expect. Now on to registering the fonts.
1536          * Currently this code only looks for TrueType fonts, so format
1537          * and rank can be specified without looking at the filename.
1538          */
1539         Font2D font = null;
1540         for (int f=0;f<files.length;f++) {
1541             if (files[f] == null) {
1542                 continue;
1543             }
1544             PhysicalFont pf =
1545                 registerFontFile(files[f], null,
1546                                  FONTFORMAT_TRUETYPE, false, Font2D.TTF_RANK);
1547             if (f == styleIndex) {
1548                 font = pf;


1773         String [] fontList = family.toArray(STR_ARRAY);
1774         if (fontList.length == 0) {
1775             return null;
1776         }
1777 
1778         /* first check that for every font in this family we can find
1779          * a font file. The specific reason for doing this is that
1780          * in at least one case on Windows a font has the face name "David"
1781          * but the registry entry is "David Regular". That is the "unique"
1782          * name of the font but in other cases the registry contains the
1783          * "full" name. See the specifications of name ids 3 and 4 in the
1784          * TrueType 'name' table.
1785          * In general this could cause a problem that we fail to register
1786          * if we all members of a family that we may end up mapping to
1787          * the wrong font member: eg return Bold when Plain is needed.
1788          */
1789         for (int f=0;f<fontList.length;f++) {
1790             String fontNameLC = fontList[f].toLowerCase(Locale.ENGLISH);
1791             String fileName = fontToFileMap.get(fontNameLC);
1792             if (fileName == null) {
1793                 FontUtilities.logInfo("Platform lookup : No file for font " +


1794                                 fontList[f] + " in family " +familyName);

1795                 return null;
1796             }
1797         }
1798 
1799         /* Currently this code only looks for TrueType fonts, so format
1800          * and rank can be specified without looking at the filename.
1801          */
1802         PhysicalFont physicalFont = null;
1803         if (fontFile != null) {
1804             physicalFont = registerFontFile(getPathName(fontFile), null,
1805                                             FONTFORMAT_TRUETYPE, false,
1806                                             Font2D.TTF_RANK);
1807         }
1808         /* Register all fonts in this family. */
1809         for (int f=0;f<fontList.length;f++) {
1810             String fontNameLC = fontList[f].toLowerCase(Locale.ENGLISH);
1811             String fileName = fontToFileMap.get(fontNameLC);
1812             if (fontFile != null && fontFile.equals(fileName)) {
1813                 continue;
1814             }


1843      * A font may exist with the specified style, or it may
1844      * exist only in some other style. For non-native fonts the scaler
1845      * may be able to emulate the required style.
1846      */
1847     public Font2D findFont2D(String name, int style, int fallback) {
1848         if (name == null) return null;
1849         String lowerCaseName = name.toLowerCase(Locale.ENGLISH);
1850         String mapName = lowerCaseName + dotStyleStr(style);
1851 
1852         /* If preferLocaleFonts() or preferProportionalFonts() has been
1853          * called we may be using an alternate set of composite fonts in this
1854          * app context. The presence of a pre-built name map indicates whether
1855          * this is so, and gives access to the alternate composite for the
1856          * name.
1857          */
1858         Font2D font = fontNameCache.get(mapName);
1859         if (font != null) {
1860             return font;
1861         }
1862 
1863         FontUtilities.logInfo("Search for font: " + name);


1864 
1865         // The check below is just so that the bitmap fonts being set by
1866         // AWT and Swing thru the desktop properties do not trigger the
1867         // the load fonts case. The two bitmap fonts are now mapped to
1868         // appropriate equivalents for serif and sansserif.
1869         // Note that the cost of this comparison is only for the first
1870         // call until the map is filled.
1871         if (FontUtilities.isWindows) {
1872             if (lowerCaseName.equals("ms sans serif")) {
1873                 name = "sansserif";
1874             } else if (lowerCaseName.equals("ms serif")) {
1875                 name = "serif";
1876             }
1877         }
1878 
1879         /* This isn't intended to support a client passing in the
1880          * string default, but if a client passes in null for the name
1881          * the java.awt.Font class internally substitutes this name.
1882          * So we need to recognise it here to prevent a loadFonts
1883          * on the unrecognised name. The only potential problem with


1955                             /* The next check is perhaps one
1956                              * that shouldn't be done. ie if we get this
1957                              * far we have probably as close a match as we
1958                              * are going to get. We could load all fonts to
1959                              * see if somehow some parts of the family are
1960                              * loaded but not all of it.
1961                              */
1962                             if (familyFont.canDoStyle(style|font.style)) {
1963                                 fontNameCache.put(mapName, familyFont);
1964                                 return familyFont;
1965                             }
1966                         }
1967                     }
1968                 }
1969             }
1970         }
1971 
1972         if (FontUtilities.isWindows) {
1973 
1974             font = findFontFromPlatformMap(lowerCaseName, style);
1975             FontUtilities.logInfo("findFontFromPlatformMap returned " + font);
1976 


1977             if (font != null) {
1978                 fontNameCache.put(mapName, font);
1979                 return font;
1980             }
1981             /* Don't want Windows to return a font from C:\Windows\Fonts
1982              * if someone has installed a font with the same name
1983              * in the JRE.
1984              */
1985             if (deferredFontFiles.size() > 0) {
1986                 font = findJREDeferredFont(lowerCaseName, style);
1987                 if (font != null) {
1988                     fontNameCache.put(mapName, font);
1989                     return font;
1990                 }
1991             }
1992             font = findFontFromPlatform(lowerCaseName, style);
1993             if (font != null) {
1994                 FontUtilities.logInfo("Found font via platform API for request:\"" +


1995                                 name + "\":, style="+style+
1996                                 " found font: " + font);

1997                 fontNameCache.put(mapName, font);
1998                 return font;
1999             }
2000         }
2001 
2002         /* If reach here and no match has been located, then if there are
2003          * uninitialised deferred fonts, load as many of those as needed
2004          * to find the deferred font. If none is found through that
2005          * search continue on.
2006          * There is possibly a minor issue when more than one
2007          * deferred font implements the same font face. Since deferred
2008          * fonts are only those in font configuration files, this is a
2009          * controlled situation, the known case being Solaris euro_fonts
2010          * versions of Arial, Times New Roman, Courier New. However
2011          * the larger font will transparently replace the smaller one
2012          *  - see addToFontList() - when it is needed by the composite font.
2013          */
2014         if (deferredFontFiles.size() > 0) {
2015             font = findDeferredFont(name, style);
2016             if (font != null) {


2045                 if (font != null) {
2046                     if (fontsAreRegistered) {
2047                         fontNameCache.put(mapName, font);
2048                     }
2049                     return font;
2050                 }
2051             }
2052             font = nameTable.get(lowerCaseName);
2053             if (font != null) {
2054                 if (fontsAreRegistered) {
2055                     fontNameCache.put(mapName, font);
2056                 }
2057                 return font;
2058             }
2059         }
2060 
2061         /* If reach here and no match has been located, then if all fonts
2062          * are not yet loaded, do so, and then recurse.
2063          */
2064         if (!loadedAllFonts) {
2065             FontUtilities.logInfo("Load fonts looking for:" + name);



2066             loadFonts();
2067             loadedAllFonts = true;
2068             return findFont2D(name, style, fallback);
2069         }
2070 
2071         if (!loadedAllFontFiles) {
2072             FontUtilities.logInfo("Load font files looking for:" + name);



2073             loadFontFiles();
2074             loadedAllFontFiles = true;
2075             return findFont2D(name, style, fallback);
2076         }
2077 
2078         /* The primary name is the locale default - ie not US/English but
2079          * whatever is the default in this locale. This is the way it always
2080          * has been but may be surprising to some developers if "Arial Regular"
2081          * were hard-coded in their app and yet "Arial Regular" was not the
2082          * default name. Fortunately for them, as a consequence of the JDK
2083          * supporting returning names and family names for arbitrary locales,
2084          * we also need to support searching all localised names for a match.
2085          * But because this case of the name used to reference a font is not
2086          * the same as the default for this locale is rare, it makes sense to
2087          * search a much shorter list of default locale names and only go to
2088          * a longer list of names in the event that no match was found.
2089          * So add here code which searches localised names too.
2090          * As in 1.4.x this happens only after loading all fonts, which
2091          * is probably the right order.
2092          */


2110                 getFontConfiguration().getFallbackFamilyName(name, null);
2111             if (compatName != null) {
2112                 font = findFont2D(compatName, style, fallback);
2113                 fontNameCache.put(mapName, font);
2114                 return font;
2115             }
2116         } else if (lowerCaseName.equals("timesroman")) {
2117             font = findFont2D("serif", style, fallback);
2118             fontNameCache.put(mapName, font);
2119             return font;
2120         } else if (lowerCaseName.equals("helvetica")) {
2121             font = findFont2D("sansserif", style, fallback);
2122             fontNameCache.put(mapName, font);
2123             return font;
2124         } else if (lowerCaseName.equals("courier")) {
2125             font = findFont2D("monospaced", style, fallback);
2126             fontNameCache.put(mapName, font);
2127             return font;
2128         }
2129 
2130         FontUtilities.logInfo("No font found for:" + name);


2131 
2132         switch (fallback) {
2133         case PHYSICAL_FALLBACK: return getDefaultPhysicalFont();
2134         case LOGICAL_FALLBACK: return getDefaultLogicalFont(style);
2135         default: return null;
2136         }
2137     }
2138 
2139     /*
2140      * Workaround for apps which are dependent on a font metrics bug
2141      * in JDK 1.1. This is an unsupported win32 private setting.
2142      * Left in for a customer - do not remove.
2143      */
2144     public boolean usePlatformFontMetrics() {
2145         return usePlatformFontMetrics;
2146     }
2147 
2148     public int getNumFonts() {
2149         return physicalFonts.size()+maxCompFont;
2150     }


2283         return null;
2284     }
2285 
2286     /*
2287      * This is called when font is determined to be invalid/bad.
2288      * It designed to be called (for example) by the font scaler
2289      * when in processing a font file it is discovered to be incorrect.
2290      * This is different than the case where fonts are discovered to
2291      * be incorrect during initial verification, as such fonts are
2292      * never registered.
2293      * Handles to this font held are re-directed to a default font.
2294      * This default may not be an ideal substitute buts it better than
2295      * crashing This code assumes a PhysicalFont parameter as it doesn't
2296      * make sense for a Composite to be "bad".
2297      */
2298     public synchronized void deRegisterBadFont(Font2D font2D) {
2299         if (!(font2D instanceof PhysicalFont)) {
2300             /* We should never reach here, but just in case */
2301             return;
2302         } else {
2303             FontUtilities.logSevere("Deregister bad font: " + font2D);



2304             replaceFont((PhysicalFont)font2D, getDefaultPhysicalFont());
2305         }
2306     }
2307 
2308     /*
2309      * This encapsulates all the work that needs to be done when a
2310      * Font2D is replaced by a different Font2D.
2311      */
2312     public synchronized void replaceFont(PhysicalFont oldFont,
2313                                          PhysicalFont newFont) {
2314 
2315         if (oldFont.handle.font2D != oldFont) {
2316             /* already done */
2317             return;
2318         }
2319 
2320         /* If we try to replace the font with itself, that won't work,
2321          * so pick any alternative physical font
2322          */
2323         if (oldFont == newFont) {
2324             FontUtilities.logSevere("Can't replace bad font with itself " + oldFont);



2325             PhysicalFont[] physFonts = getPhysicalFonts();
2326             for (int i=0; i<physFonts.length;i++) {
2327                 if (physFonts[i] != newFont) {
2328                     newFont = physFonts[i];
2329                     break;
2330                 }
2331             }
2332             if (oldFont == newFont) {
2333                 FontUtilities.logSevere("This is bad. No good physicalFonts found.");



2334                 return;
2335             }
2336         }
2337 
2338         /* eliminate references to this font, so it won't be located
2339          * by future callers, and will be eligible for GC when all
2340          * references are removed
2341          */
2342         oldFont.handle.font2D = newFont;
2343         physicalFonts.remove(oldFont.fullName);
2344         fullNameToFont.remove(oldFont.fullName.toLowerCase(Locale.ENGLISH));
2345         FontFamily.remove(oldFont);
2346         if (localeFullNamesToFont != null) {
2347             Map.Entry<?, ?>[] mapEntries = localeFullNamesToFont.entrySet().
2348                 toArray(new Map.Entry<?, ?>[0]);
2349             /* Should I be replacing these, or just I just remove
2350              * the names from the map?
2351              */
2352             for (int i=0; i<mapEntries.length;i++) {
2353                 if (mapEntries[i].getValue() == oldFont) {


2413                 String[] fullNames = ttf.getAllFullNames();
2414                 for (int n=0; n<fullNames.length; n++) {
2415                     localeFullNamesToFont.put(fullNames[n], ttf);
2416                 }
2417                 FontFamily family = FontFamily.getFamily(ttf.familyName);
2418                 if (family != null) {
2419                     FontFamily.addLocaleNames(family, ttf.getAllFamilyNames());
2420                 }
2421             }
2422         }
2423     }
2424 
2425     /* This replicate the core logic of findFont2D but operates on
2426      * all the locale names. This hasn't been merged into findFont2D to
2427      * keep the logic simpler and reduce overhead, since this case is
2428      * almost never used. The main case in which it is called is when
2429      * a bogus font name is used and we need to check all possible names
2430      * before returning the default case.
2431      */
2432     private Font2D findFont2DAllLocales(String name, int style) {
2433         FontUtilities.logInfo("Searching localised font names for:" + name);




2434 
2435         /* If reach here and no match has been located, then if we have
2436          * not yet built the map of localeFullNamesToFont for TT fonts, do so
2437          * now. This method must be called after all fonts have been loaded.
2438          */
2439         if (localeFullNamesToFont == null) {
2440             loadLocaleNames();
2441         }
2442         String lowerCaseName = name.toLowerCase();
2443         Font2D font = null;
2444 
2445         /* First see if its a family name. */
2446         FontFamily family = FontFamily.getLocaleFamily(lowerCaseName);
2447         if (family != null) {
2448           font = family.getFont(style);
2449           if (font == null) {
2450             font = family.getClosestStyle(style);
2451           }
2452           if (font != null) {
2453               return font;


2547      * a case cannot retrieve a cached metrics solely on the basis of
2548      * the Font.equals() method since it needs to also check if the Font2D
2549      * is the same.
2550      * We also use non-standard composites for Swing native L&F fonts on
2551      * Windows. In that case the policy is that the metrics reported are
2552      * based solely on the physical font in the first slot which is the
2553      * visible java.awt.Font. So in that case the metrics cache which tests
2554      * the Font does what we want. In the near future when we expand the GTK
2555      * logical font definitions we may need to revisit this if GTK reports
2556      * combined metrics instead. For now though this test can be simple.
2557      */
2558     public boolean usingAlternateCompositeFonts() {
2559         return _usingAlternateComposites;
2560     }
2561 
2562     /* Modifies the behaviour of a subsequent call to preferLocaleFonts()
2563      * to use Mincho instead of Gothic for dialoginput in JA locales
2564      * on windows. Not needed on other platforms.
2565      */
2566     public synchronized void useAlternateFontforJALocales() {
2567         FontUtilities.logInfo("Entered useAlternateFontforJALocales().");
2568 


2569         if (!FontUtilities.isWindows) {
2570             return;
2571         }
2572         gAltJAFont = true;
2573     }
2574 
2575     public boolean usingAlternateFontforJALocales() {
2576         return gAltJAFont;
2577     }
2578 
2579     public synchronized void preferLocaleFonts() {
2580         FontUtilities.logInfo("Entered preferLocaleFonts().");
2581 

2582         /* Test if re-ordering will have any effect */
2583         if (!FontConfiguration.willReorderForStartupLocale()) {
2584             return;
2585         }
2586         if (gLocalePref == true) {
2587             return;
2588         }
2589         gLocalePref = true;
2590         createCompositeFonts(fontNameCache, gLocalePref, gPropPref);
2591         _usingAlternateComposites = true;
2592     }
2593 
2594     public synchronized void preferProportionalFonts() {
2595         FontUtilities.logInfo("Entered preferProportionalFonts().");
2596 


2597         /* If no proportional fonts are configured, there's no need
2598          * to take any action.
2599          */
2600         if (!FontConfiguration.hasMonoToPropMap()) {
2601             return;
2602         }
2603         if (gPropPref == true) {
2604             return;
2605         }
2606         gPropPref = true;
2607         createCompositeFonts(fontNameCache, gLocalePref, gPropPref);
2608         _usingAlternateComposites = true;
2609     }
2610 
2611     private static HashSet<String> installedNames = null;
2612     private static HashSet<String> getInstalledNames() {
2613         if (installedNames == null) {
2614            Locale l = getSystemStartupLocale();
2615            SunFontManager fontManager = SunFontManager.getInstance();
2616            String[] installedFamilies =


2816         for (int i=0; i < ls.length; i++ ) {
2817             File theFile = new File(dirFile, ls[i]);
2818             String fullName = null;
2819             if (resolveSymLinks) {
2820                 try {
2821                     fullName = theFile.getCanonicalPath();
2822                 } catch (IOException e) {
2823                 }
2824             }
2825             if (fullName == null) {
2826                 fullName = dirName + File.separator + ls[i];
2827             }
2828 
2829             // REMIND: case compare depends on platform
2830             if (registeredFontFiles.contains(fullName)) {
2831                 continue;
2832             }
2833 
2834             if (badFonts != null && badFonts.contains(fullName)) {
2835                 if (FontUtilities.debugFonts()) {
2836                     FontUtilities.logWarning("skip bad font " + fullName);

2837                 }
2838                 continue; // skip this font file.
2839             }
2840 
2841             registeredFontFiles.add(fullName);
2842 
2843             if (FontUtilities.debugFonts()
2844                 && FontUtilities.getLogger().isLoggable(PlatformLogger.Level.INFO)) {
2845                 String message = "Registering font " + fullName;
2846                 String[] natNames = getNativeNames(fullName, null);
2847                 if (natNames == null) {
2848                     message += " with no native name";
2849                 } else {
2850                     message += " with native name(s) " + natNames[0];
2851                     for (int nn = 1; nn < natNames.length; nn++) {
2852                         message += ", " + natNames[nn];
2853                     }
2854                 }
2855                 FontUtilities.logInfo(message);
2856             }
2857             fontNames[fontCount] = fullName;
2858             nativeNames[fontCount++] = getNativeNames(fullName, null);
2859         }
2860         registerFonts(fontNames, nativeNames, fontCount, fontFormat,
2861                          useJavaRasterizer, fontRank, defer);
2862         return;
2863     }
2864 
2865     protected String[] getNativeNames(String fontFileName,
2866                                       String platformName) {
2867         return null;
2868     }
2869 
2870     /**
2871      * Returns a file name for the physical font represented by this platform
2872      * font name. The default implementation tries to obtain the file name
2873      * from the font configuration.
2874      * Subclasses may override to provide information from other sources.
2875      */


2885     }
2886 
2887     /* A call to this method should be followed by a call to
2888      * registerFontDirs(..)
2889      */
2890     public String getPlatformFontPath(boolean noType1Font) {
2891         if (fontPath == null) {
2892             fontPath = getFontPath(noType1Font);
2893         }
2894         return fontPath;
2895     }
2896 
2897     protected void loadFonts() {
2898         if (discoveredAllFonts) {
2899             return;
2900         }
2901         /* Use lock specific to the font system */
2902         synchronized (this) {
2903             if (FontUtilities.debugFonts()) {
2904                 Thread.dumpStack();
2905                 FontUtilities.logInfo("SunGraphicsEnvironment.loadFonts() called");

2906             }
2907             initialiseDeferredFonts();
2908 
2909             AccessController.doPrivileged(new PrivilegedAction<Void>() {
2910                 public Void run() {
2911                     if (fontPath == null) {
2912                         fontPath = getPlatformFontPath(noType1Font);
2913                         registerFontDirs(fontPath);
2914                     }
2915                     if (fontPath != null) {
2916                         // this will find all fonts including those already
2917                         // registered. But we have checks in place to prevent
2918                         // double registration.
2919                         if (! gotFontsFromPlatform()) {
2920                             registerFontsOnPath(fontPath, false,
2921                                                 Font2D.UNKNOWN_RANK,
2922                                                 false, true);
2923                             loadedAllFontFiles = true;
2924                         }
2925                     }


3003                             boolean preferPropFonts);
3004 
3005     /**
3006      * Returns face name for default font, or null if
3007      * no face names are used for CompositeFontDescriptors
3008      * for this platform.
3009      */
3010     public synchronized String getDefaultFontFaceName() {
3011         return defaultFontName;
3012     }
3013 
3014     public void loadFontFiles() {
3015         loadFonts();
3016         if (loadedAllFontFiles) {
3017             return;
3018         }
3019         /* Use lock specific to the font system */
3020         synchronized (this) {
3021             if (FontUtilities.debugFonts()) {
3022                 Thread.dumpStack();
3023                 FontUtilities.logInfo("loadAllFontFiles() called");
3024             }
3025             AccessController.doPrivileged(new PrivilegedAction<Void>() {
3026                 public Void run() {
3027                     if (fontPath == null) {
3028                         fontPath = getPlatformFontPath(noType1Font);
3029                     }
3030                     if (fontPath != null) {
3031                         // this will find all fonts including those already
3032                         // registered. But we have checks in place to prevent
3033                         // double registration.
3034                         registerFontsOnPath(fontPath, false,
3035                                             Font2D.UNKNOWN_RANK,
3036                                             false, true);
3037                     }
3038                     loadedAllFontFiles = true;
3039                     return null;
3040                 }
3041             });
3042         }
3043     }
3044 
3045     /*
3046      * This method asks the font configuration API for all platform names
3047      * used as components of composite/logical fonts and iterates over these
3048      * looking up their corresponding file name and registers these fonts.
3049      * It also ensures that the fonts are accessible via platform APIs.
3050      * The composites themselves are then registered.
3051      */
3052     private void
3053         initCompositeFonts(FontConfiguration fontConfig,
3054                            ConcurrentHashMap<String, Font2D>  altNameCache) {
3055         FontUtilities.logInfo("Initialising composite fonts");




3056 
3057         int numCoreFonts = fontConfig.getNumberCoreFonts();
3058         String[] fcFonts = fontConfig.getPlatformFontNames();
3059         for (int f=0; f<fcFonts.length; f++) {
3060             String platformFontName = fcFonts[f];
3061             String fontFileName =
3062                 getFileNameFromPlatformName(platformFontName);
3063             String[] nativeNames = null;
3064             if (fontFileName == null
3065                 || fontFileName.equals(platformFontName)) {
3066                 /* No file located, so register using the platform name,
3067                  * i.e. as a native font.
3068                  */
3069                 fontFileName = platformFontName;
3070             } else {
3071                 if (f < numCoreFonts) {
3072                     /* If platform APIs also need to access the font, add it
3073                      * to a set to be registered with the platform too.
3074                      * This may be used to add the parent directory to the X11
3075                      * font path if its not already there. See the docs for the


3134              * fall back component fonts to the composite.
3135              */
3136             if (altNameCache != null) {
3137                 SunFontManager.registerCompositeFont(
3138                     descriptor.getFaceName(),
3139                     componentFileNames, componentFaceNames,
3140                     descriptor.getCoreComponentCount(),
3141                     descriptor.getExclusionRanges(),
3142                     descriptor.getExclusionRangeLimits(),
3143                     true,
3144                     altNameCache);
3145             } else {
3146                 registerCompositeFont(descriptor.getFaceName(),
3147                                       componentFileNames, componentFaceNames,
3148                                       descriptor.getCoreComponentCount(),
3149                                       descriptor.getExclusionRanges(),
3150                                       descriptor.getExclusionRangeLimits(),
3151                                       true);
3152             }
3153             if (FontUtilities.debugFonts()) {
3154                 FontUtilities.logInfo("registered " + descriptor.getFaceName());

3155             }
3156         }
3157     }
3158 
3159     /**
3160      * Notifies graphics environment that the logical font configuration
3161      * uses the given platform font name. The graphics environment may
3162      * use this for platform specific initialization.
3163      */
3164     protected void addFontToPlatformFontPath(String platformFontName) {
3165     }
3166 
3167     protected void registerFontFile(String fontFileName, String[] nativeNames,
3168                                     int fontRank, boolean defer) {
3169 //      REMIND: case compare depends on platform
3170         if (registeredFontFiles.contains(fontFileName)) {
3171             return;
3172         }
3173         int fontFormat;
3174         if (ttFilter.accept(null, fontFileName)) {


< prev index next >