File: System\Windows\Forms\ControlPaintTests.Rendering.cs
Web Access
Project: src\src\System.Windows.Forms\tests\UnitTests\System.Windows.Forms.Tests.csproj (System.Windows.Forms.Tests)
// 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.Numerics;
using System.Windows.Forms.Metafiles;
using static System.Windows.Forms.Metafiles.DataHelpers;
 
namespace System.Windows.Forms.Tests;
 
public partial class ControlPaintTests
{
    [WinFormsFact]
    public void ControlPaint_DrawBorder_Solid_Rendering()
    {
        using EmfScope emf = new();
        DeviceContextState state = new(emf);
 
        using Graphics graphics = Graphics.FromHdc((IntPtr)emf.HDC);
 
        Rectangle bounds = new(10, 10, 10, 10);
        ControlPaint.DrawBorder(graphics, bounds, Color.Blue, ButtonBorderStyle.Solid);
 
        emf.Validate(
            state,
            Validate.Rectangle(
                // We match the legacy GDI+ rendering, where the right and bottom are drawn inside the bounds
                new Rectangle(10, 10, 9, 9),
                State.Pen(1, Color.Blue, PEN_STYLE.PS_SOLID)));
    }
 
    [WinFormsFact]
    public void ControlPaint_DrawBorder_Inset_Rendering()
    {
        using EmfScope emf = new();
        DeviceContextState state = new(emf);
 
        using Graphics graphics = Graphics.FromHdc((IntPtr)emf.HDC);
 
        Rectangle bounds = new(10, 10, 10, 10);
        ControlPaint.DrawBorder(graphics, bounds, Color.Gray, ButtonBorderStyle.Inset);
 
        // For whatever reason GDI+ renders as polylines scaled 16x with a 1/16th world transform applied.
        // For test readability we'll transform the points from our coordinates to the logical coordinates.
        Matrix3x2 oneSixteenth = Matrix3x2.CreateScale(0.0625f);
        Matrix3x2 times16 = Matrix3x2.CreateScale(16.0f);
 
        // This is the default pen style GDI+ renders polylines with
        PEN_STYLE penStyle = PEN_STYLE.PS_SOLID | PEN_STYLE.PS_JOIN_ROUND | PEN_STYLE.PS_COSMETIC |
            PEN_STYLE.PS_ENDCAP_FLAT | PEN_STYLE.PS_JOIN_MITER | PEN_STYLE.PS_GEOMETRIC;
 
        emf.Validate(
            state,
            // Top
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 10, 10, 19, 10),
                State.Pen(16, ControlPaint.DarkDark(Color.Gray), penStyle),
                State.Transform(oneSixteenth)),
            // Left
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 10, 10, 10, 19),
                State.Pen(16, ControlPaint.DarkDark(Color.Gray), penStyle),
                State.Transform(oneSixteenth)),
            // Bottom
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 10, 19, 19, 19),
                State.Pen(16, ControlPaint.LightLight(Color.Gray), penStyle),
                State.Transform(oneSixteenth)),
            // Right
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 19, 10, 19, 19),
                State.Pen(16, ControlPaint.LightLight(Color.Gray), penStyle),
                State.Transform(oneSixteenth)),
            // Top inset
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 11, 11, 18, 11),
                State.Pen(16, ControlPaint.Light(Color.Gray), penStyle),
                State.Transform(oneSixteenth)),
            // Left inset
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 11, 11, 11, 18),
                State.Pen(16, ControlPaint.Light(Color.Gray), penStyle),
                State.Transform(oneSixteenth)));
    }
 
    [WinFormsFact]
    public void ControlPaint_DrawBorder_Inset_ControlColor_Rendering()
    {
        using EmfScope emf = new();
        DeviceContextState state = new(emf);
 
        using Graphics graphics = Graphics.FromHdc((IntPtr)emf.HDC);
 
        Rectangle bounds = new(10, 10, 10, 10);
        ControlPaint.DrawBorder(graphics, bounds, SystemColors.Control, ButtonBorderStyle.Inset);
 
        // For whatever reason GDI+ renders as polylines scaled 16x with a 1/16th world transform applied.
        // For test readability we'll transform the points from our coordinates to the logical coordinates.
        Matrix3x2 oneSixteenth = Matrix3x2.CreateScale(0.0625f);
        Matrix3x2 times16 = Matrix3x2.CreateScale(16.0f);
 
        // This is the default pen style GDI+ renders polylines with
        PEN_STYLE penStyle = PEN_STYLE.PS_SOLID | PEN_STYLE.PS_JOIN_ROUND | PEN_STYLE.PS_COSMETIC |
            PEN_STYLE.PS_ENDCAP_FLAT | PEN_STYLE.PS_JOIN_MITER | PEN_STYLE.PS_GEOMETRIC;
 
        emf.Validate(
            state,
            // Top
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 10, 10, 19, 10),
                State.Pen(16, ControlPaint.DarkDark(SystemColors.Control), penStyle),
                State.Transform(oneSixteenth)),
            // Left
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 10, 10, 10, 19),
                State.Pen(16, ControlPaint.DarkDark(SystemColors.Control), penStyle),
                State.Transform(oneSixteenth)),
            // Bottom
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 10, 19, 19, 19),
                State.Pen(16, ControlPaint.LightLight(SystemColors.Control), penStyle),
                State.Transform(oneSixteenth)),
            // Right
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 19, 10, 19, 19),
                State.Pen(16, ControlPaint.LightLight(SystemColors.Control), penStyle),
                State.Transform(oneSixteenth)),
            // Top inset
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 11, 11, 18, 11),
                State.Pen(16, ControlPaint.Light(SystemColors.Control), penStyle),
                State.Transform(oneSixteenth)),
            // Left inset
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 11, 11, 11, 18),
                State.Pen(16, ControlPaint.Light(SystemColors.Control), penStyle),
                State.Transform(oneSixteenth)),
 
            // The bottom/right insets are only drawn if the original color was SystemColors.Control.
 
            // Bottom inset
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 11, 18, 18, 18),
                State.Pen(16, SystemColors.ControlLight, penStyle),
                State.Transform(oneSixteenth)),
            // Right inset
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 18, 11, 18, 18),
                State.Pen(16, SystemColors.ControlLight, penStyle),
                State.Transform(oneSixteenth)));
    }
 
    [WinFormsFact]
    public void ControlPaint_DrawBorder_OutSet_Rendering()
    {
        using EmfScope emf = new();
        DeviceContextState state = new(emf);
 
        using Graphics graphics = Graphics.FromHdc((IntPtr)emf.HDC);
 
        Rectangle bounds = new(10, 10, 10, 10);
        ControlPaint.DrawBorder(graphics, bounds, Color.PeachPuff, ButtonBorderStyle.Outset);
 
        string dump = emf.RecordsToStringWithState(state);
 
        // For whatever reason GDI+ renders as polylines scaled 16x with a 1/16th world transform applied.
        // For test readability we'll transform the points from our coordinates to the logical coordinates.
        Matrix3x2 oneSixteenth = Matrix3x2.CreateScale(0.0625f);
        Matrix3x2 times16 = Matrix3x2.CreateScale(16.0f);
 
        // This is the default pen style GDI+ renders polylines with
        PEN_STYLE penStyle = PEN_STYLE.PS_SOLID | PEN_STYLE.PS_JOIN_ROUND | PEN_STYLE.PS_COSMETIC |
            PEN_STYLE.PS_ENDCAP_FLAT | PEN_STYLE.PS_JOIN_MITER | PEN_STYLE.PS_GEOMETRIC;
 
        emf.Validate(
            state,
            // Top
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 10, 10, 19, 10),
                State.Pen(16, ControlPaint.LightLight(Color.PeachPuff), penStyle),
                State.Transform(oneSixteenth)),
            // Left
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 10, 10, 10, 19),
                State.Pen(16, ControlPaint.LightLight(Color.PeachPuff), penStyle),
                State.Transform(oneSixteenth)),
            // Bottom
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 10, 19, 19, 19),
                State.Pen(16, ControlPaint.DarkDark(Color.PeachPuff), penStyle),
                State.Transform(oneSixteenth)),
            // Right
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 19, 10, 19, 19),
                State.Pen(16, ControlPaint.DarkDark(Color.PeachPuff), penStyle),
                State.Transform(oneSixteenth)),
            // Top inset
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 11, 11, 18, 11),
                State.Pen(16, Color.PeachPuff, penStyle),
                State.Transform(oneSixteenth)),
            // Left inset
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 11, 11, 11, 18),
                State.Pen(16, Color.PeachPuff, penStyle),
                State.Transform(oneSixteenth)),
            // Bottom inset
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 11, 18, 18, 18),
                State.Pen(16, ControlPaint.Dark(Color.PeachPuff), penStyle),
                State.Transform(oneSixteenth)),
            // Right inset
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 18, 11, 18, 18),
                State.Pen(16, ControlPaint.Dark(Color.PeachPuff), penStyle),
                State.Transform(oneSixteenth)));
    }
 
    [WinFormsFact]
    public void ControlPaint_DrawBorder_OutSet_ControlColor_Rendering()
    {
        using EmfScope emf = new();
        DeviceContextState state = new(emf);
 
        using Graphics graphics = Graphics.FromHdc((IntPtr)emf.HDC);
 
        Rectangle bounds = new(10, 10, 10, 10);
        ControlPaint.DrawBorder(graphics, bounds, SystemColors.Control, ButtonBorderStyle.Outset);
 
        string dump = emf.RecordsToStringWithState(state);
 
        // For whatever reason GDI+ renders as polylines scaled 16x with a 1/16th world transform applied.
        // For test readability we'll transform the points from our coordinates to the logical coordinates.
        Matrix3x2 oneSixteenth = Matrix3x2.CreateScale(0.0625f);
        Matrix3x2 times16 = Matrix3x2.CreateScale(16.0f);
 
        // This is the default pen style GDI+ renders polylines with
        PEN_STYLE penStyle = PEN_STYLE.PS_SOLID | PEN_STYLE.PS_JOIN_ROUND | PEN_STYLE.PS_COSMETIC |
            PEN_STYLE.PS_ENDCAP_FLAT | PEN_STYLE.PS_JOIN_MITER | PEN_STYLE.PS_GEOMETRIC;
 
        emf.Validate(
            state,
            // Top
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 10, 10, 19, 10),
                State.Pen(16, SystemColors.ControlLightLight, penStyle),
                State.Transform(oneSixteenth)),
            // Left
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 10, 10, 10, 19),
                State.Pen(16, SystemColors.ControlLightLight, penStyle),
                State.Transform(oneSixteenth)),
            // Bottom
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 10, 19, 19, 19),
                State.Pen(16, SystemColors.ControlDarkDark, penStyle),
                State.Transform(oneSixteenth)),
            // Right
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 19, 10, 19, 19),
                State.Pen(16, SystemColors.ControlDarkDark, penStyle),
                State.Transform(oneSixteenth)),
            // Top inset
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 11, 11, 18, 11),
                State.Pen(16, SystemColors.Control, penStyle),
                State.Transform(oneSixteenth)),
            // Left inset
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 11, 11, 11, 18),
                State.Pen(16, SystemColors.Control, penStyle),
                State.Transform(oneSixteenth)),
            // Bottom inset
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 11, 18, 18, 18),
                State.Pen(16, SystemColors.ControlDark, penStyle),
                State.Transform(oneSixteenth)),
            // Right inset
            Validate.Polyline16(
                bounds: null,
                PointArray(times16, 18, 11, 18, 18),
                State.Pen(16, SystemColors.ControlDark, penStyle),
                State.Transform(oneSixteenth)));
    }
 
    [WinFormsFact]
    public void ControlPaint_DrawBorder_Dotted_Rendering()
    {
        using EmfScope emf = new();
        DeviceContextState state = new(emf);
 
        using Graphics graphics = Graphics.FromHdc((IntPtr)emf.HDC);
 
        Rectangle bounds = new(10, 10, 10, 10);
        ControlPaint.DrawBorder(graphics, bounds, Color.Green, ButtonBorderStyle.Dotted);
 
        // For whatever reason GDI+ renders as polygons scaled 16x with a 1/16th world transform applied.
        Matrix3x2 oneSixteenth = Matrix3x2.CreateScale(0.0625f);
 
        // This is the default pen style GDI+ renders dotted lines with
        PEN_STYLE penStyle = PEN_STYLE.PS_SOLID | PEN_STYLE.PS_JOIN_ROUND | PEN_STYLE.PS_COSMETIC |
            PEN_STYLE.PS_ENDCAP_FLAT | PEN_STYLE.PS_JOIN_BEVEL | PEN_STYLE.PS_GEOMETRIC;
 
        emf.Validate(
        state,
            Validate.PolyPolygon16(
                new Rectangle(8, 8, 13, 13),
                polyCount: 18,
                State.Transform(oneSixteenth),
                State.Pen(16, Color.Green, penStyle),
                State.Brush(Color.Green, BRUSH_STYLE.BS_SOLID)));
    }
 
    [WinFormsFact]
    public void ControlPaint_DrawBorder_Dashed_Rendering()
    {
        using EmfScope emf = new();
        DeviceContextState state = new(emf);
 
        using Graphics graphics = Graphics.FromHdc((IntPtr)emf.HDC);
 
        Rectangle bounds = new(10, 10, 10, 10);
        ControlPaint.DrawBorder(graphics, bounds, Color.Pink, ButtonBorderStyle.Dashed);
 
        // For whatever reason GDI+ renders as polygons scaled 16x with a 1/16th world transform applied.
        Matrix3x2 oneSixteenth = Matrix3x2.CreateScale(0.0625f);
 
        // This is the default pen style GDI+ renders dotted lines with
        PEN_STYLE penStyle = PEN_STYLE.PS_SOLID | PEN_STYLE.PS_JOIN_ROUND | PEN_STYLE.PS_COSMETIC |
            PEN_STYLE.PS_ENDCAP_FLAT | PEN_STYLE.PS_JOIN_BEVEL | PEN_STYLE.PS_GEOMETRIC;
 
        emf.Validate(
        state,
            Validate.PolyPolygon16(
                new Rectangle(8, 8, 13, 13),
                polyCount: 9,
                State.Transform(oneSixteenth),
                State.Pen(16, Color.Pink, penStyle),
                State.Brush(Color.Pink, BRUSH_STYLE.BS_SOLID)));
    }
}