PageRenderTime 62ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs

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