VisualNode.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  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.Collections.Generic;
  5. using System.Linq;
  6. using System.Reactive.Disposables;
  7. using Avalonia.Media;
  8. using Avalonia.Platform;
  9. using Avalonia.Utilities;
  10. using Avalonia.VisualTree;
  11. namespace Avalonia.Rendering.SceneGraph
  12. {
  13. /// <summary>
  14. /// A node in the low-level scene graph representing an <see cref="IVisual"/>.
  15. /// </summary>
  16. internal class VisualNode : IVisualNode
  17. {
  18. private static readonly IReadOnlyList<IVisualNode> EmptyChildren = new IVisualNode[0];
  19. private static readonly IReadOnlyList<IRef<IDrawOperation>> EmptyDrawOperations = new IRef<IDrawOperation>[0];
  20. private Rect? _bounds;
  21. private double _opacity;
  22. private List<IVisualNode> _children;
  23. private List<IRef<IDrawOperation>> _drawOperations;
  24. private IRef<IDisposable> _drawOperationsRefCounter;
  25. private bool _drawOperationsCloned;
  26. private Matrix transformRestore;
  27. /// <summary>
  28. /// Initializes a new instance of the <see cref="VisualNode"/> class.
  29. /// </summary>
  30. /// <param name="visual">The visual that this node represents.</param>
  31. /// <param name="parent">The parent scene graph node, if any.</param>
  32. public VisualNode(IVisual visual, IVisualNode parent)
  33. {
  34. Contract.Requires<ArgumentNullException>(visual != null);
  35. Visual = visual;
  36. Parent = parent;
  37. HasAncestorGeometryClip = parent != null &&
  38. (parent.HasAncestorGeometryClip || parent.GeometryClip != null);
  39. }
  40. /// <inheritdoc/>
  41. public IVisual Visual { get; }
  42. /// <inheritdoc/>
  43. public IVisualNode Parent { get; }
  44. /// <inheritdoc/>
  45. public Matrix Transform { get; set; }
  46. /// <inheritdoc/>
  47. public Rect Bounds => _bounds ?? CalculateBounds();
  48. /// <inheritdoc/>
  49. public Rect ClipBounds { get; set; }
  50. /// <inheritdoc/>
  51. public Rect LayoutBounds { get; set; }
  52. /// <inheritdoc/>
  53. public bool ClipToBounds { get; set; }
  54. /// <inheritdoc/>
  55. public IGeometryImpl GeometryClip { get; set; }
  56. /// <inheritdoc/>
  57. public bool HasAncestorGeometryClip { get; }
  58. /// <inheritdoc/>
  59. public double Opacity
  60. {
  61. get { return _opacity; }
  62. set
  63. {
  64. if (_opacity != value)
  65. {
  66. _opacity = value;
  67. OpacityChanged = true;
  68. }
  69. }
  70. }
  71. /// <summary>
  72. /// Gets or sets the opacity mask for the scene graph node.
  73. /// </summary>
  74. public IBrush OpacityMask { get; set; }
  75. /// <summary>
  76. /// Gets a value indicating whether this node in the scene graph has already
  77. /// been updated in the current update pass.
  78. /// </summary>
  79. public bool SubTreeUpdated { get; set; }
  80. /// <summary>
  81. /// Gets a value indicating whether the <see cref="Opacity"/> property has changed.
  82. /// </summary>
  83. public bool OpacityChanged { get; private set; }
  84. public IVisual LayerRoot { get; set; }
  85. /// <inheritdoc/>
  86. public IReadOnlyList<IVisualNode> Children => _children ?? EmptyChildren;
  87. /// <inheritdoc/>
  88. public IReadOnlyList<IRef<IDrawOperation>> DrawOperations => _drawOperations ?? EmptyDrawOperations;
  89. /// <summary>
  90. /// Adds a child to the <see cref="Children"/> collection.
  91. /// </summary>
  92. /// <param name="child">The child to add.</param>
  93. public void AddChild(IVisualNode child)
  94. {
  95. if (child.Disposed)
  96. {
  97. throw new ObjectDisposedException("Visual node for {node.Visual}");
  98. }
  99. EnsureChildrenCreated();
  100. _children.Add(child);
  101. }
  102. /// <summary>
  103. /// Adds an operation to the <see cref="DrawOperations"/> collection.
  104. /// </summary>
  105. /// <param name="operation">The operation to add.</param>
  106. public void AddDrawOperation(IRef<IDrawOperation> operation)
  107. {
  108. EnsureDrawOperationsCreated();
  109. _drawOperations.Add(operation.Clone());
  110. }
  111. /// <summary>
  112. /// Removes a child from the <see cref="Children"/> collection.
  113. /// </summary>
  114. /// <param name="child">The child to remove.</param>
  115. public void RemoveChild(IVisualNode child)
  116. {
  117. EnsureChildrenCreated();
  118. _children.Remove(child);
  119. }
  120. /// <summary>
  121. /// Replaces a child in the <see cref="Children"/> collection.
  122. /// </summary>
  123. /// <param name="index">The child to be replaced.</param>
  124. /// <param name="node">The child to add.</param>
  125. public void ReplaceChild(int index, IVisualNode node)
  126. {
  127. if (node.Disposed)
  128. {
  129. throw new ObjectDisposedException("Visual node for {node.Visual}");
  130. }
  131. EnsureChildrenCreated();
  132. _children[index] = node;
  133. }
  134. /// <summary>
  135. /// Replaces an item in the <see cref="DrawOperations"/> collection.
  136. /// </summary>
  137. /// <param name="index">The operation to be replaced.</param>
  138. /// <param name="operation">The operation to add.</param>
  139. public void ReplaceDrawOperation(int index, IRef<IDrawOperation> operation)
  140. {
  141. EnsureDrawOperationsCreated();
  142. var old = _drawOperations[index];
  143. _drawOperations[index] = operation.Clone();
  144. old.Dispose();
  145. }
  146. /// <summary>
  147. /// Removes items in the <see cref="Children"/> collection from the specified index
  148. /// to the end.
  149. /// </summary>
  150. /// <param name="first">The index of the first child to be removed.</param>
  151. public void TrimChildren(int first)
  152. {
  153. if (first < _children?.Count)
  154. {
  155. EnsureChildrenCreated();
  156. for (int i = first; i < _children.Count - first; i++)
  157. {
  158. _children[i].Dispose();
  159. }
  160. _children.RemoveRange(first, _children.Count - first);
  161. }
  162. }
  163. /// <summary>
  164. /// Removes items in the <see cref="DrawOperations"/> collection from the specified index
  165. /// to the end.
  166. /// </summary>
  167. /// <param name="first">The index of the first operation to be removed.</param>
  168. public void TrimDrawOperations(int first)
  169. {
  170. if (first < _drawOperations?.Count)
  171. {
  172. EnsureDrawOperationsCreated();
  173. for (int i = first; i < _drawOperations.Count; i++)
  174. {
  175. _drawOperations[i].Dispose();
  176. }
  177. _drawOperations.RemoveRange(first, _drawOperations.Count - first);
  178. }
  179. }
  180. /// <summary>
  181. /// Makes a copy of the node
  182. /// </summary>
  183. /// <param name="parent">The new parent node.</param>
  184. /// <returns>A cloned node.</returns>
  185. public VisualNode Clone(IVisualNode parent)
  186. {
  187. return new VisualNode(Visual, parent)
  188. {
  189. Transform = Transform,
  190. ClipBounds = ClipBounds,
  191. ClipToBounds = ClipToBounds,
  192. LayoutBounds = LayoutBounds,
  193. GeometryClip = GeometryClip,
  194. _opacity = Opacity,
  195. OpacityMask = OpacityMask,
  196. _drawOperations = _drawOperations,
  197. _drawOperationsRefCounter = _drawOperationsRefCounter?.Clone(),
  198. _drawOperationsCloned = true,
  199. LayerRoot= LayerRoot,
  200. };
  201. }
  202. /// <inheritdoc/>
  203. public bool HitTest(Point p)
  204. {
  205. foreach (var operation in DrawOperations)
  206. {
  207. if (operation.Item.HitTest(p))
  208. {
  209. return true;
  210. }
  211. }
  212. return false;
  213. }
  214. /// <inheritdoc/>
  215. public void BeginRender(IDrawingContextImpl context, bool skipOpacity)
  216. {
  217. transformRestore = context.Transform;
  218. if (ClipToBounds)
  219. {
  220. context.Transform = Matrix.Identity;
  221. context.PushClip(ClipBounds);
  222. }
  223. context.Transform = Transform;
  224. if (Opacity != 1 && !skipOpacity)
  225. {
  226. context.PushOpacity(Opacity);
  227. }
  228. if (GeometryClip != null)
  229. {
  230. context.PushGeometryClip(GeometryClip);
  231. }
  232. if (OpacityMask != null)
  233. {
  234. context.PushOpacityMask(OpacityMask, LayoutBounds);
  235. }
  236. }
  237. /// <inheritdoc/>
  238. public void EndRender(IDrawingContextImpl context, bool skipOpacity)
  239. {
  240. if (OpacityMask != null)
  241. {
  242. context.PopOpacityMask();
  243. }
  244. if (GeometryClip != null)
  245. {
  246. context.PopGeometryClip();
  247. }
  248. if (Opacity != 1 && !skipOpacity)
  249. {
  250. context.PopOpacity();
  251. }
  252. if (ClipToBounds)
  253. {
  254. context.Transform = Matrix.Identity;
  255. context.PopClip();
  256. }
  257. context.Transform = transformRestore;
  258. }
  259. private Rect CalculateBounds()
  260. {
  261. var result = new Rect();
  262. foreach (var operation in DrawOperations)
  263. {
  264. result = result.Union(operation.Item.Bounds);
  265. }
  266. _bounds = result;
  267. return result;
  268. }
  269. private void EnsureChildrenCreated()
  270. {
  271. if (_children == null)
  272. {
  273. _children = new List<IVisualNode>();
  274. }
  275. }
  276. private void EnsureDrawOperationsCreated()
  277. {
  278. if (_drawOperations == null)
  279. {
  280. _drawOperations = new List<IRef<IDrawOperation>>();
  281. _drawOperationsRefCounter = RefCountable.Create(Disposable.Create(DisposeDrawOperations));
  282. _drawOperationsCloned = false;
  283. }
  284. else if (_drawOperationsCloned)
  285. {
  286. _drawOperations = new List<IRef<IDrawOperation>>(_drawOperations.Select(op => op.Clone()));
  287. _drawOperationsRefCounter.Dispose();
  288. _drawOperationsRefCounter = RefCountable.Create(Disposable.Create(DisposeDrawOperations));
  289. _drawOperationsCloned = false;
  290. }
  291. }
  292. public bool Disposed { get; }
  293. public void Dispose()
  294. {
  295. _drawOperationsRefCounter?.Dispose();
  296. }
  297. private void DisposeDrawOperations()
  298. {
  299. foreach (var operation in DrawOperations)
  300. {
  301. operation.Dispose();
  302. }
  303. }
  304. }
  305. }