From 9a94a6225cb7ab9c0cbca9fa6ab37118e9022ee7 Mon Sep 17 00:00:00 2001 From: Benedikt Stebner Date: Wed, 15 Jan 2025 08:52:59 +0100 Subject: [PATCH] Skia - Only reverse radial gradient stops if we cover the whole content bounds --- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 37 ++++++++++-------- .../Media/RadialGradientBrushTests.cs | 26 ++++++++++++ ...alGradientBrush_Partial_Cover.expected.png | Bin 0 -> 8582 bytes ...alGradientBrush_Partial_Cover.expected.png | Bin 0 -> 7609 bytes 4 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_Partial_Cover.expected.png create mode 100644 tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_Partial_Cover.expected.png diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index f4ebd33c3f5..96f43b554b8 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -964,34 +964,39 @@ private static void ConfigureGradientBrush(ref PaintWrapper paintWrapper, Rect t (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); + + var endOffset = 0.0; // 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]; + var offset = stopOffsets[i]; + + if (endOffset < offset) + { + endOffset = offset; + } + + reversedStops[i] = offset; + if (reversedStops[i] > 0 && reversedStops[i] < 1) { - reversedStops[i] = Math.Abs(1 - stopOffsets[i]); + reversedStops[i] = Math.Abs(1 - offset); } } // 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) - - ) - ) + SKShader.CreateColor(stopColors[0]), + transform.HasValue + ? SKShader.CreateTwoPointConicalGradient(start, radiusStart, end, radiusEnd, + stopColors, stopOffsets, tileMode, transform.Value.ToSKMatrix()) + : SKShader.CreateTwoPointConicalGradient(start, radiusStart, end, radiusEnd, + stopColors, stopOffsets, tileMode) + + ) + ) { paintWrapper.Paint.Shader = shader; } diff --git a/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs b/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs index c70d5a2c9bf..bffacf4543e 100644 --- a/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs +++ b/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs @@ -19,6 +19,32 @@ public RadialGradientBrushTests() : base(@"Media\RadialGradientBrush") { } + [Fact] + public async Task RadialGradientBrush_Partial_Cover() + { + Decorator target = new Decorator + { + Padding = new Thickness(8), + Width = 200, + Height = 200, + Child = new Border + { + Background = new RadialGradientBrush + { + GradientStops = + { + new GradientStop { Color = Colors.White, Offset = 0 }, + new GradientStop { Color = Color.Parse("#00DD00"), Offset = 0.7 } + }, + GradientOrigin = new RelativePoint(0.7, 0.15, RelativeUnit.Relative) + } + } + }; + + await RenderToFile(target); + CompareImages(); + } + [Fact] public async Task RadialGradientBrush_RedBlue() { diff --git a/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_Partial_Cover.expected.png b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_Partial_Cover.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..f36b636083370c7753d76203961c526d67befb4e GIT binary patch literal 8582 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�)C{bAhZG_1l#zq-mJ!lKPn!Vnyys4 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 literal 0 HcmV?d00001