loss of font fidelity (missing ClearType?)

May 28, 2014 at 2:01 PM
I found another issue with upgrading to latest and using the new custom fonts mechanism (which appears to work great, this is a rendering issue).

You can see the issue here in the image below. Both are using a custom font, and the rendering changes (possibly moving to GDI+ / disabling ClearType) have introduced this somewhere along the way:

Image

That image on the right is 1.4.1.0 (my build). That image on the left is 1.4.14 (latest build). As you can see, there is a big problem with rendering the fonts. The same exact font is used in both cases. The same code. The only difference is the control. My guess is ClearType is somehow disabled / not being specified as a text drawing hint.

I do not believe the loss in fidelity has anything to do with my changes to 1.4.1.0. All I did was add support for ::selection and CssFontFactory. I didn't change anything with the actual rendering.

Is there any way to enable ClearType for the control? It is enabled for my system, but the control is ignoring it.

Did this change as part of moving to GDI+?

Unfortunately, if there is no workaround, I will have to stay with my current version of the control, as the customers will not be able to settle for this.

Thanks,
Ryan
Developer
May 28, 2014 at 7:29 PM
The change was from GDI+ to GDI not the other way around and you can still use GDI+ text rendering by setting "UseGdiPlusTextRendering=true;"
and clear-type should work and as far as I know there is no way to disable it.

Interesting... maybe the font doesn't support GDI hinting... can you send me the font?
May 28, 2014 at 8:14 PM
Hi Arthur,

Thanks for the prompt reply!

I tried that setting both ways, no luck. It is behaving like it isn't setting the hinting, is that possible?

In all of my other controls, I'm using GDI+, and am having no problems with ClearType.

And as I said, 1.4.1 is working as well. And I use exactly the same font in that case.

You can find the fonts here:

http://www.ryanrogers.com/fonts.zip

Thanks,
Ryan
Developer
May 29, 2014 at 7:54 AM
Weird... it works perfectly for me:
Image

Let's try to reproduce it in HTML Renderer demo app.
Add your fonts to the custom fonts loading in DemoForm.LoadCustomFonts method:
private void LoadCustomFonts()
{
    // load custom font font into private fonts collection
    var file = Path.GetTempFileName();
    File.WriteAllBytes(file, Resources.CustomFont);
    _privateFont.AddFontFile(file);

    _privateFont.AddFontFile(@"D:\fonts\ModerneFraktur.ttf");
    _privateFont.AddFontFile(@"D:\fonts\AppleGaramond.ttf");
            
    // add the fonts to renderer
    foreach (var fontFamily in _privateFont.Families)
        HtmlRender.AddFontFamily(fontFamily);
}
Run the demo and paste the html snippet in the editor:
<div style="font: 30px 'Moderne fraktur'">
  This is a custom font that is not installed on the system.
</div>
<div style="font: 30px 'Apple Garamond'">
  This is a custom font that is not installed on the system.
</div> 
Let me know whats the result.
May 29, 2014 at 10:23 AM
It is possibly a difference in the font point size, or transparency?

I'm using these styles:
        builder.AppendLine("div.date { font-family:\"Apple Garamond\"; font-size:13px; color:").Append(rgb).Append("; }");
        builder.AppendLine("div.title { font-family:\"Moderne Fraktur\"; font-size:20px; color:").Append(rgb).Append("; }");
        builder.AppendLine("div.body { font-family:\"Times New Roman\"; font-size:13px; color:black; }")
So those sizes are much smaller.

Second, the HtmlPanel has transparency enabled ( BackColor = Color.Transparent;). The background also has an image as you can see in he original graphic. So the text is being rendered over that other image.

Third, this I the GUI / GDI init stuff I'm using:
        // standard visual stuff
        System.Windows.Forms.Application.EnableVisualStyles();
        System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(true);
I can't think off hand anything else that would cause a discrepancy? And either way, the same exact code and font files shows the fonts rendering perfectly with 1.4.1, and not with 1.4.14, so by definition something changed between those two. We just need to figure out what. ;-)

Thanks,
Ryan
Developer
May 29, 2014 at 11:02 AM
None of this made any difference for me, as expected.
A lot has changed in a year...
What do you see if you use the demo app?
May 29, 2014 at 11:21 AM
Demo apps looks the same as what you sent. There is some visible aliasing when you crank it up to 50px, but nothing nearly as bad as what is shown in the original post.

This definitely reeks of a ClearType issue, where something resident in the program is telling Windows to not use ClearType rendering for that window. However, all of the other controls on the form are being rendered fine with ClearType, as evidenced by the labels (news, forums, Patch Notes, etc.). Those are all using my TransparentLabel control, which renders using this:
        // draw the text using cleartype hint
        e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
        TextRenderer.DrawText(e.Graphics, Text, font, point, foreColor);
