Skip to content

Commit

Permalink
[Skia] Fix RadialGradientBrush for non center origin
Browse files Browse the repository at this point in the history
  • Loading branch information
Gillibald committed Jan 8, 2025
1 parent 0dd628f commit 29ee228
Showing 1 changed file with 10 additions and 55 deletions.
65 changes: 10 additions & 55 deletions src/Skia/Avalonia.Skia/DrawingContextImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -917,13 +917,16 @@ private static void ConfigureGradientBrush(ref PaintWrapper paintWrapper, Rect t
case IRadialGradientBrush radialGradient:
{
var centerPoint = radialGradient.Center.ToPixels(targetRect);
var center = centerPoint.ToSKPoint();

var radiusX = (radialGradient.RadiusX.ToValue(targetRect.Width));
var radiusY = (radialGradient.RadiusY.ToValue(targetRect.Height));

var originPoint = radialGradient.GradientOrigin.ToPixels(targetRect);


centerPoint += new Point(originPoint.X - targetRect.Width / 2, originPoint.Y - targetRect.Height / 2);

var center = centerPoint.ToSKPoint();

Matrix? transform = null;

if (radiusX != radiusY)
Expand All @@ -940,61 +943,13 @@ private static void ConfigureGradientBrush(ref PaintWrapper paintWrapper, Rect t
var brushTransform = (-offset) * radialGradient.Transform.Value * (offset);
transform = transform.HasValue ? transform * brushTransform : brushTransform;
}

if (originPoint.Equals(centerPoint))
{
// when the origin is the same as the center the Skia RadialGradient acts the same as D2D
using (var shader =
transform.HasValue
? SKShader.CreateRadialGradient(center, (float)radiusX, stopColors, stopOffsets, tileMode,
transform.Value.ToSKMatrix())
: SKShader.CreateRadialGradient(center, (float)radiusX, stopColors, stopOffsets, tileMode)
)
{
paintWrapper.Paint.Shader = shader;
}
}
else
{
// when the origin is different to the center use a two point ConicalGradient to match the behaviour of D2D

if (radiusX != radiusY)
// Adjust the origin point for radiusX/Y transformation by reversing it
originPoint = originPoint.WithY(
(originPoint.Y - centerPoint.Y) * radiusX / radiusY + centerPoint.Y);

var origin = originPoint.ToSKPoint();

// reverse the order of the stops to match D2D
var reversedColors = new SKColor[stopColors.Length];
Array.Copy(stopColors, reversedColors, stopColors.Length);
Array.Reverse(reversedColors);

// and then reverse the reference point of the stops
var reversedStops = new float[stopOffsets.Length];
for (var i = 0; i < stopOffsets.Length; i++)
{
reversedStops[i] = stopOffsets[i];
if (reversedStops[i] > 0 && reversedStops[i] < 1)
{
reversedStops[i] = Math.Abs(1 - stopOffsets[i]);
}
}

// compose with a background colour of the final stop to match D2D's behaviour of filling with the final color
using (var shader = SKShader.CreateCompose(
SKShader.CreateColor(reversedColors[0]),
transform.HasValue
? SKShader.CreateTwoPointConicalGradient(center, (float)radiusX, origin, 0,
reversedColors, reversedStops, tileMode, transform.Value.ToSKMatrix())
: SKShader.CreateTwoPointConicalGradient(center, (float)radiusX, origin, 0,
reversedColors, reversedStops, tileMode)

)
)
{
using (var shader = transform.HasValue
? SKShader.CreateRadialGradient(center, (float)radiusX, stopColors, stopOffsets, tileMode,
transform.Value.ToSKMatrix())
: SKShader.CreateRadialGradient(center, (float)radiusX, stopColors, stopOffsets, tileMode))
{
paintWrapper.Paint.Shader = shader;
}
}

break;
Expand Down

0 comments on commit 29ee228

Please sign in to comment.