Skip to content

Commit 90125e4

Browse files
committed
Skia - Only reverse gradient stops if we reach the end
1 parent 0dd628f commit 90125e4

File tree

1 file changed

+104
-73
lines changed

1 file changed

+104
-73
lines changed

src/Skia/Avalonia.Skia/DrawingContextImpl.cs

Lines changed: 104 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -915,90 +915,121 @@ private static void ConfigureGradientBrush(ref PaintWrapper paintWrapper, Rect t
915915
break;
916916
}
917917
case IRadialGradientBrush radialGradient:
918-
{
919-
var centerPoint = radialGradient.Center.ToPixels(targetRect);
920-
var center = centerPoint.ToSKPoint();
921-
922-
var radiusX = (radialGradient.RadiusX.ToValue(targetRect.Width));
923-
var radiusY = (radialGradient.RadiusY.ToValue(targetRect.Height));
924-
925-
var originPoint = radialGradient.GradientOrigin.ToPixels(targetRect);
926-
927-
Matrix? transform = null;
928-
929-
if (radiusX != radiusY)
930-
transform =
931-
Matrix.CreateTranslation(-centerPoint)
932-
* Matrix.CreateScale(1, radiusY / radiusX)
933-
* Matrix.CreateTranslation(centerPoint);
934-
935-
936-
if (radialGradient.Transform != null)
937918
{
938-
var transformOrigin = radialGradient.TransformOrigin.ToPixels(targetRect);
939-
var offset = Matrix.CreateTranslation(transformOrigin);
940-
var brushTransform = (-offset) * radialGradient.Transform.Value * (offset);
941-
transform = transform.HasValue ? transform * brushTransform : brushTransform;
942-
}
943-
944-
if (originPoint.Equals(centerPoint))
945-
{
946-
// when the origin is the same as the center the Skia RadialGradient acts the same as D2D
947-
using (var shader =
948-
transform.HasValue
949-
? SKShader.CreateRadialGradient(center, (float)radiusX, stopColors, stopOffsets, tileMode,
950-
transform.Value.ToSKMatrix())
951-
: SKShader.CreateRadialGradient(center, (float)radiusX, stopColors, stopOffsets, tileMode)
952-
)
919+
var centerPoint = radialGradient.Center.ToPixels(targetRect);
920+
var center = centerPoint.ToSKPoint();
921+
922+
var radiusX = (radialGradient.RadiusX.ToValue(targetRect.Width));
923+
var radiusY = (radialGradient.RadiusY.ToValue(targetRect.Height));
924+
925+
var originPoint = radialGradient.GradientOrigin.ToPixels(targetRect);
926+
927+
Matrix? transform = null;
928+
929+
if (radiusX != radiusY)
930+
transform =
931+
Matrix.CreateTranslation(-centerPoint)
932+
* Matrix.CreateScale(1, radiusY / radiusX)
933+
* Matrix.CreateTranslation(centerPoint);
934+
935+
936+
if (radialGradient.Transform != null)
953937
{
954-
paintWrapper.Paint.Shader = shader;
938+
var transformOrigin = radialGradient.TransformOrigin.ToPixels(targetRect);
939+
var offset = Matrix.CreateTranslation(transformOrigin);
940+
var brushTransform = (-offset) * radialGradient.Transform.Value * (offset);
941+
transform = transform.HasValue ? transform * brushTransform : brushTransform;
955942
}
956-
}
957-
else
958-
{
959-
// when the origin is different to the center use a two point ConicalGradient to match the behaviour of D2D
960943

961-
if (radiusX != radiusY)
962-
// Adjust the origin point for radiusX/Y transformation by reversing it
963-
originPoint = originPoint.WithY(
964-
(originPoint.Y - centerPoint.Y) * radiusX / radiusY + centerPoint.Y);
965-
966-
var origin = originPoint.ToSKPoint();
967-
968-
// reverse the order of the stops to match D2D
969-
var reversedColors = new SKColor[stopColors.Length];
970-
Array.Copy(stopColors, reversedColors, stopColors.Length);
971-
Array.Reverse(reversedColors);
972-
973-
// and then reverse the reference point of the stops
974-
var reversedStops = new float[stopOffsets.Length];
975-
for (var i = 0; i < stopOffsets.Length; i++)
944+
if (originPoint.Equals(centerPoint))
976945
{
977-
reversedStops[i] = stopOffsets[i];
978-
if (reversedStops[i] > 0 && reversedStops[i] < 1)
946+
// when the origin is the same as the center the Skia RadialGradient acts the same as D2D
947+
using (var shader =
948+
transform.HasValue
949+
? SKShader.CreateRadialGradient(center, (float)radiusX, stopColors, stopOffsets, tileMode,
950+
transform.Value.ToSKMatrix())
951+
: SKShader.CreateRadialGradient(center, (float)radiusX, stopColors, stopOffsets, tileMode)
952+
)
979953
{
980-
reversedStops[i] = Math.Abs(1 - stopOffsets[i]);
954+
paintWrapper.Paint.Shader = shader;
981955
}
982956
}
983-
984-
// compose with a background colour of the final stop to match D2D's behaviour of filling with the final color
985-
using (var shader = SKShader.CreateCompose(
986-
SKShader.CreateColor(reversedColors[0]),
987-
transform.HasValue
988-
? SKShader.CreateTwoPointConicalGradient(center, (float)radiusX, origin, 0,
989-
reversedColors, reversedStops, tileMode, transform.Value.ToSKMatrix())
990-
: SKShader.CreateTwoPointConicalGradient(center, (float)radiusX, origin, 0,
991-
reversedColors, reversedStops, tileMode)
992-
993-
)
994-
)
957+
else
995958
{
996-
paintWrapper.Paint.Shader = shader;
959+
// when the origin is different to the center use a two point ConicalGradient to match the behaviour of D2D
960+
961+
if (radiusX != radiusY)
962+
// Adjust the origin point for radiusX/Y transformation by reversing it
963+
originPoint = originPoint.WithY(
964+
(originPoint.Y - centerPoint.Y) * radiusX / radiusY + centerPoint.Y);
965+
966+
var origin = originPoint.ToSKPoint();
967+
968+
//// reverse the order of the stops to match D2D
969+
var reversedColors = new SKColor[stopColors.Length];
970+
Array.Copy(stopColors, reversedColors, stopColors.Length);
971+
Array.Reverse(reversedColors);
972+
973+
var end = 0.0;
974+
975+
//// and then reverse the reference point of the stops
976+
var reversedStops = new float[stopOffsets.Length];
977+
for (var i = 0; i < stopOffsets.Length; i++)
978+
{
979+
var offset = stopOffsets[i];
980+
981+
if (end < offset)
982+
{
983+
end = offset;
984+
}
985+
986+
reversedStops[i] = offset;
987+
if (reversedStops[i] > 0 && reversedStops[i] < 1)
988+
{
989+
reversedStops[i] = Math.Abs(1 - offset);
990+
}
991+
}
992+
993+
var reverse = MathUtilities.AreClose(1, end);
994+
995+
if (reverse)
996+
{
997+
// compose with a background colour of the final stop to match D2D's behaviour of filling with the final color
998+
using (var shader = SKShader.CreateCompose(
999+
SKShader.CreateColor(reversedColors[0]),
1000+
transform.HasValue
1001+
? SKShader.CreateTwoPointConicalGradient(center, (float)radiusX, origin, 0,
1002+
reversedColors, reversedStops, tileMode, transform.Value.ToSKMatrix())
1003+
: SKShader.CreateTwoPointConicalGradient(center, (float)radiusX, origin, 0,
1004+
reversedColors, reversedStops, tileMode)
1005+
1006+
)
1007+
)
1008+
{
1009+
paintWrapper.Paint.Shader = shader;
1010+
}
1011+
}
1012+
else
1013+
{
1014+
// compose with a background colour of the final stop to match D2D's behaviour of filling with the final color
1015+
using (var shader = SKShader.CreateCompose(
1016+
SKShader.CreateColor(stopColors[0]),
1017+
transform.HasValue
1018+
? SKShader.CreateTwoPointConicalGradient(origin, 0, center, (float)radiusX,
1019+
stopColors, stopOffsets, tileMode, transform.Value.ToSKMatrix())
1020+
: SKShader.CreateTwoPointConicalGradient(origin, 0, center, (float)radiusX,
1021+
stopColors, stopOffsets, tileMode)
1022+
1023+
)
1024+
)
1025+
{
1026+
paintWrapper.Paint.Shader = shader;
1027+
}
1028+
}
9971029
}
998-
}
9991030

1000-
break;
1001-
}
1031+
break;
1032+
}
10021033
case IConicGradientBrush conicGradient:
10031034
{
10041035
var center = conicGradient.Center.ToPixels(targetRect).ToSKPoint();

0 commit comments

Comments
 (0)