From 40c21115489ee8c4d5059bce14f00ebc51fde917 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 20 Aug 2016 01:07:52 +0200 Subject: [PATCH] Fix path absolute/relative parsing logic. --- .../Media/PathMarkupParser.cs | 110 +++++++----------- 1 file changed, 45 insertions(+), 65 deletions(-) diff --git a/src/Avalonia.SceneGraph/Media/PathMarkupParser.cs b/src/Avalonia.SceneGraph/Media/PathMarkupParser.cs index 3c0150e2d3..a9b4c21948 100644 --- a/src/Avalonia.SceneGraph/Media/PathMarkupParser.cs +++ b/src/Avalonia.SceneGraph/Media/PathMarkupParser.cs @@ -17,21 +17,13 @@ namespace Avalonia.Media private static readonly Dictionary Commands = new Dictionary { { 'F', Command.FillRule }, - { 'f', Command.FillRule }, { 'M', Command.Move }, - { 'm', Command.MoveRelative }, { 'L', Command.Line }, - { 'l', Command.LineRelative }, { 'H', Command.HorizontalLine }, - { 'h', Command.HorizontalLineRelative }, { 'V', Command.VerticalLine }, - { 'v', Command.VerticalLineRelative }, { 'C', Command.CubicBezierCurve }, - { 'c', Command.CubicBezierCurveRelative }, { 'A', Command.Arc }, - { 'a', Command.Arc }, { 'Z', Command.Close }, - { 'z', Command.Close }, }; private static readonly Dictionary FillRules = new Dictionary @@ -63,18 +55,12 @@ namespace Avalonia.Media None, FillRule, Move, - MoveRelative, Line, - LineRelative, HorizontalLine, - HorizontalLineRelative, VerticalLine, - VerticalLineRelative, CubicBezierCurve, - CubicBezierCurveRelative, Arc, Close, - Eof, } /// @@ -87,11 +73,11 @@ namespace Avalonia.Media using (StringReader reader = new StringReader(s)) { - Command lastCommand = Command.None; - Command command; + Command command = Command.None; Point point = new Point(); + bool relative = false; - while ((command = ReadCommand(reader, lastCommand)) != Command.Eof) + while (ReadCommand(reader, ref command, ref relative)) { switch (command) { @@ -100,72 +86,58 @@ namespace Avalonia.Media break; case Command.Move: - case Command.MoveRelative: if (openFigure) { _context.EndFigure(false); } - point = command == Command.Move ? - ReadPoint(reader) : - ReadRelativePoint(reader, point); - + point = ReadPoint(reader, point, relative); _context.BeginFigure(point, true); openFigure = true; break; case Command.Line: - point = ReadPoint(reader); - _context.LineTo(point); - break; - - case Command.LineRelative: - point = ReadRelativePoint(reader, point); + point = ReadPoint(reader, point, relative); _context.LineTo(point); break; case Command.HorizontalLine: - point = point.WithX(ReadDouble(reader)); - _context.LineTo(point); - break; + if (!relative) + { + point = point.WithX(ReadDouble(reader)); + } + else + { + point = new Point(point.X + ReadDouble(reader), point.Y); + } - case Command.HorizontalLineRelative: - point = new Point(point.X + ReadDouble(reader), point.Y); _context.LineTo(point); break; case Command.VerticalLine: - point = point.WithY(ReadDouble(reader)); - _context.LineTo(point); - break; + if (!relative) + { + point = point.WithY(ReadDouble(reader)); + } + else + { + point = new Point(point.X, point.Y + ReadDouble(reader)); + } - case Command.VerticalLineRelative: - point = new Point(point.X, point.Y + ReadDouble(reader)); _context.LineTo(point); break; case Command.CubicBezierCurve: { - Point point1 = ReadPoint(reader); - Point point2 = ReadPoint(reader); - point = ReadPoint(reader); + Point point1 = ReadPoint(reader, point, relative); + Point point2 = ReadPoint(reader, point, relative); + point = ReadPoint(reader, point, relative); _context.CubicBezierTo(point1, point2, point); break; } - case Command.CubicBezierCurveRelative: - { - Point point1 = ReadRelativePoint(reader, point); - Point point2 = ReadRelativePoint(reader, point); - _context.CubicBezierTo(point, point1, point2); - point = point2; - break; - } - case Command.Arc: { - //example: A10,10 0 0,0 10,20 - //format - size rotationAngle isLargeArcFlag sweepDirectionFlag endPoint Size size = ReadSize(reader); ReadSeparator(reader); double rotationAngle = ReadDouble(reader); @@ -173,7 +145,7 @@ namespace Avalonia.Media bool isLargeArc = ReadBool(reader); ReadSeparator(reader); SweepDirection sweepDirection = ReadBool(reader) ? SweepDirection.Clockwise : SweepDirection.CounterClockwise; - point = ReadPoint(reader); + point = ReadPoint(reader, point, relative); _context.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection); break; @@ -187,8 +159,6 @@ namespace Avalonia.Media default: throw new NotSupportedException("Unsupported command"); } - - lastCommand = command; } if (openFigure) @@ -198,7 +168,10 @@ namespace Avalonia.Media } } - private static Command ReadCommand(StringReader reader, Command lastCommand) + private static bool ReadCommand( + StringReader reader, + ref Command command, + ref bool relative) { ReadWhitespace(reader); @@ -206,19 +179,19 @@ namespace Avalonia.Media if (i == -1) { - return Command.Eof; + return false; } else { char c = (char)i; - Command command = Command.None; + Command next = Command.None; - if (!Commands.TryGetValue(c, out command)) + if (!Commands.TryGetValue(char.ToUpperInvariant(c), out next)) { if ((char.IsDigit(c) || c == '.' || c == '+' || c == '-') && - (lastCommand != Command.None)) + (command != Command.None)) { - return lastCommand; + return true; } else { @@ -226,8 +199,10 @@ namespace Avalonia.Media } } + command = next; + relative = char.IsLower(c); reader.Read(); - return command; + return true; } } @@ -297,12 +272,17 @@ namespace Avalonia.Media return double.Parse(b.ToString(), CultureInfo.InvariantCulture); } - private static Point ReadPoint(StringReader reader) + private static Point ReadPoint(StringReader reader, Point current, bool relative) { + if (!relative) + { + current = new Point(); + } + ReadWhitespace(reader); - double x = ReadDouble(reader); + double x = current.X + ReadDouble(reader); ReadSeparator(reader); - double y = ReadDouble(reader); + double y = current.Y + ReadDouble(reader); return new Point(x, y); }