SceneBuilder.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  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.Platform;
  7. using Avalonia.Threading;
  8. using Avalonia.VisualTree;
  9. namespace Avalonia.Rendering.SceneGraph
  10. {
  11. /// <summary>
  12. /// Builds a scene graph from a visual tree.
  13. /// </summary>
  14. public class SceneBuilder : ISceneBuilder
  15. {
  16. /// <inheritdoc/>
  17. public void UpdateAll(Scene scene)
  18. {
  19. Contract.Requires<ArgumentNullException>(scene != null);
  20. Dispatcher.UIThread.VerifyAccess();
  21. UpdateSize(scene);
  22. scene.Layers.GetOrAdd(scene.Root.Visual);
  23. using (var impl = new DeferredDrawingContextImpl(this, scene.Layers))
  24. using (var context = new DrawingContext(impl))
  25. {
  26. Update(context, scene, (VisualNode)scene.Root, scene.Root.Visual.Bounds, true);
  27. }
  28. }
  29. /// <inheritdoc/>
  30. public bool Update(Scene scene, IVisual visual)
  31. {
  32. Contract.Requires<ArgumentNullException>(scene != null);
  33. Contract.Requires<ArgumentNullException>(visual != null);
  34. Dispatcher.UIThread.VerifyAccess();
  35. if (!scene.Root.Visual.IsVisible)
  36. {
  37. throw new AvaloniaInternalException("Cannot update the scene for an invisible root visual.");
  38. }
  39. var node = (VisualNode)scene.FindNode(visual);
  40. if (visual == scene.Root.Visual)
  41. {
  42. UpdateSize(scene);
  43. }
  44. if (visual.VisualRoot != null)
  45. {
  46. if (visual.IsVisible)
  47. {
  48. // If the node isn't yet part of the scene, find the nearest ancestor that is.
  49. node = node ?? FindExistingAncestor(scene, visual);
  50. // We don't need to do anything if this part of the tree has already been fully
  51. // updated.
  52. if (node != null && !node.SubTreeUpdated)
  53. {
  54. // If the control we've been asked to update isn't part of the scene then
  55. // we're carrying out an add operation, so recurse and add all the
  56. // descendents too.
  57. var recurse = node.Visual != visual;
  58. using (var impl = new DeferredDrawingContextImpl(this, scene.Layers))
  59. using (var context = new DrawingContext(impl))
  60. {
  61. var clip = scene.Root.Visual.Bounds;
  62. if (node.Parent != null)
  63. {
  64. context.PushPostTransform(node.Parent.Transform);
  65. clip = node.Parent.ClipBounds;
  66. }
  67. using (context.PushTransformContainer())
  68. {
  69. Update(context, scene, node, clip, recurse);
  70. }
  71. }
  72. return true;
  73. }
  74. }
  75. else
  76. {
  77. if (node != null)
  78. {
  79. // The control has been hidden so remove it from its parent and deindex the
  80. // node and its descendents.
  81. ((VisualNode)node.Parent)?.RemoveChild(node);
  82. Deindex(scene, node);
  83. return true;
  84. }
  85. }
  86. }
  87. else if (node != null)
  88. {
  89. // The control has been removed so remove it from its parent and deindex the
  90. // node and its descendents.
  91. var trim = FindFirstDeadAncestor(scene, node);
  92. ((VisualNode)trim.Parent).RemoveChild(trim);
  93. Deindex(scene, trim);
  94. return true;
  95. }
  96. return false;
  97. }
  98. private static VisualNode FindExistingAncestor(Scene scene, IVisual visual)
  99. {
  100. var node = scene.FindNode(visual);
  101. while (node == null && visual.IsVisible)
  102. {
  103. visual = visual.VisualParent;
  104. node = scene.FindNode(visual);
  105. }
  106. return visual.IsVisible ? (VisualNode)node : null;
  107. }
  108. private static VisualNode FindFirstDeadAncestor(Scene scene, IVisualNode node)
  109. {
  110. var parent = node.Parent;
  111. while (parent.Visual.VisualRoot == null)
  112. {
  113. node = parent;
  114. parent = node.Parent;
  115. }
  116. return (VisualNode)node;
  117. }
  118. private static void Update(DrawingContext context, Scene scene, VisualNode node, Rect clip, bool forceRecurse)
  119. {
  120. var visual = node.Visual;
  121. var opacity = visual.Opacity;
  122. var clipToBounds = visual.ClipToBounds;
  123. var bounds = new Rect(visual.Bounds.Size);
  124. var contextImpl = (DeferredDrawingContextImpl)context.PlatformImpl;
  125. contextImpl.Layers.Find(node.LayerRoot)?.Dirty.Add(node.Bounds);
  126. if (visual.IsVisible)
  127. {
  128. var m = Matrix.CreateTranslation(visual.Bounds.Position);
  129. var renderTransform = Matrix.Identity;
  130. if (visual.RenderTransform != null)
  131. {
  132. var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height));
  133. var offset = Matrix.CreateTranslation(origin);
  134. renderTransform = (-offset) * visual.RenderTransform.Value * (offset);
  135. }
  136. m = renderTransform * m;
  137. using (contextImpl.BeginUpdate(node))
  138. using (context.PushPostTransform(m))
  139. using (context.PushTransformContainer())
  140. {
  141. var clipBounds = bounds.TransformToAABB(contextImpl.Transform).Intersect(clip);
  142. forceRecurse = forceRecurse ||
  143. node.Transform != contextImpl.Transform ||
  144. node.ClipBounds != clipBounds;
  145. node.Transform = contextImpl.Transform;
  146. node.ClipBounds = clipBounds;
  147. node.ClipToBounds = clipToBounds;
  148. node.GeometryClip = visual.Clip?.PlatformImpl;
  149. node.Opacity = opacity;
  150. node.OpacityMask = visual.OpacityMask;
  151. if (ShouldStartLayer(visual))
  152. {
  153. if (node.LayerRoot != visual)
  154. {
  155. MakeLayer(scene, node);
  156. }
  157. else
  158. {
  159. UpdateLayer(node, scene.Layers[node.LayerRoot]);
  160. }
  161. }
  162. else if (node.LayerRoot == node.Visual && node.Parent != null)
  163. {
  164. ClearLayer(scene, node);
  165. }
  166. if (node.ClipToBounds)
  167. {
  168. clip = clip.Intersect(node.ClipBounds);
  169. }
  170. try
  171. {
  172. visual.Render(context);
  173. }
  174. catch { }
  175. if (visual is Visual)
  176. {
  177. var transformed = new TransformedBounds(new Rect(visual.Bounds.Size), clip, node.Transform);
  178. BoundsTracker.SetTransformedBounds((Visual)visual, transformed);
  179. }
  180. if (forceRecurse)
  181. {
  182. foreach (var child in visual.VisualChildren.OrderBy(x => x, ZIndexComparer.Instance))
  183. {
  184. var childNode = scene.FindNode(child) ?? CreateNode(scene, child, node);
  185. Update(context, scene, (VisualNode)childNode, clip, forceRecurse);
  186. }
  187. node.SubTreeUpdated = true;
  188. contextImpl.TrimChildren();
  189. }
  190. }
  191. }
  192. }
  193. private void UpdateSize(Scene scene)
  194. {
  195. var renderRoot = scene.Root.Visual as IRenderRoot;
  196. var newSize = renderRoot?.ClientSize ?? scene.Root.Visual.Bounds.Size;
  197. scene.Scaling = renderRoot?.RenderScaling ?? 1;
  198. if (scene.Size != newSize)
  199. {
  200. var oldSize = scene.Size;
  201. scene.Size = newSize;
  202. Rect horizontalDirtyRect = Rect.Empty;
  203. Rect verticalDirtyRect = Rect.Empty;
  204. if (newSize.Width > oldSize.Width)
  205. {
  206. horizontalDirtyRect = new Rect(oldSize.Width, 0, newSize.Width - oldSize.Width, oldSize.Height);
  207. }
  208. if (newSize.Height > oldSize.Height)
  209. {
  210. verticalDirtyRect = new Rect(0, oldSize.Height, newSize.Width, newSize.Height - oldSize.Height);
  211. }
  212. foreach (var layer in scene.Layers)
  213. {
  214. layer.Dirty.Add(horizontalDirtyRect);
  215. layer.Dirty.Add(verticalDirtyRect);
  216. }
  217. }
  218. }
  219. private static VisualNode CreateNode(Scene scene, IVisual visual, VisualNode parent)
  220. {
  221. var node = new VisualNode(visual, parent);
  222. node.LayerRoot = parent.LayerRoot;
  223. scene.Add(node);
  224. return node;
  225. }
  226. private static void Deindex(Scene scene, VisualNode node)
  227. {
  228. scene.Remove(node);
  229. node.SubTreeUpdated = true;
  230. scene.Layers[node.LayerRoot].Dirty.Add(node.Bounds);
  231. if (node.Visual is Visual v)
  232. {
  233. BoundsTracker.SetTransformedBounds(v, null);
  234. }
  235. foreach (VisualNode child in node.Children)
  236. {
  237. var geometry = child as IDrawOperation;
  238. if (child is VisualNode visual)
  239. {
  240. Deindex(scene, visual);
  241. }
  242. }
  243. if (node.LayerRoot == node.Visual && node.Visual != scene.Root.Visual)
  244. {
  245. scene.Layers.Remove(node.LayerRoot);
  246. }
  247. }
  248. private static void ClearLayer(Scene scene, VisualNode node)
  249. {
  250. var parent = (VisualNode)node.Parent;
  251. var oldLayerRoot = node.LayerRoot;
  252. var newLayerRoot = parent.LayerRoot;
  253. var existingDirtyRects = scene.Layers[node.LayerRoot].Dirty;
  254. var newDirtyRects = scene.Layers[newLayerRoot].Dirty;
  255. existingDirtyRects.Coalesce();
  256. foreach (var r in existingDirtyRects)
  257. {
  258. newDirtyRects.Add(r);
  259. }
  260. var oldLayer = scene.Layers[oldLayerRoot];
  261. PropagateLayer(node, scene.Layers[newLayerRoot], oldLayer);
  262. scene.Layers.Remove(oldLayer);
  263. }
  264. private static void MakeLayer(Scene scene, VisualNode node)
  265. {
  266. var oldLayerRoot = node.LayerRoot;
  267. var layer = scene.Layers.Add(node.Visual);
  268. var oldLayer = scene.Layers[oldLayerRoot];
  269. UpdateLayer(node, layer);
  270. PropagateLayer(node, layer, scene.Layers[oldLayerRoot]);
  271. }
  272. private static void UpdateLayer(VisualNode node, SceneLayer layer)
  273. {
  274. layer.Opacity = node.Visual.Opacity;
  275. if (node.Visual.OpacityMask != null)
  276. {
  277. layer.OpacityMask = node.Visual.OpacityMask?.ToImmutable();
  278. layer.OpacityMaskRect = node.ClipBounds;
  279. }
  280. else
  281. {
  282. layer.OpacityMask = null;
  283. layer.OpacityMaskRect = Rect.Empty;
  284. }
  285. layer.GeometryClip = node.HasAncestorGeometryClip ?
  286. CreateLayerGeometryClip(node) :
  287. null;
  288. }
  289. private static void PropagateLayer(VisualNode node, SceneLayer layer, SceneLayer oldLayer)
  290. {
  291. node.LayerRoot = layer.LayerRoot;
  292. layer.Dirty.Add(node.Bounds);
  293. oldLayer.Dirty.Add(node.Bounds);
  294. foreach (VisualNode child in node.Children)
  295. {
  296. // If the child is not the start of a new layer, recurse.
  297. if (child.LayerRoot != child.Visual)
  298. {
  299. PropagateLayer(child, layer, oldLayer);
  300. }
  301. }
  302. }
  303. private static bool ShouldStartLayer(IVisual visual)
  304. {
  305. var o = visual as IAvaloniaObject;
  306. return visual.VisualChildren.Count > 0 &&
  307. o != null &&
  308. o.IsAnimating(Visual.OpacityProperty);
  309. }
  310. private static IGeometryImpl CreateLayerGeometryClip(VisualNode node)
  311. {
  312. IGeometryImpl result = null;
  313. for (;;)
  314. {
  315. node = (VisualNode)node.Parent;
  316. if (node == null || (node.GeometryClip == null && !node.HasAncestorGeometryClip))
  317. {
  318. break;
  319. }
  320. if (node?.GeometryClip != null)
  321. {
  322. var transformed = node.GeometryClip.WithTransform(node.Transform);
  323. result = result == null ? transformed : result.Intersect(transformed);
  324. }
  325. }
  326. return result;
  327. }
  328. }
  329. }