} else { fontPath = dbgFontPath; } registerFontDirs(fontPath); } else if (extraFontPath != null) { /* If the font configuration contains an * "appendedfontpath" entry, it is interpreted as a * set of locations that should always be registered. * It may be additional to locations normally found * for that place, or it may be locations that need * to have all their paths registered to locate all * the needed platform names. * This is typically when the same .TTF file is * referenced from multiple font.dir files and all * of these must be read to find all the native * (XLFD) names for the font, so that X11 font APIs * can be used for as many code points as possible. */ registerFontDirs(extraFontPath); } /* On Solaris, we need to register the Japanese TrueType * directory so that we can find the corresponding * bitmap fonts. This could be done by listing the * directory in the font configuration file, but we * don't want to confuse users with this quirk. There * are no bitmap fonts for other writing systems that * correspond to TrueType fonts and have matching XLFDs. * We need to register the bitmap fonts only in * environments where they're on the X font path, i.e., * in the Japanese locale. Note that if the X Toolkit * is in use the font path isn't set up by JDK, but * users of a JA locale should have it * set up already by their login environment. */ if (FontUtilities.isSolaris && Locale.JAPAN.equals(Locale.getDefault())) { registerFontDir("/usr/openwin/lib/locale/ja/X11/fonts/TT"); } initCompositeFonts(fontConfig, null); return null; } }); boolean platformFont = AccessController.doPrivileged( new PrivilegedAction<Boolean>() { public Boolean run() { String prop = System.getProperty("java2d.font.usePlatformFont"); String env = System.getenv("JAVA2D_USEPLATFORMFONT"); return "true".equals(prop) || env != null; } }); if (platformFont) { usePlatformFontMetrics = true; System.out.println("Enabling platform font metrics for win32. This is an unsupported option."); System.out.println("This yields incorrect composite font metrics as reported by 1.1.x releases."); System.out.println("It is appropriate only for use by applications which do not use any Java 2"); System.out.println("functionality. This property will be removed in a later release."); } } /** * This method is provided for internal and exclusive use by Swing. * * @param font representing a physical font. * @return true if the underlying font is a TrueType or OpenType font * that claims to support the Microsoft Windows encoding corresponding to * the default file.encoding property of this JRE instance. * This narrow value is useful for Swing to decide if the font is useful * for the the Windows Look and Feel, or, if a composite font should be * used instead. * The information used to make the decision is obtained from * the ulCodePageRange fields in the font. * A caller can use isLogicalFont(Font) in this class before calling * this method and would not need to call this method if that * returns true. */// static boolean fontSupportsDefaultEncoding(Font font) {// String encoding =// (String) java.security.AccessController.doPrivileged(// new sun.security.action.GetPropertyAction("file.encoding")); // if (encoding == null || font == null) {// return false;// } // encoding = encoding.toLowerCase(Locale.ENGLISH); // return FontManager.fontSupportsEncoding(font, encoding);// } public Font2DHandle getNewComposite(String family, int style, Font2DHandle handle) { if (!(handle.font2D instanceof CompositeFont)) { return handle; } CompositeFont oldComp = (CompositeFont)handle.font2D; PhysicalFont oldFont = oldComp.getSlotFont(0); if (family == null) { family = oldFont.getFamilyName(null); } if (style == -1) { style = oldComp.getStyle(); } Font2D newFont = findFont2D(family, style, NO_FALLBACK); if (!(newFont instanceof PhysicalFont)) { newFont = oldFont; } PhysicalFont physicalFont = (PhysicalFont)newFont; CompositeFont dialog2D = (CompositeFont)findFont2D("dialog", style, NO_FALLBACK); if (dialog2D == null) { /* shouldn't happen */ return handle; } CompositeFont compFont = new CompositeFont(physicalFont, dialog2D); Font2DHandle newHandle = new Font2DHandle(compFont); return newHandle; } protected void registerCompositeFont(String compositeName, String[] componentFileNames, String[] componentNames, int numMetricsSlots, int[] exclusionRanges, int[] exclusionMaxIndex, boolean defer) { CompositeFont cf = new CompositeFont(compositeName, componentFileNames, componentNames, numMetricsSlots, exclusionRanges, exclusionMaxIndex, defer, this); addCompositeToFontList(cf, Font2D.FONT_CONFIG_RANK); synchronized (compFonts) { compFonts[maxCompFont++] = cf; } } /* This variant is used only when the application specifies * a variant of composite fonts which prefers locale specific or * proportional fonts. */ protected static void registerCompositeFont(String compositeName, String[] componentFileNames, String[] componentNames, int numMetricsSlots, int[] exclusionRanges, int[] exclusionMaxIndex, boolean defer, ConcurrentHashMap<String, Font2D> altNameCache) { CompositeFont cf = new CompositeFont(compositeName, componentFileNames, componentNames, numMetricsSlots, exclusionRanges, exclusionMaxIndex, defer, SunFontManager.getInstance()); /* if the cache has an existing composite for this case, make * its handle point to this new font. * This ensures that when the altNameCache that is passed in * is the global mapNameCache - ie we are running as an application - * that any statically created java.awt.Font instances which already * have a Font2D instance will have that re-directed to the new Font * on subsequent uses. This is particularly important for "the" * default font instance, or similar cases where a UI toolkit (eg * Swing) has cached a java.awt.Font. Note that if Swing is using * a custom composite APIs which update the standard composites have * no effect - this is typically the case only when using the Windows * L&F where these APIs would conflict with that L&F anyway. */ Font2D oldFont = (Font2D) altNameCache.get(compositeName.toLowerCase(Locale.ENGLISH)); if (oldFont instanceof CompositeFont) { oldFont.handle.font2D = cf; } altNameCache.put(compositeName.toLowerCase(Locale.ENGLISH), cf); } private void addCompositeToFontList(CompositeFont f, int rank) { if (FontUtilities.isLogging()) { FontUtilities.getLogger().info("Add to Family "+ f.familyName + ", Font " + f.fullName + " rank="+rank); } f.setRank(rank); compositeFonts.put(f.fullName, f); fullNameToFont.put(f.fullName.toLowerCase(Locale.ENGLISH), f); FontFamily family = FontFamily.getFamily(f.familyName); if (family == null) { family = new FontFamily(f.familyName, true, rank); } family.setFont(f, f.style); } /* * Systems may have fonts with the same name. * We want to register only one of such fonts (at least until * such time as there might be APIs which can accommodate > 1). * Rank is 1) font configuration fonts, 2) JRE fonts, 3) OT/TT fonts, * 4) Type1 fonts, 5) native fonts. * * If the new font has the same name as the old font, the higher * ranked font gets added, replacing the lower ranked one. * If the fonts are of equal rank, then make a special case of * font configuration rank fonts, which are on closer inspection, * OT/TT fonts such that the larger font is registered. This is * a heuristic since a font may be "larger" in the sense of more * code points, or be a larger "file" because it has more bitmaps. * So it is possible that using filesize may lead to less glyphs, and * using glyphs may lead to lower quality display. Probably number * of glyphs is the ideal, but filesize is information we already * have and is good enough for the known cases. * Also don't want to register fonts that match JRE font families * but are coming from a source other than the JRE. * This will ensure that we will algorithmically style the JRE * plain font and get the same set of glyphs for all styles. * * Note that this method returns a value * if it returns the same object as its argument that means this * font was newly registered. * If it returns a different object it means this font already exists, * and you should use that one. * If it returns null means this font was not registered and none * in that name is registered. The caller must find a substitute */ private PhysicalFont addToFontList(PhysicalFont f, int rank) { String fontName = f.fullName; String familyName = f.familyName; if (fontName == null || "".equals(fontName)) { return null; } if (compositeFonts.containsKey(fontName)) { /* Don't register any font that has the same name as a composite */ return null; } f.setRank(rank); if (!physicalFonts.containsKey(fontName)) { if (FontUtilities.isLogging()) { FontUtilities.getLogger().info("Add to Family "+familyName + ", Font " + fontName + " rank="+rank); } physicalFonts.put(fontName, f); FontFamily family = FontFamily.getFamily(familyName); if (family == null) { family = new FontFamily(familyName, false, rank); family.setFont(f, f.style); } else if (family.getRank() >= rank) { family.setFont(f, f.style); } fullNameToFont.put(fontName.toLowerCase(Locale.ENGLISH), f); return f; } else { PhysicalFont newFont = f; PhysicalFont oldFont = physicalFonts.get(fontName); if (oldFont == null) { return null; } /* If the new font is of an equal or higher rank, it is a * candidate to replace the current one, subject to further tests. */ if (oldFont.getRank() >= rank) { /* All fonts initialise their mapper when first * used. If the mapper is non-null then this font * has been accessed at least once. In that case * do not replace it. This may be overly stringent, * but its probably better not to replace a font that * someone is already using without a compelling reason. * Additionally the primary case where it is known * this behaviour is important is in certain composite * fonts, and since all the components of a given * composite are usually initialised together this * is unlikely. For this to be a problem, there would * have to be a case where two different composites used * different versions of the same-named font, and they * were initialised and used at separate times. * In that case we continue on and allow the new font to * be installed, but replaceFont will continue to allow * the original font to be used in Composite fonts. */ if (oldFont.mapper != null && rank > Font2D.FONT_CONFIG_RANK) { return oldFont; } /* Normally we require a higher rank to replace a font, * but as a special case, if the two fonts are the same rank, * and are instances of TrueTypeFont we want the * more complete (larger) one. */ if (oldFont.getRank() == rank) { if (oldFont instanceof TrueTypeFont && newFont instanceof TrueTypeFont) { TrueTypeFont oldTTFont = (TrueTypeFont)oldFont; TrueTypeFont newTTFont = (TrueTypeFont)newFont; if (oldTTFont.fileSize >= newTTFont.fileSize) { return oldFont; } } else { return oldFont; } } /* Don't replace ever JRE fonts. * This test is in case a font configuration references * a Lucida font, which has been mapped to a Lucida * from the host O/S. The assumption here is that any * such font configuration file is probably incorrect, or * the host O/S version is for the use of AWT. * In other words if we reach here, there's a possible * problem with our choice of font configuration fonts. */ if (oldFont.platName.startsWith(jreFontDirName)) { if (FontUtilities.isLogging()) { FontUtilities.getLogger() .warning("Unexpected attempt to replace a JRE " + " font " + fontName + " from " + oldFont.platName + " with " + newFont.platName); } return oldFont; } if (FontUtilities.isLogging()) { FontUtilities.getLogger() .info("Replace in Family " + familyName + ",Font " + fontName + " new rank="+rank + " from " + oldFont.platName + " with " + newFont.platName); } replaceFont(oldFont, newFont); physicalFonts.put(fontName, newFont); fullNameToFont.put(fontName.toLowerCase(Locale.ENGLISH), newFont); FontFamily family = FontFamily.getFamily(familyName); if (family == null) { family = new FontFamily(familyName, false, rank); family.setFont(newFont, newFont.style); } else if (family.getRank() >= rank) { family.setFont(newFont, newFont.style); } return newFont; } else { return oldFont; } } } public Font2D[] getRegisteredFonts() { PhysicalFont[] physFonts = getPhysicalFonts(); int mcf = maxCompFont; /* for MT-safety */ Font2D[] regFonts = new Font2D[physFonts.length+mcf]; System.arraycopy(compFonts, 0, regFonts, 0, mcf); System.arraycopy(physFonts, 0, regFonts, mcf, physFonts.length); return regFonts; } protected PhysicalFont[] getPhysicalFonts() { return physicalFonts.values().toArray(new PhysicalFont[0]); } /* The class FontRegistrationInfo is used when a client says not * to register a font immediately. This mechanism is used to defer * initialisation of all the components of composite fonts at JRE * start-up. The CompositeFont class is "aware" of this and when it * is first used it asks for the registration of its components. * Also in the event that any physical font is requested the * deferred fonts are initialised before triggering a search of the * system. * Two maps are used. One to track the deferred fonts. The * other to track the fonts that have been initialised through this * mechanism. */ private static final class FontRegistrationInfo { String fontFilePath; String[] nativeNames; int fontFormat; boolean javaRasterizer; int fontRank; FontRegistrationInfo(String fontPath, String[] names, int format, boolean useJavaRasterizer, int rank) { this.fontFilePath = fontPath; this.nativeNames = names; this.fontFormat = format; this.javaRasterizer = useJavaRasterizer; this.fontRank = rank; } } private final ConcurrentHashMap<String, FontRegistrationInfo> deferredFontFiles = new ConcurrentHashMap<String, FontRegistrationInfo>(); private final ConcurrentHashMap<String, Font2DHandle> initialisedFonts = new ConcurrentHashMap<String, Font2DHandle>(); /* Remind: possibly enhance initialiseDeferredFonts() to be * optionally given a name and a style and it could stop when it * finds that font - but this would be a problem if two of the * fonts reference the same font face name (cf the Solaris * euro fonts). */ protected synchronized void initialiseDeferredFonts() { for (String fileName : deferredFontFiles.keySet()) { initialiseDeferredFont(fileName); } } protected synchronized void registerDeferredJREFonts(String jreDir) { for (FontRegistrationInfo info : deferredFontFiles.values()) { if (info.fontFilePath != null && info.fontFilePath.startsWith(jreDir)) { initialiseDeferredFont(info.fontFilePath); } } } public boolean isDeferredFont(String fileName) { return deferredFontFiles.containsKey(fileName); } /* We keep a map of the files which contain the Lucida fonts so we * don't need to search for them. * But since we know what fonts these files contain, we can also avoid * opening them to look for a font name we don't recognise - see * findDeferredFont(). * For typical cases where the font isn't a JRE one the overhead is * this method call, HashMap.get() and null reference test, then * a boolean test of noOtherJREFontFiles. */ public /*private*/ PhysicalFont findJREDeferredFont(String name, int style) { PhysicalFont physicalFont; String nameAndStyle = name.toLowerCase(Locale.ENGLISH) + style; String fileName = jreFontMap.get(nameAndStyle); if (fileName != null) { fileName = jreFontDirName + File.separator + fileName; if (deferredFontFiles.get(fileName) != null) { physicalFont = initialiseDeferredFont(fileName); if (physicalFont != null && (physicalFont.getFontName(null).equalsIgnoreCase(name) || physicalFont.getFamilyName(null).equalsIgnoreCase(name)) && physicalFont.style == style) { return physicalFont; } } } /* Iterate over the deferred font files looking for any in the * jre directory that we didn't recognise, open each of these. * In almost all installations this will quickly fall through * because only the Lucidas will be present and jreOtherFontFiles * will be empty. * noOtherJREFontFiles is used so we can skip this block as soon * as its determined that its not needed - almost always after the * very first time through. */ if (noOtherJREFontFiles) { return null; } synchronized (jreLucidaFontFiles) { if (jreOtherFontFiles == null) { HashSet<String> otherFontFiles = new HashSet<String>(); for (String deferredFile : deferredFontFiles.keySet()) { File file = new File(deferredFile); String dir = file.getParent(); String fname = file.getName(); /* skip names which aren't absolute, aren't in the JRE * directory, or are known Lucida fonts. */ if (dir == null || !dir.equals(jreFontDirName) || jreLucidaFontFiles.contains(fname)) { continue; } otherFontFiles.add(deferredFile); } jreOtherFontFiles = otherFontFiles.toArray(STR_ARRAY); if (jreOtherFontFiles.length == 0) { noOtherJREFontFiles = true; } } for (int i=0; i<jreOtherFontFiles.length;i++) {Lines 501–1000 of 3912. Previous lines Load more
} else { fontPath = dbgFontPath; } registerFontDirs(fontPath); } else if (extraFontPath != null) { /* If the font configuration contains an * "appendedfontpath" entry, it is interpreted as a * set of locations that should always be registered. * It may be additional to locations normally found * for that place, or it may be locations that need * to have all their paths registered to locate all * the needed platform names. * This is typically when the same .TTF file is * referenced from multiple font.dir files and all * of these must be read to find all the native * (XLFD) names for the font, so that X11 font APIs * can be used for as many code points as possible. */ registerFontDirs(extraFontPath); } /* On Solaris, we need to register the Japanese TrueType * directory so that we can find the corresponding * bitmap fonts. This could be done by listing the * directory in the font configuration file, but we * don't want to confuse users with this quirk. There * are no bitmap fonts for other writing systems that * correspond to TrueType fonts and have matching XLFDs. * We need to register the bitmap fonts only in * environments where they're on the X font path, i.e., * in the Japanese locale. Note that if the X Toolkit * is in use the font path isn't set up by JDK, but * users of a JA locale should have it * set up already by their login environment. */ if (FontUtilities.isSolaris && Locale.JAPAN.equals(Locale.getDefault())) { registerFontDir("/usr/openwin/lib/locale/ja/X11/fonts/TT"); } initCompositeFonts(fontConfig, null); return null; } }); boolean platformFont = AccessController.doPrivileged( new PrivilegedAction<Boolean>() { public Boolean run() { String prop = System.getProperty("java2d.font.usePlatformFont"); String env = System.getenv("JAVA2D_USEPLATFORMFONT"); return "true".equals(prop) || env != null; } }); if (platformFont) { usePlatformFontMetrics = true; System.out.println("Enabling platform font metrics for win32. This is an unsupported option."); System.out.println("This yields incorrect composite font metrics as reported by 1.1.x releases."); System.out.println("It is appropriate only for use by applications which do not use any Java 2"); System.out.println("functionality. This property will be removed in a later release."); } } /** * This method is provided for internal and exclusive use by Swing. * * @param font representing a physical font. * @return true if the underlying font is a TrueType or OpenType font * that claims to support the Microsoft Windows encoding corresponding to * the default file.encoding property of this JRE instance. * This narrow value is useful for Swing to decide if the font is useful * for the the Windows Look and Feel, or, if a composite font should be * used instead. * The information used to make the decision is obtained from * the ulCodePageRange fields in the font. * A caller can use isLogicalFont(Font) in this class before calling * this method and would not need to call this method if that * returns true. */ // static boolean fontSupportsDefaultEncoding(Font font) { // String encoding = // (String) java.security.AccessController.doPrivileged( // new sun.security.action.GetPropertyAction("file.encoding")); // if (encoding == null || font == null) { // return false; // } // encoding = encoding.toLowerCase(Locale.ENGLISH); // return FontManager.fontSupportsEncoding(font, encoding); // } public Font2DHandle getNewComposite(String family, int style, Font2DHandle handle) { if (!(handle.font2D instanceof CompositeFont)) { return handle; } CompositeFont oldComp = (CompositeFont)handle.font2D; PhysicalFont oldFont = oldComp.getSlotFont(0); if (family == null) { family = oldFont.getFamilyName(null); } if (style == -1) { style = oldComp.getStyle(); } Font2D newFont = findFont2D(family, style, NO_FALLBACK); if (!(newFont instanceof PhysicalFont)) { newFont = oldFont; } PhysicalFont physicalFont = (PhysicalFont)newFont; CompositeFont dialog2D = (CompositeFont)findFont2D("dialog", style, NO_FALLBACK); if (dialog2D == null) { /* shouldn't happen */ return handle; } CompositeFont compFont = new CompositeFont(physicalFont, dialog2D); Font2DHandle newHandle = new Font2DHandle(compFont); return newHandle; } protected void registerCompositeFont(String compositeName, String[] componentFileNames, String[] componentNames, int numMetricsSlots, int[] exclusionRanges, int[] exclusionMaxIndex, boolean defer) { CompositeFont cf = new CompositeFont(compositeName, componentFileNames, componentNames, numMetricsSlots, exclusionRanges, exclusionMaxIndex, defer, this); addCompositeToFontList(cf, Font2D.FONT_CONFIG_RANK); synchronized (compFonts) { compFonts[maxCompFont++] = cf; } } /* This variant is used only when the application specifies * a variant of composite fonts which prefers locale specific or * proportional fonts. */ protected static void registerCompositeFont(String compositeName, String[] componentFileNames, String[] componentNames, int numMetricsSlots, int[] exclusionRanges, int[] exclusionMaxIndex, boolean defer, ConcurrentHashMap<String, Font2D> altNameCache) { CompositeFont cf = new CompositeFont(compositeName, componentFileNames, componentNames, numMetricsSlots, exclusionRanges, exclusionMaxIndex, defer, SunFontManager.getInstance()); /* if the cache has an existing composite for this case, make * its handle point to this new font. * This ensures that when the altNameCache that is passed in * is the global mapNameCache - ie we are running as an application - * that any statically created java.awt.Font instances which already * have a Font2D instance will have that re-directed to the new Font * on subsequent uses. This is particularly important for "the" * default font instance, or similar cases where a UI toolkit (eg * Swing) has cached a java.awt.Font. Note that if Swing is using * a custom composite APIs which update the standard composites have * no effect - this is typically the case only when using the Windows * L&F where these APIs would conflict with that L&F anyway. */ Font2D oldFont = (Font2D) altNameCache.get(compositeName.toLowerCase(Locale.ENGLISH)); if (oldFont instanceof CompositeFont) { oldFont.handle.font2D = cf; } altNameCache.put(compositeName.toLowerCase(Locale.ENGLISH), cf); } private void addCompositeToFontList(CompositeFont f, int rank) { if (FontUtilities.isLogging()) { FontUtilities.getLogger().info("Add to Family "+ f.familyName + ", Font " + f.fullName + " rank="+rank); } f.setRank(rank); compositeFonts.put(f.fullName, f); fullNameToFont.put(f.fullName.toLowerCase(Locale.ENGLISH), f); FontFamily family = FontFamily.getFamily(f.familyName); if (family == null) { family = new FontFamily(f.familyName, true, rank); } family.setFont(f, f.style); } /* * Systems may have fonts with the same name. * We want to register only one of such fonts (at least until * such time as there might be APIs which can accommodate > 1). * Rank is 1) font configuration fonts, 2) JRE fonts, 3) OT/TT fonts, * 4) Type1 fonts, 5) native fonts. * * If the new font has the same name as the old font, the higher * ranked font gets added, replacing the lower ranked one. * If the fonts are of equal rank, then make a special case of * font configuration rank fonts, which are on closer inspection, * OT/TT fonts such that the larger font is registered. This is * a heuristic since a font may be "larger" in the sense of more * code points, or be a larger "file" because it has more bitmaps. * So it is possible that using filesize may lead to less glyphs, and * using glyphs may lead to lower quality display. Probably number * of glyphs is the ideal, but filesize is information we already * have and is good enough for the known cases. * Also don't want to register fonts that match JRE font families * but are coming from a source other than the JRE. * This will ensure that we will algorithmically style the JRE * plain font and get the same set of glyphs for all styles. * * Note that this method returns a value * if it returns the same object as its argument that means this * font was newly registered. * If it returns a different object it means this font already exists, * and you should use that one. * If it returns null means this font was not registered and none * in that name is registered. The caller must find a substitute */ private PhysicalFont addToFontList(PhysicalFont f, int rank) { String fontName = f.fullName; String familyName = f.familyName; if (fontName == null || "".equals(fontName)) { return null; } if (compositeFonts.containsKey(fontName)) { /* Don't register any font that has the same name as a composite */ return null; } f.setRank(rank); if (!physicalFonts.containsKey(fontName)) { if (FontUtilities.isLogging()) { FontUtilities.getLogger().info("Add to Family "+familyName + ", Font " + fontName + " rank="+rank); } physicalFonts.put(fontName, f); FontFamily family = FontFamily.getFamily(familyName); if (family == null) { family = new FontFamily(familyName, false, rank); family.setFont(f, f.style); } else if (family.getRank() >= rank) { family.setFont(f, f.style); } fullNameToFont.put(fontName.toLowerCase(Locale.ENGLISH), f); return f; } else { PhysicalFont newFont = f; PhysicalFont oldFont = physicalFonts.get(fontName); if (oldFont == null) { return null; } /* If the new font is of an equal or higher rank, it is a * candidate to replace the current one, subject to further tests. */ if (oldFont.getRank() >= rank) { /* All fonts initialise their mapper when first * used. If the mapper is non-null then this font * has been accessed at least once. In that case * do not replace it. This may be overly stringent, * but its probably better not to replace a font that * someone is already using without a compelling reason. * Additionally the primary case where it is known * this behaviour is important is in certain composite * fonts, and since all the components of a given * composite are usually initialised together this * is unlikely. For this to be a problem, there would * have to be a case where two different composites used * different versions of the same-named font, and they * were initialised and used at separate times. * In that case we continue on and allow the new font to * be installed, but replaceFont will continue to allow * the original font to be used in Composite fonts. */ if (oldFont.mapper != null && rank > Font2D.FONT_CONFIG_RANK) { return oldFont; } /* Normally we require a higher rank to replace a font, * but as a special case, if the two fonts are the same rank, * and are instances of TrueTypeFont we want the * more complete (larger) one. */ if (oldFont.getRank() == rank) { if (oldFont instanceof TrueTypeFont && newFont instanceof TrueTypeFont) { TrueTypeFont oldTTFont = (TrueTypeFont)oldFont; TrueTypeFont newTTFont = (TrueTypeFont)newFont; if (oldTTFont.fileSize >= newTTFont.fileSize) { return oldFont; } } else { return oldFont; } } /* Don't replace ever JRE fonts. * This test is in case a font configuration references * a Lucida font, which has been mapped to a Lucida * from the host O/S. The assumption here is that any * such font configuration file is probably incorrect, or * the host O/S version is for the use of AWT. * In other words if we reach here, there's a possible * problem with our choice of font configuration fonts. */ if (oldFont.platName.startsWith(jreFontDirName)) { if (FontUtilities.isLogging()) { FontUtilities.getLogger() .warning("Unexpected attempt to replace a JRE " + " font " + fontName + " from " + oldFont.platName + " with " + newFont.platName); } return oldFont; } if (FontUtilities.isLogging()) { FontUtilities.getLogger() .info("Replace in Family " + familyName + ",Font " + fontName + " new rank="+rank + " from " + oldFont.platName + " with " + newFont.platName); } replaceFont(oldFont, newFont); physicalFonts.put(fontName, newFont); fullNameToFont.put(fontName.toLowerCase(Locale.ENGLISH), newFont); FontFamily family = FontFamily.getFamily(familyName); if (family == null) { family = new FontFamily(familyName, false, rank); family.setFont(newFont, newFont.style); } else if (family.getRank() >= rank) { family.setFont(newFont, newFont.style); } return newFont; } else { return oldFont; } } } public Font2D[] getRegisteredFonts() { PhysicalFont[] physFonts = getPhysicalFonts(); int mcf = maxCompFont; /* for MT-safety */ Font2D[] regFonts = new Font2D[physFonts.length+mcf]; System.arraycopy(compFonts, 0, regFonts, 0, mcf); System.arraycopy(physFonts, 0, regFonts, mcf, physFonts.length); return regFonts; } protected PhysicalFont[] getPhysicalFonts() { return physicalFonts.values().toArray(new PhysicalFont[0]); } /* The class FontRegistrationInfo is used when a client says not * to register a font immediately. This mechanism is used to defer * initialisation of all the components of composite fonts at JRE * start-up. The CompositeFont class is "aware" of this and when it * is first used it asks for the registration of its components. * Also in the event that any physical font is requested the * deferred fonts are initialised before triggering a search of the * system. * Two maps are used. One to track the deferred fonts. The * other to track the fonts that have been initialised through this * mechanism. */ private static final class FontRegistrationInfo { String fontFilePath; String[] nativeNames; int fontFormat; boolean javaRasterizer; int fontRank; FontRegistrationInfo(String fontPath, String[] names, int format, boolean useJavaRasterizer, int rank) { this.fontFilePath = fontPath; this.nativeNames = names; this.fontFormat = format; this.javaRasterizer = useJavaRasterizer; this.fontRank = rank; } } private final ConcurrentHashMap<String, FontRegistrationInfo> deferredFontFiles = new ConcurrentHashMap<String, FontRegistrationInfo>(); private final ConcurrentHashMap<String, Font2DHandle> initialisedFonts = new ConcurrentHashMap<String, Font2DHandle>(); /* Remind: possibly enhance initialiseDeferredFonts() to be * optionally given a name and a style and it could stop when it * finds that font - but this would be a problem if two of the * fonts reference the same font face name (cf the Solaris * euro fonts). */ protected synchronized void initialiseDeferredFonts() { for (String fileName : deferredFontFiles.keySet()) { initialiseDeferredFont(fileName); } } protected synchronized void registerDeferredJREFonts(String jreDir) { for (FontRegistrationInfo info : deferredFontFiles.values()) { if (info.fontFilePath != null && info.fontFilePath.startsWith(jreDir)) { initialiseDeferredFont(info.fontFilePath); } } } public boolean isDeferredFont(String fileName) { return deferredFontFiles.containsKey(fileName); } /* We keep a map of the files which contain the Lucida fonts so we * don't need to search for them. * But since we know what fonts these files contain, we can also avoid * opening them to look for a font name we don't recognise - see * findDeferredFont(). * For typical cases where the font isn't a JRE one the overhead is * this method call, HashMap.get() and null reference test, then * a boolean test of noOtherJREFontFiles. */ public /*private*/ PhysicalFont findJREDeferredFont(String name, int style) { PhysicalFont physicalFont; String nameAndStyle = name.toLowerCase(Locale.ENGLISH) + style; String fileName = jreFontMap.get(nameAndStyle); if (fileName != null) { fileName = jreFontDirName + File.separator + fileName; if (deferredFontFiles.get(fileName) != null) { physicalFont = initialiseDeferredFont(fileName); if (physicalFont != null && (physicalFont.getFontName(null).equalsIgnoreCase(name) || physicalFont.getFamilyName(null).equalsIgnoreCase(name)) && physicalFont.style == style) { return physicalFont; } } } /* Iterate over the deferred font files looking for any in the * jre directory that we didn't recognise, open each of these. * In almost all installations this will quickly fall through * because only the Lucidas will be present and jreOtherFontFiles * will be empty. * noOtherJREFontFiles is used so we can skip this block as soon * as its determined that its not needed - almost always after the * very first time through. */ if (noOtherJREFontFiles) { return null; } synchronized (jreLucidaFontFiles) { if (jreOtherFontFiles == null) { HashSet<String> otherFontFiles = new HashSet<String>(); for (String deferredFile : deferredFontFiles.keySet()) { File file = new File(deferredFile); String dir = file.getParent(); String fname = file.getName(); /* skip names which aren't absolute, aren't in the JRE * directory, or are known Lucida fonts. */ if (dir == null || !dir.equals(jreFontDirName) || jreLucidaFontFiles.contains(fname)) { continue; } otherFontFiles.add(deferredFile); } jreOtherFontFiles = otherFontFiles.toArray(STR_ARRAY); if (jreOtherFontFiles.length == 0) { noOtherJREFontFiles = true; } } for (int i=0; i<jreOtherFontFiles.length;i++) {