diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
index cba09297f3..2bc7121d73 100644
--- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
+++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
@@ -25,7 +25,6 @@ namespace Avalonia.Rendering
private readonly IRenderLoop _renderLoop;
private readonly IVisual _root;
private readonly ISceneBuilder _sceneBuilder;
- private readonly RenderLayers _layers;
private bool _running;
private Scene _scene;
@@ -56,7 +55,7 @@ namespace Avalonia.Rendering
_dispatcher = dispatcher ?? Dispatcher.UIThread;
_root = root;
_sceneBuilder = sceneBuilder ?? new SceneBuilder();
- _layers = new RenderLayers();
+ Layers = new RenderLayers();
_renderLoop = renderLoop;
}
@@ -80,7 +79,7 @@ namespace Avalonia.Rendering
_root = root;
_renderTarget = renderTarget;
_sceneBuilder = sceneBuilder ?? new SceneBuilder();
- _layers = new RenderLayers();
+ Layers = new RenderLayers();
}
///
@@ -94,6 +93,11 @@ namespace Avalonia.Rendering
///
public string DebugFramesPath { get; set; }
+ ///
+ /// Gets the render layers.
+ ///
+ internal RenderLayers Layers { get; }
+
///
public void AddDirty(IVisual visual)
{
@@ -192,7 +196,7 @@ namespace Avalonia.Rendering
if (scene.Generation != _lastSceneId)
{
context = _renderTarget.CreateDrawingContext(this);
- _layers.Update(scene, context);
+ Layers.Update(scene, context);
RenderToLayers(scene);
@@ -262,7 +266,7 @@ namespace Avalonia.Rendering
{
foreach (var layer in scene.Layers)
{
- var renderTarget = _layers[layer.LayerRoot].Bitmap;
+ var renderTarget = Layers[layer.LayerRoot].Bitmap;
var node = (VisualNode)scene.FindNode(layer.LayerRoot);
if (node != null)
@@ -322,7 +326,7 @@ namespace Avalonia.Rendering
foreach (var layer in scene.Layers)
{
- var bitmap = _layers[layer.LayerRoot].Bitmap;
+ var bitmap = Layers[layer.LayerRoot].Bitmap;
var sourceRect = new Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight);
if (layer.GeometryClip != null)
@@ -442,7 +446,7 @@ namespace Avalonia.Rendering
{
var index = 0;
- foreach (var layer in _layers)
+ foreach (var layer in Layers)
{
var fileName = Path.Combine(DebugFramesPath, $"frame-{id}-layer-{index++}.png");
layer.Bitmap.Save(fileName);
diff --git a/tests/Avalonia.UnitTests/TestRoot.cs b/tests/Avalonia.UnitTests/TestRoot.cs
index 9ec053f075..dc137e3533 100644
--- a/tests/Avalonia.UnitTests/TestRoot.cs
+++ b/tests/Avalonia.UnitTests/TestRoot.cs
@@ -16,8 +16,6 @@ namespace Avalonia.UnitTests
public class TestRoot : Decorator, IFocusScope, ILayoutRoot, IInputRoot, INameScope, IRenderRoot, IStyleRoot
{
private readonly NameScope _nameScope = new NameScope();
- private readonly IRenderTarget _renderTarget = Mock.Of(
- x => x.CreateDrawingContext(It.IsAny()) == Mock.Of());
public TestRoot()
{
@@ -65,7 +63,21 @@ namespace Avalonia.UnitTests
IStyleHost IStyleHost.StylingParent => StylingParent;
- public IRenderTarget CreateRenderTarget() => _renderTarget;
+ public IRenderTarget CreateRenderTarget()
+ {
+ var dc = new Mock();
+ dc.Setup(x => x.CreateLayer(It.IsAny())).Returns(() =>
+ {
+ var layerDc = new Mock();
+ var layer = new Mock();
+ layer.Setup(x => x.CreateDrawingContext(It.IsAny())).Returns(layerDc.Object);
+ return layer.Object;
+ });
+
+ var result = new Mock();
+ result.Setup(x => x.CreateDrawingContext(It.IsAny())).Returns(dc.Object);
+ return result.Object;
+ }
public void Invalidate(Rect rect)
{
diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs
index afe7b04664..e3b2577e79 100644
--- a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs
+++ b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs
@@ -21,28 +21,18 @@ namespace Avalonia.Visuals.UnitTests.Rendering
[Fact]
public void First_Frame_Calls_UpdateScene_On_Dispatcher()
{
- var loop = new Mock();
var root = new TestRoot();
var dispatcher = new Mock();
dispatcher.Setup(x => x.InvokeAsync(It.IsAny(), DispatcherPriority.Render))
.Callback((a, p) => a());
- var target = new DeferredRenderer(
- root,
- loop.Object,
- sceneBuilder: MockSceneBuilder(root).Object,
- dispatcher: dispatcher.Object);
+ CreateTargetAndRunFrame(root, dispatcher: dispatcher.Object);
- target.Start();
- RunFrame(loop);
-
-#if !NETCOREAPP1_1 // Delegate.Method is not available in netcoreapp1.1
dispatcher.Verify(x =>
x.InvokeAsync(
It.Is(a => a.Method.Name == "UpdateScene"),
DispatcherPriority.Render));
-#endif
}
[Fact]
@@ -51,15 +41,8 @@ namespace Avalonia.Visuals.UnitTests.Rendering
var loop = new Mock();
var root = new TestRoot();
var sceneBuilder = MockSceneBuilder(root);
- var dispatcher = new ImmediateDispatcher();
- var target = new DeferredRenderer(
- root,
- loop.Object,
- sceneBuilder: sceneBuilder.Object,
- dispatcher: dispatcher);
- target.Start();
- RunFrame(loop);
+ CreateTargetAndRunFrame(root, sceneBuilder: sceneBuilder.Object);
sceneBuilder.Verify(x => x.UpdateAll(It.IsAny()));
}
@@ -70,12 +53,10 @@ namespace Avalonia.Visuals.UnitTests.Rendering
var loop = new Mock();
var root = new TestRoot();
var sceneBuilder = MockSceneBuilder(root);
- var dispatcher = new ImmediateDispatcher();
var target = new DeferredRenderer(
root,
loop.Object,
- sceneBuilder: sceneBuilder.Object,
- dispatcher: dispatcher);
+ sceneBuilder: sceneBuilder.Object);
target.Start();
IgnoreFirstFrame(loop, sceneBuilder);
@@ -145,24 +126,8 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Measure(Size.Infinity);
root.Arrange(new Rect(root.DesiredSize));
- var rootLayer = CreateLayer();
- var borderLayer = CreateLayer();
- var renderTargetContext = Mock.Get(root.CreateRenderTarget().CreateDrawingContext(null));
- renderTargetContext.SetupSequence(x => x.CreateLayer(It.IsAny()))
- .Returns(rootLayer)
- .Returns(borderLayer);
-
- var loop = new Mock();
- var target = new DeferredRenderer(
- root,
- loop.Object,
- dispatcher: new ImmediateDispatcher());
- root.Renderer = target;
-
- target.Start();
- RunFrame(loop);
-
- var context = Mock.Get(rootLayer.CreateDrawingContext(null));
+ var target = CreateTargetAndRunFrame(root);
+ var context = GetLayerContext(target, root);
var animation = new BehaviorSubject(0.5);
context.Verify(x => x.PushOpacity(0.5), Times.Once);
@@ -191,24 +156,8 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Measure(Size.Infinity);
root.Arrange(new Rect(root.DesiredSize));
- var rootLayer = CreateLayer();
- var borderLayer = CreateLayer();
- var renderTargetContext = Mock.Get(root.CreateRenderTarget().CreateDrawingContext(null));
- renderTargetContext.SetupSequence(x => x.CreateLayer(It.IsAny()))
- .Returns(rootLayer)
- .Returns(borderLayer);
-
- var loop = new Mock();
- var target = new DeferredRenderer(
- root,
- loop.Object,
- dispatcher: new ImmediateDispatcher());
- root.Renderer = target;
-
- target.Start();
- RunFrame(loop);
-
- var context = Mock.Get(rootLayer.CreateDrawingContext(null));
+ var target = CreateTargetAndRunFrame(root);
+ var context = GetLayerContext(target, root);
var animation = new BehaviorSubject(0.5);
context.Verify(x => x.PushOpacity(0.5), Times.Never);
@@ -217,12 +166,11 @@ namespace Avalonia.Visuals.UnitTests.Rendering
}
[Fact]
- public void Frame_Should_Create_Layer_For_Root()
+ public void Should_Create_Layer_For_Root()
{
var loop = new Mock();
var root = new TestRoot();
var rootLayer = new Mock();
- var dispatcher = new ImmediateDispatcher();
var sceneBuilder = new Mock();
sceneBuilder.Setup(x => x.UpdateAll(It.IsAny()))
@@ -233,18 +181,9 @@ namespace Avalonia.Visuals.UnitTests.Rendering
});
var renderInterface = new Mock();
+ var target = CreateTargetAndRunFrame(root, sceneBuilder: sceneBuilder.Object);
- var target = new DeferredRenderer(
- root,
- loop.Object,
- sceneBuilder: sceneBuilder.Object,
- dispatcher: dispatcher);
-
- target.Start();
- RunFrame(loop);
-
- var context = Mock.Get(root.CreateRenderTarget().CreateDrawingContext(null));
- context.Verify(x => x.CreateLayer(root.ClientSize));
+ Assert.Single(target.Layers);
}
[Fact]
@@ -269,49 +208,44 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Measure(Size.Infinity);
root.Arrange(new Rect(root.DesiredSize));
- var rootLayer = CreateLayer();
- var borderLayer = CreateLayer();
- var renderTargetContext = Mock.Get(root.CreateRenderTarget().CreateDrawingContext(null));
- renderTargetContext.SetupSequence(x => x.CreateLayer(It.IsAny()))
- .Returns(rootLayer)
- .Returns(borderLayer);
-
var loop = new Mock();
- var target = new DeferredRenderer(
- root,
- loop.Object,
- dispatcher: new ImmediateDispatcher());
- root.Renderer = target;
+ var target = CreateTargetAndRunFrame(root, loop: loop);
- target.Start();
- RunFrame(loop);
+ Assert.Equal(new[] { root }, target.Layers.Select(x => x.LayerRoot));
- var rootContext = Mock.Get(rootLayer.CreateDrawingContext(null));
- var borderContext = Mock.Get(borderLayer.CreateDrawingContext(null));
var animation = new BehaviorSubject(0.5);
-
- rootContext.Verify(x => x.FillRectangle(Brushes.Red, new Rect(0, 0, 100, 100), 0), Times.Once);
- rootContext.Verify(x => x.FillRectangle(Brushes.Green, new Rect(0, 0, 100, 100), 0), Times.Once);
- borderContext.Verify(x => x.FillRectangle(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never);
-
- rootContext.ResetCalls();
- borderContext.ResetCalls();
border.Bind(Border.OpacityProperty, animation, BindingPriority.Animation);
RunFrame(loop);
- rootContext.Verify(x => x.FillRectangle(Brushes.Red, new Rect(0, 0, 100, 100), 0), Times.Once);
- rootContext.Verify(x => x.FillRectangle(Brushes.Green, new Rect(0, 0, 100, 100), 0), Times.Never);
- borderContext.Verify(x => x.FillRectangle(Brushes.Green, new Rect(0, 0, 100, 100), 0), Times.Once);
+ Assert.Equal(new IVisual[] { root, border }, target.Layers.Select(x => x.LayerRoot));
- rootContext.ResetCalls();
- borderContext.ResetCalls();
animation.OnCompleted();
RunFrame(loop);
- Mock.Get(borderLayer).Verify(x => x.Dispose());
- rootContext.Verify(x => x.FillRectangle(Brushes.Red, new Rect(0, 0, 100, 100), 0), Times.Once);
- rootContext.Verify(x => x.FillRectangle(Brushes.Green, new Rect(0, 0, 100, 100), 0), Times.Once);
- borderContext.Verify(x => x.FillRectangle(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never);
+ Assert.Equal(new[] { root }, target.Layers.Select(x => x.LayerRoot));
+ }
+
+ private DeferredRenderer CreateTargetAndRunFrame(
+ TestRoot root,
+ Mock loop = null,
+ ISceneBuilder sceneBuilder = null,
+ IDispatcher dispatcher = null)
+ {
+ loop = loop ?? new Mock();
+ var target = new DeferredRenderer(
+ root,
+ loop.Object,
+ sceneBuilder: sceneBuilder,
+ dispatcher: dispatcher ?? new ImmediateDispatcher());
+ root.Renderer = target;
+ target.Start();
+ RunFrame(loop);
+ return target;
+ }
+
+ private Mock GetLayerContext(DeferredRenderer renderer, IControl layerRoot)
+ {
+ return Mock.Get(renderer.Layers[layerRoot].Bitmap.CreateDrawingContext(null));
}
private void IgnoreFirstFrame(Mock loop, Mock sceneBuilder)