// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Windows.Forms.Metafiles;
using Moq;

namespace System.Windows.Forms.Tests;

public class TextRendererTests
{
    public static IEnumerable<object[]> DrawText_IDeviceContext_String_Font_Point_Color_TestData()
    {
        foreach (TextRenderingHint hint in Enum.GetValues(typeof(TextRenderingHint)))
        {
            foreach (string text in new string[] { null, string.Empty, "string" })
            {
                yield return new object[] { hint, text, null, Point.Empty, Color.Red };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Red };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Black };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.White };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Transparent };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Empty };
            }
        }
    }

    [WinFormsTheory]
    [MemberData(nameof(DrawText_IDeviceContext_String_Font_Point_Color_TestData))]
    public void TextRenderer_DrawText_InvokeIDeviceContextStringFontPointColor_Success(TextRenderingHint textRenderingHint, string text, Font font, Point pt, Color foreColor)
    {
        using Bitmap image = new(10, 10);
        using Graphics graphics = Graphics.FromImage(image);
        graphics.TextRenderingHint = textRenderingHint;
        TextRenderer.DrawText(graphics, text, font, pt, foreColor);

        // Call again to test caching.
        TextRenderer.DrawText(graphics, text, font, pt, foreColor);
    }

    public static IEnumerable<object[]> DrawText_IDeviceContext_String_Font_Point_Color_Color_TestData()
    {
        foreach (TextRenderingHint hint in Enum.GetValues(typeof(TextRenderingHint)))
        {
            foreach (string text in new string[] { null, string.Empty, "string" })
            {
                yield return new object[] { hint, text, null, Point.Empty, Color.Red, Color.Blue };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Red, Color.Blue };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Black, Color.Blue };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.White, Color.Blue };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Transparent, Color.Blue };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Empty, Color.Blue };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Red };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Black };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.White };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Transparent };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Empty };
            }
        }
    }

    [WinFormsTheory]
    [MemberData(nameof(DrawText_IDeviceContext_String_Font_Point_Color_Color_TestData))]
    public void TextRenderer_DrawText_InvokeIDeviceContextStringFontPointColorColor_Success(TextRenderingHint textRenderingHint, string text, Font font, Point pt, Color foreColor, Color backColor)
    {
        using Bitmap image = new(10, 10);
        using Graphics graphics = Graphics.FromImage(image);
        graphics.TextRenderingHint = textRenderingHint;
        TextRenderer.DrawText(graphics, text, font, pt, foreColor, backColor);

        // Call again to test caching.
        TextRenderer.DrawText(graphics, text, font, pt, foreColor, backColor);
    }

    public static IEnumerable<object[]> DrawText_IDeviceContext_String_Font_Point_Color_TextFormatFlags_TestData()
    {
        foreach (TextRenderingHint hint in Enum.GetValues(typeof(TextRenderingHint)))
        {
            foreach (string text in new string[] { null, string.Empty, "string" })
            {
                yield return new object[] { hint, text, null, Point.Empty, Color.Red, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Red, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Black, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.White, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Transparent, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Empty, TextFormatFlags.Default, };

                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, TextFormatFlags.HorizontalCenter };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, TextFormatFlags.Bottom | TextFormatFlags.Right };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, TextFormatFlags.SingleLine };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, (TextFormatFlags)1024 };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, TextFormatFlags.RightToLeft };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, (TextFormatFlags)int.MaxValue };
            }
        }
    }

    [WinFormsTheory]
    [MemberData(nameof(DrawText_IDeviceContext_String_Font_Point_Color_TextFormatFlags_TestData))]
    public void TextRenderer_DrawText_InvokeIDeviceContextStringFontPointColorTextFormatFlags_Success(TextRenderingHint textRenderingHint, string text, Font font, Point pt, Color foreColor, TextFormatFlags flags)
    {
        using Bitmap image = new(10, 10);
        using Graphics graphics = Graphics.FromImage(image);
        graphics.TextRenderingHint = textRenderingHint;
        TextRenderer.DrawText(graphics, text, font, pt, foreColor, flags);

        // Call again to test caching.
        TextRenderer.DrawText(graphics, text, font, pt, foreColor, flags);
    }

    public static IEnumerable<object[]> DrawText_IDeviceContext_String_Font_Point_Color_Color_TextFormatFlags_TestData()
    {
        foreach (TextRenderingHint hint in Enum.GetValues(typeof(TextRenderingHint)))
        {
            foreach (string text in new string[] { null, string.Empty, "string" })
            {
                yield return new object[] { hint, text, null, Point.Empty, Color.Red, Color.Blue, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Red, Color.Blue, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Black, Color.Blue, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.White, Color.Blue, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Transparent, Color.Blue, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Point(1, 2), Color.Empty, Color.Blue, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Red, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Black, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.White, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Transparent, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Empty, TextFormatFlags.Default, };

                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Blue, TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Blue, TextFormatFlags.Bottom | TextFormatFlags.Right };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Blue, TextFormatFlags.SingleLine };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Blue, (TextFormatFlags)1024 };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Blue, TextFormatFlags.RightToLeft };
                yield return new object[] { hint, text, SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Blue, (TextFormatFlags)int.MaxValue };
            }
        }
    }

    [WinFormsTheory]
    [MemberData(nameof(DrawText_IDeviceContext_String_Font_Point_Color_Color_TextFormatFlags_TestData))]
    public void TextRenderer_DrawText_InvokeIDeviceContextStringFontPointColorColorTextFormatFlags_Success(TextRenderingHint textRenderingHint, string text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags)
    {
        using Bitmap image = new(10, 10);
        using Graphics graphics = Graphics.FromImage(image);
        graphics.TextRenderingHint = textRenderingHint;
        TextRenderer.DrawText(graphics, text, font, pt, foreColor, backColor, flags);

        // Call again to test caching.
        TextRenderer.DrawText(graphics, text, font, pt, foreColor, backColor, flags);
    }

    public static IEnumerable<object[]> DrawText_IDeviceContext_String_Font_Rectangle_Color_TestData()
    {
        foreach (TextRenderingHint hint in Enum.GetValues(typeof(TextRenderingHint)))
        {
            foreach (string text in new string[] { null, string.Empty, "string" })
            {
                yield return new object[] { hint, text, null, Rectangle.Empty, Color.Red };
                yield return new object[] { hint, text, null, new Rectangle(1, 2, -3, -4), Color.Red };
                yield return new object[] { hint, text, null, new Rectangle(1, 2, int.MaxValue, int.MaxValue), Color.Red };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 3, 4), Color.Red };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Black };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.White };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Transparent };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Empty };
            }
        }
    }

    [WinFormsTheory]
    [MemberData(nameof(DrawText_IDeviceContext_String_Font_Rectangle_Color_TestData))]
    public void TextRenderer_DrawText_InvokeIDeviceContextStringFontRectangleColor_Success(TextRenderingHint textRenderingHint, string text, Font font, Rectangle bounds, Color foreColor)
    {
        using Bitmap image = new(10, 10);
        using Graphics graphics = Graphics.FromImage(image);
        graphics.TextRenderingHint = textRenderingHint;
        TextRenderer.DrawText(graphics, text, font, bounds, foreColor);

        // Call again to test caching.
        TextRenderer.DrawText(graphics, text, font, bounds, foreColor);
    }

    public static IEnumerable<object[]> DrawText_IDeviceContext_String_Font_Rectangle_Color_Color_TestData()
    {
        foreach (TextRenderingHint hint in Enum.GetValues(typeof(TextRenderingHint)))
        {
            foreach (string text in new string[] { null, string.Empty, "string" })
            {
                yield return new object[] { hint, text, null, Rectangle.Empty, Color.Red, Color.Blue };
                yield return new object[] { hint, text, null, new Rectangle(1, 2, -3, -4), Color.Red, Color.Blue };
                yield return new object[] { hint, text, null, new Rectangle(1, 2, int.MaxValue, int.MaxValue), Color.Red, Color.Blue };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Blue };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Black, Color.Blue };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.White, Color.Blue };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Transparent, Color.Blue };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Empty, Color.Blue };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Red };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Black };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.White };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Transparent };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Empty };
            }
        }
    }

    [WinFormsTheory]
    [MemberData(nameof(DrawText_IDeviceContext_String_Font_Rectangle_Color_Color_TestData))]
    public void TextRenderer_DrawText_InvokeIDeviceContextStringFontRectangleColorColor_Success(TextRenderingHint textRenderingHint, string text, Font font, Rectangle rectangle, Color foreColor, Color backColor)
    {
        using Bitmap image = new(10, 10);
        using Graphics graphics = Graphics.FromImage(image);
        graphics.TextRenderingHint = textRenderingHint;
        TextRenderer.DrawText(graphics, text, font, rectangle, foreColor, backColor);

        // Call again to test caching.
        TextRenderer.DrawText(graphics, text, font, rectangle, foreColor, backColor);
    }

    public static IEnumerable<object[]> DrawText_IDeviceContext_String_Font_Rectangle_Color_TextFormatFlags_TestData()
    {
        foreach (TextRenderingHint hint in Enum.GetValues(typeof(TextRenderingHint)))
        {
            foreach (string text in new string[] { null, string.Empty, "string" })
            {
                yield return new object[] { hint, text, null, Rectangle.Empty, Color.Red, TextFormatFlags.Default, };
                yield return new object[] { hint, text, null, new Rectangle(1, 2, -3, -4), Color.Red, TextFormatFlags.Default, };
                yield return new object[] { hint, text, null, new Rectangle(1, 2, int.MaxValue, int.MaxValue), Color.Red, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Black, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.White, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Transparent, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Empty, TextFormatFlags.Default, };

                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, TextFormatFlags.HorizontalCenter };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, TextFormatFlags.Bottom | TextFormatFlags.Right };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, TextFormatFlags.SingleLine };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, int.MaxValue, int.MaxValue), Color.Red, TextFormatFlags.SingleLine };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, (TextFormatFlags)1024 };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, TextFormatFlags.RightToLeft };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, (TextFormatFlags)int.MaxValue };
            }
        }
    }

    [WinFormsTheory]
    [MemberData(nameof(DrawText_IDeviceContext_String_Font_Rectangle_Color_TextFormatFlags_TestData))]
    public void TextRenderer_DrawText_InvokeIDeviceContextStringFontRectangleColorTextFormatFlags_Success(TextRenderingHint textRenderingHint, string text, Font font, Rectangle rectangle, Color foreColor, TextFormatFlags flags)
    {
        using Bitmap image = new(10, 10);
        using Graphics graphics = Graphics.FromImage(image);
        graphics.TextRenderingHint = textRenderingHint;
        TextRenderer.DrawText(graphics, text, font, rectangle, foreColor, flags);

        // Call again to test caching.
        TextRenderer.DrawText(graphics, text, font, rectangle, foreColor, flags);
    }

    public static IEnumerable<object[]> DrawText_IDeviceContext_String_Font_Rectangle_Color_Color_TextFormatFlags_TestData()
    {
        foreach (TextRenderingHint hint in Enum.GetValues(typeof(TextRenderingHint)))
        {
            foreach (string text in new string[] { null, string.Empty, "string" })
            {
                yield return new object[] { hint, text, null, Rectangle.Empty, Color.Red, Color.Blue, TextFormatFlags.Default, };
                yield return new object[] { hint, text, null, new Rectangle(1, 2, -3, -4), Color.Red, Color.Blue, TextFormatFlags.Default, };
                yield return new object[] { hint, text, null, new Rectangle(1, 2, int.MaxValue, int.MaxValue), Color.Blue, Color.Blue, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Blue, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Black, Color.Blue, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.White, Color.Blue, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Transparent, Color.Blue, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Empty, Color.Blue, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Red, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Black, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.White, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Transparent, TextFormatFlags.Default, };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Empty, TextFormatFlags.Default, };

                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Blue, TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Blue, TextFormatFlags.Bottom | TextFormatFlags.Right };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Blue, TextFormatFlags.SingleLine };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, int.MaxValue, int.MaxValue), Color.Red, Color.Blue, TextFormatFlags.SingleLine };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Blue, (TextFormatFlags)1024 };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Blue, TextFormatFlags.RightToLeft };
                yield return new object[] { hint, text, SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Blue, (TextFormatFlags)int.MaxValue };
            }
        }
    }

    [WinFormsTheory]
    [MemberData(nameof(DrawText_IDeviceContext_String_Font_Rectangle_Color_Color_TextFormatFlags_TestData))]
    public void TextRenderer_DrawText_InvokeIDeviceContextStringFontRectangleColorColorTextFormatFlags_Success(TextRenderingHint textRenderingHint, string text, Font font, Rectangle rectangle, Color foreColor, Color backColor, TextFormatFlags flags)
    {
        using Bitmap image = new(10, 10);
        using Graphics graphics = Graphics.FromImage(image);
        graphics.TextRenderingHint = textRenderingHint;
        TextRenderer.DrawText(graphics, text, font, rectangle, foreColor, backColor, flags);

        // Call again to test caching.
        TextRenderer.DrawText(graphics, text, font, rectangle, foreColor, backColor, flags);
    }

    [WinFormsFact]
    public void TextRenderer_DrawText_Mocked_Success()
    {
        using Bitmap image = new(10, 10);
        using Graphics graphics = Graphics.FromImage(image);
        Mock<IDeviceContext> mockDeviceContext = new(MockBehavior.Strict);
        mockDeviceContext
            .Setup(c => c.GetHdc())
            .Returns(graphics.GetHdc)
            .Verifiable();
        mockDeviceContext
            .Setup(c => c.ReleaseHdc())
            .Callback(graphics.ReleaseHdc)
            .Verifiable();

        TextRenderer.DrawText(mockDeviceContext.Object, "text", SystemFonts.MenuFont, Point.Empty, Color.Red);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Once());
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Once());

        TextRenderer.DrawText(mockDeviceContext.Object, "text", SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Blue);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(2));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(2));

        TextRenderer.DrawText(mockDeviceContext.Object, "text", SystemFonts.MenuFont, Point.Empty, Color.Red, TextFormatFlags.Default);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(3));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(3));

        TextRenderer.DrawText(mockDeviceContext.Object, "text", SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Blue, TextFormatFlags.Default);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(4));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(4));

        TextRenderer.DrawText(mockDeviceContext.Object, "text", SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(5));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(5));

        TextRenderer.DrawText(mockDeviceContext.Object, "text", SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, TextFormatFlags.Default);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(6));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(6));

        TextRenderer.DrawText(mockDeviceContext.Object, "text", SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Blue);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(7));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(7));

        TextRenderer.DrawText(mockDeviceContext.Object, "text", SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Blue, TextFormatFlags.Default);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(8));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(8));

        TextRenderer.DrawText(mockDeviceContext.Object, "text".AsSpan(), SystemFonts.MenuFont, Point.Empty, Color.Red);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(9));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(9));

        TextRenderer.DrawText(mockDeviceContext.Object, "text".AsSpan(), SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Blue);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(10));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(10));

        TextRenderer.DrawText(mockDeviceContext.Object, "text".AsSpan(), SystemFonts.MenuFont, Point.Empty, Color.Red, TextFormatFlags.Default);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(11));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(11));

        TextRenderer.DrawText(mockDeviceContext.Object, "text".AsSpan(), SystemFonts.MenuFont, Point.Empty, Color.Red, Color.Blue, TextFormatFlags.Default);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(12));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(12));

        TextRenderer.DrawText(mockDeviceContext.Object, "text".AsSpan(), SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(13));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(13));

        TextRenderer.DrawText(mockDeviceContext.Object, "text".AsSpan(), SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, TextFormatFlags.Default);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(14));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(14));

        TextRenderer.DrawText(mockDeviceContext.Object, "text".AsSpan(), SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Blue);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(15));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(15));

        TextRenderer.DrawText(mockDeviceContext.Object, "text".AsSpan(), SystemFonts.MenuFont, new Rectangle(1, 2, 300, 400), Color.Red, Color.Blue, TextFormatFlags.Default);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(16));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(16));
    }

    [WinFormsFact]
    public void TextRenderer_DrawText_NullDc_ThrowsArgumentNullException()
    {
        Assert.Throws<ArgumentNullException>("dc", () => TextRenderer.DrawText(null, "text", SystemFonts.MenuFont, Point.Empty, Color.Red));
    }

    public static IEnumerable<object[]> MeasureText_String_Font_TestData()
    {
        yield return new object[] { "string", null };
        yield return new object[] { "string", SystemFonts.MenuFont };
    }

    [WinFormsTheory]
    [MemberData(nameof(MeasureText_String_Font_TestData))]
    public void TextRenderer_MeasureText_InvokeStringFont_ReturnsExpected(string text, Font font)
    {
        Size result = TextRenderer.MeasureText(text, font);
        Assert.True(result.Width > 0);
        Assert.True(result.Height > 0);

        // Call again to test caching.
        Assert.Equal(result, TextRenderer.MeasureText(text, font));
    }

    public static IEnumerable<object[]> MeasureText_String_Font_Size_TestData()
    {
        yield return new object[] { "string", null, Size.Empty };
        yield return new object[] { "string", null, new Size(1, 2) };
        yield return new object[] { "string", null, new Size(100, 200) };
        yield return new object[] { "string", null, new Size(int.MaxValue, int.MaxValue) };
        yield return new object[] { "string", SystemFonts.MenuFont, Size.Empty };
        yield return new object[] { "string", SystemFonts.MenuFont, new Size(1, 2) };
        yield return new object[] { "string", SystemFonts.MenuFont, new Size(100, 200) };
        yield return new object[] { "string", SystemFonts.MenuFont, new Size(int.MaxValue, int.MaxValue) };
    }

    [WinFormsTheory]
    [MemberData(nameof(MeasureText_String_Font_Size_TestData))]
    public void TextRenderer_MeasureText_InvokeStringFontSize_ReturnsExpected(string text, Font font, Size proposedSize)
    {
        Size result = TextRenderer.MeasureText(text, font, proposedSize);
        Assert.True(result.Width > 0);
        Assert.True(result.Height > 0);

        // Call again to test caching.
        Assert.Equal(result, TextRenderer.MeasureText(text, font, proposedSize));
    }

    public static IEnumerable<object[]> MeasureText_String_Font_Size_TextFormatFlags_TestData()
    {
        yield return new object[] { "string", null, Size.Empty, TextFormatFlags.Default };
        yield return new object[] { "string", null, new Size(1, 2), TextFormatFlags.Default };
        yield return new object[] { "string", null, new Size(100, 200), TextFormatFlags.Default };
        yield return new object[] { "string", null, new Size(int.MaxValue, int.MaxValue), TextFormatFlags.Default };
        yield return new object[] { "string", SystemFonts.MenuFont, Size.Empty, TextFormatFlags.Default };
        yield return new object[] { "string", SystemFonts.MenuFont, new Size(1, 2), TextFormatFlags.Default };
        yield return new object[] { "string", SystemFonts.MenuFont, new Size(100, 200), TextFormatFlags.Default };
        yield return new object[] { "string", SystemFonts.MenuFont, new Size(int.MaxValue, int.MaxValue), TextFormatFlags.Default };

        yield return new object[] { "string", SystemFonts.MenuFont, new Size(100, 200), TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter };
        yield return new object[] { "string", SystemFonts.MenuFont, new Size(100, 200), TextFormatFlags.Bottom | TextFormatFlags.Right };
        yield return new object[] { "string", SystemFonts.MenuFont, new Size(100, 200), TextFormatFlags.SingleLine };
        yield return new object[] { "string", SystemFonts.MenuFont, new Size(int.MaxValue, int.MaxValue), TextFormatFlags.SingleLine };
        yield return new object[] { "string", SystemFonts.MenuFont, new Size(100, 200), (TextFormatFlags)1024 };
        yield return new object[] { "string", SystemFonts.MenuFont, new Size(100, 200), TextFormatFlags.RightToLeft };
        yield return new object[] { "string", SystemFonts.MenuFont, new Size(100, 200), (TextFormatFlags)int.MaxValue };
    }

    [WinFormsTheory]
    [MemberData(nameof(MeasureText_String_Font_Size_TextFormatFlags_TestData))]
    public void TextRenderer_MeasureText_InvokeStringFontSizeTextFormatFlags_ReturnsExpected(string text, Font font, Size proposedSize, TextFormatFlags flags)
    {
        Size result = TextRenderer.MeasureText(text, font, proposedSize, flags);
        Assert.True(result.Width > 0);
        Assert.True(result.Height > 0);

        // Call again to test caching.
        Assert.Equal(result, TextRenderer.MeasureText(text, font, proposedSize, flags));
    }

    [WinFormsTheory]
    [MemberData(nameof(MeasureText_String_Font_TestData))]
    public void TextRenderer_MeasureText_InvokeIDeviceContextStringFont_ReturnsExpected(string text, Font font)
    {
        using Bitmap image = new(10, 10);
        using Graphics graphics = Graphics.FromImage(image);

        Size result = TextRenderer.MeasureText(graphics, text, font);
        Assert.True(result.Width > 0);
        Assert.True(result.Height > 0);

        // Call again to test caching.
        Assert.Equal(result, TextRenderer.MeasureText(graphics, text, font));
    }

    [WinFormsTheory]
    [MemberData(nameof(MeasureText_String_Font_Size_TestData))]
    public void TextRenderer_MeasureText_InvokeIDeviceContextStringFontSize_ReturnsExpected(string text, Font font, Size proposedSize)
    {
        using Bitmap image = new(10, 10);
        using Graphics graphics = Graphics.FromImage(image);

        Size result = TextRenderer.MeasureText(graphics, text, font, proposedSize);
        Assert.True(result.Width > 0);
        Assert.True(result.Height > 0);

        // Call again to test caching.
        Assert.Equal(result, TextRenderer.MeasureText(graphics, text, font, proposedSize));
    }

    [WinFormsTheory]
    [MemberData(nameof(MeasureText_String_Font_Size_TextFormatFlags_TestData))]
    public void TextRenderer_MeasureText_InvokeIDeviceContextStringFontSizeTextFormatFlags_ReturnsExpected(string text, Font font, Size proposedSize, TextFormatFlags flags)
    {
        using Bitmap image = new(10, 10);
        using Graphics graphics = Graphics.FromImage(image);

        Size result = TextRenderer.MeasureText(graphics, text, font, proposedSize, flags);
        Assert.True(result.Width > 0);
        Assert.True(result.Height > 0);

        // Call again to test caching.
        Assert.Equal(result, TextRenderer.MeasureText(graphics, text, font, proposedSize, flags));
    }

    [WinFormsTheory]
    [NullAndEmptyStringData]
    public void TextRenderer_MeasureText_NullOrEmptyString_ReturnsEmpty(string text)
    {
        using Bitmap image = new(10, 10);
        using Graphics graphics = Graphics.FromImage(image);
        Assert.Equal(Size.Empty, TextRenderer.MeasureText(text, SystemFonts.MenuFont));
        Assert.Equal(Size.Empty, TextRenderer.MeasureText(text, SystemFonts.MenuFont, new Size(300, 400)));
        Assert.Equal(Size.Empty, TextRenderer.MeasureText(text, SystemFonts.MenuFont, new Size(300, 400), TextFormatFlags.Default));
        Assert.Equal(Size.Empty, TextRenderer.MeasureText(graphics, text, SystemFonts.MenuFont));
        Assert.Equal(Size.Empty, TextRenderer.MeasureText(graphics, text, SystemFonts.MenuFont, new Size(300, 400)));
        Assert.Equal(Size.Empty, TextRenderer.MeasureText(graphics, text, SystemFonts.MenuFont, new Size(300, 400), TextFormatFlags.Default));
        Assert.Equal(Size.Empty, TextRenderer.MeasureText(text.AsSpan(), SystemFonts.MenuFont));
        Assert.Equal(Size.Empty, TextRenderer.MeasureText(text.AsSpan(), SystemFonts.MenuFont, new Size(300, 400)));
        Assert.Equal(Size.Empty, TextRenderer.MeasureText(text.AsSpan(), SystemFonts.MenuFont, new Size(300, 400), TextFormatFlags.Default));
        Assert.Equal(Size.Empty, TextRenderer.MeasureText(graphics, text.AsSpan(), SystemFonts.MenuFont));
        Assert.Equal(Size.Empty, TextRenderer.MeasureText(graphics, text.AsSpan(), SystemFonts.MenuFont, new Size(300, 400)));
        Assert.Equal(Size.Empty, TextRenderer.MeasureText(graphics, text.AsSpan(), SystemFonts.MenuFont, new Size(300, 400), TextFormatFlags.Default));
    }

    [WinFormsFact]
    public void TextRenderer_MeasureText_Mocked_Success()
    {
        using Bitmap image = new(10, 10);
        using Graphics graphics = Graphics.FromImage(image);
        Mock<IDeviceContext> mockDeviceContext = new(MockBehavior.Strict);
        mockDeviceContext
            .Setup(c => c.GetHdc())
            .Returns(graphics.GetHdc)
            .Verifiable();
        mockDeviceContext
            .Setup(c => c.ReleaseHdc())
            .Callback(graphics.ReleaseHdc)
            .Verifiable();

        TextRenderer.MeasureText(mockDeviceContext.Object, "text", SystemFonts.MenuFont);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Once());
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Once());

        TextRenderer.MeasureText(mockDeviceContext.Object, "text", SystemFonts.MenuFont, new Size(300, 400));
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(2));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(2));

        TextRenderer.MeasureText(mockDeviceContext.Object, "text", SystemFonts.MenuFont, new Size(300, 400), TextFormatFlags.Default);
        mockDeviceContext.Verify(c => c.GetHdc(), Times.Exactly(3));
        mockDeviceContext.Verify(c => c.ReleaseHdc(), Times.Exactly(3));
    }

    [WinFormsFact]
    public void TextRenderer_MeasureText_NullDc_ThrowsArgumentNullException()
    {
        Assert.Throws<ArgumentNullException>("dc", () => TextRenderer.MeasureText(null, string.Empty, SystemFonts.MenuFont));
        Assert.Throws<ArgumentNullException>("dc", () => TextRenderer.MeasureText(null, string.Empty, SystemFonts.MenuFont, new Size(300, 400)));
        Assert.Throws<ArgumentNullException>("dc", () => TextRenderer.MeasureText(null, string.Empty, SystemFonts.MenuFont, new Size(300, 400), TextFormatFlags.Default));
    }

    [WinFormsTheory]
    [MemberData(nameof(TextRenderer_DrawText_DefaultBackground_RendersTransparent_TestData))]
    public unsafe void TextRenderer_DrawText_DefaultBackground_RendersTransparent(Func<IDeviceContext, Action> func)
    {
        using EmfScope emf = new();
        DeviceContextState state = new(emf);
        func(new HdcDeviceContextAdapter(emf)).Invoke();

        emf.Validate(
            state,
            Validate.TextOut(
                "Acrylic",
                bounds: null,                                   // Don't care about the bounds for this test
                State.FontFace(SystemFonts.DefaultFont.Name),
                State.TextColor(Color.Blue),
                State.BackgroundMode(BACKGROUND_MODE.TRANSPARENT)));
    }

    public static TheoryData<Func<IDeviceContext, Action>> TextRenderer_DrawText_DefaultBackground_RendersTransparent_TestData
        =>
        [
                (IDeviceContext context) => () =>
                    TextRenderer.DrawText(context, "Acrylic", SystemFonts.DefaultFont,
                        pt: default, Color.Blue),
                (IDeviceContext context) => () =>
                    TextRenderer.DrawText(context, "Acrylic", SystemFonts.DefaultFont,
                        pt: default, Color.Blue, flags: default),
                (IDeviceContext context) => () =>
                    TextRenderer.DrawText(context, "Acrylic", SystemFonts.DefaultFont,
                        bounds: new Rectangle(0, 0, int.MaxValue, int.MaxValue), Color.Blue),
                (IDeviceContext context) => () =>
                    TextRenderer.DrawText(context, "Acrylic", SystemFonts.DefaultFont,
                        bounds: new Rectangle(0, 0, int.MaxValue, int.MaxValue), Color.Blue, flags: default),
            ];

    [Theory]
    [MemberData(nameof(TextRenderer_Span_ModifyString_ThrowsArgumentOutOfRange_TestData))]
    public void TextRenderer_Span_ModifyString_ThrowsArgumentOutOfRange(Action action)
    {
        Assert.Throws<ArgumentOutOfRangeException>("flags", action);
    }

