SceneBuilderTests.cs 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
  1. using System.Linq;
  2. using System.Reactive.Subjects;
  3. using Avalonia.Controls;
  4. using Avalonia.Data;
  5. using Avalonia.Layout;
  6. using Avalonia.Media;
  7. using Avalonia.Media.Imaging;
  8. using Avalonia.Platform;
  9. using Avalonia.Rendering.SceneGraph;
  10. using Avalonia.UnitTests;
  11. using Avalonia.Utilities;
  12. using Avalonia.VisualTree;
  13. using Moq;
  14. using Xunit;
  15. namespace Avalonia.Base.UnitTests.Rendering.SceneGraph
  16. {
  17. public partial class SceneBuilderTests
  18. {
  19. [Fact]
  20. public void Should_Build_Initial_Scene()
  21. {
  22. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  23. {
  24. Border border;
  25. TextBlock textBlock;
  26. var tree = new TestRoot
  27. {
  28. Child = border = new Border
  29. {
  30. Width = 100,
  31. Height = 100,
  32. Background = Brushes.Red,
  33. Child = textBlock = new TextBlock
  34. {
  35. TextWrapping = TextWrapping.NoWrap,
  36. Text = "Hello World",
  37. }
  38. }
  39. };
  40. tree.Measure(Size.Infinity);
  41. tree.Arrange(new Rect(tree.DesiredSize));
  42. var result = new Scene(tree);
  43. var sceneBuilder = new SceneBuilder();
  44. sceneBuilder.UpdateAll(result);
  45. Assert.Same(tree, ((VisualNode)result.Root).LayerRoot);
  46. Assert.Equal(1, result.Root.Children.Count);
  47. var borderNode = (VisualNode)result.Root.Children[0];
  48. Assert.Same(borderNode, result.FindNode(border));
  49. Assert.Same(border, borderNode.Visual);
  50. Assert.Equal(1, borderNode.Children.Count);
  51. Assert.Equal(1, borderNode.DrawOperations.Count);
  52. var backgroundNode = (RectangleNode)borderNode.DrawOperations[0].Item;
  53. Assert.Equal(Brushes.Red, backgroundNode.Brush);
  54. var textBlockNode = borderNode.Children[0];
  55. Assert.Same(textBlockNode, result.FindNode(textBlock));
  56. Assert.Same(textBlock, textBlockNode.Visual);
  57. Assert.Equal(1, textBlockNode.DrawOperations.Count);
  58. var textNode = (GlyphRunNode)textBlockNode.DrawOperations[0].Item;
  59. Assert.NotNull(textNode.GlyphRun);
  60. }
  61. }
  62. [Fact]
  63. public void Should_Respect_Margin_For_ClipBounds()
  64. {
  65. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  66. {
  67. Canvas canvas;
  68. var tree = new TestRoot
  69. {
  70. Width = 200,
  71. Height = 300,
  72. Child = new Border
  73. {
  74. Margin = new Thickness(10, 20, 30, 40),
  75. Child = canvas = new Canvas
  76. {
  77. ClipToBounds = true,
  78. Background = Brushes.AliceBlue,
  79. }
  80. }
  81. };
  82. tree.Measure(Size.Infinity);
  83. tree.Arrange(new Rect(tree.DesiredSize));
  84. var result = new Scene(tree);
  85. var sceneBuilder = new SceneBuilder();
  86. sceneBuilder.UpdateAll(result);
  87. var canvasNode = result.FindNode(canvas);
  88. Assert.Equal(new Rect(10, 20, 160, 240), canvasNode.ClipBounds);
  89. // Initial ClipBounds are correct, make sure they're still correct after updating canvas.
  90. result = result.CloneScene();
  91. Assert.True(sceneBuilder.Update(result, canvas));
  92. canvasNode = result.FindNode(canvas);
  93. Assert.Equal(new Rect(10, 20, 160, 240), canvasNode.ClipBounds);
  94. }
  95. }
  96. [Fact]
  97. public void ClipBounds_Should_Be_Intersection_With_Parent_ClipBounds()
  98. {
  99. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  100. {
  101. Border border;
  102. var tree = new TestRoot
  103. {
  104. Width = 200,
  105. Height = 300,
  106. Child = new Canvas
  107. {
  108. ClipToBounds = true,
  109. Width = 100,
  110. Height = 100,
  111. HorizontalAlignment = HorizontalAlignment.Left,
  112. VerticalAlignment = VerticalAlignment.Top,
  113. Children =
  114. {
  115. (border = new Border
  116. {
  117. Background = Brushes.AliceBlue,
  118. ClipToBounds = true,
  119. Width = 100,
  120. Height = 100,
  121. [Canvas.LeftProperty] = 50,
  122. [Canvas.TopProperty] = 50,
  123. })
  124. }
  125. }
  126. };
  127. tree.Measure(Size.Infinity);
  128. tree.Arrange(new Rect(tree.DesiredSize));
  129. var scene = new Scene(tree);
  130. var sceneBuilder = new SceneBuilder();
  131. sceneBuilder.UpdateAll(scene);
  132. var borderNode = scene.FindNode(border);
  133. Assert.Equal(new Rect(50, 50, 50, 50), borderNode.ClipBounds);
  134. }
  135. }
  136. [Fact]
  137. public void Should_Update_Descendent_ClipBounds_When_Margin_Changed()
  138. {
  139. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  140. {
  141. Border border;
  142. Canvas canvas;
  143. var tree = new TestRoot
  144. {
  145. Width = 200,
  146. Height = 300,
  147. Child = canvas = new Canvas
  148. {
  149. ClipToBounds = true,
  150. Width = 100,
  151. Height = 100,
  152. HorizontalAlignment = HorizontalAlignment.Left,
  153. VerticalAlignment = VerticalAlignment.Top,
  154. Children =
  155. {
  156. (border = new Border
  157. {
  158. Background = Brushes.AliceBlue,
  159. ClipToBounds = true,
  160. Width = 100,
  161. Height = 100,
  162. [Canvas.LeftProperty] = 50,
  163. [Canvas.TopProperty] = 50,
  164. })
  165. }
  166. }
  167. };
  168. tree.Measure(Size.Infinity);
  169. tree.Arrange(new Rect(tree.DesiredSize));
  170. var scene = new Scene(tree);
  171. var sceneBuilder = new SceneBuilder();
  172. sceneBuilder.UpdateAll(scene);
  173. var borderNode = scene.FindNode(border);
  174. Assert.Equal(new Rect(50, 50, 50, 50), borderNode.ClipBounds);
  175. canvas.Width = canvas.Height = 125;
  176. canvas.Measure(Size.Infinity);
  177. canvas.Arrange(new Rect(tree.DesiredSize));
  178. // Initial ClipBounds are correct, make sure they're still correct after updating canvas.
  179. scene = scene.CloneScene();
  180. Assert.True(sceneBuilder.Update(scene, canvas));
  181. borderNode = scene.FindNode(border);
  182. Assert.Equal(new Rect(50, 50, 75, 75), borderNode.ClipBounds);
  183. }
  184. }
  185. [Fact]
  186. public void Should_Respect_ZIndex()
  187. {
  188. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  189. {
  190. Border front;
  191. Border back;
  192. var tree = new TestRoot
  193. {
  194. Child = new Panel
  195. {
  196. Children =
  197. {
  198. (front = new Border
  199. {
  200. ZIndex = 1,
  201. }),
  202. (back = new Border
  203. {
  204. ZIndex = 0,
  205. }),
  206. }
  207. }
  208. };
  209. var result = new Scene(tree);
  210. var sceneBuilder = new SceneBuilder();
  211. sceneBuilder.UpdateAll(result);
  212. var panelNode = result.FindNode(tree.Child);
  213. var expected = new IVisual[] { back, front };
  214. var actual = panelNode.Children.OfType<IVisualNode>().Select(x => x.Visual).ToArray();
  215. Assert.Equal(expected, actual);
  216. }
  217. }
  218. [Fact]
  219. public void Should_Respect_Uniform_ZIndex()
  220. {
  221. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  222. {
  223. Panel panel;
  224. var tree = new TestRoot
  225. {
  226. Child = panel = new Panel()
  227. };
  228. for (var i = 0; i < 128; i++)
  229. {
  230. panel.Children.Add(new Border());
  231. }
  232. var result = new Scene(tree);
  233. var sceneBuilder = new SceneBuilder();
  234. sceneBuilder.UpdateAll(result);
  235. var panelNode = result.FindNode(tree.Child);
  236. var expected = panel.Children.ToArray();
  237. var actual = panelNode.Children.OfType<IVisualNode>().Select(x => x.Visual).ToArray();
  238. Assert.Equal(expected, actual);
  239. }
  240. }
  241. [Fact]
  242. public void ClipBounds_Should_Be_In_Global_Coordinates()
  243. {
  244. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  245. {
  246. Border target;
  247. var tree = new TestRoot
  248. {
  249. Child = new Decorator
  250. {
  251. Margin = new Thickness(24, 26),
  252. Child = target = new Border
  253. {
  254. ClipToBounds = true,
  255. Margin = new Thickness(26, 24),
  256. Width = 100,
  257. Height = 100,
  258. }
  259. }
  260. };
  261. tree.Measure(Size.Infinity);
  262. tree.Arrange(new Rect(tree.DesiredSize));
  263. var result = new Scene(tree);
  264. var sceneBuilder = new SceneBuilder();
  265. sceneBuilder.UpdateAll(result);
  266. var targetNode = result.FindNode(target);
  267. Assert.Equal(new Rect(50, 50, 100, 100), targetNode.ClipBounds);
  268. }
  269. }
  270. [Fact]
  271. public void Transform_For_Control_With_RenderTransform_Should_Be_Correct_After_Update()
  272. {
  273. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  274. {
  275. Border border;
  276. var tree = new TestRoot
  277. {
  278. Width = 400,
  279. Height = 200,
  280. Child = new Decorator
  281. {
  282. Width = 200,
  283. Height = 100,
  284. Child = border = new Border
  285. {
  286. Background = Brushes.Red,
  287. HorizontalAlignment = HorizontalAlignment.Right,
  288. Width = 100,
  289. RenderTransform = new ScaleTransform(0.5, 1),
  290. }
  291. }
  292. };
  293. tree.Measure(Size.Infinity);
  294. tree.Arrange(new Rect(tree.DesiredSize));
  295. var scene = new Scene(tree);
  296. var sceneBuilder = new SceneBuilder();
  297. sceneBuilder.UpdateAll(scene);
  298. var expectedTransform = Matrix.CreateScale(0.5, 1) * Matrix.CreateTranslation(225, 50);
  299. var borderNode = scene.FindNode(border);
  300. Assert.Equal(expectedTransform, borderNode.Transform);
  301. scene = scene.CloneScene();
  302. Assert.True(sceneBuilder.Update(scene, border));
  303. borderNode = scene.FindNode(border);
  304. Assert.Equal(expectedTransform, borderNode.Transform);
  305. }
  306. }
  307. [Fact]
  308. public void MirrorTransform_For_Control_With_RenderTransform_Should_Be_Correct()
  309. {
  310. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  311. {
  312. Border border;
  313. var tree = new TestRoot
  314. {
  315. Width = 400,
  316. Height = 200,
  317. Child = border = new Border
  318. {
  319. HorizontalAlignment = HorizontalAlignment.Left,
  320. Background = Brushes.Red,
  321. Width = 100,
  322. RenderTransform = new ScaleTransform(0.5, 1),
  323. FlowDirection = FlowDirection.RightToLeft
  324. }
  325. };
  326. tree.Measure(Size.Infinity);
  327. tree.Arrange(new Rect(tree.DesiredSize));
  328. var scene = new Scene(tree);
  329. var sceneBuilder = new SceneBuilder();
  330. sceneBuilder.UpdateAll(scene);
  331. var expectedTransform = new Matrix(-1, 0, 0, 1, 100, 0) * Matrix.CreateScale(0.5, 1) * Matrix.CreateTranslation(25, 0);
  332. var borderNode = scene.FindNode(border);
  333. Assert.Equal(expectedTransform, borderNode.Transform);
  334. }
  335. }
  336. [Fact]
  337. public void Should_Update_Border_Background_Node()
  338. {
  339. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  340. {
  341. Border border;
  342. TextBlock textBlock;
  343. var tree = new TestRoot
  344. {
  345. Child = border = new Border
  346. {
  347. Width = 100,
  348. Height = 100,
  349. Background = Brushes.Red,
  350. Child = textBlock = new TextBlock
  351. {
  352. Foreground = Brushes.Green,
  353. Text = "Hello World",
  354. }
  355. }
  356. };
  357. tree.Measure(Size.Infinity);
  358. tree.Arrange(new Rect(tree.DesiredSize));
  359. var initial = new Scene(tree);
  360. var sceneBuilder = new SceneBuilder();
  361. sceneBuilder.UpdateAll(initial);
  362. var initialBackgroundNode = initial.FindNode(border).Children[0];
  363. var initialTextNode = initial.FindNode(textBlock).DrawOperations[0];
  364. Assert.NotNull(initialBackgroundNode);
  365. Assert.NotNull(initialTextNode);
  366. border.Background = Brushes.Green;
  367. var result = initial.CloneScene();
  368. sceneBuilder.Update(result, border);
  369. var borderNode = (VisualNode)result.Root.Children[0];
  370. Assert.Same(border, borderNode.Visual);
  371. var backgroundNode = (RectangleNode)borderNode.DrawOperations[0].Item;
  372. Assert.NotSame(initialBackgroundNode, backgroundNode);
  373. Assert.Equal(Brushes.Green, backgroundNode.Brush);
  374. var textBlockNode = (VisualNode)borderNode.Children[0];
  375. Assert.Same(textBlock, textBlockNode.Visual);
  376. var textNode = (GlyphRunNode)textBlockNode.DrawOperations[0].Item;
  377. Assert.Same(initialTextNode.Item, textNode);
  378. }
  379. }
  380. [Fact]
  381. public void Should_Update_When_Control_Added()
  382. {
  383. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  384. {
  385. Border border;
  386. var tree = new TestRoot
  387. {
  388. Width = 100,
  389. Height = 100,
  390. Child = border = new Border
  391. {
  392. Background = Brushes.Red,
  393. }
  394. };
  395. Canvas canvas;
  396. var decorator = new Decorator
  397. {
  398. Child = canvas = new Canvas(),
  399. };
  400. tree.Measure(Size.Infinity);
  401. tree.Arrange(new Rect(tree.DesiredSize));
  402. var initial = new Scene(tree);
  403. var sceneBuilder = new SceneBuilder();
  404. sceneBuilder.UpdateAll(initial);
  405. border.Child = decorator;
  406. var result = initial.CloneScene();
  407. Assert.True(sceneBuilder.Update(result, decorator));
  408. // Updating canvas should result in no-op as it should have been updated along
  409. // with decorator as part of the add opeation.
  410. Assert.False(sceneBuilder.Update(result, canvas));
  411. var borderNode = (VisualNode)result.Root.Children[0];
  412. Assert.Equal(1, borderNode.Children.Count);
  413. Assert.Equal(1, borderNode.DrawOperations.Count);
  414. var decoratorNode = (VisualNode)borderNode.Children[0];
  415. Assert.Same(decorator, decoratorNode.Visual);
  416. Assert.Same(decoratorNode, result.FindNode(decorator));
  417. var canvasNode = (VisualNode)decoratorNode.Children[0];
  418. Assert.Same(canvas, canvasNode.Visual);
  419. Assert.Same(canvasNode, result.FindNode(canvas));
  420. }
  421. }
  422. [Fact]
  423. public void Should_Update_When_Control_Removed()
  424. {
  425. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  426. {
  427. Border border;
  428. Decorator decorator;
  429. Canvas canvas;
  430. var tree = new TestRoot
  431. {
  432. Width = 100,
  433. Height = 100,
  434. Child = border = new Border
  435. {
  436. Background = Brushes.Red,
  437. Child = decorator = new Decorator
  438. {
  439. Child = canvas = new Canvas
  440. {
  441. Background = Brushes.AliceBlue,
  442. }
  443. }
  444. }
  445. };
  446. tree.Measure(Size.Infinity);
  447. tree.Arrange(new Rect(tree.DesiredSize));
  448. var initial = new Scene(tree);
  449. var sceneBuilder = new SceneBuilder();
  450. sceneBuilder.UpdateAll(initial);
  451. border.Child = null;
  452. var result = initial.CloneScene();
  453. Assert.True(sceneBuilder.Update(result, decorator));
  454. Assert.False(sceneBuilder.Update(result, canvas));
  455. var borderNode = (VisualNode)result.Root.Children[0];
  456. Assert.Equal(0, borderNode.Children.Count);
  457. Assert.Equal(1, borderNode.DrawOperations.Count);
  458. Assert.Null(result.FindNode(decorator));
  459. Assert.Equal(new Rect(0, 0, 100, 100), result.Layers.Single().Dirty.Single());
  460. }
  461. }
  462. [Fact]
  463. public void Should_Update_When_Control_Moved()
  464. {
  465. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  466. {
  467. Decorator moveFrom;
  468. Decorator moveTo;
  469. Canvas moveMe;
  470. var tree = new TestRoot
  471. {
  472. Width = 100,
  473. Height = 100,
  474. Child = new StackPanel
  475. {
  476. Children =
  477. {
  478. (moveFrom = new Decorator
  479. {
  480. Child = moveMe = new Canvas(),
  481. }),
  482. (moveTo = new Decorator()),
  483. }
  484. }
  485. };
  486. tree.Measure(Size.Infinity);
  487. tree.Arrange(new Rect(tree.DesiredSize));
  488. var scene = new Scene(tree);
  489. var sceneBuilder = new SceneBuilder();
  490. sceneBuilder.UpdateAll(scene);
  491. var moveFromNode = (VisualNode)scene.FindNode(moveFrom);
  492. var moveToNode = (VisualNode)scene.FindNode(moveTo);
  493. Assert.Equal(1, moveFromNode.Children.Count);
  494. Assert.Same(moveMe, moveFromNode.Children[0].Visual);
  495. Assert.Empty(moveToNode.Children);
  496. moveFrom.Child = null;
  497. moveTo.Child = moveMe;
  498. scene = scene.CloneScene();
  499. moveFromNode = (VisualNode)scene.FindNode(moveFrom);
  500. moveToNode = (VisualNode)scene.FindNode(moveTo);
  501. moveFromNode.SortChildren(scene);
  502. moveToNode.SortChildren(scene);
  503. sceneBuilder.Update(scene, moveFrom);
  504. sceneBuilder.Update(scene, moveTo);
  505. sceneBuilder.Update(scene, moveMe);
  506. Assert.Empty(moveFromNode.Children);
  507. Assert.Equal(1, moveToNode.Children.Count);
  508. Assert.Same(moveMe, moveToNode.Children[0].Visual);
  509. }
  510. }
  511. [Fact]
  512. public void Should_Update_When_Control_Moved_Causing_Layout_Change()
  513. {
  514. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  515. {
  516. Decorator moveFrom;
  517. Decorator moveTo;
  518. Canvas moveMe;
  519. var tree = new TestRoot
  520. {
  521. Width = 100,
  522. Height = 100,
  523. Child = new DockPanel
  524. {
  525. Children =
  526. {
  527. (moveFrom = new Decorator
  528. {
  529. Child = moveMe = new Canvas
  530. {
  531. Width = 100,
  532. Height = 100,
  533. },
  534. }),
  535. (moveTo = new Decorator()),
  536. }
  537. }
  538. };
  539. tree.Measure(Size.Infinity);
  540. tree.Arrange(new Rect(tree.DesiredSize));
  541. var scene = new Scene(tree);
  542. var sceneBuilder = new SceneBuilder();
  543. sceneBuilder.UpdateAll(scene);
  544. var moveFromNode = (VisualNode)scene.FindNode(moveFrom);
  545. var moveToNode = (VisualNode)scene.FindNode(moveTo);
  546. Assert.Equal(1, moveFromNode.Children.Count);
  547. Assert.Same(moveMe, moveFromNode.Children[0].Visual);
  548. Assert.Empty(moveToNode.Children);
  549. moveFrom.Child = null;
  550. moveTo.Child = moveMe;
  551. tree.LayoutManager.ExecuteLayoutPass();
  552. scene = scene.CloneScene();
  553. moveFromNode = (VisualNode)scene.FindNode(moveFrom);
  554. moveToNode = (VisualNode)scene.FindNode(moveTo);
  555. moveFromNode.SortChildren(scene);
  556. moveToNode.SortChildren(scene);
  557. sceneBuilder.Update(scene, moveFrom);
  558. sceneBuilder.Update(scene, moveTo);
  559. sceneBuilder.Update(scene, moveMe);
  560. Assert.Empty(moveFromNode.Children);
  561. Assert.Equal(1, moveToNode.Children.Count);
  562. Assert.Same(moveMe, moveToNode.Children[0].Visual);
  563. }
  564. }
  565. [Fact]
  566. public void Should_Update_When_Control_Made_Invisible()
  567. {
  568. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  569. {
  570. Decorator decorator;
  571. Border border;
  572. Canvas canvas;
  573. var tree = new TestRoot
  574. {
  575. Width = 100,
  576. Height = 100,
  577. Child = decorator = new Decorator
  578. {
  579. Child = border = new Border
  580. {
  581. Background = Brushes.Red,
  582. Child = canvas = new Canvas(),
  583. }
  584. }
  585. };
  586. tree.Measure(Size.Infinity);
  587. tree.Arrange(new Rect(tree.DesiredSize));
  588. var initial = new Scene(tree);
  589. var sceneBuilder = new SceneBuilder();
  590. sceneBuilder.UpdateAll(initial);
  591. border.IsVisible = false;
  592. var result = initial.CloneScene();
  593. Assert.True(sceneBuilder.Update(result, border));
  594. Assert.False(sceneBuilder.Update(result, canvas));
  595. var decoratorNode = (VisualNode)result.Root.Children[0];
  596. Assert.Equal(0, decoratorNode.Children.Count);
  597. Assert.Null(result.FindNode(border));
  598. Assert.Null(result.FindNode(canvas));
  599. Assert.Equal(new Rect(0, 0, 100, 100), result.Layers.Single().Dirty.Single());
  600. }
  601. }
  602. [Fact]
  603. public void Should_Not_Dispose_Active_VisualNode_When_Control_Reparented_And_Child_Made_Invisible()
  604. {
  605. // Issue #3115
  606. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  607. {
  608. StackPanel panel;
  609. Border border1;
  610. Border border2;
  611. var tree = new TestRoot
  612. {
  613. Width = 100,
  614. Height = 100,
  615. Child = panel = new StackPanel
  616. {
  617. Children =
  618. {
  619. (border1 = new Border
  620. {
  621. Background = Brushes.Red,
  622. }),
  623. (border2 = new Border
  624. {
  625. Background = Brushes.Green,
  626. }),
  627. }
  628. }
  629. };
  630. tree.Measure(Size.Infinity);
  631. tree.Arrange(new Rect(tree.DesiredSize));
  632. var scene = new Scene(tree);
  633. var sceneBuilder = new SceneBuilder();
  634. sceneBuilder.UpdateAll(scene);
  635. var decorator = new Decorator();
  636. tree.Child = null;
  637. decorator.Child = panel;
  638. tree.Child = decorator;
  639. border1.IsVisible = false;
  640. scene = scene.CloneScene();
  641. sceneBuilder.Update(scene, decorator);
  642. var panelNode = (VisualNode)scene.FindNode(panel);
  643. Assert.Equal(2, panelNode.Children.Count);
  644. Assert.False(panelNode.Children[0].Disposed);
  645. Assert.False(panelNode.Children[1].Disposed);
  646. }
  647. }
  648. [Fact]
  649. public void Should_Update_ClipBounds_For_Negative_Margin()
  650. {
  651. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  652. {
  653. Decorator decorator;
  654. Border border;
  655. var tree = new TestRoot
  656. {
  657. Width = 100,
  658. Height = 100,
  659. Child = decorator = new Decorator
  660. {
  661. Margin = new Thickness(0, 10, 0, 0),
  662. Child = border = new Border
  663. {
  664. Background = Brushes.Red,
  665. ClipToBounds = true,
  666. Margin = new Thickness(0, -5, 0, 0),
  667. }
  668. }
  669. };
  670. var layout = tree.LayoutManager;
  671. layout.ExecuteInitialLayoutPass();
  672. var scene = new Scene(tree);
  673. var sceneBuilder = new SceneBuilder();
  674. sceneBuilder.UpdateAll(scene);
  675. var borderNode = scene.FindNode(border);
  676. Assert.Equal(new Rect(0, 5, 100, 95), borderNode.ClipBounds);
  677. border.Margin = new Thickness(0, -8, 0, 0);
  678. layout.ExecuteLayoutPass();
  679. scene = scene.CloneScene();
  680. sceneBuilder.Update(scene, border);
  681. borderNode = scene.FindNode(border);
  682. Assert.Equal(new Rect(0, 2, 100, 98), borderNode.ClipBounds);
  683. }
  684. }
  685. [Fact]
  686. public void Should_Update_Descendent_Tranform_When_Margin_Changed()
  687. {
  688. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  689. {
  690. Decorator decorator;
  691. Border border;
  692. Canvas canvas;
  693. var tree = new TestRoot
  694. {
  695. Width = 100,
  696. Height = 100,
  697. Child = decorator = new Decorator
  698. {
  699. Margin = new Thickness(0, 10, 0, 0),
  700. Child = border = new Border
  701. {
  702. Child = canvas = new Canvas(),
  703. }
  704. }
  705. };
  706. var layout = tree.LayoutManager;
  707. layout.ExecuteInitialLayoutPass();
  708. var scene = new Scene(tree);
  709. var sceneBuilder = new SceneBuilder();
  710. sceneBuilder.UpdateAll(scene);
  711. var borderNode = scene.FindNode(border);
  712. var canvasNode = scene.FindNode(canvas);
  713. Assert.Equal(Matrix.CreateTranslation(0, 10), borderNode.Transform);
  714. Assert.Equal(Matrix.CreateTranslation(0, 10), canvasNode.Transform);
  715. decorator.Margin = new Thickness(0, 20, 0, 0);
  716. layout.ExecuteLayoutPass();
  717. scene = scene.CloneScene();
  718. sceneBuilder.Update(scene, decorator);
  719. borderNode = scene.FindNode(border);
  720. canvasNode = scene.FindNode(canvas);
  721. Assert.Equal(Matrix.CreateTranslation(0, 20), borderNode.Transform);
  722. Assert.Equal(Matrix.CreateTranslation(0, 20), canvasNode.Transform);
  723. }
  724. }
  725. [Fact]
  726. public void DirtyRects_Should_Contain_Old_And_New_Bounds_When_Margin_Changed()
  727. {
  728. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  729. {
  730. Decorator decorator;
  731. Border border;
  732. Canvas canvas;
  733. var tree = new TestRoot
  734. {
  735. Width = 100,
  736. Height = 100,
  737. Child = decorator = new Decorator
  738. {
  739. Margin = new Thickness(0, 10, 0, 0),
  740. Child = border = new Border
  741. {
  742. Background = Brushes.Red,
  743. Child = canvas = new Canvas(),
  744. }
  745. }
  746. };
  747. var layout = tree.LayoutManager;
  748. layout.ExecuteInitialLayoutPass();
  749. var scene = new Scene(tree);
  750. var sceneBuilder = new SceneBuilder();
  751. sceneBuilder.UpdateAll(scene);
  752. var borderNode = scene.FindNode(border);
  753. var canvasNode = scene.FindNode(canvas);
  754. Assert.Equal(Matrix.CreateTranslation(0, 10), borderNode.Transform);
  755. Assert.Equal(Matrix.CreateTranslation(0, 10), canvasNode.Transform);
  756. decorator.Margin = new Thickness(0, 20, 0, 0);
  757. layout.ExecuteLayoutPass();
  758. scene = scene.CloneScene();
  759. sceneBuilder.Update(scene, decorator);
  760. var rects = scene.Layers.Single().Dirty.ToArray();
  761. Assert.Equal(new[] { new Rect(0, 10, 100, 90) }, rects);
  762. }
  763. }
  764. [Fact]
  765. public void Resizing_Scene_Should_Add_DirtyRects()
  766. {
  767. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  768. {
  769. Decorator decorator;
  770. Border border;
  771. Canvas canvas;
  772. var tree = new TestRoot
  773. {
  774. ClientSize = new Size(100, 100),
  775. Child = decorator = new Decorator
  776. {
  777. Margin = new Thickness(0, 10, 0, 0),
  778. Child = border = new Border
  779. {
  780. Background = Brushes.Red,
  781. Child = canvas = new Canvas(),
  782. }
  783. }
  784. };
  785. var animation = new BehaviorSubject<double>(0.5);
  786. border.Bind(Border.OpacityProperty, animation, BindingPriority.Animation);
  787. var scene = new Scene(tree);
  788. var sceneBuilder = new SceneBuilder();
  789. sceneBuilder.UpdateAll(scene);
  790. Assert.Equal(new Size(100, 100), scene.Size);
  791. tree.ClientSize = new Size(110, 120);
  792. scene = scene.CloneScene();
  793. sceneBuilder.Update(scene, tree);
  794. Assert.Equal(new Size(110, 120), scene.Size);
  795. var expected = new[]
  796. {
  797. new Rect(100, 0, 10, 100),
  798. new Rect(0, 100, 110, 20),
  799. };
  800. Assert.Equal(expected, scene.Layers[tree].Dirty.ToArray());
  801. // Layers are disabled. See #2244
  802. // Assert.Equal(expected, scene.Layers[border].Dirty.ToArray());
  803. }
  804. }
  805. [Fact]
  806. public void Setting_Opacity_Should_Add_Descendent_Bounds_To_DirtyRects()
  807. {
  808. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  809. {
  810. Decorator decorator;
  811. Border border;
  812. var tree = new TestRoot
  813. {
  814. Child = decorator = new Decorator
  815. {
  816. Child = border = new Border
  817. {
  818. Background = Brushes.Red,
  819. Width = 100,
  820. Height = 100,
  821. }
  822. }
  823. };
  824. tree.Measure(Size.Infinity);
  825. tree.Arrange(new Rect(tree.DesiredSize));
  826. var scene = new Scene(tree);
  827. var sceneBuilder = new SceneBuilder();
  828. sceneBuilder.UpdateAll(scene);
  829. decorator.Opacity = 0.5;
  830. scene = scene.CloneScene();
  831. sceneBuilder.Update(scene, decorator);
  832. Assert.NotEmpty(scene.Layers.Single().Dirty);
  833. var dirty = scene.Layers.Single().Dirty.Single();
  834. Assert.Equal(new Rect(0, 0, 100, 100), dirty);
  835. }
  836. }
  837. [Fact]
  838. public void Should_Set_GeometryClip()
  839. {
  840. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  841. {
  842. var clip = StreamGeometry.Parse("M100,0 L0,100 100,100");
  843. Decorator decorator;
  844. var tree = new TestRoot
  845. {
  846. Child = decorator = new Decorator
  847. {
  848. Clip = clip,
  849. }
  850. };
  851. var scene = new Scene(tree);
  852. var sceneBuilder = new SceneBuilder();
  853. sceneBuilder.UpdateAll(scene);
  854. var decoratorNode = scene.FindNode(decorator);
  855. Assert.Same(clip.PlatformImpl, decoratorNode.GeometryClip);
  856. }
  857. }
  858. [Fact]
  859. public void Disposing_Scene_Releases_DrawOperation_References()
  860. {
  861. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  862. {
  863. var bitmap = RefCountable.Create(Mock.Of<IBitmapImpl>(
  864. x => x.PixelSize == new PixelSize(100, 100) &&
  865. x.Dpi == new Vector(96, 96)));
  866. Image img;
  867. var tree = new TestRoot
  868. {
  869. Child = img = new Image
  870. {
  871. Source = new Bitmap(bitmap),
  872. Height = 100,
  873. Width = 100
  874. }
  875. };
  876. tree.Measure(Size.Infinity);
  877. tree.Arrange(new Rect(new Size(100, 100)));
  878. Assert.Equal(2, bitmap.RefCount);
  879. IRef<IDrawOperation> operation;
  880. using (var scene = new Scene(tree))
  881. {
  882. var sceneBuilder = new SceneBuilder();
  883. sceneBuilder.UpdateAll(scene);
  884. operation = scene.FindNode(img).DrawOperations[0];
  885. Assert.Equal(1, operation.RefCount);
  886. Assert.Equal(3, bitmap.RefCount);
  887. }
  888. Assert.Equal(0, operation.RefCount);
  889. Assert.Equal(2, bitmap.RefCount);
  890. }
  891. }
  892. [Fact]
  893. public void Replacing_Control_Releases_DrawOperation_Reference()
  894. {
  895. using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
  896. {
  897. var bitmap = RefCountable.Create(Mock.Of<IBitmapImpl>(
  898. x => x.PixelSize == new PixelSize(100, 100) &&
  899. x.Dpi == new Vector(96, 96)));
  900. Image img;
  901. var tree = new TestRoot
  902. {
  903. Child = img = new Image
  904. {
  905. Source = new Bitmap(bitmap),
  906. Width = 100,
  907. Height = 100
  908. }
  909. };
  910. tree.Measure(Size.Infinity);
  911. tree.Arrange(new Rect(new Size(100, 100)));
  912. var scene = new Scene(tree);
  913. var sceneBuilder = new SceneBuilder();
  914. sceneBuilder.UpdateAll(scene);
  915. var operation = scene.FindNode(img).DrawOperations[0];
  916. tree.Child = new Decorator();
  917. using (var result = scene.CloneScene())
  918. {
  919. sceneBuilder.Update(result, img);
  920. scene.Dispose();
  921. Assert.Equal(0, operation.RefCount);
  922. Assert.Equal(2, bitmap.RefCount);
  923. }
  924. }
  925. }
  926. }
  927. }