Skip to content

Commit

Permalink
feat(skia): Support Shape.StrokeDashArray and CompositionStrokeDashArray
Browse files Browse the repository at this point in the history
  • Loading branch information
Youssef1313 committed May 13, 2024
1 parent 9b6804f commit c3c499f
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 140 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using Uno.UI.Samples.Controls;
using Microsoft.UI.Xaml.Controls;

namespace SamplesApp.Windows_UI_Xaml_Shapes.PathTestsControl
namespace SamplesApp.Windows_UI_Xaml_Shapes.PathTestsControl;

[Sample("Path", IsManualTest = true)]
public sealed partial class Path_With_DashStrokeArray : UserControl
{
[SampleControlInfo("Path", "Path_With_DashStrokeArray")]
public sealed partial class Path_With_DashStrokeArray : UserControl
public Path_With_DashStrokeArray()
{
public Path_With_DashStrokeArray()
{
this.InitializeComponent();
}
this.InitializeComponent();
}
}
13 changes: 11 additions & 2 deletions src/Uno.UI.Composition/Composition/CompositionSpriteShape.skia.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#nullable enable

using System;
using System.Linq;
using SkiaSharp;
using Uno;
using Uno.Extensions;
Expand Down Expand Up @@ -56,8 +57,10 @@ internal override void Paint(in Visual.PaintingSession session)

// Set stroke thickness
strokePaint.StrokeWidth = StrokeThickness;
// TODO: Add support for dashes here
// strokePaint.PathEffect = SKPathEffect.CreateDash();
if (StrokeDashArray is { Count: > 0 } strokeDashArray)
{
strokePaint.PathEffect = SKPathEffect.CreateDash(strokeDashArray.ToEvenArray(), 0);
}

// Generate stroke geometry for bounds that will be passed to a brush.
// - [Future]: This generated geometry should also be used for hit testing.
Expand Down Expand Up @@ -117,6 +120,12 @@ private static SKPaint TryCreateAndClearPaint(in Visual.PaintingSession session,
paint.Shader.Dispose();
paint.Shader = null;
}

if (paint.PathEffect != null)
{
paint.PathEffect.Dispose();
paint.PathEffect = null;
}
}

paint.ColorFilter = session.Filters.OpacityColorFilter;
Expand Down
67 changes: 67 additions & 0 deletions src/Uno.UI.Composition/Composition/CompositionStrokeDashArray.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System.Collections;
using System.Collections.Generic;
using Uno;

namespace Microsoft.UI.Composition;

[NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__MACOS__")]
public partial class CompositionStrokeDashArray : CompositionObject, IList<float>, IEnumerable<float>
{
private readonly List<float> _list;

internal CompositionStrokeDashArray()
{
_list = new List<float>();
}

public uint Size => (uint)_list.Count;

public int IndexOf(float item)
=> _list.IndexOf(item);

public void Insert(int index, float item)
=> _list.Insert(index, item);

public void RemoveAt(int index)
=> _list.RemoveAt(index);

public float this[int index]
{
get => _list[index];
set => _list[index] = value;
}

public void Add(float item)
=> _list.Add(item);

public void Clear()
=> _list.Clear();

public bool Contains(float item)
=> _list.Contains(item);

public void CopyTo(float[] array, int arrayIndex)
=> _list.CopyTo(array, arrayIndex);

public bool Remove(float item)
=> _list.Remove(item);

public int Count
=> _list.Count;

public bool IsReadOnly
=> false;

public IEnumerator<float> GetEnumerator()
=> _list.GetEnumerator();

IEnumerator IEnumerable.GetEnumerator()
=> _list.GetEnumerator();

internal float[] ToEvenArray()
{
return _list.Count % 2 == 0
? _list.ToArray()
: [.. _list, .. _list];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,11 @@
#pragma warning disable 114 // new keyword hiding
namespace Microsoft.UI.Composition
{
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
#if false || false || false || false || false || false || false
[global::Uno.NotImplemented]
#endif
public partial class CompositionStrokeDashArray : global::Microsoft.UI.Composition.CompositionObject, global::System.Collections.Generic.IList<float>, global::System.Collections.Generic.IEnumerable<float>
{
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
internal CompositionStrokeDashArray()
{
}
#endif
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public uint Size
{
get
{
throw new global::System.NotImplementedException("The member uint CompositionStrokeDashArray.Size is not implemented. For more information, visit https://aka.platform.uno/notimplemented#m=uint%20CompositionStrokeDashArray.Size");
}
}
#endif
// Forced skipping of method Microsoft.UI.Composition.CompositionStrokeDashArray.Clear()
// Forced skipping of method Microsoft.UI.Composition.CompositionStrokeDashArray.RemoveAt(uint)
// Forced skipping of method Microsoft.UI.Composition.CompositionStrokeDashArray.Append(float)
Expand All @@ -37,122 +22,7 @@ public uint Size
// Forced skipping of method Microsoft.UI.Composition.CompositionStrokeDashArray.SetAt(uint, float)
// Forced skipping of method Microsoft.UI.Composition.CompositionStrokeDashArray.InsertAt(uint, float)
// Processing: System.Collections.Generic.IList<float>
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
// DeclaringType: System.Collections.Generic.IList<float>
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public int IndexOf(float item)
{
throw new global::System.NotSupportedException();
}
#endif
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
// DeclaringType: System.Collections.Generic.IList<float>
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public void Insert(int index, float item)
{
throw new global::System.NotSupportedException();
}
#endif
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
// DeclaringType: System.Collections.Generic.IList<float>
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public void RemoveAt(int index)
{
throw new global::System.NotSupportedException();
}
#endif
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public float this[int index]
{
get
{
throw new global::System.NotSupportedException();
}
set
{
throw new global::System.NotSupportedException();
}
}
#endif
// Processing: System.Collections.Generic.ICollection<float>
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
// DeclaringType: System.Collections.Generic.ICollection<float>
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public void Add(float item)
{
throw new global::System.NotSupportedException();
}
#endif
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
// DeclaringType: System.Collections.Generic.ICollection<float>
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public void Clear()
{
throw new global::System.NotSupportedException();
}
#endif
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
// DeclaringType: System.Collections.Generic.ICollection<float>
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public bool Contains(float item)
{
throw new global::System.NotSupportedException();
}
#endif
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
// DeclaringType: System.Collections.Generic.ICollection<float>
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public void CopyTo(float[] array, int arrayIndex)
{
throw new global::System.NotSupportedException();
}
#endif
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
// DeclaringType: System.Collections.Generic.ICollection<float>
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public bool Remove(float item)
{
throw new global::System.NotSupportedException();
}
#endif
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public int Count
{
get
{
throw new global::System.NotSupportedException();
}
}
#endif
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public bool IsReadOnly
{
get
{
throw new global::System.NotSupportedException();
}
}
#endif
// Processing: System.Collections.Generic.IEnumerable<float>
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
// DeclaringType: System.Collections.Generic.IEnumerable<float>
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public global::System.Collections.Generic.IEnumerator<float> GetEnumerator()
{
throw new global::System.NotSupportedException();
}
#endif
// Processing: System.Collections.IEnumerable
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
// DeclaringType: System.Collections.IEnumerable
[global::Uno.NotImplemented("__ANDROID__", "__IOS__", "IS_UNIT_TESTS", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
global::System.Collections.IEnumerator global::System.Collections.IEnumerable.GetEnumerator()
{
throw new global::System.NotSupportedException();
}
#endif
}
}
19 changes: 19 additions & 0 deletions src/Uno.UI/UI/Xaml/Shapes/Shape.skia.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ private void UpdateRender()
OnFillBrushChanged();
OnStrokeBrushChanged();
UpdateStrokeThickness();
UpdateStrokeDashArray();
}

private void OnFillBrushChanged()
Expand All @@ -81,6 +82,24 @@ private void UpdateStrokeThickness()
_shape.StrokeThickness = (float)ActualStrokeThickness;
}

private void UpdateStrokeDashArray()
{
var compositionStrokeDashArray = new CompositionStrokeDashArray();
var strokeDashArray = StrokeDashArray;
if (strokeDashArray is null)
{
_shape.StrokeDashArray = null;
return;
}

for (int i = 0; i < strokeDashArray.Count; i++)
{
compositionStrokeDashArray.Add((float)strokeDashArray[i]);
}

_shape.StrokeDashArray = compositionStrokeDashArray;
}

private void OnStrokeBrushChanged()
{
_strokeSubscription.Disposable = null;
Expand Down

0 comments on commit c3c499f

Please sign in to comment.