SceneBuilder.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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. // TODO: Check equality between node.OpacityMask and visual.OpacityMask before assigning.
  151. node.OpacityMask = visual.OpacityMask?.ToImmutable();
  152. if (ShouldStartLayer(visual))
  153. {
  154. if (node.LayerRoot != visual)
  155. {
  156. MakeLayer(scene, node);
  157. }
  158. else
  159. {
  160. UpdateLayer(node, scene.Layers[node.LayerRoot]);
  161. }
  162. }
  163. else if (node.LayerRoot == node.Visual && node.Parent != null)
  164. {
  165. ClearLayer(scene, node);
  166. }
  167. if (node.ClipToBounds)
  168. {
  169. clip = clip.Intersect(node.ClipBounds);
  170. }
  171. try
  172. {
  173. visual.Render(context);
  174. }
  175. catch { }
  176. var transformed = new TransformedBounds(new Rect(visual.Bounds.Size), clip, node.Transform);
  177. visual.TransformedBounds = transformed;
  178. if (forceRecurse)
  179. {
  180. foreach (var child in visual.VisualChildren.OrderBy(x => x, ZIndexComparer.Instance))
  181. {
  182. var childNode = scene.FindNode(child) ?? CreateNode(scene, child, node);
  183. Update(context, scene, (VisualNode)childNode, clip, forceRecurse);
  184. }
  185. node.SubTreeUpdated = true;
  186. contextImpl.TrimChildren();
  187. }
  188. }
  189. }
  190. }
  191. private void UpdateSize(Scene scene)
  192. {
  193. var renderRoot = scene.Root.Visual as IRenderRoot;
  194. var newSize = renderRoot?.ClientSize ?? scene.Root.Visual.Bounds.Size;
  195. scene.Scaling = renderRoot?.RenderScaling ?? 1;
  196. if (scene.Size != newSize)
  197. {
  198. var oldSize = scene.Size;
  199. scene.Size = newSize;
  200. Rect horizontalDirtyRect = Rect.Empty;
  201. Rect verticalDirtyRect = Rect.Empty;
  202. if (newSize.Width > oldSize.Width)
  203. {
  204. horizontalDirtyRect = new Rect(oldSize.Width, 0, newSize.Width - oldSize.Width, oldSize.Height);
  205. }
  206. if (newSize.Height > oldSize.Height)
  207. {
  208. verticalDirtyRect = new Rect(0, oldSize.Height, newSize.Width, newSize.Height - oldSize.Height);
  209. }
  210. foreach (var layer in scene.Layers)
  211. {
  212. layer.Dirty.Add(horizontalDirtyRect);
  213. layer.Dirty.Add(verticalDirtyRect);
  214. }
  215. }
  216. }
  217. private static VisualNode CreateNode(Scene scene, IVisual visual, VisualNode parent)
  218. {
  219. var node = new VisualNode(visual, parent);
  220. node.LayerRoot = parent.LayerRoot;
  221. scene.Add(node);
  222. return node;
  223. }
  224. private static void Deindex(Scene scene, VisualNode node)
  225. {
  226. foreach (VisualNode child in node.Children)
  227. {
  228. if (child is VisualNode visual)
  229. {
  230. Deindex(scene, visual);
  231. }
  232. }
  233. scene.Remove(node);
  234. node.SubTreeUpdated = true;
  235. scene.Layers[node.LayerRoot].Dirty.Add(node.Bounds);
  236. node.Visual.TransformedBounds = null;
  237. if (node.LayerRoot == node.Visual && node.Visual != scene.Root.Visual)
  238. {
  239. scene.Layers.Remove(node.LayerRoot);
  240. }
  241. }
  242. private static void ClearLayer(Scene scene, VisualNode node)
  243. {
  244. var parent = (VisualNode)node.Parent;
  245. var oldLayerRoot = node.LayerRoot;
  246. var newLayerRoot = parent.LayerRoot;
  247. var existingDirtyRects = scene.Layers[node.LayerRoot].Dirty;
  248. var newDirtyRects = scene.Layers[newLayerRoot].Dirty;
  249. existingDirtyRects.Coalesce();
  250. foreach (var r in existingDirtyRects)
  251. {
  252. newDirtyRects.Add(r);
  253. }
  254. var oldLayer = scene.Layers[oldLayerRoot];
  255. PropagateLayer(node, scene.Layers[newLayerRoot], oldLayer);
  256. scene.Layers.Remove(oldLayer);
  257. }
  258. private static void MakeLayer(Scene scene, VisualNode node)
  259. {
  260. var oldLayerRoot = node.LayerRoot;
  261. var layer = scene.Layers.Add(node.Visual);
  262. var oldLayer = scene.Layers[oldLayerRoot];
  263. UpdateLayer(node, layer);
  264. PropagateLayer(node, layer, scene.Layers[oldLayerRoot]);
  265. }
  266. private static void UpdateLayer(VisualNode node, SceneLayer layer)
  267. {
  268. layer.Opacity = node.Visual.Opacity;
  269. if (node.Visual.OpacityMask != null)
  270. {
  271. layer.OpacityMask = node.Visual.OpacityMask?.ToImmutable();
  272. layer.OpacityMaskRect = node.ClipBounds;
  273. }
  274. else
  275. {
  276. layer.OpacityMask = null;
  277. layer.OpacityMaskRect = Rect.Empty;
  278. }
  279. layer.GeometryClip = node.HasAncestorGeometryClip ?
  280. CreateLayerGeometryClip(node) :
  281. null;
  282. }
  283. private static void PropagateLayer(VisualNode node, SceneLayer layer, SceneLayer oldLayer)
  284. {
  285. node.LayerRoot = layer.LayerRoot;
  286. layer.Dirty.Add(node.Bounds);
  287. oldLayer.Dirty.Add(node.Bounds);
  288. foreach (VisualNode child in node.Children)
  289. {
  290. // If the child is not the start of a new layer, recurse.
  291. if (child.LayerRoot != child.Visual)
  292. {
  293. PropagateLayer(child, layer, oldLayer);
  294. }
  295. }
  296. }
  297. private static bool ShouldStartLayer(IVisual visual)
  298. {
  299. var o = visual as IAvaloniaObject;
  300. return visual.VisualChildren.Count > 0 &&
  301. o != null &&
  302. o.IsAnimating(Visual.OpacityProperty);
  303. }
  304. private static IGeometryImpl CreateLayerGeometryClip(VisualNode node)
  305. {
  306. IGeometryImpl result = null;
  307. for (;;)
  308. {
  309. node = (VisualNode)node.Parent;
  310. if (node == null || (node.GeometryClip == null && !node.HasAncestorGeometryClip))
  311. {
  312. break;
  313. }
  314. if (node?.GeometryClip != null)
  315. {
  316. var transformed = node.GeometryClip.WithTransform(node.Transform);
  317. result = result == null ? transformed : result.Intersect(transformed);
  318. }
  319. }
  320. return result;
  321. }
  322. }
  323. }