From 0c80f885b764869c6a544f148efb3503d50d9218 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Mon, 19 Jul 2021 12:56:17 +0200 Subject: [PATCH 1/3] Implement indexed sort for visual children. --- .../Rendering/SceneGraph/SceneBuilder.cs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs index f2a09b815e..43246c8e9d 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Avalonia.Media; using Avalonia.Platform; using Avalonia.Threading; @@ -258,14 +259,25 @@ namespace Avalonia.Rendering.SceneGraph } else if (visualChildren.Count > 1) { - var sortedChildren = new IVisual[visualChildren.Count]; - visualChildren.CopyTo(sortedChildren, 0); + var count = visualChildren.Count; + var sortedChildren = new (IVisual visual, int index)[count]; - Array.Sort(sortedChildren, ZIndexComparer.ComparisonInstance); + for (var i = 0; i < count; i++) + { + sortedChildren[i] = (visualChildren[i], i); + } + + // Regular Array.Sort is unstable, we need to provide indices as well to avoid reshuffling elements. + Array.Sort(sortedChildren, (lhs, rhs) => + { + var result = ZIndexComparer.Instance.Compare(lhs.visual, rhs.visual); + + return result == 0 ? lhs.index.CompareTo(rhs.index) : result; + }); foreach (var child in sortedChildren) { - var childNode = GetOrCreateChildNode(scene, child, node); + var childNode = GetOrCreateChildNode(scene, child.Item1, node); Update(context, scene, (VisualNode)childNode, clip, forceRecurse); } } From c598b3883adb6f6908173ff18ca83465335955e3 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Mon, 19 Jul 2021 13:12:28 +0200 Subject: [PATCH 2/3] Add unit test that verifies ordering. --- .../Rendering/SceneGraph/SceneBuilderTests.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs index 42e573c8a5..e317b43efc 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs @@ -245,6 +245,34 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph } } + [Fact] + public void Should_Respect_Uniform_ZIndex() + { + using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) + { + Panel panel; + + var tree = new TestRoot + { + Child = panel = new Panel() + }; + + for (var i = 0; i < 128; i++) + { + panel.Children.Add(new Border()); + } + + var result = new Scene(tree); + var sceneBuilder = new SceneBuilder(); + sceneBuilder.UpdateAll(result); + + var panelNode = result.FindNode(tree.Child); + var expected = panel.Children.ToArray(); + var actual = panelNode.Children.OfType().Select(x => x.Visual).ToArray(); + Assert.Equal(expected, actual); + } + } + [Fact] public void ClipBounds_Should_Be_In_Global_Coordinates() { From 13a244fed53c36c091cb87d9fd1478dc8603d32c Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Mon, 19 Jul 2021 13:14:17 +0200 Subject: [PATCH 3/3] Remove usage. --- src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs index 43246c8e9d..c6cdf474bb 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Avalonia.Media; using Avalonia.Platform; using Avalonia.Threading;