diff --git a/.ncrunch/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject b/.ncrunch/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject index 04ab17c4e1..2627a59093 100644 --- a/.ncrunch/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject +++ b/.ncrunch/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject @@ -1,5 +1,8 @@  + + ..\TestFiles\Direct2D1\**.* + 3000 True diff --git a/.ncrunch/Avalonia.Skia.RenderTests.v3.ncrunchproject b/.ncrunch/Avalonia.Skia.RenderTests.v3.ncrunchproject index a8c3abe8f2..7fe2430013 100644 --- a/.ncrunch/Avalonia.Skia.RenderTests.v3.ncrunchproject +++ b/.ncrunch/Avalonia.Skia.RenderTests.v3.ncrunchproject @@ -1,7 +1,9 @@  - 1000 - True + + ..\TestFiles\Skia\**.* + + 3000 True \ No newline at end of file diff --git a/Avalonia.sln b/Avalonia.sln index a29f3dd754..679ef1579e 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27004.2008 +VisualStudioVersion = 15.0.27130.2024 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Base", "src\Avalonia.Base\Avalonia.Base.csproj", "{B09B78D8-9B26-48B0-9149-D64A2F120F3F}" EndProject @@ -45,11 +45,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Layout.UnitTests", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Interactivity.UnitTests", "tests\Avalonia.Interactivity.UnitTests\Avalonia.Interactivity.UnitTests.csproj", "{08478EF5-44E8-42E9-92D6-15E00EC038D8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Direct2D1.RenderTests", "tests\Avalonia.RenderTests\Avalonia.Direct2D1.RenderTests.csproj", "{DABFD304-D6A4-4752-8123-C2CCF7AC7831}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Direct2D1.RenderTests", "tests\Avalonia.Direct2D1.RenderTests\Avalonia.Direct2D1.RenderTests.csproj", "{DABFD304-D6A4-4752-8123-C2CCF7AC7831}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Input.UnitTests", "tests\Avalonia.Input.UnitTests\Avalonia.Input.UnitTests.csproj", "{AC18926A-E784-40FE-B09D-BB0FE2B599F0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Direct2D1.UnitTests", "tests\Avalonia.Direct2D1.UnitTests\Avalonia.Direct2D1.UnitTests.csproj", "{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1.UnitTests", "tests\Avalonia.Direct2D1.UnitTests\Avalonia.Direct2D1.UnitTests.csproj", "{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.Xaml.UnitTests", "tests\Avalonia.Markup.Xaml.UnitTests\Avalonia.Markup.Xaml.UnitTests.csproj", "{99135EAB-653D-47E4-A378-C96E1278CA44}" EndProject @@ -114,8 +114,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.DesignerSupport.Te EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.DesignerSupport.TestApp", "tests\Avalonia.DesignerSupport.TestApp\Avalonia.DesignerSupport.TestApp.csproj", "{F1381F98-4D24-409A-A6C5-1C5B1E08BB08}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Avalonia.RenderTests", "tests\Avalonia.RenderTests\Avalonia.RenderTests.shproj", "{48840EDD-24BF-495D-911E-2EB12AE75D3B}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualizationTest", "samples\VirtualizationTest\VirtualizationTest.csproj", "{FBCAF3D0-2808-4934-8E96-3F607594517B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interop", "Interop", "{A0CC0258-D18C-4AB3-854F-7101680FC3F9}" @@ -176,7 +174,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Direct3DInteropSample", "sa EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32.Interop", "src\Windows\Avalonia.Win32.Interop\Avalonia.Win32.Interop.csproj", "{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.Skia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Remote.Protocol", "src\Avalonia.Remote.Protocol\Avalonia.Remote.Protocol.csproj", "{D78A720C-C0C6-478B-8564-F167F9BDD01B}" EndProject @@ -200,7 +198,6 @@ Global src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4 src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.projitems*{40759a76-d0f2-464e-8000-6ff0f5c4bd7c}*SharedItemsImports = 4 src\Shared\PlatformSupport\PlatformSupport.projitems*{4488ad85-1495-4809-9aa4-ddfe0a48527e}*SharedItemsImports = 4 - tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{48840edd-24bf-495d-911e-2eb12ae75d3b}*SharedItemsImports = 13 src\Shared\PlatformSupport\PlatformSupport.projitems*{4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}*SharedItemsImports = 4 src\Shared\PlatformSupport\PlatformSupport.projitems*{7863ea94-f0fb-4386-bf8c-e5bfa761560a}*SharedItemsImports = 4 src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 4 @@ -2643,7 +2640,6 @@ Global {57E0455D-D565-44BB-B069-EE1AA20F8337} = {9B9E3891-2366-4253-A952-D08BCEB71098} {52F55355-D120-42AC-8116-8410A7D602FA} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {F1381F98-4D24-409A-A6C5-1C5B1E08BB08} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {48840EDD-24BF-495D-911E-2EB12AE75D3B} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {FBCAF3D0-2808-4934-8E96-3F607594517B} = {9B9E3891-2366-4253-A952-D08BCEB71098} {A0CC0258-D18C-4AB3-854F-7101680FC3F9} = {9B9E3891-2366-4253-A952-D08BCEB71098} {C7A69145-60B6-4882-97D6-A3921DD43978} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} diff --git a/build.cake b/build.cake index 61fda13695..01aefff093 100644 --- a/build.cake +++ b/build.cake @@ -197,8 +197,8 @@ Task("Run-Render-Tests") .IsDependentOn("Build") .WithCriteria(() => !parameters.SkipTests && parameters.IsRunningOnWindows) .Does(() => { - RunCoreTest("./tests/Avalonia.RenderTests/Avalonia.Skia.RenderTests.csproj", parameters, true); - RunCoreTest("./tests/Avalonia.RenderTests/Avalonia.Direct2D1.RenderTests.csproj", parameters, true); + RunCoreTest("./tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj", parameters, true); + RunCoreTest("./tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj", parameters, true); }); Task("Run-Designer-Unit-Tests") diff --git a/samples/Previewer/MainWindow.xaml.cs b/samples/Previewer/MainWindow.xaml.cs index c72b1f7e55..8eabf44bc3 100644 --- a/samples/Previewer/MainWindow.xaml.cs +++ b/samples/Previewer/MainWindow.xaml.cs @@ -39,7 +39,7 @@ namespace Previewer })); new BsonTcpTransport().Listen(IPAddress.Loopback, 25000, t => { - Dispatcher.UIThread.InvokeAsync(() => + Dispatcher.UIThread.Post(() => { if (_connection != null) { @@ -61,7 +61,7 @@ namespace Previewer private void OnMessage(IAvaloniaRemoteTransportConnection transport, object obj) { - Dispatcher.UIThread.InvokeAsync(() => + Dispatcher.UIThread.Post(() => { if (transport != _connection) return; diff --git a/samples/RemoteTest/Program.cs b/samples/RemoteTest/Program.cs index dce168c7ea..f518e77143 100644 --- a/samples/RemoteTest/Program.cs +++ b/samples/RemoteTest/Program.cs @@ -25,7 +25,7 @@ namespace RemoteTest var transport = new BsonTcpTransport(); transport.Listen(IPAddress.Loopback, port, sc => { - Dispatcher.UIThread.InvokeAsync(() => + Dispatcher.UIThread.Post(() => { new RemoteServer(sc).Content = new MainView(); }); @@ -34,7 +34,7 @@ namespace RemoteTest var cts = new CancellationTokenSource(); transport.Connect(IPAddress.Loopback, port).ContinueWith(t => { - Dispatcher.UIThread.InvokeAsync(() => + Dispatcher.UIThread.Post(() => { var window = new Window() { diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs index 17e6ea8f0f..a46d567d28 100644 --- a/src/Avalonia.Base/AvaloniaObject.cs +++ b/src/Avalonia.Base/AvaloniaObject.cs @@ -774,7 +774,7 @@ namespace Avalonia } else { - Dispatcher.UIThread.InvokeAsync(Set); + Dispatcher.UIThread.Post(Set); } } diff --git a/src/Avalonia.Base/PriorityBindingEntry.cs b/src/Avalonia.Base/PriorityBindingEntry.cs index b44b845f25..570bfe03dc 100644 --- a/src/Avalonia.Base/PriorityBindingEntry.cs +++ b/src/Avalonia.Base/PriorityBindingEntry.cs @@ -123,7 +123,7 @@ namespace Avalonia } else { - Dispatcher.UIThread.InvokeAsync(Signal); + Dispatcher.UIThread.Post(Signal); } } @@ -135,7 +135,7 @@ namespace Avalonia } else { - Dispatcher.UIThread.InvokeAsync(() => _owner.Completed(this)); + Dispatcher.UIThread.Post(() => _owner.Completed(this)); } } } diff --git a/src/Avalonia.Base/Threading/AvaloniaScheduler.cs b/src/Avalonia.Base/Threading/AvaloniaScheduler.cs index f9d67470c1..46529f0a5a 100644 --- a/src/Avalonia.Base/Threading/AvaloniaScheduler.cs +++ b/src/Avalonia.Base/Threading/AvaloniaScheduler.cs @@ -33,7 +33,7 @@ namespace Avalonia.Threading if (!Dispatcher.UIThread.CheckAccess()) { var cancellation = new CancellationDisposable(); - Dispatcher.UIThread.InvokeAsync(() => + Dispatcher.UIThread.Post(() => { if (!cancellation.Token.IsCancellationRequested) { diff --git a/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs b/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs index 7a0249f876..6af5ab63cf 100644 --- a/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs +++ b/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs @@ -36,7 +36,7 @@ namespace Avalonia.Threading /// public override void Post(SendOrPostCallback d, object state) { - Dispatcher.UIThread.InvokeAsync(() => d(state), DispatcherPriority.Send); + Dispatcher.UIThread.Post(() => d(state), DispatcherPriority.Send); } /// @@ -45,7 +45,7 @@ namespace Avalonia.Threading if (Dispatcher.UIThread.CheckAccess()) d(state); else - Dispatcher.UIThread.InvokeTaskAsync(() => d(state), DispatcherPriority.Send).Wait(); + Dispatcher.UIThread.InvokeAsync(() => d(state), DispatcherPriority.Send).Wait(); } } } \ No newline at end of file diff --git a/src/Avalonia.Base/Threading/Dispatcher.cs b/src/Avalonia.Base/Threading/Dispatcher.cs index 4a096fc326..7d29a4f969 100644 --- a/src/Avalonia.Base/Threading/Dispatcher.cs +++ b/src/Avalonia.Base/Threading/Dispatcher.cs @@ -79,13 +79,13 @@ namespace Avalonia.Threading public void RunJobs(DispatcherPriority minimumPriority) => _jobRunner.RunJobs(minimumPriority); /// - public Task InvokeTaskAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal) + public Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal) { return _jobRunner?.InvokeAsync(action, priority); } /// - public void InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal) + public void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal) { _jobRunner?.Post(action, priority); } diff --git a/src/Avalonia.Base/Threading/IDispatcher.cs b/src/Avalonia.Base/Threading/IDispatcher.cs index 6301015a9a..4009dcdeab 100644 --- a/src/Avalonia.Base/Threading/IDispatcher.cs +++ b/src/Avalonia.Base/Threading/IDispatcher.cs @@ -25,7 +25,7 @@ namespace Avalonia.Threading /// The method. /// The priority with which to invoke the method. /// A task that can be used to track the method's execution. - void InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal); + void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal); /// /// Post action that will be invoked on main thread @@ -34,6 +34,6 @@ namespace Avalonia.Threading /// The priority with which to invoke the method. // TODO: The naming of this method is confusing: the Async suffix usually means return a task. // Remove this and rename InvokeTaskAsync as InvokeAsync. See #816. - Task InvokeTaskAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal); + Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal); } } \ No newline at end of file diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index 5f6b3ad4c8..d2d4151e3d 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -191,7 +191,7 @@ namespace Avalonia.Controls.Presenters // The measure is currently invalid so there's no point trying to bring the // current char into view until a measure has been carried out as the scroll // viewer extents may not be up-to-date. - Dispatcher.UIThread.InvokeAsync( + Dispatcher.UIThread.Post( () => { var rect = FormattedText.HitTestTextPosition(caretIndex); diff --git a/src/Avalonia.Controls/Primitives/AdornerLayer.cs b/src/Avalonia.Controls/Primitives/AdornerLayer.cs index d7862881fb..a469f09867 100644 --- a/src/Avalonia.Controls/Primitives/AdornerLayer.cs +++ b/src/Avalonia.Controls/Primitives/AdornerLayer.cs @@ -18,8 +18,6 @@ namespace Avalonia.Controls.Primitives private static readonly AttachedProperty s_adornedElementInfoProperty = AvaloniaProperty.RegisterAttached("AdornedElementInfo"); - private readonly BoundsTracker _tracker = new BoundsTracker(); - static AdornerLayer() { AdornedElementProperty.Changed.Subscribe(AdornedElementChanged); @@ -118,7 +116,7 @@ namespace Avalonia.Controls.Primitives adorner.SetValue(s_adornedElementInfoProperty, info); } - info.Subscription = _tracker.Track(adorned).Subscribe(x => + info.Subscription = adorned.GetObservable(TransformedBoundsProperty).Subscribe(x => { info.Bounds = x; InvalidateArrange(); diff --git a/src/Avalonia.Controls/Remote/RemoteWidget.cs b/src/Avalonia.Controls/Remote/RemoteWidget.cs index c05aeaf970..83360a0010 100644 --- a/src/Avalonia.Controls/Remote/RemoteWidget.cs +++ b/src/Avalonia.Controls/Remote/RemoteWidget.cs @@ -18,7 +18,7 @@ namespace Avalonia.Controls.Remote public RemoteWidget(IAvaloniaRemoteTransportConnection connection) { _connection = connection; - _connection.OnMessage += (t, msg) => Dispatcher.UIThread.InvokeAsync(() => OnMessage(msg)); + _connection.OnMessage += (t, msg) => Dispatcher.UIThread.Post(() => OnMessage(msg)); _connection.Send(new ClientSupportedPixelFormatsMessage { Formats = new[] diff --git a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs index c2e6a200f9..cf4cec9268 100644 --- a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs +++ b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs @@ -46,16 +46,16 @@ namespace Avalonia.Controls.Remote.Server { _lastReceivedFrame = lastFrame.SequenceId; } - Dispatcher.UIThread.InvokeAsync(RenderIfNeeded); + Dispatcher.UIThread.Post(RenderIfNeeded); } if (obj is ClientSupportedPixelFormatsMessage supportedFormats) { lock (_lock) _supportedFormats = supportedFormats.Formats; - Dispatcher.UIThread.InvokeAsync(RenderIfNeeded); + Dispatcher.UIThread.Post(RenderIfNeeded); } if (obj is MeasureViewportMessage measure) - Dispatcher.UIThread.InvokeAsync(() => + Dispatcher.UIThread.Post(() => { var m = Measure(new Size(measure.Width, measure.Height)); _transport.Send(new MeasureViewportMessage @@ -69,7 +69,7 @@ namespace Avalonia.Controls.Remote.Server lock (_lock) { if (_pendingAllocation == null) - Dispatcher.UIThread.InvokeAsync(() => + Dispatcher.UIThread.Post(() => { ClientViewportAllocatedMessage allocation; lock (_lock) @@ -168,7 +168,7 @@ namespace Avalonia.Controls.Remote.Server public override void Invalidate(Rect rect) { _invalidated = true; - Dispatcher.UIThread.InvokeAsync(RenderIfNeeded); + Dispatcher.UIThread.Post(RenderIfNeeded); } public override IMouseDevice MouseDevice { get; } = new MouseDevice(); diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs index fa3ecdedef..2e1c011685 100644 --- a/src/Avalonia.Controls/TreeView.cs +++ b/src/Avalonia.Controls/TreeView.cs @@ -250,7 +250,7 @@ namespace Avalonia.Controls if (AutoScrollToSelectedItem) { - Dispatcher.UIThread.InvokeAsync(container.ContainerControl.BringIntoView); + Dispatcher.UIThread.Post(container.ContainerControl.BringIntoView); } break; diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index 535dfd700b..3c7ef86d5d 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -49,7 +49,7 @@ namespace Avalonia.DesignerSupport.Remote // In previewer mode we completely ignore client-side viewport size if (obj is ClientViewportAllocatedMessage alloc) { - Dispatcher.UIThread.InvokeAsync(() => SetDpi(new Vector(alloc.DpiX, alloc.DpiY))); + Dispatcher.UIThread.Post(() => SetDpi(new Vector(alloc.DpiX, alloc.DpiY))); return; } base.OnMessage(transport, obj); diff --git a/src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs b/src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs index ac3438d71c..51cf1d4dde 100644 --- a/src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs +++ b/src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs @@ -140,7 +140,7 @@ namespace Avalonia.DesignerSupport.Remote }; } - private static void OnTransportMessage(IAvaloniaRemoteTransportConnection transport, object obj) => Dispatcher.UIThread.InvokeAsync(() => + private static void OnTransportMessage(IAvaloniaRemoteTransportConnection transport, object obj) => Dispatcher.UIThread.Post(() => { if (obj is ClientSupportedPixelFormatsMessage formats) { diff --git a/src/Avalonia.Layout/LayoutManager.cs b/src/Avalonia.Layout/LayoutManager.cs index f8911dc036..b6b786a077 100644 --- a/src/Avalonia.Layout/LayoutManager.cs +++ b/src/Avalonia.Layout/LayoutManager.cs @@ -203,7 +203,7 @@ namespace Avalonia.Layout { if (!_queued && !_running) { - Dispatcher.UIThread.InvokeAsync(ExecuteLayoutPass, DispatcherPriority.Layout); + Dispatcher.UIThread.Post(ExecuteLayoutPass, DispatcherPriority.Layout); _queued = true; } } diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index 041d8f8f6b..82cc0a260d 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -415,7 +415,7 @@ namespace Avalonia.Rendering if (!_updateQueued && (_dirty == null || _dirty.Count > 0)) { _updateQueued = true; - _dispatcher.InvokeAsync(UpdateScene, DispatcherPriority.Render); + _dispatcher.Post(UpdateScene, DispatcherPriority.Render); } Scene scene = null; diff --git a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs index 84313f0906..e830d5c313 100644 --- a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs @@ -169,7 +169,7 @@ namespace Avalonia.Rendering { foreach (var e in visual.GetSelfAndVisualDescendants()) { - BoundsTracker.SetTransformedBounds((Visual)visual, null); + visual.TransformedBounds = null; } } @@ -197,7 +197,7 @@ namespace Avalonia.Rendering if (filter?.Invoke(visual) != false) { - bool containsPoint = BoundsTracker.GetTransformedBounds((Visual)visual)?.Contains(p) == true; + bool containsPoint = visual.TransformedBounds?.Contains(p) == true; if ((containsPoint || !visual.ClipToBounds) && visual.VisualChildren.Count > 0) { @@ -257,10 +257,7 @@ namespace Avalonia.Rendering new TransformedBounds(bounds, new Rect(), context.CurrentContainerTransform); #pragma warning restore 0618 - if (visual is Visual) - { - BoundsTracker.SetTransformedBounds((Visual)visual, transformed); - } + visual.TransformedBounds = transformed; foreach (var child in visual.VisualChildren.OrderBy(x => x, ZIndexComparer.Instance)) { diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs index 8f4f487e08..41ff802164 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs @@ -209,11 +209,8 @@ namespace Avalonia.Rendering.SceneGraph } catch { } - if (visual is Visual) - { - var transformed = new TransformedBounds(new Rect(visual.Bounds.Size), clip, node.Transform); - BoundsTracker.SetTransformedBounds((Visual)visual, transformed); - } + var transformed = new TransformedBounds(new Rect(visual.Bounds.Size), clip, node.Transform); + visual.TransformedBounds = transformed; if (forceRecurse) { @@ -279,10 +276,7 @@ namespace Avalonia.Rendering.SceneGraph scene.Layers[node.LayerRoot].Dirty.Add(node.Bounds); - if (node.Visual is Visual v) - { - BoundsTracker.SetTransformedBounds(v, null); - } + node.Visual.TransformedBounds = null; foreach (VisualNode child in node.Children) { diff --git a/src/Avalonia.Visuals/Visual.cs b/src/Avalonia.Visuals/Visual.cs index 3662fe50be..5f3861a51a 100644 --- a/src/Avalonia.Visuals/Visual.cs +++ b/src/Avalonia.Visuals/Visual.cs @@ -32,6 +32,11 @@ namespace Avalonia public static readonly DirectProperty BoundsProperty = AvaloniaProperty.RegisterDirect(nameof(Bounds), o => o.Bounds); + public static readonly DirectProperty TransformedBoundsProperty = + AvaloniaProperty.RegisterDirect( + nameof(TransformedBounds), + o => o.TransformedBounds); + /// /// Defines the property. /// @@ -87,6 +92,7 @@ namespace Avalonia AvaloniaProperty.Register(nameof(ZIndex)); private Rect _bounds; + private TransformedBounds? _transformedBounds; private IRenderRoot _visualRoot; private IVisual _visualParent; @@ -135,6 +141,11 @@ namespace Avalonia protected set { SetAndRaise(BoundsProperty, ref _bounds, value); } } + /// + /// Gets the bounds of the control relative to the window, accounting for rendering transforms. + /// + public TransformedBounds? TransformedBounds => _transformedBounds; + /// /// Gets a value indicating whether the control should be clipped to its bounds. /// @@ -253,6 +264,12 @@ namespace Avalonia /// Gets the root of the visual tree, if the control is attached to a visual tree. /// IRenderRoot IVisual.VisualRoot => VisualRoot; + + TransformedBounds? IVisual.TransformedBounds + { + get { return _transformedBounds; } + set { SetAndRaise(TransformedBoundsProperty, ref _transformedBounds, value); } + } /// /// Invalidates the visual and queues a repaint. diff --git a/src/Avalonia.Visuals/VisualTree/BoundsTracker.cs b/src/Avalonia.Visuals/VisualTree/BoundsTracker.cs deleted file mode 100644 index 42c4e3c98e..0000000000 --- a/src/Avalonia.Visuals/VisualTree/BoundsTracker.cs +++ /dev/null @@ -1,51 +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. - -using System; - -namespace Avalonia.VisualTree -{ - /// - /// Tracks the bounds of a control. - /// - /// - /// This class is used to track a controls's bounds for hit testing. - /// TODO: This shouldn't be implemented as an attached property: it would be more performant - /// to just store bounds in some sort of central repository. - /// - public class BoundsTracker - { - /// - /// Defines the TransformedBounds attached property. - /// - private static AttachedProperty TransformedBoundsProperty = - AvaloniaProperty.RegisterAttached("TransformedBounds"); - - /// - /// Starts tracking the specified visual. - /// - /// The visual. - /// An observable that returns the tracked bounds. - public IObservable Track(Visual visual) - { - return visual.GetObservable(TransformedBoundsProperty); - } - - /// - /// Sets the transformed bounds of the visual. - /// - /// The visual. - /// The transformed bounds. - internal static void SetTransformedBounds(Visual visual, TransformedBounds? value) - { - visual.SetValue(TransformedBoundsProperty, value); - } - - /// - /// Gets the transformed bounds of the visual. - /// - /// The visual. - /// The transformed bounds or null if the visual is not visible. - public static TransformedBounds? GetTransformedBounds(Visual visual) => visual.GetValue(TransformedBoundsProperty); - } -} diff --git a/src/Avalonia.Visuals/VisualTree/IVisual.cs b/src/Avalonia.Visuals/VisualTree/IVisual.cs index 2047996c3e..278a802597 100644 --- a/src/Avalonia.Visuals/VisualTree/IVisual.cs +++ b/src/Avalonia.Visuals/VisualTree/IVisual.cs @@ -36,6 +36,11 @@ namespace Avalonia.VisualTree /// Rect Bounds { get; } + /// + /// Gets the bounds of the control relative to the window, accounting for rendering transforms. + /// + TransformedBounds? TransformedBounds { get; set; } + /// /// Gets a value indicating whether the control should be clipped to its bounds. /// diff --git a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs index 136023c31d..c41a136bce 100644 --- a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs +++ b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs @@ -351,7 +351,7 @@ namespace Avalonia.Gtk3 void OnInput(RawInputEventArgs args) { - Dispatcher.UIThread.InvokeAsync(() => Input?.Invoke(args), DispatcherPriority.Input); + Dispatcher.UIThread.Post(() => Input?.Invoke(args), DispatcherPriority.Input); } public Point PointToClient(Point point) diff --git a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs index daff4dd751..0db622ba13 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs @@ -41,7 +41,7 @@ namespace Avalonia.LinuxFramebuffer if(_renderQueued) return; _renderQueued = true; - Dispatcher.UIThread.InvokeAsync(() => + Dispatcher.UIThread.Post(() => { Paint?.Invoke(new Rect(default(Point), ClientSize)); _renderQueued = false; diff --git a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs index e733beae27..896c91d087 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs @@ -62,7 +62,7 @@ public static class LinuxFramebufferPlatformExtensions public TokenClosable(CancellationToken token) { - token.Register(() => Dispatcher.UIThread.InvokeAsync(() => Closed?.Invoke(this, new EventArgs()))); + token.Register(() => Dispatcher.UIThread.Post(() => Closed?.Invoke(this, new EventArgs()))); } } diff --git a/src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs b/src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs index 3f6f15ed5b..90eabc69fb 100644 --- a/src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs +++ b/src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs @@ -104,7 +104,7 @@ namespace Avalonia.Markup.Data.Plugins protected override void SubscribeCore(IObserver observer) { - _subscription = Instance.GetWeakObservable(_property).Subscribe(observer); + _subscription = Instance?.GetWeakObservable(_property).Subscribe(observer); } } } diff --git a/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs b/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs index 5ea7972871..667ee12fa0 100644 --- a/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs +++ b/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs @@ -107,7 +107,7 @@ namespace Avalonia.MonoMac if (_nonUiRedrawQueued) return; _nonUiRedrawQueued = true; - Dispatcher.UIThread.InvokeAsync( + Dispatcher.UIThread.Post( () => { lock (SyncRoot) diff --git a/tests/Avalonia.RenderTests/Avalonia.Direct2D1.RenderTests.csproj b/tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj similarity index 69% rename from tests/Avalonia.RenderTests/Avalonia.Direct2D1.RenderTests.csproj rename to tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj index 6af8fd8963..42d99cc19a 100644 --- a/tests/Avalonia.RenderTests/Avalonia.Direct2D1.RenderTests.csproj +++ b/tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj @@ -1,19 +1,9 @@ - - - obj-Direct2D1 - - + netcoreapp2.0 - bin\Direct2D\$(Configuration) - false - False - $(DefineConstants);AVALONIA_DIRECT2D - Library - - + @@ -33,7 +23,5 @@ - - \ No newline at end of file diff --git a/tests/Avalonia.Direct2D1.UnitTests/Properties/AssemblyInfo.cs b/tests/Avalonia.Direct2D1.UnitTests/Properties/AssemblyInfo.cs index a8edd50b31..a462e5b079 100644 --- a/tests/Avalonia.Direct2D1.UnitTests/Properties/AssemblyInfo.cs +++ b/tests/Avalonia.Direct2D1.UnitTests/Properties/AssemblyInfo.cs @@ -4,7 +4,5 @@ using System.Reflection; using Xunit; -[assembly: AssemblyTitle("Avalonia.Direct2D1.UnitTests")] - // Don't run tests in parallel. [assembly: CollectionBehavior(DisableTestParallelization = true)] \ No newline at end of file diff --git a/tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Observable.cs b/tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Observable.cs index 62d5c28f49..aa78c100c1 100644 --- a/tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Observable.cs +++ b/tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Observable.cs @@ -103,20 +103,22 @@ namespace Avalonia.Markup.UnitTests.Data { using (var sync = UnitTestSynchronizationContext.Begin()) { - var data = new Class1(); - var target = new ExpressionObserver(data, "Next^.Foo", true); + var data1 = new Class1(); + var data2 = new Class2("foo"); + var target = new ExpressionObserver(data1, "Next^.Foo", true); var result = new List(); var sub = target.Subscribe(x => result.Add(x)); - data.Next.OnNext(new Class2("foo")); + data1.Next.OnNext(data2); sync.ExecutePostedCallbacks(); Assert.Equal(new[] { new BindingNotification("foo") }, result); sub.Dispose(); - Assert.Equal(0, data.PropertyChangedSubscriptionCount); + Assert.Equal(0, data1.PropertyChangedSubscriptionCount); - GC.KeepAlive(data); + GC.KeepAlive(data1); + GC.KeepAlive(data2); } } diff --git a/tests/Avalonia.RenderTests/.gitignore b/tests/Avalonia.RenderTests/.gitignore deleted file mode 100644 index 76146e97c7..0000000000 --- a/tests/Avalonia.RenderTests/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -obj-Skia/ -obj-Skia/* \ No newline at end of file diff --git a/tests/Avalonia.RenderTests/Avalonia.RenderTests.projitems b/tests/Avalonia.RenderTests/Avalonia.RenderTests.projitems deleted file mode 100644 index ff729a6b48..0000000000 --- a/tests/Avalonia.RenderTests/Avalonia.RenderTests.projitems +++ /dev/null @@ -1,33 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - 48840edd-24bf-495d-911e-2eb12ae75d3b - - - Avalonia.RenderTests - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tests/Avalonia.RenderTests/Avalonia.RenderTests.shproj b/tests/Avalonia.RenderTests/Avalonia.RenderTests.shproj deleted file mode 100644 index e3bed80491..0000000000 --- a/tests/Avalonia.RenderTests/Avalonia.RenderTests.shproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - 48840edd-24bf-495d-911e-2eb12ae75d3b - 14.0 - - - - - - - - - - - \ No newline at end of file diff --git a/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs b/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs index a5d06a1b0e..80b850635d 100644 --- a/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs +++ b/tests/Avalonia.RenderTests/Controls/TextBlockTests.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.Threading.Tasks; using Avalonia.Controls; using Avalonia.Layout; using Avalonia.Media; @@ -20,7 +21,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls } [Fact] - public void Wrapping_NoWrap() + public async Task Wrapping_NoWrap() { Decorator target = new Decorator { @@ -38,7 +39,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls } }; - RenderToFile(target); + await RenderToFile(target); CompareImages(); } } diff --git a/tests/Avalonia.RenderTests/Properties/AssemblyInfo.cs b/tests/Avalonia.RenderTests/Properties/AssemblyInfo.cs index d5ba64ac05..a462e5b079 100644 --- a/tests/Avalonia.RenderTests/Properties/AssemblyInfo.cs +++ b/tests/Avalonia.RenderTests/Properties/AssemblyInfo.cs @@ -4,7 +4,5 @@ using System.Reflection; using Xunit; -[assembly: AssemblyTitle("Avalonia.Direct2D1.RenderTests")] - // Don't run tests in parallel. [assembly: CollectionBehavior(DisableTestParallelization = true)] \ No newline at end of file diff --git a/tests/Avalonia.RenderTests/TestBase.cs b/tests/Avalonia.RenderTests/TestBase.cs index cf38ef3818..321dbc4fbe 100644 --- a/tests/Avalonia.RenderTests/TestBase.cs +++ b/tests/Avalonia.RenderTests/TestBase.cs @@ -46,7 +46,8 @@ namespace Avalonia.Direct2D1.RenderTests public TestBase(string outputPath) { - var testFiles = Path.GetFullPath(@"..\..\..\..\..\TestFiles\"); + var testPath = GetTestsDirectory(); + var testFiles = Path.Combine(testPath, "TestFiles"); #if AVALONIA_SKIA var platform = "Skia"; #else @@ -142,6 +143,18 @@ namespace Avalonia.Direct2D1.RenderTests } } + private string GetTestsDirectory() + { + var path = Directory.GetCurrentDirectory(); + + while (path.Length > 0 && Path.GetFileName(path) != "tests") + { + path = Path.GetDirectoryName(path); + } + + return path; + } + private class TestThreadingInterface : IPlatformThreadingInterface { public bool CurrentThreadIsLoopThread => MainThread.ManagedThreadId == Thread.CurrentThread.ManagedThreadId; diff --git a/tests/Avalonia.RenderTests/Avalonia.Skia.RenderTests.csproj b/tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj similarity index 69% rename from tests/Avalonia.RenderTests/Avalonia.Skia.RenderTests.csproj rename to tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj index 370cfac6dd..4a297a340d 100644 --- a/tests/Avalonia.RenderTests/Avalonia.Skia.RenderTests.csproj +++ b/tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj @@ -1,21 +1,10 @@ - - - obj-Skia - - - - + netcoreapp2.0 - bin\Skia\$(Configuration) - false - False - $(DefineConstants);AVALONIA_SKIA;AVALONIA_SKIA_SKIP_FAIL - Library + AVALONIA_SKIA;AVALONIA_SKIA_SKIP_FAIL - - + @@ -35,9 +24,6 @@ - - - \ No newline at end of file diff --git a/tests/Avalonia.UnitTests/ImmediateDispatcher.cs b/tests/Avalonia.UnitTests/ImmediateDispatcher.cs index 4019e65bdf..92f64bde6f 100644 --- a/tests/Avalonia.UnitTests/ImmediateDispatcher.cs +++ b/tests/Avalonia.UnitTests/ImmediateDispatcher.cs @@ -14,12 +14,12 @@ namespace Avalonia.UnitTests return true; } - public void InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal) + public void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal) { action(); } - public Task InvokeTaskAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal) + public Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal) { action(); return Task.FromResult(null); diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs index c97070a2aa..8fcb54775b 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs @@ -24,13 +24,13 @@ namespace Avalonia.Visuals.UnitTests.Rendering var root = new TestRoot(); var dispatcher = new Mock(); - dispatcher.Setup(x => x.InvokeAsync(It.IsAny(), DispatcherPriority.Render)) + dispatcher.Setup(x => x.Post(It.IsAny(), DispatcherPriority.Render)) .Callback((a, p) => a()); CreateTargetAndRunFrame(root, dispatcher: dispatcher.Object); dispatcher.Verify(x => - x.InvokeAsync( + x.Post( It.Is(a => a.Method.Name == "UpdateScene"), DispatcherPriority.Render)); } diff --git a/tests/Avalonia.Visuals.UnitTests/VisualTree/BoundsTrackerTests.cs b/tests/Avalonia.Visuals.UnitTests/VisualTree/TransformedBoundsTests.cs similarity index 92% rename from tests/Avalonia.Visuals.UnitTests/VisualTree/BoundsTrackerTests.cs rename to tests/Avalonia.Visuals.UnitTests/VisualTree/TransformedBoundsTests.cs index ea3a1cdd78..7bc0b72bef 100644 --- a/tests/Avalonia.Visuals.UnitTests/VisualTree/BoundsTrackerTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/VisualTree/TransformedBoundsTests.cs @@ -17,14 +17,13 @@ using Avalonia.Platform; namespace Avalonia.Visuals.UnitTests.VisualTree { - public class BoundsTrackerTests + public class TransformedBoundsTests { [Fact] public void Should_Track_Bounds() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { - var target = new BoundsTracker(); var control = default(Rectangle); var tree = new Decorator { @@ -46,7 +45,7 @@ namespace Avalonia.Visuals.UnitTests.VisualTree tree.Arrange(new Rect(0, 0, 100, 100)); ImmediateRenderer.Render(tree, context); - var track = target.Track(control); + var track = control.GetObservable(Visual.TransformedBoundsProperty); var results = new List(); track.Subscribe(results.Add); diff --git a/tests/TestFiles/Cairo/SVGPath/SVGPath.expected.png b/tests/TestFiles/Cairo/SVGPath/SVGPath.expected.png deleted file mode 100644 index 9830048810..0000000000 Binary files a/tests/TestFiles/Cairo/SVGPath/SVGPath.expected.png and /dev/null differ diff --git a/tests/TestFiles/Skia/Controls/TextBlock/Wrapping_NoWrap.expected.png b/tests/TestFiles/Skia/Controls/TextBlock/Wrapping_NoWrap.expected.png new file mode 100644 index 0000000000..2296e02d68 Binary files /dev/null and b/tests/TestFiles/Skia/Controls/TextBlock/Wrapping_NoWrap.expected.png differ diff --git a/tools/packages.config b/tools/packages.config index e0dd39bd2b..e52a2c7e98 100644 --- a/tools/packages.config +++ b/tools/packages.config @@ -1,4 +1,4 @@ - +