diff --git a/samples/ControlCatalog/Pages/CanvasPage.xaml b/samples/ControlCatalog/Pages/CanvasPage.xaml index 211c312e94..f934f57c22 100644 --- a/samples/ControlCatalog/Pages/CanvasPage.xaml +++ b/samples/ControlCatalog/Pages/CanvasPage.xaml @@ -13,7 +13,7 @@ - + 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); } diff --git a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs index 5b8e8724d8..4228745d6b 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs @@ -6,6 +6,8 @@ using Avalonia.Platform; using SharpDX.Direct2D1; using SweepDirection = SharpDX.Direct2D1.SweepDirection; using D2D = SharpDX.Direct2D1; +using Avalonia.Logging; +using System; namespace Avalonia.Direct2D1.Media { @@ -76,7 +78,20 @@ namespace Avalonia.Direct2D1.Media public void Dispose() { - _sink.Close(); + // Put a catch around sink.Close as it may throw if there were an error e.g. parsing a path. + try + { + _sink.Close(); + } + catch (Exception ex) + { + Logger.Error( + LogArea.Visual, + this, + "GeometrySink.Close exception: {Exception}", + ex); + } + _sink.Dispose(); } } diff --git a/tests/Avalonia.RenderTests/Shapes/PathTests.cs b/tests/Avalonia.RenderTests/Shapes/PathTests.cs index 9250b6a8a0..2e5d528bce 100644 --- a/tests/Avalonia.RenderTests/Shapes/PathTests.cs +++ b/tests/Avalonia.RenderTests/Shapes/PathTests.cs @@ -24,6 +24,260 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes { } +#if AVALONIA_CAIRO + [Fact(Skip = "Broken in Cairo: waiting for Skia")] +#else + [Fact] +#endif + public void Line_Absolute() + { + Decorator target = new Decorator + { + Width = 200, + Height = 200, + Child = new Path + { + Stroke = Brushes.Red, + StrokeThickness = 1, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Data = StreamGeometry.Parse("M 10,190 L 190,10 M0,0M200,200"), + } + }; + + RenderToFile(target); + CompareImages(); + } + +#if AVALONIA_CAIRO + [Fact(Skip = "Broken in Cairo: waiting for Skia")] +#else + [Fact] +#endif + public void Line_Relative() + { + Decorator target = new Decorator + { + Width = 200, + Height = 200, + Child = new Path + { + Stroke = Brushes.Red, + StrokeThickness = 1, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Data = StreamGeometry.Parse("M10,190 l190,-190 M0,0M200,200"), + } + }; + + RenderToFile(target); + CompareImages(); + } + +#if AVALONIA_CAIRO + [Fact(Skip = "Broken in Cairo: waiting for Skia")] +#else + [Fact] +#endif + public void HorizontalLine_Absolute() + { + Decorator target = new Decorator + { + Width = 200, + Height = 200, + Child = new Path + { + Stroke = Brushes.Red, + StrokeThickness = 1, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Data = StreamGeometry.Parse("M190,100 H10 M0,0M200,200"), + } + }; + + RenderToFile(target); + CompareImages(); + } + +#if AVALONIA_CAIRO + [Fact(Skip = "Broken in Cairo: waiting for Skia")] +#else + [Fact] +#endif + public void HorizontalLine_Relative() + { + Decorator target = new Decorator + { + Width = 200, + Height = 200, + Child = new Path + { + Stroke = Brushes.Red, + StrokeThickness = 1, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Data = StreamGeometry.Parse("M190,100 h-180 M0,0M200,200"), + } + }; + + RenderToFile(target); + CompareImages(); + } + +#if AVALONIA_CAIRO + [Fact(Skip = "Broken in Cairo: waiting for Skia")] +#else + [Fact] +#endif + public void VerticalLine_Absolute() + { + Decorator target = new Decorator + { + Width = 200, + Height = 200, + Child = new Path + { + Stroke = Brushes.Red, + StrokeThickness = 1, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Data = StreamGeometry.Parse("M100,190 V10 M0,0M200,200"), + } + }; + + RenderToFile(target); + CompareImages(); + } + +#if AVALONIA_CAIRO + [Fact(Skip = "Broken in Cairo: waiting for Skia")] +#else + [Fact] +#endif + public void VerticalLine_Relative() + { + Decorator target = new Decorator + { + Width = 200, + Height = 200, + Child = new Path + { + Stroke = Brushes.Red, + StrokeThickness = 1, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Data = StreamGeometry.Parse("M100,190 V-180 M0,0M200,200"), + } + }; + + RenderToFile(target); + CompareImages(); + } + +#if AVALONIA_CAIRO + [Fact(Skip = "Broken in Cairo: waiting for Skia")] +#else + [Fact] +#endif + public void CubicBezier_Absolute() + { + Decorator target = new Decorator + { + Width = 200, + Height = 200, + Child = new Path + { + Fill = Brushes.Gray, + Stroke = Brushes.Red, + StrokeThickness = 1, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Data = StreamGeometry.Parse("M190,0 C10,10 190,190 10,190 M0,0M200,200"), + } + }; + + RenderToFile(target); + CompareImages(); + } + +#if AVALONIA_CAIRO + [Fact(Skip = "Broken in Cairo: waiting for Skia")] +#else + [Fact] +#endif + public void CubicBezier_Relative() + { + Decorator target = new Decorator + { + Width = 200, + Height = 200, + Child = new Path + { + Fill = Brushes.Gray, + Stroke = Brushes.Red, + StrokeThickness = 1, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Data = StreamGeometry.Parse("M190,0 c-180,10 0,190 -180,190 M0,0M200,200"), + } + }; + + RenderToFile(target); + CompareImages(); + } + +#if AVALONIA_CAIRO + [Fact(Skip = "Broken in Cairo: waiting for Skia")] +#else + [Fact] +#endif + public void Arc_Absolute() + { + Decorator target = new Decorator + { + Width = 200, + Height = 200, + Child = new Path + { + Fill = Brushes.Gray, + Stroke = Brushes.Red, + StrokeThickness = 1, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Data = StreamGeometry.Parse("M190,100 A90,90 0 1,0 10,100 M0,0M200,200"), + } + }; + + RenderToFile(target); + CompareImages(); + } + +#if AVALONIA_CAIRO + [Fact(Skip = "Broken in Cairo: waiting for Skia")] +#else + [Fact] +#endif + public void Arc_Relative() + { + Decorator target = new Decorator + { + Width = 200, + Height = 200, + Child = new Path + { + Fill = Brushes.Gray, + Stroke = Brushes.Red, + StrokeThickness = 1, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Data = StreamGeometry.Parse("M190,100 a90,90 0 1,0 -180,0 M0,0M200,200"), + } + }; + + RenderToFile(target); + CompareImages(); + } + [Fact] public void Path_100px_Triangle_Centered() { diff --git a/tests/TestFiles/Cairo/Shapes/Path/Arc_Absolute.expected.png b/tests/TestFiles/Cairo/Shapes/Path/Arc_Absolute.expected.png new file mode 100644 index 0000000000..113cc908e6 Binary files /dev/null and b/tests/TestFiles/Cairo/Shapes/Path/Arc_Absolute.expected.png differ diff --git a/tests/TestFiles/Cairo/Shapes/Path/Arc_Relative.expected.png b/tests/TestFiles/Cairo/Shapes/Path/Arc_Relative.expected.png new file mode 100644 index 0000000000..113cc908e6 Binary files /dev/null and b/tests/TestFiles/Cairo/Shapes/Path/Arc_Relative.expected.png differ diff --git a/tests/TestFiles/Cairo/Shapes/Path/CubicBezier_Absolute.expected.png b/tests/TestFiles/Cairo/Shapes/Path/CubicBezier_Absolute.expected.png new file mode 100644 index 0000000000..8c8f5350ee Binary files /dev/null and b/tests/TestFiles/Cairo/Shapes/Path/CubicBezier_Absolute.expected.png differ diff --git a/tests/TestFiles/Cairo/Shapes/Path/CubicBezier_Relative.expected.png b/tests/TestFiles/Cairo/Shapes/Path/CubicBezier_Relative.expected.png new file mode 100644 index 0000000000..8c8f5350ee Binary files /dev/null and b/tests/TestFiles/Cairo/Shapes/Path/CubicBezier_Relative.expected.png differ diff --git a/tests/TestFiles/Cairo/Shapes/Path/HorizontalLine_Absolute.expected.png b/tests/TestFiles/Cairo/Shapes/Path/HorizontalLine_Absolute.expected.png new file mode 100644 index 0000000000..546ffec3bb Binary files /dev/null and b/tests/TestFiles/Cairo/Shapes/Path/HorizontalLine_Absolute.expected.png differ diff --git a/tests/TestFiles/Cairo/Shapes/Path/HorizontalLine_Relative.expected.png b/tests/TestFiles/Cairo/Shapes/Path/HorizontalLine_Relative.expected.png new file mode 100644 index 0000000000..546ffec3bb Binary files /dev/null and b/tests/TestFiles/Cairo/Shapes/Path/HorizontalLine_Relative.expected.png differ diff --git a/tests/TestFiles/Cairo/Shapes/Path/Line_Absolute.expected.png b/tests/TestFiles/Cairo/Shapes/Path/Line_Absolute.expected.png new file mode 100644 index 0000000000..4661a6a8c4 Binary files /dev/null and b/tests/TestFiles/Cairo/Shapes/Path/Line_Absolute.expected.png differ diff --git a/tests/TestFiles/Cairo/Shapes/Path/VerticalLine_Absolute.expected.png b/tests/TestFiles/Cairo/Shapes/Path/VerticalLine_Absolute.expected.png new file mode 100644 index 0000000000..b2e2beafd4 Binary files /dev/null and b/tests/TestFiles/Cairo/Shapes/Path/VerticalLine_Absolute.expected.png differ diff --git a/tests/TestFiles/Cairo/Shapes/Path/VerticalLine_Relative.expected.png b/tests/TestFiles/Cairo/Shapes/Path/VerticalLine_Relative.expected.png new file mode 100644 index 0000000000..ff36de2a5c Binary files /dev/null and b/tests/TestFiles/Cairo/Shapes/Path/VerticalLine_Relative.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Shapes/Path/Arc_Absolute.expected.png b/tests/TestFiles/Direct2D1/Shapes/Path/Arc_Absolute.expected.png new file mode 100644 index 0000000000..113cc908e6 Binary files /dev/null and b/tests/TestFiles/Direct2D1/Shapes/Path/Arc_Absolute.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Shapes/Path/Arc_Relative.expected.png b/tests/TestFiles/Direct2D1/Shapes/Path/Arc_Relative.expected.png new file mode 100644 index 0000000000..113cc908e6 Binary files /dev/null and b/tests/TestFiles/Direct2D1/Shapes/Path/Arc_Relative.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Shapes/Path/CubicBezier_Absolute.expected.png b/tests/TestFiles/Direct2D1/Shapes/Path/CubicBezier_Absolute.expected.png new file mode 100644 index 0000000000..8c8f5350ee Binary files /dev/null and b/tests/TestFiles/Direct2D1/Shapes/Path/CubicBezier_Absolute.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Shapes/Path/CubicBezier_Relative.expected.png b/tests/TestFiles/Direct2D1/Shapes/Path/CubicBezier_Relative.expected.png new file mode 100644 index 0000000000..8c8f5350ee Binary files /dev/null and b/tests/TestFiles/Direct2D1/Shapes/Path/CubicBezier_Relative.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Shapes/Path/HorizontalLine_Absolute.expected.png b/tests/TestFiles/Direct2D1/Shapes/Path/HorizontalLine_Absolute.expected.png new file mode 100644 index 0000000000..546ffec3bb Binary files /dev/null and b/tests/TestFiles/Direct2D1/Shapes/Path/HorizontalLine_Absolute.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Shapes/Path/HorizontalLine_Relative.expected.png b/tests/TestFiles/Direct2D1/Shapes/Path/HorizontalLine_Relative.expected.png new file mode 100644 index 0000000000..546ffec3bb Binary files /dev/null and b/tests/TestFiles/Direct2D1/Shapes/Path/HorizontalLine_Relative.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Shapes/Path/Line_Absolute.expected.png b/tests/TestFiles/Direct2D1/Shapes/Path/Line_Absolute.expected.png new file mode 100644 index 0000000000..4661a6a8c4 Binary files /dev/null and b/tests/TestFiles/Direct2D1/Shapes/Path/Line_Absolute.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Shapes/Path/Line_Relative.expected.png b/tests/TestFiles/Direct2D1/Shapes/Path/Line_Relative.expected.png new file mode 100644 index 0000000000..4661a6a8c4 Binary files /dev/null and b/tests/TestFiles/Direct2D1/Shapes/Path/Line_Relative.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Shapes/Path/VerticalLine_Absolute.expected.png b/tests/TestFiles/Direct2D1/Shapes/Path/VerticalLine_Absolute.expected.png new file mode 100644 index 0000000000..b2e2beafd4 Binary files /dev/null and b/tests/TestFiles/Direct2D1/Shapes/Path/VerticalLine_Absolute.expected.png differ diff --git a/tests/TestFiles/Direct2D1/Shapes/Path/VerticalLine_Relative.expected.png b/tests/TestFiles/Direct2D1/Shapes/Path/VerticalLine_Relative.expected.png new file mode 100644 index 0000000000..ff36de2a5c Binary files /dev/null and b/tests/TestFiles/Direct2D1/Shapes/Path/VerticalLine_Relative.expected.png differ diff --git a/tests/TestFiles/Skia/Shapes/Path/Arc_Absolute.expected.png b/tests/TestFiles/Skia/Shapes/Path/Arc_Absolute.expected.png new file mode 100644 index 0000000000..113cc908e6 Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Path/Arc_Absolute.expected.png differ diff --git a/tests/TestFiles/Skia/Shapes/Path/Arc_Relative.expected.png b/tests/TestFiles/Skia/Shapes/Path/Arc_Relative.expected.png new file mode 100644 index 0000000000..113cc908e6 Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Path/Arc_Relative.expected.png differ diff --git a/tests/TestFiles/Skia/Shapes/Path/CubicBezier_Absolute.expected.png b/tests/TestFiles/Skia/Shapes/Path/CubicBezier_Absolute.expected.png new file mode 100644 index 0000000000..8c8f5350ee Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Path/CubicBezier_Absolute.expected.png differ diff --git a/tests/TestFiles/Skia/Shapes/Path/CubicBezier_Relative.expected.png b/tests/TestFiles/Skia/Shapes/Path/CubicBezier_Relative.expected.png new file mode 100644 index 0000000000..8c8f5350ee Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Path/CubicBezier_Relative.expected.png differ diff --git a/tests/TestFiles/Skia/Shapes/Path/HorizontalLine_Absolute.expected.png b/tests/TestFiles/Skia/Shapes/Path/HorizontalLine_Absolute.expected.png new file mode 100644 index 0000000000..546ffec3bb Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Path/HorizontalLine_Absolute.expected.png differ diff --git a/tests/TestFiles/Skia/Shapes/Path/HorizontalLine_Relative.expected.png b/tests/TestFiles/Skia/Shapes/Path/HorizontalLine_Relative.expected.png new file mode 100644 index 0000000000..546ffec3bb Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Path/HorizontalLine_Relative.expected.png differ diff --git a/tests/TestFiles/Skia/Shapes/Path/Line_Absolute.expected.png b/tests/TestFiles/Skia/Shapes/Path/Line_Absolute.expected.png new file mode 100644 index 0000000000..4661a6a8c4 Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Path/Line_Absolute.expected.png differ diff --git a/tests/TestFiles/Skia/Shapes/Path/Line_Relative.expected.png b/tests/TestFiles/Skia/Shapes/Path/Line_Relative.expected.png new file mode 100644 index 0000000000..4661a6a8c4 Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Path/Line_Relative.expected.png differ diff --git a/tests/TestFiles/Skia/Shapes/Path/VerticalLine_Absolute.expected.png b/tests/TestFiles/Skia/Shapes/Path/VerticalLine_Absolute.expected.png new file mode 100644 index 0000000000..b2e2beafd4 Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Path/VerticalLine_Absolute.expected.png differ diff --git a/tests/TestFiles/Skia/Shapes/Path/VerticalLine_Relative.expected.png b/tests/TestFiles/Skia/Shapes/Path/VerticalLine_Relative.expected.png new file mode 100644 index 0000000000..ff36de2a5c Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Path/VerticalLine_Relative.expected.png differ