Browse Source

Merge pull request #2339 from AvaloniaUI/fixes/2335-drawing-crashes

Fix crashes related to null geometries.
pull/2341/head
Steven Kirk 8 years ago
committed by GitHub
parent
commit
587270f1d5
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 23
      src/Avalonia.Controls/Shapes/Shape.cs
  2. 2
      src/Avalonia.Visuals/Media/DrawingContext.cs
  3. 7
      src/Avalonia.Visuals/Media/GeometryDrawing.cs
  4. 11
      src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs
  5. 16
      tests/Avalonia.Controls.UnitTests/Shapes/PathTests.cs
  6. 13
      tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs

23
src/Avalonia.Controls/Shapes/Shape.cs

@ -195,7 +195,7 @@ namespace Avalonia.Controls.Shapes
if (deferCalculateTransform)
{
_calculateTransformOnArrange = true;
return DefiningGeometry.Bounds.Size;
return DefiningGeometry?.Bounds.Size ?? Size.Empty;
}
else
{
@ -217,17 +217,22 @@ namespace Avalonia.Controls.Shapes
private Size CalculateShapeSizeAndSetTransform(Size availableSize)
{
// This should probably use GetRenderBounds(strokeThickness) but then the calculations
// will multiply the stroke thickness as well, which isn't correct.
var (size, transform) = CalculateSizeAndTransform(availableSize, DefiningGeometry.Bounds, Stretch);
if (_transform != transform)
if (DefiningGeometry != null)
{
_transform = transform;
_renderedGeometry = null;
// This should probably use GetRenderBounds(strokeThickness) but then the calculations
// will multiply the stroke thickness as well, which isn't correct.
var (size, transform) = CalculateSizeAndTransform(availableSize, DefiningGeometry.Bounds, Stretch);
if (_transform != transform)
{
_transform = transform;
_renderedGeometry = null;
}
return size;
}
return size;
return Size.Empty;
}
internal static (Size, Matrix) CalculateSizeAndTransform(Size availableSize, Rect shapeBounds, Stretch Stretch)

2
src/Avalonia.Visuals/Media/DrawingContext.cs

@ -109,6 +109,8 @@ namespace Avalonia.Media
/// <param name="geometry">The geometry.</param>
public void DrawGeometry(IBrush brush, Pen pen, Geometry geometry)
{
Contract.Requires<ArgumentNullException>(geometry != null);
if (brush != null || PenIsVisible(pen))
{
PlatformImpl.DrawGeometry(brush, pen, geometry.PlatformImpl);

7
src/Avalonia.Visuals/Media/GeometryDrawing.cs

@ -31,7 +31,10 @@
public override void Draw(DrawingContext context)
{
context.DrawGeometry(Brush, Pen, Geometry);
if (Geometry != null)
{
context.DrawGeometry(Brush, Pen, Geometry);
}
}
public override Rect GetBounds()
@ -41,4 +44,4 @@
return Geometry?.GetRenderBounds(pen) ?? new Rect();
}
}
}
}

11
src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs

@ -89,9 +89,14 @@ namespace Avalonia.Rendering.SceneGraph
/// <inheritdoc/>
public override bool HitTest(Point p)
{
p *= Transform.Invert();
return (Brush != null && Geometry.FillContains(p)) ||
(Pen != null && Geometry.StrokeContains(Pen, p));
if (Transform.HasInverse)
{
p *= Transform.Invert();
return (Brush != null && Geometry.FillContains(p)) ||
(Pen != null && Geometry.StrokeContains(Pen, p));
}
return false;
}
}
}

16
tests/Avalonia.Controls.UnitTests/Shapes/PathTests.cs

@ -0,0 +1,16 @@
using Avalonia.Controls.Shapes;
using Xunit;
namespace Avalonia.Controls.UnitTests.Shapes
{
public class PathTests
{
[Fact]
public void Path_With_Null_Data_Does_Not_Throw_On_Measure()
{
var target = new Path();
target.Measure(Size.Infinity);
}
}
}

13
tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs

@ -61,6 +61,19 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
Assert.Equal(1, bitmap.RefCount);
}
[Fact]
public void HitTest_On_Geometry_Node_With_Zero_Transform_Does_Not_Throw()
{
var geometry = Mock.Of<IGeometryImpl>();
var geometryNode = new GeometryNode(
new Matrix(),
Brushes.Black,
null,
geometry);
geometryNode.HitTest(new Point());
}
private class TestDrawOperation : DrawOperation
{
public TestDrawOperation(Rect bounds, Matrix transform, Pen pen)

Loading…
Cancel
Save