csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
320 lines
12 KiB
320 lines
12 KiB
using System.Collections.Generic;
|
|
using Avalonia.Collections;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Layout;
|
|
using Avalonia.Media;
|
|
using Avalonia.Platform;
|
|
using Avalonia.Rendering;
|
|
using Avalonia.UnitTests;
|
|
using Avalonia.VisualTree;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace Avalonia.Visuals.UnitTests.Rendering
|
|
{
|
|
public class ImmediateRendererTests
|
|
{
|
|
[Fact]
|
|
public void AddDirty_Call_RenderRoot_Invalidate()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
|
|
{
|
|
var visual = new Mock<Visual>();
|
|
var child = new Mock<Visual>() { CallBase = true };
|
|
var renderRoot = visual.As<IRenderRoot>();
|
|
|
|
visual.As<IVisual>().Setup(v => v.Bounds).Returns(new Rect(0, 0, 400, 400));
|
|
|
|
child.As<IVisual>().Setup(v => v.Bounds).Returns(new Rect(10, 10, 100, 100));
|
|
child.As<IVisual>().Setup(v => v.VisualParent).Returns(visual.Object);
|
|
|
|
var target = new ImmediateRenderer(visual.Object);
|
|
|
|
target.AddDirty(child.Object);
|
|
|
|
renderRoot.Verify(v => v.Invalidate(new Rect(10, 10, 100, 100)));
|
|
}
|
|
}
|
|
|
|
[Fact(Skip = "https://github.com/moq/moq4/issues/988")]
|
|
public void AddDirty_With_RenderTransform_Call_RenderRoot_Invalidate()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
|
|
{
|
|
var visual = new Mock<Visual>();
|
|
var child = new Mock<Visual>() { CallBase = true };
|
|
var renderRoot = visual.As<IRenderRoot>();
|
|
|
|
visual.As<IVisual>().Setup(v => v.Bounds).Returns(new Rect(0, 0, 400, 400));
|
|
|
|
child.As<IVisual>().Setup(v => v.Bounds).Returns(new Rect(100, 100, 100, 100));
|
|
child.As<IVisual>().Setup(v => v.VisualParent).Returns(visual.Object);
|
|
child.Object.RenderTransform = new ScaleTransform() { ScaleX = 2, ScaleY = 2 };
|
|
|
|
var target = new ImmediateRenderer(visual.Object);
|
|
|
|
target.AddDirty(child.Object);
|
|
|
|
renderRoot.Verify(v => v.Invalidate(new Rect(50, 50, 200, 200)));
|
|
}
|
|
}
|
|
|
|
[Fact(Skip = "https://github.com/moq/moq4/issues/988")]
|
|
public void AddDirty_For_Child_Moved_Should_Invalidate_Previous_Bounds()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
|
|
{
|
|
var visual = new Mock<Visual>() { CallBase = true };
|
|
var child = new Mock<Visual>() { CallBase = true };
|
|
var renderRoot = visual.As<IRenderRoot>();
|
|
var renderTarget = visual.As<IRenderTarget>();
|
|
|
|
renderRoot.Setup(r => r.CreateRenderTarget()).Returns(renderTarget.Object);
|
|
|
|
renderTarget.Setup(r => r.CreateDrawingContext(It.IsAny<IVisualBrushRenderer>()))
|
|
.Returns(Mock.Of<IDrawingContextImpl>());
|
|
|
|
visual.As<IVisual>().Setup(v => v.Bounds).Returns(new Rect(0, 0, 400, 400));
|
|
|
|
visual.As<IVisual>().Setup(v => v.VisualChildren)
|
|
.Returns(new AvaloniaList<IVisual>() { child.As<IVisual>().Object });
|
|
|
|
Rect childBounds = new Rect(0, 0, 100, 100);
|
|
child.As<IVisual>().Setup(v => v.Bounds).Returns(() => childBounds);
|
|
child.As<IVisual>().Setup(v => v.VisualParent).Returns(visual.Object);
|
|
child.As<IVisual>().Setup(v => v.VisualChildren).Returns(new AvaloniaList<IVisual>());
|
|
|
|
var invalidationCalls = new List<Rect>();
|
|
|
|
renderRoot.Setup(v => v.Invalidate(It.IsAny<Rect>())).Callback<Rect>(v => invalidationCalls.Add(v));
|
|
|
|
var target = new ImmediateRenderer(visual.Object);
|
|
|
|
target.AddDirty(child.Object);
|
|
|
|
Assert.Equal(new Rect(0, 0, 100, 100), invalidationCalls[0]);
|
|
|
|
target.Paint(new Rect(0, 0, 100, 100));
|
|
|
|
//move child 100 pixels bottom/right
|
|
childBounds = new Rect(100, 100, 100, 100);
|
|
|
|
//renderer should invalidate old child bounds with new one
|
|
//as on old area there can be artifacts
|
|
target.AddDirty(child.Object);
|
|
|
|
//invalidate first old position
|
|
Assert.Equal(new Rect(0, 0, 100, 100), invalidationCalls[1]);
|
|
|
|
//then new position
|
|
Assert.Equal(new Rect(100, 100, 100, 100), invalidationCalls[2]);
|
|
}
|
|
}
|
|
|
|
[Fact(Skip = "https://github.com/moq/moq4/issues/988")]
|
|
public void Should_Render_Child_In_Parent_With_RenderTransform()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
|
|
{
|
|
var targetMock = new Mock<Control>() { CallBase = true };
|
|
var target = targetMock.Object;
|
|
target.Width = 100;
|
|
target.Height = 50;
|
|
|
|
var child = new Panel()
|
|
{
|
|
RenderTransform = new RotateTransform() { Angle = 90 },
|
|
Children = { new Panel() { Children = { target } } }
|
|
};
|
|
|
|
var visualTarget = targetMock.As<IVisual>();
|
|
int rendered = 0;
|
|
visualTarget.Setup(v => v.Render(It.IsAny<DrawingContext>())).Callback(() => rendered++);
|
|
|
|
var root = new TestRoot(child);
|
|
root.Renderer = new ImmediateRenderer(root);
|
|
|
|
root.LayoutManager.ExecuteInitialLayoutPass();
|
|
|
|
root.Measure(new Size(50, 100));
|
|
root.Arrange(new Rect(new Size(50, 100)));
|
|
|
|
root.Renderer.Paint(root.Bounds);
|
|
|
|
Assert.Equal(1, rendered);
|
|
}
|
|
}
|
|
|
|
[Fact(Skip = "https://github.com/moq/moq4/issues/988")]
|
|
public void Should_Render_Child_In_Parent_With_RenderTransform2()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
|
|
{
|
|
var targetMock = new Mock<Control>() { CallBase = true };
|
|
var target = targetMock.Object;
|
|
|
|
target.Width = 100;
|
|
target.Height = 50;
|
|
target.HorizontalAlignment = HorizontalAlignment.Center;
|
|
target.VerticalAlignment = VerticalAlignment.Center;
|
|
|
|
var child = new Panel()
|
|
{
|
|
RenderTransform = new RotateTransform() { Angle = 90 },
|
|
Children = { new Panel() { Children = { target } } }
|
|
};
|
|
|
|
var visualTarget = targetMock.As<IVisual>();
|
|
int rendered = 0;
|
|
visualTarget.Setup(v => v.Render(It.IsAny<DrawingContext>())).Callback(() => rendered++);
|
|
|
|
var root = new TestRoot(child);
|
|
root.Renderer = new ImmediateRenderer(root);
|
|
|
|
root.LayoutManager.ExecuteInitialLayoutPass();
|
|
|
|
root.Measure(new Size(300, 100));
|
|
root.Arrange(new Rect(new Size(300, 100)));
|
|
root.Renderer.Paint(root.Bounds);
|
|
|
|
Assert.Equal(1, rendered);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Should_Not_Clip_Children_With_RenderTransform_When_In_Bounds()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
|
|
{
|
|
const int RootWidth = 300;
|
|
const int RootHeight = 300;
|
|
|
|
var rootGrid = new Grid { Width = RootWidth, Height = RootHeight, ClipToBounds = true };
|
|
|
|
var stackPanel = new StackPanel
|
|
{
|
|
Orientation = Orientation.Horizontal,
|
|
VerticalAlignment = VerticalAlignment.Top,
|
|
HorizontalAlignment = HorizontalAlignment.Right,
|
|
Margin = new Thickness(0, 10, 0, 0),
|
|
RenderTransformOrigin = new RelativePoint(new Point(0, 0), RelativeUnit.Relative),
|
|
RenderTransform = new TransformGroup
|
|
{
|
|
Children = { new RotateTransform { Angle = 90 }, new TranslateTransform { X = 240 } }
|
|
}
|
|
};
|
|
|
|
rootGrid.Children.Add(stackPanel);
|
|
|
|
TestControl CreateControl()
|
|
=> new TestControl
|
|
{
|
|
Width = 80, Height = 40, Margin = new Thickness(0, 0, 5, 0), ClipToBounds = true
|
|
};
|
|
|
|
var control1 = CreateControl();
|
|
var control2 = CreateControl();
|
|
var control3 = CreateControl();
|
|
|
|
stackPanel.Children.Add(control1);
|
|
stackPanel.Children.Add(control2);
|
|
stackPanel.Children.Add(control3);
|
|
|
|
var root = new TestRoot(rootGrid);
|
|
root.Renderer = new ImmediateRenderer(root);
|
|
root.LayoutManager.ExecuteInitialLayoutPass();
|
|
|
|
var rootSize = new Size(RootWidth, RootHeight);
|
|
root.Measure(rootSize);
|
|
root.Arrange(new Rect(rootSize));
|
|
|
|
root.Renderer.Paint(root.Bounds);
|
|
|
|
Assert.True(control1.Rendered);
|
|
Assert.True(control2.Rendered);
|
|
Assert.True(control3.Rendered);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Should_Not_Render_Clipped_Child_With_RenderTransform_When_Not_In_Bounds()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
|
|
{
|
|
const int RootWidth = 300;
|
|
const int RootHeight = 300;
|
|
|
|
var rootGrid = new Grid { Width = RootWidth, Height = RootHeight, ClipToBounds = true };
|
|
|
|
var stackPanel = new StackPanel
|
|
{
|
|
Orientation = Orientation.Horizontal,
|
|
VerticalAlignment = VerticalAlignment.Top,
|
|
HorizontalAlignment = HorizontalAlignment.Right,
|
|
Margin = new Thickness(0, 10, 0, 0),
|
|
RenderTransformOrigin = new RelativePoint(new Point(0, 0), RelativeUnit.Relative),
|
|
RenderTransform = new TransformGroup
|
|
{
|
|
Children = { new RotateTransform { Angle = 90 }, new TranslateTransform { X = 280 } }
|
|
}
|
|
};
|
|
|
|
rootGrid.Children.Add(stackPanel);
|
|
|
|
TestControl CreateControl()
|
|
=> new TestControl
|
|
{
|
|
Width = 160, Height = 40, Margin = new Thickness(0, 0, 5, 0), ClipToBounds = true
|
|
};
|
|
|
|
var control1 = CreateControl();
|
|
var control2 = CreateControl();
|
|
var control3 = CreateControl();
|
|
|
|
stackPanel.Children.Add(control1);
|
|
stackPanel.Children.Add(control2);
|
|
stackPanel.Children.Add(control3);
|
|
|
|
var root = new TestRoot(rootGrid);
|
|
root.Renderer = new ImmediateRenderer(root);
|
|
root.LayoutManager.ExecuteInitialLayoutPass();
|
|
|
|
var rootSize = new Size(RootWidth, RootHeight);
|
|
root.Measure(rootSize);
|
|
root.Arrange(new Rect(rootSize));
|
|
|
|
root.Renderer.Paint(root.Bounds);
|
|
|
|
Assert.True(control1.Rendered);
|
|
Assert.True(control2.Rendered);
|
|
Assert.False(control3.Rendered);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Static_Render_Method_Does_Not_Update_TransformedBounds()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
|
|
{
|
|
var target = new Border();
|
|
var expected = new TransformedBounds(new Rect(1, 2, 3, 4), new Rect(4, 5, 6, 7), Matrix.CreateRotation(0.8));
|
|
|
|
((IVisual)target).TransformedBounds = expected;
|
|
|
|
var renderTarget = Mock.Of<IRenderTarget>(x =>
|
|
x.CreateDrawingContext(It.IsAny<IVisualBrushRenderer>()) == Mock.Of<IDrawingContextImpl>());
|
|
ImmediateRenderer.Render(target, renderTarget);
|
|
|
|
Assert.Equal(expected, target.TransformedBounds);
|
|
}
|
|
}
|
|
|
|
private class TestControl : Control
|
|
{
|
|
public bool Rendered { get; private set; }
|
|
|
|
public override void Render(DrawingContext context)
|
|
=> Rendered = true;
|
|
}
|
|
}
|
|
}
|
|
|