JDK-8192972 : Wrong glyphs are rendered on Windows when subpixel antialiasing is enabled
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 8u152,9.0.1
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: windows
  • Submitted: 2017-12-04
  • Updated: 2020-05-15
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.
Other
tbdUnresolved
Related Reports
Relates :  
Description
Steps to reproduce:
1) Install Source Code Pro font from https://github.com/adobe-fonts/source-code-pro/archive/2.030R-ro/1.050R-it.zip
(install all fonts from TTF subfolder)
2) Set system locale to Russian 
(on Windows 10 it's done in Control Panel -> Region -> Administrative -> Language for non-Unicode programs -> Change system locale...,
reboot is required)
3) Run the sample program with source given below.

Expected result: '123' digits are rendered in opened window (see attached renderingWithUSLocale.png).
Actual result: different glyphs are rendered (see attached renderingWithRussianLocale.png).

The issue is reproduced with latest Java 8 (1.8.0_152) and 9 (9.0.1) release builds.

---Sample program source code start---

import javax.swing.*;
import java.awt.*;

public class FontDrawingTest {
    public static void main(String[] args) {
        GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame();
            frame.add(new MyComponent());
            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            frame.setSize(200, 200);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }

    private static class MyComponent extends JComponent {
        private final Font font = new Font("Source Code Pro", Font.ITALIC, 24);
        private final String text = "123";

        @Override
        protected void paintComponent(Graphics g) {
            ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, 
                                              RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
            g.setFont(font);
            g.drawString(text, 70, 80);
        }
    }
}

---Sample program source code end---
Comments
That is more of a workaround than an ideal solution. It bails on using the native GDI rasteriser and will use the JDK's bundled one (T2K in 8, freetype in 11 and later). So it might be worth keeping this bug open to reflect that there may be a case where we can try a little harder to get GDI to pick the right font.
15-05-2020

[~prr] Hello Phil. While working on the bug JDK-8228713 and porting the fix for JDK-8236996 to JDK 8 this week, I verified that this issue is already not reproducible with JDK 15+22, that it was reproducible with the latest JDK 8 and became resolved in JDK 8 exactly by the backport of JDK-8236996. I think that this issue can be closed as a duplicate of JDK-8236996 which resolved it.
15-05-2020

If you're interested, here's how we're trying to fix it in JetBrains Runtime - https://github.com/JetBrains/jdk8u_jdk/commit/4ae0566f89d911d7510954484c6989c770e99f6d. Just as you say, we're trying to find any charset supported by given font. This is done by querying Windows API for available font/charset combinations in font's family and matching returned values with localized font names.
14-12-2017

Yes .. I am sure it is due to Windows not using the font JDK intended it to use. charset is part of the LOFONT parameter The LOGFONT docs at https://msdn.microsoft.com/en-us/library/dd145037(v=vs.85).aspx say for charset : "This parameter is important in the font mapping process. To ensure consistent results, specify a specific character set." We may need to add logic to try to make sure whatever charset we pass is supported by the font. I don't think it matters what charset the actual code point would support since we can render CJK glyphs in a US locale (for example) .. so maybe just find anything that is supported if DEFAULT doesn't work and NULL otherwise ? The risk of breaking other cases seems probable if we aren't careful here.
04-12-2017

This is related to the implementation of subpixel rendering on Windows in lcdglyph.c. CreateFontIndirectW is called with a DEFAULT_CHARSET value, which on a system with Russian locale is supposedly equivalent to RUSSIAN_CHARSET. As Source Code Pro Italic font doesn't support Cyrillic characters, Windows seems to be falling back to a synthetic italic font (based on Source Code Pro Regular), which has a different char-to-glyph mapping.
04-12-2017