3912 lines · 165.2 KB · Java
RawDownload
                                files = tmpFontFiles.toArray(files);                                for (int f=0; f<files.length;f++) {                                    try {                                        files[f].delete();                                    } catch (Exception e) {                                    }                                }                            }                             return null;                          }                           });                      }                    };                    java.security.AccessController.doPrivileged(                       new java.security.PrivilegedAction() {                          public Object run() {                              /* The thread must be a member of a thread group                               * which will not get GCed before VM exit.                               * Make its parent the top-level thread group.                               */                              ThreadGroup tg =                                  Thread.currentThread().getThreadGroup();                              for (ThreadGroup tgn = tg;                                   tgn != null;                                   tg = tgn, tgn = tg.getParent());                              fileCloser = new Thread(tg, fileCloserRunnable);                              fileCloser.setContextClassLoader(null);                              Runtime.getRuntime().addShutdownHook(fileCloser);                              return null;                          }                    });                }            }        }        return font2D;    }     /* remind: used in X11GraphicsEnvironment and called often enough     * that we ought to obsolete this code     */    public synchronized String getFullNameByFileName(String fileName) {        PhysicalFont[] physFonts = getPhysicalFonts();        for (int i=0;i<physFonts.length;i++) {            if (physFonts[i].platName.equals(fileName)) {                return (physFonts[i].getFontName(null));            }        }        return null;    }     /*     * This is called when font is determined to be invalid/bad.     * It designed to be called (for example) by the font scaler     * when in processing a font file it is discovered to be incorrect.     * This is different than the case where fonts are discovered to     * be incorrect during initial verification, as such fonts are     * never registered.     * Handles to this font held are re-directed to a default font.     * This default may not be an ideal substitute buts it better than     * crashing This code assumes a PhysicalFont parameter as it doesn't     * make sense for a Composite to be "bad".     */    public synchronized void deRegisterBadFont(Font2D font2D) {        if (!(font2D instanceof PhysicalFont)) {            /* We should never reach here, but just in case */            return;        } else {            if (FontUtilities.isLogging()) {                FontUtilities.getLogger()                                     .severe("Deregister bad font: " + font2D);            }            replaceFont((PhysicalFont)font2D, getDefaultPhysicalFont());        }    }     /*     * This encapsulates all the work that needs to be done when a     * Font2D is replaced by a different Font2D.     */    public synchronized void replaceFont(PhysicalFont oldFont,                                         PhysicalFont newFont) {         if (oldFont.handle.font2D != oldFont) {            /* already done */            return;        }         /* If we try to replace the font with itself, that won't work,         * so pick any alternative physical font         */        if (oldFont == newFont) {            if (FontUtilities.isLogging()) {                FontUtilities.getLogger()                      .severe("Can't replace bad font with itself " + oldFont);            }            PhysicalFont[] physFonts = getPhysicalFonts();            for (int i=0; i<physFonts.length;i++) {                if (physFonts[i] != newFont) {                    newFont = physFonts[i];                    break;                }            }            if (oldFont == newFont) {                if (FontUtilities.isLogging()) {                    FontUtilities.getLogger()                           .severe("This is bad. No good physicalFonts found.");                }                return;            }        }         /* eliminate references to this font, so it won't be located         * by future callers, and will be eligible for GC when all         * references are removed         */        oldFont.handle.font2D = newFont;        physicalFonts.remove(oldFont.fullName);        fullNameToFont.remove(oldFont.fullName.toLowerCase(Locale.ENGLISH));        FontFamily.remove(oldFont);         if (localeFullNamesToFont != null) {            Map.Entry[] mapEntries =                (Map.Entry[])localeFullNamesToFont.entrySet().                toArray(new Map.Entry[0]);            /* Should I be replacing these, or just I just remove             * the names from the map?             */            for (int i=0; i<mapEntries.length;i++) {                if (mapEntries[i].getValue() == oldFont) {                    try {                        mapEntries[i].setValue(newFont);                    } catch (Exception e) {                        /* some maps don't support this operation.                         * In this case just give up and remove the entry.                         */                        localeFullNamesToFont.remove(mapEntries[i].getKey());                    }                }            }        }         for (int i=0; i<maxCompFont; i++) {            /* Deferred initialization of composites shouldn't be             * a problem for this case, since a font must have been             * initialised to be discovered to be bad.             * Some JRE composites on Solaris use two versions of the same             * font. The replaced font isn't bad, just "smaller" so there's             * no need to make the slot point to the new font.             * Since composites have a direct reference to the Font2D (not             * via a handle) making this substitution is not safe and could             * cause an additional problem and so this substitution is             * warranted only when a font is truly "bad" and could cause             * a crash. So we now replace it only if its being substituted             * with some font other than a fontconfig rank font             * Since in practice a substitution will have the same rank             * this may never happen, but the code is safer even if its             * also now a no-op.             * The only obvious "glitch" from this stems from the current             * implementation that when asked for the number of glyphs in a             * composite it lies and returns the number in slot 0 because             * composite glyphs aren't contiguous. Since we live with that             * we can live with the glitch that depending on how it was             * initialised a composite may return different values for this.             * Fixing the issues with composite glyph ids is tricky as             * there are exclusion ranges and unlike other fonts even the             * true "numGlyphs" isn't a contiguous range. Likely the only             * solution is an API that returns an array of glyph ranges             * which takes precedence over the existing API. That might             * also need to address excluding ranges which represent a             * code point supported by an earlier component.             */            if (newFont.getRank() > Font2D.FONT_CONFIG_RANK) {                compFonts[i].replaceComponentFont(oldFont, newFont);            }        }    }     private synchronized void loadLocaleNames() {        if (localeFullNamesToFont != null) {            return;        }        localeFullNamesToFont = new HashMap<String, TrueTypeFont>();        Font2D[] fonts = getRegisteredFonts();        for (int i=0; i<fonts.length; i++) {            if (fonts[i] instanceof TrueTypeFont) {                TrueTypeFont ttf = (TrueTypeFont)fonts[i];                String[] fullNames = ttf.getAllFullNames();                for (int n=0; n<fullNames.length; n++) {                    localeFullNamesToFont.put(fullNames[n], ttf);                }                FontFamily family = FontFamily.getFamily(ttf.familyName);                if (family != null) {                    FontFamily.addLocaleNames(family, ttf.getAllFamilyNames());                }            }        }    }     /* This replicate the core logic of findFont2D but operates on     * all the locale names. This hasn't been merged into findFont2D to     * keep the logic simpler and reduce overhead, since this case is     * almost never used. The main case in which it is called is when     * a bogus font name is used and we need to check all possible names     * before returning the default case.     */    private Font2D findFont2DAllLocales(String name, int style) {         if (FontUtilities.isLogging()) {            FontUtilities.getLogger()                           .info("Searching localised font names for:" + name);        }         /* If reach here and no match has been located, then if we have         * not yet built the map of localeFullNamesToFont for TT fonts, do so         * now. This method must be called after all fonts have been loaded.         */        if (localeFullNamesToFont == null) {            loadLocaleNames();        }        String lowerCaseName = name.toLowerCase();        Font2D font = null;         /* First see if its a family name. */        FontFamily family = FontFamily.getLocaleFamily(lowerCaseName);        if (family != null) {          font = family.getFont(style);          if (font == null) {            font = family.getClosestStyle(style);          }          if (font != null) {              return font;          }        }         /* If it wasn't a family name, it should be a full name. */        synchronized (this) {            font = localeFullNamesToFont.get(name);        }        if (font != null) {            if (font.style == style || style == Font.PLAIN) {                return font;            } else {                family = FontFamily.getFamily(font.getFamilyName(null));                if (family != null) {                    Font2D familyFont = family.getFont(style);                    /* We exactly matched the requested style, use it! */                    if (familyFont != null) {                        return familyFont;                    } else {                        familyFont = family.getClosestStyle(style);                        if (familyFont != null) {                            /* The next check is perhaps one                             * that shouldn't be done. ie if we get this                             * far we have probably as close a match as we                             * are going to get. We could load all fonts to                             * see if somehow some parts of the family are                             * loaded but not all of it.                             * This check is commented out for now.                             */                            if (!familyFont.canDoStyle(style)) {                                familyFont = null;                            }                            return familyFont;                        }                    }                }            }        }        return font;    }     /* Supporting "alternate" composite fonts on 2D graphics objects     * is accessed by the application by calling methods on the local     * GraphicsEnvironment. The overall implementation is described     * in one place, here, since otherwise the implementation is spread     * around it may be difficult to track.     * The methods below call into SunGraphicsEnvironment which creates a     * new FontConfiguration instance. The FontConfiguration class,     * and its platform sub-classes are updated to take parameters requesting     * these behaviours. This is then used to create new composite font     * instances. Since this calls the initCompositeFont method in     * SunGraphicsEnvironment it performs the same initialization as is     * performed normally. There may be some duplication of effort, but     * that code is already written to be able to perform properly if called     * to duplicate work. The main difference is that if we detect we are     * running in an applet/browser/Java plugin environment these new fonts     * are not placed in the "default" maps but into an AppContext instance.     * The font lookup mechanism in java.awt.Font.getFont2D() is also updated     * so that look-up for composite fonts will in that case always     * do a lookup rather than returning a cached result.     * This is inefficient but necessary else singleton java.awt.Font     * instances would not retrieve the correct Font2D for the appcontext.     * sun.font.FontManager.findFont2D is also updated to that it uses     * a name map cache specific to that appcontext.     *     * Getting an AppContext is expensive, so there is a global variable     * that records whether these methods have ever been called and can     * avoid the expense for almost all applications. Once the correct     * CompositeFont is associated with the Font, everything should work     * through existing mechanisms.     * A special case is that GraphicsEnvironment.getAllFonts() must     * return an AppContext specific list.     *     * Calling the methods below is "heavyweight" but it is expected that     * these methods will be called very rarely.     *     * If _usingPerAppContextComposites is true, we are in "applet"     * (eg browser) enviroment and at least one context has selected     * an alternate composite font behaviour.     * If _usingAlternateComposites is true, we are not in an "applet"     * environment and the (single) application has selected     * an alternate composite font behaviour.     *     * - Printing: The implementation delegates logical fonts to an AWT     * mechanism which cannot use these alternate configurations.     * We can detect that alternate fonts are in use and back-off to 2D, but     * that uses outlines. Much of this can be fixed with additional work     * but that may have to wait. The results should be correct, just not     * optimal.     */    private static final Object altJAFontKey       = new Object();    private static final Object localeFontKey       = new Object();    private static final Object proportionalFontKey = new Object();    private boolean _usingPerAppContextComposites = false;    private boolean _usingAlternateComposites = false;     /* These values are used only if we are running as a standalone     * application, as determined by maybeMultiAppContext();     */    private static boolean gAltJAFont = false;    private boolean gLocalePref = false;    private boolean gPropPref = false;     /* This method doesn't check if alternates are selected in this app     * context. Its used by the FontMetrics caching code which in such     * a case cannot retrieve a cached metrics solely on the basis of     * the Font.equals() method since it needs to also check if the Font2D     * is the same.     * We also use non-standard composites for Swing native L&F fonts on     * Windows. In that case the policy is that the metrics reported are     * based solely on the physical font in the first slot which is the     * visible java.awt.Font. So in that case the metrics cache which tests     * the Font does what we want. In the near future when we expand the GTK     * logical font definitions we may need to revisit this if GTK reports     * combined metrics instead. For now though this test can be simple.     */    public boolean maybeUsingAlternateCompositeFonts() {       return _usingAlternateComposites || _usingPerAppContextComposites;    }     public boolean usingAlternateCompositeFonts() {        return (_usingAlternateComposites ||                (_usingPerAppContextComposites &&                AppContext.getAppContext().get(CompositeFont.class) != null));    }     private static boolean maybeMultiAppContext() {        Boolean appletSM = (Boolean)            java.security.AccessController.doPrivileged(                new java.security.PrivilegedAction() {                        public Object run() {                            SecurityManager sm = System.getSecurityManager();                            return new Boolean                                (sm instanceof sun.applet.AppletSecurity);                        }                    });        return appletSM.booleanValue();    }     /* Modifies the behaviour of a subsequent call to preferLocaleFonts()     * to use Mincho instead of Gothic for dialoginput in JA locales     * on windows. Not needed on other platforms.     */    public synchronized void useAlternateFontforJALocales() {        if (FontUtilities.isLogging()) {            FontUtilities.getLogger()                .info("Entered useAlternateFontforJALocales().");        }        if (!FontUtilities.isWindows) {            return;        }         if (!maybeMultiAppContext()) {            gAltJAFont = true;        } else {            AppContext appContext = AppContext.getAppContext();            appContext.put(altJAFontKey, altJAFontKey);        }    }     public boolean usingAlternateFontforJALocales() {        if (!maybeMultiAppContext()) {            return gAltJAFont;        } else {            AppContext appContext = AppContext.getAppContext();            return appContext.get(altJAFontKey) == altJAFontKey;        }    }     public synchronized void preferLocaleFonts() {        if (FontUtilities.isLogging()) {            FontUtilities.getLogger().info("Entered preferLocaleFonts().");        }        /* Test if re-ordering will have any effect */        if (!FontConfiguration.willReorderForStartupLocale()) {            return;        }         if (!maybeMultiAppContext()) {            if (gLocalePref == true) {                return;            }            gLocalePref = true;            createCompositeFonts(fontNameCache, gLocalePref, gPropPref);            _usingAlternateComposites = true;        } else {            AppContext appContext = AppContext.getAppContext();            if (appContext.get(localeFontKey) == localeFontKey) {                return;            }            appContext.put(localeFontKey, localeFontKey);            boolean acPropPref =                appContext.get(proportionalFontKey) == proportionalFontKey;            ConcurrentHashMap<String, Font2D>                altNameCache = new ConcurrentHashMap<String, Font2D> ();            /* If there is an existing hashtable, we can drop it. */            appContext.put(CompositeFont.class, altNameCache);            _usingPerAppContextComposites = true;            createCompositeFonts(altNameCache, true, acPropPref);        }    }     public synchronized void preferProportionalFonts() {        if (FontUtilities.isLogging()) {            FontUtilities.getLogger()                .info("Entered preferProportionalFonts().");        }        /* If no proportional fonts are configured, there's no need         * to take any action.         */        if (!FontConfiguration.hasMonoToPropMap()) {            return;        }         if (!maybeMultiAppContext()) {            if (gPropPref == true) {                return;            }            gPropPref = true;            createCompositeFonts(fontNameCache, gLocalePref, gPropPref);            _usingAlternateComposites = true;        } else {            AppContext appContext = AppContext.getAppContext();            if (appContext.get(proportionalFontKey) == proportionalFontKey) {                return;            }            appContext.put(proportionalFontKey, proportionalFontKey);            boolean acLocalePref =                appContext.get(localeFontKey) == localeFontKey;            ConcurrentHashMap<String, Font2D>                altNameCache = new ConcurrentHashMap<String, Font2D> ();            /* If there is an existing hashtable, we can drop it. */            appContext.put(CompositeFont.class, altNameCache);            _usingPerAppContextComposites = true;            createCompositeFonts(altNameCache, acLocalePref, true);        }    }     private static HashSet<String> installedNames = null;    private static HashSet<String> getInstalledNames() {        if (installedNames == null) {           Locale l = getSystemStartupLocale();           SunFontManager fontManager = SunFontManager.getInstance();           String[] installedFamilies =               fontManager.getInstalledFontFamilyNames(l);           Font[] installedFonts = fontManager.getAllInstalledFonts();           HashSet<String> names = new HashSet<String>();           for (int i=0; i<installedFamilies.length; i++) {               names.add(installedFamilies[i].toLowerCase(l));           }           for (int i=0; i<installedFonts.length; i++) {               names.add(installedFonts[i].getFontName(l).toLowerCase(l));           }           installedNames = names;        }        return installedNames;    }     /* Keys are used to lookup per-AppContext Hashtables */    private static final Object regFamilyKey  = new Object();    private static final Object regFullNameKey = new Object();    private Hashtable<String,FontFamily> createdByFamilyName;    private Hashtable<String,Font2D>     createdByFullName;    private boolean fontsAreRegistered = false;    private boolean fontsAreRegisteredPerAppContext = false;     public boolean registerFont(Font font) {        /* This method should not be called with "null".

Lines 2501–3000 of 3912. Previous lines