From 18d59ff64988c3d725cb6f3407257975eaddd466 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 14 Mar 2019 14:36:07 +0300 Subject: [PATCH 01/23] Custom draw operations, exposed SkCanvas and reduced Skia api visibility --- samples/RenderDemo/MainWindow.xaml | 3 + samples/RenderDemo/Pages/CustomSkiaPage.cs | 119 ++++++++++++++++++ src/Avalonia.Visuals/Media/DrawingContext.cs | 7 ++ .../Platform/IDrawingContextImpl.cs | 7 ++ .../SceneGraph/CustomDrawOperation.cs | 39 ++++++ .../SceneGraph/DeferredDrawingContextImpl.cs | 9 ++ src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 7 +- src/Skia/Avalonia.Skia/FormattedTextImpl.cs | 2 +- .../Avalonia.Skia/FramebufferRenderTarget.cs | 2 +- src/Skia/Avalonia.Skia/GeometryImpl.cs | 2 +- src/Skia/Avalonia.Skia/GlRenderTarget.cs | 2 +- .../Avalonia.Skia/ISkiaDrawingContextImpl.cs | 10 ++ src/Skia/Avalonia.Skia/ImmutableBitmap.cs | 2 +- .../Avalonia.Skia/PlatformRenderInterface.cs | 2 +- src/Skia/Avalonia.Skia/StreamGeometryImpl.cs | 2 +- src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs | 2 +- .../Avalonia.Skia/TransformedGeometryImpl.cs | 2 +- src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs | 2 +- .../Media/DrawingContextImpl.cs | 3 + .../Media/FormattedTextImpl.cs | 2 +- 20 files changed, 214 insertions(+), 12 deletions(-) create mode 100644 samples/RenderDemo/Pages/CustomSkiaPage.cs create mode 100644 src/Avalonia.Visuals/Rendering/SceneGraph/CustomDrawOperation.cs create mode 100644 src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs diff --git a/samples/RenderDemo/MainWindow.xaml b/samples/RenderDemo/MainWindow.xaml index 41164c7780..c15abad188 100644 --- a/samples/RenderDemo/MainWindow.xaml +++ b/samples/RenderDemo/MainWindow.xaml @@ -33,6 +33,9 @@ + + + diff --git a/samples/RenderDemo/Pages/CustomSkiaPage.cs b/samples/RenderDemo/Pages/CustomSkiaPage.cs new file mode 100644 index 0000000000..2e59d934a1 --- /dev/null +++ b/samples/RenderDemo/Pages/CustomSkiaPage.cs @@ -0,0 +1,119 @@ +using System; +using System.Diagnostics; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Media; +using Avalonia.Platform; +using Avalonia.Rendering.SceneGraph; +using Avalonia.Skia; +using Avalonia.Threading; +using SkiaSharp; + +namespace RenderDemo.Pages +{ + public class CustomSkiaPage : Control + { + public CustomSkiaPage() + { + ClipToBounds = true; + } + + class CustomDrawOp : ICustomDrawOperation + { + private readonly FormattedText _noSkia; + + public CustomDrawOp(Rect bounds, FormattedText noSkia) + { + _noSkia = noSkia; + Bounds = bounds; + } + + public void Dispose() + { + // No-op + } + + public Rect Bounds { get; } + public bool HitTest(Point p) => false; + public bool Equals(ICustomDrawOperation other) => false; + static Stopwatch St = Stopwatch.StartNew(); + public void Render(IDrawingContextImpl context) + { + var canvas = (context as ISkiaDrawingContextImpl)?.SkCanvas; + if (canvas == null) + context.DrawText(Brushes.Black, new Point(), _noSkia.PlatformImpl); + else + { + canvas.Save(); + // create the first shader + var colors = new SKColor[] { + new SKColor(0, 255, 255), + new SKColor(255, 0, 255), + new SKColor(255, 255, 0), + new SKColor(0, 255, 255) + }; + + var sx = Animate(100, 2, 10); + var sy = Animate(1000, 5, 15); + var lightPosition = new SKPoint( + (float)(Bounds.Width / 2 + Math.Cos(St.Elapsed.TotalSeconds) * Bounds.Width / 4), + (float)(Bounds.Height / 2 + Math.Sin(St.Elapsed.TotalSeconds) * Bounds.Height / 4)); + using (var sweep = + SKShader.CreateSweepGradient(new SKPoint((int)Bounds.Width / 2, (int)Bounds.Height / 2), colors, + null)) + using(var turbulence = SKShader.CreatePerlinNoiseFractalNoise(0.05f, 0.05f, 4, 0)) + using(var shader = SKShader.CreateCompose(sweep, turbulence, SKBlendMode.SrcATop)) + using(var blur = SKImageFilter.CreateBlur(Animate(100, 2, 10), Animate(100, 5, 15))) + using (var paint = new SKPaint + { + Shader = shader, + ImageFilter = blur + }) + canvas.DrawPaint(paint); + + using (var pseudoLight = SKShader.CreateRadialGradient( + lightPosition, + (float) (Bounds.Width/3), + new [] { + new SKColor(255, 200, 200, 100), + SKColors.Transparent, + new SKColor(40,40,40, 220), + new SKColor(20,20,20, (byte)Animate(100, 200,220)) }, + new float[] { 0.3f, 0.3f, 0.8f, 1 }, + SKShaderTileMode.Clamp)) + using (var paint = new SKPaint + { + Shader = pseudoLight + }) + canvas.DrawPaint(paint); + canvas.Restore(); + } + } + static int Animate(int d, int from, int to) + { + var ms = (int)(St.ElapsedMilliseconds / d); + var diff = to - from; + var range = diff * 2; + var v = ms % range; + if (v > diff) + v = range - v; + var rv = v + from; + if (rv < from || rv > to) + throw new Exception("WTF"); + return rv; + } + } + + + + public override void Render(DrawingContext context) + { + var noSkia = new FormattedText() + { + Text = "Current rendering API is not Skia" + }; + context.Custom(new CustomDrawOp(new Rect(0, 0, Bounds.Width, Bounds.Height), noSkia)); + Dispatcher.UIThread.InvokeAsync(InvalidateVisual, DispatcherPriority.Background); + } + } +} diff --git a/src/Avalonia.Visuals/Media/DrawingContext.cs b/src/Avalonia.Visuals/Media/DrawingContext.cs index fd593db991..d3af71ffcb 100644 --- a/src/Avalonia.Visuals/Media/DrawingContext.cs +++ b/src/Avalonia.Visuals/Media/DrawingContext.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using Avalonia.Media.Imaging; using Avalonia.Platform; +using Avalonia.Rendering.SceneGraph; using Avalonia.Threading; using Avalonia.Visuals.Media.Imaging; @@ -131,6 +132,12 @@ namespace Avalonia.Media } } + /// + /// Draws a custom drawing operation + /// + /// custom operation + public void Custom(ICustomDrawOperation custom) => PlatformImpl.Custom(custom); + /// /// Draws text. /// diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs index 57b974f900..e5be04ebf9 100644 --- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs @@ -3,6 +3,7 @@ using System; using Avalonia.Media; +using Avalonia.Rendering.SceneGraph; using Avalonia.Utilities; using Avalonia.Visuals.Media.Imaging; @@ -139,5 +140,11 @@ namespace Avalonia.Platform /// Pops the latest pushed geometry clip. /// void PopGeometryClip(); + + /// + /// Adds a custom draw operation + /// + /// Custom draw operation + void Custom(ICustomDrawOperation custom); } } diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/CustomDrawOperation.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/CustomDrawOperation.cs new file mode 100644 index 0000000000..68e2237430 --- /dev/null +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/CustomDrawOperation.cs @@ -0,0 +1,39 @@ +using System; +using Avalonia.Media; +using Avalonia.Platform; + +namespace Avalonia.Rendering.SceneGraph +{ + internal sealed class CustomDrawOperation : DrawOperation + { + public Matrix Transform { get; } + public ICustomDrawOperation Custom { get; } + public CustomDrawOperation(ICustomDrawOperation custom, Matrix transform) + : base(custom.Bounds, transform, null) + { + Transform = transform; + Custom = custom; + } + + public override bool HitTest(Point p) + { + return Custom.HitTest(p * Transform); + } + + public override void Render(IDrawingContextImpl context) + { + context.Transform = Transform; + Custom.Render(context); + } + + public override void Dispose() => Custom.Dispose(); + + public bool Equals(Matrix transform, ICustomDrawOperation custom) => + Transform == transform && Custom?.Equals(custom) == true; + } + + public interface ICustomDrawOperation : IDrawOperation, IEquatable + { + + } +} diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs index dfed0d911c..0b33851911 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs @@ -165,6 +165,15 @@ namespace Avalonia.Rendering.SceneGraph ++_drawOperationindex; } } + + public void Custom(ICustomDrawOperation custom) + { + var next = NextDrawAs(); + if (next == null || !next.Item.Equals(Transform, custom)) + Add(new CustomDrawOperation(custom, Transform)); + else + ++_drawOperationindex; + } /// public void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text) diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 10e746cbd5..af6b0fe22f 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -9,6 +9,7 @@ using System.Threading; using Avalonia.Media; using Avalonia.Platform; using Avalonia.Rendering; +using Avalonia.Rendering.SceneGraph; using Avalonia.Rendering.Utilities; using Avalonia.Utilities; using Avalonia.Visuals.Media.Imaging; @@ -19,7 +20,7 @@ namespace Avalonia.Skia /// /// Skia based drawing context. /// - public class DrawingContextImpl : IDrawingContextImpl + internal class DrawingContextImpl : IDrawingContextImpl, ISkiaDrawingContextImpl { private IDisposable[] _disposables; private readonly Vector _dpi; @@ -99,6 +100,8 @@ namespace Avalonia.Skia /// public SKCanvas Canvas { get; } + SKCanvas ISkiaDrawingContextImpl.SkCanvas => Canvas; + /// public void Clear(Color color) { @@ -296,6 +299,8 @@ namespace Avalonia.Skia Canvas.Restore(); } + public void Custom(ICustomDrawOperation custom) => custom.Render(this); + /// public void PushOpacityMask(IBrush mask, Rect bounds) { diff --git a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs index 7e3f4aa40a..47852a4d9e 100644 --- a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs +++ b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs @@ -13,7 +13,7 @@ namespace Avalonia.Skia /// /// Skia formatted text implementation. /// - public class FormattedTextImpl : IFormattedTextImpl + internal class FormattedTextImpl : IFormattedTextImpl { public FormattedTextImpl( string text, diff --git a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs index 0cb4c3db67..1af3d2968c 100644 --- a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs @@ -13,7 +13,7 @@ namespace Avalonia.Skia /// /// Skia render target that renders to a framebuffer surface. No gpu acceleration available. /// - public class FramebufferRenderTarget : IRenderTarget + internal class FramebufferRenderTarget : IRenderTarget { private readonly IFramebufferPlatformSurface _platformSurface; private SKImageInfo _currentImageInfo; diff --git a/src/Skia/Avalonia.Skia/GeometryImpl.cs b/src/Skia/Avalonia.Skia/GeometryImpl.cs index fbbd6eb58c..5940de418e 100644 --- a/src/Skia/Avalonia.Skia/GeometryImpl.cs +++ b/src/Skia/Avalonia.Skia/GeometryImpl.cs @@ -11,7 +11,7 @@ namespace Avalonia.Skia /// /// A Skia implementation of . /// - public abstract class GeometryImpl : IGeometryImpl + internal abstract class GeometryImpl : IGeometryImpl { private PathCache _pathCache; diff --git a/src/Skia/Avalonia.Skia/GlRenderTarget.cs b/src/Skia/Avalonia.Skia/GlRenderTarget.cs index cd8c334b53..7c0c42ca37 100644 --- a/src/Skia/Avalonia.Skia/GlRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/GlRenderTarget.cs @@ -8,7 +8,7 @@ using static Avalonia.OpenGL.GlConsts; namespace Avalonia.Skia { - public class GlRenderTarget : IRenderTarget + internal class GlRenderTarget : IRenderTarget { private readonly GRContext _grContext; private IGlPlatformSurfaceRenderTarget _surface; diff --git a/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs b/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs new file mode 100644 index 0000000000..ff82990c47 --- /dev/null +++ b/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs @@ -0,0 +1,10 @@ +using Avalonia.Platform; +using SkiaSharp; + +namespace Avalonia.Skia +{ + public interface ISkiaDrawingContextImpl : IDrawingContextImpl + { + SKCanvas SkCanvas { get; } + } +} diff --git a/src/Skia/Avalonia.Skia/ImmutableBitmap.cs b/src/Skia/Avalonia.Skia/ImmutableBitmap.cs index 49992df395..f283040eac 100644 --- a/src/Skia/Avalonia.Skia/ImmutableBitmap.cs +++ b/src/Skia/Avalonia.Skia/ImmutableBitmap.cs @@ -12,7 +12,7 @@ namespace Avalonia.Skia /// /// Immutable Skia bitmap. /// - public class ImmutableBitmap : IDrawableBitmapImpl + internal class ImmutableBitmap : IDrawableBitmapImpl { private readonly SKImage _image; diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index c6e68b1c8b..6e13b154b4 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs @@ -15,7 +15,7 @@ namespace Avalonia.Skia /// /// Skia platform render interface. /// - public class PlatformRenderInterface : IPlatformRenderInterface + internal class PlatformRenderInterface : IPlatformRenderInterface { private GRContext GrContext { get; } diff --git a/src/Skia/Avalonia.Skia/StreamGeometryImpl.cs b/src/Skia/Avalonia.Skia/StreamGeometryImpl.cs index c19ff79d87..2764c65c6f 100644 --- a/src/Skia/Avalonia.Skia/StreamGeometryImpl.cs +++ b/src/Skia/Avalonia.Skia/StreamGeometryImpl.cs @@ -10,7 +10,7 @@ namespace Avalonia.Skia /// /// A Skia implementation of a . /// - public class StreamGeometryImpl : GeometryImpl, IStreamGeometryImpl + internal class StreamGeometryImpl : GeometryImpl, IStreamGeometryImpl { private Rect _bounds; private readonly SKPath _effectivePath; diff --git a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs index 4b7eae1af4..9340c9add4 100644 --- a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs @@ -14,7 +14,7 @@ namespace Avalonia.Skia /// /// Skia render target that writes to a surface. /// - public class SurfaceRenderTarget : IRenderTargetBitmapImpl, IDrawableBitmapImpl + internal class SurfaceRenderTarget : IRenderTargetBitmapImpl, IDrawableBitmapImpl { private readonly SKSurface _surface; private readonly SKCanvas _canvas; diff --git a/src/Skia/Avalonia.Skia/TransformedGeometryImpl.cs b/src/Skia/Avalonia.Skia/TransformedGeometryImpl.cs index e95069eef3..9826bc2ce3 100644 --- a/src/Skia/Avalonia.Skia/TransformedGeometryImpl.cs +++ b/src/Skia/Avalonia.Skia/TransformedGeometryImpl.cs @@ -9,7 +9,7 @@ namespace Avalonia.Skia /// /// A Skia implementation of a . /// - public class TransformedGeometryImpl : GeometryImpl, ITransformedGeometryImpl + internal class TransformedGeometryImpl : GeometryImpl, ITransformedGeometryImpl { /// /// Initializes a new instance of the class. diff --git a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs index c9d6fa6c11..fea21cde58 100644 --- a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs +++ b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs @@ -13,7 +13,7 @@ namespace Avalonia.Skia /// /// Skia based writeable bitmap. /// - public class WriteableBitmapImpl : IWriteableBitmapImpl, IDrawableBitmapImpl + internal class WriteableBitmapImpl : IWriteableBitmapImpl, IDrawableBitmapImpl { private static readonly SKBitmapReleaseDelegate s_releaseDelegate = ReleaseProc; private readonly SKBitmap _bitmap; diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index 5e150ff647..8ecada1ced 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using Avalonia.Media; using Avalonia.Platform; using Avalonia.Rendering; +using Avalonia.Rendering.SceneGraph; using Avalonia.Utilities; using SharpDX; using SharpDX.Direct2D1; @@ -508,5 +509,7 @@ namespace Avalonia.Direct2D1.Media { PopLayer(); } + + public void Custom(ICustomDrawOperation custom) => custom.Render(this); } } diff --git a/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs index 7164ec7c0d..91adc29214 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs @@ -9,7 +9,7 @@ using DWrite = SharpDX.DirectWrite; namespace Avalonia.Direct2D1.Media { - public class FormattedTextImpl : IFormattedTextImpl + internal class FormattedTextImpl : IFormattedTextImpl { public FormattedTextImpl( string text, From 1db8031b02578e250707893c497ff8e4b0d0deed Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 14 Mar 2019 15:16:30 +0100 Subject: [PATCH 02/23] Custom skia gpu support. --- src/Skia/Avalonia.Skia/CustomRenderTarget.cs | 39 +++++++++++++++++++ src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs | 23 +++++++++++ .../Avalonia.Skia/ICustomSkiaRenderSession.cs | 26 +++++++++++++ .../Avalonia.Skia/ICustomSkiaRenderTarget.cs | 16 ++++++++ .../Avalonia.Skia/PlatformRenderInterface.cs | 32 ++++++++++++--- .../SkiaApplicationExtensions.cs | 7 +++- src/Skia/Avalonia.Skia/SkiaPlatform.cs | 6 +-- 7 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 src/Skia/Avalonia.Skia/CustomRenderTarget.cs create mode 100644 src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs create mode 100644 src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs create mode 100644 src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs diff --git a/src/Skia/Avalonia.Skia/CustomRenderTarget.cs b/src/Skia/Avalonia.Skia/CustomRenderTarget.cs new file mode 100644 index 0000000000..dd62237b0c --- /dev/null +++ b/src/Skia/Avalonia.Skia/CustomRenderTarget.cs @@ -0,0 +1,39 @@ +using Avalonia.Platform; +using Avalonia.Rendering; + +namespace Avalonia.Skia +{ + /// + /// Adapts to be used within Skia rendering pipeline. + /// + internal class CustomRenderTarget : IRenderTarget + { + private readonly ICustomSkiaRenderTarget _renderTarget; + + public CustomRenderTarget(ICustomSkiaRenderTarget renderTarget) + { + _renderTarget = renderTarget; + } + + public void Dispose() + { + _renderTarget.Dispose(); + } + + public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer) + { + ICustomSkiaRenderSession session = _renderTarget.BeginRendering(); + + var nfo = new DrawingContextImpl.CreateInfo + { + GrContext = session.GrContext, + Canvas = session.Canvas, + Dpi = SkiaPlatform.DefaultDpi * session.ScaleFactor, + VisualBrushRenderer = visualBrushRenderer, + DisableTextLcdRendering = true + }; + + return new DrawingContextImpl(nfo, session); + } + } +} diff --git a/src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs b/src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs new file mode 100644 index 0000000000..0cd2e346ff --- /dev/null +++ b/src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using SkiaSharp; + +namespace Avalonia.Skia +{ + /// + /// Custom Skia gpu instance. + /// + public interface ICustomSkiaGpu + { + /// + /// Skia GrContext used. + /// + GRContext GrContext { get; } + + /// + /// Attempts to create custom render target from given surfaces. + /// + /// Surfaces. + /// Created render target or if it fails. + ICustomSkiaRenderTarget TryCreateRenderTarget(IEnumerable surfaces); + } +} diff --git a/src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs b/src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs new file mode 100644 index 0000000000..70b3a49bcf --- /dev/null +++ b/src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs @@ -0,0 +1,26 @@ +using System; +using SkiaSharp; + +namespace Avalonia.Skia +{ + /// + /// Custom render session for Skia render target. + /// + public interface ICustomSkiaRenderSession : IDisposable + { + /// + /// GrContext used by this session. + /// + GRContext GrContext { get; } + + /// + /// Canvas that will be used to render. + /// + SKCanvas Canvas { get; } + + /// + /// Scaling factor. + /// + double ScaleFactor { get; } + } +} diff --git a/src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs b/src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs new file mode 100644 index 0000000000..1609eaf7fe --- /dev/null +++ b/src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs @@ -0,0 +1,16 @@ +using System; + +namespace Avalonia.Skia +{ + /// + /// Custom Skia render target. + /// + public interface ICustomSkiaRenderTarget : IDisposable + { + /// + /// Start rendering to this render target. + /// + /// + ICustomSkiaRenderSession BeginRendering(); + } +} diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index c6e68b1c8b..ec162f9767 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs @@ -15,14 +15,25 @@ namespace Avalonia.Skia /// /// Skia platform render interface. /// - public class PlatformRenderInterface : IPlatformRenderInterface + internal class PlatformRenderInterface : IPlatformRenderInterface { + private readonly ICustomSkiaGpu _customSkiaGpu; + private GRContext GrContext { get; } public IEnumerable InstalledFontNames => SKFontManager.Default.FontFamilies; - public PlatformRenderInterface() + public PlatformRenderInterface(ICustomSkiaGpu customSkiaGpu) { + if (customSkiaGpu != null) + { + _customSkiaGpu = customSkiaGpu; + + GrContext = _customSkiaGpu.GrContext; + + return; + } + var gl = AvaloniaLocator.Current.GetService(); if (gl != null) { @@ -32,12 +43,11 @@ namespace Avalonia.Skia ? GRGlInterface.AssembleGlInterface((_, proc) => display.GlInterface.GetProcAddress(proc)) : GRGlInterface.AssembleGlesInterface((_, proc) => display.GlInterface.GetProcAddress(proc))) { - GrContext = GRContext.Create(GRBackend.OpenGL, iface); } } } - + /// public IFormattedTextImpl CreateFormattedText( string text, @@ -98,13 +108,23 @@ namespace Avalonia.Skia DisableTextLcdRendering = false, GrContext = GrContext }; - + return new SurfaceRenderTarget(createInfo); } /// - public virtual IRenderTarget CreateRenderTarget(IEnumerable surfaces) + public IRenderTarget CreateRenderTarget(IEnumerable surfaces) { + if (_customSkiaGpu != null) + { + ICustomSkiaRenderTarget customRenderTarget = _customSkiaGpu.TryCreateRenderTarget(surfaces); + + if (customRenderTarget != null) + { + return new CustomRenderTarget(customRenderTarget); + } + } + foreach (var surface in surfaces) { if (surface is IGlPlatformSurface glSurface && GrContext != null) diff --git a/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs b/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs index f4412df473..0778c64736 100644 --- a/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs +++ b/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using System; using Avalonia.Controls; using Avalonia.Skia; @@ -18,9 +19,11 @@ namespace Avalonia /// Builder type. /// Builder. /// Configure builder. - public static T UseSkia(this T builder) where T : AppBuilderBase, new() + public static T UseSkia(this T builder, Func gpuFactory = null) where T : AppBuilderBase, new() { - builder.UseRenderingSubsystem(() => SkiaPlatform.Initialize(), "Skia"); + var customGpu = gpuFactory?.Invoke(); + + builder.UseRenderingSubsystem(() => SkiaPlatform.Initialize(customGpu), "Skia"); return builder; } } diff --git a/src/Skia/Avalonia.Skia/SkiaPlatform.cs b/src/Skia/Avalonia.Skia/SkiaPlatform.cs index a9d69aea31..f287f58685 100644 --- a/src/Skia/Avalonia.Skia/SkiaPlatform.cs +++ b/src/Skia/Avalonia.Skia/SkiaPlatform.cs @@ -13,10 +13,10 @@ namespace Avalonia.Skia /// /// Initialize Skia platform. /// - public static void Initialize() + public static void Initialize(ICustomSkiaGpu customGpu) { - var renderInterface = new PlatformRenderInterface(); - + var renderInterface = new PlatformRenderInterface(customGpu); + AvaloniaLocator.CurrentMutable .Bind().ToConstant(renderInterface); } From 853476943539cb434378ce62696f692ddeb2a09e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20Komosi=C5=84ski?= Date: Sat, 16 Mar 2019 16:45:30 +0100 Subject: [PATCH 03/23] Platform geometry implementations for D2D and Skia. --- samples/ControlCatalog/MainView.xaml | 3 ++ samples/ControlCatalog/Pages/EllipsePage.xaml | 23 ++++++++++++++ .../ControlCatalog/Pages/EllipsePage.xaml.cs | 18 +++++++++++ samples/ControlCatalog/Pages/LinePage.xaml | 21 +++++++++++++ samples/ControlCatalog/Pages/LinePage.xaml.cs | 18 +++++++++++ .../ControlCatalog/Pages/RectanglePage.xaml | 21 +++++++++++++ .../Pages/RectanglePage.xaml.cs | 18 +++++++++++ src/Avalonia.Visuals/Media/EllipseGeometry.cs | 31 +------------------ src/Avalonia.Visuals/Media/LineGeometry.cs | 10 +----- .../Media/RectangleGeometry.cs | 28 ++++++----------- .../Platform/IEllipseGeometryImpl.cs | 12 +++++++ .../Platform/ILineGeometryImpl.cs | 12 +++++++ .../Platform/IPlatformRenderInterface.cs | 22 +++++++++++++ .../Platform/IRectangleGeometryImpl.cs | 12 +++++++ src/Skia/Avalonia.Skia/EllipseGeometryImpl.cs | 26 ++++++++++++++++ src/Skia/Avalonia.Skia/LineGeometryImpl.cs | 30 ++++++++++++++++++ .../Avalonia.Skia/PlatformRenderInterface.cs | 6 ++++ .../Avalonia.Skia/RectangleGeometryImpl.cs | 26 ++++++++++++++++ .../Avalonia.Direct2D1/Direct2D1Platform.cs | 8 ++--- .../Media/EllipseGeometryImpl.cs | 28 +++++++++++++++++ .../Media/LineGeometryImpl.cs | 28 +++++++++++++++++ .../Media/RectangleGeometryImpl.cs | 27 ++++++++++++++++ .../Wpf/Direct2DImageSurface.cs | 2 +- .../MockPlatformRenderInterface.cs | 15 +++++++++ .../VisualTree/MockRenderInterface.cs | 15 +++++++++ 25 files changed, 398 insertions(+), 62 deletions(-) create mode 100644 samples/ControlCatalog/Pages/EllipsePage.xaml create mode 100644 samples/ControlCatalog/Pages/EllipsePage.xaml.cs create mode 100644 samples/ControlCatalog/Pages/LinePage.xaml create mode 100644 samples/ControlCatalog/Pages/LinePage.xaml.cs create mode 100644 samples/ControlCatalog/Pages/RectanglePage.xaml create mode 100644 samples/ControlCatalog/Pages/RectanglePage.xaml.cs create mode 100644 src/Avalonia.Visuals/Platform/IEllipseGeometryImpl.cs create mode 100644 src/Avalonia.Visuals/Platform/ILineGeometryImpl.cs create mode 100644 src/Avalonia.Visuals/Platform/IRectangleGeometryImpl.cs create mode 100644 src/Skia/Avalonia.Skia/EllipseGeometryImpl.cs create mode 100644 src/Skia/Avalonia.Skia/LineGeometryImpl.cs create mode 100644 src/Skia/Avalonia.Skia/RectangleGeometryImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/LineGeometryImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/RectangleGeometryImpl.cs diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index 2ddb5887e5..874449c9b6 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -23,14 +23,17 @@ + + + diff --git a/samples/ControlCatalog/Pages/EllipsePage.xaml b/samples/ControlCatalog/Pages/EllipsePage.xaml new file mode 100644 index 0000000000..f66cca9cdb --- /dev/null +++ b/samples/ControlCatalog/Pages/EllipsePage.xaml @@ -0,0 +1,23 @@ + + + Ellipse + A control which represents an ellipse with a fill and a stroke. + + + + + + + + + + + + + + diff --git a/samples/ControlCatalog/Pages/EllipsePage.xaml.cs b/samples/ControlCatalog/Pages/EllipsePage.xaml.cs new file mode 100644 index 0000000000..e450e961ed --- /dev/null +++ b/samples/ControlCatalog/Pages/EllipsePage.xaml.cs @@ -0,0 +1,18 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace ControlCatalog.Pages +{ + public class EllipsePage : UserControl + { + public EllipsePage() + { + this.InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/samples/ControlCatalog/Pages/LinePage.xaml b/samples/ControlCatalog/Pages/LinePage.xaml new file mode 100644 index 0000000000..62ab917578 --- /dev/null +++ b/samples/ControlCatalog/Pages/LinePage.xaml @@ -0,0 +1,21 @@ + + + Line + A control which represents a line. + + + + + + + + + + + + diff --git a/samples/ControlCatalog/Pages/LinePage.xaml.cs b/samples/ControlCatalog/Pages/LinePage.xaml.cs new file mode 100644 index 0000000000..43b8049d45 --- /dev/null +++ b/samples/ControlCatalog/Pages/LinePage.xaml.cs @@ -0,0 +1,18 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace ControlCatalog.Pages +{ + public class LinePage : UserControl + { + public LinePage() + { + this.InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/samples/ControlCatalog/Pages/RectanglePage.xaml b/samples/ControlCatalog/Pages/RectanglePage.xaml new file mode 100644 index 0000000000..49701812c4 --- /dev/null +++ b/samples/ControlCatalog/Pages/RectanglePage.xaml @@ -0,0 +1,21 @@ + + + Rectangle + A control which represents a rectangle with a fill and a stroke. + + + + + + + + + + + + diff --git a/samples/ControlCatalog/Pages/RectanglePage.xaml.cs b/samples/ControlCatalog/Pages/RectanglePage.xaml.cs new file mode 100644 index 0000000000..0ee8a1a40f --- /dev/null +++ b/samples/ControlCatalog/Pages/RectanglePage.xaml.cs @@ -0,0 +1,18 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace ControlCatalog.Pages +{ + public class RectanglePage : UserControl + { + public RectanglePage() + { + this.InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/src/Avalonia.Visuals/Media/EllipseGeometry.cs b/src/Avalonia.Visuals/Media/EllipseGeometry.cs index ca84d4cc7b..c2df9db635 100644 --- a/src/Avalonia.Visuals/Media/EllipseGeometry.cs +++ b/src/Avalonia.Visuals/Media/EllipseGeometry.cs @@ -1,7 +1,6 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -using System; using Avalonia.Platform; namespace Avalonia.Media @@ -57,36 +56,8 @@ namespace Avalonia.Media protected override IGeometryImpl CreateDefiningGeometry() { var factory = AvaloniaLocator.Current.GetService(); - var geometry = factory.CreateStreamGeometry(); - using (var ctx = geometry.Open()) - { - var rect = Rect; - double controlPointRatio = (Math.Sqrt(2) - 1) * 4 / 3; - var center = rect.Center; - var radius = new Vector(rect.Width / 2, rect.Height / 2); - - var x0 = center.X - radius.X; - var x1 = center.X - (radius.X * controlPointRatio); - var x2 = center.X; - var x3 = center.X + (radius.X * controlPointRatio); - var x4 = center.X + radius.X; - - var y0 = center.Y - radius.Y; - var y1 = center.Y - (radius.Y * controlPointRatio); - var y2 = center.Y; - var y3 = center.Y + (radius.Y * controlPointRatio); - var y4 = center.Y + radius.Y; - - ctx.BeginFigure(new Point(x2, y0), true); - ctx.CubicBezierTo(new Point(x3, y0), new Point(x4, y1), new Point(x4, y2)); - ctx.CubicBezierTo(new Point(x4, y3), new Point(x3, y4), new Point(x2, y4)); - ctx.CubicBezierTo(new Point(x1, y4), new Point(x0, y3), new Point(x0, y2)); - ctx.CubicBezierTo(new Point(x0, y1), new Point(x1, y0), new Point(x2, y0)); - ctx.EndFigure(true); - } - - return geometry; + return factory.CreateEllipseGeometry(Rect); } } } diff --git a/src/Avalonia.Visuals/Media/LineGeometry.cs b/src/Avalonia.Visuals/Media/LineGeometry.cs index f7ba4ccb0e..90577dabd8 100644 --- a/src/Avalonia.Visuals/Media/LineGeometry.cs +++ b/src/Avalonia.Visuals/Media/LineGeometry.cs @@ -73,16 +73,8 @@ namespace Avalonia.Media protected override IGeometryImpl CreateDefiningGeometry() { var factory = AvaloniaLocator.Current.GetService(); - var geometry = factory.CreateStreamGeometry(); - using (var context = geometry.Open()) - { - context.BeginFigure(StartPoint, false); - context.LineTo(EndPoint); - context.EndFigure(false); - } - - return geometry; + return factory.CreateLineGeometry(StartPoint, EndPoint); } } } diff --git a/src/Avalonia.Visuals/Media/RectangleGeometry.cs b/src/Avalonia.Visuals/Media/RectangleGeometry.cs index 3ccfd80f93..9250500644 100644 --- a/src/Avalonia.Visuals/Media/RectangleGeometry.cs +++ b/src/Avalonia.Visuals/Media/RectangleGeometry.cs @@ -16,12 +16,6 @@ namespace Avalonia.Media public static readonly StyledProperty RectProperty = AvaloniaProperty.Register(nameof(Rect)); - public Rect Rect - { - get => GetValue(RectProperty); - set => SetValue(RectProperty, value); - } - static RectangleGeometry() { AffectsGeometry(RectProperty); @@ -43,25 +37,23 @@ namespace Avalonia.Media Rect = rect; } + /// + /// Gets or sets the bounds of the rectangle. + /// + public Rect Rect + { + get => GetValue(RectProperty); + set => SetValue(RectProperty, value); + } + /// public override Geometry Clone() => new RectangleGeometry(Rect); protected override IGeometryImpl CreateDefiningGeometry() { var factory = AvaloniaLocator.Current.GetService(); - var geometry = factory.CreateStreamGeometry(); - - using (var context = geometry.Open()) - { - var rect = Rect; - context.BeginFigure(rect.TopLeft, true); - context.LineTo(rect.TopRight); - context.LineTo(rect.BottomRight); - context.LineTo(rect.BottomLeft); - context.EndFigure(true); - } - return geometry; + return factory.CreateRectangleGeometry(Rect); } } } diff --git a/src/Avalonia.Visuals/Platform/IEllipseGeometryImpl.cs b/src/Avalonia.Visuals/Platform/IEllipseGeometryImpl.cs new file mode 100644 index 0000000000..982cf286a3 --- /dev/null +++ b/src/Avalonia.Visuals/Platform/IEllipseGeometryImpl.cs @@ -0,0 +1,12 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Platform +{ + /// + /// Defines the platform-specific interface for a . + /// + public interface IEllipseGeometryImpl : IGeometryImpl + { + } +} diff --git a/src/Avalonia.Visuals/Platform/ILineGeometryImpl.cs b/src/Avalonia.Visuals/Platform/ILineGeometryImpl.cs new file mode 100644 index 0000000000..a8aa46fb13 --- /dev/null +++ b/src/Avalonia.Visuals/Platform/ILineGeometryImpl.cs @@ -0,0 +1,12 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Platform +{ + /// + /// Defines the platform-specific interface for a . + /// + public interface ILineGeometryImpl : IGeometryImpl + { + } +} diff --git a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs index 3a1f79e32a..45ce8f5874 100644 --- a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs +++ b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs @@ -36,6 +36,28 @@ namespace Avalonia.Platform Size constraint, IReadOnlyList spans); + /// + /// Creates an ellipse geometry implementation. + /// + /// The bounds of the ellipse. + /// An . + IEllipseGeometryImpl CreateEllipseGeometry(Rect rect); + + /// + /// Creates a line geometry implementation. + /// + /// The start of the line. + /// The end of the line. + /// An . + ILineGeometryImpl CreateLineGeometry(Point p1, Point p2); + + /// + /// Creates a rectangle geometry implementation. + /// + /// The bounds of the rectangle. + /// An . + IRectangleGeometryImpl CreateRectangleGeometry(Rect rect); + /// /// Creates a stream geometry implementation. /// diff --git a/src/Avalonia.Visuals/Platform/IRectangleGeometryImpl.cs b/src/Avalonia.Visuals/Platform/IRectangleGeometryImpl.cs new file mode 100644 index 0000000000..7ada2c874d --- /dev/null +++ b/src/Avalonia.Visuals/Platform/IRectangleGeometryImpl.cs @@ -0,0 +1,12 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Platform +{ + /// + /// Defines the platform-specific interface for a . + /// + public interface IRectangleGeometryImpl : IGeometryImpl + { + } +} diff --git a/src/Skia/Avalonia.Skia/EllipseGeometryImpl.cs b/src/Skia/Avalonia.Skia/EllipseGeometryImpl.cs new file mode 100644 index 0000000000..92a0a5ff80 --- /dev/null +++ b/src/Skia/Avalonia.Skia/EllipseGeometryImpl.cs @@ -0,0 +1,26 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Platform; +using SkiaSharp; + +namespace Avalonia.Skia +{ + /// + /// A Skia implementation of a . + /// + internal class EllipseGeometryImpl : GeometryImpl, IEllipseGeometryImpl + { + public override Rect Bounds { get; } + public override SKPath EffectivePath { get; } + + public EllipseGeometryImpl(Rect rect) + { + var path = new SKPath(); + path.AddOval(rect.ToSKRect()); + + EffectivePath = path; + Bounds = rect; + } + } +} diff --git a/src/Skia/Avalonia.Skia/LineGeometryImpl.cs b/src/Skia/Avalonia.Skia/LineGeometryImpl.cs new file mode 100644 index 0000000000..a78c76d44a --- /dev/null +++ b/src/Skia/Avalonia.Skia/LineGeometryImpl.cs @@ -0,0 +1,30 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Platform; +using SkiaSharp; + +namespace Avalonia.Skia +{ + /// + /// A Skia implementation of a . + /// + internal class LineGeometryImpl : GeometryImpl, ILineGeometryImpl + { + public override Rect Bounds { get; } + public override SKPath EffectivePath { get; } + + public LineGeometryImpl(Point p1, Point p2) + { + var path = new SKPath(); + path.MoveTo(p1.ToSKPoint()); + path.LineTo(p2.ToSKPoint()); + + EffectivePath = path; + Bounds = new Rect( + new Point(Math.Min(p1.X, p2.X), Math.Min(p1.Y, p2.Y)), + new Point(Math.Max(p1.X, p2.X), Math.Max(p1.Y, p2.Y))); + } + } +} diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index c6e68b1c8b..f1e89bc464 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs @@ -50,6 +50,12 @@ namespace Avalonia.Skia return new FormattedTextImpl(text, typeface, textAlignment, wrapping, constraint, spans); } + public IEllipseGeometryImpl CreateEllipseGeometry(Rect rect) => new EllipseGeometryImpl(rect); + + public ILineGeometryImpl CreateLineGeometry(Point p1, Point p2) => new LineGeometryImpl(p1, p2); + + public IRectangleGeometryImpl CreateRectangleGeometry(Rect rect) => new RectangleGeometryImpl(rect); + /// public IStreamGeometryImpl CreateStreamGeometry() { diff --git a/src/Skia/Avalonia.Skia/RectangleGeometryImpl.cs b/src/Skia/Avalonia.Skia/RectangleGeometryImpl.cs new file mode 100644 index 0000000000..235cd37b56 --- /dev/null +++ b/src/Skia/Avalonia.Skia/RectangleGeometryImpl.cs @@ -0,0 +1,26 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Platform; +using SkiaSharp; + +namespace Avalonia.Skia +{ + /// + /// A Skia implementation of a . + /// + internal class RectangleGeometryImpl : GeometryImpl, IRectangleGeometryImpl + { + public override Rect Bounds { get; } + public override SKPath EffectivePath { get; } + + public RectangleGeometryImpl(Rect rect) + { + var path = new SKPath(); + path.AddRect(rect.ToSKRect()); + + EffectivePath = path; + Bounds = rect; + } + } +} diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs index 8412a65e23..cb37a93bb3 100644 --- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs +++ b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs @@ -182,10 +182,10 @@ namespace Avalonia.Direct2D1 return new WriteableWicBitmapImpl(size, dpi, format); } - public IStreamGeometryImpl CreateStreamGeometry() - { - return new StreamGeometryImpl(); - } + public IEllipseGeometryImpl CreateEllipseGeometry(Rect rect) => new EllipseGeometryImpl(rect); + public ILineGeometryImpl CreateLineGeometry(Point p1, Point p2) => new LineGeometryImpl(p1, p2); + public IRectangleGeometryImpl CreateRectangleGeometry(Rect rect) => new RectangleGeometryImpl(rect); + public IStreamGeometryImpl CreateStreamGeometry() => new StreamGeometryImpl(); public IBitmapImpl LoadBitmap(string fileName) { diff --git a/src/Windows/Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs new file mode 100644 index 0000000000..c6bf475ed1 --- /dev/null +++ b/src/Windows/Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs @@ -0,0 +1,28 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Platform; +using SharpDX.Direct2D1; + +namespace Avalonia.Direct2D1.Media +{ + /// + /// A Direct2D implementation of a . + /// + internal class EllipseGeometryImpl : GeometryImpl, IEllipseGeometryImpl + { + /// + /// Initializes a new instance of the class. + /// + public EllipseGeometryImpl(Rect rect) + : base(CreateGeometry(rect)) + { + } + + private static Geometry CreateGeometry(Rect rect) + { + var ellipse = new Ellipse(rect.Center.ToSharpDX(), (float)rect.Width / 2, (float)rect.Height / 2); + return new EllipseGeometry(Direct2D1Platform.Direct2D1Factory, ellipse); + } + } +} diff --git a/src/Windows/Avalonia.Direct2D1/Media/LineGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/LineGeometryImpl.cs new file mode 100644 index 0000000000..b2d11247b9 --- /dev/null +++ b/src/Windows/Avalonia.Direct2D1/Media/LineGeometryImpl.cs @@ -0,0 +1,28 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Platform; +using SharpDX.Direct2D1; + +namespace Avalonia.Direct2D1.Media +{ + /// + /// A Direct2D implementation of a . + /// + internal class LineGeometryImpl : StreamGeometryImpl, ILineGeometryImpl + { + /// + /// Initializes a new instance of the class. + /// + public LineGeometryImpl(Point p1, Point p2) + { + using (var sink = ((PathGeometry)Geometry).Open()) + { + sink.BeginFigure(p1.ToSharpDX(), FigureBegin.Hollow); + sink.AddLine(p2.ToSharpDX()); + sink.EndFigure(FigureEnd.Open); + sink.Close(); + } + } + } +} diff --git a/src/Windows/Avalonia.Direct2D1/Media/RectangleGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/RectangleGeometryImpl.cs new file mode 100644 index 0000000000..55b2b66b3f --- /dev/null +++ b/src/Windows/Avalonia.Direct2D1/Media/RectangleGeometryImpl.cs @@ -0,0 +1,27 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Platform; +using SharpDX.Direct2D1; + +namespace Avalonia.Direct2D1.Media +{ + /// + /// A Direct2D implementation of a . + /// + internal class RectangleGeometryImpl : GeometryImpl, IRectangleGeometryImpl + { + /// + /// Initializes a new instance of the class. + /// + public RectangleGeometryImpl(Rect rect) + : base(CreateGeometry(rect)) + { + } + + private static Geometry CreateGeometry(Rect rect) + { + return new RectangleGeometry(Direct2D1Platform.Direct2D1Factory, rect.ToDirect2D()); + } + } +} diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs index 400dd59ea9..5b04c5d7ff 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs @@ -50,7 +50,7 @@ namespace Avalonia.Win32.Interop.Wpf { _resource = texture.QueryInterface(); - Target = new RenderTarget(AvaloniaLocator.Current.GetService(), surface, + Target = new RenderTarget(Direct2D1Platform.Direct2D1Factory, surface, new RenderTargetProperties { DpiX = (float) dpi.X, diff --git a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs index 0e2abb314d..1aeaf6bf8b 100644 --- a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs +++ b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs @@ -22,6 +22,21 @@ namespace Avalonia.UnitTests return Mock.Of(); } + public IEllipseGeometryImpl CreateEllipseGeometry(Rect rect) + { + throw new NotImplementedException(); + } + + public ILineGeometryImpl CreateLineGeometry(Point p1, Point p2) + { + throw new NotImplementedException(); + } + + public IRectangleGeometryImpl CreateRectangleGeometry(Rect rect) + { + throw new NotImplementedException(); + } + public IRenderTarget CreateRenderTarget(IEnumerable surfaces) { return Mock.Of(); diff --git a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs index fec0f0831a..34be5f1dde 100644 --- a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs +++ b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs @@ -56,6 +56,21 @@ namespace Avalonia.Visuals.UnitTests.VisualTree throw new NotImplementedException(); } + public IEllipseGeometryImpl CreateEllipseGeometry(Rect rect) + { + throw new NotImplementedException(); + } + + public ILineGeometryImpl CreateLineGeometry(Point p1, Point p2) + { + throw new NotImplementedException(); + } + + public IRectangleGeometryImpl CreateRectangleGeometry(Rect rect) + { + throw new NotImplementedException(); + } + class MockStreamGeometry : IStreamGeometryImpl { private MockStreamGeometryContext _impl = new MockStreamGeometryContext(); From 0f414d839177d34317fb4d87d9b12332ab45a8dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20Komosi=C5=84ski?= Date: Sun, 17 Mar 2019 17:43:23 +0100 Subject: [PATCH 04/23] Fix unit tests. --- src/Skia/Avalonia.Skia/SkiaPlatform.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Skia/Avalonia.Skia/SkiaPlatform.cs b/src/Skia/Avalonia.Skia/SkiaPlatform.cs index f287f58685..e4185c43a2 100644 --- a/src/Skia/Avalonia.Skia/SkiaPlatform.cs +++ b/src/Skia/Avalonia.Skia/SkiaPlatform.cs @@ -13,7 +13,7 @@ namespace Avalonia.Skia /// /// Initialize Skia platform. /// - public static void Initialize(ICustomSkiaGpu customGpu) + public static void Initialize(ICustomSkiaGpu customGpu = null) { var renderInterface = new PlatformRenderInterface(customGpu); From adf92d2ecb3ba3111fd3cf3efddd58b0250e129a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20Komosi=C5=84ski?= Date: Sun, 17 Mar 2019 17:57:15 +0100 Subject: [PATCH 05/23] Add license headers. --- src/Skia/Avalonia.Skia/CustomRenderTarget.cs | 3 +++ src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs | 3 +++ src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs | 3 +++ src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs | 3 +++ 4 files changed, 12 insertions(+) diff --git a/src/Skia/Avalonia.Skia/CustomRenderTarget.cs b/src/Skia/Avalonia.Skia/CustomRenderTarget.cs index dd62237b0c..23a509a2a4 100644 --- a/src/Skia/Avalonia.Skia/CustomRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/CustomRenderTarget.cs @@ -1,3 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + using Avalonia.Platform; using Avalonia.Rendering; diff --git a/src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs b/src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs index 0cd2e346ff..751dd3c1e7 100644 --- a/src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs +++ b/src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs @@ -1,3 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + using System.Collections.Generic; using SkiaSharp; diff --git a/src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs b/src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs index 70b3a49bcf..6a4591921e 100644 --- a/src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs +++ b/src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs @@ -1,3 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + using System; using SkiaSharp; diff --git a/src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs b/src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs index 1609eaf7fe..f67b28b77b 100644 --- a/src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs @@ -1,3 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + using System; namespace Avalonia.Skia From b6ee0d025bc32469c17e56934e4981e164a424e1 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 3 Apr 2019 17:48:34 +0200 Subject: [PATCH 06/23] Update version to 0.8.0. --- build/SharedVersion.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/SharedVersion.props b/build/SharedVersion.props index b46ac16a79..7ea1dd0c65 100644 --- a/build/SharedVersion.props +++ b/build/SharedVersion.props @@ -2,7 +2,7 @@ xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> Avalonia - 0.7.1 + 0.8.0 Copyright 2018 © The AvaloniaUI Project https://github.com/AvaloniaUI/Avalonia/blob/master/licence.md https://github.com/AvaloniaUI/Avalonia/ @@ -11,4 +11,4 @@ CS1591 latest - \ No newline at end of file + From fe5d5bca1bfb616c9816891f051e80c4568894a3 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Mon, 8 Apr 2019 13:43:49 +0200 Subject: [PATCH 07/23] Make TreeView.SelectionModeProperty public so it can be set from styles. --- src/Avalonia.Controls/TreeView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index 94989254dc..0c9bedfa93 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -48,7 +48,7 @@ namespace Avalonia.Controls /// /// Defines the property. /// - protected static readonly StyledProperty SelectionModeProperty = + public static readonly StyledProperty SelectionModeProperty = AvaloniaProperty.Register( nameof(SelectionMode)); From ebe92b661975e185c739aaed1481f30520691766 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Mon, 8 Apr 2019 13:56:31 +0200 Subject: [PATCH 08/23] Make sure that property is registered on a correct type. --- src/Avalonia.Controls/TreeView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index 0c9bedfa93..2b1aa45dd4 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -49,7 +49,7 @@ namespace Avalonia.Controls /// Defines the property. /// public static readonly StyledProperty SelectionModeProperty = - AvaloniaProperty.Register( + AvaloniaProperty.Register( nameof(SelectionMode)); private static readonly IList Empty = new object[0]; From 9209c9be421f18e20ebf95647ffdf3dedf99120b Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Mon, 8 Apr 2019 14:49:53 +0200 Subject: [PATCH 09/23] Implement platform options for Skia. --- .../SkiaApplicationExtensions.cs | 10 ++++------ src/Skia/Avalonia.Skia/SkiaOptions.cs | 19 +++++++++++++++++++ src/Skia/Avalonia.Skia/SkiaPlatform.cs | 8 +++++++- 3 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 src/Skia/Avalonia.Skia/SkiaOptions.cs diff --git a/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs b/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs index 0778c64736..102f1f92aa 100644 --- a/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs +++ b/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -using System; using Avalonia.Controls; using Avalonia.Skia; @@ -19,12 +18,11 @@ namespace Avalonia /// Builder type. /// Builder. /// Configure builder. - public static T UseSkia(this T builder, Func gpuFactory = null) where T : AppBuilderBase, new() + public static T UseSkia(this T builder) where T : AppBuilderBase, new() { - var customGpu = gpuFactory?.Invoke(); - - builder.UseRenderingSubsystem(() => SkiaPlatform.Initialize(customGpu), "Skia"); - return builder; + return builder.UseRenderingSubsystem(() => SkiaPlatform.Initialize( + AvaloniaLocator.Current.GetService() ?? new SkiaOptions()), + "Skia"); } } } diff --git a/src/Skia/Avalonia.Skia/SkiaOptions.cs b/src/Skia/Avalonia.Skia/SkiaOptions.cs new file mode 100644 index 0000000000..bac1849be8 --- /dev/null +++ b/src/Skia/Avalonia.Skia/SkiaOptions.cs @@ -0,0 +1,19 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Skia; + +namespace Avalonia +{ + /// + /// Options for Skia rendering subsystem. + /// + public class SkiaOptions + { + /// + /// Custom gpu factory to use. Can be used to customize behavior of Skia renderer. + /// + public Func CustomGpuFactory { get; set; } + } +} diff --git a/src/Skia/Avalonia.Skia/SkiaPlatform.cs b/src/Skia/Avalonia.Skia/SkiaPlatform.cs index e4185c43a2..f16e967f42 100644 --- a/src/Skia/Avalonia.Skia/SkiaPlatform.cs +++ b/src/Skia/Avalonia.Skia/SkiaPlatform.cs @@ -13,8 +13,14 @@ namespace Avalonia.Skia /// /// Initialize Skia platform. /// - public static void Initialize(ICustomSkiaGpu customGpu = null) + public static void Initialize() { + Initialize(new SkiaOptions()); + } + + public static void Initialize(SkiaOptions options) + { + var customGpu = options.CustomGpuFactory?.Invoke(); var renderInterface = new PlatformRenderInterface(customGpu); AvaloniaLocator.CurrentMutable From 0961cc122ae9b3c0b75f1fc2bb955f6baa9acd4b Mon Sep 17 00:00:00 2001 From: artyom Date: Mon, 8 Apr 2019 17:07:01 +0300 Subject: [PATCH 10/23] Add xmlns, move files to Avalonia.ReactiveUI namespace --- .../AppBuilderExtensions.cs | 7 ++++++- src/Avalonia.ReactiveUI/Attributes.cs | 8 ++++++++ .../AvaloniaActivationForViewFetcher.cs | 18 +++++++++++++++++- src/Avalonia.ReactiveUI/ReactiveUserControl.cs | 2 +- src/Avalonia.ReactiveUI/ReactiveWindow.cs | 2 +- src/Avalonia.ReactiveUI/RoutedViewHost.cs | 8 ++++++-- .../AvaloniaActivationForViewFetcherTest.cs | 1 + .../RoutedViewHostTest.cs | 1 + 8 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 src/Avalonia.ReactiveUI/Attributes.cs diff --git a/src/Avalonia.ReactiveUI/AppBuilderExtensions.cs b/src/Avalonia.ReactiveUI/AppBuilderExtensions.cs index d763febdf3..f67cb7f40a 100644 --- a/src/Avalonia.ReactiveUI/AppBuilderExtensions.cs +++ b/src/Avalonia.ReactiveUI/AppBuilderExtensions.cs @@ -6,10 +6,15 @@ using Avalonia.Threading; using ReactiveUI; using Splat; -namespace Avalonia +namespace Avalonia.ReactiveUI { public static class AppBuilderExtensions { + /// + /// Initializes ReactiveUI framework to use with Avalonia. Registers Avalonia + /// scheduler and Avalonia activation for view fetcher. Always remember to + /// call this method if you are using ReactiveUI in your application. + /// public static TAppBuilder UseReactiveUI(this TAppBuilder builder) where TAppBuilder : AppBuilderBase, new() { diff --git a/src/Avalonia.ReactiveUI/Attributes.cs b/src/Avalonia.ReactiveUI/Attributes.cs new file mode 100644 index 0000000000..e908d1de80 --- /dev/null +++ b/src/Avalonia.ReactiveUI/Attributes.cs @@ -0,0 +1,8 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using Avalonia.Metadata; + +[assembly: XmlnsDefinition("http://reactiveui.net", "Avalonia.ReactiveUI")] \ No newline at end of file diff --git a/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs b/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs index e1db604e95..cfa7a270be 100644 --- a/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs +++ b/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs @@ -9,15 +9,24 @@ using Avalonia.VisualTree; using Avalonia.Controls; using ReactiveUI; -namespace Avalonia +namespace Avalonia.ReactiveUI { + /// + /// Determines when Avalonia IVisuals get activated. + /// public class AvaloniaActivationForViewFetcher : IActivationForViewFetcher { + /// + /// Returns affinity for view. + /// public int GetAffinityForView(Type view) { return typeof(IVisual).GetTypeInfo().IsAssignableFrom(view.GetTypeInfo()) ? 10 : 0; } + /// + /// Returns activation observable for activatable Avalonia view. + /// public IObservable GetActivationForView(IActivatable view) { if (!(view is IVisual visual)) return Observable.Return(false); @@ -25,6 +34,9 @@ namespace Avalonia return GetActivationForVisual(visual); } + /// + /// Listens to Opened and Closed events for Avalonia windows. + /// private IObservable GetActivationForWindowBase(WindowBase window) { var windowLoaded = Observable @@ -42,6 +54,10 @@ namespace Avalonia .DistinctUntilChanged(); } + /// + /// Listens to AttachedToVisualTree and DetachedFromVisualTree + /// events for Avalonia IVisuals. + /// private IObservable GetActivationForVisual(IVisual visual) { var visualLoaded = Observable diff --git a/src/Avalonia.ReactiveUI/ReactiveUserControl.cs b/src/Avalonia.ReactiveUI/ReactiveUserControl.cs index 43e2ef93b6..010acc3ae0 100644 --- a/src/Avalonia.ReactiveUI/ReactiveUserControl.cs +++ b/src/Avalonia.ReactiveUI/ReactiveUserControl.cs @@ -6,7 +6,7 @@ using Avalonia.VisualTree; using Avalonia.Controls; using ReactiveUI; -namespace Avalonia +namespace Avalonia.ReactiveUI { /// /// A ReactiveUI UserControl that implements diff --git a/src/Avalonia.ReactiveUI/ReactiveWindow.cs b/src/Avalonia.ReactiveUI/ReactiveWindow.cs index bb50a37764..f0f115afbc 100644 --- a/src/Avalonia.ReactiveUI/ReactiveWindow.cs +++ b/src/Avalonia.ReactiveUI/ReactiveWindow.cs @@ -6,7 +6,7 @@ using Avalonia.VisualTree; using Avalonia.Controls; using ReactiveUI; -namespace Avalonia +namespace Avalonia.ReactiveUI { /// /// A ReactiveUI Window that implements diff --git a/src/Avalonia.ReactiveUI/RoutedViewHost.cs b/src/Avalonia.ReactiveUI/RoutedViewHost.cs index e364d5de0b..4bd86a67c0 100644 --- a/src/Avalonia.ReactiveUI/RoutedViewHost.cs +++ b/src/Avalonia.ReactiveUI/RoutedViewHost.cs @@ -1,13 +1,17 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + using System; using System.Reactive.Disposables; using System.Reactive.Linq; using Avalonia.Animation; using Avalonia.Controls; using Avalonia.Styling; +using Avalonia; using ReactiveUI; using Splat; -namespace Avalonia +namespace Avalonia.ReactiveUI { /// /// This control hosts the View associated with ReactiveUI RoutingState, @@ -157,7 +161,7 @@ namespace Avalonia return; } - var viewLocator = ViewLocator ?? ReactiveUI.ViewLocator.Current; + var viewLocator = ViewLocator ?? global::ReactiveUI.ViewLocator.Current; var view = viewLocator.ResolveView(viewModel); if (view == null) throw new Exception($"Couldn't find view for '{viewModel}'. Is it registered?"); diff --git a/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs index 70a5504a7d..d9f1ce47dd 100644 --- a/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs +++ b/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs @@ -11,6 +11,7 @@ using DynamicData; using Xunit; using Splat; using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; namespace Avalonia { diff --git a/tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs index de09a1ea89..401d169896 100644 --- a/tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs +++ b/tests/Avalonia.ReactiveUI.UnitTests/RoutedViewHostTest.cs @@ -14,6 +14,7 @@ using Avalonia.Markup.Xaml; using System.ComponentModel; using System.Threading.Tasks; using System.Reactive; +using Avalonia.ReactiveUI; namespace Avalonia { From a66a2d33aa5abe93160c2286d327820b6b4e4e39 Mon Sep 17 00:00:00 2001 From: artyom Date: Mon, 8 Apr 2019 17:55:55 +0300 Subject: [PATCH 11/23] Add missing usings --- samples/BindingDemo/App.xaml.cs | 1 + samples/ControlCatalog.Desktop/Program.cs | 1 + samples/ControlCatalog.NetCore/Program.cs | 1 + samples/RenderDemo/App.xaml.cs | 1 + samples/VirtualizationDemo/Program.cs | 1 + 5 files changed, 5 insertions(+) diff --git a/samples/BindingDemo/App.xaml.cs b/samples/BindingDemo/App.xaml.cs index 01c52a2a49..f2f44cd502 100644 --- a/samples/BindingDemo/App.xaml.cs +++ b/samples/BindingDemo/App.xaml.cs @@ -3,6 +3,7 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Logging.Serilog; using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; using Serilog; namespace BindingDemo diff --git a/samples/ControlCatalog.Desktop/Program.cs b/samples/ControlCatalog.Desktop/Program.cs index dd5644dd6b..b7aa34f5ba 100644 --- a/samples/ControlCatalog.Desktop/Program.cs +++ b/samples/ControlCatalog.Desktop/Program.cs @@ -4,6 +4,7 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Logging.Serilog; using Avalonia.Platform; +using Avalonia.ReactiveUI; using Serilog; namespace ControlCatalog diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs index d13a5b5ef3..c8f3fb9921 100644 --- a/samples/ControlCatalog.NetCore/Program.cs +++ b/samples/ControlCatalog.NetCore/Program.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; using Avalonia; using Avalonia.Skia; +using Avalonia.ReactiveUI; namespace ControlCatalog.NetCore { diff --git a/samples/RenderDemo/App.xaml.cs b/samples/RenderDemo/App.xaml.cs index 0f627961e6..d95018520a 100644 --- a/samples/RenderDemo/App.xaml.cs +++ b/samples/RenderDemo/App.xaml.cs @@ -4,6 +4,7 @@ using Avalonia; using Avalonia.Logging.Serilog; using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; namespace RenderDemo { diff --git a/samples/VirtualizationDemo/Program.cs b/samples/VirtualizationDemo/Program.cs index 98f1f08d6c..9d8f7c1a3d 100644 --- a/samples/VirtualizationDemo/Program.cs +++ b/samples/VirtualizationDemo/Program.cs @@ -5,6 +5,7 @@ using System; using Avalonia; using Avalonia.Controls; using Avalonia.Logging.Serilog; +using Avalonia.ReactiveUI; using Serilog; namespace VirtualizationDemo From cf1401e5f20e2a08ec6b458729822f180d4bbdac Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Mon, 8 Apr 2019 17:04:26 +0200 Subject: [PATCH 12/23] Use ListBox properties for TreeView implementation. --- src/Avalonia.Controls/ListBox.cs | 4 ++-- src/Avalonia.Controls/TreeView.cs | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Controls/ListBox.cs b/src/Avalonia.Controls/ListBox.cs index fce568e56d..041b81155a 100644 --- a/src/Avalonia.Controls/ListBox.cs +++ b/src/Avalonia.Controls/ListBox.cs @@ -30,13 +30,13 @@ namespace Avalonia.Controls /// /// Defines the property. /// - public static readonly new AvaloniaProperty SelectedItemsProperty = + public static readonly new DirectProperty SelectedItemsProperty = SelectingItemsControl.SelectedItemsProperty; /// /// Defines the property. /// - public static readonly new AvaloniaProperty SelectionModeProperty = + public static readonly new StyledProperty SelectionModeProperty = SelectingItemsControl.SelectionModeProperty; /// diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index 2b1aa45dd4..c3fbce1d83 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -40,8 +40,7 @@ namespace Avalonia.Controls /// Defines the property. /// public static readonly DirectProperty SelectedItemsProperty = - AvaloniaProperty.RegisterDirect( - nameof(SelectedItems), + ListBox.SelectedItemsProperty.AddOwner( o => o.SelectedItems, (o, v) => o.SelectedItems = v); @@ -49,8 +48,7 @@ namespace Avalonia.Controls /// Defines the property. /// public static readonly StyledProperty SelectionModeProperty = - AvaloniaProperty.Register( - nameof(SelectionMode)); + ListBox.SelectionModeProperty.AddOwner(); private static readonly IList Empty = new object[0]; private object _selectedItem; From 12fc28e2d08d9dfdb9da9dcbeb8517c0d7f01cf0 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Mon, 8 Apr 2019 17:24:17 +0200 Subject: [PATCH 13/23] Add mocks for geometry impls. --- tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs index 1aeaf6bf8b..c73c30365b 100644 --- a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs +++ b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs @@ -24,17 +24,17 @@ namespace Avalonia.UnitTests public IEllipseGeometryImpl CreateEllipseGeometry(Rect rect) { - throw new NotImplementedException(); + return Mock.Of(); } public ILineGeometryImpl CreateLineGeometry(Point p1, Point p2) { - throw new NotImplementedException(); + return Mock.Of(); } public IRectangleGeometryImpl CreateRectangleGeometry(Rect rect) { - throw new NotImplementedException(); + return Mock.Of(); } public IRenderTarget CreateRenderTarget(IEnumerable surfaces) From aad6bf703e19095b376d07f2e2e6b4194f11daf8 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 8 Apr 2019 20:03:33 +0100 Subject: [PATCH 14/23] bump version number and copyright year. --- build/SharedVersion.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/SharedVersion.props b/build/SharedVersion.props index 7ea1dd0c65..4f0b1f0a5b 100644 --- a/build/SharedVersion.props +++ b/build/SharedVersion.props @@ -2,8 +2,8 @@ xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> Avalonia - 0.8.0 - Copyright 2018 © The AvaloniaUI Project + 0.8.1 + Copyright 2019 © The AvaloniaUI Project https://github.com/AvaloniaUI/Avalonia/blob/master/licence.md https://github.com/AvaloniaUI/Avalonia/ https://github.com/AvaloniaUI/Avalonia/ From 129f8ca535490a6fe22f4ec5a306329b0b45309d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro?= Date: Tue, 9 Apr 2019 23:52:28 +0100 Subject: [PATCH 15/23] XML comment fixes. --- src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs | 2 ++ src/Avalonia.Controls/Window.cs | 3 ++- src/Avalonia.Styling/StyledElement.cs | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs b/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs index 0ade1af249..b59ed166bc 100644 --- a/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs +++ b/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs @@ -19,6 +19,7 @@ namespace Avalonia.Utilities /// /// The type of the target. /// The type of the event arguments. + /// The type of the subscriber. /// The event source. /// The name of the event. /// The subscriber. @@ -40,6 +41,7 @@ namespace Avalonia.Utilities /// Unsubscribes from an event. /// /// The type of the event arguments. + /// The type of the subscriber. /// The event source. /// The name of the event. /// The subscriber. diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index f5af6774b5..c8e09b8f9c 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -291,7 +291,8 @@ namespace Avalonia.Controls /// /// The dialog result. /// - /// When the window is shown with the method, the + /// When the window is shown with the + /// or method, the /// resulting task will produce the value when the window /// is closed. /// diff --git a/src/Avalonia.Styling/StyledElement.cs b/src/Avalonia.Styling/StyledElement.cs index e52a1961ba..d314a8d44e 100644 --- a/src/Avalonia.Styling/StyledElement.cs +++ b/src/Avalonia.Styling/StyledElement.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.ComponentModel; using System.Linq; using System.Reactive.Linq; using System.Reactive.Subjects; From d448aad129b1f3320dc6a07021dd121960d5ed7d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 10 Apr 2019 17:36:19 +0200 Subject: [PATCH 16/23] Update portable.xaml. #2307 updated the portable.xaml submodule but the changes were then lost in a subsequent merge. Re-updates the submodule to target the `fixes/moar-line-info` branch. --- .../Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github index ab55261737..7452b23169 160000 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github +++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github @@ -1 +1 @@ -Subproject commit ab5526173722b8988bc5ca3c03c8752ce89c0975 +Subproject commit 7452b23169e4948907fa10e2c115b672897d0e04 From 63da34f25a64f4c3a343ffe9d1da74e81f1f2006 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 10 Apr 2019 17:38:44 +0200 Subject: [PATCH 17/23] Set `ProvideLineInfo` in XAML reader settings. --- src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs index a1f8bf6cf6..4c352f199f 100644 --- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs +++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs @@ -162,7 +162,8 @@ namespace Avalonia.Markup.Xaml var readerSettings = new XamlXmlReaderSettings() { BaseUri = uri, - LocalAssembly = localAssembly + LocalAssembly = localAssembly, + ProvideLineInfo = true, }; var context = IsDesignMode ? AvaloniaXamlSchemaContext.DesignInstance : AvaloniaXamlSchemaContext.Instance; From 88d1f175d21cbc755591069a162765d210204b2c Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 11 Apr 2019 18:53:43 +0200 Subject: [PATCH 18/23] Remove geometry pages. --- samples/ControlCatalog/MainView.xaml | 3 --- samples/ControlCatalog/Pages/EllipsePage.xaml | 23 ------------------- .../ControlCatalog/Pages/EllipsePage.xaml.cs | 18 --------------- samples/ControlCatalog/Pages/LinePage.xaml | 21 ----------------- samples/ControlCatalog/Pages/LinePage.xaml.cs | 18 --------------- .../ControlCatalog/Pages/RectanglePage.xaml | 21 ----------------- .../Pages/RectanglePage.xaml.cs | 18 --------------- 7 files changed, 122 deletions(-) delete mode 100644 samples/ControlCatalog/Pages/EllipsePage.xaml delete mode 100644 samples/ControlCatalog/Pages/EllipsePage.xaml.cs delete mode 100644 samples/ControlCatalog/Pages/LinePage.xaml delete mode 100644 samples/ControlCatalog/Pages/LinePage.xaml.cs delete mode 100644 samples/ControlCatalog/Pages/RectanglePage.xaml delete mode 100644 samples/ControlCatalog/Pages/RectanglePage.xaml.cs diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index 79bfc671ef..b79db9f053 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -24,17 +24,14 @@ - - - diff --git a/samples/ControlCatalog/Pages/EllipsePage.xaml b/samples/ControlCatalog/Pages/EllipsePage.xaml deleted file mode 100644 index f66cca9cdb..0000000000 --- a/samples/ControlCatalog/Pages/EllipsePage.xaml +++ /dev/null @@ -1,23 +0,0 @@ - - - Ellipse - A control which represents an ellipse with a fill and a stroke. - - - - - - - - - - - - - - diff --git a/samples/ControlCatalog/Pages/EllipsePage.xaml.cs b/samples/ControlCatalog/Pages/EllipsePage.xaml.cs deleted file mode 100644 index e450e961ed..0000000000 --- a/samples/ControlCatalog/Pages/EllipsePage.xaml.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Markup.Xaml; - -namespace ControlCatalog.Pages -{ - public class EllipsePage : UserControl - { - public EllipsePage() - { - this.InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - } -} diff --git a/samples/ControlCatalog/Pages/LinePage.xaml b/samples/ControlCatalog/Pages/LinePage.xaml deleted file mode 100644 index 62ab917578..0000000000 --- a/samples/ControlCatalog/Pages/LinePage.xaml +++ /dev/null @@ -1,21 +0,0 @@ - - - Line - A control which represents a line. - - - - - - - - - - - - diff --git a/samples/ControlCatalog/Pages/LinePage.xaml.cs b/samples/ControlCatalog/Pages/LinePage.xaml.cs deleted file mode 100644 index 43b8049d45..0000000000 --- a/samples/ControlCatalog/Pages/LinePage.xaml.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Markup.Xaml; - -namespace ControlCatalog.Pages -{ - public class LinePage : UserControl - { - public LinePage() - { - this.InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - } -} diff --git a/samples/ControlCatalog/Pages/RectanglePage.xaml b/samples/ControlCatalog/Pages/RectanglePage.xaml deleted file mode 100644 index 49701812c4..0000000000 --- a/samples/ControlCatalog/Pages/RectanglePage.xaml +++ /dev/null @@ -1,21 +0,0 @@ - - - Rectangle - A control which represents a rectangle with a fill and a stroke. - - - - - - - - - - - - diff --git a/samples/ControlCatalog/Pages/RectanglePage.xaml.cs b/samples/ControlCatalog/Pages/RectanglePage.xaml.cs deleted file mode 100644 index 0ee8a1a40f..0000000000 --- a/samples/ControlCatalog/Pages/RectanglePage.xaml.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Markup.Xaml; - -namespace ControlCatalog.Pages -{ - public class RectanglePage : UserControl - { - public RectanglePage() - { - this.InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - } -} From 1b869ff27b68901d8db4b7235e199b7f00355581 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Fri, 12 Apr 2019 11:32:41 +0200 Subject: [PATCH 19/23] Get rid of not needed interfaces. --- .../Platform/IEllipseGeometryImpl.cs | 12 ------------ src/Avalonia.Visuals/Platform/ILineGeometryImpl.cs | 12 ------------ .../Platform/IPlatformRenderInterface.cs | 12 ++++++------ .../Platform/IRectangleGeometryImpl.cs | 12 ------------ src/Skia/Avalonia.Skia/EllipseGeometryImpl.cs | 3 +-- src/Skia/Avalonia.Skia/LineGeometryImpl.cs | 3 +-- src/Skia/Avalonia.Skia/PlatformRenderInterface.cs | 6 +++--- src/Skia/Avalonia.Skia/RectangleGeometryImpl.cs | 3 +-- src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs | 6 +++--- .../Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs | 3 +-- .../Avalonia.Direct2D1/Media/LineGeometryImpl.cs | 3 +-- .../Media/RectangleGeometryImpl.cs | 3 +-- .../MockPlatformRenderInterface.cs | 12 ++++++------ .../VisualTree/MockRenderInterface.cs | 6 +++--- 14 files changed, 27 insertions(+), 69 deletions(-) delete mode 100644 src/Avalonia.Visuals/Platform/IEllipseGeometryImpl.cs delete mode 100644 src/Avalonia.Visuals/Platform/ILineGeometryImpl.cs delete mode 100644 src/Avalonia.Visuals/Platform/IRectangleGeometryImpl.cs diff --git a/src/Avalonia.Visuals/Platform/IEllipseGeometryImpl.cs b/src/Avalonia.Visuals/Platform/IEllipseGeometryImpl.cs deleted file mode 100644 index 982cf286a3..0000000000 --- a/src/Avalonia.Visuals/Platform/IEllipseGeometryImpl.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) The Avalonia Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Avalonia.Platform -{ - /// - /// Defines the platform-specific interface for a . - /// - public interface IEllipseGeometryImpl : IGeometryImpl - { - } -} diff --git a/src/Avalonia.Visuals/Platform/ILineGeometryImpl.cs b/src/Avalonia.Visuals/Platform/ILineGeometryImpl.cs deleted file mode 100644 index a8aa46fb13..0000000000 --- a/src/Avalonia.Visuals/Platform/ILineGeometryImpl.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) The Avalonia Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Avalonia.Platform -{ - /// - /// Defines the platform-specific interface for a . - /// - public interface ILineGeometryImpl : IGeometryImpl - { - } -} diff --git a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs index 45ce8f5874..87db9251e1 100644 --- a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs +++ b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs @@ -40,23 +40,23 @@ namespace Avalonia.Platform /// Creates an ellipse geometry implementation. /// /// The bounds of the ellipse. - /// An . - IEllipseGeometryImpl CreateEllipseGeometry(Rect rect); + /// An ellipse geometry.. + IGeometryImpl CreateEllipseGeometry(Rect rect); /// /// Creates a line geometry implementation. /// /// The start of the line. /// The end of the line. - /// An . - ILineGeometryImpl CreateLineGeometry(Point p1, Point p2); + /// A line geometry. + IGeometryImpl CreateLineGeometry(Point p1, Point p2); /// /// Creates a rectangle geometry implementation. /// /// The bounds of the rectangle. - /// An . - IRectangleGeometryImpl CreateRectangleGeometry(Rect rect); + /// A rectangle. + IGeometryImpl CreateRectangleGeometry(Rect rect); /// /// Creates a stream geometry implementation. diff --git a/src/Avalonia.Visuals/Platform/IRectangleGeometryImpl.cs b/src/Avalonia.Visuals/Platform/IRectangleGeometryImpl.cs deleted file mode 100644 index 7ada2c874d..0000000000 --- a/src/Avalonia.Visuals/Platform/IRectangleGeometryImpl.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) The Avalonia Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Avalonia.Platform -{ - /// - /// Defines the platform-specific interface for a . - /// - public interface IRectangleGeometryImpl : IGeometryImpl - { - } -} diff --git a/src/Skia/Avalonia.Skia/EllipseGeometryImpl.cs b/src/Skia/Avalonia.Skia/EllipseGeometryImpl.cs index 92a0a5ff80..aae1dd8cef 100644 --- a/src/Skia/Avalonia.Skia/EllipseGeometryImpl.cs +++ b/src/Skia/Avalonia.Skia/EllipseGeometryImpl.cs @@ -1,7 +1,6 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -using Avalonia.Platform; using SkiaSharp; namespace Avalonia.Skia @@ -9,7 +8,7 @@ namespace Avalonia.Skia /// /// A Skia implementation of a . /// - internal class EllipseGeometryImpl : GeometryImpl, IEllipseGeometryImpl + internal class EllipseGeometryImpl : GeometryImpl { public override Rect Bounds { get; } public override SKPath EffectivePath { get; } diff --git a/src/Skia/Avalonia.Skia/LineGeometryImpl.cs b/src/Skia/Avalonia.Skia/LineGeometryImpl.cs index a78c76d44a..e929e153d1 100644 --- a/src/Skia/Avalonia.Skia/LineGeometryImpl.cs +++ b/src/Skia/Avalonia.Skia/LineGeometryImpl.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; -using Avalonia.Platform; using SkiaSharp; namespace Avalonia.Skia @@ -10,7 +9,7 @@ namespace Avalonia.Skia /// /// A Skia implementation of a . /// - internal class LineGeometryImpl : GeometryImpl, ILineGeometryImpl + internal class LineGeometryImpl : GeometryImpl { public override Rect Bounds { get; } public override SKPath EffectivePath { get; } diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index f1e89bc464..6240a1cb4b 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs @@ -50,11 +50,11 @@ namespace Avalonia.Skia return new FormattedTextImpl(text, typeface, textAlignment, wrapping, constraint, spans); } - public IEllipseGeometryImpl CreateEllipseGeometry(Rect rect) => new EllipseGeometryImpl(rect); + public IGeometryImpl CreateEllipseGeometry(Rect rect) => new EllipseGeometryImpl(rect); - public ILineGeometryImpl CreateLineGeometry(Point p1, Point p2) => new LineGeometryImpl(p1, p2); + public IGeometryImpl CreateLineGeometry(Point p1, Point p2) => new LineGeometryImpl(p1, p2); - public IRectangleGeometryImpl CreateRectangleGeometry(Rect rect) => new RectangleGeometryImpl(rect); + public IGeometryImpl CreateRectangleGeometry(Rect rect) => new RectangleGeometryImpl(rect); /// public IStreamGeometryImpl CreateStreamGeometry() diff --git a/src/Skia/Avalonia.Skia/RectangleGeometryImpl.cs b/src/Skia/Avalonia.Skia/RectangleGeometryImpl.cs index 235cd37b56..a873e8e2df 100644 --- a/src/Skia/Avalonia.Skia/RectangleGeometryImpl.cs +++ b/src/Skia/Avalonia.Skia/RectangleGeometryImpl.cs @@ -1,7 +1,6 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -using Avalonia.Platform; using SkiaSharp; namespace Avalonia.Skia @@ -9,7 +8,7 @@ namespace Avalonia.Skia /// /// A Skia implementation of a . /// - internal class RectangleGeometryImpl : GeometryImpl, IRectangleGeometryImpl + internal class RectangleGeometryImpl : GeometryImpl { public override Rect Bounds { get; } public override SKPath EffectivePath { get; } diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs index cb37a93bb3..5ab9a8f74d 100644 --- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs +++ b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs @@ -182,9 +182,9 @@ namespace Avalonia.Direct2D1 return new WriteableWicBitmapImpl(size, dpi, format); } - public IEllipseGeometryImpl CreateEllipseGeometry(Rect rect) => new EllipseGeometryImpl(rect); - public ILineGeometryImpl CreateLineGeometry(Point p1, Point p2) => new LineGeometryImpl(p1, p2); - public IRectangleGeometryImpl CreateRectangleGeometry(Rect rect) => new RectangleGeometryImpl(rect); + public IGeometryImpl CreateEllipseGeometry(Rect rect) => new EllipseGeometryImpl(rect); + public IGeometryImpl CreateLineGeometry(Point p1, Point p2) => new LineGeometryImpl(p1, p2); + public IGeometryImpl CreateRectangleGeometry(Rect rect) => new RectangleGeometryImpl(rect); public IStreamGeometryImpl CreateStreamGeometry() => new StreamGeometryImpl(); public IBitmapImpl LoadBitmap(string fileName) diff --git a/src/Windows/Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs index c6bf475ed1..9440966406 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs @@ -1,7 +1,6 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -using Avalonia.Platform; using SharpDX.Direct2D1; namespace Avalonia.Direct2D1.Media @@ -9,7 +8,7 @@ namespace Avalonia.Direct2D1.Media /// /// A Direct2D implementation of a . /// - internal class EllipseGeometryImpl : GeometryImpl, IEllipseGeometryImpl + internal class EllipseGeometryImpl : GeometryImpl { /// /// Initializes a new instance of the class. diff --git a/src/Windows/Avalonia.Direct2D1/Media/LineGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/LineGeometryImpl.cs index b2d11247b9..6b73fce309 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/LineGeometryImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/LineGeometryImpl.cs @@ -1,7 +1,6 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -using Avalonia.Platform; using SharpDX.Direct2D1; namespace Avalonia.Direct2D1.Media @@ -9,7 +8,7 @@ namespace Avalonia.Direct2D1.Media /// /// A Direct2D implementation of a . /// - internal class LineGeometryImpl : StreamGeometryImpl, ILineGeometryImpl + internal class LineGeometryImpl : StreamGeometryImpl { /// /// Initializes a new instance of the class. diff --git a/src/Windows/Avalonia.Direct2D1/Media/RectangleGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/RectangleGeometryImpl.cs index 55b2b66b3f..194de4dd14 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/RectangleGeometryImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/RectangleGeometryImpl.cs @@ -1,7 +1,6 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -using Avalonia.Platform; using SharpDX.Direct2D1; namespace Avalonia.Direct2D1.Media @@ -9,7 +8,7 @@ namespace Avalonia.Direct2D1.Media /// /// A Direct2D implementation of a . /// - internal class RectangleGeometryImpl : GeometryImpl, IRectangleGeometryImpl + internal class RectangleGeometryImpl : GeometryImpl { /// /// Initializes a new instance of the class. diff --git a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs index c73c30365b..a3cc3dec17 100644 --- a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs +++ b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs @@ -22,19 +22,19 @@ namespace Avalonia.UnitTests return Mock.Of(); } - public IEllipseGeometryImpl CreateEllipseGeometry(Rect rect) + public IGeometryImpl CreateEllipseGeometry(Rect rect) { - return Mock.Of(); + return Mock.Of(); } - public ILineGeometryImpl CreateLineGeometry(Point p1, Point p2) + public IGeometryImpl CreateLineGeometry(Point p1, Point p2) { - return Mock.Of(); + return Mock.Of(); } - public IRectangleGeometryImpl CreateRectangleGeometry(Rect rect) + public IGeometryImpl CreateRectangleGeometry(Rect rect) { - return Mock.Of(); + return Mock.Of(); } public IRenderTarget CreateRenderTarget(IEnumerable surfaces) diff --git a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs index 34be5f1dde..03470670d2 100644 --- a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs +++ b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs @@ -56,17 +56,17 @@ namespace Avalonia.Visuals.UnitTests.VisualTree throw new NotImplementedException(); } - public IEllipseGeometryImpl CreateEllipseGeometry(Rect rect) + public IGeometryImpl CreateEllipseGeometry(Rect rect) { throw new NotImplementedException(); } - public ILineGeometryImpl CreateLineGeometry(Point p1, Point p2) + public IGeometryImpl CreateLineGeometry(Point p1, Point p2) { throw new NotImplementedException(); } - public IRectangleGeometryImpl CreateRectangleGeometry(Rect rect) + public IGeometryImpl CreateRectangleGeometry(Rect rect) { throw new NotImplementedException(); } From a39763a5f20bc00076fa52823641618f67a02e20 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 12 Apr 2019 16:58:46 +0300 Subject: [PATCH 20/23] Disable Mono tests for Linux until https://github.com/mono/mono/issues/13969 is fixed --- nukebuild/Build.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index bb31034299..84092d52eb 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -122,6 +122,14 @@ partial class Build : NukeBuild foreach(var fw in frameworks) { + if (fw.StartsWith("net4") + && RuntimeInformation.IsOSPlatform(OSPlatform.Linux) + && Environment.GetEnvironmentVariable("FORCE_LINUX_TESTS") != "1") + { + Information($"Skipping {fw} tests on Linux - https://github.com/mono/mono/issues/13969"); + continue; + } + Information("Running for " + fw); DotNetTest(c => { From 1e74e8fc60b52360b57f0850298c318656e87875 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 13 Apr 2019 16:26:08 +0200 Subject: [PATCH 21/23] Add failing tests for #2388. --- .../WindowTests.cs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs index 8221dadc86..ee416c4cb0 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs @@ -292,6 +292,51 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void Calling_Show_On_Closed_Window_Should_Throw() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var windowImpl = Mock.Of(x => x.Scaling == 1); + var target = new Window(windowImpl); + + target.Show(); + target.Close(); + + var openedRaised = false; + target.Opened += (s, e) => openedRaised = true; + + var ex = Assert.Throws(() => target.Show()); + Assert.Equal("Cannot re-show a closed window.", ex.Message); + Assert.False(openedRaised); + } + } + + [Fact] + public async Task Calling_ShowDialog_On_Closed_Window_Should_Throw() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var parent = new Mock(); + var windowImpl = new Mock(); + windowImpl.SetupProperty(x => x.Closed); + windowImpl.Setup(x => x.Scaling).Returns(1); + + var target = new Window(windowImpl.Object); + var task = target.ShowDialog(parent.Object); + + windowImpl.Object.Closed(); + await task; + + var openedRaised = false; + target.Opened += (s, e) => openedRaised = true; + + var ex = await Assert.ThrowsAsync(() => target.ShowDialog(parent.Object)); + Assert.Equal("Cannot re-show a closed window.", ex.Message); + Assert.False(openedRaised); + } + } + [Fact] public void Window_Should_Be_Centered_When_WindowStartupLocation_Is_CenterScreen() { From 30e006ac78d91b49eddd0ad9368ccff216e58c32 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 13 Apr 2019 16:26:43 +0200 Subject: [PATCH 22/23] Throw an exception when trying to re-show closed window. --- src/Avalonia.Controls/Window.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index c8e09b8f9c..6c3517af62 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -373,6 +373,11 @@ namespace Avalonia.Controls /// public override void Show() { + if (PlatformImpl == null) + { + throw new InvalidOperationException("Cannot re-show a closed window."); + } + if (IsVisible) { return; From 53e666ac90f98d72d77dca160499248187c61aee Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 13 Apr 2019 16:31:33 +0200 Subject: [PATCH 23/23] Added exception details to XML docs. --- src/Avalonia.Controls/Window.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 6c3517af62..e40e114769 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -371,6 +371,9 @@ namespace Avalonia.Controls /// /// Shows the window. /// + /// + /// The window has already been closed. + /// public override void Show() { if (PlatformImpl == null) @@ -402,6 +405,9 @@ namespace Avalonia.Controls /// Shows the window as a dialog. /// /// The dialog's owner window. + /// + /// The window has already been closed. + /// /// /// A task that can be used to track the lifetime of the dialog. ///