From 13d8263fa34a2da2f92b8609bf50b1a292d50d6d Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Mon, 25 Jan 2016 00:58:57 +0300 Subject: [PATCH 01/15] Added CubicBezierCurveRelative implementation option for path rendering. Fixed ReadDouble (whitespaces processing). --- src/Perspex.SceneGraph/Media/PathMarkupParser.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Perspex.SceneGraph/Media/PathMarkupParser.cs b/src/Perspex.SceneGraph/Media/PathMarkupParser.cs index e02f65caba..da56f1af6e 100644 --- a/src/Perspex.SceneGraph/Media/PathMarkupParser.cs +++ b/src/Perspex.SceneGraph/Media/PathMarkupParser.cs @@ -150,6 +150,15 @@ namespace Perspex.Media break; } + case Command.CubicBezierCurveRelative: + { + Point point1 = ReadRelativePoint(reader, point); + Point point2 = ReadRelativePoint(reader, point); + _context.BezierTo(point, point1, point2); + point = point2; + break; + } + case Command.Close: _context.EndFigure(true); openFigure = false; @@ -202,8 +211,9 @@ namespace Perspex.Media } } - private static double ReadDouble(TextReader reader) + private static double ReadDouble(StringReader reader) { + ReadWhitespace(reader); // TODO: Handle Infinity, NaN and scientific notation. StringBuilder b = new StringBuilder(); bool readSign = false; From e07d085ef51505e7d7d6d7fc6feccbfd9047dd30 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Mon, 25 Jan 2016 01:02:27 +0300 Subject: [PATCH 02/15] Fixed Line rendering (PointPair instead of Rect) and added unit-tests. --- src/Perspex.Controls/Shapes/Line.cs | 24 ++++++--- src/Perspex.SceneGraph/Media/LineGeometry.cs | 48 ++++++++++++++---- src/Perspex.SceneGraph/PointPair.cs | 48 ++++++++++++++++++ tests/Perspex.RenderTests/Shapes/LineTests.cs | 40 ++++++++++++++- .../Shapes/Line/Line_1px_Stroke.expected.png | Bin 618 -> 624 bytes .../Line_1px_Stroke_Reversed.expected.png | Bin 0 -> 629 bytes .../Line_1px_Stroke_Vertical.expected.png | Bin 0 -> 621 bytes .../Shapes/Line/Line_1px_Stroke.expected.png | Bin 618 -> 624 bytes .../Line_1px_Stroke_Reversed.expected.png | Bin 0 -> 629 bytes .../Line_1px_Stroke_Vertical.expected.png | Bin 0 -> 621 bytes .../Shapes/Line/Line_1px_Stroke.expected.png | Bin 618 -> 624 bytes .../Line_1px_Stroke_Reversed.expected.png | Bin 0 -> 629 bytes .../Line_1px_Stroke_Vertical.expected.png | Bin 0 -> 621 bytes 13 files changed, 142 insertions(+), 18 deletions(-) create mode 100644 src/Perspex.SceneGraph/PointPair.cs create mode 100644 tests/TestFiles/Cairo/Shapes/Line/Line_1px_Stroke_Reversed.expected.png create mode 100644 tests/TestFiles/Cairo/Shapes/Line/Line_1px_Stroke_Vertical.expected.png create mode 100644 tests/TestFiles/Direct2D1/Shapes/Line/Line_1px_Stroke_Reversed.expected.png create mode 100644 tests/TestFiles/Direct2D1/Shapes/Line/Line_1px_Stroke_Vertical.expected.png create mode 100644 tests/TestFiles/Skia/Shapes/Line/Line_1px_Stroke_Reversed.expected.png create mode 100644 tests/TestFiles/Skia/Shapes/Line/Line_1px_Stroke_Vertical.expected.png diff --git a/src/Perspex.Controls/Shapes/Line.cs b/src/Perspex.Controls/Shapes/Line.cs index 785ea7bbd1..f71cb216e4 100644 --- a/src/Perspex.Controls/Shapes/Line.cs +++ b/src/Perspex.Controls/Shapes/Line.cs @@ -9,19 +9,31 @@ namespace Perspex.Controls.Shapes { public class Line : Shape { - private Geometry _geometry; + public static readonly PerspexProperty PointPairProperty = + PerspexProperty.Register("PointPair"); - private Size _geometrySize; + private LineGeometry _geometry; + private PointPair _pointPair; + + public Line() + { + StrokeThickness = 1; + } + + public PointPair PointPair + { + get { return GetValue(PointPairProperty); } + set { SetValue(PointPairProperty, value); } + } public override Geometry DefiningGeometry { get { - if (_geometry == null || _geometrySize != Bounds.Size) + if (_geometry == null || _pointPair == null || PointPair.P1 != _pointPair.P1 || PointPair.P2 != _pointPair.P2) { - var rect = new Rect(Bounds.Size).Deflate(StrokeThickness); - _geometry = new LineGeometry(rect.TopLeft, rect.BottomRight); - _geometrySize = Bounds.Size; + _pointPair = PointPair; + _geometry = new LineGeometry(_pointPair); } return _geometry; diff --git a/src/Perspex.SceneGraph/Media/LineGeometry.cs b/src/Perspex.SceneGraph/Media/LineGeometry.cs index 196fdc40eb..6efc5c9ead 100644 --- a/src/Perspex.SceneGraph/Media/LineGeometry.cs +++ b/src/Perspex.SceneGraph/Media/LineGeometry.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using Perspex.Platform; +using System; namespace Perspex.Media { @@ -10,25 +11,22 @@ namespace Perspex.Media /// public class LineGeometry : Geometry { - private Point _startPoint; - private Point _endPoint; + private PointPair _pointPair; /// /// Initializes a new instance of the class. /// - /// The start point. - /// The end point. - public LineGeometry(Point startPoint, Point endPoint) + /// The pointPair. + public LineGeometry(PointPair pointPair) { - _startPoint = startPoint; - _endPoint = endPoint; + _pointPair = pointPair; IPlatformRenderInterface factory = PerspexLocator.Current.GetService(); IStreamGeometryImpl impl = factory.CreateStreamGeometry(); using (IStreamGeometryContextImpl context = impl.Open()) { - context.BeginFigure(startPoint, false); - context.LineTo(endPoint); + context.BeginFigure(_pointPair.P1, false); + context.LineTo(_pointPair.P2); context.EndFigure(false); } @@ -36,12 +34,40 @@ namespace Perspex.Media } /// - public override Rect Bounds => new Rect(_startPoint, _endPoint); + public override Rect Bounds + { + get + { + double xMin, yMin, xMax, yMax; + if (_pointPair.P1.X <= _pointPair.P2.X) + { + xMin = _pointPair.P1.X; + xMax = _pointPair.P2.X; + } + else + { + xMin = _pointPair.P2.X; + xMax = _pointPair.P1.X; + } + if (_pointPair.P1.Y <= _pointPair.P2.Y) + { + yMin = _pointPair.P1.Y; + yMax = _pointPair.P2.Y; + } + else + { + yMin = _pointPair.P2.Y; + yMax = _pointPair.P1.Y; + } + + return new Rect(xMin, yMin, xMax - xMin, yMax - yMin); + } + } /// public override Geometry Clone() { - return new LineGeometry(Bounds.TopLeft, Bounds.BottomRight); + return new LineGeometry(new PointPair(_pointPair.P1, _pointPair.P2)); } } } diff --git a/src/Perspex.SceneGraph/PointPair.cs b/src/Perspex.SceneGraph/PointPair.cs new file mode 100644 index 0000000000..cc036f13f8 --- /dev/null +++ b/src/Perspex.SceneGraph/PointPair.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Perspex +{ + /// + /// Defines a PointPair. + /// + public class PointPair + { + /// + /// The first point. + /// + public Point P1 { get; set; } + + /// + /// The second point. + /// + public Point P2 { get; set; } + + /// + /// Initializes a new instance of the structure. + /// + /// The first point. + /// The second point. + public PointPair(Point p1, Point p2) + { + P1 = p1; + P2 = p2; + } + + /// + /// Initializes a new instance of the structure. + /// + /// The x position of first point. + /// The y position of first point. + /// The x position of second point. + /// The y position of second point. + public PointPair(double x1, double y1, double x2, double y2) + { + P1 = new Point(x1, y1); + P2 = new Point(x2, y2); + } + } +} diff --git a/tests/Perspex.RenderTests/Shapes/LineTests.cs b/tests/Perspex.RenderTests/Shapes/LineTests.cs index 80eb7c75ca..2e836a898d 100644 --- a/tests/Perspex.RenderTests/Shapes/LineTests.cs +++ b/tests/Perspex.RenderTests/Shapes/LineTests.cs @@ -26,13 +26,51 @@ namespace Perspex.Direct2D1.RenderTests.Shapes { Decorator target = new Decorator { - Padding = new Thickness(8), Width = 200, Height = 200, Child = new Line { Stroke = Brushes.Black, StrokeThickness = 1, + PointPair = new PointPair(0, 0, 200, 200) + } + }; + + RenderToFile(target); + CompareImages(); + } + + [Fact] + public void Line_1px_Stroke_Reversed() + { + Decorator target = new Decorator + { + Width = 200, + Height = 200, + Child = new Line + { + Stroke = Brushes.Black, + StrokeThickness = 1, + PointPair = new PointPair(200, 0, 0, 200) + } + }; + + RenderToFile(target); + CompareImages(); + } + + [Fact] + public void Line_1px_Stroke_Vertical() + { + Decorator target = new Decorator + { + Width = 200, + Height = 200, + Child = new Line + { + Stroke = Brushes.Black, + StrokeThickness = 1, + PointPair = new PointPair(100, 200, 100, 0) } }; diff --git a/tests/TestFiles/Cairo/Shapes/Line/Line_1px_Stroke.expected.png b/tests/TestFiles/Cairo/Shapes/Line/Line_1px_Stroke.expected.png index 18ade2da0f3d2f0e70679fdbcc139ddfc43265a6..f0a6a9b10984cd1276deb34e741a0a9ba815a51b 100644 GIT binary patch literal 624 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(GggNy^j3F{C2y?PW(!215asgB;!U+8YaJmp{1WAj;Fz829+hH`@cRk0}cM oP!!@&YE&2{Mno70AGeZsk`ufzBV)xvV5(v8boFyt=akR{0E2FQp#T5? literal 618 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(GggNyO8|F{C2y?d6TUha5y$4^EyFFok;&PnPOJ-gCz|CmnrO;a2slob?S* zD-iq$K3!P9^Zeas^M3RH*mQ1hANL#qPL_!dqr{L7gBIPsVM%xNb!1@J z*w6hZk(GggN#4`NF{C2y?d6M{4Gui42Sw8Uuf5UM#qqr`o7Gt0lhh5yZGFGbl{2l@ u?|aV7UFaad&N51jgfKY3UwGi!8CEAb!3zP#lN^9ahr!d;&t;ucLK6V^2zq(| literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Cairo/Shapes/Line/Line_1px_Stroke_Vertical.expected.png b/tests/TestFiles/Cairo/Shapes/Line/Line_1px_Stroke_Vertical.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..845961351cca646869f1d7ba644262407a61ac98 GIT binary patch literal 621 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(GggN!-)LF{C2y?d6TU42lBG2Zg8Bzf@`YbBx7!(o?Roic{ssl&@7ja8eLp jVR9TLMo1X!Pcw@yXX;<`K5s2B$uM}j`njxgN@xNAErwO? literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Direct2D1/Shapes/Line/Line_1px_Stroke.expected.png b/tests/TestFiles/Direct2D1/Shapes/Line/Line_1px_Stroke.expected.png index 18ade2da0f3d2f0e70679fdbcc139ddfc43265a6..f0a6a9b10984cd1276deb34e741a0a9ba815a51b 100644 GIT binary patch literal 624 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(GggNy^j3F{C2y?PW(!215asgB;!U+8YaJmp{1WAj;Fz829+hH`@cRk0}cM oP!!@&YE&2{Mno70AGeZsk`ufzBV)xvV5(v8boFyt=akR{0E2FQp#T5? literal 618 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(GggNyO8|F{C2y?d6TUha5y$4^EyFFok;&PnPOJ-gCz|CmnrO;a2slob?S* zD-iq$K3!P9^Zeas^M3RH*mQ1hANL#qPL_!dqr{L7gBIPsVM%xNb!1@J z*w6hZk(GggN#4`NF{C2y?d6M{4Gui42Sw8Uuf5UM#qqr`o7Gt0lhh5yZGFGbl{2l@ u?|aV7UFaad&N51jgfKY3UwGi!8CEAb!3zP#lN^9ahr!d;&t;ucLK6V^2zq(| literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Direct2D1/Shapes/Line/Line_1px_Stroke_Vertical.expected.png b/tests/TestFiles/Direct2D1/Shapes/Line/Line_1px_Stroke_Vertical.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..845961351cca646869f1d7ba644262407a61ac98 GIT binary patch literal 621 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(GggN!-)LF{C2y?d6TU42lBG2Zg8Bzf@`YbBx7!(o?Roic{ssl&@7ja8eLp jVR9TLMo1X!Pcw@yXX;<`K5s2B$uM}j`njxgN@xNAErwO? literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Skia/Shapes/Line/Line_1px_Stroke.expected.png b/tests/TestFiles/Skia/Shapes/Line/Line_1px_Stroke.expected.png index 18ade2da0f3d2f0e70679fdbcc139ddfc43265a6..f0a6a9b10984cd1276deb34e741a0a9ba815a51b 100644 GIT binary patch literal 624 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(GggNy^j3F{C2y?PW(!215asgB;!U+8YaJmp{1WAj;Fz829+hH`@cRk0}cM oP!!@&YE&2{Mno70AGeZsk`ufzBV)xvV5(v8boFyt=akR{0E2FQp#T5? literal 618 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(GggNyO8|F{C2y?d6TUha5y$4^EyFFok;&PnPOJ-gCz|CmnrO;a2slob?S* zD-iq$K3!P9^Zeas^M3RH*mQ1hANL#qPL_!dqr{L7gBIPsVM%xNb!1@J z*w6hZk(GggN#4`NF{C2y?d6M{4Gui42Sw8Uuf5UM#qqr`o7Gt0lhh5yZGFGbl{2l@ u?|aV7UFaad&N51jgfKY3UwGi!8CEAb!3zP#lN^9ahr!d;&t;ucLK6V^2zq(| literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Skia/Shapes/Line/Line_1px_Stroke_Vertical.expected.png b/tests/TestFiles/Skia/Shapes/Line/Line_1px_Stroke_Vertical.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..845961351cca646869f1d7ba644262407a61ac98 GIT binary patch literal 621 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(GggN!-)LF{C2y?d6TU42lBG2Zg8Bzf@`YbBx7!(o?Roic{ssl&@7ja8eLp jVR9TLMo1X!Pcw@yXX;<`K5s2B$uM}j`njxgN@xNAErwO? literal 0 HcmV?d00001 From 5c969c40b8ca21bffbaca43c1e5a82132d9605d8 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Mon, 25 Jan 2016 01:06:36 +0300 Subject: [PATCH 03/15] Implemented Polygon, Polyline, PolylineGeometry. Added unit-tests with data and demo code in TestApplication. --- samples/TestApplicationShared/MainWindow.cs | 37 +++++++++++-- src/Perspex.Controls/Perspex.Controls.csproj | 2 + src/Perspex.Controls/Shapes/Polygon.cs | 28 ++++++++++ src/Perspex.Controls/Shapes/Polyline.cs | 33 +++++++++++ .../Media/PolylineGeometry.cs | 50 +++++++++++++++++ .../Perspex.SceneGraph.csproj | 2 + .../Perspex.Cairo.RenderTests.csproj | 2 + .../Perspex.Direct2D1.RenderTests.csproj | 2 + .../Perspex.Skia.RenderTests.csproj | 2 + .../Shapes/PolygonTests.cs | 24 ++++++++ .../Shapes/PolylineTests.cs | 52 ++++++++++++++++++ .../Polygon/Polygon_1px_Stroke.expected.png | Bin 0 -> 3969 bytes .../Polyline/Polyline_1px_Stroke.expected.png | Bin 0 -> 1604 bytes .../Polygon/Polygon_1px_Stroke.expected.png | Bin 0 -> 3969 bytes .../Polyline/Polyline_1px_Stroke.expected.png | Bin 0 -> 1604 bytes .../Polygon/Polygon_1px_Stroke.expected.png | Bin 0 -> 3969 bytes .../Polyline/Polyline_1px_Stroke.expected.png | Bin 0 -> 1604 bytes 17 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 src/Perspex.Controls/Shapes/Polygon.cs create mode 100644 src/Perspex.Controls/Shapes/Polyline.cs create mode 100644 src/Perspex.SceneGraph/Media/PolylineGeometry.cs create mode 100644 tests/Perspex.RenderTests/Shapes/PolygonTests.cs create mode 100644 tests/Perspex.RenderTests/Shapes/PolylineTests.cs create mode 100644 tests/TestFiles/Cairo/Shapes/Polygon/Polygon_1px_Stroke.expected.png create mode 100644 tests/TestFiles/Cairo/Shapes/Polyline/Polyline_1px_Stroke.expected.png create mode 100644 tests/TestFiles/Direct2D1/Shapes/Polygon/Polygon_1px_Stroke.expected.png create mode 100644 tests/TestFiles/Direct2D1/Shapes/Polyline/Polyline_1px_Stroke.expected.png create mode 100644 tests/TestFiles/Skia/Shapes/Polygon/Polygon_1px_Stroke.expected.png create mode 100644 tests/TestFiles/Skia/Shapes/Polyline/Polyline_1px_Stroke.expected.png diff --git a/samples/TestApplicationShared/MainWindow.cs b/samples/TestApplicationShared/MainWindow.cs index 02edd23634..a0e0a2848e 100644 --- a/samples/TestApplicationShared/MainWindow.cs +++ b/samples/TestApplicationShared/MainWindow.cs @@ -542,6 +542,17 @@ namespace TestApplication private static TabItem LayoutTab() { + var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3), + new Point(9, 1), new Point(10, 0), new Point(15, 0) }; + var polygonPoints = new Point[] { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) }; + for (int i = 0; i < polylinePoints.Length; i++) + { + polylinePoints[i] = polylinePoints[i] * 13; + } + for (int i = 0; i < polygonPoints.Length; i++) + { + polygonPoints[i] = polygonPoints[i] * 15; + } return new TabItem { Header = "Layout", @@ -690,13 +701,31 @@ namespace TestApplication }, new Line { - Width = 90, - Height = 70, Stroke = Brushes.Red, StrokeThickness = 2, + PointPair = new PointPair(120, 185, 30, 115) + }, + new Perspex.Controls.Shapes.Path + { + Fill = Brushes.Orange, + Data = StreamGeometry.Parse("M 30,250 c 50,0 50,-50 c 50,0 50,50 h -50 v 50 l -50,-50 Z"), + }, + new Polygon + { + Stroke = Brushes.DarkBlue, + Fill = Brushes.Violet, + Points = polygonPoints, + StrokeThickness = 1, + [Canvas.LeftProperty] = 150, + [Canvas.TopProperty] = 180, + }, + new Polyline + { + Stroke = Brushes.Brown, + Points = polylinePoints, [Canvas.LeftProperty] = 30, - [Canvas.TopProperty] = 120 - } + [Canvas.TopProperty] = 350, + }, } }, } diff --git a/src/Perspex.Controls/Perspex.Controls.csproj b/src/Perspex.Controls/Perspex.Controls.csproj index 394fdccd2d..e02af26c3f 100644 --- a/src/Perspex.Controls/Perspex.Controls.csproj +++ b/src/Perspex.Controls/Perspex.Controls.csproj @@ -48,6 +48,8 @@ + + diff --git a/src/Perspex.Controls/Shapes/Polygon.cs b/src/Perspex.Controls/Shapes/Polygon.cs new file mode 100644 index 0000000000..0e6d846d90 --- /dev/null +++ b/src/Perspex.Controls/Shapes/Polygon.cs @@ -0,0 +1,28 @@ +using Perspex.Media; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Perspex.Controls.Shapes +{ + public class Polygon : Shape + { + public static readonly PerspexProperty> PointsProperty = + PerspexProperty.Register>("Points"); + + public IList Points + { + get { return GetValue(PointsProperty); } + set { SetValue(PointsProperty, value); } + } + + public override Geometry DefiningGeometry => new PolylineGeometry(Points, true); + + protected override Size MeasureOverride(Size availableSize) + { + return new Size(StrokeThickness, StrokeThickness); + } + } +} diff --git a/src/Perspex.Controls/Shapes/Polyline.cs b/src/Perspex.Controls/Shapes/Polyline.cs new file mode 100644 index 0000000000..8e27535dc5 --- /dev/null +++ b/src/Perspex.Controls/Shapes/Polyline.cs @@ -0,0 +1,33 @@ +using Perspex.Media; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Perspex.Controls.Shapes +{ + public class Polyline: Shape + { + public static readonly PerspexProperty> PointsProperty = + PerspexProperty.Register>("Points"); + + public Polyline() + { + StrokeThickness = 1; // Default Thickness + } + + public IList Points + { + get { return GetValue(PointsProperty); } + set { SetValue(PointsProperty, value); } + } + + public override Geometry DefiningGeometry => new PolylineGeometry(Points, false); + + protected override Size MeasureOverride(Size availableSize) + { + return new Size(StrokeThickness, StrokeThickness); + } + } +} diff --git a/src/Perspex.SceneGraph/Media/PolylineGeometry.cs b/src/Perspex.SceneGraph/Media/PolylineGeometry.cs new file mode 100644 index 0000000000..244f027339 --- /dev/null +++ b/src/Perspex.SceneGraph/Media/PolylineGeometry.cs @@ -0,0 +1,50 @@ +using Perspex.Platform; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Perspex.Media +{ + /// + /// Represents the geometry of an polyline or polygon. + /// + public class PolylineGeometry : Geometry + { + private IList _points; + private bool _isFilled; + + public PolylineGeometry(IList points, bool isFilled) + { + _points = points; + _isFilled = isFilled; + IPlatformRenderInterface factory = PerspexLocator.Current.GetService(); + IStreamGeometryImpl impl = factory.CreateStreamGeometry(); + + using (IStreamGeometryContextImpl context = impl.Open()) + { + if (points.Count > 0) + { + context.BeginFigure(points[0], isFilled); + for (int i = 1; i < points.Count; i++) + { + context.LineTo(points[i]); + } + context.EndFigure(isFilled); + } + } + + PlatformImpl = impl; + } + + /// + public override Rect Bounds => PlatformImpl.Bounds; + + /// + public override Geometry Clone() + { + return new PolylineGeometry(new List(_points), _isFilled); + } + } +} diff --git a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj index ac08406268..b1e42b4ea9 100644 --- a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj +++ b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj @@ -71,6 +71,7 @@ + @@ -107,6 +108,7 @@ + diff --git a/tests/Perspex.RenderTests/Perspex.Cairo.RenderTests.csproj b/tests/Perspex.RenderTests/Perspex.Cairo.RenderTests.csproj index dd6953d355..18d7aeffcf 100644 --- a/tests/Perspex.RenderTests/Perspex.Cairo.RenderTests.csproj +++ b/tests/Perspex.RenderTests/Perspex.Cairo.RenderTests.csproj @@ -74,6 +74,8 @@ + + diff --git a/tests/Perspex.RenderTests/Perspex.Direct2D1.RenderTests.csproj b/tests/Perspex.RenderTests/Perspex.Direct2D1.RenderTests.csproj index 2abf92fdb5..a922029365 100644 --- a/tests/Perspex.RenderTests/Perspex.Direct2D1.RenderTests.csproj +++ b/tests/Perspex.RenderTests/Perspex.Direct2D1.RenderTests.csproj @@ -79,6 +79,8 @@ + + diff --git a/tests/Perspex.RenderTests/Perspex.Skia.RenderTests.csproj b/tests/Perspex.RenderTests/Perspex.Skia.RenderTests.csproj index 08bba41fce..e82de9eff2 100644 --- a/tests/Perspex.RenderTests/Perspex.Skia.RenderTests.csproj +++ b/tests/Perspex.RenderTests/Perspex.Skia.RenderTests.csproj @@ -70,6 +70,8 @@ + + diff --git a/tests/Perspex.RenderTests/Shapes/PolygonTests.cs b/tests/Perspex.RenderTests/Shapes/PolygonTests.cs new file mode 100644 index 0000000000..8e9c2cbb6e --- /dev/null +++ b/tests/Perspex.RenderTests/Shapes/PolygonTests.cs @@ -0,0 +1,24 @@ +// 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 PolygonTests : TestBase + { + public PolygonTests() + : base(@"Shapes\Polygon") + { + } + } +} diff --git a/tests/Perspex.RenderTests/Shapes/PolylineTests.cs b/tests/Perspex.RenderTests/Shapes/PolylineTests.cs new file mode 100644 index 0000000000..79e45ace28 --- /dev/null +++ b/tests/Perspex.RenderTests/Shapes/PolylineTests.cs @@ -0,0 +1,52 @@ +// 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 PolylineTests : TestBase + { + public PolylineTests() + : base(@"Shapes\Polyline") + { + } + + [Fact] + public void Polyline_1px_Stroke() + { + var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3), + new Point(9, 1), new Point(10, 0), new Point(15, 0) }; + var offsetPoint = new Point(0, 50); + for (int i = 0; i < polylinePoints.Length; i++) + { + polylinePoints[i] = polylinePoints[i] * 13 + offsetPoint; + } + + Decorator target = new Decorator + { + Padding = new Thickness(8), + Width = 230, + Height = 130, + Child = new Polyline + { + Stroke = Brushes.Brown, + Points = polylinePoints, + StrokeThickness = 1 + } + }; + + RenderToFile(target); + CompareImages(); + } + } +} diff --git a/tests/TestFiles/Cairo/Shapes/Polygon/Polygon_1px_Stroke.expected.png b/tests/TestFiles/Cairo/Shapes/Polygon/Polygon_1px_Stroke.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..2989e4bac47b430a77f1b29006510aa2e7155eb6 GIT binary patch literal 3969 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 Gi1;7bHjujj literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Cairo/Shapes/Polyline/Polyline_1px_Stroke.expected.png b/tests/TestFiles/Cairo/Shapes/Polyline/Polyline_1px_Stroke.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..7cbe87fa6c7972e51836270cc2c0ed38736e2e78 GIT binary patch literal 1604 zcmZuxe>l^59RF@@+1XVRYVv#N$62>bN-VRR3FB&po6$`%`4JJqx}25HFwA+hO^@Wq zMt)SAQ@L=fFi{A{q*Dsfa8f!CH}{?Euj@X~^ZC3#ulMWqetp01_w#(e+#}v@8?+6z z0RY(GewaiB;{>=li1pw}-BkY(43INaHzH8?#ApfxurL=d7XY}Gi(CnY0|0#1o#aAG zIyUp%ImXDS zaM*%#f#Hr@6!^p{S6)s$o>?+3=P=10_R?f}v$;uV>LKHeLJ`+oz|ZGJ6;8U*kE*hM z{Nw0tK7xbVrBq~gX8EtbAW;dY))X~}$@wsua+FS2w-*ZyIH+o=(FUyx=q20k1yB^e zCQ@BWD!@D5472`;Nj|(^8kTzt%4Ve?SQnpcr>Em_c-R@Q#psbFpQd>4{nCX#BQ`4l zF=43UwV##oc+1mou0)3n#OB~}yI^PV%@~;~=)-W62fF%Jm^htz&{{mcV@!$>57sUj ze>5=E7-C?3O*crVoAm}~+y-y79BLVV5{G8A77I6Wrt(CEMS~3uiLGTSd8B`xBEPL_ zoSX<@vuqJ!MqI%8g&BOS$d~-*3oBB5dpSpCdi>lDx9)9J}e*9E*U2K1$R@l zR+I3a zOpQUdsXQutpuRuQfM5~zm{)VZ80E}S9(x65^a<9yD1A0-1i?az`>1igfY45g9Kw~6 zvCsC33iGR>ihBOQ5bhNji&0WMJA5G_BZ}QBVJup(m@TQ8CYExYirn{!2S<(C!3i(vtnY8sBQ)?- z(8aEun<=w%MU{wWWAm;wV$bOxvdrvFv^^Fx{`% z-H_UCS)ktBWx@^WRc|2}8!C7A;eS4IDUGQqw={8?aYi%RU(5+F+8V)RZVgv~II#2T zMG6sRz)|9gpp`RWA#d$wK;8)^3mY?SiG{o_<=5)Y{r$Aqedhxbmd)}3?w$()PI)o5wS?GO* zG`q}GailB0_g3*lls#uE%^mW(kw1{QaZ{>!!ArEjM4(3iKSfeHGlfY59HK)uZ{+ozWIaA6w2nmhkGE)|*noAlpr6KTNZLu%X%#eN()+dY5 zFg)gZ!d9@j2f+g3KP6t=14{YnMC`f}jnoYLt|jgA_tP1kIb0Niu5m#N((>SWcmCX# zg@fUAq#89DyYA@gB?!;Pj)TgGWH7Ysq@Vv(|3A}X)2Y@fkcfsiRZS>05_eZ`QXP@W F`3HG3#Bu-t literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Direct2D1/Shapes/Polygon/Polygon_1px_Stroke.expected.png b/tests/TestFiles/Direct2D1/Shapes/Polygon/Polygon_1px_Stroke.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..2989e4bac47b430a77f1b29006510aa2e7155eb6 GIT binary patch literal 3969 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 Gi1;7bHjujj literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Direct2D1/Shapes/Polyline/Polyline_1px_Stroke.expected.png b/tests/TestFiles/Direct2D1/Shapes/Polyline/Polyline_1px_Stroke.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..7cbe87fa6c7972e51836270cc2c0ed38736e2e78 GIT binary patch literal 1604 zcmZuxe>l^59RF@@+1XVRYVv#N$62>bN-VRR3FB&po6$`%`4JJqx}25HFwA+hO^@Wq zMt)SAQ@L=fFi{A{q*Dsfa8f!CH}{?Euj@X~^ZC3#ulMWqetp01_w#(e+#}v@8?+6z z0RY(GewaiB;{>=li1pw}-BkY(43INaHzH8?#ApfxurL=d7XY}Gi(CnY0|0#1o#aAG zIyUp%ImXDS zaM*%#f#Hr@6!^p{S6)s$o>?+3=P=10_R?f}v$;uV>LKHeLJ`+oz|ZGJ6;8U*kE*hM z{Nw0tK7xbVrBq~gX8EtbAW;dY))X~}$@wsua+FS2w-*ZyIH+o=(FUyx=q20k1yB^e zCQ@BWD!@D5472`;Nj|(^8kTzt%4Ve?SQnpcr>Em_c-R@Q#psbFpQd>4{nCX#BQ`4l zF=43UwV##oc+1mou0)3n#OB~}yI^PV%@~;~=)-W62fF%Jm^htz&{{mcV@!$>57sUj ze>5=E7-C?3O*crVoAm}~+y-y79BLVV5{G8A77I6Wrt(CEMS~3uiLGTSd8B`xBEPL_ zoSX<@vuqJ!MqI%8g&BOS$d~-*3oBB5dpSpCdi>lDx9)9J}e*9E*U2K1$R@l zR+I3a zOpQUdsXQutpuRuQfM5~zm{)VZ80E}S9(x65^a<9yD1A0-1i?az`>1igfY45g9Kw~6 zvCsC33iGR>ihBOQ5bhNji&0WMJA5G_BZ}QBVJup(m@TQ8CYExYirn{!2S<(C!3i(vtnY8sBQ)?- z(8aEun<=w%MU{wWWAm;wV$bOxvdrvFv^^Fx{`% z-H_UCS)ktBWx@^WRc|2}8!C7A;eS4IDUGQqw={8?aYi%RU(5+F+8V)RZVgv~II#2T zMG6sRz)|9gpp`RWA#d$wK;8)^3mY?SiG{o_<=5)Y{r$Aqedhxbmd)}3?w$()PI)o5wS?GO* zG`q}GailB0_g3*lls#uE%^mW(kw1{QaZ{>!!ArEjM4(3iKSfeHGlfY59HK)uZ{+ozWIaA6w2nmhkGE)|*noAlpr6KTNZLu%X%#eN()+dY5 zFg)gZ!d9@j2f+g3KP6t=14{YnMC`f}jnoYLt|jgA_tP1kIb0Niu5m#N((>SWcmCX# zg@fUAq#89DyYA@gB?!;Pj)TgGWH7Ysq@Vv(|3A}X)2Y@fkcfsiRZS>05_eZ`QXP@W F`3HG3#Bu-t literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Skia/Shapes/Polygon/Polygon_1px_Stroke.expected.png b/tests/TestFiles/Skia/Shapes/Polygon/Polygon_1px_Stroke.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..2989e4bac47b430a77f1b29006510aa2e7155eb6 GIT binary patch literal 3969 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 Gi1;7bHjujj literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Skia/Shapes/Polyline/Polyline_1px_Stroke.expected.png b/tests/TestFiles/Skia/Shapes/Polyline/Polyline_1px_Stroke.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..7cbe87fa6c7972e51836270cc2c0ed38736e2e78 GIT binary patch literal 1604 zcmZuxe>l^59RF@@+1XVRYVv#N$62>bN-VRR3FB&po6$`%`4JJqx}25HFwA+hO^@Wq zMt)SAQ@L=fFi{A{q*Dsfa8f!CH}{?Euj@X~^ZC3#ulMWqetp01_w#(e+#}v@8?+6z z0RY(GewaiB;{>=li1pw}-BkY(43INaHzH8?#ApfxurL=d7XY}Gi(CnY0|0#1o#aAG zIyUp%ImXDS zaM*%#f#Hr@6!^p{S6)s$o>?+3=P=10_R?f}v$;uV>LKHeLJ`+oz|ZGJ6;8U*kE*hM z{Nw0tK7xbVrBq~gX8EtbAW;dY))X~}$@wsua+FS2w-*ZyIH+o=(FUyx=q20k1yB^e zCQ@BWD!@D5472`;Nj|(^8kTzt%4Ve?SQnpcr>Em_c-R@Q#psbFpQd>4{nCX#BQ`4l zF=43UwV##oc+1mou0)3n#OB~}yI^PV%@~;~=)-W62fF%Jm^htz&{{mcV@!$>57sUj ze>5=E7-C?3O*crVoAm}~+y-y79BLVV5{G8A77I6Wrt(CEMS~3uiLGTSd8B`xBEPL_ zoSX<@vuqJ!MqI%8g&BOS$d~-*3oBB5dpSpCdi>lDx9)9J}e*9E*U2K1$R@l zR+I3a zOpQUdsXQutpuRuQfM5~zm{)VZ80E}S9(x65^a<9yD1A0-1i?az`>1igfY45g9Kw~6 zvCsC33iGR>ihBOQ5bhNji&0WMJA5G_BZ}QBVJup(m@TQ8CYExYirn{!2S<(C!3i(vtnY8sBQ)?- z(8aEun<=w%MU{wWWAm;wV$bOxvdrvFv^^Fx{`% z-H_UCS)ktBWx@^WRc|2}8!C7A;eS4IDUGQqw={8?aYi%RU(5+F+8V)RZVgv~II#2T zMG6sRz)|9gpp`RWA#d$wK;8)^3mY?SiG{o_<=5)Y{r$Aqedhxbmd)}3?w$()PI)o5wS?GO* zG`q}GailB0_g3*lls#uE%^mW(kw1{QaZ{>!!ArEjM4(3iKSfeHGlfY59HK)uZ{+ozWIaA6w2nmhkGE)|*noAlpr6KTNZLu%X%#eN()+dY5 zFg)gZ!d9@j2f+g3KP6t=14{YnMC`f}jnoYLt|jgA_tP1kIb0Niu5m#N((>SWcmCX# zg@fUAq#89DyYA@gB?!;Pj)TgGWH7Ysq@Vv(|3A}X)2Y@fkcfsiRZS>05_eZ`QXP@W F`3HG3#Bu-t literal 0 HcmV?d00001 From bf9d9e270b331c0bb026ed065bb972194c9bb27c Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Mon, 25 Jan 2016 02:00:19 +0300 Subject: [PATCH 04/15] Added PolygonTests with evenOdd fill. Fixed errors after merge. --- .../Media/PathMarkupParser.cs | 2 +- .../Perspex.SceneGraph.csproj | 3 --- .../Shapes/PolygonTests.cs | 27 +++++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/Perspex.SceneGraph/Media/PathMarkupParser.cs b/src/Perspex.SceneGraph/Media/PathMarkupParser.cs index 643ec3136a..b0da89e878 100644 --- a/src/Perspex.SceneGraph/Media/PathMarkupParser.cs +++ b/src/Perspex.SceneGraph/Media/PathMarkupParser.cs @@ -168,7 +168,7 @@ namespace Perspex.Media { Point point1 = ReadRelativePoint(reader, point); Point point2 = ReadRelativePoint(reader, point); - _context.BezierTo(point, point1, point2); + _context.CubicBezierTo(point, point1, point2); point = point2; break; } diff --git a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj index 70c4c24647..1bfebfeb3f 100644 --- a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj +++ b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj @@ -106,9 +106,6 @@ - - - diff --git a/tests/Perspex.RenderTests/Shapes/PolygonTests.cs b/tests/Perspex.RenderTests/Shapes/PolygonTests.cs index 8e9c2cbb6e..284315a246 100644 --- a/tests/Perspex.RenderTests/Shapes/PolygonTests.cs +++ b/tests/Perspex.RenderTests/Shapes/PolygonTests.cs @@ -20,5 +20,32 @@ namespace Perspex.Direct2D1.RenderTests.Shapes : base(@"Shapes\Polygon") { } + + [Fact] + public void Polygon_1px_Stroke() + { + var polygonPoints = new Point[] { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) }; + for (int i = 0; i < polygonPoints.Length; i++) + { + polygonPoints[i] = polygonPoints[i] * 15; + } + + Decorator target = new Decorator + { + Padding = new Thickness(8), + Width = 200, + Height = 150, + Child = new Polygon + { + Stroke = Brushes.DarkBlue, + Fill = Brushes.Violet, + Points = polygonPoints, + StrokeThickness = 1 + } + }; + + RenderToFile(target); + CompareImages(); + } } } From 93e1f0d388359bc663f7dc593d4fa205704c9b55 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Mon, 25 Jan 2016 14:32:12 +0300 Subject: [PATCH 05/15] Removed PointPair. --- samples/TestApplicationShared/MainWindow.cs | 3 +- src/Perspex.Controls/Shapes/Line.cs | 29 +++++++---- src/Perspex.SceneGraph/Media/LineGeometry.cs | 38 ++++++++------- .../Media/PathMarkupParser.cs | 20 ++++---- .../Perspex.SceneGraph.csproj | 1 - src/Perspex.SceneGraph/PointPair.cs | 48 ------------------- tests/Perspex.RenderTests/Shapes/LineTests.cs | 9 ++-- 7 files changed, 59 insertions(+), 89 deletions(-) delete mode 100644 src/Perspex.SceneGraph/PointPair.cs diff --git a/samples/TestApplicationShared/MainWindow.cs b/samples/TestApplicationShared/MainWindow.cs index 68bde7f204..4fb3099b84 100644 --- a/samples/TestApplicationShared/MainWindow.cs +++ b/samples/TestApplicationShared/MainWindow.cs @@ -704,7 +704,8 @@ namespace TestApplication { Stroke = Brushes.Red, StrokeThickness = 2, - PointPair = new PointPair(120, 185, 30, 115) + StartPoint = new Point(120, 185), + EndPoint = new Point(30, 115) }, new Perspex.Controls.Shapes.Path { diff --git a/src/Perspex.Controls/Shapes/Line.cs b/src/Perspex.Controls/Shapes/Line.cs index f71cb216e4..40b00a1317 100644 --- a/src/Perspex.Controls/Shapes/Line.cs +++ b/src/Perspex.Controls/Shapes/Line.cs @@ -9,31 +9,42 @@ namespace Perspex.Controls.Shapes { public class Line : Shape { - public static readonly PerspexProperty PointPairProperty = - PerspexProperty.Register("PointPair"); + public static readonly PerspexProperty StartPointProperty = + PerspexProperty.Register("StartPoint"); + + public static readonly PerspexProperty EndPointProperty = + PerspexProperty.Register("EndPoint"); private LineGeometry _geometry; - private PointPair _pointPair; + private Point _startPoint; + private Point _endPoint; public Line() { StrokeThickness = 1; } - public PointPair PointPair + public Point StartPoint + { + get { return GetValue(StartPointProperty); } + set { SetValue(StartPointProperty, value); } + } + + public Point EndPoint { - get { return GetValue(PointPairProperty); } - set { SetValue(PointPairProperty, value); } + get { return GetValue(EndPointProperty); } + set { SetValue(EndPointProperty, value); } } public override Geometry DefiningGeometry { get { - if (_geometry == null || _pointPair == null || PointPair.P1 != _pointPair.P1 || PointPair.P2 != _pointPair.P2) + if (_geometry == null || StartPoint != _startPoint || EndPoint != _endPoint) { - _pointPair = PointPair; - _geometry = new LineGeometry(_pointPair); + _startPoint = StartPoint; + _endPoint = EndPoint; + _geometry = new LineGeometry(_startPoint, _endPoint); } return _geometry; diff --git a/src/Perspex.SceneGraph/Media/LineGeometry.cs b/src/Perspex.SceneGraph/Media/LineGeometry.cs index 6efc5c9ead..d9f24422b1 100644 --- a/src/Perspex.SceneGraph/Media/LineGeometry.cs +++ b/src/Perspex.SceneGraph/Media/LineGeometry.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using Perspex.Platform; -using System; namespace Perspex.Media { @@ -11,22 +10,25 @@ namespace Perspex.Media /// public class LineGeometry : Geometry { - private PointPair _pointPair; + private Point _startPoint; + private Point _endPoint; /// /// Initializes a new instance of the class. /// - /// The pointPair. - public LineGeometry(PointPair pointPair) + /// The start point. + /// The end point. + public LineGeometry(Point startPoint, Point endPoint) { - _pointPair = pointPair; + _startPoint = startPoint; + _endPoint = endPoint; IPlatformRenderInterface factory = PerspexLocator.Current.GetService(); IStreamGeometryImpl impl = factory.CreateStreamGeometry(); using (IStreamGeometryContextImpl context = impl.Open()) { - context.BeginFigure(_pointPair.P1, false); - context.LineTo(_pointPair.P2); + context.BeginFigure(_startPoint, false); + context.LineTo(_endPoint); context.EndFigure(false); } @@ -39,25 +41,25 @@ namespace Perspex.Media get { double xMin, yMin, xMax, yMax; - if (_pointPair.P1.X <= _pointPair.P2.X) + if (_startPoint.X <= _endPoint.X) { - xMin = _pointPair.P1.X; - xMax = _pointPair.P2.X; + xMin = _startPoint.X; + xMax = _endPoint.X; } else { - xMin = _pointPair.P2.X; - xMax = _pointPair.P1.X; + xMin = _endPoint.X; + xMax = _startPoint.X; } - if (_pointPair.P1.Y <= _pointPair.P2.Y) + if (_startPoint.Y <= _endPoint.Y) { - yMin = _pointPair.P1.Y; - yMax = _pointPair.P2.Y; + yMin = _startPoint.Y; + yMax = _endPoint.Y; } else { - yMin = _pointPair.P2.Y; - yMax = _pointPair.P1.Y; + yMin = _endPoint.Y; + yMax = _startPoint.Y; } return new Rect(xMin, yMin, xMax - xMin, yMax - yMin); @@ -67,7 +69,7 @@ namespace Perspex.Media /// public override Geometry Clone() { - return new LineGeometry(new PointPair(_pointPair.P1, _pointPair.P2)); + return new LineGeometry(_startPoint, _endPoint); } } } diff --git a/src/Perspex.SceneGraph/Media/PathMarkupParser.cs b/src/Perspex.SceneGraph/Media/PathMarkupParser.cs index b0da89e878..4d08d4ecf6 100644 --- a/src/Perspex.SceneGraph/Media/PathMarkupParser.cs +++ b/src/Perspex.SceneGraph/Media/PathMarkupParser.cs @@ -147,6 +147,16 @@ namespace Perspex.Media _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 @@ -164,15 +174,6 @@ namespace Perspex.Media break; } - case Command.CubicBezierCurveRelative: - { - Point point1 = ReadRelativePoint(reader, point); - Point point2 = ReadRelativePoint(reader, point); - _context.CubicBezierTo(point, point1, point2); - point = point2; - break; - } - case Command.Close: _context.EndFigure(true); openFigure = false; @@ -228,6 +229,7 @@ namespace Perspex.Media private static double ReadDouble(StringReader reader) { ReadWhitespace(reader); + // TODO: Handle Infinity, NaN and scientific notation. StringBuilder b = new StringBuilder(); bool readSign = false; diff --git a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj index 1bfebfeb3f..e6448449d9 100644 --- a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj +++ b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj @@ -106,7 +106,6 @@ - diff --git a/src/Perspex.SceneGraph/PointPair.cs b/src/Perspex.SceneGraph/PointPair.cs deleted file mode 100644 index cc036f13f8..0000000000 --- a/src/Perspex.SceneGraph/PointPair.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Perspex -{ - /// - /// Defines a PointPair. - /// - public class PointPair - { - /// - /// The first point. - /// - public Point P1 { get; set; } - - /// - /// The second point. - /// - public Point P2 { get; set; } - - /// - /// Initializes a new instance of the structure. - /// - /// The first point. - /// The second point. - public PointPair(Point p1, Point p2) - { - P1 = p1; - P2 = p2; - } - - /// - /// Initializes a new instance of the structure. - /// - /// The x position of first point. - /// The y position of first point. - /// The x position of second point. - /// The y position of second point. - public PointPair(double x1, double y1, double x2, double y2) - { - P1 = new Point(x1, y1); - P2 = new Point(x2, y2); - } - } -} diff --git a/tests/Perspex.RenderTests/Shapes/LineTests.cs b/tests/Perspex.RenderTests/Shapes/LineTests.cs index 2e836a898d..6cd40db424 100644 --- a/tests/Perspex.RenderTests/Shapes/LineTests.cs +++ b/tests/Perspex.RenderTests/Shapes/LineTests.cs @@ -32,7 +32,8 @@ namespace Perspex.Direct2D1.RenderTests.Shapes { Stroke = Brushes.Black, StrokeThickness = 1, - PointPair = new PointPair(0, 0, 200, 200) + StartPoint = new Point(0, 0), + EndPoint = new Point(200, 200) } }; @@ -51,7 +52,8 @@ namespace Perspex.Direct2D1.RenderTests.Shapes { Stroke = Brushes.Black, StrokeThickness = 1, - PointPair = new PointPair(200, 0, 0, 200) + StartPoint = new Point(200, 0), + EndPoint = new Point(0, 200) } }; @@ -70,7 +72,8 @@ namespace Perspex.Direct2D1.RenderTests.Shapes { Stroke = Brushes.Black, StrokeThickness = 1, - PointPair = new PointPair(100, 200, 100, 0) + StartPoint = new Point(100, 200), + EndPoint = new Point(100, 0) } }; From 9ea66ea262f02fb164f88c6f741839623fe56698 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Wed, 27 Jan 2016 09:35:28 +1030 Subject: [PATCH 06/15] dropped Perspex prefix folder from step --- docs/build.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build.md b/docs/build.md index b3be7581c4..c501b02c38 100644 --- a/docs/build.md +++ b/docs/build.md @@ -19,7 +19,7 @@ is linked as a submodule in the git repository, so run: git submodule update --init -The next step is to download the Skia native libraries. Run ```getnatives.ps1``` PowerShell script which can be found under the folder ```Perspex\src\Skia\```. +The next step is to download the Skia native libraries. Run ```getnatives.ps1``` PowerShell script which can be found under the folder ```src\Skia\```. ## Linux From d4b27f1332bf439986a968e3b9ba4ea616f21f68 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Wed, 27 Jan 2016 09:40:24 +1030 Subject: [PATCH 07/15] point to the Perspex organization --- docs/build.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/build.md b/docs/build.md index c501b02c38..db59f43154 100644 --- a/docs/build.md +++ b/docs/build.md @@ -39,7 +39,7 @@ Then install the needed packages: ### Clone the Perspex repository - git clone https://github.com/grokys/Perspex.git + git clone https://github.com/Perspex/Perspex.git We currently need to build our own private version of ReactiveUI as it doesn't work on mono. This is linked as a submodule in the git repository, so run: @@ -57,4 +57,4 @@ Set the TestApplication project as the startup project and click Run. There will be some compile errors in the tests, but ignore them for now. -You can track the Linux version's progress in the [Linux issue](https://github.com/grokys/Perspex/issues/78). +You can track the Linux version's progress in the [Linux issue](https://github.com/Perspex/Perspex/issues/78). From 18280bb8c646386979a89c069b17cdc577e70058 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Wed, 27 Jan 2016 09:40:53 +1030 Subject: [PATCH 08/15] and the other reference to the Skia folder --- docs/build.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build.md b/docs/build.md index db59f43154..e0a8698fc8 100644 --- a/docs/build.md +++ b/docs/build.md @@ -46,7 +46,7 @@ is linked as a submodule in the git repository, so run: git submodule update --init -The next step is to download the Skia native libraries. Run ```getnatives.sh``` script which can be found under the folder ```Perspex\src\Skia\```. +The next step is to download the Skia native libraries. Run ```getnatives.sh``` script which can be found under the folder ```src\Skia\```. ### Load the Project in MonoDevelop From 954fe6da11ba57bbcc085727801c16fb8efbdab3 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Wed, 27 Jan 2016 09:48:18 +1030 Subject: [PATCH 09/15] added a third project which impacts Windows-only dev --- docs/build.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/build.md b/docs/build.md index e0a8698fc8..935341c0d5 100644 --- a/docs/build.md +++ b/docs/build.md @@ -7,8 +7,11 @@ Perspex requires Visual Studio 2015 to build on Windows. ### Install GTK Sharp To compile the full project under windows, you must have [gtk-sharp](http://www.mono-project.com/download/#download-win) installed. However, if you're -not interested in building the cross-platform bits you can simply unload the Perspex.Cairo and -Perspex.Gtk project in Visual Studio. +not interested in building the cross-platform bits you can simply unload these projects from Visual Studio: + + - Perspex.Cairo + - Perspex.Cairo.RenderTests + - Perspex.Gtk ### Clone the Perspex repository From a74e9b3ff7dd8a660c5648a71f68c396b2b93d74 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 27 Jan 2016 02:27:12 +0300 Subject: [PATCH 10/15] Fixed `Path_Tick_Scaled`, `Path_Tick_Scaled_Stroke_8px` and `Path_Expander_With_Border` for Skia --- src/Skia/Perspex.Skia/DrawingContextImpl.cs | 16 +---- src/Skia/Perspex.Skia/MethodTable.cs | 35 ++++++++++- src/Skia/Perspex.Skia/PerspexHandleHolder.cs | 59 +++++++++++++++++++ src/Skia/Perspex.Skia/StreamGeometryImpl.cs | 40 +++++++++++-- tests/Perspex.RenderTests/Shapes/PathTests.cs | 12 ---- 5 files changed, 129 insertions(+), 33 deletions(-) diff --git a/src/Skia/Perspex.Skia/DrawingContextImpl.cs b/src/Skia/Perspex.Skia/DrawingContextImpl.cs index 405f021515..cce05bd1ae 100644 --- a/src/Skia/Perspex.Skia/DrawingContextImpl.cs +++ b/src/Skia/Perspex.Skia/DrawingContextImpl.cs @@ -37,18 +37,13 @@ namespace Perspex.Skia public void DrawGeometry(Brush brush, Pen pen, Geometry geometry) { var impl = ((StreamGeometryImpl) geometry.PlatformImpl); - var oldTransform = Transform; - if (!impl.Transform.IsIdentity) - Transform = impl.Transform*Transform; - var size = geometry.Bounds.Size; using(var fill = brush!=null?CreateBrush(brush, size):null) using (var stroke = pen?.Brush != null ? CreateBrush(pen, size) : null) { - MethodTable.Instance.DrawGeometry(Handle, impl.Path.Handle, fill != null ? fill.Brush : null, + MethodTable.Instance.DrawGeometry(Handle, impl.EffectivePath, fill != null ? fill.Brush : null, stroke != null ? stroke.Brush : null, impl.FillRule == FillRule.EvenOdd); } - Transform = oldTransform; } unsafe NativeBrushContainer CreateBrush(Brush brush, Size targetSize) @@ -196,14 +191,7 @@ namespace Perspex.Skia if(_currentTransform == value) return; _currentTransform = value; - _fmatrix[0] = (float)value.M11; - _fmatrix[1] = (float)value.M21; - _fmatrix[2] = (float)value.M31; - - _fmatrix[3] = (float)value.M12; - _fmatrix[4] = (float)value.M22; - _fmatrix[5] = (float)value.M32; - MethodTable.Instance.SetTransform(Handle, _fmatrix); + MethodTable.Instance.SetTransform(Handle, value); } } } diff --git a/src/Skia/Perspex.Skia/MethodTable.cs b/src/Skia/Perspex.Skia/MethodTable.cs index ba21588333..d17ead8720 100644 --- a/src/Skia/Perspex.Skia/MethodTable.cs +++ b/src/Skia/Perspex.Skia/MethodTable.cs @@ -47,9 +47,9 @@ namespace Perspex.Skia public _PopClip PopClip; [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void _SetTransform(IntPtr ctx, float[] matrix6); + public delegate void _SetTransform(IntPtr ctx, void* matrix6); - public _SetTransform SetTransform; + public _SetTransform SetTransformNative; [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void _DrawLine(IntPtr ctx, void* brush, float x1, float y1, float x2, float y2); @@ -66,6 +66,11 @@ namespace Perspex.Skia public _DisposePath DisposePath; + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate IntPtr _TransformPath(IntPtr path, void* matrix6); + + public _TransformPath TransformPathNative; + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void _DrawGeometry(IntPtr ctx, IntPtr path, void* fill, void* stroke, bool useEvenOdd); @@ -185,10 +190,34 @@ namespace Perspex.Skia typeof (_RebuildFormattedText), typeof (_DestroyFormattedText), typeof (_DrawFormattedText), - typeof (_SetOption) + typeof (_SetOption), + typeof (_TransformPath) }; + void ConvertMatrix(Matrix value, float* target) + { + target[0] = (float)value.M11; + target[1] = (float)value.M21; + target[2] = (float)value.M31; + + target[3] = (float)value.M12; + target[4] = (float)value.M22; + target[5] = (float)value.M32; + } + public unsafe IntPtr TransformPath(IntPtr path, Matrix matrix) + { + var tmp = stackalloc float[6]; + ConvertMatrix(matrix, tmp); + return TransformPathNative(path, tmp); + } + + public unsafe void SetTransform(IntPtr ctx, Matrix matrix) + { + var tmp = stackalloc float[6]; + ConvertMatrix(matrix, tmp); + SetTransformNative(ctx, tmp); + } protected MethodTable(IntPtr methodTable) { diff --git a/src/Skia/Perspex.Skia/PerspexHandleHolder.cs b/src/Skia/Perspex.Skia/PerspexHandleHolder.cs index d8f52e8f61..158a2f768c 100644 --- a/src/Skia/Perspex.Skia/PerspexHandleHolder.cs +++ b/src/Skia/Perspex.Skia/PerspexHandleHolder.cs @@ -44,4 +44,63 @@ namespace Perspex.Skia Dispose(); } } + + class RefCountable : IDisposable where T : PerspexHandleHolder + { + class Shared + { + public readonly T Target; + private int _refCount = 1; + + public Shared(T target) + { + Target = target; + } + + public void AddRef() => _refCount++; + public void Release() + { + _refCount--; + if (_refCount <= 0) + Target.Dispose(); + } + } + + public bool IsDisposed => _shared == null; + private Shared _shared; + public void CheckDisposed() + { + if (IsDisposed) + throw new ObjectDisposedException(GetType().FullName); + } + + public IntPtr Handle + { + get + { + CheckDisposed(); + return _shared.Target.Handle; + } + } + + public RefCountable(T handle) + { + _shared = new Shared(handle); + } + + public RefCountable(RefCountable other) + { + other._shared.Target.CheckDisposed(); + other._shared.AddRef(); + _shared = other._shared; + } + + public RefCountable Clone() => new RefCountable(this); + + public void Dispose() + { + _shared?.Release(); + _shared = null; + } + } } \ No newline at end of file diff --git a/src/Skia/Perspex.Skia/StreamGeometryImpl.cs b/src/Skia/Perspex.Skia/StreamGeometryImpl.cs index 3c62e65e7d..292af3d651 100644 --- a/src/Skia/Perspex.Skia/StreamGeometryImpl.cs +++ b/src/Skia/Perspex.Skia/StreamGeometryImpl.cs @@ -41,7 +41,11 @@ namespace Perspex.Skia class StreamGeometryImpl : IStreamGeometryImpl { - public SkPath Path; + RefCountable _path; + RefCountable _transformedPath; + private Matrix _transform = Matrix.Identity; + + public IntPtr EffectivePath => (_transformedPath ?? _path).Handle; public Rect GetRenderBounds(double strokeThickness) { @@ -51,11 +55,35 @@ namespace Perspex.Skia public Rect Bounds { get; private set; } - public Matrix Transform { get; set; } = Matrix.Identity; + public Matrix Transform + { + get { return _transform; } + set + { + if(_transform == value) + return; + _transform = value; + ApplyTransform(); + } + } + + void ApplyTransform() + { + if(_path == null) + return; + if (_transformedPath != null) + { + _transformedPath.Dispose(); + _transformedPath = null; + } + if (!_transform.IsIdentity) + _transformedPath = + new RefCountable(new SkPath(MethodTable.Instance.TransformPath(_path.Handle, Transform))); + } public IStreamGeometryImpl Clone() { - return new StreamGeometryImpl() {Path = Path, Transform = Transform, Bounds = Bounds}; + return new StreamGeometryImpl {_path = _path?.Clone(), _transformedPath = _transformedPath?.Clone(), _transform = Transform, Bounds = Bounds}; } public IStreamGeometryContextImpl Open() @@ -77,7 +105,11 @@ namespace Perspex.Skia { var arr = _elements.ToArray(); SkRect rc; - _geometryImpl.Path = new SkPath(MethodTable.Instance.CreatePath(arr, arr.Length, out rc)); + _geometryImpl._path?.Dispose(); + _geometryImpl._path = + new RefCountable(new SkPath(MethodTable.Instance.CreatePath(arr, arr.Length, out rc))); + _geometryImpl.ApplyTransform(); + _geometryImpl.Bounds = rc.ToRect(); } diff --git a/tests/Perspex.RenderTests/Shapes/PathTests.cs b/tests/Perspex.RenderTests/Shapes/PathTests.cs index 68b5956234..3d52b87ac2 100644 --- a/tests/Perspex.RenderTests/Shapes/PathTests.cs +++ b/tests/Perspex.RenderTests/Shapes/PathTests.cs @@ -46,11 +46,7 @@ namespace Perspex.Direct2D1.RenderTests.Shapes CompareImages(); } -#if PERSPEX_SKIA - [Fact(Skip = "FIXME")] -#else [Fact] -#endif public void Path_Tick_Scaled() { Decorator target = new Decorator @@ -73,11 +69,7 @@ namespace Perspex.Direct2D1.RenderTests.Shapes CompareImages(); } -#if PERSPEX_SKIA - [Fact(Skip = "FIXME")] -#else [Fact] -#endif public void Path_Tick_Scaled_Stroke_8px() { Decorator target = new Decorator @@ -100,11 +92,7 @@ namespace Perspex.Direct2D1.RenderTests.Shapes CompareImages(); } -#if PERSPEX_SKIA - [Fact(Skip = "FIXME")] -#else [Fact] -#endif public void Path_Expander_With_Border() { Decorator target = new Decorator From 3556a66b59481254f1d5631b48c0f6bb392f2bd8 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 27 Jan 2016 02:39:54 +0300 Subject: [PATCH 11/15] Use curl if available --- src/Skia/getnatives.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Skia/getnatives.sh b/src/Skia/getnatives.sh index 7ceace9db3..7486b35f80 100755 --- a/src/Skia/getnatives.sh +++ b/src/Skia/getnatives.sh @@ -1,7 +1,13 @@ #!/bin/sh -rm -rf native +rm -rf native native.zip mkdir -p native cd native +if which curl +then +curl `cat ../native.url` -o native.zip +else wget `cat ../native.url` -O native.zip -unzip native.zip +fi +unzip native.zip +chmod -R +x . From 7667d9d510cf7464aad8cde6c7db580782a7f414 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Thu, 28 Jan 2016 14:42:09 +0300 Subject: [PATCH 12/15] Added Binding to Polygon and Polyline. --- samples/ControlCatalog/Pages/CanvasPage.paml | 9 +++-- samples/TestApplicationShared/MainWindow.cs | 4 ++ .../Context/PerspexWiringContext.cs | 2 + .../Converters/PointsListTypeConverter.cs | 37 +++++++++++++++++++ .../Perspex.Markup.Xaml.csproj | 1 + 5 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/PointsListTypeConverter.cs diff --git a/samples/ControlCatalog/Pages/CanvasPage.paml b/samples/ControlCatalog/Pages/CanvasPage.paml index 4a3f682d17..8aaa8176bd 100644 --- a/samples/ControlCatalog/Pages/CanvasPage.paml +++ b/samples/ControlCatalog/Pages/CanvasPage.paml @@ -2,12 +2,13 @@ Canvas A panel which lays out its children by explicit coordinates - - + - + + + + - \ No newline at end of file diff --git a/samples/TestApplicationShared/MainWindow.cs b/samples/TestApplicationShared/MainWindow.cs index 4fb3099b84..30490f774b 100644 --- a/samples/TestApplicationShared/MainWindow.cs +++ b/samples/TestApplicationShared/MainWindow.cs @@ -725,6 +725,10 @@ namespace TestApplication { Stroke = Brushes.Brown, Points = polylinePoints, + StrokeThickness = 5, + StrokeJoin = PenLineJoin.Round, + StrokeStartLineCap = PenLineCap.Triangle, + StrokeEndLineCap = PenLineCap.Triangle, [Canvas.LeftProperty] = 30, [Canvas.TopProperty] = 350, }, diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs index e42df57d59..45e3e7285d 100644 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs +++ b/src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs @@ -21,6 +21,7 @@ using Perspex.Media.Imaging; using Perspex.Metadata; using Perspex.Platform; using Perspex.Styling; +using System.Collections.Generic; namespace Perspex.Markup.Xaml.Context { @@ -101,6 +102,7 @@ namespace Perspex.Markup.Xaml.Context new TypeConverterRegistration(typeof(PerspexList), new PerspexListTypeConverter()), new TypeConverterRegistration(typeof(IMemberSelector), new MemberSelectorTypeConverter()), new TypeConverterRegistration(typeof(Point), new PointTypeConverter()), + new TypeConverterRegistration(typeof(IList), new PointsListTypeConverter()), new TypeConverterRegistration(typeof(PerspexProperty), new PerspexPropertyTypeConverter()), new TypeConverterRegistration(typeof(RelativePoint), new RelativePointTypeConverter()), new TypeConverterRegistration(typeof(RelativeRect), new RelativeRectTypeConverter()), diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/PointsListTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/PointsListTypeConverter.cs new file mode 100644 index 0000000000..cff7443eff --- /dev/null +++ b/src/Markup/Perspex.Markup.Xaml/Converters/PointsListTypeConverter.cs @@ -0,0 +1,37 @@ +using OmniXaml.TypeConversion; +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace Perspex.Markup.Xaml.Converters +{ + public class PointsListTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value) + { + string strValue = (string)value; + string[] pointStrs = strValue.Split(new[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + var result = new List(pointStrs.Length); + foreach (var pointStr in pointStrs) + { + result.Add(Point.Parse(pointStr, culture)); + } + return result; + } + + public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj index d9cd4c6f63..74cf64f3ec 100644 --- a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj +++ b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj @@ -41,6 +41,7 @@ + From 5b79178947ffe9d8ed61117d241d62e911e36c12 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Thu, 28 Jan 2016 14:43:41 +0300 Subject: [PATCH 13/15] Added LineJoin parameter to geometric primitives. Fixed Bounds for Line, Polygon, Polyline. --- src/Perspex.Controls/Shapes/Line.cs | 5 --- src/Perspex.Controls/Shapes/Polygon.cs | 5 --- src/Perspex.Controls/Shapes/Polyline.cs | 5 --- src/Perspex.Controls/Shapes/Shape.cs | 4 +- .../Media/PolylineGeometry.cs | 30 +++++++++++++++ .../Perspex.SceneGraph.csproj | 2 +- src/Skia/Perspex.Skia/DrawingContextImpl.cs | 6 +-- .../Shapes/PolygonTests.cs | 33 +++++++++++++---- .../Shapes/PolylineTests.cs | 37 +++++++++++++++---- 9 files changed, 91 insertions(+), 36 deletions(-) diff --git a/src/Perspex.Controls/Shapes/Line.cs b/src/Perspex.Controls/Shapes/Line.cs index 40b00a1317..f9a8c9cbc5 100644 --- a/src/Perspex.Controls/Shapes/Line.cs +++ b/src/Perspex.Controls/Shapes/Line.cs @@ -50,10 +50,5 @@ namespace Perspex.Controls.Shapes return _geometry; } } - - protected override Size MeasureOverride(Size availableSize) - { - return new Size(StrokeThickness, StrokeThickness); - } } } diff --git a/src/Perspex.Controls/Shapes/Polygon.cs b/src/Perspex.Controls/Shapes/Polygon.cs index 0e6d846d90..9536d710a5 100644 --- a/src/Perspex.Controls/Shapes/Polygon.cs +++ b/src/Perspex.Controls/Shapes/Polygon.cs @@ -19,10 +19,5 @@ namespace Perspex.Controls.Shapes } public override Geometry DefiningGeometry => new PolylineGeometry(Points, true); - - protected override Size MeasureOverride(Size availableSize) - { - return new Size(StrokeThickness, StrokeThickness); - } } } diff --git a/src/Perspex.Controls/Shapes/Polyline.cs b/src/Perspex.Controls/Shapes/Polyline.cs index 8e27535dc5..ba6ce1c174 100644 --- a/src/Perspex.Controls/Shapes/Polyline.cs +++ b/src/Perspex.Controls/Shapes/Polyline.cs @@ -24,10 +24,5 @@ namespace Perspex.Controls.Shapes } public override Geometry DefiningGeometry => new PolylineGeometry(Points, false); - - protected override Size MeasureOverride(Size availableSize) - { - return new Size(StrokeThickness, StrokeThickness); - } } } diff --git a/src/Perspex.Controls/Shapes/Shape.cs b/src/Perspex.Controls/Shapes/Shape.cs index 6e7934b0e7..eb07be6a78 100644 --- a/src/Perspex.Controls/Shapes/Shape.cs +++ b/src/Perspex.Controls/Shapes/Shape.cs @@ -96,6 +96,8 @@ namespace Perspex.Controls.Shapes public PenLineCap StrokeEndLineCap { get; set; } = PenLineCap.Flat; + public PenLineJoin StrokeJoin { get; set; } = PenLineJoin.Miter; + public override void Render(DrawingContext context) { var geometry = RenderedGeometry; @@ -103,7 +105,7 @@ namespace Perspex.Controls.Shapes if (geometry != null) { var pen = new Pen(Stroke, StrokeThickness, new DashStyle(StrokeDashArray), - StrokeDashCap, StrokeStartLineCap, StrokeEndLineCap); + StrokeDashCap, StrokeStartLineCap, StrokeEndLineCap, StrokeJoin); context.DrawGeometry(Fill, pen, geometry); } } diff --git a/src/Perspex.SceneGraph/Media/PolylineGeometry.cs b/src/Perspex.SceneGraph/Media/PolylineGeometry.cs index 244f027339..817d1d8012 100644 --- a/src/Perspex.SceneGraph/Media/PolylineGeometry.cs +++ b/src/Perspex.SceneGraph/Media/PolylineGeometry.cs @@ -39,6 +39,36 @@ namespace Perspex.Media } /// + public override Rect Bounds + { + get + { + double xMin = double.MaxValue, yMin = double.MaxValue; + double xMax = double.MinValue, yMax = double.MinValue; + foreach (var point in _points) + { + if (point.X < xMin) + { + xMin = point.X; + } + else if (point.X > xMax) + { + xMax = point.X; + } + + if (point.Y < yMin) + { + yMin = point.Y; + } + else if (point.Y > yMax) + { + yMax = point.Y; + } + } + + return new Rect(xMin, yMin, xMax - xMin, yMax - yMin); + } + } public override Rect Bounds => PlatformImpl.Bounds; /// diff --git a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj index e6448449d9..6578b9c7b5 100644 --- a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj +++ b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj @@ -72,12 +72,12 @@ + - diff --git a/src/Skia/Perspex.Skia/DrawingContextImpl.cs b/src/Skia/Perspex.Skia/DrawingContextImpl.cs index 405f021515..a430ead5a3 100644 --- a/src/Skia/Perspex.Skia/DrawingContextImpl.cs +++ b/src/Skia/Perspex.Skia/DrawingContextImpl.cs @@ -56,7 +56,6 @@ namespace Perspex.Skia var rv = NativeBrushPool.Instance.Get(); rv.Brush->Opacity = brush.Opacity; - var solid = brush as SolidColorBrush; if (solid != null) { @@ -108,8 +107,6 @@ namespace Perspex.Skia rv.Brush->Bitmap = bitmap.Handle; rv.Brush->BitmapTileMode = tileBrush.TileMode; rv.Brush->BitmapTranslation = new SkiaPoint(-helper.DestinationRect.X, -helper.DestinationRect.Y); - - } return rv; @@ -119,8 +116,9 @@ namespace Perspex.Skia { var brush = CreateBrush(pen.Brush, targetSize); brush.Brush->Stroke = true; - brush.Brush->StrokeThickness = (float)pen.Thickness; + brush.Brush->StrokeThickness = (float)(pen.Thickness / ((Transform.M11 + Transform.M22) * 0.5)); brush.Brush->StrokeLineCap = pen.StartLineCap; + brush.Brush->StrokeLineJoin = pen.LineJoin; brush.Brush->StrokeMiterLimit = (float)pen.MiterLimit; if (pen.DashStyle?.Dashes != null) diff --git a/tests/Perspex.RenderTests/Shapes/PolygonTests.cs b/tests/Perspex.RenderTests/Shapes/PolygonTests.cs index 284315a246..dd1db5bd06 100644 --- a/tests/Perspex.RenderTests/Shapes/PolygonTests.cs +++ b/tests/Perspex.RenderTests/Shapes/PolygonTests.cs @@ -24,22 +24,17 @@ namespace Perspex.Direct2D1.RenderTests.Shapes [Fact] public void Polygon_1px_Stroke() { - var polygonPoints = new Point[] { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) }; - for (int i = 0; i < polygonPoints.Length; i++) - { - polygonPoints[i] = polygonPoints[i] * 15; - } - Decorator target = new Decorator { Padding = new Thickness(8), Width = 200, - Height = 150, + Height = 200, Child = new Polygon { Stroke = Brushes.DarkBlue, + Stretch = Stretch.Uniform, Fill = Brushes.Violet, - Points = polygonPoints, + Points = new [] { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) }, StrokeThickness = 1 } }; @@ -47,5 +42,27 @@ namespace Perspex.Direct2D1.RenderTests.Shapes RenderToFile(target); CompareImages(); } + + [Fact] + public void Polygon_NonUniformFill() + { + Decorator target = new Decorator + { + Padding = new Thickness(8), + Width = 400, + Height = 200, + Child = new Polygon + { + Stroke = Brushes.DarkBlue, + Stretch = Stretch.Fill, + Fill = Brushes.Violet, + Points = new[] { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) }, + StrokeThickness = 5, + } + }; + + RenderToFile(target); + CompareImages(); + } } } diff --git a/tests/Perspex.RenderTests/Shapes/PolylineTests.cs b/tests/Perspex.RenderTests/Shapes/PolylineTests.cs index 79e45ace28..72aac1b0f8 100644 --- a/tests/Perspex.RenderTests/Shapes/PolylineTests.cs +++ b/tests/Perspex.RenderTests/Shapes/PolylineTests.cs @@ -26,21 +26,17 @@ namespace Perspex.Direct2D1.RenderTests.Shapes { var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3), new Point(9, 1), new Point(10, 0), new Point(15, 0) }; - var offsetPoint = new Point(0, 50); - for (int i = 0; i < polylinePoints.Length; i++) - { - polylinePoints[i] = polylinePoints[i] * 13 + offsetPoint; - } Decorator target = new Decorator { Padding = new Thickness(8), - Width = 230, - Height = 130, + Width = 400, + Height = 200, Child = new Polyline { Stroke = Brushes.Brown, Points = polylinePoints, + Stretch = Stretch.Uniform, StrokeThickness = 1 } }; @@ -48,5 +44,32 @@ namespace Perspex.Direct2D1.RenderTests.Shapes RenderToFile(target); CompareImages(); } + + [Fact] + public void Polyline_10px_Stroke_PenLineJoin() + { + var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3), + new Point(9, 1), new Point(10, 0), new Point(15, 0) }; + + Decorator target = new Decorator + { + Padding = new Thickness(8), + Width = 400, + Height = 200, + Child = new Polyline + { + Stroke = Brushes.Brown, + Points = polylinePoints, + Stretch = Stretch.Uniform, + StrokeJoin = PenLineJoin.Round, + StrokeStartLineCap = PenLineCap.Round, + StrokeEndLineCap = PenLineCap.Round, + StrokeThickness = 10 + } + }; + + RenderToFile(target); + CompareImages(); + } } } From d8bec31dd8d2bdc7f2389e50798d9794da80311f Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Thu, 28 Jan 2016 16:36:22 +0300 Subject: [PATCH 14/15] Added tests data for Polyline and Polygon rendering. --- .../Media/PolylineGeometry.cs | 1 - src/Skia/Perspex.Skia/DrawingContextImpl.cs | 2 +- .../Shapes/PolygonTests.cs | 8 ++++++++ .../Shapes/PolylineTests.cs | 8 ++++++++ .../Polygon/Polygon_1px_Stroke.expected.png | Bin 3969 -> 5142 bytes .../Polygon_NonUniformFill.expected.png | Bin 0 -> 8742 bytes ...yline_10px_Stroke_PenLineJoin.expected.png | Bin 0 -> 3942 bytes .../Polygon/Polygon_1px_Stroke.expected.png | Bin 3969 -> 5142 bytes .../Polygon_NonUniformFill.expected.png | Bin 0 -> 8742 bytes ...yline_10px_Stroke_PenLineJoin.expected.png | Bin 0 -> 3942 bytes .../Polyline/Polyline_1px_Stroke.expected.png | Bin 1604 -> 2993 bytes .../Polygon/Polygon_1px_Stroke.expected.png | Bin 3969 -> 5142 bytes .../Polygon_NonUniformFill.expected.png | Bin 0 -> 8742 bytes ...yline_10px_Stroke_PenLineJoin.expected.png | Bin 0 -> 3942 bytes .../Polyline/Polyline_1px_Stroke.expected.png | Bin 1604 -> 2993 bytes 15 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tests/TestFiles/Cairo/Shapes/Polygon/Polygon_NonUniformFill.expected.png create mode 100644 tests/TestFiles/Cairo/Shapes/Polyline/Polyline_10px_Stroke_PenLineJoin.expected.png create mode 100644 tests/TestFiles/Direct2D1/Shapes/Polygon/Polygon_NonUniformFill.expected.png create mode 100644 tests/TestFiles/Direct2D1/Shapes/Polyline/Polyline_10px_Stroke_PenLineJoin.expected.png create mode 100644 tests/TestFiles/Skia/Shapes/Polygon/Polygon_NonUniformFill.expected.png create mode 100644 tests/TestFiles/Skia/Shapes/Polyline/Polyline_10px_Stroke_PenLineJoin.expected.png diff --git a/src/Perspex.SceneGraph/Media/PolylineGeometry.cs b/src/Perspex.SceneGraph/Media/PolylineGeometry.cs index 817d1d8012..0b431d6ae2 100644 --- a/src/Perspex.SceneGraph/Media/PolylineGeometry.cs +++ b/src/Perspex.SceneGraph/Media/PolylineGeometry.cs @@ -69,7 +69,6 @@ namespace Perspex.Media return new Rect(xMin, yMin, xMax - xMin, yMax - yMin); } } - public override Rect Bounds => PlatformImpl.Bounds; /// public override Geometry Clone() diff --git a/src/Skia/Perspex.Skia/DrawingContextImpl.cs b/src/Skia/Perspex.Skia/DrawingContextImpl.cs index d3fff009b7..8e7d481433 100644 --- a/src/Skia/Perspex.Skia/DrawingContextImpl.cs +++ b/src/Skia/Perspex.Skia/DrawingContextImpl.cs @@ -111,7 +111,7 @@ namespace Perspex.Skia { var brush = CreateBrush(pen.Brush, targetSize); brush.Brush->Stroke = true; - brush.Brush->StrokeThickness = (float)(pen.Thickness / ((Transform.M11 + Transform.M22) * 0.5)); + brush.Brush->StrokeThickness = (float)pen.Thickness; brush.Brush->StrokeLineCap = pen.StartLineCap; brush.Brush->StrokeLineJoin = pen.LineJoin; brush.Brush->StrokeMiterLimit = (float)pen.MiterLimit; diff --git a/tests/Perspex.RenderTests/Shapes/PolygonTests.cs b/tests/Perspex.RenderTests/Shapes/PolygonTests.cs index dd1db5bd06..94f6bf584a 100644 --- a/tests/Perspex.RenderTests/Shapes/PolygonTests.cs +++ b/tests/Perspex.RenderTests/Shapes/PolygonTests.cs @@ -21,7 +21,11 @@ namespace Perspex.Direct2D1.RenderTests.Shapes { } +#if PERSPEX_CAIRO + [Fact(Skip = "Caused by cairo bug")] +#else [Fact] +#endif public void Polygon_1px_Stroke() { Decorator target = new Decorator @@ -43,7 +47,11 @@ namespace Perspex.Direct2D1.RenderTests.Shapes CompareImages(); } +#if PERSPEX_CAIRO + [Fact(Skip = "Caused by cairo bug")] +#else [Fact] +#endif public void Polygon_NonUniformFill() { Decorator target = new Decorator diff --git a/tests/Perspex.RenderTests/Shapes/PolylineTests.cs b/tests/Perspex.RenderTests/Shapes/PolylineTests.cs index 72aac1b0f8..ca91be8e4b 100644 --- a/tests/Perspex.RenderTests/Shapes/PolylineTests.cs +++ b/tests/Perspex.RenderTests/Shapes/PolylineTests.cs @@ -21,7 +21,11 @@ namespace Perspex.Direct2D1.RenderTests.Shapes { } +#if PERSPEX_CAIRO + [Fact(Skip = "Caused by cairo bug")] +#else [Fact] +#endif public void Polyline_1px_Stroke() { var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3), @@ -45,7 +49,11 @@ namespace Perspex.Direct2D1.RenderTests.Shapes CompareImages(); } +#if PERSPEX_CAIRO + [Fact(Skip = "Caused by cairo bug")] +#else [Fact] +#endif public void Polyline_10px_Stroke_PenLineJoin() { var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3), diff --git a/tests/TestFiles/Cairo/Shapes/Polygon/Polygon_1px_Stroke.expected.png b/tests/TestFiles/Cairo/Shapes/Polygon/Polygon_1px_Stroke.expected.png index 2989e4bac47b430a77f1b29006510aa2e7155eb6..f62be2d4bfa4425998fff3e21b68b64d21c50fef 100644 GIT binary patch literal 5142 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 Gi1;7bHjujj diff --git a/tests/TestFiles/Cairo/Shapes/Polygon/Polygon_NonUniformFill.expected.png b/tests/TestFiles/Cairo/Shapes/Polygon/Polygon_NonUniformFill.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..0888c74c30360fd88ea2f85601e4ecccde9cb94e GIT binary patch literal 8742 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 literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Cairo/Shapes/Polyline/Polyline_10px_Stroke_PenLineJoin.expected.png b/tests/TestFiles/Cairo/Shapes/Polyline/Polyline_10px_Stroke_PenLineJoin.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..d908a572cbf8b6e42961456aa871beefe1024c3c GIT binary patch literal 3942 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 Gi1;7bHjujj diff --git a/tests/TestFiles/Direct2D1/Shapes/Polygon/Polygon_NonUniformFill.expected.png b/tests/TestFiles/Direct2D1/Shapes/Polygon/Polygon_NonUniformFill.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..0888c74c30360fd88ea2f85601e4ecccde9cb94e GIT binary patch literal 8742 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 literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Direct2D1/Shapes/Polyline/Polyline_10px_Stroke_PenLineJoin.expected.png b/tests/TestFiles/Direct2D1/Shapes/Polyline/Polyline_10px_Stroke_PenLineJoin.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..d908a572cbf8b6e42961456aa871beefe1024c3c GIT binary patch literal 3942 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 literal 1604 zcmZuxe>l^59RF@@+1XVRYVv#N$62>bN-VRR3FB&po6$`%`4JJqx}25HFwA+hO^@Wq zMt)SAQ@L=fFi{A{q*Dsfa8f!CH}{?Euj@X~^ZC3#ulMWqetp01_w#(e+#}v@8?+6z z0RY(GewaiB;{>=li1pw}-BkY(43INaHzH8?#ApfxurL=d7XY}Gi(CnY0|0#1o#aAG zIyUp%ImXDS zaM*%#f#Hr@6!^p{S6)s$o>?+3=P=10_R?f}v$;uV>LKHeLJ`+oz|ZGJ6;8U*kE*hM z{Nw0tK7xbVrBq~gX8EtbAW;dY))X~}$@wsua+FS2w-*ZyIH+o=(FUyx=q20k1yB^e zCQ@BWD!@D5472`;Nj|(^8kTzt%4Ve?SQnpcr>Em_c-R@Q#psbFpQd>4{nCX#BQ`4l zF=43UwV##oc+1mou0)3n#OB~}yI^PV%@~;~=)-W62fF%Jm^htz&{{mcV@!$>57sUj ze>5=E7-C?3O*crVoAm}~+y-y79BLVV5{G8A77I6Wrt(CEMS~3uiLGTSd8B`xBEPL_ zoSX<@vuqJ!MqI%8g&BOS$d~-*3oBB5dpSpCdi>lDx9)9J}e*9E*U2K1$R@l zR+I3a zOpQUdsXQutpuRuQfM5~zm{)VZ80E}S9(x65^a<9yD1A0-1i?az`>1igfY45g9Kw~6 zvCsC33iGR>ihBOQ5bhNji&0WMJA5G_BZ}QBVJup(m@TQ8CYExYirn{!2S<(C!3i(vtnY8sBQ)?- z(8aEun<=w%MU{wWWAm;wV$bOxvdrvFv^^Fx{`% z-H_UCS)ktBWx@^WRc|2}8!C7A;eS4IDUGQqw={8?aYi%RU(5+F+8V)RZVgv~II#2T zMG6sRz)|9gpp`RWA#d$wK;8)^3mY?SiG{o_<=5)Y{r$Aqedhxbmd)}3?w$()PI)o5wS?GO* zG`q}GailB0_g3*lls#uE%^mW(kw1{QaZ{>!!ArEjM4(3iKSfeHGlfY59HK)uZ{+ozWIaA6w2nmhkGE)|*noAlpr6KTNZLu%X%#eN()+dY5 zFg)gZ!d9@j2f+g3KP6t=14{YnMC`f}jnoYLt|jgA_tP1kIb0Niu5m#N((>SWcmCX# zg@fUAq#89DyYA@gB?!;Pj)TgGWH7Ysq@Vv(|3A}X)2Y@fkcfsiRZS>05_eZ`QXP@W F`3HG3#Bu-t diff --git a/tests/TestFiles/Skia/Shapes/Polygon/Polygon_1px_Stroke.expected.png b/tests/TestFiles/Skia/Shapes/Polygon/Polygon_1px_Stroke.expected.png index 2989e4bac47b430a77f1b29006510aa2e7155eb6..f62be2d4bfa4425998fff3e21b68b64d21c50fef 100644 GIT binary patch literal 5142 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 Gi1;7bHjujj diff --git a/tests/TestFiles/Skia/Shapes/Polygon/Polygon_NonUniformFill.expected.png b/tests/TestFiles/Skia/Shapes/Polygon/Polygon_NonUniformFill.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..0888c74c30360fd88ea2f85601e4ecccde9cb94e GIT binary patch literal 8742 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 literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Skia/Shapes/Polyline/Polyline_10px_Stroke_PenLineJoin.expected.png b/tests/TestFiles/Skia/Shapes/Polyline/Polyline_10px_Stroke_PenLineJoin.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..d908a572cbf8b6e42961456aa871beefe1024c3c GIT binary patch literal 3942 zcmb_fc|4Ts+ka-k9CD0gDx5JUl`N@KBwI7GW{EIHizdrKOj?l1Iuns4(GkhMCMqTS zE=(xPI3-H<7_v{c#Cw~0&+q-b@89qI@yyKk`Ci}azLxuX?&q$#nSrpNgdhY#!bXO= zXCMf6AN+oc;s@7e@zP=N1-o&^KnHr>F2x3akj_L?A_TpR7Fxf=2SFleBVD4EkKJ^? zN7(rfe>Bhg&K6`03e_KVJ)FUaI`Sa+>{*vnLZk^HAwhBb!|tlP>|N_^bS_$*l^YhC zzmTq^^lAHHjUOR8A(-!v?N1_#DXy}gd!vw%-CJHd-kwtV_1BRj<4L|V z)#FKiCzO+X_x5-bXQ%9I|KLh|GR|T-+u&1G3SdG%1p8N z`#?Xjrq=28)NAdG%hGzw(a+~ZIASm+mDUzMQ?*650zg0+P=fN z_t(O96h91}5bls&T6o=7>IfaDhD1>Yqkhh&w!JbrPM9E~@qj+JVIb|bD1L!vr6a=V z1d6Z^!UcccLI>Z0VB03#DdK=90eG2Jbn7$$q6-RL7u?KG+O37s0V_@PJXY8W7~A2< zPRCbVh9L?~c+kR6qGORVVA-boB*{)39EuMHpXmNtC!Z-mlmm?TAub~wM}UN_RSN}q z43{TBLtlh}2J5&Z&ohL<;4V)pxY8(ln$Tcz=_^&tuwEo~~Y<)7mdL zG^DJrA@U=!$eKNb&N9pXnRFAReod6@?Ae{nQhlR^2KyJw2wJqIyE`SW>vr8uBuXOg z#Ba=Ne%G7#b>BGnyu7ckPQH_O<467Eq{Y0f<_~MX4cTOG_5Gt=yIUp6w%)dOrcL9- zK@B)EYWHbr+oe6UB>9MplMAffPbJCruU0ZIhXDy^p#9*qw0%{X0XBC#anXs!-kzOG z-@7lOR4;7Z7Mq(PK<_}IkLozD?TQ#VcX4t#t|8|zP_QkD&1SpO62q}bZ4d=2nVpHV zYZ=(Dd@i?`{()W4Xq2H!2M!#NsLQ!p{)WT#tKzg?^(f(j{6%A91%uExMIifsz!-gx zOr*=-rT?bufN;~Z8}m5bbsOgbjGWZ{M;lXb%Pco{N=tqi7MZ?>VE*`2cc?5j?b%Ltg(P|5GRU7Hb24CGSTma{aQF8QiMC#M=)g}Ky zo;CyI5x%;a+ea(+pn5A)Q|XYB2u=leplxkdF_q)~?k?qq9`=ZQf(U#-6qoRX&2}gl z!&l$s3i%lXQ4F4$NHff0?3ka`O?fi{>|^hLS~)TkJJ_zV|IDkBrnz%$Za0iU?Mu`a ze5zN0DpPJz@Ri_=4!|#QbzA$CM$U>DaQ1?`Ugx??z1!mRs=mg*k|lY?-1qdZdP5e6 zFAAbHdIu@a3~b)_d9_}xY4*2X7ZYsYj<*g@%3hTM>PFYiu=`t&6Y`_1gQN9weojLE^GYj)B)b{tY zNGWJZEz2k`w+4f1+H;1icGE2H$fGf<+CXyT=!>@_M~xTX3=wG;dh@O}+Nny6(hvKa4$O>&fVY9r-`Atb_VdL#_K2fP!S2Urh^RotekOg$*#=h?)C(z(Xv&9-6dF{1{Ahf zA!w=_=mJG9d$Mq5H<=}4hB%Tq+hr>^m1X_Xuxe2afb8kRe|>x2cg zcVs8#+WOUvT`@O5yr{>6=b`f3Hrs+LlsJ{HEt{CY&4`xe%5$}wO%B&8*R{rcsMALC z5vz9VN>j_j72-^10}D=s!$+=cJwHQN)SdY)B=n*WZVP?UnrXfI;HNbF%GERKTttzC+Zq`c_C(=6NXuCALzOZnOmY8?SC#+>6FC;E5wRKP7 zr6~+%Ffu2cQv&wi>t}RT{bh;kAb_ zSi-LzGtYp3|6T}c=mvqtgaP?it%VQb_y172XIJVxF?ebA8bIBpmB32h4m^T zz({zi74~}rLRAzXf9O@*<{|Qc0}vf0y^2gpGG8**5d*^9(oqlhv;mKil3QDG%Mb>I zKkHTG10!qSEdWm#6afIRakAzzKxRb1yq^Lh-CLoGq0l~WF2~HQ{2SR0IPz=Z*({A3 zdT~?g=(I_&K%#C?okB^tXAh{rmB^8cPPR)Pw4|^(LN^M%(sU+f<_$k-NaM}Wempw$ zA(Oh0a%YYpxpj*aGgHq`>g^hu)0R3JkH@SGE4jGmk$jc9p8r#*>e|@4w!5OYNS%jowu` zB@DC`e=_mKa!ms6ug$VpMPJ7N+Nuhz54W*i+LXGPtZ7zs^n?`l?;faRP)X4z_j=4s z4?kv55suu*BWL}5P3J3%gy@0t7`8T*0y_v&lWcOBurC1LUnHzpXN^QvJ@6noS#Vxz znic;LW7n*2Q>+sJ=nm&ceQT2+@%;}{>3l0e5IuF6%%&Dl_0%QFK`KbpdRE!p;$lN* zgiv89M2}~cAJ6V!xGS-G>)_u(h4zl%lYu@sJbz{JKu{&+el7?ODH}Yn0Dww7@ZkSq zsyzFb8DOc*k`~)^0)E0E`he9Y^}bq-0XS6hW76(H^d74SPbYT@tQC~lG}q9k5x{`A z{C9*WAAl!8iB1To(ip7<|@NVQbm1(Kr+%d&@5Y0b?8@ z%WZ*xiMk!a1w~*CoE0|~jwlYL^MMOW!x$7Rd9FDC4T`y-7>se%if0Z${kZ=y6EJMB zsJ~EXWK-5w>JFU@!YS_Krc@M;ymXkmj%~nYxKT_yKZbG#BAT0od#V;fN02B+re#(U zoiAYz0ga8?lB|=0G3LON7DzS&NrNJ;q;3#SO`R)w9F8QOQDW(JT5aTBrB8{2pqzRM zcBYHpz}p+6ia+fxM7+OobF9@3ue;A|=jz&(#GKPDdmsex<+)zH{QN7LInZ}NcOgLb zUWUO=66xJ0-$^KDMH}9*^f_RYC@OJL%#!(RSiE~+!*?VqP;F!BbNrYxg8T0H|8xnO bI=ADOG;A?wB4gRGZcEfi&rJ8Z4u$bwCF8$UA*MpHZEI&Bs+L*YlJWhu3znaN~o-Ii$3FrwNB@hRWa*G3oz?SG{RfY~ zh&De32}R{khCK!R$=QW9PwwcW*jfI~^b$=1djKzPI6hP^({Ur`!i>jiXpHs^+X8Oo zph8hm9&u~BH>oeXx|jpZQ^RBXE)}&@cE!#PCOghY++5nAO_H#&IhVY>KXfH{&-&u) ztqCMa>&rXkvXmhEB-e%eE!@$T4YPB*)VltV9XTlh)ltAQ+hc4ilm?+_+whWJTD70bW zcAgzVI^vc_cQzw(8exX{Nl19u&ARGvdxnP%3f(i?hrUp(Q5=HC$Yjl*;JUTp!r0SB zB2P`in`c+mI`=0MwydC^&A6h^SxUp6(5s<&4x-KAB=&Xw)#Z7n{mz` zS;$3wPFVRCJW~sJuN^}6n*!!$wa!zr&I}I>s-D!kUQiL@DXr%6?BMUKlIbm4F!Ck!F!($m^5 zxVjrVzcZJ2Q>!ST9s&v3)!p8>d;|1Mxty@!hZ*oK_)+`8JEXOBt)&GvsX62rC&Et1UG6In`Qcs z+i23T4mu>${O8F2kaU(JO6YxVcmtS^%?di3@)8c-sWQg$`6ohz*EZpq=P}sLrZfRY zXO*1VXM4s>fD7AR;-fY0#yR(NVcM#HTbx&VNGED) zvk=n2rnIVS#csxyI_C1EKvhFb=#T&8mF4mlvl9Do6?UL(3jOi@v!7Wcpa@JBGDqa( z8Hr9~3HJ5~{G#bGOF>YL#|?uuFnEDnw%L*A*rDpZ3-Gb|6E<0Pg>4+FYTQcT^W_Ml zmF+9V%T#ihY5OX_29hslAq*Aqb}XUQ?iC>BvlP4qIVAepc3mJjSPx#L+H_56P`^w5 zS^*|l7cR9@ZZQV}>2#%~3i`y= zoAhdk^SVYU#G0ZFDJf-v+a^AyT(^37>FKZI+i%+al+o~fYHTcE@_p*;RAG?e@CZ#0 zjXdGs`(oYb{A~21fx$a?%Xe{4lIPssx6ePW#|>UOmfNrPfq21ymb52z{(!7<{^K7P z{cj(tR@XznZzTVIMxc1rVtm&>(e3FzyfxP^MP1$P+#<5UMk3t*K=#djwB_71c^}xZ0y)~gr#uEtr41cuf<`U!(GUhe^?DnFe2*q1K z!Nn4OvDpfIuTpc~t*?4}zRbvp-*yxtTW-{YgQ-=WNLvOL?@1tql#NmZHnt%c!=~U&(nd)2866nx6ZkjwnfvH4*G46&28tPX ziZVMPZpgS`aL6@Os22+Z1p+Nn$R1zmL82m{_wK000TN+!hWzzsHQ`qHwC6sXa#EeE~LU!_e- zrknqRI`@3Cby<9l7FMCxiF+>d=lOXx+j)k=qp7-7;TNar=6~L!^q_HaEz*$@r@RQE z8jK~}k1JtU*QUo{u&njI%3iHQi%JS-oRn!nX#rkR&@{<0s5tqu((ft;`%VJAf=3@3^*NHmP|%u=4+a1ogM!Sg#K_pQ5liTL nd{y(_5XF9Jkc_z@iFw^EzRI9nM#JuEH|f0CNKRj{%Ht@ literal 1604 zcmZuxe>l^59RF@@+1XVRYVv#N$62>bN-VRR3FB&po6$`%`4JJqx}25HFwA+hO^@Wq zMt)SAQ@L=fFi{A{q*Dsfa8f!CH}{?Euj@X~^ZC3#ulMWqetp01_w#(e+#}v@8?+6z z0RY(GewaiB;{>=li1pw}-BkY(43INaHzH8?#ApfxurL=d7XY}Gi(CnY0|0#1o#aAG zIyUp%ImXDS zaM*%#f#Hr@6!^p{S6)s$o>?+3=P=10_R?f}v$;uV>LKHeLJ`+oz|ZGJ6;8U*kE*hM z{Nw0tK7xbVrBq~gX8EtbAW;dY))X~}$@wsua+FS2w-*ZyIH+o=(FUyx=q20k1yB^e zCQ@BWD!@D5472`;Nj|(^8kTzt%4Ve?SQnpcr>Em_c-R@Q#psbFpQd>4{nCX#BQ`4l zF=43UwV##oc+1mou0)3n#OB~}yI^PV%@~;~=)-W62fF%Jm^htz&{{mcV@!$>57sUj ze>5=E7-C?3O*crVoAm}~+y-y79BLVV5{G8A77I6Wrt(CEMS~3uiLGTSd8B`xBEPL_ zoSX<@vuqJ!MqI%8g&BOS$d~-*3oBB5dpSpCdi>lDx9)9J}e*9E*U2K1$R@l zR+I3a zOpQUdsXQutpuRuQfM5~zm{)VZ80E}S9(x65^a<9yD1A0-1i?az`>1igfY45g9Kw~6 zvCsC33iGR>ihBOQ5bhNji&0WMJA5G_BZ}QBVJup(m@TQ8CYExYirn{!2S<(C!3i(vtnY8sBQ)?- z(8aEun<=w%MU{wWWAm;wV$bOxvdrvFv^^Fx{`% z-H_UCS)ktBWx@^WRc|2}8!C7A;eS4IDUGQqw={8?aYi%RU(5+F+8V)RZVgv~II#2T zMG6sRz)|9gpp`RWA#d$wK;8)^3mY?SiG{o_<=5)Y{r$Aqedhxbmd)}3?w$()PI)o5wS?GO* zG`q}GailB0_g3*lls#uE%^mW(kw1{QaZ{>!!ArEjM4(3iKSfeHGlfY59HK)uZ{+ozWIaA6w2nmhkGE)|*noAlpr6KTNZLu%X%#eN()+dY5 zFg)gZ!d9@j2f+g3KP6t=14{YnMC`f}jnoYLt|jgA_tP1kIb0Niu5m#N((>SWcmCX# zg@fUAq#89DyYA@gB?!;Pj)TgGWH7Ysq@Vv(|3A}X)2Y@fkcfsiRZS>05_eZ`QXP@W F`3HG3#Bu-t From 3fb89ded780efdc41ed8a37dc6841b5bac0a8445 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Fri, 29 Jan 2016 01:55:21 +0300 Subject: [PATCH 15/15] Fixed @kekekeks notes. --- src/Perspex.Controls/Shapes/Line.cs | 4 ++-- src/Perspex.Controls/Shapes/Polyline.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Perspex.Controls/Shapes/Line.cs b/src/Perspex.Controls/Shapes/Line.cs index f9a8c9cbc5..0d659b126f 100644 --- a/src/Perspex.Controls/Shapes/Line.cs +++ b/src/Perspex.Controls/Shapes/Line.cs @@ -19,9 +19,9 @@ namespace Perspex.Controls.Shapes private Point _startPoint; private Point _endPoint; - public Line() + static Line() { - StrokeThickness = 1; + StrokeThicknessProperty.OverrideDefaultValue(1); } public Point StartPoint diff --git a/src/Perspex.Controls/Shapes/Polyline.cs b/src/Perspex.Controls/Shapes/Polyline.cs index ba6ce1c174..75b1353f6f 100644 --- a/src/Perspex.Controls/Shapes/Polyline.cs +++ b/src/Perspex.Controls/Shapes/Polyline.cs @@ -12,9 +12,9 @@ namespace Perspex.Controls.Shapes public static readonly PerspexProperty> PointsProperty = PerspexProperty.Register>("Points"); - public Polyline() + static Polyline() { - StrokeThickness = 1; // Default Thickness + StrokeThicknessProperty.OverrideDefaultValue(1); } public IList Points