CrossUI.Avalonia.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. #nullable enable
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using Avalonia.Controls;
  6. using Avalonia.Media;
  7. using Avalonia.Media.Imaging;
  8. using Avalonia.Media.Immutable;
  9. using CrossUI;
  10. namespace CrossUI
  11. {
  12. using Avalonia;
  13. public partial class CrossGlobals
  14. {
  15. public static ICrossStreamGeometryContextImplProvider GetContextImplProvider()
  16. {
  17. return new AvaloniaCrossStreamGeometryContextImplProvider();
  18. }
  19. }
  20. public class AvaloniaCrossStreamGeometryContextImplProvider : ICrossStreamGeometryContextImplProvider
  21. {
  22. public ICrossStreamGeometryContextImpl Create()
  23. {
  24. return new AvaloniaCrossStreamGeometryContextImpl();
  25. }
  26. }
  27. public class AvaloniaCrossStreamGeometryContextImpl : ICrossStreamGeometryContextImpl
  28. {
  29. private StreamGeometry _streamGeometry;
  30. private StreamGeometryContext _context;
  31. private bool _isClosed;
  32. public AvaloniaCrossStreamGeometryContextImpl()
  33. {
  34. _streamGeometry = new StreamGeometry();
  35. _context = _streamGeometry.Open();
  36. }
  37. public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection, bool isStroked)
  38. {
  39. _context.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection, isStroked);
  40. }
  41. public void BeginFigure(Point point, bool isFilled, bool isClosed)
  42. {
  43. _isClosed = isClosed;
  44. _context.BeginFigure(point, isFilled);
  45. }
  46. public void CubicBezierTo(Point controlPoint1, Point controlPoint2, Point endPoint, bool isStroked)
  47. {
  48. _context.CubicBezierTo(controlPoint1, controlPoint2, endPoint, isStroked);
  49. }
  50. public void Dispose()
  51. {
  52. _context.Dispose();
  53. }
  54. public void EndFigure()
  55. {
  56. _context.EndFigure(_isClosed);
  57. Dispose();
  58. }
  59. public object GetGeometry()
  60. {
  61. return _streamGeometry;
  62. }
  63. public void LineTo(Point point, bool isStroked)
  64. {
  65. _context.LineTo(point, isStroked);
  66. }
  67. public void QuadraticBezierTo(Point controlPoint, Point endPoint, bool isStroked)
  68. {
  69. _context.QuadraticBezierTo(controlPoint, endPoint, isStroked);
  70. }
  71. }
  72. }
  73. namespace Avalonia.Skia.RenderTests.CrossUI
  74. {
  75. class AvaloniaCrossControl : Control
  76. {
  77. private readonly CrossControl _src;
  78. private readonly Dictionary<CrossControl, AvaloniaCrossControl> _children;
  79. public AvaloniaCrossControl(CrossControl src)
  80. {
  81. _src = src;
  82. _children = src.Children.ToDictionary(x => x, x => new AvaloniaCrossControl(x));
  83. Width = src.Bounds.Width;
  84. Height = src.Bounds.Height;
  85. RenderTransform = new MatrixTransform(src.RenderTransform);
  86. RenderTransformOrigin = new RelativePoint(default, RelativeUnit.Relative);
  87. RenderOptions = RenderOptions with { BitmapInterpolationMode = src.BitmapInterpolationMode };
  88. foreach (var ch in src.Children)
  89. {
  90. var c = _children[ch];
  91. VisualChildren.Add(c);
  92. LogicalChildren.Add(c);
  93. }
  94. }
  95. protected override Size MeasureOverride(Size availableSize)
  96. {
  97. foreach (var ch in _children)
  98. ch.Value.Measure(ch.Key.Bounds.Size);
  99. return _src.Bounds.Size;
  100. }
  101. protected override Size ArrangeOverride(Size finalSize)
  102. {
  103. foreach (var ch in _children)
  104. ch.Value.Arrange(ch.Key.Bounds);
  105. return finalSize;
  106. }
  107. public override void Render(DrawingContext context)
  108. {
  109. _src.Render(new AvaloniaCrossDrawingContext(context));
  110. }
  111. }
  112. class AvaloniaCrossDrawingContext : ICrossDrawingContext
  113. {
  114. private readonly DrawingContext _ctx;
  115. private readonly Stack<DrawingContext.PushedState> _stack = new();
  116. public AvaloniaCrossDrawingContext(DrawingContext ctx)
  117. {
  118. _ctx = ctx;
  119. }
  120. static Transform? ConvertTransform(Matrix? m) => m == null ? null : new MatrixTransform(m.Value);
  121. static RelativeRect ConvertRect(Rect rc, BrushMappingMode mode)
  122. => new RelativeRect(rc,
  123. mode == BrushMappingMode.RelativeToBoundingBox ? RelativeUnit.Relative : RelativeUnit.Absolute);
  124. static RelativePoint ConvertPoint(Point pt, BrushMappingMode mode)
  125. => new(pt, mode == BrushMappingMode.RelativeToBoundingBox ? RelativeUnit.Relative : RelativeUnit.Absolute);
  126. static RelativeScalar ConvertScalar(double scalar, BrushMappingMode mode)
  127. => new(scalar, mode == BrushMappingMode.RelativeToBoundingBox ? RelativeUnit.Relative : RelativeUnit.Absolute);
  128. static Geometry ConvertGeometry(CrossGeometry g)
  129. {
  130. switch (g)
  131. {
  132. case CrossRectangleGeometry rg:
  133. return new RectangleGeometry(rg.Rect);
  134. case CrossSvgGeometry svg:
  135. return PathGeometry.Parse(svg.Path);
  136. case CrossEllipseGeometry ellipse:
  137. return new EllipseGeometry(ellipse.Rect);
  138. case CrossStreamGeometry streamGeometry:
  139. return (StreamGeometry)streamGeometry.GetContext().GetGeometry();
  140. case CrossPathGeometry path:
  141. return new PathGeometry()
  142. {
  143. Figures = RetAddRange(new PathFigures(), path.Figures.Select(f =>
  144. new PathFigure()
  145. {
  146. StartPoint = f.Start,
  147. IsClosed = f.Closed,
  148. Segments = RetAddRange<PathSegments, PathSegment>(new PathSegments(),
  149. f.Segments.Select<CrossPathSegment, PathSegment>(s =>
  150. s switch
  151. {
  152. CrossPathSegment.Line l => new LineSegment()
  153. {
  154. Point = l.To,
  155. IsStroked = l.IsStroked
  156. },
  157. CrossPathSegment.Arc a => new ArcSegment()
  158. {
  159. Point = a.Point,
  160. RotationAngle = a.RotationAngle,
  161. Size = a.Size,
  162. IsLargeArc = a.IsLargeArc,
  163. SweepDirection = a.SweepDirection,
  164. IsStroked = a.IsStroked
  165. },
  166. CrossPathSegment.CubicBezier c => new BezierSegment()
  167. {
  168. Point1 = c.Point1,
  169. Point2 = c.Point2,
  170. Point3 = c.Point3,
  171. IsStroked = c.IsStroked
  172. },
  173. CrossPathSegment.QuadraticBezier q => new QuadraticBezierSegment()
  174. {
  175. Point1 = q.Point1,
  176. Point2 = q.Point2,
  177. IsStroked = q.IsStroked
  178. },
  179. CrossPathSegment.PolyLine p => new PolyLineSegment()
  180. {
  181. Points = p.Points.ToList(),
  182. IsStroked = p.IsStroked
  183. },
  184. CrossPathSegment.PolyBezierSegment p => new PolyBezierSegment(p.Points,p.IsStroked),
  185. _ => throw new InvalidOperationException()
  186. }))
  187. }))
  188. };
  189. default:
  190. throw new NotSupportedException();
  191. }
  192. }
  193. static TList RetAddRange<TList, T>(TList l, IEnumerable<T> en) where TList : IList<T>
  194. {
  195. foreach(var e in en)
  196. l.Add(e);
  197. return l;
  198. }
  199. static Drawing ConvertDrawing(CrossDrawing src)
  200. {
  201. if (src is CrossDrawingGroup g)
  202. return new DrawingGroup() { Children = new DrawingCollection(g.Children.Select(ConvertDrawing)) };
  203. if (src is CrossGeometryDrawing geo)
  204. return new GeometryDrawing()
  205. {
  206. Geometry = ConvertGeometry(geo.Geometry), Brush = ConvertBrush(geo.Brush), Pen = ConvertPen(geo.Pen)
  207. };
  208. throw new NotSupportedException();
  209. }
  210. static IBrush? ConvertBrush(CrossBrush? brush)
  211. {
  212. if (brush == null)
  213. return null;
  214. static Brush Sync(Brush dst, CrossBrush src)
  215. {
  216. dst.Opacity = src.Opacity;
  217. dst.Transform = ConvertTransform(src.Transform);
  218. dst.TransformOrigin = new RelativePoint(default, RelativeUnit.Absolute);
  219. if (src.RelativeTransform != null)
  220. throw new PlatformNotSupportedException();
  221. return dst;
  222. }
  223. static Brush SyncTile(TileBrush dst, CrossTileBrush src)
  224. {
  225. dst.Stretch = src.Stretch;
  226. dst.AlignmentX = src.AlignmentX;
  227. dst.AlignmentY = src.AlignmentY;
  228. dst.TileMode = src.TileMode;
  229. dst.SourceRect = ConvertRect(src.Viewbox, src.ViewboxUnits);
  230. dst.DestinationRect = ConvertRect(src.Viewport, src.ViewportUnits);
  231. return Sync(dst, src);
  232. }
  233. static Brush SyncGradient(GradientBrush dst, CrossGradientBrush src)
  234. {
  235. dst.GradientStops = new GradientStops();
  236. dst.GradientStops.AddRange(src.GradientStops);
  237. dst.SpreadMethod = src.SpreadMethod;
  238. return Sync(dst, src);
  239. }
  240. if (brush is CrossSolidColorBrush br)
  241. return Sync(new SolidColorBrush(br.Color), brush);
  242. if (brush is CrossDrawingBrush db)
  243. return SyncTile(new DrawingBrush(ConvertDrawing(db.Drawing)), db);
  244. if (brush is CrossRadialGradientBrush radial)
  245. return SyncGradient(
  246. new RadialGradientBrush()
  247. {
  248. Center = ConvertPoint(radial.Center, radial.MappingMode),
  249. GradientOrigin = ConvertPoint(radial.GradientOrigin, radial.MappingMode),
  250. RadiusX = ConvertScalar(radial.RadiusX, radial.MappingMode),
  251. RadiusY = ConvertScalar(radial.RadiusY, radial.MappingMode)
  252. }, radial);
  253. throw new NotSupportedException();
  254. }
  255. static IPen? ConvertPen(CrossPen? pen)
  256. {
  257. if (pen == null)
  258. return null;
  259. return new Pen(ConvertBrush(pen.Brush), pen.Thickness) { LineCap = pen.LineCap, LineJoin = pen.LineJoin };
  260. }
  261. static IImage ConvertImage(CrossImage image)
  262. {
  263. if (image is CrossBitmapImage bi)
  264. return new Bitmap(bi.Path);
  265. if (image is CrossDrawingImage di)
  266. return new DrawingImage(ConvertDrawing(di.Drawing));
  267. throw new NotSupportedException();
  268. }
  269. public void PushTransform(Matrix matrix)
  270. {
  271. _stack.Push(_ctx.PushTransform(matrix));
  272. }
  273. public void Pop()
  274. {
  275. var state = _stack.Pop();
  276. state.Dispose();
  277. }
  278. public void DrawLine(CrossPen pen, Point p1, Point p2)
  279. {
  280. var avPen = ConvertPen(pen);
  281. if (avPen == null)
  282. {
  283. return;
  284. }
  285. _ctx.DrawLine(avPen, p1, p2);
  286. }
  287. public void DrawRectangle(CrossBrush? brush, CrossPen? pen, Rect rc) => _ctx.DrawRectangle(ConvertBrush(brush), ConvertPen(pen), rc);
  288. public void DrawGeometry(CrossBrush? brush, CrossPen? pen, CrossGeometry geometry) =>
  289. _ctx.DrawGeometry(ConvertBrush(brush), ConvertPen(pen), ConvertGeometry(geometry));
  290. public void DrawImage(CrossImage image, Rect rc) => _ctx.DrawImage(ConvertImage(image), rc);
  291. }
  292. }