#pragma warning disable CS0618 // Type or member is obsolete
    public static TheoryData<Action> TextRenderer_Span_ModifyString_ThrowsArgumentOutOfRange_TestData()
        =>
        [
            () => TextRenderer.DrawText(
                MockDC.Instance,
                string.Empty.AsSpan(),
                null,
                default(Point),
                Color.Empty,
                TextFormatFlags.ModifyString),
            () => TextRenderer.DrawText(
                MockDC.Instance,
                string.Empty.AsSpan(),
                null,
                default(Point),
                Color.Empty,
                Color.Empty,
                TextFormatFlags.ModifyString),
            () => TextRenderer.DrawText(
                MockDC.Instance,
                string.Empty.AsSpan(),
                null,
                default(Rectangle),
                Color.Empty,
                TextFormatFlags.ModifyString),
            () => TextRenderer.DrawText(
                MockDC.Instance,
                string.Empty.AsSpan(),
                null,
                default(Rectangle),
                Color.Empty,
                Color.Empty,
                TextFormatFlags.ModifyString),
            () => TextRenderer.MeasureText(
                MockDC.Instance,
                string.Empty.AsSpan(),
                null,
                default,
                TextFormatFlags.ModifyString),
            () => TextRenderer.MeasureText(
                string.Empty.AsSpan(),
                null,
                default,
                TextFormatFlags.ModifyString),
        ];
