diff --git a/src/Avalonia.Base/Rendering/Composition/Compositor.cs b/src/Avalonia.Base/Rendering/Composition/Compositor.cs index 8504201bd0f..4190991b259 100644 --- a/src/Avalonia.Base/Rendering/Composition/Compositor.cs +++ b/src/Avalonia.Base/Rendering/Composition/Compositor.cs @@ -294,7 +294,7 @@ public async Task CreateCompositionVisualSnapshot(CompositionVisual visu throw new InvalidOperationException(); if (visual.Root == null) throw new InvalidOperationException(); - var impl = await InvokeServerJobAsync(() => _server.CreateCompositionVisualSnapshot(visual.Server, scaling), true); + var impl = await InvokeServerJobAsync(() => _server.CreateCompositionVisualSnapshot(visual.Server, scaling, true), true); return new Bitmap(RefCountable.Create(impl)); } diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs index 69d317fff15..4f300503b2f 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs @@ -20,9 +20,12 @@ protected override void RenderCore(ServerVisualRenderContext context, LtrbRect c { base.RenderCore(context, currentTransformedClip); - foreach (var ch in Children) + if (context.RenderChildren) { - ch.Render(context, currentTransformedClip); + foreach (var ch in Children) + { + ch.Render(context, currentTransformedClip); + } } } diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs index 8afdb6a2cc1..e5b5e0e6c26 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs @@ -215,7 +215,7 @@ void RenderRootToContextWithClip(IDrawingContextImpl context, ServerCompositionV using (var proxy = new CompositorDrawingContextProxy(context)) { - var ctx = new ServerVisualRenderContext(proxy, DirtyRects, false); + var ctx = new ServerVisualRenderContext(proxy, DirtyRects, false, true); root.Render(ctx, null); } diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs index 7d203a7c478..cb4da6723ff 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs @@ -49,7 +49,7 @@ public IReadOnlyDictionary RT_GetRenderInterfaceFeatures() } public IBitmapImpl CreateCompositionVisualSnapshot(ServerCompositionVisual visual, - double scaling) + double scaling, bool renderChildren) { using (RenderInterface.EnsureCurrent()) { @@ -69,11 +69,12 @@ public IBitmapImpl CreateCompositionVisualSnapshot(ServerCompositionVisual visua PostTransform = invertRootTransform * scaleTransform, Transform = Matrix.Identity }; - var ctx = new ServerVisualRenderContext(proxy, null, true); + var ctx = new ServerVisualRenderContext(proxy, null, true, renderChildren); visual.Render(ctx, null); } - if (target is IDrawingContextLayerWithRenderContextAffinityImpl affined) + if (target is IDrawingContextLayerWithRenderContextAffinityImpl affined + && affined.HasRenderContextAffinity) return affined.CreateNonAffinedSnapshot(); // We are returning the original target, so prevent it from being disposed @@ -87,4 +88,4 @@ public IBitmapImpl CreateCompositionVisualSnapshot(ServerCompositionVisual visua } } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerVisualRenderContext.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerVisualRenderContext.cs index 0778a7a6213..4ee22d3bff2 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerVisualRenderContext.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerVisualRenderContext.cs @@ -8,15 +8,17 @@ internal class ServerVisualRenderContext { public IDirtyRectTracker? DirtyRects { get; } public bool DetachedRendering { get; } + public bool RenderChildren { get; } public CompositorDrawingContextProxy Canvas { get; } private readonly Stack? _transformStack; public ServerVisualRenderContext(CompositorDrawingContextProxy canvas, IDirtyRectTracker? dirtyRects, - bool detachedRendering) + bool detachedRendering, bool renderChildren) { Canvas = canvas; DirtyRects = dirtyRects; DetachedRendering = detachedRendering; + RenderChildren = renderChildren; if (detachedRendering) { _transformStack = new(); @@ -72,4 +74,4 @@ public void Dispose() } } -} \ No newline at end of file +} diff --git a/tests/Avalonia.Headless.UnitTests/RenderingTests.cs b/tests/Avalonia.Headless.UnitTests/RenderingTests.cs index 119b17cf2f1..74afb158658 100644 --- a/tests/Avalonia.Headless.UnitTests/RenderingTests.cs +++ b/tests/Avalonia.Headless.UnitTests/RenderingTests.cs @@ -1,8 +1,10 @@ using System.Collections.ObjectModel; +using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Controls.Shapes; using Avalonia.Layout; using Avalonia.Media; +using Avalonia.Rendering.Composition; using Avalonia.Threading; namespace Avalonia.Headless.UnitTests; @@ -37,7 +39,7 @@ public void Should_Render_Last_Frame_To_Bitmap() Assert.NotNull(frame); } - + #if NUNIT [AvaloniaTest, Timeout(10000)] #elif XUNIT @@ -136,4 +138,36 @@ public void Should_Not_Hang_With_Non_Trivial_Layout() var frame = window.CaptureRenderedFrame(); Assert.NotNull(frame); } + +#if NUNIT + [AvaloniaTest, Timeout(10000)] +#elif XUNIT + [AvaloniaFact(Timeout = 10000)] +#endif + public async Task Should_Render_To_A_Compositor_Snapshot_Capture() + { + var window = new Window + { + Content = new ContentControl + { + HorizontalAlignment = HorizontalAlignment.Stretch, + VerticalAlignment = VerticalAlignment.Stretch, + Width = 100, + Height = 100, + Background = Brushes.Green + }, + SizeToContent = SizeToContent.WidthAndHeight + }; + + window.Show(); + + var compositionVisual = ElementComposition.GetElementVisual(window)!; + var snapshot = await compositionVisual.Compositor.CreateCompositionVisualSnapshot(compositionVisual, 1); + + Assert.NotNull(snapshot); + // ReSharper disable CompareOfFloatsByEqualityOperator + Assert.True(100 == snapshot.Size.Width); + Assert.True(100 == snapshot.Size.Height); + // ReSharper restore CompareOfFloatsByEqualityOperator + } }