Skip to content

Commit

Permalink
feat: SVG vector rendering on on Skia
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinZikmund committed Oct 14, 2022
1 parent a175ff8 commit bb941b7
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 165 deletions.
120 changes: 62 additions & 58 deletions src/AddIns/Uno.UI.Svg/SvgCanvas.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@ namespace Uno.UI.Svg;
internal partial class SvgCanvas : SKXamlCanvas
{
private readonly SvgImageSource _svgImageSource;
private SKSvg? _skSvg;
private readonly SvgProvider _svgProvider;
private readonly CompositeDisposable _disposables = new();
private SKMatrix _currentScaleMatrix = default;

public SvgCanvas(SvgImageSource svgImageSource)
public SvgCanvas(SvgImageSource svgImageSource, SvgProvider svgProvider)
{
_svgImageSource = svgImageSource;
_svgProvider = svgProvider;

SizeChanged += SvgCanvas_SizeChanged;

_disposables.Add(_svgImageSource.Subscribe(OnSourceOpened));
_svgProvider.SourceLoaded += SvgProviderSourceOpened;
_disposables.Add(() => _svgProvider.SourceLoaded -= SvgProviderSourceOpened);
_disposables.Add(_svgImageSource.RegisterDisposablePropertyChangedCallback(SvgImageSource.UriSourceProperty, SourcePropertyChanged));
_disposables.Add(_svgImageSource.RegisterDisposablePropertyChangedCallback(SvgImageSource.RasterizePixelHeightProperty, SourcePropertyChanged));
_disposables.Add(_svgImageSource.RegisterDisposablePropertyChangedCallback(SvgImageSource.RasterizePixelWidthProperty, SourcePropertyChanged));
Expand All @@ -40,76 +44,76 @@ public SvgCanvas(SvgImageSource svgImageSource)

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

protected override Size MeasureOverride(Size availableSize)
private void SvgProviderSourceOpened(object sender, EventArgs e)
{
if (_skSvg?.Picture != null)
{
// TODO:MZ: Handle case where SVG is rasterized
var measuredSize = new Size(_skSvg.Picture.CullRect.Width, _skSvg.Picture.CullRect.Height);
return measuredSize;
//Size ret;

//if (
// double.IsInfinity(availableSize.Width)
// && double.IsInfinity(availableSize.Height)
//)
//{
// ret = measuredSize;
//}
//else
//{
// ret = ImageSizeHelper.AdjustSize(availableSize, measuredSize);
//}

// Always making sure the ret size isn't bigger than the available size for an image with a fixed width or height
//ret = new Size(
// !Double.IsNaN(Width) && (ret.Width > availableSize.Width) ? availableSize.Width : ret.Width,
// !Double.IsNaN(Height) && (ret.Height > availableSize.Height) ? availableSize.Height : ret.Height
//);

//if (this.Log().IsEnabled(LogLevel.Debug))
//{
// this.Log().LogDebug($"Measure {this} availableSize:{availableSize} measuredSize:{_lastMeasuredSize} ret:{ret} Stretch: {Stretch} Width:{Width} Height:{Height}");
//}
}
else
{
return default;
}
InvalidateMeasure();
Invalidate();
}

//protected override Size MeasureOverride(Size availableSize)
//{
// if (_skSvg?.Picture != null)
// {
// // TODO:MZ: Handle case where SVG is rasterized
// var measuredSize = new Size(_skSvg.Picture.CullRect.Width, _skSvg.Picture.CullRect.Height);
// return measuredSize;
// //Size ret;

// //if (
// // double.IsInfinity(availableSize.Width)
// // && double.IsInfinity(availableSize.Height)
// //)
// //{
// // ret = measuredSize;
// //}
// //else
// //{
// // ret = ImageSizeHelper.AdjustSize(availableSize, measuredSize);
// //}

// // Always making sure the ret size isn't bigger than the available size for an image with a fixed width or height
// //ret = new Size(
// // !Double.IsNaN(Width) && (ret.Width > availableSize.Width) ? availableSize.Width : ret.Width,
// // !Double.IsNaN(Height) && (ret.Height > availableSize.Height) ? availableSize.Height : ret.Height
// //);

// //if (this.Log().IsEnabled(LogLevel.Debug))
// //{
// // this.Log().LogDebug($"Measure {this} availableSize:{availableSize} measuredSize:{_lastMeasuredSize} ret:{ret} Stretch: {Stretch} Width:{Width} Height:{Height}");
// //}
// }
// else
// {
// return default;
// }
//}

protected override Size ArrangeOverride(Size finalSize)
{
return base.ArrangeOverride(finalSize);
}
finalSize = base.ArrangeOverride(finalSize);

private void OnSourceOpened(ImageData obj)
{
try
SKMatrix scaleMatrix = default;
if (_svgProvider.SkSvg?.Picture?.CullRect is { } rect)
{
_skSvg = new SKSvg();
using var memoryStream = new MemoryStream(obj.Data);
_skSvg.Load(memoryStream);
InvalidateMeasure();
Invalidate();
scaleMatrix = SKMatrix.CreateScale((float)finalSize.Width / rect.Width, (float)finalSize.Height / rect.Height);

}
catch (Exception)

if (scaleMatrix != _currentScaleMatrix)
{
_svgImageSource.RaiseImageFailed(SvgImageSourceLoadStatus.InvalidFormat);
_currentScaleMatrix = scaleMatrix;
Invalidate();
}

return finalSize;
}


protected override void OnPaintSurface(SKPaintSurfaceEventArgs e)
{
if (_skSvg is not null)
if (_svgProvider.SkSvg?.Picture is { } picture)
{
var scale = SKMatrix.CreateScale(0.5f, 0.5f);
var image = Parent as Image;
var width = ActualWidth;
var height = ActualHeight;
var fit = _skSvg.Picture!.CullRect.AspectFit(new SKSize((float)width, (float)height));
//scale = SKMatrix.CreateScale((float)fit.Width / (float)_skSvg.Picture!.CullRect.Width, (float)fit.Height / (float)_skSvg.Picture!.CullRect.Height);
e.Surface.Canvas.DrawPicture(_skSvg.Picture, ref scale);
e.Surface.Canvas.DrawPicture(picture, ref _currentScaleMatrix);
}
if (double.IsNaN(_svgImageSource.RasterizePixelHeight) && double.IsNaN(_svgImageSource.RasterizePixelWidth))
{
Expand Down
57 changes: 44 additions & 13 deletions src/AddIns/Uno.UI.Svg/SvgProvider.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
#nullable enable

using System;
using System.IO;
using ShimSkiaSharp;
using Svg.Skia;
using Uno.UI.Xaml.Media.Imaging.Svg;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;

namespace Uno.UI.Svg;

[Preserve]
public partial class SvgProvider : ISvgProvider
{
private SvgImageSource _owner;
private readonly SvgImageSource _owner;

private SKSvg? _skSvg;

public SvgProvider(object owner)
{
Expand All @@ -20,23 +27,47 @@ public SvgProvider(object owner)
}

_owner = svgImageSource;
_owner.Subscribe(OnSourceOpened);
}

public UIElement GetCanvas()
{
return new SvgCanvas(_owner);
}
public event EventHandler? SourceLoaded;

public UIElement? GetImage(SvgImageSource imageSource)
internal SKSvg? SkSvg => _skSvg;

public bool IsParsed => _skSvg?.Picture is not null;

public Size SourceSize
{
_owner.RaiseImageOpened();
return null;
//imageSource.RasterizePixelHeight
//var svg = new SKSvg();
get
{
if (_skSvg?.Picture?.CullRect is { } rect)
{
return new Size(rect.Width, rect.Height);
}

return default;
}
}

//svg.Load(stream);
public UIElement GetCanvas() => new SvgCanvas(_owner, this);

//SKXamlCanvas canvas = new SKXamlCanvas();
//canvas.(svg.Picture);
private void OnSourceOpened(ImageData imageData)
{
try
{
_skSvg = new SKSvg();
using (var memoryStream = new MemoryStream(imageData.Data))
{
_skSvg.Load(memoryStream);
}
_owner.RaiseImageOpened();
SourceLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception)
{
_skSvg?.Dispose();
_skSvg = null;
_owner.RaiseImageFailed(SvgImageSourceLoadStatus.InvalidFormat);
}
}
}
6 changes: 0 additions & 6 deletions src/AddIns/Uno.UI.Svg/SvgProvider.skia.cs

This file was deleted.

3 changes: 0 additions & 3 deletions src/AddIns/Uno.UI.Svg/Uno.UI.Svg.Skia.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@

<Import Project="..\..\Common.targets" />
<Import Project="..\..\Uno.CrossTargetting.props" />
<ItemGroup>
<None Remove="SvgProvider.skia.cs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\Uno.Foundation\Uno.Foundation.Skia.csproj" />
Expand Down
Loading

0 comments on commit bb941b7

Please sign in to comment.