#pragma warning restore CS0618

    private class MockDC : IDeviceContext
    {
        public static MockDC Instance { get; } = new();
        public void Dispose() { }
        public IntPtr GetHdc() => IntPtr.Zero;
        public void ReleaseHdc() { }
    }

    [WinFormsTheory]
    [MemberData(nameof(TextRenderer_DrawText_Padding_TestData))]
    public unsafe void TextRenderer_DrawText_Padding_Point(TextFormatFlags flags, Rectangle expectedBounds)
    {
        using EmfScope emf = new();
        DeviceContextState state = new(emf);
        TextRenderer.DrawText(
            new HdcDeviceContextAdapter(emf),
            "Sparkling Cider",
            SystemFonts.DefaultFont,
            (Point)default,
            Color.Red,
            flags);

        emf.Validate(
            state,
            Validate.TextOut(
                "Sparkling Cider",
                expectedBounds,
                State.FontFace(SystemFonts.DefaultFont.Name),
                State.TextColor(Color.Red)));
    }

    [WinFormsTheory]
    [MemberData(nameof(TextRenderer_DrawText_Padding_TestData))]
    public unsafe void TextRenderer_DrawText_Padding_Rectangle(TextFormatFlags flags, Rectangle expectedBounds)
    {
        using EmfScope emf = new();
        DeviceContextState state = new(emf);
        TextRenderer.DrawText(
            new HdcDeviceContextAdapter(emf),
            "Sparkling Cider",
            SystemFonts.DefaultFont,
            new Rectangle(0, 0, int.MaxValue, int.MaxValue),
            Color.Red,
            flags);

        emf.Validate(
            state,
            Validate.TextOut(
                "Sparkling Cider",
                expectedBounds,
                State.FontFace(SystemFonts.DefaultFont.Name),
                State.TextColor(Color.Red)));
    }

    public static TheoryData<TextFormatFlags, Rectangle> TextRenderer_DrawText_Padding_TestData
        => new()
        {
            { TextFormatFlags.GlyphOverhangPadding, new Rectangle(3, 0, 70, 12) },
            { TextFormatFlags.LeftAndRightPadding, new Rectangle(5, 0, 70, 12) },
            { TextFormatFlags.NoPadding, new Rectangle(0, 0, 70, 12) }
        };

    [WinFormsTheory]
    [MemberData(nameof(TextRenderer_MeasureText_Padding_TestData))]
    public void TextRenderer_MeasureText_Padding(TextFormatFlags flags, Size expectedSize)
    {
        using Bitmap image = new(200, 50);
        using Graphics graphics = Graphics.FromImage(image);
        Size size = TextRenderer.MeasureText(
            graphics,
            "Sparkling Cider",
            SystemFonts.DefaultFont,
            new Size(int.MaxValue, int.MaxValue),
            flags);

        Assert.Equal(expectedSize, size);
    }

    public static TheoryData<TextFormatFlags, Size> TextRenderer_MeasureText_Padding_TestData
        => new()
        {
            { TextFormatFlags.GlyphOverhangPadding, new Size(78, 13) },
            { TextFormatFlags.LeftAndRightPadding, new Size(82, 13) },
            { TextFormatFlags.NoPadding, new Size(71, 13) }
        };

    [WinFormsTheory]
    [MemberData(nameof(TextRenderer_DrawText_ApplyState_TestData))]
    public void TextRenderer_DrawText_ApplyState(TextFormatFlags flags, Rectangle expectedBounds)
    {
        using var hdc = new CreateDcScope(default);
        DeviceContextState state = new(hdc);

        using MemoryStream stream = new(1024);
        using (Metafile metafileRecorder = new(stream, hdc.HDC, EmfType.EmfOnly))
        using (Graphics graphics = Graphics.FromImage(metafileRecorder))
        {
            using Matrix matrix = new();
            matrix.Translate(5, 10);
            graphics.Transform = matrix;
            using Region region = new(new Rectangle(1, 2, 6, 8));
            graphics.Clip = region;

            // We have modified graphics, but several tests don't set all the flags
            // TextRenderer asserts for to ensure integrity.
            using NoAssertContext noAssertContext = new();

            TextRenderer.DrawText(
                graphics,
                "Landshark",
                SystemFonts.DefaultFont,
                new Rectangle(0, 0, int.MaxValue, int.MaxValue),
                Color.Red,
                flags);
        }

        // Need to queue the stream back to the beginning for the reader
        stream.Position = 0;
        using Metafile metafile = new(stream);
        using EmfScope emf = new((HENHMETAFILE)metafile.GetHenhmetafile());

        emf.Validate(
            state,
            Validate.TextOut(
                "Landshark",
                expectedBounds,
                State.FontFace(SystemFonts.DefaultFont.Name),
                State.TextColor(Color.Red)));
    }

    public static TheoryData<TextFormatFlags, Rectangle> TextRenderer_DrawText_ApplyState_TestData
        => new()
        {
            { TextFormatFlags.Default, new Rectangle(3, 0, 49, 12) },
            { TextFormatFlags.PreserveGraphicsTranslateTransform, new Rectangle(8, 10, 49, 12) },
            { TextFormatFlags.PreserveGraphicsClipping, new Rectangle(6, 12, 5, 0) },
            { TextFormatFlags.PreserveGraphicsClipping | TextFormatFlags.PreserveGraphicsTranslateTransform, new Rectangle(8, 12, 3, 7) },
        };

    [WinFormsTheory]
    [MemberData(nameof(TextRenderer_MeasureText_ApplyState_TestData))]
    public void TextRenderer_MeasureText_ApplyState(TextFormatFlags flags, Size expectedSize)
    {
        using Bitmap image = new(200, 50);
        using Graphics graphics = Graphics.FromImage(image);
        using Matrix matrix = new();
        matrix.Translate(5, 10);
        graphics.Transform = matrix;
        using Region region = new(new Rectangle(1, 2, 6, 8));
        graphics.Clip = region;

        // We have modified graphics, but several tests don't set all the flags
        // TextRenderer asserts for to ensure integrity.
        using NoAssertContext noAssertContext = new();

        Size size = TextRenderer.MeasureText(
            graphics,
            "Landshark",
            SystemFonts.DefaultFont,
            new Size(int.MaxValue, int.MaxValue),
            flags);

        Assert.Equal(expectedSize, size);
    }

    public static TheoryData<TextFormatFlags, Size> TextRenderer_MeasureText_ApplyState_TestData
        => new()
        {
            // State application doesn't practically impact size measurements, but we still want to have a regression test
            // here in case something sneaks in.
            { TextFormatFlags.Default, new Size(57, 13) },
            { TextFormatFlags.PreserveGraphicsTranslateTransform, new Size(57, 13) },
            { TextFormatFlags.PreserveGraphicsClipping, new Size(57, 13) },
            { TextFormatFlags.PreserveGraphicsClipping | TextFormatFlags.PreserveGraphicsTranslateTransform, new Size(57, 13) },
        };
}
