none
GDI+ and ClearType : inconsistent behavior

    Question

  • Hi,

    I've got a strange bug with the property Graphics.TextRenderingHint, in a case where I use DrawString() with TextRenderingHint.SystemDefault and TextRenderingHint.ClearTypeGridEdit.

    Depending on the order of my instructions, the strings are not drawn in the same way.

    Compare the different cases below :

    http://www.imageno.com/w2y59tsml9g0pic.html

    The code used to obtain this result :

    namespace GdiBug 
        using System; 
        using System.Drawing; 
        using System.Drawing.Text; 
        using System.Windows.Forms; 
     
        public partial class Form1 : Form 
        { 
            [STAThread] 
            static void Main(string[] args) 
            { 
                Application.EnableVisualStyles(); 
                Application.SetCompatibleTextRenderingDefault(false); 
     
                bool withBug = args == null || args.Length == 0 || args[0] != "false"
     
                Form1 form = new Form1(); 
                form.WithBug = withBug; 
                form.Text = withBug ? "With Bug" : "Without Bug"
                Application.Run(form); 
            } 
     
            public Form1() 
            { 
                this.Font = new Font("Tahoma", 12f, FontStyle.Bold); 
                this.ClientSize = new Size(200, 60); 
            } 
     
            public bool WithBug { getset; } 
     
            protected override void OnPaint(PaintEventArgs e) 
            { 
                base.OnPaint(e); 
     
                using (SolidBrush b = new SolidBrush(ForeColor)) 
                { 
                    if (WithBug) 
                    { 
                        // Draws ClearType first 
                        e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; 
                        e.Graphics.DrawString("ClearTypeGridFit", Font, b, 10, 0); 
     
                        // Then SystemDefault = aliased 
                        e.Graphics.TextRenderingHint = TextRenderingHint.SystemDefault; 
                        e.Graphics.DrawString("SystemDefault", Font, b, 10, 24); 
                    } 
                    else 
                    { 
                        // Draws SystemDefault first (with antialias) 
                        e.Graphics.TextRenderingHint = TextRenderingHint.SystemDefault; 
                        e.Graphics.DrawString("SystemDefault", Font, b, 10, 0); 
     
                        // Then ClearTypeGridFit = same result as SystemDefault 
                        e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; 
                        e.Graphics.DrawString("ClearTypeGridFit", Font, b, 10, 24); 
                    } 
                } 
            } 
        } 

    Use the application by giving execution argument "true" or "false" (assuming "true" if missing).

    The only difference between the 2 columns is the order of instructions. In left column (expected behavior), SystemDefault enum is equal to ClearTypeGridFit when the system has ClearType enabled. In right column, despite the ClearType setting turned on, If you set TextRenderingHint to ClearTypeGridFit, then if you switch back to SystemDefault, the string will be drawn without ClearType turned on...

    The incorrect cases highlighten : http://www.imageno.com/b6fs6i89ge83pic.html

    By Design or not ?? Any workaround ?? (Note this problem is encountered for different controls using different render mode explicitely, so a "just use the good case" is irrevelant).

    Thanks !


    Wednesday, February 11, 2009 1:38 PM

Answers

  • They couldn't fix the bugz in Graphics.DrawString() because way too much .NET 1.x code depended on its quirks.  That's what Application.SetCompatibleTextRenderingDefault() is all about too.  If you really want to use GDI+, you'll have to find the workarounds for the bugs yourself.  Right now, using Graphics.DrawString() in a Paint event is a bug.
    Hans Passant.
    • Marked as answer by Steven.Yu Monday, February 16, 2009 2:19 AM
    Wednesday, February 11, 2009 2:48 PM
    Moderator

All replies

  • Graphics.DrawString() is too broken to be usable.  It got replaced by TextRenderer.DrawText().
    Hans Passant.
    Wednesday, February 11, 2009 2:06 PM
    Moderator
  • nobugz said:

    Graphics.DrawString() is too broken to be usable.  It got replaced by TextRenderer.DrawText().


    Hans Passant.

    You suggest to go back to the old GDI instead of using GDI+ ?

    Moreover, the msdn doc for the GDI+ method DrawString() and TextRenderingHint enum don't speak about switching rendering hint... Could not accept it's a bug since... ever ?

    I have now to convince the creator of the components we use...

    Thanks for the alternative anyway, but I would prefer having an alternative based on GDI+.

    Wednesday, February 11, 2009 2:14 PM
  • They couldn't fix the bugz in Graphics.DrawString() because way too much .NET 1.x code depended on its quirks.  That's what Application.SetCompatibleTextRenderingDefault() is all about too.  If you really want to use GDI+, you'll have to find the workarounds for the bugs yourself.  Right now, using Graphics.DrawString() in a Paint event is a bug.
    Hans Passant.
    • Marked as answer by Steven.Yu Monday, February 16, 2009 2:19 AM
    Wednesday, February 11, 2009 2:48 PM
    Moderator
  • Okay,

    For now I'm trying to find a workaround for our app (ie. by creating a fake control which render itself using SystemDefault, to force the correct initialization of these "context").
    Wednesday, February 11, 2009 3:36 PM