diff --git a/samples/TestApplicationShared/MainWindow.cs b/samples/TestApplicationShared/MainWindow.cs
index 4c27018c6f..534626027c 100644
--- a/samples/TestApplicationShared/MainWindow.cs
+++ b/samples/TestApplicationShared/MainWindow.cs
@@ -688,6 +688,15 @@ namespace TestApplication
[Canvas.LeftProperty] = 130,
[Canvas.TopProperty] = 79,
},
+ new Line
+ {
+ Width = 90,
+ Height = 70,
+ Stroke = Brushes.Red,
+ StrokeThickness = 2,
+ [Canvas.LeftProperty] = 30,
+ [Canvas.TopProperty] = 120
+ }
}
},
}
diff --git a/src/Perspex.Controls/Perspex.Controls.csproj b/src/Perspex.Controls/Perspex.Controls.csproj
index b563cdbe82..cf44ab2997 100644
--- a/src/Perspex.Controls/Perspex.Controls.csproj
+++ b/src/Perspex.Controls/Perspex.Controls.csproj
@@ -67,6 +67,7 @@
+
diff --git a/src/Perspex.Controls/Shapes/Line.cs b/src/Perspex.Controls/Shapes/Line.cs
new file mode 100644
index 0000000000..785ea7bbd1
--- /dev/null
+++ b/src/Perspex.Controls/Shapes/Line.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Perspex.Media;
+
+namespace Perspex.Controls.Shapes
+{
+ public class Line : Shape
+ {
+ private Geometry _geometry;
+
+ private Size _geometrySize;
+
+ public override Geometry DefiningGeometry
+ {
+ get
+ {
+ if (_geometry == null || _geometrySize != Bounds.Size)
+ {
+ var rect = new Rect(Bounds.Size).Deflate(StrokeThickness);
+ _geometry = new LineGeometry(rect.TopLeft, rect.BottomRight);
+ _geometrySize = Bounds.Size;
+ }
+
+ return _geometry;
+ }
+ }
+
+ protected override Size MeasureOverride(Size availableSize)
+ {
+ return new Size(StrokeThickness, StrokeThickness);
+ }
+ }
+}
diff --git a/src/Perspex.SceneGraph/Media/LineGeometry.cs b/src/Perspex.SceneGraph/Media/LineGeometry.cs
new file mode 100644
index 0000000000..196fdc40eb
--- /dev/null
+++ b/src/Perspex.SceneGraph/Media/LineGeometry.cs
@@ -0,0 +1,47 @@
+// Copyright (c) The Perspex Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using Perspex.Platform;
+
+namespace Perspex.Media
+{
+ ///
+ /// Represents the geometry of a line.
+ ///
+ public class LineGeometry : Geometry
+ {
+ private Point _startPoint;
+ private Point _endPoint;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The start point.
+ /// The end point.
+ public LineGeometry(Point startPoint, Point endPoint)
+ {
+ _startPoint = startPoint;
+ _endPoint = endPoint;
+ IPlatformRenderInterface factory = PerspexLocator.Current.GetService();
+ IStreamGeometryImpl impl = factory.CreateStreamGeometry();
+
+ using (IStreamGeometryContextImpl context = impl.Open())
+ {
+ context.BeginFigure(startPoint, false);
+ context.LineTo(endPoint);
+ context.EndFigure(false);
+ }
+
+ PlatformImpl = impl;
+ }
+
+ ///
+ public override Rect Bounds => new Rect(_startPoint, _endPoint);
+
+ ///
+ public override Geometry Clone()
+ {
+ return new LineGeometry(Bounds.TopLeft, Bounds.BottomRight);
+ }
+ }
+}
diff --git a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj
index a7be9919f3..f3079729e3 100644
--- a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj
+++ b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj
@@ -70,6 +70,7 @@
+
diff --git a/tests/Perspex.RenderTests/Perspex.Cairo.RenderTests.csproj b/tests/Perspex.RenderTests/Perspex.Cairo.RenderTests.csproj
index 60b3b02b11..dd6953d355 100644
--- a/tests/Perspex.RenderTests/Perspex.Cairo.RenderTests.csproj
+++ b/tests/Perspex.RenderTests/Perspex.Cairo.RenderTests.csproj
@@ -71,6 +71,7 @@
+
diff --git a/tests/Perspex.RenderTests/Perspex.Direct2D1.RenderTests.csproj b/tests/Perspex.RenderTests/Perspex.Direct2D1.RenderTests.csproj
index eb948aec81..2abf92fdb5 100644
--- a/tests/Perspex.RenderTests/Perspex.Direct2D1.RenderTests.csproj
+++ b/tests/Perspex.RenderTests/Perspex.Direct2D1.RenderTests.csproj
@@ -76,6 +76,7 @@
+
diff --git a/tests/Perspex.RenderTests/Perspex.Skia.RenderTests.csproj b/tests/Perspex.RenderTests/Perspex.Skia.RenderTests.csproj
index 14dd170a8f..08bba41fce 100644
--- a/tests/Perspex.RenderTests/Perspex.Skia.RenderTests.csproj
+++ b/tests/Perspex.RenderTests/Perspex.Skia.RenderTests.csproj
@@ -68,6 +68,7 @@
+
diff --git a/tests/Perspex.RenderTests/Shapes/LineTests.cs b/tests/Perspex.RenderTests/Shapes/LineTests.cs
new file mode 100644
index 0000000000..80eb7c75ca
--- /dev/null
+++ b/tests/Perspex.RenderTests/Shapes/LineTests.cs
@@ -0,0 +1,43 @@
+// Copyright (c) The Perspex Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using Perspex.Controls;
+using Perspex.Controls.Shapes;
+using Perspex.Media;
+using Xunit;
+
+#if PERSPEX_CAIRO
+namespace Perspex.Cairo.RenderTests.Shapes
+#elif PERSPEX_SKIA
+namespace Perspex.Skia.RenderTests
+#else
+namespace Perspex.Direct2D1.RenderTests.Shapes
+#endif
+{
+ public class LineTests : TestBase
+ {
+ public LineTests()
+ : base(@"Shapes\Line")
+ {
+ }
+
+ [Fact]
+ public void Line_1px_Stroke()
+ {
+ Decorator target = new Decorator
+ {
+ Padding = new Thickness(8),
+ Width = 200,
+ Height = 200,
+ Child = new Line
+ {
+ Stroke = Brushes.Black,
+ StrokeThickness = 1,
+ }
+ };
+
+ RenderToFile(target);
+ CompareImages();
+ }
+ }
+}
diff --git a/tests/TestFiles/Cairo/Shapes/Line/Line_1px_Stroke.expected.png b/tests/TestFiles/Cairo/Shapes/Line/Line_1px_Stroke.expected.png
new file mode 100644
index 0000000000..18ade2da0f
Binary files /dev/null and b/tests/TestFiles/Cairo/Shapes/Line/Line_1px_Stroke.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Shapes/Line/Line_1px_Stroke.expected.png b/tests/TestFiles/Direct2D1/Shapes/Line/Line_1px_Stroke.expected.png
new file mode 100644
index 0000000000..18ade2da0f
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Shapes/Line/Line_1px_Stroke.expected.png differ
diff --git a/tests/TestFiles/Skia/Shapes/Line/Line_1px_Stroke.expected.png b/tests/TestFiles/Skia/Shapes/Line/Line_1px_Stroke.expected.png
new file mode 100644
index 0000000000..18ade2da0f
Binary files /dev/null and b/tests/TestFiles/Skia/Shapes/Line/Line_1px_Stroke.expected.png differ