-
Bug
-
Resolution: Unresolved
-
P4
-
7
-
x86
-
windows_7
FULL PRODUCT VERSION :
C:\Windows\Fonts>java -version
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b146)
Java HotSpot(TM) 64-Bit Server VM (build 21.0-b16, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
if i have this piece of code:
public static void main(String[] args) {
Font[] allFontsArray = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
Font font = new Font("Tahoma",Font.PLAIN,12);
font.getFamily();
System.err.println(font);
font = FontUtilities.getCompositeFontUIResource(font);
System.err.println(font);
font = font.deriveFont(font.getStyle());
System.err.println(font);
}
where i ask for the Tahom font in Plain
then after the call font.getFamily() if you look what really is the Font2D instance that it got, then you see that it got the Tahoma BOLD font2d instance not the plain version.
if i don't do the call:
Font[] allFontsArray = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
then it works fine. So somehow it is when we load in all the fonts.
I tracked it down a bit: SunFontManager:
private synchronized HashMap<String,String> getFullNameToFileMap()
after the call to the Win32FontManager (which i can't find the source)
populateFontFileNameMap()
i have a fontToFamilyNameMap of 300 entries that have Dutch names (my locale is not dutch but is in english i have a english windows version but i am dutch (like many of us do here) but i don't know if this is relevant because the call to resolveWindowsFonts() seems to resolve that just fine
After the call getFullNameToFileMap() my fontToFileMap is about 244 big with all English names so: tahoma=tahoma.ttf
at this moment the physicalFonts field of the SunFontManager doesn;'t have Tahoma only some JRE fonts and so on.
Now we come back to loadFonts() of the SunFontManager
It does not call: registerFontsOnPath() because the if: if (! gotFontsFromPlatform()) blocks that
so it goes directly into:
registerOtherFontFiles(registeredFontFiles);
that call does this:
for (String file : fontToFileMap.values()) {
registerFontFile(file);
}
but that does nothing for any of the fontToFileMap values because they are never:
if (new File(file).isAbsolute()
and absolute file..
so until now the call to:
private PhysicalFont addToFontList(PhysicalFont f, int rank)
is not done for any entry in the fontToFileMap
So no PhysicalFont is created or better said no:
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);
}
FontFamily is created for a Font and nothing is set yet for every style in the FontFamily instance (plain,bold, etc)
So we are now back in:
getAllInstalledFonts()
that calls:
getFontNamesFromPlatform()
that calls again:
checkForUnreferencedFontFiles()
and now it comes
now it makes a List of all the registryFiles:
ArrayList<String> registryFiles = new ArrayList<String>();
for (String regFile : fontToFileMap.values()) {
registryFiles.add(regFile.toLowerCase());
}
and later on:
for (String pathFile : getFontFilesFromPath(false)) {
if (!registryFiles.contains(pathFile))
it blocks anything that is in that List that also comes from the font files from path..
And because of that the call to
private PhysicalFont addToFontList(PhysicalFont f, int rank)
is again not made for anything that was in the registry....
My registry lists Tahoma but not Tahoma bold.
So now it encounters Tahoma that one just skips
then it encounteres Tahoma bold that one it calls addToFontList on
And because of this, a FontFamily instance is created for "Tahoma" and bold, italic fields and so on are registered there, but not the plain
Then later on there is code that finds the best possible match if there is no plain font2d and that maps to bold...
For example i can fix this issue if i just clear() the
ArrayList<String> registryFiles = new ArrayList<String>();
right before the if:
for (String pathFile : getFontFilesFromPath(false)) {
if (!registryFiles.contains(pathFile))
so that it never contains anything and just makes all the PhysicalFonts and registers also the PLAIN version of the font
So the fix could be to not fill up the registryFiles list..
Or if we go back, this method:
protected void registerOtherFontFiles(HashSet registeredFontFiles) {
if (getFullNameToFileMap().size() == 0) {
return;
}
for (String file : fontToFileMap.values()) {
registerFontFile(file);
}
}
shoud really do:
protected void registerOtherFontFiles(HashSet registeredFontFiles) {
if (getFullNameToFileMap().size() == 0) {
return;
}
for (String file : fontToFileMap.values()) {
registerFontFile(getPathName(file));
}
}
because then at least everything that is inside the fontFileMap will be registered and loaded correctly.
REGRESSION. Last worked in version 7
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See my description
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
that i get the plain version of the font if i ask for it
ACTUAL -
I get the bold because the plain font2d file is not in the registered FontFamily instance.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
public static void main(String[] args) {
Font[] allFontsArray = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
Font font = new Font("Tahoma",Font.PLAIN,12);
font.getFamily();
System.err.println(font);
font = FontUtilities.getCompositeFontUIResource(font);
System.err.println(font);
font = font.deriveFont(font.getStyle());
System.err.println(font);
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
i haven't found one yet,
yes not calling getAllFonts() and so on, but i can't really control that.
C:\Windows\Fonts>java -version
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b146)
Java HotSpot(TM) 64-Bit Server VM (build 21.0-b16, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
if i have this piece of code:
public static void main(String[] args) {
Font[] allFontsArray = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
Font font = new Font("Tahoma",Font.PLAIN,12);
font.getFamily();
System.err.println(font);
font = FontUtilities.getCompositeFontUIResource(font);
System.err.println(font);
font = font.deriveFont(font.getStyle());
System.err.println(font);
}
where i ask for the Tahom font in Plain
then after the call font.getFamily() if you look what really is the Font2D instance that it got, then you see that it got the Tahoma BOLD font2d instance not the plain version.
if i don't do the call:
Font[] allFontsArray = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
then it works fine. So somehow it is when we load in all the fonts.
I tracked it down a bit: SunFontManager:
private synchronized HashMap<String,String> getFullNameToFileMap()
after the call to the Win32FontManager (which i can't find the source)
populateFontFileNameMap()
i have a fontToFamilyNameMap of 300 entries that have Dutch names (my locale is not dutch but is in english i have a english windows version but i am dutch (like many of us do here) but i don't know if this is relevant because the call to resolveWindowsFonts() seems to resolve that just fine
After the call getFullNameToFileMap() my fontToFileMap is about 244 big with all English names so: tahoma=tahoma.ttf
at this moment the physicalFonts field of the SunFontManager doesn;'t have Tahoma only some JRE fonts and so on.
Now we come back to loadFonts() of the SunFontManager
It does not call: registerFontsOnPath() because the if: if (! gotFontsFromPlatform()) blocks that
so it goes directly into:
registerOtherFontFiles(registeredFontFiles);
that call does this:
for (String file : fontToFileMap.values()) {
registerFontFile(file);
}
but that does nothing for any of the fontToFileMap values because they are never:
if (new File(file).isAbsolute()
and absolute file..
so until now the call to:
private PhysicalFont addToFontList(PhysicalFont f, int rank)
is not done for any entry in the fontToFileMap
So no PhysicalFont is created or better said no:
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);
}
FontFamily is created for a Font and nothing is set yet for every style in the FontFamily instance (plain,bold, etc)
So we are now back in:
getAllInstalledFonts()
that calls:
getFontNamesFromPlatform()
that calls again:
checkForUnreferencedFontFiles()
and now it comes
now it makes a List of all the registryFiles:
ArrayList<String> registryFiles = new ArrayList<String>();
for (String regFile : fontToFileMap.values()) {
registryFiles.add(regFile.toLowerCase());
}
and later on:
for (String pathFile : getFontFilesFromPath(false)) {
if (!registryFiles.contains(pathFile))
it blocks anything that is in that List that also comes from the font files from path..
And because of that the call to
private PhysicalFont addToFontList(PhysicalFont f, int rank)
is again not made for anything that was in the registry....
My registry lists Tahoma but not Tahoma bold.
So now it encounters Tahoma that one just skips
then it encounteres Tahoma bold that one it calls addToFontList on
And because of this, a FontFamily instance is created for "Tahoma" and bold, italic fields and so on are registered there, but not the plain
Then later on there is code that finds the best possible match if there is no plain font2d and that maps to bold...
For example i can fix this issue if i just clear() the
ArrayList<String> registryFiles = new ArrayList<String>();
right before the if:
for (String pathFile : getFontFilesFromPath(false)) {
if (!registryFiles.contains(pathFile))
so that it never contains anything and just makes all the PhysicalFonts and registers also the PLAIN version of the font
So the fix could be to not fill up the registryFiles list..
Or if we go back, this method:
protected void registerOtherFontFiles(HashSet registeredFontFiles) {
if (getFullNameToFileMap().size() == 0) {
return;
}
for (String file : fontToFileMap.values()) {
registerFontFile(file);
}
}
shoud really do:
protected void registerOtherFontFiles(HashSet registeredFontFiles) {
if (getFullNameToFileMap().size() == 0) {
return;
}
for (String file : fontToFileMap.values()) {
registerFontFile(getPathName(file));
}
}
because then at least everything that is inside the fontFileMap will be registered and loaded correctly.
REGRESSION. Last worked in version 7
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See my description
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
that i get the plain version of the font if i ask for it
ACTUAL -
I get the bold because the plain font2d file is not in the registered FontFamily instance.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
public static void main(String[] args) {
Font[] allFontsArray = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
Font font = new Font("Tahoma",Font.PLAIN,12);
font.getFamily();
System.err.println(font);
font = FontUtilities.getCompositeFontUIResource(font);
System.err.println(font);
font = font.deriveFont(font.getStyle());
System.err.println(font);
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
i haven't found one yet,
yes not calling getAllFonts() and so on, but i can't really control that.