DeferredDrawingContextImpl.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. using System;
  2. using System.Collections.Generic;
  3. using Avalonia.Media;
  4. using Avalonia.Platform;
  5. using Avalonia.Utilities;
  6. using Avalonia.Visuals.Media.Imaging;
  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, IDrawingContextWithAcrylicLikeSupport
  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 since 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, IPen pen, IGeometryImpl geometry)
  89. {
  90. var next = NextDrawAs<GeometryNode>();
  91. if (next == null || !next.Item.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 DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
  102. {
  103. var next = NextDrawAs<ImageNode>();
  104. if (next == null || !next.Item.Equals(Transform, source, opacity, sourceRect, destRect, bitmapInterpolationMode))
  105. {
  106. Add(new ImageNode(Transform, source, opacity, sourceRect, destRect, bitmapInterpolationMode));
  107. }
  108. else
  109. {
  110. ++_drawOperationindex;
  111. }
  112. }
  113. /// <inheritdoc/>
  114. public void DrawBitmap(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect sourceRect)
  115. {
  116. // This method is currently only used to composite layers so shouldn't be called here.
  117. throw new NotSupportedException();
  118. }
  119. /// <inheritdoc/>
  120. public void DrawLine(IPen pen, Point p1, Point p2)
  121. {
  122. var next = NextDrawAs<LineNode>();
  123. if (next == null || !next.Item.Equals(Transform, pen, p1, p2))
  124. {
  125. Add(new LineNode(Transform, pen, p1, p2, CreateChildScene(pen.Brush)));
  126. }
  127. else
  128. {
  129. ++_drawOperationindex;
  130. }
  131. }
  132. /// <inheritdoc/>
  133. public void DrawRectangle(IBrush brush, IPen pen, RoundedRect rect,
  134. BoxShadows boxShadows = default)
  135. {
  136. var next = NextDrawAs<RectangleNode>();
  137. if (next == null || !next.Item.Equals(Transform, brush, pen, rect, boxShadows))
  138. {
  139. Add(new RectangleNode(Transform, brush, pen, rect, boxShadows, CreateChildScene(brush)));
  140. }
  141. else
  142. {
  143. ++_drawOperationindex;
  144. }
  145. }
  146. /// <inheritdoc/>
  147. public void DrawRectangle(IExperimentalAcrylicMaterial material, RoundedRect rect)
  148. {
  149. var next = NextDrawAs<ExperimentalAcrylicNode>();
  150. if (next == null || !next.Item.Equals(Transform, material, rect))
  151. {
  152. Add(new ExperimentalAcrylicNode(Transform, material, rect));
  153. }
  154. else
  155. {
  156. ++_drawOperationindex;
  157. }
  158. }
  159. public void Custom(ICustomDrawOperation custom)
  160. {
  161. var next = NextDrawAs<CustomDrawOperation>();
  162. if (next == null || !next.Item.Equals(Transform, custom))
  163. Add(new CustomDrawOperation(custom, Transform));
  164. else
  165. ++_drawOperationindex;
  166. }
  167. /// <inheritdoc/>
  168. public void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text)
  169. {
  170. var next = NextDrawAs<TextNode>();
  171. if (next == null || !next.Item.Equals(Transform, foreground, origin, text))
  172. {
  173. Add(new TextNode(Transform, foreground, origin, text, CreateChildScene(foreground)));
  174. }
  175. else
  176. {
  177. ++_drawOperationindex;
  178. }
  179. }
  180. /// <inheritdoc/>
  181. public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
  182. {
  183. var next = NextDrawAs<GlyphRunNode>();
  184. if (next == null || !next.Item.Equals(Transform, foreground, glyphRun))
  185. {
  186. Add(new GlyphRunNode(Transform, foreground, glyphRun, CreateChildScene(foreground)));
  187. }
  188. else
  189. {
  190. ++_drawOperationindex;
  191. }
  192. }
  193. public IRenderTargetBitmapImpl CreateLayer(Size size)
  194. {
  195. throw new NotSupportedException("Creating layers on a deferred drawing context not supported");
  196. }
  197. /// <inheritdoc/>
  198. public void PopClip()
  199. {
  200. var next = NextDrawAs<ClipNode>();
  201. if (next == null || !next.Item.Equals(null))
  202. {
  203. Add(new ClipNode());
  204. }
  205. else
  206. {
  207. ++_drawOperationindex;
  208. }
  209. }
  210. /// <inheritdoc/>
  211. public void PopGeometryClip()
  212. {
  213. var next = NextDrawAs<GeometryClipNode>();
  214. if (next == null || !next.Item.Equals(null))
  215. {
  216. Add((new GeometryClipNode()));
  217. }
  218. else
  219. {
  220. ++_drawOperationindex;
  221. }
  222. }
  223. /// <inheritdoc/>
  224. public void PopOpacity()
  225. {
  226. var next = NextDrawAs<OpacityNode>();
  227. if (next == null || !next.Item.Equals(null))
  228. {
  229. Add(new OpacityNode());
  230. }
  231. else
  232. {
  233. ++_drawOperationindex;
  234. }
  235. }
  236. /// <inheritdoc/>
  237. public void PopOpacityMask()
  238. {
  239. var next = NextDrawAs<OpacityMaskNode>();
  240. if (next == null || !next.Item.Equals(null, null))
  241. {
  242. Add(new OpacityMaskNode());
  243. }
  244. else
  245. {
  246. ++_drawOperationindex;
  247. }
  248. }
  249. /// <inheritdoc/>
  250. public void PushClip(Rect clip)
  251. {
  252. var next = NextDrawAs<ClipNode>();
  253. if (next == null || !next.Item.Equals(clip))
  254. {
  255. Add(new ClipNode(clip));
  256. }
  257. else
  258. {
  259. ++_drawOperationindex;
  260. }
  261. }
  262. /// <inheritdoc />
  263. public void PushClip(RoundedRect clip)
  264. {
  265. var next = NextDrawAs<ClipNode>();
  266. if (next == null || !next.Item.Equals(clip))
  267. {
  268. Add(new ClipNode(clip));
  269. }
  270. else
  271. {
  272. ++_drawOperationindex;
  273. }
  274. }
  275. /// <inheritdoc/>
  276. public void PushGeometryClip(IGeometryImpl clip)
  277. {
  278. var next = NextDrawAs<GeometryClipNode>();
  279. if (next == null || !next.Item.Equals(clip))
  280. {
  281. Add(new GeometryClipNode(clip));
  282. }
  283. else
  284. {
  285. ++_drawOperationindex;
  286. }
  287. }
  288. /// <inheritdoc/>
  289. public void PushOpacity(double opacity)
  290. {
  291. var next = NextDrawAs<OpacityNode>();
  292. if (next == null || !next.Item.Equals(opacity))
  293. {
  294. Add(new OpacityNode(opacity));
  295. }
  296. else
  297. {
  298. ++_drawOperationindex;
  299. }
  300. }
  301. /// <inheritdoc/>
  302. public void PushOpacityMask(IBrush mask, Rect bounds)
  303. {
  304. var next = NextDrawAs<OpacityMaskNode>();
  305. if (next == null || !next.Item.Equals(mask, bounds))
  306. {
  307. Add(new OpacityMaskNode(mask, bounds, CreateChildScene(mask)));
  308. }
  309. else
  310. {
  311. ++_drawOperationindex;
  312. }
  313. }
  314. public readonly struct UpdateState : IDisposable
  315. {
  316. public UpdateState(
  317. DeferredDrawingContextImpl owner,
  318. VisualNode node,
  319. int childIndex,
  320. int drawOperationIndex)
  321. {
  322. Owner = owner;
  323. Node = node;
  324. ChildIndex = childIndex;
  325. DrawOperationIndex = drawOperationIndex;
  326. }
  327. public void Dispose()
  328. {
  329. Owner._node.TrimDrawOperations(Owner._drawOperationindex);
  330. var dirty = Owner.Layers.GetOrAdd(Owner._node.LayerRoot).Dirty;
  331. foreach (var operation in Owner._node.DrawOperations)
  332. {
  333. dirty.Add(operation.Item.Bounds);
  334. }
  335. Owner._node = Node;
  336. Owner._childIndex = ChildIndex;
  337. Owner._drawOperationindex = DrawOperationIndex;
  338. }
  339. public DeferredDrawingContextImpl Owner { get; }
  340. public VisualNode Node { get; }
  341. public int ChildIndex { get; }
  342. public int DrawOperationIndex { get; }
  343. }
  344. private void Add<T>(T node) where T : class, IDrawOperation
  345. {
  346. using (var refCounted = RefCountable.Create(node))
  347. {
  348. Add(refCounted);
  349. }
  350. }
  351. private void Add(IRef<IDrawOperation> node)
  352. {
  353. if (_drawOperationindex < _node.DrawOperations.Count)
  354. {
  355. _node.ReplaceDrawOperation(_drawOperationindex, node);
  356. }
  357. else
  358. {
  359. _node.AddDrawOperation(node);
  360. }
  361. ++_drawOperationindex;
  362. }
  363. private IRef<T> NextDrawAs<T>() where T : class, IDrawOperation
  364. {
  365. return _drawOperationindex < _node.DrawOperations.Count ? _node.DrawOperations[_drawOperationindex] as IRef<T> : null;
  366. }
  367. private IDictionary<IVisual, Scene> CreateChildScene(IBrush brush)
  368. {
  369. var visualBrush = brush as VisualBrush;
  370. if (visualBrush != null)
  371. {
  372. var visual = visualBrush.Visual;
  373. if (visual != null)
  374. {
  375. (visual as IVisualBrushInitialize)?.EnsureInitialized();
  376. var scene = new Scene(visual);
  377. _sceneBuilder.UpdateAll(scene);
  378. return new Dictionary<IVisual, Scene> { { visualBrush.Visual, scene } };
  379. }
  380. }
  381. return null;
  382. }
  383. }
  384. }