SceneBuilder.cs 14 KB

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