fileName = jreOtherFontFiles[i]; if (fileName == null) { continue; } jreOtherFontFiles[i] = null; physicalFont = initialiseDeferredFont(fileName); if (physicalFont != null && (physicalFont.getFontName(null).equalsIgnoreCase(name) || physicalFont.getFamilyName(null).equalsIgnoreCase(name)) && physicalFont.style == style) { return physicalFont; } } } return null; } /* This skips JRE installed fonts. */ private PhysicalFont findOtherDeferredFont(String name, int style) { for (String fileName : deferredFontFiles.keySet()) { File file = new File(fileName); String dir = file.getParent(); String fname = file.getName(); if (dir != null && dir.equals(jreFontDirName) && jreLucidaFontFiles.contains(fname)) { continue; } PhysicalFont physicalFont = initialiseDeferredFont(fileName); if (physicalFont != null && (physicalFont.getFontName(null).equalsIgnoreCase(name) || physicalFont.getFamilyName(null).equalsIgnoreCase(name)) && physicalFont.style == style) { return physicalFont; } } return null; } private PhysicalFont findDeferredFont(String name, int style) { PhysicalFont physicalFont = findJREDeferredFont(name, style); if (physicalFont != null) { return physicalFont; } else { return findOtherDeferredFont(name, style); } } public void registerDeferredFont(String fileNameKey, String fullPathName, String[] nativeNames, int fontFormat, boolean useJavaRasterizer, int fontRank) { FontRegistrationInfo regInfo = new FontRegistrationInfo(fullPathName, nativeNames, fontFormat, useJavaRasterizer, fontRank); deferredFontFiles.put(fileNameKey, regInfo); } public synchronized PhysicalFont initialiseDeferredFont(String fileNameKey) { if (fileNameKey == null) { return null; } if (FontUtilities.isLogging()) { FontUtilities.getLogger() .info("Opening deferred font file " + fileNameKey); } PhysicalFont physicalFont; FontRegistrationInfo regInfo = deferredFontFiles.get(fileNameKey); if (regInfo != null) { deferredFontFiles.remove(fileNameKey); physicalFont = registerFontFile(regInfo.fontFilePath, regInfo.nativeNames, regInfo.fontFormat, regInfo.javaRasterizer, regInfo.fontRank); if (physicalFont != null) { /* Store the handle, so that if a font is bad, we * retrieve the substituted font. */ initialisedFonts.put(fileNameKey, physicalFont.handle); } else { initialisedFonts.put(fileNameKey, getDefaultPhysicalFont().handle); } } else { Font2DHandle handle = initialisedFonts.get(fileNameKey); if (handle == null) { /* Probably shouldn't happen, but just in case */ physicalFont = getDefaultPhysicalFont(); } else { physicalFont = (PhysicalFont)(handle.font2D); } } return physicalFont; } public boolean isRegisteredFontFile(String name) { return registeredFonts.containsKey(name); } public PhysicalFont getRegisteredFontFile(String name) { return registeredFonts.get(name); } /* Note that the return value from this method is not always * derived from this file, and may be null. See addToFontList for * some explanation of this. */ public PhysicalFont registerFontFile(String fileName, String[] nativeNames, int fontFormat, boolean useJavaRasterizer, int fontRank) { PhysicalFont regFont = registeredFonts.get(fileName); if (regFont != null) { return regFont; } PhysicalFont physicalFont = null; try { String name; switch (fontFormat) { case FONTFORMAT_TRUETYPE: int fn = 0; TrueTypeFont ttf; do { ttf = new TrueTypeFont(fileName, nativeNames, fn++, useJavaRasterizer); PhysicalFont pf = addToFontList(ttf, fontRank); if (physicalFont == null) { physicalFont = pf; } } while (fn < ttf.getFontCount()); break; case FONTFORMAT_TYPE1: Type1Font t1f = new Type1Font(fileName, nativeNames); physicalFont = addToFontList(t1f, fontRank); break; case FONTFORMAT_NATIVE: NativeFont nf = new NativeFont(fileName, false); physicalFont = addToFontList(nf, fontRank); default: } if (FontUtilities.isLogging()) { FontUtilities.getLogger() .info("Registered file " + fileName + " as font " + physicalFont + " rank=" + fontRank); } } catch (FontFormatException ffe) { if (FontUtilities.isLogging()) { FontUtilities.getLogger().warning("Unusable font: " + fileName + " " + ffe.toString()); } } if (physicalFont != null && fontFormat != FONTFORMAT_NATIVE) { registeredFonts.put(fileName, physicalFont); } return physicalFont; } public void registerFonts(String[] fileNames, String[][] nativeNames, int fontCount, int fontFormat, boolean useJavaRasterizer, int fontRank, boolean defer) { for (int i=0; i < fontCount; i++) { if (defer) { registerDeferredFont(fileNames[i],fileNames[i], nativeNames[i], fontFormat, useJavaRasterizer, fontRank); } else { registerFontFile(fileNames[i], nativeNames[i], fontFormat, useJavaRasterizer, fontRank); } } } /* * This is the Physical font used when some other font on the system * can't be located. There has to be at least one font or the font * system is not useful and the graphics environment cannot sustain * the Java platform. */ public PhysicalFont getDefaultPhysicalFont() { if (defaultPhysicalFont == null) { /* findFont2D will load all fonts before giving up the search. * If the JRE Lucida isn't found (eg because the JRE fonts * directory is missing), it could find another version of Lucida * from the host system. This is OK because at that point we are * trying to gracefully handle/recover from a system * misconfiguration and this is probably a reasonable substitution. */ defaultPhysicalFont = (PhysicalFont) findFont2D("Lucida Sans Regular", Font.PLAIN, NO_FALLBACK); if (defaultPhysicalFont == null) { defaultPhysicalFont = (PhysicalFont) findFont2D("Arial", Font.PLAIN, NO_FALLBACK); } if (defaultPhysicalFont == null) { /* Because of the findFont2D call above, if we reach here, we * know all fonts have already been loaded, just accept any * match at this point. If this fails we are in real trouble * and I don't know how to recover from there being absolutely * no fonts anywhere on the system. */ Iterator i = physicalFonts.values().iterator(); if (i.hasNext()) { defaultPhysicalFont = (PhysicalFont)i.next(); } else { throw new Error("Probable fatal error:No fonts found."); } } } return defaultPhysicalFont; } public CompositeFont getDefaultLogicalFont(int style) { return (CompositeFont)findFont2D("dialog", style, NO_FALLBACK); } /* * return String representation of style prepended with "." * This is useful for performance to avoid unnecessary string operations. */ private static String dotStyleStr(int num) { switch(num){ case Font.BOLD: return ".bold"; case Font.ITALIC: return ".italic"; case Font.ITALIC | Font.BOLD: return ".bolditalic"; default: return ".plain"; } } /* This is implemented only on windows and is called from code that * executes only on windows. This isn't pretty but its not a precedent * in this file. This very probably should be cleaned up at some point. */ protected void populateFontFileNameMap(HashMap<String,String> fontToFileMap, HashMap<String,String> fontToFamilyNameMap, HashMap<String,ArrayList<String>> familyToFontListMap, Locale locale) { } /* Obtained from Platform APIs (windows only) * Map from lower-case font full name to basename of font file. * Eg "arial bold" -> ARIALBD.TTF. * For TTC files, there is a mapping for each font in the file. */ private HashMap<String,String> fontToFileMap = null; /* Obtained from Platform APIs (windows only) * Map from lower-case font full name to the name of its font family * Eg "arial bold" -> "Arial" */ private HashMap<String,String> fontToFamilyNameMap = null; /* Obtained from Platform APIs (windows only) * Map from a lower-case family name to a list of full names of * the member fonts, eg: * "arial" -> ["Arial", "Arial Bold", "Arial Italic","Arial Bold Italic"] */ private HashMap<String,ArrayList<String>> familyToFontListMap= null; /* The directories which contain platform fonts */ private String[] pathDirs = null; private boolean haveCheckedUnreferencedFontFiles; private String[] getFontFilesFromPath(boolean noType1) { final FilenameFilter filter; if (noType1) { filter = ttFilter; } else { filter = new TTorT1Filter(); } return (String[])AccessController.doPrivileged(new PrivilegedAction() { public Object run() { if (pathDirs.length == 1) { File dir = new File(pathDirs[0]); String[] files = dir.list(filter); if (files == null) { return new String[0]; } for (int f=0; f<files.length; f++) { files[f] = files[f].toLowerCase(); } return files; } else { ArrayList<String> fileList = new ArrayList<String>(); for (int i = 0; i< pathDirs.length; i++) { File dir = new File(pathDirs[i]); String[] files = dir.list(filter); if (files == null) { continue; } for (int f=0; f<files.length ; f++) { fileList.add(files[f].toLowerCase()); } } return fileList.toArray(STR_ARRAY); } } }); } /* This is needed since some windows registry names don't match * the font names. * - UPC styled font names have a double space, but the * registry entry mapping to a file doesn't. * - Marlett is in a hidden file not listed in the registry * - The registry advertises that the file david.ttf contains a * font with the full name "David Regular" when in fact its * just "David". * Directly fix up these known cases as this is faster. * If a font which doesn't match these known cases has no file, * it may be a font that has been temporarily added to the known set * or it may be an installed font with a missing registry entry. * Installed fonts are those in the windows font directories. * Make a best effort attempt to locate these. * We obtain the list of TrueType fonts in these directories and * filter out all the font files we already know about from the registry. * What remains may be "bad" fonts, duplicate fonts, or perhaps the * missing font(s) we are looking for. * Open each of these files to find out. */ private void resolveWindowsFonts() { ArrayList<String> unmappedFontNames = null; for (String font : fontToFamilyNameMap.keySet()) { String file = fontToFileMap.get(font); if (file == null) { if (font.indexOf(" ") > 0) { String newName = font.replaceFirst(" ", " "); file = fontToFileMap.get(newName); /* If this name exists and isn't for a valid name * replace the mapping to the file with this font */ if (file != null && !fontToFamilyNameMap.containsKey(newName)) { fontToFileMap.remove(newName); fontToFileMap.put(font, file); } } else if (font.equals("marlett")) { fontToFileMap.put(font, "marlett.ttf"); } else if (font.equals("david")) { file = fontToFileMap.get("david regular"); if (file != null) { fontToFileMap.remove("david regular"); fontToFileMap.put("david", file); } } else { if (unmappedFontNames == null) { unmappedFontNames = new ArrayList<String>(); } unmappedFontNames.add(font); } } } if (unmappedFontNames != null) { HashSet<String> unmappedFontFiles = new HashSet<String>(); /* Every font key in fontToFileMap ought to correspond to a * font key in fontToFamilyNameMap. Entries that don't seem * to correspond are likely fonts that were named differently * by GDI than in the registry. One known cause of this is when * Windows has had its regional settings changed so that from * GDI we get a localised (eg Chinese or Japanese) name for the * font, but the registry retains the English version of the name * that corresponded to the "install" locale for windows. * Since we are in this code block because there are unmapped * font names, we can look to find unused font->file mappings * and then open the files to read the names. We don't generally * want to open font files, as its a performance hit, but this * occurs only for a small number of fonts on specific system * configs - ie is believed that a "true" Japanese windows would * have JA names in the registry too. * Clone fontToFileMap and remove from the clone all keys which * match a fontToFamilyNameMap key. What remains maps to the * files we want to open to find the fonts GDI returned. * A font in such a file is added to the fontToFileMap after * checking its one of the unmappedFontNames we are looking for. * The original name that didn't map is removed from fontToFileMap * so essentially this "fixes up" fontToFileMap to use the same * name as GDI. * Also note that typically the fonts for which this occurs in * CJK locales are TTC fonts and not all fonts in a TTC may have * localised names. Eg MSGOTHIC.TTC contains 3 fonts and one of * them "MS UI Gothic" has no JA name whereas the other two do. * So not every font in these files is unmapped or new. */ HashMap<String,String> ffmapCopy = (HashMap<String,String>)(fontToFileMap.clone()); for (String key : fontToFamilyNameMap.keySet()) { ffmapCopy.remove(key); } for (String key : ffmapCopy.keySet()) { unmappedFontFiles.add(ffmapCopy.get(key)); fontToFileMap.remove(key); } resolveFontFiles(unmappedFontFiles, unmappedFontNames); /* If there are still unmapped font names, this means there's * something that wasn't in the registry. We need to get all * the font files directly and look at the ones that weren't * found in the registry. */ if (unmappedFontNames.size() > 0) { /* getFontFilesFromPath() returns all lower case names. * To compare we also need lower case * versions of the names from the registry. */ ArrayList<String> registryFiles = new ArrayList<String>(); for (String regFile : fontToFileMap.values()) { registryFiles.add(regFile.toLowerCase()); } /* We don't look for Type1 files here as windows will * not enumerate these, so aren't useful in reconciling * GDI's unmapped files. We do find these later when * we enumerate all fonts. */ for (String pathFile : getFontFilesFromPath(true)) { if (!registryFiles.contains(pathFile)) { unmappedFontFiles.add(pathFile); } } resolveFontFiles(unmappedFontFiles, unmappedFontNames); } /* remove from the set of names that will be returned to the * user any fonts that can't be mapped to files. */ if (unmappedFontNames.size() > 0) { int sz = unmappedFontNames.size(); for (int i=0; i<sz; i++) { String name = unmappedFontNames.get(i); String familyName = fontToFamilyNameMap.get(name); if (familyName != null) { ArrayList family = familyToFontListMap.get(familyName); if (family != null) { if (family.size() <= 1) { familyToFontListMap.remove(familyName); } } } fontToFamilyNameMap.remove(name); if (FontUtilities.isLogging()) { FontUtilities.getLogger() .info("No file for font:" + name); } } } } } /** * In some cases windows may have fonts in the fonts folder that * don't show up in the registry or in the GDI calls to enumerate fonts. * The only way to find these is to list the directory. We invoke this * only in getAllFonts/Families, so most searches for a specific * font that is satisfied by the GDI/registry calls don't take the * additional hit of listing the directory. This hit is small enough * that its not significant in these 'enumerate all the fonts' cases. * The basic approach is to cross-reference the files windows found * with the ones in the directory listing approach, and for each * in the latter list that is missing from the former list, register it. */ private synchronized void checkForUnreferencedFontFiles() { if (haveCheckedUnreferencedFontFiles) { return; }Lines 1001–1500 of 3912. Previous lines Load more
fileName = jreOtherFontFiles[i]; if (fileName == null) { continue; } jreOtherFontFiles[i] = null; physicalFont = initialiseDeferredFont(fileName); if (physicalFont != null && (physicalFont.getFontName(null).equalsIgnoreCase(name) || physicalFont.getFamilyName(null).equalsIgnoreCase(name)) && physicalFont.style == style) { return physicalFont; } } } return null; } /* This skips JRE installed fonts. */ private PhysicalFont findOtherDeferredFont(String name, int style) { for (String fileName : deferredFontFiles.keySet()) { File file = new File(fileName); String dir = file.getParent(); String fname = file.getName(); if (dir != null && dir.equals(jreFontDirName) && jreLucidaFontFiles.contains(fname)) { continue; } PhysicalFont physicalFont = initialiseDeferredFont(fileName); if (physicalFont != null && (physicalFont.getFontName(null).equalsIgnoreCase(name) || physicalFont.getFamilyName(null).equalsIgnoreCase(name)) && physicalFont.style == style) { return physicalFont; } } return null; } private PhysicalFont findDeferredFont(String name, int style) { PhysicalFont physicalFont = findJREDeferredFont(name, style); if (physicalFont != null) { return physicalFont; } else { return findOtherDeferredFont(name, style); } } public void registerDeferredFont(String fileNameKey, String fullPathName, String[] nativeNames, int fontFormat, boolean useJavaRasterizer, int fontRank) { FontRegistrationInfo regInfo = new FontRegistrationInfo(fullPathName, nativeNames, fontFormat, useJavaRasterizer, fontRank); deferredFontFiles.put(fileNameKey, regInfo); } public synchronized PhysicalFont initialiseDeferredFont(String fileNameKey) { if (fileNameKey == null) { return null; } if (FontUtilities.isLogging()) { FontUtilities.getLogger() .info("Opening deferred font file " + fileNameKey); } PhysicalFont physicalFont; FontRegistrationInfo regInfo = deferredFontFiles.get(fileNameKey); if (regInfo != null) { deferredFontFiles.remove(fileNameKey); physicalFont = registerFontFile(regInfo.fontFilePath, regInfo.nativeNames, regInfo.fontFormat, regInfo.javaRasterizer, regInfo.fontRank); if (physicalFont != null) { /* Store the handle, so that if a font is bad, we * retrieve the substituted font. */ initialisedFonts.put(fileNameKey, physicalFont.handle); } else { initialisedFonts.put(fileNameKey, getDefaultPhysicalFont().handle); } } else { Font2DHandle handle = initialisedFonts.get(fileNameKey); if (handle == null) { /* Probably shouldn't happen, but just in case */ physicalFont = getDefaultPhysicalFont(); } else { physicalFont = (PhysicalFont)(handle.font2D); } } return physicalFont; } public boolean isRegisteredFontFile(String name) { return registeredFonts.containsKey(name); } public PhysicalFont getRegisteredFontFile(String name) { return registeredFonts.get(name); } /* Note that the return value from this method is not always * derived from this file, and may be null. See addToFontList for * some explanation of this. */ public PhysicalFont registerFontFile(String fileName, String[] nativeNames, int fontFormat, boolean useJavaRasterizer, int fontRank) { PhysicalFont regFont = registeredFonts.get(fileName); if (regFont != null) { return regFont; } PhysicalFont physicalFont = null; try { String name; switch (fontFormat) { case FONTFORMAT_TRUETYPE: int fn = 0; TrueTypeFont ttf; do { ttf = new TrueTypeFont(fileName, nativeNames, fn++, useJavaRasterizer); PhysicalFont pf = addToFontList(ttf, fontRank); if (physicalFont == null) { physicalFont = pf; } } while (fn < ttf.getFontCount()); break; case FONTFORMAT_TYPE1: Type1Font t1f = new Type1Font(fileName, nativeNames); physicalFont = addToFontList(t1f, fontRank); break; case FONTFORMAT_NATIVE: NativeFont nf = new NativeFont(fileName, false); physicalFont = addToFontList(nf, fontRank); default: } if (FontUtilities.isLogging()) { FontUtilities.getLogger() .info("Registered file " + fileName + " as font " + physicalFont + " rank=" + fontRank); } } catch (FontFormatException ffe) { if (FontUtilities.isLogging()) { FontUtilities.getLogger().warning("Unusable font: " + fileName + " " + ffe.toString()); } } if (physicalFont != null && fontFormat != FONTFORMAT_NATIVE) { registeredFonts.put(fileName, physicalFont); } return physicalFont; } public void registerFonts(String[] fileNames, String[][] nativeNames, int fontCount, int fontFormat, boolean useJavaRasterizer, int fontRank, boolean defer) { for (int i=0; i < fontCount; i++) { if (defer) { registerDeferredFont(fileNames[i],fileNames[i], nativeNames[i], fontFormat, useJavaRasterizer, fontRank); } else { registerFontFile(fileNames[i], nativeNames[i], fontFormat, useJavaRasterizer, fontRank); } } } /* * This is the Physical font used when some other font on the system * can't be located. There has to be at least one font or the font * system is not useful and the graphics environment cannot sustain * the Java platform. */ public PhysicalFont getDefaultPhysicalFont() { if (defaultPhysicalFont == null) { /* findFont2D will load all fonts before giving up the search. * If the JRE Lucida isn't found (eg because the JRE fonts * directory is missing), it could find another version of Lucida * from the host system. This is OK because at that point we are * trying to gracefully handle/recover from a system * misconfiguration and this is probably a reasonable substitution. */ defaultPhysicalFont = (PhysicalFont) findFont2D("Lucida Sans Regular", Font.PLAIN, NO_FALLBACK); if (defaultPhysicalFont == null) { defaultPhysicalFont = (PhysicalFont) findFont2D("Arial", Font.PLAIN, NO_FALLBACK); } if (defaultPhysicalFont == null) { /* Because of the findFont2D call above, if we reach here, we * know all fonts have already been loaded, just accept any * match at this point. If this fails we are in real trouble * and I don't know how to recover from there being absolutely * no fonts anywhere on the system. */ Iterator i = physicalFonts.values().iterator(); if (i.hasNext()) { defaultPhysicalFont = (PhysicalFont)i.next(); } else { throw new Error("Probable fatal error:No fonts found."); } } } return defaultPhysicalFont; } public CompositeFont getDefaultLogicalFont(int style) { return (CompositeFont)findFont2D("dialog", style, NO_FALLBACK); } /* * return String representation of style prepended with "." * This is useful for performance to avoid unnecessary string operations. */ private static String dotStyleStr(int num) { switch(num){ case Font.BOLD: return ".bold"; case Font.ITALIC: return ".italic"; case Font.ITALIC | Font.BOLD: return ".bolditalic"; default: return ".plain"; } } /* This is implemented only on windows and is called from code that * executes only on windows. This isn't pretty but its not a precedent * in this file. This very probably should be cleaned up at some point. */ protected void populateFontFileNameMap(HashMap<String,String> fontToFileMap, HashMap<String,String> fontToFamilyNameMap, HashMap<String,ArrayList<String>> familyToFontListMap, Locale locale) { } /* Obtained from Platform APIs (windows only) * Map from lower-case font full name to basename of font file. * Eg "arial bold" -> ARIALBD.TTF. * For TTC files, there is a mapping for each font in the file. */ private HashMap<String,String> fontToFileMap = null; /* Obtained from Platform APIs (windows only) * Map from lower-case font full name to the name of its font family * Eg "arial bold" -> "Arial" */ private HashMap<String,String> fontToFamilyNameMap = null; /* Obtained from Platform APIs (windows only) * Map from a lower-case family name to a list of full names of * the member fonts, eg: * "arial" -> ["Arial", "Arial Bold", "Arial Italic","Arial Bold Italic"] */ private HashMap<String,ArrayList<String>> familyToFontListMap= null; /* The directories which contain platform fonts */ private String[] pathDirs = null; private boolean haveCheckedUnreferencedFontFiles; private String[] getFontFilesFromPath(boolean noType1) { final FilenameFilter filter; if (noType1) { filter = ttFilter; } else { filter = new TTorT1Filter(); } return (String[])AccessController.doPrivileged(new PrivilegedAction() { public Object run() { if (pathDirs.length == 1) { File dir = new File(pathDirs[0]); String[] files = dir.list(filter); if (files == null) { return new String[0]; } for (int f=0; f<files.length; f++) { files[f] = files[f].toLowerCase(); } return files; } else { ArrayList<String> fileList = new ArrayList<String>(); for (int i = 0; i< pathDirs.length; i++) { File dir = new File(pathDirs[i]); String[] files = dir.list(filter); if (files == null) { continue; } for (int f=0; f<files.length ; f++) { fileList.add(files[f].toLowerCase()); } } return fileList.toArray(STR_ARRAY); } } }); } /* This is needed since some windows registry names don't match * the font names. * - UPC styled font names have a double space, but the * registry entry mapping to a file doesn't. * - Marlett is in a hidden file not listed in the registry * - The registry advertises that the file david.ttf contains a * font with the full name "David Regular" when in fact its * just "David". * Directly fix up these known cases as this is faster. * If a font which doesn't match these known cases has no file, * it may be a font that has been temporarily added to the known set * or it may be an installed font with a missing registry entry. * Installed fonts are those in the windows font directories. * Make a best effort attempt to locate these. * We obtain the list of TrueType fonts in these directories and * filter out all the font files we already know about from the registry. * What remains may be "bad" fonts, duplicate fonts, or perhaps the * missing font(s) we are looking for. * Open each of these files to find out. */ private void resolveWindowsFonts() { ArrayList<String> unmappedFontNames = null; for (String font : fontToFamilyNameMap.keySet()) { String file = fontToFileMap.get(font); if (file == null) { if (font.indexOf(" ") > 0) { String newName = font.replaceFirst(" ", " "); file = fontToFileMap.get(newName); /* If this name exists and isn't for a valid name * replace the mapping to the file with this font */ if (file != null && !fontToFamilyNameMap.containsKey(newName)) { fontToFileMap.remove(newName); fontToFileMap.put(font, file); } } else if (font.equals("marlett")) { fontToFileMap.put(font, "marlett.ttf"); } else if (font.equals("david")) { file = fontToFileMap.get("david regular"); if (file != null) { fontToFileMap.remove("david regular"); fontToFileMap.put("david", file); } } else { if (unmappedFontNames == null) { unmappedFontNames = new ArrayList<String>(); } unmappedFontNames.add(font); } } } if (unmappedFontNames != null) { HashSet<String> unmappedFontFiles = new HashSet<String>(); /* Every font key in fontToFileMap ought to correspond to a * font key in fontToFamilyNameMap. Entries that don't seem * to correspond are likely fonts that were named differently * by GDI than in the registry. One known cause of this is when * Windows has had its regional settings changed so that from * GDI we get a localised (eg Chinese or Japanese) name for the * font, but the registry retains the English version of the name * that corresponded to the "install" locale for windows. * Since we are in this code block because there are unmapped * font names, we can look to find unused font->file mappings * and then open the files to read the names. We don't generally * want to open font files, as its a performance hit, but this * occurs only for a small number of fonts on specific system * configs - ie is believed that a "true" Japanese windows would * have JA names in the registry too. * Clone fontToFileMap and remove from the clone all keys which * match a fontToFamilyNameMap key. What remains maps to the * files we want to open to find the fonts GDI returned. * A font in such a file is added to the fontToFileMap after * checking its one of the unmappedFontNames we are looking for. * The original name that didn't map is removed from fontToFileMap * so essentially this "fixes up" fontToFileMap to use the same * name as GDI. * Also note that typically the fonts for which this occurs in * CJK locales are TTC fonts and not all fonts in a TTC may have * localised names. Eg MSGOTHIC.TTC contains 3 fonts and one of * them "MS UI Gothic" has no JA name whereas the other two do. * So not every font in these files is unmapped or new. */ HashMap<String,String> ffmapCopy = (HashMap<String,String>)(fontToFileMap.clone()); for (String key : fontToFamilyNameMap.keySet()) { ffmapCopy.remove(key); } for (String key : ffmapCopy.keySet()) { unmappedFontFiles.add(ffmapCopy.get(key)); fontToFileMap.remove(key); } resolveFontFiles(unmappedFontFiles, unmappedFontNames); /* If there are still unmapped font names, this means there's * something that wasn't in the registry. We need to get all * the font files directly and look at the ones that weren't * found in the registry. */ if (unmappedFontNames.size() > 0) { /* getFontFilesFromPath() returns all lower case names. * To compare we also need lower case * versions of the names from the registry. */ ArrayList<String> registryFiles = new ArrayList<String>(); for (String regFile : fontToFileMap.values()) { registryFiles.add(regFile.toLowerCase()); } /* We don't look for Type1 files here as windows will * not enumerate these, so aren't useful in reconciling * GDI's unmapped files. We do find these later when * we enumerate all fonts. */ for (String pathFile : getFontFilesFromPath(true)) { if (!registryFiles.contains(pathFile)) { unmappedFontFiles.add(pathFile); } } resolveFontFiles(unmappedFontFiles, unmappedFontNames); } /* remove from the set of names that will be returned to the * user any fonts that can't be mapped to files. */ if (unmappedFontNames.size() > 0) { int sz = unmappedFontNames.size(); for (int i=0; i<sz; i++) { String name = unmappedFontNames.get(i); String familyName = fontToFamilyNameMap.get(name); if (familyName != null) { ArrayList family = familyToFontListMap.get(familyName); if (family != null) { if (family.size() <= 1) { familyToFontListMap.remove(familyName); } } } fontToFamilyNameMap.remove(name); if (FontUtilities.isLogging()) { FontUtilities.getLogger() .info("No file for font:" + name); } } } } } /** * In some cases windows may have fonts in the fonts folder that * don't show up in the registry or in the GDI calls to enumerate fonts. * The only way to find these is to list the directory. We invoke this * only in getAllFonts/Families, so most searches for a specific * font that is satisfied by the GDI/registry calls don't take the * additional hit of listing the directory. This hit is small enough * that its not significant in these 'enumerate all the fonts' cases. * The basic approach is to cross-reference the files windows found * with the ones in the directory listing approach, and for each * in the latter list that is missing from the former list, register it. */ private synchronized void checkForUnreferencedFontFiles() { if (haveCheckedUnreferencedFontFiles) { return; }