JDK-4795932 : RFE: Java 2D should locate fonts by using the windows registry
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 6
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2002-12-18
  • Updated: 2004-09-07
  • Resolved: 2004-09-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6
6 mustangFixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Description

Name: jk109818			Date: 12/18/2002


FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)

FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
Java can't use Fonts in Windows which have been installed,
but not copied to the system fonts directory (see the
closed BUG 4234839). This should at least be documented
(with GraphicsEnvironment.getAllFonts) if you are unwilling
to fix it. As it is the result can be surprising to the
user (and developers).
On my system the full list of installed fonts can be found
under the registry key HKLM\Software\Microsoft\Windows
NT\CurrentVersion\Fonts
This list includes both the font name and the filename
(which is a full path for those not in the system
directory).

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Add any font but deselect the 'copy' checkbox.
2. Look at the list of fonts available in any Java
application that uses fonts. The added font will be missing.
3.

EXPECTED VERSUS ACTUAL BEHAVIOR :
The list of available fonts should have been complete.

This bug can be reproduced always.

CUSTOMER WORKAROUND :
Ensure that all required fonts are copied to the system
font directory.
Ensure that all users are aware of this requirement.
(Review ID: 147059) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mustang FIXED IN: mustang INTEGRATED IN: mustang
08-09-2004

