SceneBuilder.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using System.Linq;
  5. using Avalonia.Media;
  6. using Avalonia.Threading;
  7. using Avalonia.VisualTree;
  8. namespace Avalonia.Rendering.SceneGraph
  9. {
  10. public class SceneBuilder : ISceneBuilder
  11. {
  12. public void UpdateAll(Scene scene)
  13. {
  14. Contract.Requires<ArgumentNullException>(scene != null);
  15. Dispatcher.UIThread.VerifyAccess();
  16. UpdateSize(scene);
  17. scene.Layers.GetOrAdd(scene.Root.Visual);
  18. using (var impl = new DeferredDrawingContextImpl(this, scene.Layers))
  19. using (var context = new DrawingContext(impl))
  20. {
  21. Update(context, scene, (VisualNode)scene.Root, scene.Root.Visual.Bounds, true);
  22. }
  23. }
  24. public bool Update(Scene scene, IVisual visual)
  25. {
  26. Contract.Requires<ArgumentNullException>(scene != null);
  27. Contract.Requires<ArgumentNullException>(visual != null);
  28. Dispatcher.UIThread.VerifyAccess();
  29. var node = (VisualNode)scene.FindNode(visual);
  30. if (visual == scene.Root.Visual)
  31. {
  32. UpdateSize(scene);
  33. }
  34. if (visual.VisualRoot != null)
  35. {
  36. if (visual.IsVisible)
  37. {
  38. // If the node isn't yet part of the scene, find the nearest ancestor that is.
  39. node = node ?? FindExistingAncestor(scene, visual);
  40. // We don't need to do anything if this part of the tree has already been fully
  41. // updated.
  42. if (node != null && !node.SubTreeUpdated)
  43. {
  44. // If the control we've been asked to update isn't part of the scene then
  45. // we're carrying out an add operation, so recurse and add all the
  46. // descendents too.
  47. var recurse = node.Visual != visual;
  48. using (var impl = new DeferredDrawingContextImpl(this, scene.Layers))
  49. using (var context = new DrawingContext(impl))
  50. {
  51. var clip = scene.Root.Visual.Bounds;
  52. if (node.Parent != null)
  53. {
  54. context.PushPostTransform(node.Parent.Transform);
  55. clip = node.Parent.ClipBounds;
  56. }
  57. Update(context, scene, node, clip, recurse);
  58. }
  59. return true;
  60. }
  61. }
  62. else
  63. {
  64. if (node != null)
  65. {
  66. // The control has been hidden so remove it from its parent and deindex the
  67. // node and its descendents.
  68. ((VisualNode)node.Parent)?.RemoveChild(node);
  69. Deindex(scene, node);
  70. return true;
  71. }
  72. }
  73. }
  74. else if (node != null)
  75. {
  76. // The control has been removed so remove it from its parent and deindex the
  77. // node and its descendents.
  78. var trim = FindFirstDeadAncestor(scene, node);
  79. ((VisualNode)trim.Parent).RemoveChild(trim);
  80. Deindex(scene, trim);
  81. return true;
  82. }
  83. return false;
  84. }
  85. private static VisualNode FindExistingAncestor(Scene scene, IVisual visual)
  86. {
  87. var node = scene.FindNode(visual);
  88. while (node == null && visual.IsVisible)
  89. {
  90. visual = visual.VisualParent;
  91. node = scene.FindNode(visual);
  92. }
  93. return visual.IsVisible ? (VisualNode)node : null;
  94. }
  95. private static VisualNode FindFirstDeadAncestor(Scene scene, IVisualNode node)
  96. {
  97. var parent = node.Parent;
  98. while (parent.Visual.VisualRoot == null)
  99. {
  100. node = parent;
  101. parent = node.Parent;
  102. }
  103. return (VisualNode)node;
  104. }
  105. private static void Update(DrawingContext context, Scene scene, VisualNode node, Rect clip, bool forceRecurse)
  106. {
  107. var visual = node.Visual;
  108. var opacity = visual.Opacity;
  109. var clipToBounds = visual.ClipToBounds;
  110. var bounds = new Rect(visual.Bounds.Size);
  111. var contextImpl = (DeferredDrawingContextImpl)context.PlatformImpl;
  112. contextImpl.Layers.Find(node.LayerRoot)?.Dirty.Add(node.Bounds);
  113. if (visual.IsVisible)
  114. {
  115. var m = Matrix.CreateTranslation(visual.Bounds.Position);
  116. var renderTransform = Matrix.Identity;
  117. if (visual.RenderTransform != null)
  118. {
  119. var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height));
  120. var offset = Matrix.CreateTranslation(origin);
  121. renderTransform = (-offset) * visual.RenderTransform.Value * (offset);
  122. }
  123. m = renderTransform * m;
  124. using (contextImpl.BeginUpdate(node))
  125. using (context.PushPostTransform(m))
  126. using (context.PushTransformContainer())
  127. {
  128. forceRecurse = forceRecurse || node.Transform != contextImpl.Transform;
  129. node.Transform = contextImpl.Transform;
  130. node.ClipBounds = bounds.TransformToAABB(node.Transform).Intersect(clip);
  131. node.ClipToBounds = clipToBounds;
  132. node.GeometryClip = visual.Clip;
  133. node.Opacity = opacity;
  134. node.OpacityMask = visual.OpacityMask;
  135. if (opacity < 1 && node.LayerRoot != visual)
  136. {
  137. SetLayer(scene, node, node.Visual);
  138. }
  139. else if (opacity >= 1 && node.LayerRoot == node.Visual && node.Parent != null)
  140. {
  141. ClearLayer(scene, node);
  142. }
  143. if (node.LayerRoot == visual)
  144. {
  145. var layer = scene.Layers.Find(visual);
  146. if (layer != null)
  147. {
  148. layer.Opacity = visual.Opacity;
  149. }
  150. }
  151. if (node.ClipToBounds)
  152. {
  153. clip = clip.Intersect(node.ClipBounds);
  154. }
  155. try
  156. {
  157. visual.Render(context);
  158. }
  159. catch { }
  160. if (forceRecurse)
  161. {
  162. foreach (var child in visual.VisualChildren.OrderBy(x => x, ZIndexComparer.Instance))
  163. {
  164. var childNode = scene.FindNode(child) ?? CreateNode(scene, child, node);
  165. Update(context, scene, (VisualNode)childNode, clip, forceRecurse);
  166. }
  167. node.SubTreeUpdated = true;
  168. contextImpl.TrimChildren();
  169. }
  170. }
  171. }
  172. }
  173. private void UpdateSize(Scene scene)
  174. {
  175. var renderRoot = scene.Root.Visual as IRenderRoot;
  176. var newSize = renderRoot?.ClientSize ?? scene.Root.Visual.Bounds.Size;
  177. scene.Scaling = renderRoot?.RenderScaling ?? 1;
  178. if (scene.Size != newSize)
  179. {
  180. var oldSize = scene.Size;
  181. scene.Size = newSize;
  182. Rect horizontalDirtyRect = Rect.Empty;
  183. Rect verticalDirtyRect = Rect.Empty;
  184. if (newSize.Width > oldSize.Width)
  185. {
  186. horizontalDirtyRect = new Rect(oldSize.Width, 0, newSize.Width - oldSize.Width, oldSize.Height);
  187. }
  188. if (newSize.Height > oldSize.Height)
  189. {
  190. verticalDirtyRect = new Rect(0, oldSize.Height, newSize.Width, newSize.Height - oldSize.Height);
  191. }
  192. foreach (var layer in scene.Layers)
  193. {
  194. layer.Dirty.Add(horizontalDirtyRect);
  195. layer.Dirty.Add(verticalDirtyRect);
  196. }
  197. }
  198. }
  199. private static VisualNode CreateNode(Scene scene, IVisual visual, VisualNode parent)
  200. {
  201. var node = new VisualNode(visual, parent);
  202. node.LayerRoot = parent.LayerRoot;
  203. scene.Add(node);
  204. return node;
  205. }
  206. private static void Deindex(Scene scene, VisualNode node)
  207. {
  208. scene.Remove(node);
  209. node.SubTreeUpdated = true;
  210. foreach (VisualNode child in node.Children)
  211. {
  212. var geometry = child as IDrawOperation;
  213. var visual = child as VisualNode;
  214. if (geometry != null)
  215. {
  216. scene.Layers[child.LayerRoot].Dirty.Add(geometry.Bounds);
  217. }
  218. if (visual != null)
  219. {
  220. Deindex(scene, visual);
  221. }
  222. }
  223. if (node.LayerRoot == node.Visual)
  224. {
  225. scene.Layers.Remove(node.LayerRoot);
  226. }
  227. }
  228. private static void ClearLayer(Scene scene, VisualNode node)
  229. {
  230. var parent = (VisualNode)node.Parent;
  231. var oldLayerRoot = node.LayerRoot;
  232. var newLayerRoot = parent.LayerRoot;
  233. var existingDirtyRects = scene.Layers[node.LayerRoot].Dirty;
  234. var newDirtyRects = scene.Layers[newLayerRoot].Dirty;
  235. existingDirtyRects.Coalesce();
  236. foreach (var r in existingDirtyRects)
  237. {
  238. newDirtyRects.Add(r);
  239. }
  240. SetLayer(scene, node, newLayerRoot);
  241. scene.Layers.Remove(oldLayerRoot);
  242. }
  243. private static void SetLayer(Scene scene, VisualNode node, IVisual layerRoot)
  244. {
  245. if (node.LayerRoot == layerRoot)
  246. {
  247. throw new AvaloniaInternalException("Called SetLayer with unchanged LayerRoot.");
  248. }
  249. var oldLayerRoot = node.LayerRoot;
  250. node.LayerRoot = layerRoot;
  251. var layer = scene.Layers.GetOrAdd(layerRoot);
  252. layer.Dirty.Add(node.Bounds);
  253. scene.Layers[oldLayerRoot].Dirty.Add(node.Bounds);
  254. foreach (VisualNode child in node.Children)
  255. {
  256. // If the child is not the start of a new layer, recurse.
  257. if (child.LayerRoot != child.Visual)
  258. {
  259. SetLayer(scene, child, layerRoot);
  260. }
  261. }
  262. }
  263. }
  264. }