Browse Source

Merge pull request #4749 from olliholliday/fix/radial-gradient-brush

Fix RadialGradientBrush GradientOrigin property usage.
pull/4815/head
Max Katz 6 years ago
committed by GitHub
parent
commit
be4b29c597
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 43
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  2. 124
      tests/Avalonia.RenderTests/Media/RadialGradientBrushTests.cs
  3. BIN
      tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png
  4. BIN
      tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png
  5. BIN
      tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png
  6. BIN
      tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png
  7. BIN
      tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png
  8. BIN
      tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png
  9. BIN
      tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png
  10. BIN
      tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png

43
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;

124
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();
}
/// <summary>
/// Tests using a GradientOrigin that falls inside of the circle described by Center/Radius.
/// </summary>
[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();
}
/// <summary>
/// Tests using a GradientOrigin that falls outside of the circle described by Center/Radius.
/// </summary>
[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();
}
/// <summary>
/// Tests using a GradientOrigin that falls inside of the circle described by Center/Radius.
/// </summary>
[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();
}
/// <summary>
/// Tests using a GradientOrigin that falls outside of the circle described by Center/Radius.
/// </summary>
[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();
}
}
}

BIN
tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
tests/TestFiles/Direct2D1/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Inside.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedBlue_Offset_Outside.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Inside.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
tests/TestFiles/Skia/Media/RadialGradientBrush/RadialGradientBrush_RedGreenBlue_Offset_Outside.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Loading…
Cancel
Save