Browse Source

Initial

pull/1661/head
Benedikt Schroeder 8 years ago
parent
commit
cbca7beefd
  1. 805
      src/Avalonia.Visuals/Media/PathMarkupParser.cs
  2. 10
      src/Avalonia.Visuals/Media/StreamGeometry.cs
  3. 127
      tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs

805
src/Avalonia.Visuals/Media/PathMarkupParser.cs

@ -5,50 +5,46 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace Avalonia.Media
{
/// <summary>
/// Parses a path markup string.
/// </summary>
public class PathMarkupParser
public class PathMarkupParser : IDisposable
{
private static readonly Dictionary<char, Command> Commands = new Dictionary<char, Command>
{
{ 'F', Command.FillRule },
{ 'M', Command.Move },
{ 'L', Command.Line },
{ 'H', Command.HorizontalLine },
{ 'V', Command.VerticalLine },
{ 'Q', Command.QuadraticBezierCurve },
{ 'T', Command.SmoothQuadraticBezierCurve },
{ 'C', Command.CubicBezierCurve },
{ 'S', Command.SmoothCubicBezierCurve },
{ 'A', Command.Arc },
{ 'Z', Command.Close },
};
private static readonly Dictionary<char, FillRule> FillRules = new Dictionary<char, FillRule>
{
{'0', FillRule.EvenOdd },
{'1', FillRule.NonZero }
};
private static readonly string s_separatorPattern;
private readonly StreamGeometryContext _context;
private Point _currentPoint;
private Point? _previousControlPoint;
private PathGeometry _currentGeometry;
private PathFigure _currentFigure;
private bool _isDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="PathMarkupParser"/> class.
/// </summary>
/// <param name="context">The context for the geometry.</param>
public PathMarkupParser(StreamGeometryContext context)
private static readonly Dictionary<char, Command> s_commands =
new Dictionary<char, Command>
{
{ 'F', Command.FillRule },
{ 'M', Command.Move },
{ 'L', Command.Line },
{ 'H', Command.HorizontalLine },
{ 'V', Command.VerticalLine },
{ 'Q', Command.QuadraticBezierCurve },
{ 'T', Command.SmoothQuadraticBezierCurve },
{ 'C', Command.CubicBezierCurve },
{ 'S', Command.SmoothCubicBezierCurve },
{ 'A', Command.Arc },
{ 'Z', Command.Close },
};
static PathMarkupParser()
{
_context = context;
s_separatorPattern = CreatesSeparatorPattern();
}
/// <summary>
/// Defines the command currently being processed.
/// </summary>
private enum Command
{
None,
@ -62,358 +58,581 @@ namespace Avalonia.Media
SmoothCubicBezierCurve,
SmoothQuadraticBezierCurve,
Arc,
Close,
Close
}
/// <summary>
/// Parses the specified markup string.
/// </summary>
/// <param name="s">The markup string.</param>
public void Parse(string s)
public PathGeometry Parse(string s)
{
bool openFigure = false;
_currentGeometry = new PathGeometry();
var tokens = ParseTokens(s);
using (StringReader reader = new StringReader(s))
return CreateGeometry(tokens);
}
void IDisposable.Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (_isDisposed)
{
Command command = Command.None;
Point point = new Point();
bool relative = false;
Point? previousControlPoint = null;
return;
}
if (disposing)
{
_currentFigure = null;
_currentGeometry = null;
}
_isDisposed = true;
}
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)
{
return Regex.Split(s, s_separatorPattern).Where(t => !string.IsNullOrEmpty(t)).Select(CommandToken.Parse);
}
private static Point MirrorControlPoint(Point controlPoint, Point center)
{
var dir = controlPoint - center;
return center + -dir;
}
while (ReadCommand(reader, ref command, ref relative))
private PathGeometry CreateGeometry(IEnumerable<CommandToken> commandTokens)
{
_currentGeometry = new PathGeometry();
_currentPoint = new Point();
foreach (var commandToken in commandTokens)
{
try
{
switch (command)
while (true)
{
case Command.FillRule:
_context.SetFillRule(ReadFillRule(reader));
previousControlPoint = null;
break;
case Command.Move:
if (openFigure)
{
_context.EndFigure(false);
}
point = ReadPoint(reader, point, relative);
_context.BeginFigure(point, true);
openFigure = true;
previousControlPoint = null;
break;
case Command.Line:
point = ReadPoint(reader, point, relative);
_context.LineTo(point);
previousControlPoint = null;
break;
case Command.HorizontalLine:
if (!relative)
{
point = point.WithX(ReadDouble(reader));
}
else
{
point = new Point(point.X + ReadDouble(reader), point.Y);
}
_context.LineTo(point);
previousControlPoint = null;
break;
case Command.VerticalLine:
if (!relative)
{
point = point.WithY(ReadDouble(reader));
}
else
{
point = new Point(point.X, point.Y + ReadDouble(reader));
}
_context.LineTo(point);
previousControlPoint = null;
break;
case Command.QuadraticBezierCurve:
{
Point handle = ReadPoint(reader, point, relative);
previousControlPoint = handle;
ReadSeparator(reader);
point = ReadPoint(reader, point, relative);
_context.QuadraticBezierTo(handle, point);
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.SmoothQuadraticBezierCurve:
{
Point end = ReadPoint(reader, point, relative);
if(previousControlPoint != null)
previousControlPoint = MirrorControlPoint((Point)previousControlPoint, point);
_context.QuadraticBezierTo(previousControlPoint ?? point, end);
point = end;
case Command.SmoothCubicBezierCurve:
AddSmoothCubicBezierCurve(commandToken);
break;
}
case Command.CubicBezierCurve:
{
Point point1 = ReadPoint(reader, point, relative);
ReadSeparator(reader);
Point point2 = ReadPoint(reader, point, relative);
previousControlPoint = point2;
ReadSeparator(reader);
point = ReadPoint(reader, point, relative);
_context.CubicBezierTo(point1, point2, point);
case Command.SmoothQuadraticBezierCurve:
AddSmoothQuadraticBezierCurve(commandToken);
break;
}
case Command.SmoothCubicBezierCurve:
{
Point point2 = ReadPoint(reader, point, relative);
ReadSeparator(reader);
Point end = ReadPoint(reader, point, relative);
if(previousControlPoint != null)
previousControlPoint = MirrorControlPoint((Point)previousControlPoint, point);
_context.CubicBezierTo(previousControlPoint ?? point, point2, end);
previousControlPoint = point2;
point = end;
case Command.Arc:
AddArc(commandToken);
break;
}
case Command.Arc:
{
Size size = ReadSize(reader);
ReadSeparator(reader);
double rotationAngle = ReadDouble(reader);
ReadSeparator(reader);
bool isLargeArc = ReadBool(reader);
ReadSeparator(reader);
SweepDirection sweepDirection = ReadBool(reader) ? SweepDirection.Clockwise : SweepDirection.CounterClockwise;
ReadSeparator(reader);
point = ReadPoint(reader, point, relative);
_context.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection);
previousControlPoint = null;
case Command.Close:
CloseFigure();
break;
}
default:
throw new NotSupportedException("Unsupported command");
}
case Command.Close:
_context.EndFigure(true);
openFigure = false;
previousControlPoint = null;
break;
if (commandToken.HasImplicitCommands)
{
continue;
}
default:
throw new NotSupportedException("Unsupported command");
break;
}
}
if (openFigure)
catch (InvalidDataException)
{
_context.EndFigure(false);
break;
}
catch (NotSupportedException)
{
break;
}
}
return _currentGeometry;
}
private Point MirrorControlPoint(Point controlPoint, Point center)
private void SetFillRule(CommandToken commandToken)
{
Point dir = (controlPoint - center);
return center + -dir;
_currentGeometry.FillRule = commandToken.ReadFillRule();
}
private static bool ReadCommand(
StringReader reader,
ref Command command,
ref bool relative)
private void CloseFigure()
{
ReadWhitespace(reader);
if (_currentFigure != null && !_currentFigure.IsClosed)
{
_currentFigure.IsClosed = true;
}
int i = reader.Peek();
_previousControlPoint = null;
if (i == -1)
_currentFigure = null;
}
private void CreateFigure()
{
_currentFigure = new PathFigure
{
return false;
StartPoint = _currentPoint,
IsClosed = false
};
_currentGeometry.Figures.Add(_currentFigure);
}
private void AddSegment(PathSegment segment)
{
if (_currentFigure == null)
{
CreateFigure();
}
else
_currentFigure.Segments.Add(segment);
}
private void AddMove(CommandToken commandToken)
{
var currentPoint = commandToken.ReadPoint();
_currentPoint = currentPoint;
CreateFigure();
if (!commandToken.HasImplicitCommands)
{
char c = (char)i;
Command next = Command.None;
return;
}
if (!Commands.TryGetValue(char.ToUpperInvariant(c), out next))
while (commandToken.HasImplicitCommands)
{
AddLine(commandToken);
if (commandToken.IsRelative)
{
if ((char.IsDigit(c) || c == '.' || c == '+' || c == '-') &&
(command != Command.None))
{
return true;
}
else
{
throw new InvalidDataException("Unexpected path command '" + c + "'.");
}
continue;
}
command = next;
relative = char.IsLower(c);
reader.Read();
return true;
_currentPoint = currentPoint;
CreateFigure();
}
}
private static FillRule ReadFillRule(StringReader reader)
private void AddLine(CommandToken commandToken)
{
int i = reader.Read();
if (i == -1)
{
throw new InvalidDataException("Invalid fill rule");
}
char c = (char)i;
FillRule rule;
_currentPoint = commandToken.IsRelative
? commandToken.ReadRelativePoint(_currentPoint)
: commandToken.ReadPoint();
if (!FillRules.TryGetValue(c, out rule))
var lineSegment = new LineSegment
{
throw new InvalidDataException("Invalid fill rule");
}
Point = _currentPoint
};
return rule;
AddSegment(lineSegment);
}
private static double ReadDouble(StringReader reader)
private void AddHorizontalLine(CommandToken commandToken)
{
ReadWhitespace(reader);
_currentPoint = commandToken.IsRelative
? new Point(_currentPoint.X + commandToken.ReadDouble(), _currentPoint.Y)
: _currentPoint.WithX(commandToken.ReadDouble());
// TODO: Handle Infinity, NaN and scientific notation.
StringBuilder b = new StringBuilder();
bool readSign = false;
bool readPoint = false;
bool readExponent = false;
int i;
var lineSegment = new LineSegment
{
Point = _currentPoint
};
while ((i = reader.Peek()) != -1)
AddSegment(lineSegment);
}
private void AddVerticalLine(CommandToken commandToken)
{
_currentPoint = commandToken.IsRelative
? new Point(_currentPoint.X, _currentPoint.Y + commandToken.ReadDouble())
: _currentPoint.WithY(commandToken.ReadDouble());
var lineSegment = new LineSegment
{
char c = char.ToUpperInvariant((char)i);
Point = _currentPoint
};
if (((c == '+' || c == '-') && !readSign) ||
(c == '.' && !readPoint) ||
(c == 'E' && !readExponent) ||
char.IsDigit(c))
{
if (b.Length != 0 && !readExponent && c == '-')
break;
b.Append(c);
reader.Read();
AddSegment(lineSegment);
}
if (!readSign)
{
readSign = c == '+' || c == '-';
}
private void AddCubicBezierCurve(CommandToken commandToken)
{
var point1 = commandToken.IsRelative
? commandToken.ReadRelativePoint(_currentPoint)
: commandToken.ReadPoint();
if (!readPoint)
{
readPoint = c == '.';
}
var point2 = commandToken.IsRelative
? commandToken.ReadRelativePoint(_currentPoint)
: commandToken.ReadPoint();
if (c == 'E')
{
readSign = false;
readExponent = true;
}
}
else
{
break;
}
}
_previousControlPoint = point2;
var point3 = commandToken.IsRelative
? commandToken.ReadRelativePoint(_currentPoint)
: commandToken.ReadPoint();
var bezierSegment = new BezierSegment
{
Point1 = point1,
Point2 = point2,
Point3 = point3
};
AddSegment(bezierSegment);
return double.Parse(b.ToString(), CultureInfo.InvariantCulture);
_currentPoint = point3;
}
private static Point ReadPoint(StringReader reader, Point current, bool relative)
private void AddQuadraticBezierCurve(CommandToken commandToken)
{
if (!relative)
var start = commandToken.IsRelative
? commandToken.ReadRelativePoint(_currentPoint)
: commandToken.ReadPoint();
_previousControlPoint = start;
var end = commandToken.IsRelative
? commandToken.ReadRelativePoint(_currentPoint)
: commandToken.ReadPoint();
var quadraticBezierSegment = new QuadraticBezierSegment
{
current = new Point();
}
Point1 = start,
Point2 = end
};
AddSegment(quadraticBezierSegment);
ReadWhitespace(reader);
double x = current.X + ReadDouble(reader);
ReadSeparator(reader);
double y = current.Y + ReadDouble(reader);
return new Point(x, y);
_currentPoint = end;
}
private static Size ReadSize(StringReader reader)
private void AddSmoothCubicBezierCurve(CommandToken commandToken)
{
ReadWhitespace(reader);
double x = ReadDouble(reader);
ReadSeparator(reader);
double y = ReadDouble(reader);
return new Size(x, y);
var point2 = commandToken.IsRelative
? commandToken.ReadRelativePoint(_currentPoint)
: commandToken.ReadPoint();
var end = commandToken.IsRelative
? commandToken.ReadRelativePoint(_currentPoint)
: commandToken.ReadPoint();
if (_previousControlPoint != null)
{
_previousControlPoint = MirrorControlPoint((Point)_previousControlPoint, _currentPoint);
}
var bezierSegment =
new BezierSegment { Point1 = _previousControlPoint ?? _currentPoint, Point2 = point2, Point3 = end };
AddSegment(bezierSegment);
_previousControlPoint = point2;
_currentPoint = end;
}
private static bool ReadBool(StringReader reader)
private void AddSmoothQuadraticBezierCurve(CommandToken commandToken)
{
return ReadDouble(reader) != 0;
var end = commandToken.IsRelative
? commandToken.ReadRelativePoint(_currentPoint)
: commandToken.ReadPoint();
if (_previousControlPoint != null)
{
_previousControlPoint = MirrorControlPoint((Point)_previousControlPoint, _currentPoint);
}
var quadraticBezierSegment = new QuadraticBezierSegment
{
Point1 = _previousControlPoint ?? _currentPoint,
Point2 = end
};
AddSegment(quadraticBezierSegment);
_currentPoint = end;
}
private static Point ReadRelativePoint(StringReader reader, Point lastPoint)
private void AddArc(CommandToken commandToken)
{
ReadWhitespace(reader);
double x = ReadDouble(reader);
ReadSeparator(reader);
double y = ReadDouble(reader);
return new Point(lastPoint.X + x, lastPoint.Y + y);
var size = commandToken.ReadSize();
var rotationAngle = commandToken.ReadDouble();
var isLargeArc = commandToken.ReadBool();
var sweepDirection = commandToken.ReadBool() ? SweepDirection.Clockwise : SweepDirection.CounterClockwise;
var end = commandToken.IsRelative
? commandToken.ReadRelativePoint(_currentPoint)
: commandToken.ReadPoint();
var arcSegment = new ArcSegment
{
Size = size,
RotationAngle = rotationAngle,
IsLargeArc = isLargeArc,
SweepDirection = sweepDirection,
Point = end
};
AddSegment(arcSegment);
_currentPoint = end;
_previousControlPoint = null;
}
private static void ReadSeparator(StringReader reader)
private class CommandToken
{
int i;
bool readComma = false;
private const string ArgumentExpression = @"-?[0-9]*\.?\d+";
while ((i = reader.Peek()) != -1)
private CommandToken(Command command, bool isRelative, IEnumerable<string> arguments)
{
char c = (char)i;
Command = command;
IsRelative = isRelative;
Arguments = new List<string>(arguments);
}
public Command Command { get; }
public bool IsRelative { get; }
if (char.IsWhiteSpace(c))
public bool HasImplicitCommands
{
get
{
reader.Read();
if (CurrentPosition == 0 && Arguments.Count > 0)
{
return true;
}
return CurrentPosition < Arguments.Count - 1;
}
else if (c == ',')
}
private int CurrentPosition { get; set; }
private List<string> Arguments { get; }
public static CommandToken Parse(string s)
{
using (var reader = new StringReader(s))
{
if (readComma)
var command = Command.None;
var isRelative = false;
if (!ReadCommand(reader, ref command, ref isRelative))
{
throw new InvalidDataException("Unexpected ','.");
throw new InvalidDataException("No path command declared.");
}
readComma = true;
reader.Read();
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);
}
else
}
public FillRule ReadFillRule()
{
if (CurrentPosition == Arguments.Count)
{
break;
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");
}
}
}
private static void ReadWhitespace(StringReader reader)
{
int i;
public bool ReadBool()
{
if (CurrentPosition == Arguments.Count)
{
throw new InvalidDataException("Invalid boolean value");
}
var value = Arguments[CurrentPosition];
while ((i = reader.Peek()) != -1)
CurrentPosition++;
switch (value)
{
case "1":
{
return true;
}
case "0":
{
return false;
}
default:
throw new InvalidDataException("Invalid boolean value");
}
}
public double ReadDouble()
{
char c = (char)i;
if (CurrentPosition == Arguments.Count)
{
throw new InvalidDataException("Invalid double value");
}
var value = Arguments[CurrentPosition];
CurrentPosition++;
return double.Parse(value, CultureInfo.InvariantCulture);
}
if (char.IsWhiteSpace(c))
public Size ReadSize()
{
var width = ReadDouble();
var height = ReadDouble();
return new Size(width, height);
}
public Point ReadPoint()
{
var x = ReadDouble();
var y = ReadDouble();
return new Point(x, y);
}
public Point ReadRelativePoint(Point origin)
{
var x = ReadDouble();
var y = ReadDouble();
return new Point(origin.X + x, origin.Y + y);
}
private static bool ReadCommand(
TextReader reader,
ref Command command,
ref bool relative)
{
ReadWhitespace(reader);
var i = reader.Peek();
if (i == -1)
{
reader.Read();
return false;
}
else
var c = (char)i;
if (!s_commands.TryGetValue(char.ToUpperInvariant(c), out var next))
{
break;
throw new InvalidDataException("Unexpected path command '" + c + "'.");
}
command = next;
relative = char.IsLower(c);
reader.Read();
return true;
}
private static void ReadWhitespace(TextReader reader)
{
int i;
while ((i = reader.Peek()) != -1)
{
var c = (char)i;
if (char.IsWhiteSpace(c))
{
reader.Read();
}
else
{
break;
}
}
}
}

