DeferredDrawingContextImpl.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  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 Avalonia.Media;
  6. using Avalonia.Platform;
  7. using Avalonia.VisualTree;
  8. namespace Avalonia.Rendering.SceneGraph
  9. {
  10. /// <summary>
  11. /// A drawing context which builds a scene graph.
  12. /// </summary>
  13. internal class DeferredDrawingContextImpl : IDrawingContextImpl
  14. {
  15. private readonly ISceneBuilder _sceneBuilder;
  16. private VisualNode _node;
  17. private int _childIndex;
  18. private int _drawOperationindex;
  19. /// <summary>
  20. /// Initializes a new instance of the <see cref="DeferredDrawingContextImpl"/> class.
  21. /// </summary>
  22. /// <param name="sceneBuilder">
  23. /// A scene builder used for constructing child scenes for visual brushes.
  24. /// </param>
  25. /// <param name="layers">The scene layers.</param>
  26. public DeferredDrawingContextImpl(ISceneBuilder sceneBuilder, SceneLayers layers)
  27. {
  28. _sceneBuilder = sceneBuilder;
  29. Layers = layers;
  30. }
  31. /// <inheritdoc/>
  32. public Matrix Transform { get; set; } = Matrix.Identity;
  33. /// <summary>
  34. /// Gets the layers in the scene being built.
  35. /// </summary>
  36. public SceneLayers Layers { get; }
  37. /// <summary>
  38. /// Informs the drawing context of the visual node that is about to be rendered.
  39. /// </summary>
  40. /// <param name="node">The visual node.</param>
  41. /// <returns>
  42. /// An object which when disposed will commit the changes to visual node.
  43. /// </returns>
  44. public UpdateState BeginUpdate(VisualNode node)
  45. {
  46. Contract.Requires<ArgumentNullException>(node != null);
  47. if (_node != null)
  48. {
  49. if (_childIndex < _node.Children.Count)
  50. {
  51. _node.ReplaceChild(_childIndex, node);
  52. }
  53. else
  54. {
  55. _node.AddChild(node);
  56. }
  57. ++_childIndex;
  58. }
  59. var state = new UpdateState(this, _node, _childIndex, _drawOperationindex);
  60. _node = node;
  61. _childIndex = _drawOperationindex = 0;
  62. return state;
  63. }
  64. /// <inheritdoc/>
  65. public void Clear(Color color)
  66. {
  67. // Cannot clear a deferred scene.
  68. }
  69. /// <inheritdoc/>
  70. public void Dispose()
  71. {
  72. // Nothing to do here as we allocate no unmanaged resources.
  73. }
  74. /// <summary>
  75. /// Removes any remaining drawing operations from the visual node.
  76. /// </summary>
  77. /// <remarks>
  78. /// Drawing operations are updated in place, overwriting existing drawing operations if
  79. /// they are different. Once drawing has completed for the current visual node, it is
  80. /// possible that there are stale drawing operations at the end of the list. This method
  81. /// trims these stale drawing operations.
  82. /// </remarks>
  83. public void TrimChildren()
  84. {
  85. _node.TrimChildren(_childIndex);
  86. }
  87. /// <inheritdoc/>
  88. public void DrawGeometry(IBrush brush, Pen pen, IGeometryImpl geometry)
  89. {
  90. var next = NextDrawAs<GeometryNode>();
  91. if (next == null || !next.Equals(Transform, brush, pen, geometry))
  92. {
  93. Add(new GeometryNode(Transform, brush, pen, geometry, CreateChildScene(brush)));
  94. }
  95. else
  96. {
  97. ++_drawOperationindex;
  98. }
  99. }
  100. /// <inheritdoc/>
  101. public void DrawImage(IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect)
  102. {
  103. var next = NextDrawAs<ImageNode>();
  104. if (next == null || !next.Equals(Transform, source, opacity, sourceRect, destRect))
  105. {
  106. Add(new ImageNode(Transform, source, opacity, sourceRect, destRect));
  107. }
  108. else
  109. {
  110. ++_drawOperationindex;
  111. }
  112. }
  113. /// <inheritdoc/>
  114. public void DrawImage(IBitmapImpl source, IBrush opacityMask, Rect opacityMaskRect, Rect sourceRect)
  115. {
  116. throw new NotImplementedException();
  117. }
  118. /// <inheritdoc/>
  119. public void DrawLine(Pen pen, Point p1, Point p2)
  120. {
  121. var next = NextDrawAs<LineNode>();
  122. if (next == null || !next.Equals(Transform, pen, p1, p2))
  123. {
  124. Add(new LineNode(Transform, pen, p1, p2, CreateChildScene(pen.Brush)));
  125. }
  126. else
  127. {
  128. ++_drawOperationindex;
  129. }
  130. }
  131. /// <inheritdoc/>
  132. public void DrawRectangle(Pen pen, Rect rect, float cornerRadius = 0)
  133. {
  134. var next = NextDrawAs<RectangleNode>();
  135. if (next == null || !next.Equals(Transform, null, pen, rect, cornerRadius))
  136. {
  137. Add(new RectangleNode(Transform, null, pen, rect, cornerRadius, CreateChildScene(pen.Brush)));
  138. }
  139. else
  140. {
  141. ++_drawOperationindex;
  142. }
  143. }
  144. /// <inheritdoc/>
  145. public void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text)
  146. {
  147. var next = NextDrawAs<TextNode>();
  148. if (next == null || !next.Equals(Transform, foreground, origin, text))
  149. {
  150. Add(new TextNode(Transform, foreground, origin, text, CreateChildScene(foreground)));
  151. }
  152. else
  153. {
  154. ++_drawOperationindex;
  155. }
  156. }
  157. /// <inheritdoc/>
  158. public void FillRectangle(IBrush brush, Rect rect, float cornerRadius = 0)
  159. {
  160. var next = NextDrawAs<RectangleNode>();
  161. if (next == null || !next.Equals(Transform, brush, null, rect, cornerRadius))
  162. {
  163. Add(new RectangleNode(Transform, brush, null, rect, cornerRadius, CreateChildScene(brush)));
  164. }
  165. else
  166. {
  167. ++_drawOperationindex;
  168. }
  169. }
  170. /// <inheritdoc/>
  171. public void PopClip()
  172. {
  173. var next = NextDrawAs<ClipNode>();
  174. if (next == null || !next.Equals(null))
  175. {
  176. Add(new ClipNode());
  177. }
  178. else
  179. {
  180. ++_drawOperationindex;
  181. }
  182. }
  183. /// <inheritdoc/>
  184. public void PopGeometryClip()
  185. {
  186. var next = NextDrawAs<GeometryClipNode>();
  187. if (next == null || !next.Equals(null))
  188. {
  189. Add(new GeometryClipNode());
  190. }
  191. else
  192. {
  193. ++_drawOperationindex;
  194. }
  195. }
  196. /// <inheritdoc/>
  197. public void PopOpacity()
  198. {
  199. var next = NextDrawAs<OpacityNode>();
  200. if (next == null || !next.Equals(null))
  201. {
  202. Add(new OpacityNode());
  203. }
  204. else
  205. {
  206. ++_drawOperationindex;
  207. }
  208. }
  209. /// <inheritdoc/>
  210. public void PopOpacityMask()
  211. {
  212. var next = NextDrawAs<OpacityMaskNode>();
  213. if (next == null || !next.Equals(null, null))
  214. {
  215. Add(new OpacityMaskNode());
  216. }
  217. else
  218. {
  219. ++_drawOperationindex;
  220. }
  221. }
  222. /// <inheritdoc/>
  223. public void PushClip(Rect clip)
  224. {
  225. var next = NextDrawAs<ClipNode>();
  226. if (next == null || !next.Equals(clip))
  227. {
  228. Add(new ClipNode(clip));
  229. }
  230. else
  231. {
  232. ++_drawOperationindex;
  233. }
  234. }
  235. /// <inheritdoc/>
  236. public void PushGeometryClip(IGeometryImpl clip)
  237. {
  238. var next = NextDrawAs<GeometryClipNode>();
  239. if (next == null || !next.Equals(clip))
  240. {
  241. Add(new GeometryClipNode(clip));
  242. }
  243. else
  244. {
  245. ++_drawOperationindex;
  246. }
  247. }
  248. /// <inheritdoc/>
  249. public void PushOpacity(double opacity)
  250. {
  251. var next = NextDrawAs<OpacityNode>();
  252. if (next == null || !next.Equals(opacity))
  253. {
  254. Add(new OpacityNode(opacity));
  255. }
  256. else
  257. {
  258. ++_drawOperationindex;
  259. }
  260. }
  261. /// <inheritdoc/>
  262. public void PushOpacityMask(IBrush mask, Rect bounds)
  263. {
  264. var next = NextDrawAs<OpacityMaskNode>();
  265. if (next == null || !next.Equals(mask, bounds))
  266. {
  267. Add(new OpacityMaskNode(mask, bounds, CreateChildScene(mask)));
  268. }
  269. else
  270. {
  271. ++_drawOperationindex;
  272. }
  273. }
  274. public struct UpdateState : IDisposable
  275. {
  276. public UpdateState(
  277. DeferredDrawingContextImpl owner,
  278. VisualNode node,
  279. int childIndex,
  280. int drawOperationIndex)
  281. {
  282. Owner = owner;
  283. Node = node;
  284. ChildIndex = childIndex;
  285. DrawOperationIndex = drawOperationIndex;
  286. }
  287. public void Dispose()
  288. {
  289. Owner._node.TrimDrawOperations(Owner._drawOperationindex);
  290. var dirty = Owner.Layers.GetOrAdd(Owner._node.LayerRoot).Dirty;
  291. foreach (var operation in Owner._node.DrawOperations)
  292. {
  293. dirty.Add(operation.Bounds);
  294. }
  295. Owner._node = Node;
  296. Owner._childIndex = ChildIndex;
  297. Owner._drawOperationindex = DrawOperationIndex;
  298. }
  299. public DeferredDrawingContextImpl Owner { get; }
  300. public VisualNode Node { get; }
  301. public int ChildIndex { get; }
  302. public int DrawOperationIndex { get; }
  303. }
  304. private void Add(IDrawOperation node)
  305. {
  306. if (_drawOperationindex < _node.DrawOperations.Count)
  307. {
  308. _node.ReplaceDrawOperation(_drawOperationindex, node);
  309. }
  310. else
  311. {
  312. _node.AddDrawOperation(node);
  313. }
  314. ++_drawOperationindex;
  315. }
  316. private T NextDrawAs<T>() where T : class, IDrawOperation
  317. {
  318. return _drawOperationindex < _node.DrawOperations.Count ? _node.DrawOperations[_drawOperationindex] as T : null;
  319. }
  320. private IDictionary<IVisual, Scene> CreateChildScene(IBrush brush)
  321. {
  322. var visualBrush = brush as VisualBrush;
  323. if (visualBrush != null)
  324. {
  325. var visual = visualBrush.Visual;
  326. if (visual != null)
  327. {
  328. (visual as IVisualBrushInitialize)?.EnsureInitialized();
  329. var scene = new Scene(visual);
  330. _sceneBuilder.UpdateAll(scene);
  331. return new Dictionary<IVisual, Scene> { { visualBrush.Visual, scene } };
  332. }
  333. }
  334. return null;
  335. }
  336. }
  337. }