Skip to content

Commit

Permalink
feat: Added CompositionRectangleGeometry implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
VitezslavImrysek committed Jul 30, 2021
1 parent 031eae3 commit 8309bc7
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 13 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 CompositionRectangleGeometry : global::Windows.UI.Composition.CompositionGeometry
{
#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 Size
{
Expand All @@ -21,7 +21,7 @@ public partial class CompositionRectangleGeometry : global::Windows.UI.Composit
}
}
#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 Offset
{
Expand Down
9 changes: 4 additions & 5 deletions src/Uno.UWP/UI/Composition/CompositionGeometry.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#nullable enable

using Windows.Graphics;

namespace Windows.UI.Composition
{
public partial class CompositionGeometry : CompositionObject
Expand All @@ -9,15 +11,12 @@ internal CompositionGeometry(Compositor compositor) : base(compositor)

}

internal CompositionGeometry()
{

}

public float TrimStart { get; set; }

public float TrimOffset { get; set; }

public float TrimEnd { get; set; }

internal virtual IGeometrySource2D? BuildGeometry() => null;
}
}
152 changes: 152 additions & 0 deletions src/Uno.UWP/UI/Composition/CompositionGeometry.skia.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#nullable enable

using System;
using System.Numerics;
using SkiaSharp;

namespace Windows.UI.Composition
{
public partial class CompositionGeometry : CompositionObject
{
/// <summary>
/// Kappa = (sqrt(2) - 1) * 4/3;
// Used to calculate bezier control points for each of the circle four arcs.
// - Approximating a 1/4 circle with a bezier curve.
/// </summary>
private const double CIRCLE_BEZIER_KAPPA = 0.552284749830793398402251632279597438092895833835930764235;

internal static SKPath BuildLineGeometry(Vector2 start, Vector2 end)
{
SKPath path = new SKPath();

path.MoveTo(start.ToSKPoint());
path.LineTo(end.ToSKPoint());

return path;
}

internal static SKPath BuildRectangleGeometry(Vector2 offset, Vector2 size)
{
SKPath path = new SKPath();

// Top left
path.MoveTo(new SKPoint(offset.X, offset.Y));
// Top right
path.RLineTo(new SKPoint(size.X, 0));
// Bottom right
path.RLineTo(new SKPoint(0, size.Y));
// Bottom left
path.RLineTo(new SKPoint(-size.X, 0));
// Top left
path.Close();

return path;
}

internal static SKPath BuildRoundedRectangleGeometry(Vector2 offset, Vector2 size, Vector2 cornerRadius)
{
float radiusX = Clamp(cornerRadius.X, 0, size.X * 0.5f);
float radiusY = Clamp(cornerRadius.Y, 0, size.Y * 0.5f);

float bezierX = (float)((1.0 - CIRCLE_BEZIER_KAPPA) * radiusX);
float bezierY = (float)((1.0 - CIRCLE_BEZIER_KAPPA) * radiusY);

SKPath path = new SKPath();
var lastPoint = new SKPoint(offset.X + radiusX, offset.Y);

path.MoveTo(lastPoint);
// Top line
path.LineTo(lastPoint + new SKPoint(size.X - 2 * radiusX, 0));
lastPoint += new SKPoint(size.X - 2 * radiusX, 0);
// Top-right Arc
path.CubicTo(
lastPoint + new SKPoint(radiusX - bezierX, 0), // 1st control point
lastPoint + new SKPoint(radiusX, bezierY), // 2nd control point
lastPoint + new SKPoint(radiusX, radiusY)); // End point
lastPoint += new SKPoint(radiusX, radiusY);

// Right line
path.LineTo(lastPoint + new SKPoint(0, size.Y - 2 * radiusY));
lastPoint += new SKPoint(0, size.Y - 2 * radiusY);
// Bottom-right Arc
path.CubicTo(
lastPoint + new SKPoint(0, bezierY), // 1st control point
lastPoint + new SKPoint(-bezierX, radiusY), // 2nd control point
lastPoint + new SKPoint(-radiusX, radiusY)); // End point
lastPoint += new SKPoint(-radiusX, radiusY);

// Bottom line
path.LineTo(lastPoint + new SKPoint(-(size.X - 2 * radiusX), 0));
lastPoint = lastPoint + new SKPoint(-(size.X - 2 * radiusX), 0);
// Bottom-left Arc
path.CubicTo(
lastPoint + new SKPoint(-radiusX + bezierX, 0), // 1st control point
lastPoint + new SKPoint(-radiusX, -bezierY), // 2nd control point
lastPoint + new SKPoint(-radiusX, -radiusY)); // End point
lastPoint += new SKPoint(-radiusX, -radiusY);

// Left line
path.LineTo(lastPoint + new SKPoint(0, -(size.Y - 2 * radiusY)));
lastPoint += new SKPoint(0, -(size.Y - 2 * radiusY));
// Top-left Arc
path.CubicTo(
lastPoint + new SKPoint(0, -radiusY + bezierY), // 1st control point
lastPoint + new SKPoint(bezierX, -radiusY), // 2nd control point
lastPoint + new SKPoint(radiusX, -radiusY)); // End point

path.Close();

return path;
}

internal static SKPath BuildEllipseGeometry(Vector2 center, Vector2 radius)
{
SKRect rect = SKRect.Create(center.X - radius.X, center.Y - radius.Y, radius.X * 2, radius.Y * 2);

float bezierX = (float)((1.0 - CIRCLE_BEZIER_KAPPA) * radius.X);
float bezierY = (float)((1.0 - CIRCLE_BEZIER_KAPPA) * radius.Y);

// IMPORTANT:
// - The order of following operations is important for dashed strokes.
// - Stroke might get merged in the end.
// - WPF starts with bottom right ellipse arc.
// - TODO: Verify UWP behavior

SKPath path = new SKPath();

path.MoveTo(new SKPoint(rect.Right, rect.Top + radius.Y));
// Bottom-right Arc
path.CubicTo(
new SKPoint(rect.Right, rect.Bottom - bezierY), // 1st control point
new SKPoint(rect.Right - bezierX, rect.Bottom), // 2nd control point
new SKPoint(rect.Right - radius.X, rect.Bottom)); // End point

// Bottom-left Arc
path.CubicTo(
new SKPoint(rect.Left + bezierX, rect.Bottom), // 1st control point
new SKPoint(rect.Left, rect.Bottom - bezierY), // 2nd control point
new SKPoint(rect.Left, rect.Bottom - radius.Y)); // End point

// Top-left Arc
path.CubicTo(
new SKPoint(rect.Left, rect.Top + bezierY), // 1st control point
new SKPoint(rect.Left + bezierX, rect.Top), // 2nd control point
new SKPoint(rect.Left + radius.X, rect.Top)); // End point

// Top-right Arc
path.CubicTo(
new SKPoint(rect.Right - bezierX, rect.Top), // 1st control point
new SKPoint(rect.Right, rect.Top + bezierY), // 2nd control point
new SKPoint(rect.Right, rect.Top + radius.Y)); // End point

path.Close();

return path;
}

private static float Clamp(float value, float minValue, float maxValue)
{
return Math.Min(Math.Max(Math.Abs(value), minValue), maxValue);
}
}
}
12 changes: 11 additions & 1 deletion src/Uno.UWP/UI/Composition/CompositionPathGeometry.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
#nullable enable