Are you specifically setting the ClearType hint in the rendering logic?

Thanks,
Ryan
Developer
May 29, 2014 at 11:36 AM
Good, so it's not a machine issue.

I think you are mixing GDI and GDI+ text rendering in you application.
"Application.SetCompatibleTextRenderingDefault(true);" will set WinForms controls to use GDI+ text rendering but "TextRenderer" uses GDI text rendering, also setting "e.Graphics.TextRenderingHint" is for GDI+ it has no effect on "TextRenderer.DrawText".
you should probably use "Application.SetCompatibleTextRenderingDefault(false);".
But all this have nothing to do with HtmlRenderer...

Are you sure setting "UseGdiPlusTextRendering=true" did nothing?

can you create a new plain form, add HtmlPanel to it and see what happens.
May 29, 2014 at 12:54 PM
Edited May 29, 2014 at 12:59 PM
Yeah my SetCompatibleTextRendering should have no impact as I use no stock controls. Every control is either mine built from scratch and does it's own rendering, or HtmlPanel. As I suspexcted, changing it to false made no difference. It's holdover code from the prototype back when I used to still use some standard controls.

However, you said:
"TextRenderer" uses GDI text rendering, also setting "e.Graphics.TextRenderingHint" is for GDI+ it has no effect on "TextRenderer.DrawText".
That is simply not true, despite what the docs may say. Not setting the hint makes the label text look EXACTLY like your text. Exactly. TextRenderer.DrawText definitely is affected by this hint.

.Net 2.0 target runtime, FYI.

As I said before, if you aren't using this hint, and you are using TextRenderer.DrawText, then this quite possibly why it is not working.

I will go back to my modified 1.4.1 code and see if I added that hint by chance, and perhaps that is why it is working in my build...

Ryan
Developer
May 29, 2014 at 1:10 PM
Strange... please let me know if adding the hint the HtmlPanel OnPaint helps.
But what is so special about this application? Why does it works in demo?
May 29, 2014 at 1:26 PM
I fixed it by adding the hinting into your latest code: ;-)

The new HtmlPanel.OnPaint:
        /// <summary>
        /// Perform paint of the html in the control.
        /// </summary>
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            if (_htmlContainer != null)
            {
                e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;  // this is the line I added

                _htmlContainer.ScrollOffset = AutoScrollPosition;
                _htmlContainer.PerformPaint(e.Graphics);

                // call mouse move to handle paint after scroll or html change affecting mouse cursor.
                var mp = PointToClient(MousePosition);
                _htmlContainer.HandleMouseMove(this, new MouseEventArgs(MouseButtons.None, 0, mp.X, mp.Y, 0));
            }
        }
I went back and looked at my 1.4.1 code, and this was what was there:
    /// <summary>
    /// Perform paint of the html in the control.
    /// </summary>
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        if (_htmlContainer != null)
        {
            _htmlContainer.ScrollOffset = AutoScrollPosition;
            e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
            _htmlContainer.PerformPaint(e.Graphics);
        }
    }
My guess is I added it there as well, but forgot. It was 15-16 months ago. ;-) Or else it used to be there and you got rid of it. Either way, that is why it wasn't working now.

So mystery solved I think. If you could please make sure this fix makes it into the next build that would be great so that I can start (and keep) using the official builds so I don't have to manage my own code stream would be great.

Of course, this only has an affect when UseGdiPlusRendering is true. If I set it to false, the text goes back to ugly. But if I set it to true and use the official build, it stays ugly. It is only actually rendering with ClearType when the Hint is set.

Let me know if any questions.

Thanks,
Ryan
Developer
May 29, 2014 at 1:34 PM
Will add it.
And you sure the demo works fine? How that can be?
May 29, 2014 at 1:46 PM
Our posts crossed...sorry I hadn't gotten the email notification of your post.

As far as differences, it could be lots of stuff. I do a lot of tricks to get transparency to with my Transparent Windows Forms and Controls library. And also some double-buffer stuff with compositing for performance and accuracy with the pseudo-transparency. In fact, now that I think about it, that might be it. This is in my main window form:
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;

            // turn on form compositing (double buffering) if Vista or higher
            // we can't do this on XP due to GDI+ issue in that case
            OperatingSystem OS = Environment.OSVersion;
            if ((OS.Platform == PlatformID.Win32NT) && (OS.Version.Major >= 6))
            {
                cp.ExStyle |= Native.WS_EX_COMPOSITED;
            }

            return cp;
        }
    }
I'm guessing that when the window style is WS_EX_COMPOSITED, that GDI+ requires the hint in order to use ClearType!!!

That would certainly explain it...

Ryan
Developer
May 29, 2014 at 2:09 PM
nope... not it.
the only way I found to get what you are seeing is either disable clear type in control panel>fonts or disable smooth edges for screen fonts in System properties.
i can't find a way to do that for a single application...