10
src/Avalonia.Visuals/Media/StreamGeometry.cs

@ -35,14 +35,10 @@ namespace Avalonia.Media
/// <returns>A <see cref="StreamGeometry"/>.</returns>
public static new StreamGeometry Parse(string s)
{
StreamGeometry result = new StreamGeometry();
using (StreamGeometryContext ctx = result.Open())
using (var parser = new PathMarkupParser())
{
PathMarkupParser parser = new PathMarkupParser(ctx);
parser.Parse(s);
return result;
}
return parser.Parse(s);
}
}
/// <inheritdoc/>

127
tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs

@ -8,53 +8,128 @@ using Xunit;
namespace Avalonia.Visuals.UnitTests.Media
{
using System.Linq;
public class PathMarkupParserTests
{
[Fact]
public void Parses_Move()
{
using (AvaloniaLocator.EnterScope())
{
var result = new Mock<IStreamGeometryContextImpl>();
var parser = PrepareParser(result);
using (var parser = new PathMarkupParser())
{
var geometry = parser.Parse("M10 10");
parser.Parse("M10 10");
var figure = geometry.Figures.First();
result.Verify(x => x.BeginFigure(new Point(10, 10), true));
Assert.Equal(new Point(10, 10), figure.StartPoint);
}
}
[Fact]
public void Parses_Line()
{
using (AvaloniaLocator.EnterScope())
using (var parser = new PathMarkupParser())
{
var result = new Mock<IStreamGeometryContextImpl>();
var geometry = parser.Parse("M0 0L10 10");
var parser = PrepareParser(result);
var figure = geometry.Figures.First();
parser.Parse("M0 0L10 10");
var segment = figure.Segments.First();
result.Verify(x => x.LineTo(new Point(10, 10)));
Assert.IsType<LineSegment>(segment);
var lineSegment = (LineSegment)segment;
Assert.Equal(new Point(10, 10), lineSegment.Point);
}
}
[Fact]
public void Parses_Close()
{
using (AvaloniaLocator.EnterScope())
using (var parser = new PathMarkupParser())
{
var result = new Mock<IStreamGeometryContextImpl>();
var geometry = parser.Parse("M0 0L10 10z");
var figure = geometry.Figures.First();
Assert.True(figure.IsClosed);
}
}
[Fact]
public void Parses_FillMode_Before_Move()
{
using (var parser = new PathMarkupParser())
{
var geometry = parser.Parse("F 1M0,0");
Assert.Equal(FillRule.NonZero, geometry.FillRule);
}
}
[Theory]
[InlineData("M0 0 10 10 20 20")]
[InlineData("M0,0 10,10 20,20")]
[InlineData("M0,0,10,10,20,20")]
public void Parses_Implicit_Line_Command_After_Move(string pathData)
{
using (var parser = new PathMarkupParser())
{
var geometry = parser.Parse(pathData);
var figure = geometry.Figures[0];
var segment = figure.Segments[0];
Assert.IsType<LineSegment>(segment);
var parser = PrepareParser(result);
var lineSegment = (LineSegment)segment;
parser.Parse("M0 0L10 10z");
Assert.Equal(new Point(10, 10), lineSegment.Point);
result.Verify(x => x.EndFigure(true));
figure = geometry.Figures[1];
segment = figure.Segments[0];
Assert.IsType<LineSegment>(segment);
lineSegment = (LineSegment)segment;
Assert.Equal(new Point(20, 20), lineSegment.Point);
}
}
[Theory]
[InlineData("m0 0 10 10 20 20")]
[InlineData("m0,0 10,10 20,20")]
[InlineData("m0,0,10,10,20,20")]
public void Parses_Implicit_Line_Command_After_Relative_Move(string pathData)
{
using (var parser = new PathMarkupParser())
{
var geometry = parser.Parse(pathData);
var figure = geometry.Figures[0];
var segment = figure.Segments[0];
Assert.IsType<LineSegment>(segment);
var lineSegment = (LineSegment)segment;
Assert.Equal(new Point(10, 10), lineSegment.Point);
segment = figure.Segments[1];
Assert.IsType<LineSegment>(segment);
lineSegment = (LineSegment)segment;
Assert.Equal(new Point(30, 30), lineSegment.Point);
}
}
[Theory]
[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")]
@ -75,29 +150,17 @@ namespace Avalonia.Visuals.UnitTests.Media
".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 ")]
[InlineData(
"F1M16,12C16,14.209 14.209,16 12,16 9.791,16 8,14.209 8,12 8,11.817 8.03,11.644 8.054,11.467L6.585,10 4,10 " +
"4,6.414 2.5,7.914 0,5.414 0,3.586 3.586,0 4.414,0 7.414,3 7.586,3 9,1.586 11.914,4.5 10.414,6 " +
"F1M16,12C16,14.209 14.209,16 12,16 9.791,16 8,14.209 8,12 8,11.817 8.03,11.644 8.054,11.467L6.585,10 4,10 " +
"4,6.414 2.5,7.914 0,5.414 0,3.586 3.586,0 4.414,0 7.414,3 7.586,3 9,1.586 11.914,4.5 10.414,6 " +
"12.461,8.046C14.45,8.278,16,9.949,16,12")]
public void Should_Parse(string pathData)
{
using (AvaloniaLocator.EnterScope())
using (var parser = new PathMarkupParser())
{
var parser = PrepareParser();
parser.Parse(pathData);
Assert.True(true);
}
}
private static PathMarkupParser PrepareParser(Mock<IStreamGeometryContextImpl> implMock = null)
{
AvaloniaLocator.CurrentMutable
.Bind<IPlatformRenderInterface>()
.ToConstant(Mock.Of<IPlatformRenderInterface>());
return new PathMarkupParser(
new StreamGeometryContext(implMock != null ? implMock.Object : Mock.Of<IStreamGeometryContextImpl>()));
}
}
}
Loading…
Cancel
Save