diff --git a/src/Avalonia.Visuals/Media/PathMarkupParser.cs b/src/Avalonia.Visuals/Media/PathMarkupParser.cs
index e8824753b5..a322d404bf 100644
--- a/src/Avalonia.Visuals/Media/PathMarkupParser.cs
+++ b/src/Avalonia.Visuals/Media/PathMarkupParser.cs
@@ -82,7 +82,8 @@ namespace Avalonia.Media
/// The path data.
public void Parse(string pathData)
{
- var tokens = ParseTokens(pathData);
+ var normalizedPathData = NormalizeWhiteSpaces(pathData);
+ var tokens = ParseTokens(normalizedPathData);
CreateGeometry(tokens);
}
@@ -107,6 +108,45 @@ 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();
@@ -123,7 +163,9 @@ namespace Avalonia.Media
private static IEnumerable ParseTokens(string s)
{
- return Regex.Split(s, s_separatorPattern).Where(t => !string.IsNullOrEmpty(t)).Select(CommandToken.Parse);
+ 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)
@@ -135,7 +177,7 @@ namespace Avalonia.Media
private void CreateGeometry(IEnumerable commandTokens)
{
- _currentPoint = new Point();
+ _currentPoint = new Point();
foreach (var commandToken in commandTokens)
{
@@ -468,7 +510,7 @@ namespace Avalonia.Media
private List Arguments { get; }
public static CommandToken Parse(string s)
- {
+ {
using (var reader = new StringReader(s))
{
var command = Command.None;
@@ -590,7 +632,7 @@ namespace Avalonia.Media
var y = ReadDouble();
return new Point(origin.X + x, origin.Y + y);
- }
+ }
private static bool ReadCommand(TextReader reader, ref Command command, ref bool relative)
{
diff --git a/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs
index c8bea43fb0..35ec38789e 100644
--- a/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs
+++ b/tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs
@@ -7,6 +7,8 @@ using Xunit;
namespace Avalonia.Visuals.UnitTests.Media
{
+ using System.IO;
+
public class PathMarkupParserTests
{
[Fact]
@@ -140,6 +142,7 @@ namespace Avalonia.Visuals.UnitTests.Media
}
[Theory]
+ [InlineData(" M0 0")]
[InlineData("F1 M24,14 A2,2,0,1,1,20,14 A2,2,0,1,1,24,14 z")] // issue #1107
[InlineData("M0 0L10 10z")]
[InlineData("M50 50 L100 100 L150 50")]
@@ -173,5 +176,18 @@ namespace Avalonia.Visuals.UnitTests.Media
Assert.True(true);
}
}
+
+ [Theory]
+ [InlineData("0 0")]
+ [InlineData("j")]
+ public void Throws_InvalidDataException_On_None_Defined_Command(string pathData)
+ {
+ var pathGeometry = new PathGeometry();
+ using (var context = new PathGeometryContext(pathGeometry))
+ using (var parser = new PathMarkupParser(context))
+ {
+ Assert.Throws(() => parser.Parse(pathData));
+ }
+ }
}
}
\ No newline at end of file