From 11564814b32a844145ed1450b5ea42e53889bf3a Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 13 Jul 2026 20:41:00 +0500 Subject: [PATCH] Fixed copypasta-induced bug with custom-hit-test housekeeping (#21769) --- .../Rendering/Composition/Visual.cs | 2 +- .../Rendering/CompositorHitTestingTests.cs | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Rendering/Composition/Visual.cs b/src/Avalonia.Base/Rendering/Composition/Visual.cs index e4b469d327..6134d48220 100644 --- a/src/Avalonia.Base/Rendering/Composition/Visual.cs +++ b/src/Avalonia.Base/Rendering/Composition/Visual.cs @@ -45,7 +45,7 @@ namespace Avalonia.Rendering.Composition var parent = Parent; while (parent != null) { - parent.CustomHitTestCountInSubTree -= CustomHitTestCountInSubTree; + parent.CustomHitTestCountInSubTree += CustomHitTestCountInSubTree; parent = parent.Parent; } } diff --git a/tests/Avalonia.Base.UnitTests/Rendering/CompositorHitTestingTests.cs b/tests/Avalonia.Base.UnitTests/Rendering/CompositorHitTestingTests.cs index 6fe481a517..9dbb446bdc 100644 --- a/tests/Avalonia.Base.UnitTests/Rendering/CompositorHitTestingTests.cs +++ b/tests/Avalonia.Base.UnitTests/Rendering/CompositorHitTestingTests.cs @@ -444,6 +444,42 @@ public class CompositorHitTestingTests : CompositorTestsBase } } + [Fact] + public void Removing_ICustomHitTest_Child_Should_Restore_SubTree_Bounds_Optimization() + { + using (var s = new CompositorTestServices(new Size(200, 200))) + { + var custom = new CustomHitTestBorder + { + Width = 100, + Height = 100, + Background = Brushes.Red + }; + var container = new Panel + { + Width = 200, + Height = 200, + Children = { custom } + }; + + s.TopLevel.Content = container; + s.RunJobs(); + + var containerVisual = ElementComposition.GetElementVisual(container); + Assert.NotNull(containerVisual); + + // While the subtree contains an ICustomHitTest visual, the bounds-based optimization must be disabled. + Assert.True(containerVisual!.DisableSubTreeBoundsHitTestOptimization); + + container.Children.Remove(custom); + s.RunJobs(); + + // Once the custom hit test visual leaves the subtree, the accounting must return to zero and re-enable + // the optimization. A sign bug when attaching to a new parent leaves the count stuck at a non-zero value. + Assert.False(containerVisual.DisableSubTreeBoundsHitTestOptimization); + } + } + [Fact] public void HitTest_Should_Not_Hit_Controls_Next_Pixel() {