diff --git a/Perspex.Controls/Shapes/Shape.cs b/Perspex.Controls/Shapes/Shape.cs index 271e575682..7a03cafcba 100644 --- a/Perspex.Controls/Shapes/Shape.cs +++ b/Perspex.Controls/Shapes/Shape.cs @@ -26,6 +26,8 @@ namespace Perspex.Controls.Shapes private Matrix transform = Matrix.Identity; + private Geometry renderedGeometry; + public abstract Geometry DefiningGeometry { get; @@ -41,15 +43,17 @@ namespace Perspex.Controls.Shapes { get { - var result = this.DefiningGeometry; - - if (result != null) + if (this.renderedGeometry == null) { - result = result.Clone(); - result.Transform = new MatrixTransform(this.transform); + if (this.DefiningGeometry != null) + { + this.renderedGeometry = this.DefiningGeometry.Clone(); + this.renderedGeometry.Transform = new MatrixTransform(this.transform); + } + } - return result; + return this.renderedGeometry; } } @@ -83,7 +87,9 @@ namespace Perspex.Controls.Shapes protected override Size MeasureOverride(Size availableSize) { - Rect shapeBounds = this.DefiningGeometry.GetRenderBounds(this.StrokeThickness); + // This should probably use GetRenderBounds(strokeThickness) but then the calculations + // will multiply the stroke thickness as well, which isn't correct. + Rect shapeBounds = this.DefiningGeometry.Bounds; Size shapeSize = new Size(shapeBounds.Right, shapeBounds.Bottom); Matrix translate = Matrix.Identity; double width = this.Width; @@ -111,12 +117,12 @@ namespace Perspex.Controls.Shapes if (shapeBounds.Width > 0) { - sx = desiredX / shapeBounds.Width; + sx = desiredX / shapeSize.Width; } if (shapeBounds.Height > 0) { - sy = desiredY / shapeBounds.Height; + sy = desiredY / shapeSize.Height; } if (double.IsInfinity(availableSize.Width)) @@ -154,11 +160,15 @@ namespace Perspex.Controls.Shapes break; } - this.transform = translate * Matrix.Scaling(sx, sy); + var t = translate * Matrix.Scaling(sx, sy); + + if (this.transform != t) + { + this.transform = t; + this.renderedGeometry = null; + } - double finalX = (width > 0) ? width : shapeSize.Width * sx; - double finalY = (height > 0) ? height : shapeSize.Width * sy; - return new Size(finalX, finalY); + return new Size(shapeSize.Width * sx, shapeSize.Height * sy); } } } diff --git a/TestFiles/Direct2D1/Shapes/Path/Path_100px_Triangle_Centered.expected.png b/TestFiles/Direct2D1/Shapes/Path/Path_100px_Triangle_Centered.expected.png index 6db62e30c3..dab965f988 100644 Binary files a/TestFiles/Direct2D1/Shapes/Path/Path_100px_Triangle_Centered.expected.png and b/TestFiles/Direct2D1/Shapes/Path/Path_100px_Triangle_Centered.expected.png differ diff --git a/TestFiles/Direct2D1/Shapes/Path/Path_Expander_With_Border.expected.png b/TestFiles/Direct2D1/Shapes/Path/Path_Expander_With_Border.expected.png new file mode 100644 index 0000000000..9c72e69ea9 Binary files /dev/null and b/TestFiles/Direct2D1/Shapes/Path/Path_Expander_With_Border.expected.png differ diff --git a/Windows/Perspex.Direct2D1.RenderTests/Shapes/PathTests.cs b/Windows/Perspex.Direct2D1.RenderTests/Shapes/PathTests.cs index 0b1b69694e..f72b71195f 100644 --- a/Windows/Perspex.Direct2D1.RenderTests/Shapes/PathTests.cs +++ b/Windows/Perspex.Direct2D1.RenderTests/Shapes/PathTests.cs @@ -65,5 +65,33 @@ namespace Perspex.Direct2D1.RenderTests.Shapes this.RenderToFile(target); this.CompareImages(); } + + [TestMethod] + public void Path_Expander_With_Border() + { + Decorator target = new Decorator + { + Width = 200, + Height = 200, + Content = new Border + { + BorderBrush = Brushes.Red, + BorderThickness = 1, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Content = new Path + { + Fill = Brushes.Black, + Stroke = Brushes.Black, + StrokeThickness = 1, + Stretch = Stretch.Uniform, + Data = StreamGeometry.Parse("M 0 2 L 4 6 L 0 10 Z"), + } + } + }; + + this.RenderToFile(target); + this.CompareImages(); + } } } diff --git a/Windows/Perspex.Direct2D1/Media/GeometryImpl.cs b/Windows/Perspex.Direct2D1/Media/GeometryImpl.cs index 510b618533..4fd2584e67 100644 --- a/Windows/Perspex.Direct2D1/Media/GeometryImpl.cs +++ b/Windows/Perspex.Direct2D1/Media/GeometryImpl.cs @@ -60,6 +60,16 @@ namespace Perspex.Direct2D1.Media } } - public abstract Rect GetRenderBounds(double strokeThickness); + public Rect GetRenderBounds(double strokeThickness) + { + if (this.transformed != null) + { + return this.transformed.GetWidenedBounds((float)strokeThickness).ToPerspex(); + } + else + { + return this.DefiningGeometry.GetWidenedBounds((float)strokeThickness).ToPerspex(); + } + } } } diff --git a/Windows/Perspex.Direct2D1/Media/StreamGeometryImpl.cs b/Windows/Perspex.Direct2D1/Media/StreamGeometryImpl.cs index 41f0a91a68..2567f937c7 100644 --- a/Windows/Perspex.Direct2D1/Media/StreamGeometryImpl.cs +++ b/Windows/Perspex.Direct2D1/Media/StreamGeometryImpl.cs @@ -44,11 +44,6 @@ namespace Perspex.Direct2D1.Media return new StreamGeometryImpl(result); } - public override Rect GetRenderBounds(double strokeThickness) - { - return this.path.GetWidenedBounds((float)strokeThickness).ToPerspex(); - } - public IStreamGeometryContextImpl Open() { return new StreamGeometryContextImpl(this.path.Open());