diff --git a/src/Avalonia.Visuals/Media/PathGeometry.cs b/src/Avalonia.Visuals/Media/PathGeometry.cs index ecda07ada1..5cf98aa5e7 100644 --- a/src/Avalonia.Visuals/Media/PathGeometry.cs +++ b/src/Avalonia.Visuals/Media/PathGeometry.cs @@ -8,6 +8,8 @@ using Avalonia.Platform; namespace Avalonia.Media { + using Avalonia.Visuals.Platform; + public class PathGeometry : StreamGeometry { /// @@ -28,7 +30,7 @@ namespace Avalonia.Media static PathGeometry() { - FiguresProperty.Changed.AddClassHandler((s, e) => + FiguresProperty.Changed.AddClassHandler((s, e) => s.OnFiguresChanged(e.NewValue as PathFigures)); } @@ -40,6 +42,24 @@ namespace Avalonia.Media Figures = new PathFigures(); } + /// + /// Parses the specified path data to a . + /// + /// The s. + /// + public static new PathGeometry Parse(string pathData) + { + var pathGeometry = new PathGeometry(); + + using (var context = new PathGeometryContext(pathGeometry)) + using (var parser = new PathMarkupParser(context)) + { + parser.Parse(pathData); + } + + return pathGeometry; + } + /// /// Gets or sets the figures. /// diff --git a/src/Avalonia.Visuals/Media/PathMarkupParser.cs b/src/Avalonia.Visuals/Media/PathMarkupParser.cs index c3fcf19148..2ffff75de3 100644 --- a/src/Avalonia.Visuals/Media/PathMarkupParser.cs +++ b/src/Avalonia.Visuals/Media/PathMarkupParser.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; +using Avalonia.Platform; namespace Avalonia.Media { @@ -17,13 +18,6 @@ namespace Avalonia.Media public class PathMarkupParser : IDisposable { private static readonly string s_separatorPattern; - - private Point _currentPoint; - private Point? _previousControlPoint; - private PathGeometry _currentGeometry; - private PathFigure _currentFigure; - private bool _isDisposed; - private static readonly Dictionary s_commands = new Dictionary { @@ -40,11 +34,32 @@ namespace Avalonia.Media { 'Z', Command.Close }, }; + private IGeometryContext _geometryContext; + private Point _currentPoint; + private Point? _previousControlPoint; + private bool? _isOpen; + private bool _isDisposed; + static PathMarkupParser() { s_separatorPattern = CreatesSeparatorPattern(); } + /// + /// Initializes a new instance of the class. + /// + /// The geometry context. + /// geometryContext + public PathMarkupParser(IGeometryContext geometryContext) + { + if (geometryContext == null) + { + throw new ArgumentNullException(nameof(geometryContext)); + } + + _geometryContext = geometryContext; + } + private enum Command { None, @@ -61,13 +76,15 @@ namespace Avalonia.Media Close } - public PathGeometry Parse(string s) + /// + /// Parses the specified path data and writes the result to the geometryContext of this instance. + /// + /// The path data. + public void Parse(string pathData) { - _currentGeometry = new PathGeometry(); - - var tokens = ParseTokens(s); + var tokens = ParseTokens(pathData); - return CreateGeometry(tokens); + CreateGeometry(tokens); } void IDisposable.Dispose() @@ -84,9 +101,7 @@ namespace Avalonia.Media if (disposing) { - _currentFigure = null; - - _currentGeometry = null; + _geometryContext = null; } _isDisposed = true; @@ -118,11 +133,9 @@ namespace Avalonia.Media return center + -dir; } - private PathGeometry CreateGeometry(IEnumerable commandTokens) + private void CreateGeometry(IEnumerable commandTokens) { - _currentGeometry = new PathGeometry(); - - _currentPoint = new Point(); + _currentPoint = new Point(); foreach (var commandToken in commandTokens) { @@ -188,46 +201,32 @@ namespace Avalonia.Media break; } } - - return _currentGeometry; - } - - private void SetFillRule(CommandToken commandToken) - { - _currentGeometry.FillRule = commandToken.ReadFillRule(); } - private void CloseFigure() + private void CreateFigure() { - if (_currentFigure != null && !_currentFigure.IsClosed) - { - _currentFigure.IsClosed = true; - } - - _previousControlPoint = null; + _geometryContext.BeginFigure(_currentPoint); - _currentFigure = null; + this._isOpen = true; } - private void CreateFigure() + private void SetFillRule(CommandToken commandToken) { - _currentFigure = new PathFigure - { - StartPoint = _currentPoint, - IsClosed = false - }; + var fillRule = commandToken.ReadFillRule(); - _currentGeometry.Figures.Add(_currentFigure); + _geometryContext.SetFillRule(fillRule); } - private void AddSegment(PathSegment segment) + private void CloseFigure() { - if (_currentFigure == null) + if (_isOpen == true) { - CreateFigure(); + _geometryContext.EndFigure(true); } - _currentFigure.Segments.Add(segment); + _previousControlPoint = null; + + _isOpen = null; } private void AddMove(CommandToken commandToken) @@ -266,66 +265,64 @@ namespace Avalonia.Media ? commandToken.ReadRelativePoint(_currentPoint) : commandToken.ReadPoint(); - var lineSegment = new LineSegment + if (_isOpen == null) { - Point = _currentPoint - }; + CreateFigure(); + } - AddSegment(lineSegment); + _geometryContext.LineTo(_currentPoint); } private void AddHorizontalLine(CommandToken commandToken) { _currentPoint = commandToken.IsRelative - ? new Point(_currentPoint.X + commandToken.ReadDouble(), _currentPoint.Y) - : _currentPoint.WithX(commandToken.ReadDouble()); + ? new Point(_currentPoint.X + commandToken.ReadDouble(), _currentPoint.Y) + : _currentPoint.WithX(commandToken.ReadDouble()); - var lineSegment = new LineSegment + if (_isOpen == null) { - Point = _currentPoint - }; + CreateFigure(); + } - AddSegment(lineSegment); + _geometryContext.LineTo(_currentPoint); } private void AddVerticalLine(CommandToken commandToken) { _currentPoint = commandToken.IsRelative - ? new Point(_currentPoint.X, _currentPoint.Y + commandToken.ReadDouble()) - : _currentPoint.WithY(commandToken.ReadDouble()); + ? new Point(_currentPoint.X, _currentPoint.Y + commandToken.ReadDouble()) + : _currentPoint.WithY(commandToken.ReadDouble()); - var lineSegment = new LineSegment + if (_isOpen == null) { - Point = _currentPoint - }; + CreateFigure(); + } - AddSegment(lineSegment); + _geometryContext.LineTo(_currentPoint); } private void AddCubicBezierCurve(CommandToken commandToken) { var point1 = commandToken.IsRelative - ? commandToken.ReadRelativePoint(_currentPoint) - : commandToken.ReadPoint(); + ? commandToken.ReadRelativePoint(_currentPoint) + : commandToken.ReadPoint(); var point2 = commandToken.IsRelative - ? commandToken.ReadRelativePoint(_currentPoint) - : commandToken.ReadPoint(); + ? commandToken.ReadRelativePoint(_currentPoint) + : commandToken.ReadPoint(); _previousControlPoint = point2; var point3 = commandToken.IsRelative - ? commandToken.ReadRelativePoint(_currentPoint) - : commandToken.ReadPoint(); + ? commandToken.ReadRelativePoint(_currentPoint) + : commandToken.ReadPoint(); - var bezierSegment = new BezierSegment + if (_isOpen == null) { - Point1 = point1, - Point2 = point2, - Point3 = point3 - }; + CreateFigure(); + } - AddSegment(bezierSegment); + _geometryContext.CubicBezierTo(point1, point2, point3); _currentPoint = point3; } @@ -333,22 +330,21 @@ namespace Avalonia.Media private void AddQuadraticBezierCurve(CommandToken commandToken) { var start = commandToken.IsRelative - ? commandToken.ReadRelativePoint(_currentPoint) - : commandToken.ReadPoint(); + ? commandToken.ReadRelativePoint(_currentPoint) + : commandToken.ReadPoint(); _previousControlPoint = start; var end = commandToken.IsRelative - ? commandToken.ReadRelativePoint(_currentPoint) - : commandToken.ReadPoint(); + ? commandToken.ReadRelativePoint(_currentPoint) + : commandToken.ReadPoint(); - var quadraticBezierSegment = new QuadraticBezierSegment + if (_isOpen == null) { - Point1 = start, - Point2 = end - }; + CreateFigure(); + } - AddSegment(quadraticBezierSegment); + _geometryContext.QuadraticBezierTo(start, end); _currentPoint = end; } @@ -356,8 +352,8 @@ namespace Avalonia.Media private void AddSmoothCubicBezierCurve(CommandToken commandToken) { var point2 = commandToken.IsRelative - ? commandToken.ReadRelativePoint(_currentPoint) - : commandToken.ReadPoint(); + ? commandToken.ReadRelativePoint(_currentPoint) + : commandToken.ReadPoint(); var end = commandToken.IsRelative ? commandToken.ReadRelativePoint(_currentPoint) @@ -368,10 +364,12 @@ namespace Avalonia.Media _previousControlPoint = MirrorControlPoint((Point)_previousControlPoint, _currentPoint); } - var bezierSegment = - new BezierSegment { Point1 = _previousControlPoint ?? _currentPoint, Point2 = point2, Point3 = end }; + if (_isOpen == null) + { + CreateFigure(); + } - AddSegment(bezierSegment); + _geometryContext.CubicBezierTo(_previousControlPoint ?? _currentPoint, point2, end); _previousControlPoint = point2; @@ -389,13 +387,12 @@ namespace Avalonia.Media _previousControlPoint = MirrorControlPoint((Point)_previousControlPoint, _currentPoint); } - var quadraticBezierSegment = new QuadraticBezierSegment + if (_isOpen == null) { - Point1 = _previousControlPoint ?? _currentPoint, - Point2 = end - }; + CreateFigure(); + } - AddSegment(quadraticBezierSegment); + _geometryContext.QuadraticBezierTo(_previousControlPoint ?? _currentPoint, end); _currentPoint = end; } @@ -414,16 +411,12 @@ namespace Avalonia.Media ? commandToken.ReadRelativePoint(_currentPoint) : commandToken.ReadPoint(); - var arcSegment = new ArcSegment + if (_isOpen == null) { - Size = size, - RotationAngle = rotationAngle, - IsLargeArc = isLargeArc, - SweepDirection = sweepDirection, - Point = end - }; + CreateFigure(); + } - AddSegment(arcSegment); + _geometryContext.ArcTo(end, size, rotationAngle, isLargeArc, sweepDirection); _currentPoint = end; @@ -589,10 +582,7 @@ namespace Avalonia.Media return new Point(origin.X + x, origin.Y + y); } - private static bool ReadCommand( - TextReader reader, - ref Command command, - ref bool relative) + private static bool ReadCommand(TextReader reader, ref Command command, ref bool relative) { ReadWhitespace(reader); diff --git a/src/Avalonia.Visuals/Media/StreamGeometry.cs b/src/Avalonia.Visuals/Media/StreamGeometry.cs index 1983740375..2622175d60 100644 --- a/src/Avalonia.Visuals/Media/StreamGeometry.cs +++ b/src/Avalonia.Visuals/Media/StreamGeometry.cs @@ -5,6 +5,8 @@ using Avalonia.Platform; namespace Avalonia.Media { + using Avalonia.Visuals.Platform; + /// /// Represents the geometry of an arbitrarily complex shape. /// @@ -35,10 +37,15 @@ namespace Avalonia.Media /// A . public static new StreamGeometry Parse(string s) { - using (var parser = new PathMarkupParser()) - { - return parser.Parse(s); - } + var streamGeometry = new StreamGeometry(); + + using (var context = streamGeometry.Open()) + using (var parser = new PathMarkupParser(context)) + { + parser.Parse(s); + } + + return streamGeometry; } /// diff --git a/src/Avalonia.Visuals/Media/StreamGeometryContext.cs b/src/Avalonia.Visuals/Media/StreamGeometryContext.cs index 70b889f817..7521582067 100644 --- a/src/Avalonia.Visuals/Media/StreamGeometryContext.cs +++ b/src/Avalonia.Visuals/Media/StreamGeometryContext.cs @@ -15,7 +15,7 @@ namespace Avalonia.Media /// . /// /// TODO: This class is just a wrapper around IStreamGeometryContextImpl: is it needed? - public class StreamGeometryContext : IDisposable + public class StreamGeometryContext : IGeometryContext { private readonly IStreamGeometryContextImpl _impl; diff --git a/src/Avalonia.Visuals/Platform/IGeometryContext.cs b/src/Avalonia.Visuals/Platform/IGeometryContext.cs new file mode 100644 index 0000000000..ac63837428 --- /dev/null +++ b/src/Avalonia.Visuals/Platform/IGeometryContext.cs @@ -0,0 +1,66 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Media; + +namespace Avalonia.Platform +{ + /// + /// Describes a geometry using drawing commands. + /// + public interface IGeometryContext : IDisposable + { + /// + /// Draws an arc to the specified point. + /// + /// The destination point. + /// The radii of an oval whose perimeter is used to draw the angle. + /// The rotation angle of the oval that specifies the curve. + /// true to draw the arc greater than 180 degrees; otherwise, false. + /// + /// A value that indicates whether the arc is drawn in the Clockwise or Counterclockwise direction. + /// + void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection); + + /// + /// Begins a new figure. + /// + /// The starting point for the figure. + /// Whether the figure is filled. + void BeginFigure(Point startPoint, bool isFilled = true); + + /// + /// Draws a Bezier curve to the specified point. + /// + /// The first control point used to specify the shape of the curve. + /// The second control point used to specify the shape of the curve. + /// The destination point for the end of the curve. + void CubicBezierTo(Point point1, Point point2, Point point3); + + /// + /// Draws a quadratic Bezier curve to the specified point + /// + /// Control point + /// DestinationPoint + void QuadraticBezierTo(Point control, Point endPoint); + + /// + /// Draws a line to the specified point. + /// + /// The destination point. + void LineTo(Point point); + + /// + /// Ends the figure started by . + /// + /// Whether the figure is closed. + void EndFigure(bool isClosed); + + /// + /// Sets the fill rule. + /// + /// The fill rule. + void SetFillRule(FillRule fillRule); + } +} \ No newline at end of file diff --git a/src/Avalonia.Visuals/Platform/IStreamGeometryContextImpl.cs b/src/Avalonia.Visuals/Platform/IStreamGeometryContextImpl.cs index 386560c6b6..da9505cd2d 100644 --- a/src/Avalonia.Visuals/Platform/IStreamGeometryContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IStreamGeometryContextImpl.cs @@ -1,62 +1,12 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -using System; -using Avalonia.Media; - namespace Avalonia.Platform { /// /// Describes a geometry using drawing commands. /// - public interface IStreamGeometryContextImpl : IDisposable - { - /// - /// Draws an arc to the specified point. - /// - /// The destination point. - /// The radii of an oval whose perimeter is used to draw the angle. - /// The rotation angle of the oval that specifies the curve. - /// true to draw the arc greater than 180 degrees; otherwise, false. - /// - /// A value that indicates whether the arc is drawn in the Clockwise or Counterclockwise direction. - /// - void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection); - - /// - /// Begins a new figure. - /// - /// The starting point for the figure. - /// Whether the figure is filled. - void BeginFigure(Point startPoint, bool isFilled); - - /// - /// Draws a Bezier curve to the specified point. - /// - /// The first control point used to specify the shape of the curve. - /// The second control point used to specify the shape of the curve. - /// The destination point for the end of the curve. - void CubicBezierTo(Point point1, Point point2, Point point3); - - /// - /// Draws a quadratic Bezier curve to the specified point - /// - /// Control point - /// DestinationPoint - void QuadraticBezierTo(Point control, Point endPoint); - - /// - /// Draws a line to the specified point. - /// - /// The destination point. - void LineTo(Point point); - - /// - /// Ends the figure started by . - /// - /// Whether the figure is closed. - void EndFigure(bool isClosed); - - void SetFillRule(FillRule fillRule); + public interface IStreamGeometryContextImpl : IGeometryContext + { } } diff --git a/src/Avalonia.Visuals/Platform/PathGeometryContext.cs b/src/Avalonia.Visuals/Platform/PathGeometryContext.cs new file mode 100644 index 0000000000..cc881094fd --- /dev/null +++ b/src/Avalonia.Visuals/Platform/PathGeometryContext.cs @@ -0,0 +1,85 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Media; +using Avalonia.Platform; +using System; + +namespace Avalonia.Visuals.Platform +{ + public class PathGeometryContext : IGeometryContext + { + private PathFigure _currentFigure; + private PathGeometry _pathGeometry; + + public PathGeometryContext(PathGeometry pathGeometry) + { + _pathGeometry = pathGeometry ?? throw new ArgumentNullException(nameof(pathGeometry)); + } + + public void Dispose() + { + _pathGeometry = null; + } + + public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection) + { + var arcSegment = new ArcSegment + { + Size = size, + RotationAngle = rotationAngle, + IsLargeArc = isLargeArc, + SweepDirection = sweepDirection, + Point = point + }; + + _currentFigure.Segments.Add(arcSegment); + } + + public void BeginFigure(Point startPoint, bool isFilled) + { + _currentFigure = new PathFigure { StartPoint = startPoint, IsClosed = false, IsFilled = isFilled }; + + _pathGeometry.Figures.Add(_currentFigure); + } + + public void CubicBezierTo(Point point1, Point point2, Point point3) + { + var bezierSegment = new BezierSegment { Point1 = point1, Point2 = point2, Point3 = point3 }; + + _currentFigure.Segments.Add(bezierSegment); + } + + public void QuadraticBezierTo(Point control, Point endPoint) + { + var quadraticBezierSegment = new QuadraticBezierSegment { Point1 = control, Point2 = endPoint }; + + _currentFigure.Segments.Add(quadraticBezierSegment); + } + + public void LineTo(Point point) + { + var lineSegment = new LineSegment + { + Point = point + }; + + _currentFigure.Segments.Add(lineSegment); + } + + public void EndFigure(bool isClosed) + { + if (_currentFigure != null) + { + _currentFigure.IsClosed = isClosed; + } + + _currentFigure = null; + } + + public void SetFillRule(FillRule fillRule) + { + _pathGeometry.FillRule = fillRule; + } + } +} diff --git a/tests/Avalonia.Benchmarks/Visuals/Media/PathMarkupParserTests.cs b/tests/Avalonia.Benchmarks/Visuals/Media/PathMarkupParserTests.cs index 6d0027fe23..c4106340b2 100644 --- a/tests/Avalonia.Benchmarks/Visuals/Media/PathMarkupParserTests.cs +++ b/tests/Avalonia.Benchmarks/Visuals/Media/PathMarkupParserTests.cs @@ -26,14 +26,20 @@ namespace Avalonia.Benchmarks.Visuals.Media [Benchmark] public void Parse_Large_Path() { - var path = "F1 M 16.6309 18.6563C 17.1309 8.15625 29.8809 14.1563 29.8809 14.1563C 30.8809 11.1563 34.1308 11.4063" + - " 34.1308 11.4063C 33.5 12 34.6309 13.1563 34.6309 13.1563C 32.1309 13.1562 31.1309 14.9062 31.1309 14.9" + - "062C 41.1309 23.9062 32.6309 27.9063 32.6309 27.9062C 24.6309 24.9063 21.1309 22.1562 16.6309 18.6563 Z" + - " M 16.6309 19.9063C 21.6309 24.1563 25.1309 26.1562 31.6309 28.6562C 31.6309 28.6562 26.3809 39.1562 18" + - ".3809 36.1563C 18.3809 36.1563 18 38 16.3809 36.9063C 15 36 16.3809 34.9063 16.3809 34.9063C 16.3809 34" + - ".9063 10.1309 30.9062 16.6309 19.9063 Z "; - var parser = new PathMarkupParser(); - var result = parser.Parse(path); + const string PathData = "F1 M 16.6309 18.6563C 17.1309 8.15625 29.8809 14.1563 29.8809 14.1563C 30.8809 11.1563 34.1308 11.4063" + + " 34.1308 11.4063C 33.5 12 34.6309 13.1563 34.6309 13.1563C 32.1309 13.1562 31.1309 14.9062 31.1309 14.9" + + "062C 41.1309 23.9062 32.6309 27.9063 32.6309 27.9062C 24.6309 24.9063 21.1309 22.1562 16.6309 18.6563 Z" + + " M 16.6309 19.9063C 21.6309 24.1563 25.1309 26.1562 31.6309 28.6562C 31.6309 28.6562 26.3809 39.1562 18" + + ".3809 36.1563C 18.3809 36.1563 18 38 16.3809 36.9063C 15 36 16.3809 34.9063 16.3809 34.9063C 16.3809 34" + + ".9063 10.1309 30.9062 16.6309 19.9063 Z "; + + var streamGeometry = new StreamGeometry(); + + using (var context = streamGeometry.Open()) + using (var parser = new PathMarkupParser(context)) + { + parser.Parse(PathData); + } } } } diff --git a/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs index d7eb6129ac..c8bea43fb0 100644 --- a/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs @@ -2,24 +2,23 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using Avalonia.Media; -using Avalonia.Platform; -using Moq; +using Avalonia.Visuals.Platform; using Xunit; namespace Avalonia.Visuals.UnitTests.Media { - using System.Linq; - public class PathMarkupParserTests { [Fact] public void Parses_Move() { - using (var parser = new PathMarkupParser()) + var pathGeometry = new PathGeometry(); + using (var context = new PathGeometryContext(pathGeometry)) + using (var parser = new PathMarkupParser(context)) { - var geometry = parser.Parse("M10 10"); + parser.Parse("M10 10"); - var figure = geometry.Figures.First(); + var figure = pathGeometry.Figures[0]; Assert.Equal(new Point(10, 10), figure.StartPoint); } @@ -28,13 +27,15 @@ namespace Avalonia.Visuals.UnitTests.Media [Fact] public void Parses_Line() { - using (var parser = new PathMarkupParser()) + var pathGeometry = new PathGeometry(); + using (var context = new PathGeometryContext(pathGeometry)) + using (var parser = new PathMarkupParser(context)) { - var geometry = parser.Parse("M0 0L10 10"); + parser.Parse("M0 0L10 10"); - var figure = geometry.Figures.First(); + var figure = pathGeometry.Figures[0]; - var segment = figure.Segments.First(); + var segment = figure.Segments[0]; Assert.IsType(segment); @@ -47,11 +48,13 @@ namespace Avalonia.Visuals.UnitTests.Media [Fact] public void Parses_Close() { - using (var parser = new PathMarkupParser()) + var pathGeometry = new PathGeometry(); + using (var context = new PathGeometryContext(pathGeometry)) + using (var parser = new PathMarkupParser(context)) { - var geometry = parser.Parse("M0 0L10 10z"); + parser.Parse("M0 0L10 10z"); - var figure = geometry.Figures.First(); + var figure = pathGeometry.Figures[0]; Assert.True(figure.IsClosed); } @@ -60,11 +63,13 @@ namespace Avalonia.Visuals.UnitTests.Media [Fact] public void Parses_FillMode_Before_Move() { - using (var parser = new PathMarkupParser()) + var pathGeometry = new PathGeometry(); + using (var context = new PathGeometryContext(pathGeometry)) + using (var parser = new PathMarkupParser(context)) { - var geometry = parser.Parse("F 1M0,0"); + parser.Parse("F 1M0,0"); - Assert.Equal(FillRule.NonZero, geometry.FillRule); + Assert.Equal(FillRule.NonZero, pathGeometry.FillRule); } } @@ -74,11 +79,13 @@ namespace Avalonia.Visuals.UnitTests.Media [InlineData("M0,0,10,10,20,20")] public void Parses_Implicit_Line_Command_After_Move(string pathData) { - using (var parser = new PathMarkupParser()) + var pathGeometry = new PathGeometry(); + using (var context = new PathGeometryContext(pathGeometry)) + using (var parser = new PathMarkupParser(context)) { - var geometry = parser.Parse(pathData); + parser.Parse(pathData); - var figure = geometry.Figures[0]; + var figure = pathGeometry.Figures[0]; var segment = figure.Segments[0]; @@ -88,7 +95,7 @@ namespace Avalonia.Visuals.UnitTests.Media Assert.Equal(new Point(10, 10), lineSegment.Point); - figure = geometry.Figures[1]; + figure = pathGeometry.Figures[1]; segment = figure.Segments[0]; @@ -106,11 +113,13 @@ namespace Avalonia.Visuals.UnitTests.Media [InlineData("m0,0,10,10,20,20")] public void Parses_Implicit_Line_Command_After_Relative_Move(string pathData) { - using (var parser = new PathMarkupParser()) + var pathGeometry = new PathGeometry(); + using (var context = new PathGeometryContext(pathGeometry)) + using (var parser = new PathMarkupParser(context)) { - var geometry = parser.Parse(pathData); + parser.Parse(pathData); - var figure = geometry.Figures[0]; + var figure = pathGeometry.Figures[0]; var segment = figure.Segments[0]; @@ -155,7 +164,9 @@ namespace Avalonia.Visuals.UnitTests.Media "12.461,8.046C14.45,8.278,16,9.949,16,12")] public void Should_Parse(string pathData) { - using (var parser = new PathMarkupParser()) + var pathGeometry = new PathGeometry(); + using (var context = new PathGeometryContext(pathGeometry)) + using (var parser = new PathMarkupParser(context)) { parser.Parse(pathData);