Skip to content

Commit 4b998b1

Browse files
authored
Merge branch 'master' into feature/renderOptionsRequiresFullOpacityHandling
2 parents c582880 + c59e63e commit 4b998b1

File tree

6 files changed

+106
-6
lines changed

6 files changed

+106
-6
lines changed

src/Avalonia.Base/Rendering/Composition/ICompositionTargetDebugEvents.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@ namespace Avalonia.Rendering.Composition;
22

33
internal interface ICompositionTargetDebugEvents
44
{
5+
int RenderedVisuals { get; }
6+
void IncrementRenderedVisuals();
57
void RectInvalidated(Rect rc);
68
}

src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.DirtyProperties.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ private const CompositionVisualChangedFields CompositionFieldsMask
3838
CompositionVisualChangedFields.Size
3939
| CompositionVisualChangedFields.SizeAnimated
4040
| CompositionVisualChangedFields.ClipToBounds
41+
| CompositionVisualChangedFields.Clip
4142
| CompositionVisualChangedFields.ClipToBoundsAnimated;
4243

4344
partial void OnFieldsDeserialized(CompositionVisualChangedFields changed)

src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public void Render(CompositorDrawingContextProxy canvas, Rect currentTransformed
3838
return;
3939

4040
Root!.RenderedVisuals++;
41+
Root!.DebugEvents?.IncrementRenderedVisuals();
4142

4243
var boundsRect = new Rect(new Size(Size.X, Size.Y));
4344

@@ -182,11 +183,24 @@ public virtual UpdateResult Update(ServerCompositionTarget root)
182183

183184
if (_clipSizeDirty || positionChanged)
184185
{
185-
_transformedClipBounds = ClipToBounds
186-
? new Rect(new Size(Size.X, Size.Y))
187-
.TransformToAABB(GlobalTransformMatrix)
188-
: null;
186+
Rect? transformedVisualBounds = null;
187+
Rect? transformedClipBounds = null;
189188

189+
if (ClipToBounds)
190+
transformedVisualBounds = new Rect(new Size(Size.X, Size.Y)).TransformToAABB(GlobalTransformMatrix);
191+
192+
if (Clip != null)
193+
transformedClipBounds = Clip.Bounds.TransformToAABB(GlobalTransformMatrix);
194+
195+
if (transformedVisualBounds != null && transformedClipBounds != null)
196+
_transformedClipBounds = transformedVisualBounds.Value.Intersect(transformedClipBounds.Value);
197+
else if (transformedVisualBounds != null)
198+
_transformedClipBounds = transformedVisualBounds;
199+
else if (transformedClipBounds != null)
200+
_transformedClipBounds = transformedClipBounds;
201+
else
202+
_transformedClipBounds = null;
203+
190204
_clipSizeDirty = false;
191205
}
192206

src/Avalonia.Controls/Primitives/Track.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ static Track()
5252
ThumbProperty.Changed.AddClassHandler<Track>((x, e) => x.ThumbChanged(e));
5353
IncreaseButtonProperty.Changed.AddClassHandler<Track>((x, e) => x.ButtonChanged(e));
5454
DecreaseButtonProperty.Changed.AddClassHandler<Track>((x, e) => x.ButtonChanged(e));
55-
AffectsArrange<Track>(MinimumProperty, MaximumProperty, ValueProperty, OrientationProperty);
55+
AffectsArrange<Track>(IsDirectionReversedProperty, MinimumProperty, MaximumProperty, ValueProperty, OrientationProperty);
5656
}
5757