EVALUATION The javadoc generated API docs is not the right place to document a platform specific implementation note. Any documentation of the locations used by JRE (as noted in 4234839) would be better to be in platform-specific release notes. As noted in 4234839 we are open to trying to find fonts in additional locations, its just not clear how big the need and benefit is to justify the change. There have been few requests for this feature. So realistically this probably won't get implemented for 1.5 which places it a long way off. Also application-supplied fonts have the potential for being less conformant than platform-supplied fonts which opens the door to needing to add more robustness features before adding this feature. I will keep this open (as an RFE) until we can decide if there is the time to implement it in the 1.5 release. If we don't we can hand this off to ask the doc team to see if the release notes can include some explanation of the probable locations fonts will be found from. ###@###.### 2002-12-18 ============================ A fix has been implemented for this which is targeted for a release after tiger (1.5). The primary motivation for the fix is that its fairly common to request a font that is present on the system, particularly for something like the Swing Windows L&F, where the requested font is not one that is typically used by JDK, so triggering an expensive search of system fonts. But we can accelerate this operation greatly by using a combination of windows font enumeration APIS and the font->file mappings in the windows registry. Requesting a font such as "Tahoma" can now very quickly be mapped to the right font, and request to enumerate all font families for the default locale, using GraphicsEnvironment.getAvailableFontFamilyNames() will both execute much more quickly. But the windows APIs don't do a "full search", since the registry mappings typically use the English names, or the system locale names, and the enumeration APIs return the same, so requests for fonts which don't exist can still trigger the old more thorough search. This is established behaviour and in any case JDK has APIs to request the name of a font localised to a particular locale. So the only slight downside is for an app that asks for some font which really doesn't exist this is a small additional overhead, but its so small its not going to be noticeable, but it does mean that we cannot completely do away with the slower process. A side-effect is that fonts that are not in the windows system directory are now available too. This was the original focus of this RFE. The performance boost is substantial and improves the fixed start-up cost of the Swing Windows L&F. Of course the perceived benefits will vary somewhat depending on whether you are measuring these in a microbenchmark, or a large app (eg netbeans), and if the latter type of app, whether it in any case triggers the old behaviour. The number of fonts installed on a system is also a significant factor. Systems with very few fonts will still benefit, but not nearly as much as systems with a larger number of fonts. So the following should be taken with that cautionary note : On a 1.7Ghz P4 system with 256 Mb RAM, running Windows XP, this program : public class GAFF { public static void main(String args[]) { long t0 =System.currentTimeMillis(); GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); String[] all = ge.getAvailableFontFamilyNames(); long t1 =System.currentTimeMillis(); System.out.println("time=" + (t1-t0)+"ms"); } } executed the body of "main" in approx 625ms on JDK 1.5, and 280ms with this fix. In another experiment on the same system, this program showed the time to intialise Tahoma (after basic graphics environment initialisation) reduced from 360ms to 80ms - this should translate into estimated reduction in time for initialising Tahoma of approx 0.25 seconds relative to 1.5 without the fix. This should translate directly into a start-up improvement. import java.awt.*; public class Tahoma { public static void main(String args[]) { GraphicsEnvironment.getLocalGraphicsEnvironment(); long t1 = System.nanoTime(); Font f = new Font("Tahoma", Font.PLAIN, 12); String family = f.getFamily(); long t2 = System.nanoTime(); System.out.println("Tahoma Time = " + (t2-t1)); } } There should also be a memory footprint reduction. ###@###.### 2004-04-30 ================================================== Whilst testing this code I have discovered that the windows registry entries need to be treated with caution. These are entries that have mappings like "Arial Bold" -> ARIALBD.TTF Two problems I found are : - The Windows registry entry for "David" names it "David Regular" There's no obvious reason for this and its inconsistent with other regular fonts such as Arial. It causes the particular problem that if you try to ask for the file that contains "David", none is listed in the registry. - All of the "UPC" fonts should have a double space in their font name after the family name and before the style. Eg you may expect "BrowalliaUPC Italic" but the font's actual name is "BrowalliaUPC Italic". This seems odd but windows enumerates the double space name via APIs, and its what JDK finds too, so odd as it is, its the name of the font. However the registry entry has only one space. This causes look up to fail for all but the non-styled version of the font. The fix for both of these problems is that we need to check that all members of a family that are enumerated by font APIs have a registry font->file mapping. Looking up fonts which behave like this will cause all fonts to be loaded. Another implication of this is we cannot simply implement "getAllFonts" as returning the set of fonts listed in the registry, as we cannot trust the names there, except as an "accelerator". ie only if all members of a family have registry entries can we use the registry. If that wasn't enough, to reinforce this, it has been observed that registry entries exist for files which aren't actually installed. It looks like windows pre-creates the registry mappings for some fonts. Eg a system that did not have DAVID.TTF in \windows\fonts, still had a registry entry for it. One font, MARLETT.TTF is installed as a hidden file, perhaps because it is used for windows icons, so perhaps they want to minimise the risk of users messing with it. This was observed on Windows 2000 Windows XP. It also doesn't show up if you open the fonts directory in Windows Explorer. Despite this windows APIs enumerate it, so we see it in the list of known fonts and families, but we will fail to find a font mapping. Therefore this is another reason why - if a font is requested and we have no registry entry, we need to do things the old way. - we can't use the registry for getAllFonts Also this makes clearer that the registry font name mappings have a correspondence to what is shown in the windows explorer font directory view. The UPC font names shown there have the same single-spacing as we see in the registry. So the windows font enumeration APIs to appear safe for discovering what font families and font names are available for the default locale. But the registry may not always help us find the font files. So we can implement getAllFonts using the windows font APIs, lazily map that font to a file via the registry if a mapping exists, or via loading all the fonts if none doesn't. This means that unless you actually "use" the fonts in the list, you don't take the hit. One additional snag is that the fonts used in fontconfig.properties files are always referenced there using the English name - if one exists - and in other locales the name returned by windows may be the localised name. Thus we think these names correspond to different fonts and although it doesn't cause any serious problems, we enumerate the same font twice, since it gets added to the list twice. The solution to that is to check if the file is one we already registered. This depends on there being a registry entry for the font in the localised name, which there always is for these fonts. Hopefully that is the end of the problems - the code now seems to work on win98, and winXP US and JA. ====== Consideration was given to doing something similar on Solaris/Linux using fontconfig. However fontconfig doesn't yet offer the necessary support. - It can't enumerate font full names. - The family names it returns will always be the English name, unless a font has no English name, in which case it will return the first name it found that can be encoded using latin chars, failing that the Postscript name. This is not what JDK does or wants. We'd use it even if this only really worked for English locales, but not knowing for sure which of the possible family names we got is too much of a gamble. We want to be able to express a preference for the MS platformID names, and be able to specify the language we want with a fallback to English if its not available. Additionally for the MS platformID names, fontconfig currently ignores names which specify an encoding id other than unicode. Since most, if not all, fonts actually expect you to interpret the encoding ID soley as meaning the encoding of the cmap, then this is not what we want either. The encoding of the MS names is always unicode - all of the MS symbol encoded fonts are like this for example. fontconfig 2.3 is expected to have some additional support for the latter, and perhaps for the former too, so we can look to revisit this in the future. ###@###.### 2004-05-07 ===========================
07-05-2004