Skip to content
This repository has been archived by the owner on Dec 21, 2023. It is now read-only.

[WinForms.GDI] improve support for gradient fills #171

Merged
merged 4 commits into from
Oct 2, 2021

Conversation

swharden
Copy link
Contributor

@swharden swharden commented Sep 14, 2021

This PR improves the WinForms GDI control's support for fills using gradient paints. It's not perfect (GDI support for gradient fills remains limited), but it's an improvement that may be worth considering. Related #44

EDIT: When filing rectangles with horizontal or vertical linear gradients (perhaps the most common use case, and fully supported by GDI) the appearance is excellent. It would be great if there were some way to at least support this functionality even if the partial functionality for the rest of the fill types is omitted.

  • Based on this comment block I suspect this was supported in the past.
  • SkiaCanvas.cs SetFillPaint() is a useful reference.
  • Linear paints in GDI "wrap around" whereas in Skia they keep going (see screenshots below).
  • Radial paint ends at the edge of the gradient rather than filling the whole shape. Achieving the desired outcome may be possible with a rectangular clip, drawing a solid filled rectangle, then drawing the radial shape on top. This means adding extra logic to all fill methods though. I can look into this based on your input.
  • Pattern and Image paints remain unsupported.

I'm a bit new here and not sure if your group is looking for these types of contributions at this time (#88) so feel free to do what you want with this, and I welcome any feedback you may have 馃憤

Demonstration

public class GradientTestDrawing : IDrawable
{
    public void Draw(ICanvas canvas, RectangleF dirtyRect)
    {
        // start with a known solid fill color
        canvas.FillColor = Colors.Maroon;

        // shape 1: linear gradient
        LinearGradientPaint linearPaint = new()
        {
            StartPoint = new Point(0, 0),
            EndPoint = new Point(1, 1),
            StartColor = Colors.Magenta,
            EndColor = Colors.Green,
        };
        Rectangle rect1 = new(10, 10, 100, 50);
        canvas.SetFillPaint(linearPaint, rect1);
        canvas.FillRectangle(rect1);

        // shape 2: solid color
        Rectangle rect2 = new(120, 10, 100, 50);
        canvas.FillColor = Colors.Navy;
        canvas.FillRectangle(rect2);

        // shape 3: linear gradient again
        Rectangle rect3 = new(230, 10, 100, 50);
        canvas.SetFillPaint(linearPaint, rect3);
        canvas.FillRectangle(rect3);

        // shape 4: radial gradient
        RadialGradientPaint radialPaint = new()
        {
            Center = new Point(.5, .5),
            Radius = .5,
            StartColor = Colors.Magenta,
            EndColor = Colors.Green,
        };
        Rectangle rect4 = new(340, 10, 100, 50);
        canvas.SetFillPaint(radialPaint, rect4);
        canvas.FillRectangle(rect4);
    }
}

The rectangular gradient fills work great!

Skia GDI Before GDI After
image image image

TestPattern1

Advanced fill gradients reveal GDIs limitations

Skia GDI Before GDI After
testpattern1-skia testpattern1-gdi-before testpattern1-gdi-after

EDIT: using WrapMode.TileFlipXY for linear gradients still isn't perfect, but may be less astonishing than the default tiling behavior seen in the screenshots above:
image

The GDI canvas now has separate SolidBrush, LinearGradientBrush, and PathGradientBrush objects.

When FillBrush is requested it returns a gradient brush if it exists, otherwise it returns or creates a solid brush with the current fill color.

Assigning the canvas's FillColor clears any stored gradient brushes and reverts to SolidFill behavior.
An "active brush" field is now used for all fill tasks.

Assigning to FillColor sets the active brush to a solid brush, but loading a linear or radial gradient paint switches it to an appropriate gradient fill brush.
@jonlipsky jonlipsky marked this pull request as ready for review October 2, 2021 20:42
@jonlipsky jonlipsky merged commit 36d4584 into dotnet:main Oct 2, 2021
@swharden swharden deleted the gdi-fill-gradient branch October 2, 2021 22:38
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants