JDK-8144703 : ClassCastException: sun.font.CompositeFont cannot be cast to PhysicalFont
Type:Bug
Component:client-libs
Sub-Component:2d
Affected Version:8u66
Priority:P3
Status:Resolved
Resolution:Fixed
OS:linux
Submitted:2015-12-04
Updated:2016-10-13
Resolved:2016-06-29
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.
Java app gives the following exception message:
Exception in thread "main" java.lang.ClassCastException:
sun.font.CompositeFont cannot be cast to sun.font.PhysicalFont
Comments
There is no possibility to create an auto test since the problem is reproducible only with specific font file. As far as I understand we avoid creating manual regression tests.
10-06-2016
Problem description:
If an incorrect font file is used, we unable to initialise the font during CompositeFont.doDeferredInitialisation() invocation and assign default physical font to the corresponding components entry. Later at the same method, (i.e. doDeferredInitialisation()) we try to update this entry one more time, since the name retrieved from the entry and the name provide by componentNames array are different. The method SunFontManager.findFont2D() may return a composite font for such case. As a result we get ClassCastException trying to assign CompositeFont object to the instance of PhysicalFont.
Fix:
Surround invocation of SunFontManager.findFont2D() inside CompositeFont.doDeferredInitialisation() with 'try-catch' to avoid propagation of ClassCastException.
09-06-2016
It seems the font file provided by the submitter has an incorrect format or something like that. Windows font viewer cannot open Helvetica.ttf and reports that it is not a valid font file.
Java is unable to retrieve 'font name' and 'family name' during initialisation which take place at CompositeFont.doDeferredInitialisation() and assigns default physical font (Lucida Sans Regular) to the corresponding components entry. Later at the same method, (i.e. doDeferredInitialisation()) we try to update this entry one more time, since the name retrieved from the entry and the name provide by componentNames array are different. The method SunFontManager.findFont2D() returns a composite font for the name 'Helvetica', since this font is only present as a part of composite. As a result we get ClassCastException trying to assign CompositeFont object to the instance of PhysicalFont.
So the exception is caused by incorrect font file format.
Note: I converted provided font file (Helvetica.ttf) to TrueTypeFont using on-line font converter at http://www.files-conversion.com/font-converter.php
I was not able to reproduce the problem using the converted font file.
Anyway I think we should NOT fail with ClassCastException even if a font file with incorrect format is used.
09-06-2016
The problem is reproducible on jdk8u92 and jdk9
09-06-2016
The fix for JDK-8132850 didn't resolve the problem. It just changed the conditions under which the issue can be observed.
ClassCastException is still reproducible on Linux with a slightly changed test case (CanDisplayTest2.java). The steps to reproduce are the same.
09-06-2016
The problem is reproducible on Linux.
Steps to reproduce:
1. Install font, (i.e. 'cp Helvetica.ttf /usr/share/fonts' and then 'sudo fc-cache -f')
2. Run the test, (i.e. 'java CanDisplayTest')
Actual results:
The following exception is thrown
Exception in thread "main" java.lang.ClassCastException: sun.font.CompositeFont cannot be cast to sun.font.PhysicalFont
at sun.font.CompositeFont.doDeferredInitialisation(CompositeFont.java:274)
at sun.font.CompositeFont.getSlotFont(CompositeFont.java:341)
at sun.font.CompositeGlyphMapper.getSlotMapper(CompositeGlyphMapper.java:114)
at sun.font.CompositeGlyphMapper.convertToGlyph(CompositeGlyphMapper.java:124)
at sun.font.CompositeGlyphMapper.charToGlyph(CompositeGlyphMapper.java:182)
at sun.font.CharToGlyphMapper.canDisplay(CharToGlyphMapper.java:55)
at sun.font.CompositeFont.canDisplay(CompositeFont.java:424)
at java.awt.Font.canDisplay(Font.java:1977)
at CanDisplayTest2.main(CanDisplayTest2.java:5)
Expected results:
The test should print out 'false'.
09-06-2016
Tests and font file attached
09-06-2016
Most likely the problem is already fixed by JDK-8132850