5858
public Track()
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using Avalonia.Controls;
2+
using Avalonia.Media;
3+
using Xunit;
4+
5+
namespace Avalonia.Base.UnitTests.Rendering;
6+
/// <summary>
7+
/// Test class that verifies how clipping influences rendering in the compositor
8+
/// </summary>
9+
public class CompositorInvalidationClippingTests : CompositorTestsBase
10+
{
11+
[Fact]
12+
// Test case: When the ClipToBounds is false, all visuals should be rendered
13+
public void Siblings_Should_Be_Rendered_On_Invalidate_Without_ClipToBounds()
14+
{
15+
AssertRenderedVisuals(clipToBounds: false, clipGeometry: false, expectedRenderedVisualsCount: 4);
16+
}
17+
18+
[Fact]
19+
// Test case: When the ClipToBounds is true, only visuals within the clipped boundary should be rendered
20+
public void Siblings_Should_Not_Be_Rendered_On_Invalidate_With_ClipToBounds()
21+
{
22+
AssertRenderedVisuals(clipToBounds: true, clipGeometry: false, expectedRenderedVisualsCount: 3);
23+
}
24+
25+
[Fact]
26+
// Test case: When the Clip is used, only visuals within the clip geometry should be rendered
27+
public void Siblings_Should_Not_Be_Rendered_On_Invalidate_With_Clip()
28+
{
29+
AssertRenderedVisuals(clipToBounds: false, clipGeometry: true, expectedRenderedVisualsCount: 3);
30+
}
31+
32+
private void AssertRenderedVisuals(bool clipToBounds, bool clipGeometry, int expectedRenderedVisualsCount)
33+
{
34+
using (var s = new CompositorCanvas())
35+
{
36+
//#1 visual is top level
37+
//#2 visual is s.Canvas
38+
39+
//#3 visual is border1
40+
s.Canvas.Children.Add(new Border()
41+
{
42+
[Canvas.LeftProperty] = 0, [Canvas.TopProperty] = 0,
43+
Width = 20, Height = 10,
44+
Background = Brushes.Red,
45+
ClipToBounds = clipToBounds,
46+
Clip = clipGeometry ? new RectangleGeometry(new Rect(new Size(20, 10))) : null
47+
});
48+
49+
//#4 visual is border2
50+
s.Canvas.Children.Add(new Border()
51+
{
52+
[Canvas.LeftProperty] = 30, [Canvas.TopProperty] = 50,
53+
Width = 20, Height = 10,
54+
Background = Brushes.Red,
55+
ClipToBounds = clipToBounds,
56+
Clip = clipGeometry ? new RectangleGeometry(new Rect(new Size(20, 10))) : null
57+
});
58+
s.RunJobs();
59+
s.Events.Reset();
60+
61+
//invalidate border1
62+
s.Canvas.Children[0].IsVisible = false;
63+
s.RunJobs();
64+
65+
s.AssertRenderedVisuals(expectedRenderedVisualsCount);
66+
}
67+
}
68+
}

tests/Avalonia.UnitTests/CompositorTestServices.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,13 @@ public void AssertRects(params Rect[] rects)
8989
Events.Rects.Clear();
9090
}
9191

92+
public void AssertRenderedVisuals(int renderVisuals)
93+
{
94+
RunJobs();
95+
Assert.Equal(Events.RenderedVisuals, renderVisuals);
96+
Events.Rects.Clear();
97+
}
98+
9299
public void AssertHitTest(double x, double y, Func<Visual, bool> filter, params object[] expected)
93100
=> AssertHitTest(new Point(x, y), filter, expected);
94101

@@ -110,6 +117,13 @@ public class DebugEvents : ICompositionTargetDebugEvents
110117
{
111118
public List<Rect> Rects = new();
112119

120+
public int RenderedVisuals { get; private set; }
121+
122+
public void IncrementRenderedVisuals()
123+
{
124+
RenderedVisuals++;
125+
}
126+
113127
public void RectInvalidated(Rect rc)
114128
{
115129
Rects.Add(rc);
@@ -118,6 +132,7 @@ public void RectInvalidated(Rect rc)
118132
public void Reset()
119133
{
120134
Rects.Clear();
135+
RenderedVisuals = 0;
121136
}
122137
}
123138

@@ -218,4 +233,4 @@ public void CommitRequested(Compositor compositor)
218233
{
219234
Dispatcher.UIThread.Post(() => compositor.Commit(), DispatcherPriority.UiThreadRender);
220235
}
221-
}
236+
}

0 commit comments

Comments
 (0)