DeferredDrawingContextImpl.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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.VisualTree;
  10. namespace Avalonia.Rendering.SceneGraph
  11. {
  12. public class DeferredDrawingContextImpl : IDrawingContextImpl
  13. {
  14. private Stack<Frame> _stack = new Stack<Frame>();
  15. public Matrix Transform { get; set; }
  16. private VisualNode Node => _stack.Peek().Node;
  17. private int Index
  18. {
  19. get { return _stack.Peek().Index; }
  20. set { _stack.Peek().Index = value; }
  21. }
  22. public IDisposable Begin(VisualNode node)
  23. {
  24. if (_stack.Count > 0)
  25. {
  26. var next = NextNodeAs<VisualNode>();
  27. if (next == null || next != node)
  28. {
  29. Add(node);
  30. }
  31. else
  32. {
  33. ++Index;
  34. }
  35. }
  36. _stack.Push(new Frame(node));
  37. return Disposable.Create(Pop);
  38. }
  39. public void Dispose()
  40. {
  41. }
  42. public void TrimNodes()
  43. {
  44. var frame = _stack.Peek();
  45. var children = frame.Node.Children;
  46. var index = frame.Index;
  47. if (children.Count > index)
  48. {
  49. children.RemoveRange(index, children.Count - index);
  50. }
  51. }
  52. public void DrawGeometry(IBrush brush, Pen pen, IGeometryImpl geometry)
  53. {
  54. var next = NextNodeAs<GeometryNode>();
  55. if (next == null || !next.Equals(Transform, brush, pen, geometry))
  56. {
  57. Add(new GeometryNode(Transform, brush, pen, geometry));
  58. }
  59. else
  60. {
  61. ++Index;
  62. }
  63. }
  64. public void DrawImage(IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect)
  65. {
  66. var next = NextNodeAs<ImageNode>();
  67. if (next == null || !next.Equals(Transform, source, opacity, sourceRect, destRect))
  68. {
  69. Add(new ImageNode(Transform, source, opacity, sourceRect, destRect));
  70. }
  71. else
  72. {
  73. ++Index;
  74. }
  75. }
  76. public void DrawLine(Pen pen, Point p1, Point p2)
  77. {
  78. var next = NextNodeAs<LineNode>();
  79. if (next == null || !next.Equals(Transform, pen, p1, p2))
  80. {
  81. Add(new LineNode(Transform, pen, p1, p2));
  82. }
  83. else
  84. {
  85. ++Index;
  86. }
  87. }
  88. public void DrawRectangle(Pen pen, Rect rect, float cornerRadius = 0)
  89. {
  90. var next = NextNodeAs<RectangleNode>();
  91. if (next == null || !next.Equals(Transform, null, pen, rect, cornerRadius))
  92. {
  93. Add(new RectangleNode(Transform, null, pen, rect, cornerRadius));
  94. }
  95. else
  96. {
  97. ++Index;
  98. }
  99. }
  100. public void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text)
  101. {
  102. var next = NextNodeAs<TextNode>();
  103. if (next == null || !next.Equals(Transform, foreground, origin, text))
  104. {
  105. Add(new TextNode(Transform, foreground, origin, text));
  106. }
  107. else
  108. {
  109. ++Index;
  110. }
  111. }
  112. public void FillRectangle(IBrush brush, Rect rect, float cornerRadius = 0)
  113. {
  114. var next = NextNodeAs<RectangleNode>();
  115. if (next == null || !next.Equals(Transform, brush, null, rect, cornerRadius))
  116. {
  117. Add(new RectangleNode(Transform, brush, null, rect, cornerRadius));
  118. }
  119. else
  120. {
  121. ++Index;
  122. }
  123. }
  124. public void PopClip()
  125. {
  126. // TODO: Implement
  127. }
  128. public void PopGeometryClip()
  129. {
  130. // TODO: Implement
  131. }
  132. public void PopOpacity()
  133. {
  134. // TODO: Implement
  135. }
  136. public void PopOpacityMask()
  137. {
  138. // TODO: Implement
  139. }
  140. public void PushClip(Rect clip)
  141. {
  142. // TODO: Implement
  143. }
  144. public void PushGeometryClip(Geometry clip)
  145. {
  146. // TODO: Implement
  147. }
  148. public void PushOpacity(double opacity)
  149. {
  150. // TODO: Implement
  151. }
  152. public void PushOpacityMask(IBrush mask, Rect bounds)
  153. {
  154. // TODO: Implement
  155. }
  156. private void Add(ISceneNode node)
  157. {
  158. var index = Index;
  159. if (index < Node.Children.Count)
  160. {
  161. Node.Children[index] = node;
  162. }
  163. else
  164. {
  165. Node.Children.Add(node);
  166. }
  167. ++Index;
  168. }
  169. private T NextNodeAs<T>() where T : class, ISceneNode
  170. {
  171. return Index < Node.Children.Count ? Node.Children[Index] as T : null;
  172. }
  173. private void Pop() => _stack.Pop();
  174. class Frame
  175. {
  176. public Frame(VisualNode node)
  177. {
  178. Node = node;
  179. }
  180. public VisualNode Node { get; }
  181. public int Index { get; set; }
  182. }
  183. }
  184. }