using Windows.Graphics;

namespace Windows.UI.Composition
{
public partial class CompositionPathGeometry : CompositionGeometry
{
private CompositionPath? _path;

internal CompositionPathGeometry(Compositor compositor, CompositionPath? path = null) : base(compositor)
{
Path = path;
}

public CompositionPath? Path { get; set; }
public CompositionPath? Path
{
get => _path;
set => SetProperty(ref _path, value);
}

internal override IGeometrySource2D? BuildGeometry() => Path?.GeometrySource;
}
}
29 changes: 29 additions & 0 deletions src/Uno.UWP/UI/Composition/CompositionRectangleGeometry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#nullable enable

using System.Numerics;

namespace Windows.UI.Composition
{
public partial class CompositionRectangleGeometry : CompositionGeometry
{
private Vector2 _size;
private Vector2 _offset;

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

}

public Vector2 Size
{
get => _size;
set => SetProperty(ref _size, value);
}

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

using SkiaSharp;
using Windows.Graphics;

namespace Windows.UI.Composition
{
public partial class CompositionRectangleGeometry : CompositionGeometry
{
internal override IGeometrySource2D? BuildGeometry()
=> new SkiaGeometrySource2D(BuildRectangleGeometry(Offset, Size));
}
}
16 changes: 12 additions & 4 deletions src/Uno.UWP/UI/Composition/SkiaGeometrySource2D.skia.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,27 @@

using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Text;
using Windows.Graphics;

namespace Windows.UI.Composition
{
public class SkiaGeometrySource2D : IGeometrySource2D
{
public SkiaGeometrySource2D(SKPath? source = null)
public SkiaGeometrySource2D()
{
Geometry = new SKPath();
}

public SKPath? Geometry { get; }
public SkiaGeometrySource2D(SKPath source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}

Geometry = source;
}

public SKPath Geometry { get; }
}
}

0 comments on commit 8309bc7

Please sign in to comment.