DeferredDrawingContextImpl.cs 12 KB

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