Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8146035

Windows - With LCD antialiasing, some glyphs are not rendered correctly

    Details

    • Subcomponent:
      2d
    • Resolved In Build:
      b117

      Backports

        Description

        On Windows, when LCD antialiasing is enabled, glyphs of some fonts can be rendered only partially by JRE (or not rendered at all). For example, only one bar can be rendered for 'equals' character (=) instead of two.

        The same behavior is not observed in native applications.

          Issue Links

            Activity

            Hide
            prr Philip Race added a comment -
            The bug report references a font called Inconsolata available from
            http://www.levien.com/type/myfonts/inconsolata.html

            This is an Opentype/CFF font. What I see is that "native apps" do not
            attempt to use LCD text with this font. They instead use greyscale.
            When we request the glyph from Windows in LCD mode it seems to do a bad job on it
            which is probably why it is not something windows does unless you ask it to.
            Note that if I use "-Dsun.java2d.font.scaler=t2k", the glyph renders perfectly.
            So this is a Windows bug, not a JDK one.

            Since this is a Windows bug then I suspect only Microsoft can fix it.
            We can only work around it.

            The workaround above is one possibility but you then lose the native rendering
            completely.
            Of course since this is not a standard Windows font probably the better way of
            doing it is to load the font via Font.createFont(..) since in that case JDK will
            automatically go the T2K route, but for just that font.
            Show
            prr Philip Race added a comment - The bug report references a font called Inconsolata available from http://www.levien.com/type/myfonts/inconsolata.html This is an Opentype/CFF font. What I see is that "native apps" do not attempt to use LCD text with this font. They instead use greyscale. When we request the glyph from Windows in LCD mode it seems to do a bad job on it which is probably why it is not something windows does unless you ask it to. Note that if I use "-Dsun.java2d.font.scaler=t2k", the glyph renders perfectly. So this is a Windows bug, not a JDK one. Since this is a Windows bug then I suspect only Microsoft can fix it. We can only work around it. The workaround above is one possibility but you then lose the native rendering completely. Of course since this is not a standard Windows font probably the better way of doing it is to load the font via Font.createFont(..) since in that case JDK will automatically go the T2K route, but for just that font.
            Hide
            prr Philip Race added a comment -
            Windows bug, not a JDK bug.
            Show
            prr Philip Race added a comment - Windows bug, not a JDK bug.
            Hide
            aivanov Alexey Ivanov added a comment -
            Windows does not use ClearType with this font, Inconsolata, because it has PostScript outlines. MSDN explicitly mentions that ClearType antialiasing is not possible with PostScript OpenType fonts. See Remarks section in LOGFONT structure documentation: https://msdn.microsoft.com/en-us/library/dd145037%28v=vs.85%29.aspx

            Although it's not spelt out in the documentation, the result of GetGlyphOutline depends on the bitmap selected into the DC.

            In Java native code, a compatible DC is created. It is used for measuring the glyph size. Then a compatible bitmap is created with the correct size, and the glyph is rendered.

            Remarks section of CreateCompatibleDC function documentation https://msdn.microsoft.com/en-us/library/vs/alm/dd183489%28v=vs.85%29.aspx states:

            “When the memory DC is created, its display surface is exactly one monochrome pixel wide and one monochrome pixel high. Before an application can use a memory DC for drawing operations, it must select a bitmap of the correct width and height into the DC.”

            That is when GetGlyphOutline is called, a monochrome bitmap is selected into the DC. GetGlyphOutline does not perform any drawing, yet its result is affected by the selected bitmap: antialiasing is not possible in black-and-white mode.

            For Inconsolata font with the size of 12, GetGlyphOutline returns the glyph size is 4×1. It corresponds to what we see: one line is rendered, in this case it is the lower of two.

            If you select a compatible bitmap into the DC before calling GetGlyphOutline, the result changes to 6×4, and equals sign becomes distinguishable from minus sign.

            For this particular font, the height of glyphs for 'a' and 'b' in the sample is also affected. With monochrome bitmap, the height of 'a' and 'b' is 6 and 8 correspondingly; with compatible bitmap, the height is 1px greater: 7 and 9.
            Show
            aivanov Alexey Ivanov added a comment - Windows does not use ClearType with this font, Inconsolata, because it has PostScript outlines. MSDN explicitly mentions that ClearType antialiasing is not possible with PostScript OpenType fonts. See Remarks section in LOGFONT structure documentation: https://msdn.microsoft.com/en-us/library/dd145037%28v=vs.85%29.aspx Although it's not spelt out in the documentation, the result of GetGlyphOutline depends on the bitmap selected into the DC. In Java native code, a compatible DC is created. It is used for measuring the glyph size. Then a compatible bitmap is created with the correct size, and the glyph is rendered. Remarks section of CreateCompatibleDC function documentation https://msdn.microsoft.com/en-us/library/vs/alm/dd183489%28v=vs.85%29.aspx states: “When the memory DC is created, its display surface is exactly one monochrome pixel wide and one monochrome pixel high. Before an application can use a memory DC for drawing operations, it must select a bitmap of the correct width and height into the DC.” That is when GetGlyphOutline is called, a monochrome bitmap is selected into the DC. GetGlyphOutline does not perform any drawing, yet its result is affected by the selected bitmap: antialiasing is not possible in black-and-white mode. For Inconsolata font with the size of 12, GetGlyphOutline returns the glyph size is 4×1. It corresponds to what we see: one line is rendered, in this case it is the lower of two. If you select a compatible bitmap into the DC before calling GetGlyphOutline, the result changes to 6×4, and equals sign becomes distinguishable from minus sign. For this particular font, the height of glyphs for 'a' and 'b' in the sample is also affected. With monochrome bitmap, the height of 'a' and 'b' is 6 and 8 correspondingly; with compatible bitmap, the height is 1px greater: 7 and 9.
            Hide
            aivanov Alexey Ivanov added a comment -
            Changing lfQuality member of LOGFONT structure does not affect the result if monochrome bitmap is selected into the DC. Yet if you use NONANTIALIASED_QUALITY when compatible bitmap is selected, you'll get the same results as if the monochrome bitmap is selected.

            If you render the test string '=' to compatible bitmap with NONANTIALIASED_QUALITY, you can see 'minus' instead of '=' in native Win32 app too. With font size of 12px, the lower line of the pair is rendered; with font size of 15px, the upper line is rendered. If you set the font size to 10px, nothing is rendered at all: equals sign looks like a space.
            Show
            aivanov Alexey Ivanov added a comment - Changing lfQuality member of LOGFONT structure does not affect the result if monochrome bitmap is selected into the DC. Yet if you use NONANTIALIASED_QUALITY when compatible bitmap is selected, you'll get the same results as if the monochrome bitmap is selected. If you render the test string '=' to compatible bitmap with NONANTIALIASED_QUALITY, you can see 'minus' instead of '=' in native Win32 app too. With font size of 12px, the lower line of the pair is rendered; with font size of 15px, the upper line is rendered. If you set the font size to 10px, nothing is rendered at all: equals sign looks like a space.
            Hide
            aivanov Alexey Ivanov added a comment - - edited
            The suggested fix is posted to 2d-dev mailing list:
            http://mail.openjdk.java.net/pipermail/2d-dev/2016-April/006674.html

            The patch is available here:
            http://adm-12504.intellij.net/
            http://cr.openjdk.java.net/~aivanov/dmitry.batrak/8146035/jdk9/webrev.00/

            The suggested fix creates a dummy compatible bitmap and selects into hMemoryDC before GetGlyphOutline is called. It makes sure, Windows uses ClearType antialiasing for measuring the dimensions of the glyph.

            This situation was also mentioned in MSDN blog post comments:
            https://blogs.msdn.microsoft.com/oldnewthing/20060614-00/?p=30873#comment-392143


            I will sponsor integrating the patch into the codebase as soon as code review is complete.
            Show
            aivanov Alexey Ivanov added a comment - - edited The suggested fix is posted to 2d-dev mailing list: http://mail.openjdk.java.net/pipermail/2d-dev/2016-April/006674.html The patch is available here: • http://adm-12504.intellij.net/ • http://cr.openjdk.java.net/~aivanov/dmitry.batrak/8146035/jdk9/webrev.00/ The suggested fix creates a dummy compatible bitmap and selects into hMemoryDC before GetGlyphOutline is called. It makes sure, Windows uses ClearType antialiasing for measuring the dimensions of the glyph. This situation was also mentioned in MSDN blog post comments: https://blogs.msdn.microsoft.com/oldnewthing/20060614-00/?p=30873#comment-392143 I will sponsor integrating the patch into the codebase as soon as code review is complete.
            Hide
            aivanov Alexey Ivanov added a comment -
            EqualsGlyph.java is a test case which demonstrates the problem.

            The test case is based on the test case from JDK-8146097.
            If you don't have Inconsolata, it will show a message.

            See http://www.levien.com/type/myfonts/inconsolata.html for more information on the font. You can download the font from Google Fonts: https://www.google.com/fonts/specimen/Inconsolata
            Show
            aivanov Alexey Ivanov added a comment - EqualsGlyph.java is a test case which demonstrates the problem. The test case is based on the test case from JDK-8146097 . If you don't have Inconsolata, it will show a message. See http://www.levien.com/type/myfonts/inconsolata.html for more information on the font. You can download the font from Google Fonts: https://www.google.com/fonts/specimen/Inconsolata
            Hide
            prr Philip Race added a comment -
            I am guessing that Microsoft have very distinct rasterisation paths for CFF and TT fonts.
            Perhaps they licensed the CFF code from Adobe and it has never been augmented
            to handle ClearType. I don't *think* it can be a hinting issue since in that case they
            would probably say they need hints even in the TrueType case.
            Show
            prr Philip Race added a comment - I am guessing that Microsoft have very distinct rasterisation paths for CFF and TT fonts. Perhaps they licensed the CFF code from Adobe and it has never been augmented to handle ClearType. I don't *think* it can be a hinting issue since in that case they would probably say they need hints even in the TrueType case.
            Hide
            hgupdate HG Updates added a comment -
            URL: http://hg.openjdk.java.net/jdk9/client/jdk/rev/161066523d96
            User: aivanov
            Date: 2016-04-14 10:09:24 +0000
            Show
            hgupdate HG Updates added a comment - URL: http://hg.openjdk.java.net/jdk9/client/jdk/rev/161066523d96 User: aivanov Date: 2016-04-14 10:09:24 +0000
            Hide
            hgupdate HG Updates added a comment -
            URL: http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/161066523d96
            User: lana
            Date: 2016-05-04 18:39:50 +0000
            Show
            hgupdate HG Updates added a comment - URL: http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/161066523d96 User: lana Date: 2016-05-04 18:39:50 +0000

              People

              • Assignee:
                aivanov Alexey Ivanov
                Reporter:
                shadowbug Shadow Bug
              • Votes:
                0 Vote for this issue
                Watchers:
                4 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: