Skip to content

Commit

Permalink
feat: Added CompositionRadialGradientBrush implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
VitezslavImrysek committed Jul 30, 2021
1 parent ab93de0 commit 031eae3
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
#pragma warning disable 114 // new keyword hiding
namespace Windows.UI.Composition
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
#if false
[global::Uno.NotImplemented]
#endif
public partial class CompositionRadialGradientBrush : global::Windows.UI.Composition.CompositionGradientBrush
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
#if false
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public global::System.Numerics.Vector2 GradientOriginOffset
{
Expand All @@ -21,7 +21,7 @@ public partial class CompositionRadialGradientBrush : global::Windows.UI.Compos
}
}
#endif
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
#if false
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public global::System.Numerics.Vector2 EllipseRadius
{
Expand All @@ -35,7 +35,7 @@ public partial class CompositionRadialGradientBrush : global::Windows.UI.Compos
}
}
#endif
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
#if false
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public global::System.Numerics.Vector2 EllipseCenter
{
Expand Down
37 changes: 37 additions & 0 deletions src/Uno.UWP/UI/Composition/CompositionRadialGradientBrush.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#nullable enable

using System.Numerics;

namespace Windows.UI.Composition
{
public partial class CompositionRadialGradientBrush : CompositionGradientBrush
{
private Vector2 _gradientOriginOffset = Vector2.Zero;
private Vector2 _ellipseRadius = new Vector2(0.5f, 0.5f);
private Vector2 _ellipseCenter = new Vector2(0.5f, 0.5f);

internal CompositionRadialGradientBrush(Compositor compositor)
: base(compositor)
{

}

public Vector2 GradientOriginOffset
{
get => _gradientOriginOffset;
set => SetProperty(ref _gradientOriginOffset, value);
}

public Vector2 EllipseRadius
{
get => _ellipseRadius;
set => SetProperty(ref _ellipseRadius, value);
}

public Vector2 EllipseCenter
{
get => _ellipseCenter;
set => SetProperty(ref _ellipseCenter, value);
}
}
}
133 changes: 133 additions & 0 deletions src/Uno.UWP/UI/Composition/CompositionRadialGradientBrush.skia.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#nullable enable

using SkiaSharp;

namespace Windows.UI.Composition
{
public partial class CompositionRadialGradientBrush : CompositionGradientBrush
{
private protected override void UpdatePaintCore(SKPaint paint, SKRect bounds)
{
var center = EllipseCenter.ToSKPoint();
var gradientOrigin = EllipseCenter.ToSKPoint() + GradientOriginOffset.ToSKPoint();
var radius = EllipseRadius.ToSKPoint();
var transform = CreateTransformMatrix(bounds);

// Transform the points into absolute coordinates.
if (MappingMode == CompositionMappingMode.Relative)
{
// If the point are provided relative they must be multiplied by bounds.
center.X *= bounds.Width;
center.Y *= bounds.Height;

gradientOrigin.X *= bounds.Width;
gradientOrigin.Y *= bounds.Height;

radius.X *= bounds.Width;
radius.Y *= bounds.Height;
}

// Translate gradient points by bounds offset.
center.X += bounds.Left;
center.Y += bounds.Top;

gradientOrigin.X += bounds.Left;
gradientOrigin.Y += bounds.Top;
//

// SkiaSharp does not allow explicit definition of RadiusX and RadiusY.
// Compute transformation matrix to compensate.
ComputeRadiusAndScale(center, radius.X, radius.Y, out float gradientRadius, out SKMatrix matrix);

// Clean up old shader
if (paint.Shader != null)
{
paint.Shader.Dispose();
paint.Shader = null;
}

if (gradientRadius > 0)
{
// Create radial gradient shader.
SKShader shader =
SKShader.CreateTwoPointConicalGradient(
/* start */ gradientOrigin, /* start radius */ 0,
/* end */ center, /* gradient radius */ gradientRadius,
Colors, ColorPositions,
TileMode, transform.PreConcat(matrix));

paint.Shader = shader;
}
else
{
// With radius equal to 0, SkiaSharp does not draw anything.
// But we expect last gradient color.

// If there are no gradient stops available, use transparent.
SKColor color = SKColors.Transparent;
if (Colors!.Length > 0)
{
color = Colors[Colors.Length - 1];
}

paint.Color = color;
}
}

private void ComputeRadiusAndScale(SKPoint center, float radiusX, float radiusY, out float radius, out SKMatrix matrix)
{
matrix = SKMatrix.Identity;
if (radiusX == 0 || radiusY == 0)
{
// Handle this specific case as zero division would cause us troubles.
radius = 0;
return;
}

float scaleDownRatio;
if (radiusX >= radiusY)
{
// radiusX is larger, use it and scale down radiusY.
radius = radiusX;

scaleDownRatio = radiusY / radiusX;

SetScaleTranslate(
ref matrix,
/* scale x */ 1,
/* scale y */ scaleDownRatio,
/* translate x */ 0,
/* translate y */ center.Y - scaleDownRatio * center.Y);
}
else
{
// radiusY is larger, use it and scale down radiusX.
radius = radiusY;

scaleDownRatio = radiusX / radiusY;

SetScaleTranslate(
ref matrix,
/* scale x */ scaleDownRatio,
/* scale y */ 1,
/* translate x */ center.X - scaleDownRatio * center.X,
/* translate y */ 0);
}
}

private void SetScaleTranslate(ref SKMatrix matrix, float sx, float sy, float tx, float ty)
{
matrix.ScaleX = sx;
matrix.SkewX = 0;
matrix.TransX = tx;

matrix.SkewY = 0;
matrix.ScaleY = sy;
matrix.TransY = ty;

matrix.Persp0 = 0;
matrix.Persp1 = 0;
matrix.Persp2 = 1;
}
}
}

0 comments on commit 031eae3

Please sign in to comment.