Unregister font with GraphicsEnvironment?

I recently learned how to register a TTF font with a local GraphicsEnvironment, st, for my use case (SVG-PNG transcoding), Apache Batik can recognize the font:

import java.awt.Font; import java.awt.FontFormatException; import java.awt.GraphicsEnvironment; // [...] GraphicsEnvironment lge = GraphicsEnvironment.getLocalGraphicsEnvironment(); try { Font font = Font.createFont(Font.TRUETYPE_FONT, fontFile); lge.registerFont(font); } catch (FontFormatException e) { logger.warn(e.getMessage(), e); } catch (IOException e) { logger.warn(e.getMessage(), e); } 

However, I was wondering if I can unregister previously existing fonts to ensure that only registered fonts will be used in transcoding.

GraphicsEnvironment # unregisterFont (...) does not exist, how can I do this?

PS: I do not want to subclass GraphicsEnvironment, since I cannot assume that there is any particular subclass, for example sun.awt.Win32GraphicsEnvironment.

EDIT: Additional Information:

  • As sun.font.FontManager is modified using Java7 (from class to interface and much more), I would prefer not to use a workaround based on it.
  • My JVM is an Oracle JVM.
+7
java fonts awt batik
source share
1 answer

This cannot be done without reflecting private static variables and such ... are you sure you need to do this?

Check the source code on sun.font.FontManager.registerFont , it may already have the security you need. (This is the method that does the actual work when calling GraphicsEnvironment.registerFont )

 public boolean registerFont(Font font) { /* This method should not be called with "null". * It is the caller responsibility to ensure that. */ if (font == null) { return false; } /* Initialise these objects only once we start to use this API */ synchronized (regFamilyKey) { if (createdByFamilyName == null) { createdByFamilyName = new Hashtable<String,FontFamily>(); createdByFullName = new Hashtable<String,Font2D>(); } } if (! FontAccess.getFontAccess().isCreatedFont(font)) { return false; } /* We want to ensure that this font cannot override existing * installed fonts. Check these conditions : * - family name is not that of an installed font * - full name is not that of an installed font * - family name is not the same as the full name of an installed font * - full name is not the same as the family name of an installed font * The last two of these may initially look odd but the reason is * that (unfortunately) Font constructors do not distinuguish these. * An extreme example of such a problem would be a font which has * family name "Dialog.Plain" and full name of "Dialog". * The one arguably overly stringent restriction here is that if an * application wants to supply a new member of an existing family * It will get rejected. But since the JRE can perform synthetic * styling in many cases its not necessary. * We don't apply the same logic to registered fonts. If apps want * to do this lets assume they have a reason. It won't cause problems * except for themselves. */ HashSet<String> names = getInstalledNames(); Locale l = getSystemStartupLocale(); String familyName = font.getFamily(l).toLowerCase(); String fullName = font.getFontName(l).toLowerCase(); if (names.contains(familyName) || names.contains(fullName)) { return false; } /* Checks passed, now register the font */ Hashtable<String,FontFamily> familyTable; Hashtable<String,Font2D> fullNameTable; if (!maybeMultiAppContext()) { familyTable = createdByFamilyName; fullNameTable = createdByFullName; fontsAreRegistered = true; } else { AppContext appContext = AppContext.getAppContext(); familyTable = (Hashtable<String,FontFamily>)appContext.get(regFamilyKey); fullNameTable = (Hashtable<String,Font2D>)appContext.get(regFullNameKey); if (familyTable == null) { familyTable = new Hashtable<String,FontFamily>(); fullNameTable = new Hashtable<String,Font2D>(); appContext.put(regFamilyKey, familyTable); appContext.put(regFullNameKey, fullNameTable); } fontsAreRegisteredPerAppContext = true; } /* Create the FontFamily and add font to the tables */ Font2D font2D = FontUtilities.getFont2D(font); int style = font2D.getStyle(); FontFamily family = familyTable.get(familyName); if (family == null) { family = new FontFamily(font.getFamily(l)); familyTable.put(familyName, family); } /* Remove name cache entries if not using app contexts. * To accommodate a case where code may have registered first a plain * family member and then used it and is now registering a bold family * member, we need to remove all members of the family, so that the * new style can get picked up rather than continuing to synthesise. */ if (fontsAreRegistered) { removeFromCache(family.getFont(Font.PLAIN)); removeFromCache(family.getFont(Font.BOLD)); removeFromCache(family.getFont(Font.ITALIC)); removeFromCache(family.getFont(Font.BOLD|Font.ITALIC)); removeFromCache(fullNameTable.get(fullName)); } family.setFont(font2D, style); fullNameTable.put(fullName, font2D); return true; } 
+4
source share

All Articles