diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
index 98528a128a..05a8daaec8 100644
--- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
+++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
@@ -583,14 +583,45 @@ namespace Avalonia.Skia
var center = radialGradient.Center.ToPixels(targetSize).ToSKPoint();
var radius = (float)(radialGradient.Radius * targetSize.Width);
- // TODO: There is no SetAlpha in SkiaSharp
- //paint.setAlpha(128);
+ var origin = radialGradient.GradientOrigin.ToPixels(targetSize).ToSKPoint();
- // would be nice to cache these shaders possibly?
- using (var shader =
- SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode))
+ if (origin.Equals(center))
{
- paintWrapper.Paint.Shader = shader;
+ // when the origin is the same as the center the Skia RadialGradient acts the same as D2D
+ using (var shader =
+ SKShader.CreateRadialGradient(center, radius, 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
+
+ // 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]),
+ SKShader.CreateTwoPointConicalGradient(center, radius, origin, 0, reversedColors, reversedStops, tileMode)
+ ))
+ {
+ paintWrapper.Paint.Shader = shader;
+ }
}
break;
diff --git a/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs b/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs
index 9beb860bee..2941b8dc34 100644
--- a/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs
+++ b/tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs
@@ -18,7 +18,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
public RadialGradientBrushTests() : base(@"Media\RadialGradientBrush")
{
}
-
+
[Fact]
public async Task RadialGradientBrush_RedBlue()
{
@@ -43,5 +43,127 @@ namespace Avalonia.Direct2D1.RenderTests.Media
await RenderToFile(target);
CompareImages();
}
+
+ ///
+ /// Tests using a GradientOrigin that falls inside of the circle described by Center/Radius.
+ ///
+ [Fact]
+ public async Task RadialGradientBrush_RedBlue_Offset_Inside()
+ {
+ Decorator target = new Decorator
+ {
+ Padding = new Thickness(8),
+ Width = 200,
+ Height = 200,
+ Child = new Border
+ {
+ Background = new RadialGradientBrush
+ {
+ GradientStops =
+ {
+ new GradientStop { Color = Colors.Red, Offset = 0 },
+ new GradientStop { Color = Colors.Blue, Offset = 1 }
+ },
+ GradientOrigin = new RelativePoint(0.25, 0.25, RelativeUnit.Relative)
+ }
+ }
+ };
+
+ await RenderToFile(target);
+ CompareImages();
+ }
+
+ ///
+ /// Tests using a GradientOrigin that falls outside of the circle described by Center/Radius.
+ ///
+ [Fact]
+ public async Task RadialGradientBrush_RedBlue_Offset_Outside()
+ {
+ Decorator target = new Decorator
+ {
+ Padding = new Thickness(8),
+ Width = 200,
+ Height = 200,
+ Child = new Border
+ {
+ Background = new RadialGradientBrush
+ {
+ GradientStops =
+ {
+ new GradientStop { Color = Colors.Red, Offset = 0 },
+ new GradientStop { Color = Colors.Blue, Offset = 1 }
+ },
+ GradientOrigin = new RelativePoint(0.1, 0.1, RelativeUnit.Relative)
+ }
+ }
+ };
+
+ await RenderToFile(target);
+ CompareImages();
+ }
+
+ ///
+ /// Tests using a GradientOrigin that falls inside of the circle described by Center/Radius.
+ ///
+ [Fact]
+ public async Task RadialGradientBrush_RedGreenBlue_Offset_Inside()
+ {
+ Decorator target = new Decorator
+ {
+ Padding = new Thickness(8),
+ Width = 200,
+ Height = 200,
+ Child = new Border
+ {
+ Background = new RadialGradientBrush
+ {
+ GradientStops =
+ {
+ new GradientStop { Color = Colors.Red, Offset = 0 },
+ new GradientStop { Color = Colors.Green, Offset = 0.5 },
+ new GradientStop { Color = Colors.Blue, Offset = 1 }
+ },
+ GradientOrigin = new RelativePoint(0.25, 0.25, RelativeUnit.Relative),
+ Center = new RelativePoint(0.5, 0.5, RelativeUnit.Relative),
+ Radius = 0.5
+ }
+ }
+ };
+
+ await RenderToFile(target);
+ CompareImages();
+ }
+
+ ///
+ /// Tests using a GradientOrigin that falls outside of the circle described by Center/Radius.
+ ///
+ [Fact]
+ public async Task RadialGradientBrush_RedGreenBlue_Offset_Outside()
+ {
+ Decorator target = new Decorator
+ {
+ Padding = new Thickness(8),
+ Width = 200,
+ Height = 200,
+ Child = new Border
+ {
+ Background = new RadialGradientBrush
+ {
+ GradientStops =
+ {
+ new GradientStop { Color = Colors.Red, Offset = 0 },
+ new GradientStop { Color = Colors.Green, Offset = 0.25 },
+ new GradientStop { Color = Colors.Blue, Offset = 1 }
+ },
+ GradientOrigin = new RelativePoint(0.1, 0.1, RelativeUnit.Relative),
+ Center = new RelativePoint(0.5, 0.5, RelativeUnit.Relative),
+ Radius = 0.5
+ }
+ }
+ };
+
+ await RenderToFile(target);
+ CompareImages();
+ }
}
}
diff --git a/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png
new file mode 100644
index 0000000000..4d690abee5
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png
new file mode 100644
index 0000000000..667aa9151e
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png
new file mode 100644
index 0000000000..1d660f79d1
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png
new file mode 100644
index 0000000000..ea1009b54a
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png
new file mode 100644
index 0000000000..4d690abee5
Binary files /dev/null and b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png
new file mode 100644
index 0000000000..667aa9151e
Binary files /dev/null and b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png
new file mode 100644
index 0000000000..1d660f79d1
Binary files /dev/null and b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png
new file mode 100644
index 0000000000..ea1009b54a
Binary files /dev/null and b/tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png differ