| 
					
				 | 
			
			
				@@ -5,9 +5,6 @@ using System; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Collections.Generic; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Globalization; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.IO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using System.Linq; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using System.Text; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using System.Text.RegularExpressions; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using Avalonia.Platform; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 namespace Avalonia.Media 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -17,7 +14,6 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     public class PathMarkupParser : IDisposable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private static readonly string s_separatorPattern; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private static readonly Dictionary<char, Command> s_commands = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             new Dictionary<char, Command> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -37,14 +33,9 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private IGeometryContext _geometryContext; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private Point _currentPoint; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private Point? _previousControlPoint; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private bool? _isOpen; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private bool _isOpen; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private bool _isDisposed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        static PathMarkupParser() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            s_separatorPattern = CreatesSeparatorPattern(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// Initializes a new instance of the <see cref="PathMarkupParser"/> class. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// </summary> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -76,18 +67,6 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             Close 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// Parses the specified path data and writes the result to the geometryContext of this instance. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <param name="pathData">The path data.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public void Parse(string pathData) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var normalizedPathData = NormalizeWhiteSpaces(pathData); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var tokens = ParseTokens(normalizedPathData); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            CreateGeometry(tokens); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         void IDisposable.Dispose() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             Dispose(true); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -108,66 +87,6 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _isDisposed = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private static string NormalizeWhiteSpaces(string s) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            int length = s.Length, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                index = 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                i = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var source = s.ToCharArray(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var skip = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            for (; i < length; i++) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var c = source[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (char.IsWhiteSpace(c)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (skip) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    source[index++] = c; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    skip = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                skip = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                source[index++] = c; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (char.IsWhiteSpace(source[index - 1])) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                index--; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return char.IsWhiteSpace(source[0]) ? new string(source, 1, index) : new string(source, 0, index); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private static string CreatesSeparatorPattern() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var stringBuilder = new StringBuilder(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            foreach (var command in s_commands.Keys) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                stringBuilder.Append(command); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                stringBuilder.Append(char.ToLower(command)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return @"(?=[" + stringBuilder + "])"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private static IEnumerable<CommandToken> ParseTokens(string s) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var expressions = Regex.Split(s, s_separatorPattern).Where(t => !string.IsNullOrEmpty(t)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return expressions.Select(CommandToken.Parse); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private static Point MirrorControlPoint(Point controlPoint, Point center) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var dir = controlPoint - center; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -175,76 +94,78 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return center + -dir; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void CreateGeometry(IEnumerable<CommandToken> commandTokens) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Parses the specified path data and writes the result to the geometryContext of this instance. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="pathData">The path data.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void Parse(string pathData) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var span = pathData.AsSpan(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _currentPoint = new Point(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            foreach (var commandToken in commandTokens) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            while(!span.IsEmpty) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                try 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    while (true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        switch (commandToken.Command) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            case Command.None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            case Command.FillRule: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                SetFillRule(commandToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            case Command.Move: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                AddMove(commandToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            case Command.Line: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                AddLine(commandToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            case Command.HorizontalLine: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                AddHorizontalLine(commandToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            case Command.VerticalLine: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                AddVerticalLine(commandToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            case Command.CubicBezierCurve: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                AddCubicBezierCurve(commandToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            case Command.QuadraticBezierCurve: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                AddQuadraticBezierCurve(commandToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            case Command.SmoothCubicBezierCurve: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                AddSmoothCubicBezierCurve(commandToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            case Command.SmoothQuadraticBezierCurve: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                AddSmoothQuadraticBezierCurve(commandToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            case Command.Arc: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                AddArc(commandToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            case Command.Close: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                CloseFigure(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                throw new NotSupportedException("Unsupported command"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        if (commandToken.HasImplicitCommands) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                catch (InvalidDataException) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if(!ReadCommand(ref span, out var command, out var relative)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                catch (NotSupportedException) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                bool initialCommand = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                do 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (!initialCommand) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        span = ReadSeparator(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    switch (command) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case Command.None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case Command.FillRule: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            SetFillRule(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case Command.Move: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            AddMove(ref span, relative); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case Command.Line: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            AddLine(ref span, relative); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case Command.HorizontalLine: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            AddHorizontalLine(ref span, relative); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case Command.VerticalLine: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            AddVerticalLine(ref span, relative); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case Command.CubicBezierCurve: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            AddCubicBezierCurve(ref span, relative); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case Command.QuadraticBezierCurve: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            AddQuadraticBezierCurve(ref span, relative); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case Command.SmoothCubicBezierCurve: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            AddSmoothCubicBezierCurve(ref span, relative); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case Command.SmoothQuadraticBezierCurve: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            AddSmoothQuadraticBezierCurve(ref span, relative); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case Command.Arc: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            AddArc(ref span, relative); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case Command.Close: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            CloseFigure(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            throw new NotSupportedException("Unsupported command"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    initialCommand = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } while (PeekArgument(span)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_isOpen != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (_isOpen) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 _geometryContext.EndFigure(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -252,7 +173,7 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private void CreateFigure() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_isOpen != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (_isOpen) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 _geometryContext.EndFigure(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -262,62 +183,72 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _isOpen = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void SetFillRule(CommandToken commandToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void SetFillRule(ref ReadOnlySpan<char> span) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var fillRule = commandToken.ReadFillRule(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!ReadArgument(ref span, out var fillRule) || fillRule.Length != 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                throw new InvalidDataException("Invalid fill rule."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            FillRule rule; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _geometryContext.SetFillRule(fillRule); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            switch (fillRule[0]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                case '0': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    rule = FillRule.EvenOdd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                case '1': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    rule = FillRule.NonZero; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    throw new InvalidDataException("Invalid fill rule"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _geometryContext.SetFillRule(rule); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private void CloseFigure() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_isOpen == true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (_isOpen) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 _geometryContext.EndFigure(true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _previousControlPoint = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _isOpen = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _isOpen = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void AddMove(CommandToken commandToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void AddMove(ref ReadOnlySpan<char> span, bool relative) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var currentPoint = commandToken.IsRelative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                   ? commandToken.ReadRelativePoint(_currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                   : commandToken.ReadPoint(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var currentPoint = relative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                ? ReadRelativePoint(ref span, _currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                : ReadPoint(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _currentPoint = currentPoint; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             CreateFigure(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (!commandToken.HasImplicitCommands) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            while (PeekArgument(span)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                span = ReadSeparator(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                AddLine(ref span, relative); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            while (commandToken.HasImplicitCommands) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                AddLine(commandToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (commandToken.IsRelative) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (!relative) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _currentPoint = currentPoint; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    CreateFigure(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                _currentPoint = currentPoint; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                CreateFigure(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void AddLine(CommandToken commandToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void AddLine(ref ReadOnlySpan<char> span, bool relative) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _currentPoint = commandToken.IsRelative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                ? commandToken.ReadRelativePoint(_currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                : commandToken.ReadPoint(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _currentPoint = relative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                ? ReadRelativePoint(ref span, _currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                : ReadPoint(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_isOpen == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!_isOpen) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 CreateFigure(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -325,13 +256,13 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _geometryContext.LineTo(_currentPoint); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void AddHorizontalLine(CommandToken commandToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void AddHorizontalLine(ref ReadOnlySpan<char> span, bool relative) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _currentPoint = commandToken.IsRelative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                ? new Point(_currentPoint.X + commandToken.ReadDouble(), _currentPoint.Y) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                : _currentPoint.WithX(commandToken.ReadDouble()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _currentPoint = relative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                ? new Point(_currentPoint.X + ReadDouble(ref span), _currentPoint.Y) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                : _currentPoint.WithX(ReadDouble(ref span)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_isOpen == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!_isOpen) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 CreateFigure(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -339,13 +270,13 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _geometryContext.LineTo(_currentPoint); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void AddVerticalLine(CommandToken commandToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void AddVerticalLine(ref ReadOnlySpan<char> span, bool relative) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _currentPoint = commandToken.IsRelative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                ? new Point(_currentPoint.X, _currentPoint.Y + commandToken.ReadDouble()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                : _currentPoint.WithY(commandToken.ReadDouble()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _currentPoint = relative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                ? new Point(_currentPoint.X, _currentPoint.Y + ReadDouble(ref span)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                : _currentPoint.WithY(ReadDouble(ref span)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_isOpen == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!_isOpen) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 CreateFigure(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -353,23 +284,27 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _geometryContext.LineTo(_currentPoint); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void AddCubicBezierCurve(CommandToken commandToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void AddCubicBezierCurve(ref ReadOnlySpan<char> span, bool relative) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var point1 = commandToken.IsRelative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                             ? commandToken.ReadRelativePoint(_currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                             : commandToken.ReadPoint(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var point1 = relative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ? ReadRelativePoint(ref span, _currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    : ReadPoint(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var point2 = commandToken.IsRelative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                             ? commandToken.ReadRelativePoint(_currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                             : commandToken.ReadPoint(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = ReadSeparator(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var point2 = relative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ? ReadRelativePoint(ref span, _currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    : ReadPoint(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _previousControlPoint = point2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var point3 = commandToken.IsRelative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                             ? commandToken.ReadRelativePoint(_currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                             : commandToken.ReadPoint(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = ReadSeparator(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var point3 = relative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ? ReadRelativePoint(ref span, _currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    : ReadPoint(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_isOpen == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!_isOpen) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 CreateFigure(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -379,19 +314,21 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _currentPoint = point3; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void AddQuadraticBezierCurve(CommandToken commandToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void AddQuadraticBezierCurve(ref ReadOnlySpan<char> span, bool relative) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var start = commandToken.IsRelative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            ? commandToken.ReadRelativePoint(_currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            : commandToken.ReadPoint(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var start = relative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ? ReadRelativePoint(ref span, _currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    : ReadPoint(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _previousControlPoint = start; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var end = commandToken.IsRelative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                          ? commandToken.ReadRelativePoint(_currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                          : commandToken.ReadPoint(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = ReadSeparator(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var end = relative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ? ReadRelativePoint(ref span, _currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    : ReadPoint(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_isOpen == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!_isOpen) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 CreateFigure(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -401,22 +338,24 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _currentPoint = end; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void AddSmoothCubicBezierCurve(CommandToken commandToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void AddSmoothCubicBezierCurve(ref ReadOnlySpan<char> span, bool relative) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var point2 = commandToken.IsRelative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                             ? commandToken.ReadRelativePoint(_currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                             : commandToken.ReadPoint(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var point2 = relative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ? ReadRelativePoint(ref span, _currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    : ReadPoint(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var end = commandToken.IsRelative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                          ? commandToken.ReadRelativePoint(_currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                          : commandToken.ReadPoint(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = ReadSeparator(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var end = relative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ? ReadRelativePoint(ref span, _currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    : ReadPoint(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (_previousControlPoint != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 _previousControlPoint = MirrorControlPoint((Point)_previousControlPoint, _currentPoint); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_isOpen == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!_isOpen) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 CreateFigure(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -428,18 +367,18 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _currentPoint = end; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void AddSmoothQuadraticBezierCurve(CommandToken commandToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void AddSmoothQuadraticBezierCurve(ref ReadOnlySpan<char> span, bool relative) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var end = commandToken.IsRelative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                          ? commandToken.ReadRelativePoint(_currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                          : commandToken.ReadPoint(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var end = relative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ? ReadRelativePoint(ref span, _currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    : ReadPoint(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (_previousControlPoint != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 _previousControlPoint = MirrorControlPoint((Point)_previousControlPoint, _currentPoint); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_isOpen == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!_isOpen) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 CreateFigure(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -449,21 +388,27 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _currentPoint = end; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void AddArc(CommandToken commandToken) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void AddArc(ref ReadOnlySpan<char> span, bool relative) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var size = commandToken.ReadSize(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var size = ReadSize(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = ReadSeparator(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var rotationAngle = commandToken.ReadDouble(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var rotationAngle = ReadDouble(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = ReadSeparator(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var isLargeArc = ReadBool(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var isLargeArc = commandToken.ReadBool(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = ReadSeparator(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var sweepDirection = commandToken.ReadBool() ? SweepDirection.Clockwise : SweepDirection.CounterClockwise; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var sweepDirection = ReadBool(ref span) ? SweepDirection.Clockwise : SweepDirection.CounterClockwise; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = ReadSeparator(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var end = commandToken.IsRelative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                          ? commandToken.ReadRelativePoint(_currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                          : commandToken.ReadPoint(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var end = relative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ? ReadRelativePoint(ref span, _currentPoint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    : ReadPoint(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_isOpen == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!_isOpen) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 CreateFigure(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -475,210 +420,134 @@ namespace Avalonia.Media 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _previousControlPoint = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private class CommandToken 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private static bool PeekArgument(ReadOnlySpan<char> span) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            private const string ArgumentExpression = @"-?[0-9]*\.?\d+"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            private CommandToken(Command command, bool isRelative, IEnumerable<string> arguments) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                Command = command; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                IsRelative = isRelative; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                Arguments = new List<string>(arguments); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            public Command Command { get; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = SkipWhitespace(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            public bool IsRelative { get; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return !span.IsEmpty && (span[0] == ',' || span[0] == '-' || char.IsDigit(span[0])); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            public bool HasImplicitCommands 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private static bool ReadArgument(ref ReadOnlySpan<char> remaining, out ReadOnlySpan<char> argument) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            remaining = SkipWhitespace(remaining); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (remaining.IsEmpty) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                get 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (CurrentPosition == 0 && Arguments.Count > 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return CurrentPosition < Arguments.Count - 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                argument = ReadOnlySpan<char>.Empty; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            private int CurrentPosition { get; set; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            private List<string> Arguments { get; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            public static CommandToken Parse(string s) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            {               
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                using (var reader = new StringReader(s)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var command = Command.None; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var isRelative = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (!ReadCommand(reader, ref command, ref isRelative)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        throw new InvalidDataException("No path command declared."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var commandArguments = reader.ReadToEnd(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var argumentMatches = Regex.Matches(commandArguments, ArgumentExpression); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var arguments = new List<string>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    foreach (Match match in argumentMatches) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        arguments.Add(match.Value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return new CommandToken(command, isRelative, arguments); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            public FillRule ReadFillRule() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var valid = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int i = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (remaining[i] == '-') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (CurrentPosition == Arguments.Count) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    throw new InvalidDataException("Invalid fill rule"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var value = Arguments[CurrentPosition]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                CurrentPosition++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                switch (value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    case "0": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            return FillRule.EvenOdd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    case "1": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            return FillRule.NonZero; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        throw new InvalidDataException("Invalid fill rule"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                i++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (; i < remaining.Length && char.IsNumber(remaining[i]); i++) valid = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            public bool ReadBool() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (i < remaining.Length && remaining[i] == '.') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (CurrentPosition == Arguments.Count) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    throw new InvalidDataException("Invalid boolean value"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var value = Arguments[CurrentPosition]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                CurrentPosition++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                switch (value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    case "1": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    case "0": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        throw new InvalidDataException("Invalid boolean value"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                valid = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                i++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (; i < remaining.Length && char.IsNumber(remaining[i]); i++) valid = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            public double ReadDouble() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!valid) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (CurrentPosition == Arguments.Count) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    throw new InvalidDataException("Invalid double value"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var value = Arguments[CurrentPosition]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                CurrentPosition++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return double.Parse(value, CultureInfo.InvariantCulture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                argument = ReadOnlySpan<char>.Empty; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            argument = remaining.Slice(0, i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            remaining = remaining.Slice(i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            public Size ReadSize() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var width = ReadDouble(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var height = ReadDouble(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return new Size(width, height); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            public Point ReadPoint() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private static ReadOnlySpan<char> ReadSeparator(ReadOnlySpan<char> span) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = SkipWhitespace(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!span.IsEmpty && span[0] == ',') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var x = ReadDouble(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var y = ReadDouble(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return new Point(x, y); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                span = span.Slice(1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return span; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            public Point ReadRelativePoint(Point origin) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var x = ReadDouble(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var y = ReadDouble(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return new Point(origin.X + x, origin.Y + y); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            }           
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private static ReadOnlySpan<char> SkipWhitespace(ReadOnlySpan<char> span) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int i = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (; i < span.Length && char.IsWhiteSpace(span[i]); i++) ; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return span.Slice(i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            private static bool ReadCommand(TextReader reader, ref Command command, ref bool relative) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private bool ReadBool(ref ReadOnlySpan<char> span) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!ReadArgument(ref span, out var boolValue) || boolValue.Length != 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ReadWhitespace(reader); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var i = reader.Peek(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (i == -1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                throw new InvalidDataException("Invalid bool rule."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            switch (boolValue[0]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                case '0': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                case '1': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    throw new InvalidDataException("Invalid bool rule"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var c = (char)i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private double ReadDouble(ref ReadOnlySpan<char> span) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!ReadArgument(ref span, out var doubleValue)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                throw new InvalidDataException("Invalid double value"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (!s_commands.TryGetValue(char.ToUpperInvariant(c), out var next)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    throw new InvalidDataException("Unexpected path command '" + c + "'."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return double.Parse(doubleValue.ToString(), CultureInfo.InvariantCulture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                command = next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private Size ReadSize(ref ReadOnlySpan<char> span) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var width = ReadDouble(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = ReadSeparator(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var height = ReadDouble(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return new Size(width, height); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                relative = char.IsLower(c); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private Point ReadPoint(ref ReadOnlySpan<char> span) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var x = ReadDouble(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = ReadSeparator(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var y = ReadDouble(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return new Point(x, y); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                reader.Read(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private Point ReadRelativePoint(ref ReadOnlySpan<char> span, Point origin) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var x = ReadDouble(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = ReadSeparator(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var y = ReadDouble(ref span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return new Point(origin.X + x, origin.Y + y); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private bool ReadCommand(ref ReadOnlySpan<char> span, out Command command, out bool relative) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = SkipWhitespace(span); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (span.IsEmpty) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                command = default; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                relative = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            private static void ReadWhitespace(TextReader reader) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var c = span[0]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!s_commands.TryGetValue(char.ToUpperInvariant(c), out command)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                int i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                while ((i = reader.Peek()) != -1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var c = (char)i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (char.IsWhiteSpace(c)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        reader.Read(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                throw new InvalidDataException("Unexpected path command '" + c + "'."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            relative = char.IsLower(c); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            span = span.Slice(1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 |