Skip to content

Commit bb941b7

Browse files
committed
feat: SVG vector rendering on on Skia
1 parent a175ff8 commit bb941b7

File tree

9 files changed

+222
-165
lines changed

9 files changed

+222
-165
lines changed

src/AddIns/Uno.UI.Svg/SvgCanvas.cs

Lines changed: 62 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,19 @@ namespace Uno.UI.Svg;
1515
internal partial class SvgCanvas : SKXamlCanvas
1616
{
1717
private readonly SvgImageSource _svgImageSource;
18-
private SKSvg? _skSvg;
18+
private readonly SvgProvider _svgProvider;
1919
private readonly CompositeDisposable _disposables = new();
20+
private SKMatrix _currentScaleMatrix = default;
2021

21-
public SvgCanvas(SvgImageSource svgImageSource)
22+
public SvgCanvas(SvgImageSource svgImageSource, SvgProvider svgProvider)
2223
{
2324
_svgImageSource = svgImageSource;
25+
_svgProvider = svgProvider;
26+
2427
SizeChanged += SvgCanvas_SizeChanged;
2528

26-
_disposables.Add(_svgImageSource.Subscribe(OnSourceOpened));
29+
_svgProvider.SourceLoaded += SvgProviderSourceOpened;
30+
_disposables.Add(() => _svgProvider.SourceLoaded -= SvgProviderSourceOpened);
2731
_disposables.Add(_svgImageSource.RegisterDisposablePropertyChangedCallback(SvgImageSource.UriSourceProperty, SourcePropertyChanged));
2832
_disposables.Add(_svgImageSource.RegisterDisposablePropertyChangedCallback(SvgImageSource.RasterizePixelHeightProperty, SourcePropertyChanged));
2933
_disposables.Add(_svgImageSource.RegisterDisposablePropertyChangedCallback(SvgImageSource.RasterizePixelWidthProperty, SourcePropertyChanged));
@@ -40,76 +44,76 @@ public SvgCanvas(SvgImageSource svgImageSource)
4044

4145
private void SvgCanvas_SizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs args) => Invalidate();
4246

43-
protected override Size MeasureOverride(Size availableSize)
47+
private void SvgProviderSourceOpened(object sender, EventArgs e)
4448
{
45-
if (_skSvg?.Picture != null)
46-
{
47-
// TODO:MZ: Handle case where SVG is rasterized
48-
var measuredSize = new Size(_skSvg.Picture.CullRect.Width, _skSvg.Picture.CullRect.Height);
49-
return measuredSize;
50-
//Size ret;
51-
52-
//if (
53-
// double.IsInfinity(availableSize.Width)
54-
// && double.IsInfinity(availableSize.Height)
55-
//)
56-
//{
57-
// ret = measuredSize;
58-
//}
59-
//else
60-
//{
61-
// ret = ImageSizeHelper.AdjustSize(availableSize, measuredSize);
62-
//}
63-
64-
// Always making sure the ret size isn't bigger than the available size for an image with a fixed width or height
65-
//ret = new Size(
66-
// !Double.IsNaN(Width) && (ret.Width > availableSize.Width) ? availableSize.Width : ret.Width,
67-
// !Double.IsNaN(Height) && (ret.Height > availableSize.Height) ? availableSize.Height : ret.Height
68-
//);
69-
70-
//if (this.Log().IsEnabled(LogLevel.Debug))
71-
//{
72-
// this.Log().LogDebug($"Measure {this} availableSize:{availableSize} measuredSize:{_lastMeasuredSize} ret:{ret} Stretch: {Stretch} Width:{Width} Height:{Height}");
73-
//}
74-
}
75-
else
76-
{
77-
return default;
78-
}
49+
InvalidateMeasure();
50+
Invalidate();
7951
}
8052

53+
//protected override Size MeasureOverride(Size availableSize)
54+
//{
55+
// if (_skSvg?.Picture != null)
56+
// {
57+
// // TODO:MZ: Handle case where SVG is rasterized
58+
// var measuredSize = new Size(_skSvg.Picture.CullRect.Width, _skSvg.Picture.CullRect.Height);
59+
// return measuredSize;
60+
// //Size ret;
61+
62+
// //if (
63+
// // double.IsInfinity(availableSize.Width)
64+
// // && double.IsInfinity(availableSize.Height)
65+
// //)
66+
// //{
67+
// // ret = measuredSize;
68+
// //}
69+
// //else
70+
// //{
71+
// // ret = ImageSizeHelper.AdjustSize(availableSize, measuredSize);
72+
// //}
73+
74+
// // Always making sure the ret size isn't bigger than the available size for an image with a fixed width or height
75+
// //ret = new Size(
76+
// // !Double.IsNaN(Width) && (ret.Width > availableSize.Width) ? availableSize.Width : ret.Width,
77+
// // !Double.IsNaN(Height) && (ret.Height > availableSize.Height) ? availableSize.Height : ret.Height
78+
// //);
79+
80+
// //if (this.Log().IsEnabled(LogLevel.Debug))
81+
// //{
82+
// // this.Log().LogDebug($"Measure {this} availableSize:{availableSize} measuredSize:{_lastMeasuredSize} ret:{ret} Stretch: {Stretch} Width:{Width} Height:{Height}");
83+
// //}
84+
// }
85+
// else
86+
// {
87+
// return default;
88+
// }
89+
//}
90+
8191
protected override Size ArrangeOverride(Size finalSize)
8292
{
83-
return base.ArrangeOverride(finalSize);
84-
}
93+
finalSize = base.ArrangeOverride(finalSize);
8594

86-
private void OnSourceOpened(ImageData obj)
87-
{
88-
try
95+
SKMatrix scaleMatrix = default;
96+
if (_svgProvider.SkSvg?.Picture?.CullRect is { } rect)
8997
{
90-
_skSvg = new SKSvg();
91-
using var memoryStream = new MemoryStream(obj.Data);
92-
_skSvg.Load(memoryStream);
93-
InvalidateMeasure();
94-
Invalidate();
98+
scaleMatrix = SKMatrix.CreateScale((float)finalSize.Width / rect.Width, (float)finalSize.Height / rect.Height);
99+
95100
}
96-
catch (Exception)
101+
102+
if (scaleMatrix != _currentScaleMatrix)
97103
{
98-
_svgImageSource.RaiseImageFailed(SvgImageSourceLoadStatus.InvalidFormat);
104+
_currentScaleMatrix = scaleMatrix;
105+
Invalidate();
99106
}
107+
108+
return finalSize;
100109
}
101110

111+
102112
protected override void OnPaintSurface(SKPaintSurfaceEventArgs e)
103113
{
104-
if (_skSvg is not null)
114+
if (_svgProvider.SkSvg?.Picture is { } picture)
105115
{
106-
var scale = SKMatrix.CreateScale(0.5f, 0.5f);
107-
var image = Parent as Image;
108-
var width = ActualWidth;
109-
var height = ActualHeight;
110-
var fit = _skSvg.Picture!.CullRect.AspectFit(new SKSize((float)width, (float)height));
111-
//scale = SKMatrix.CreateScale((float)fit.Width / (float)_skSvg.Picture!.CullRect.Width, (float)fit.Height / (float)_skSvg.Picture!.CullRect.Height);
112-
e.Surface.Canvas.DrawPicture(_skSvg.Picture, ref scale);
116+
e.Surface.Canvas.DrawPicture(picture, ref _currentScaleMatrix);
113117
}
114118
if (double.IsNaN(_svgImageSource.RasterizePixelHeight) && double.IsNaN(_svgImageSource.RasterizePixelWidth))
115119
{

src/AddIns/Uno.UI.Svg/SvgProvider.cs

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
#nullable enable
22

33
using System;
4+
using System.IO;
5+
using ShimSkiaSharp;
6+
using Svg.Skia;
47
using Uno.UI.Xaml.Media.Imaging.Svg;
8+
using Windows.Foundation;
59
using Windows.UI.Xaml;
10+
using Windows.UI.Xaml.Media;
611
using Windows.UI.Xaml.Media.Imaging;
712

813
namespace Uno.UI.Svg;
914

1015
[Preserve]
1116
public partial class SvgProvider : ISvgProvider
1217
{
13-
private SvgImageSource _owner;
18+
private readonly SvgImageSource _owner;
19+
20+
private SKSvg? _skSvg;
1421

1522
public SvgProvider(object owner)
1623
{
@@ -20,23 +27,47 @@ public SvgProvider(object owner)
2027
}
2128

2229
_owner = svgImageSource;
30+
_owner.Subscribe(OnSourceOpened);
2331
}
2432

25-
public UIElement GetCanvas()
26-
{
27-
return new SvgCanvas(_owner);
28-
}
33+
public event EventHandler? SourceLoaded;
2934

30-
public UIElement? GetImage(SvgImageSource imageSource)
35+
internal SKSvg? SkSvg => _skSvg;
36+
37+
public bool IsParsed => _skSvg?.Picture is not null;
38+
39+
public Size SourceSize
3140
{
32-
_owner.RaiseImageOpened();
33-
return null;
34-
//imageSource.RasterizePixelHeight
35-
//var svg = new SKSvg();
41+
get
42+
{
43+
if (_skSvg?.Picture?.CullRect is { } rect)
44+
{
45+
return new Size(rect.Width, rect.Height);
46+
}
47+
48+
return default;
49+
}
50+
}
3651

37-
//svg.Load(stream);
52+
public UIElement GetCanvas() => new SvgCanvas(_owner, this);
3853

39-
//SKXamlCanvas canvas = new SKXamlCanvas();
40-
//canvas.(svg.Picture);
54+
private void OnSourceOpened(ImageData imageData)
55+
{
56+
try
57+
{
58+
_skSvg = new SKSvg();
59+
using (var memoryStream = new MemoryStream(imageData.Data))
60+
{
61+
_skSvg.Load(memoryStream);
62+
}
63+
_owner.RaiseImageOpened();
64+
SourceLoaded?.Invoke(this, EventArgs.Empty);
65+
}
66+
catch (Exception)
67+
{
68+
_skSvg?.Dispose();
69+
_skSvg = null;
70+
_owner.RaiseImageFailed(SvgImageSourceLoadStatus.InvalidFormat);
71+
}
4172
}
4273
}

src/AddIns/Uno.UI.Svg/SvgProvider.skia.cs

Lines changed: 0 additions & 6 deletions
This file was deleted.

src/AddIns/Uno.UI.Svg/Uno.UI.Svg.Skia.csproj

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@
2929

3030
<Import Project="..\..\Common.targets" />
3131
<Import Project="..\..\Uno.CrossTargetting.props" />
32-
<ItemGroup>
33-
<None Remove="SvgProvider.skia.cs" />
34-
</ItemGroup>
3532

3633
<ItemGroup>
3734
<ProjectReference Include="..\..\Uno.Foundation\Uno.Foundation.Skia.csproj" />

0 commit comments

Comments
 (0)