ImmediateRendererTests.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. using System.Collections.Generic;
  2. using Avalonia.Collections;
  3. using Avalonia.Controls;
  4. using Avalonia.Layout;
  5. using Avalonia.Media;
  6. using Avalonia.Platform;
  7. using Avalonia.Rendering;
  8. using Avalonia.UnitTests;
  9. using Avalonia.VisualTree;
  10. using Moq;
  11. using Xunit;
  12. namespace Avalonia.Visuals.UnitTests.Rendering
  13. {
  14. public class ImmediateRendererTests
  15. {
  16. [Fact]
  17. public void AddDirty_Call_RenderRoot_Invalidate()
  18. {
  19. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  20. {
  21. var visual = new Mock<Visual>();
  22. var child = new Mock<Visual>() { CallBase = true };
  23. var renderRoot = visual.As<IRenderRoot>();
  24. visual.As<IVisual>().Setup(v => v.Bounds).Returns(new Rect(0, 0, 400, 400));
  25. child.As<IVisual>().Setup(v => v.Bounds).Returns(new Rect(10, 10, 100, 100));
  26. child.As<IVisual>().Setup(v => v.VisualParent).Returns(visual.Object);
  27. var target = new ImmediateRenderer(visual.Object);
  28. target.AddDirty(child.Object);
  29. renderRoot.Verify(v => v.Invalidate(new Rect(10, 10, 100, 100)));
  30. }
  31. }
  32. [Fact(Skip = "https://github.com/moq/moq4/issues/988")]
  33. public void AddDirty_With_RenderTransform_Call_RenderRoot_Invalidate()
  34. {
  35. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  36. {
  37. var visual = new Mock<Visual>();
  38. var child = new Mock<Visual>() { CallBase = true };
  39. var renderRoot = visual.As<IRenderRoot>();
  40. visual.As<IVisual>().Setup(v => v.Bounds).Returns(new Rect(0, 0, 400, 400));
  41. child.As<IVisual>().Setup(v => v.Bounds).Returns(new Rect(100, 100, 100, 100));
  42. child.As<IVisual>().Setup(v => v.VisualParent).Returns(visual.Object);
  43. child.Object.RenderTransform = new ScaleTransform() { ScaleX = 2, ScaleY = 2 };
  44. var target = new ImmediateRenderer(visual.Object);
  45. target.AddDirty(child.Object);
  46. renderRoot.Verify(v => v.Invalidate(new Rect(50, 50, 200, 200)));
  47. }
  48. }
  49. [Fact(Skip = "https://github.com/moq/moq4/issues/988")]
  50. public void AddDirty_For_Child_Moved_Should_Invalidate_Previous_Bounds()
  51. {
  52. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  53. {
  54. var visual = new Mock<Visual>() { CallBase = true };
  55. var child = new Mock<Visual>() { CallBase = true };
  56. var renderRoot = visual.As<IRenderRoot>();
  57. var renderTarget = visual.As<IRenderTarget>();
  58. renderRoot.Setup(r => r.CreateRenderTarget()).Returns(renderTarget.Object);
  59. renderTarget.Setup(r => r.CreateDrawingContext(It.IsAny<IVisualBrushRenderer>()))
  60. .Returns(Mock.Of<IDrawingContextImpl>());
  61. visual.As<IVisual>().Setup(v => v.Bounds).Returns(new Rect(0, 0, 400, 400));
  62. visual.As<IVisual>().Setup(v => v.VisualChildren)
  63. .Returns(new AvaloniaList<IVisual>() { child.As<IVisual>().Object });
  64. Rect childBounds = new Rect(0, 0, 100, 100);
  65. child.As<IVisual>().Setup(v => v.Bounds).Returns(() => childBounds);
  66. child.As<IVisual>().Setup(v => v.VisualParent).Returns(visual.Object);
  67. child.As<IVisual>().Setup(v => v.VisualChildren).Returns(new AvaloniaList<IVisual>());
  68. var invalidationCalls = new List<Rect>();
  69. renderRoot.Setup(v => v.Invalidate(It.IsAny<Rect>())).Callback<Rect>(v => invalidationCalls.Add(v));
  70. var target = new ImmediateRenderer(visual.Object);
  71. target.AddDirty(child.Object);
  72. Assert.Equal(new Rect(0, 0, 100, 100), invalidationCalls[0]);
  73. target.Paint(new Rect(0, 0, 100, 100));
  74. //move child 100 pixels bottom/right
  75. childBounds = new Rect(100, 100, 100, 100);
  76. //renderer should invalidate old child bounds with new one
  77. //as on old area there can be artifacts
  78. target.AddDirty(child.Object);
  79. //invalidate first old position
  80. Assert.Equal(new Rect(0, 0, 100, 100), invalidationCalls[1]);
  81. //then new position
  82. Assert.Equal(new Rect(100, 100, 100, 100), invalidationCalls[2]);
  83. }
  84. }
  85. [Fact(Skip = "https://github.com/moq/moq4/issues/988")]
  86. public void Should_Render_Child_In_Parent_With_RenderTransform()
  87. {
  88. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  89. {
  90. var targetMock = new Mock<Control>() { CallBase = true };
  91. var target = targetMock.Object;
  92. target.Width = 100;
  93. target.Height = 50;
  94. var child = new Panel()
  95. {
  96. RenderTransform = new RotateTransform() { Angle = 90 },
  97. Children = { new Panel() { Children = { target } } }
  98. };
  99. var visualTarget = targetMock.As<IVisual>();
  100. int rendered = 0;
  101. visualTarget.Setup(v => v.Render(It.IsAny<DrawingContext>())).Callback(() => rendered++);
  102. var root = new TestRoot(child);
  103. root.Renderer = new ImmediateRenderer(root);
  104. root.LayoutManager.ExecuteInitialLayoutPass();
  105. root.Measure(new Size(50, 100));
  106. root.Arrange(new Rect(new Size(50, 100)));
  107. root.Renderer.Paint(root.Bounds);
  108. Assert.Equal(1, rendered);
  109. }
  110. }
  111. [Fact(Skip = "https://github.com/moq/moq4/issues/988")]
  112. public void Should_Render_Child_In_Parent_With_RenderTransform2()
  113. {
  114. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  115. {
  116. var targetMock = new Mock<Control>() { CallBase = true };
  117. var target = targetMock.Object;
  118. target.Width = 100;
  119. target.Height = 50;
  120. target.HorizontalAlignment = HorizontalAlignment.Center;
  121. target.VerticalAlignment = VerticalAlignment.Center;
  122. var child = new Panel()
  123. {
  124. RenderTransform = new RotateTransform() { Angle = 90 },
  125. Children = { new Panel() { Children = { target } } }
  126. };
  127. var visualTarget = targetMock.As<IVisual>();
  128. int rendered = 0;
  129. visualTarget.Setup(v => v.Render(It.IsAny<DrawingContext>())).Callback(() => rendered++);
  130. var root = new TestRoot(child);
  131. root.Renderer = new ImmediateRenderer(root);
  132. root.LayoutManager.ExecuteInitialLayoutPass();
  133. root.Measure(new Size(300, 100));
  134. root.Arrange(new Rect(new Size(300, 100)));
  135. root.Renderer.Paint(root.Bounds);
  136. Assert.Equal(1, rendered);
  137. }
  138. }
  139. [Fact]
  140. public void Should_Not_Clip_Children_With_RenderTransform_When_In_Bounds()
  141. {
  142. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  143. {
  144. const int RootWidth = 300;
  145. const int RootHeight = 300;
  146. var rootGrid = new Grid { Width = RootWidth, Height = RootHeight, ClipToBounds = true };
  147. var stackPanel = new StackPanel
  148. {
  149. Orientation = Orientation.Horizontal,
  150. VerticalAlignment = VerticalAlignment.Top,
  151. HorizontalAlignment = HorizontalAlignment.Right,
  152. Margin = new Thickness(0, 10, 0, 0),
  153. RenderTransformOrigin = new RelativePoint(new Point(0, 0), RelativeUnit.Relative),
  154. RenderTransform = new TransformGroup
  155. {
  156. Children = { new RotateTransform { Angle = 90 }, new TranslateTransform { X = 240 } }
  157. }
  158. };
  159. rootGrid.Children.Add(stackPanel);
  160. TestControl CreateControl()
  161. => new TestControl
  162. {
  163. Width = 80, Height = 40, Margin = new Thickness(0, 0, 5, 0), ClipToBounds = true
  164. };
  165. var control1 = CreateControl();
  166. var control2 = CreateControl();
  167. var control3 = CreateControl();
  168. stackPanel.Children.Add(control1);
  169. stackPanel.Children.Add(control2);
  170. stackPanel.Children.Add(control3);
  171. var root = new TestRoot(rootGrid);
  172. root.Renderer = new ImmediateRenderer(root);
  173. root.LayoutManager.ExecuteInitialLayoutPass();
  174. var rootSize = new Size(RootWidth, RootHeight);
  175. root.Measure(rootSize);
  176. root.Arrange(new Rect(rootSize));
  177. root.Renderer.Paint(root.Bounds);
  178. Assert.True(control1.Rendered);
  179. Assert.True(control2.Rendered);
  180. Assert.True(control3.Rendered);
  181. }
  182. }
  183. [Fact]
  184. public void Should_Not_Render_Clipped_Child_With_RenderTransform_When_Not_In_Bounds()
  185. {
  186. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  187. {
  188. const int RootWidth = 300;
  189. const int RootHeight = 300;
  190. var rootGrid = new Grid { Width = RootWidth, Height = RootHeight, ClipToBounds = true };
  191. var stackPanel = new StackPanel
  192. {
  193. Orientation = Orientation.Horizontal,
  194. VerticalAlignment = VerticalAlignment.Top,
  195. HorizontalAlignment = HorizontalAlignment.Right,
  196. Margin = new Thickness(0, 10, 0, 0),
  197. RenderTransformOrigin = new RelativePoint(new Point(0, 0), RelativeUnit.Relative),
  198. RenderTransform = new TransformGroup
  199. {
  200. Children = { new RotateTransform { Angle = 90 }, new TranslateTransform { X = 280 } }
  201. }
  202. };
  203. rootGrid.Children.Add(stackPanel);
  204. TestControl CreateControl()
  205. => new TestControl
  206. {
  207. Width = 160, Height = 40, Margin = new Thickness(0, 0, 5, 0), ClipToBounds = true
  208. };
  209. var control1 = CreateControl();
  210. var control2 = CreateControl();
  211. var control3 = CreateControl();
  212. stackPanel.Children.Add(control1);
  213. stackPanel.Children.Add(control2);
  214. stackPanel.Children.Add(control3);
  215. var root = new TestRoot(rootGrid);
  216. root.Renderer = new ImmediateRenderer(root);
  217. root.LayoutManager.ExecuteInitialLayoutPass();
  218. var rootSize = new Size(RootWidth, RootHeight);
  219. root.Measure(rootSize);
  220. root.Arrange(new Rect(rootSize));
  221. root.Renderer.Paint(root.Bounds);
  222. Assert.True(control1.Rendered);
  223. Assert.True(control2.Rendered);
  224. Assert.False(control3.Rendered);
  225. }
  226. }
  227. private class TestControl : Control
  228. {
  229. public bool Rendered { get; private set; }
  230. public override void Render(DrawingContext context)
  231. => Rendered = true;
  232. }
  233. }
  234. }