Browse Source

Merge pull request #2375 from MarchingCube/fixes/geometry-impls

Platform geometry implementations for D2D and Skia.
pull/2449/head
Nikita Tsukanov 7 years ago
committed by GitHub
parent
commit
433eb7e5ac
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 31
      src/Avalonia.Visuals/Media/EllipseGeometry.cs
  2. 10
      src/Avalonia.Visuals/Media/LineGeometry.cs
  3. 28
      src/Avalonia.Visuals/Media/RectangleGeometry.cs
  4. 22
      src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs
  5. 25
      src/Skia/Avalonia.Skia/EllipseGeometryImpl.cs
  6. 29
      src/Skia/Avalonia.Skia/LineGeometryImpl.cs
  7. 6
      src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
  8. 25
      src/Skia/Avalonia.Skia/RectangleGeometryImpl.cs
  9. 8
      src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
  10. 27
      src/Windows/Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs
  11. 27
      src/Windows/Avalonia.Direct2D1/Media/LineGeometryImpl.cs
  12. 26
      src/Windows/Avalonia.Direct2D1/Media/RectangleGeometryImpl.cs
  13. 2
      src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs
  14. 15
      tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs
  15. 15
      tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs

31
src/Avalonia.Visuals/Media/EllipseGeometry.cs

@ -1,7 +1,6 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Avalonia.Platform;
namespace Avalonia.Media
@ -57,36 +56,8 @@ namespace Avalonia.Media
protected override IGeometryImpl CreateDefiningGeometry()
{
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var geometry = factory.CreateStreamGeometry();
using (var ctx = geometry.Open())
{
var rect = Rect;
double controlPointRatio = (Math.Sqrt(2) - 1) * 4 / 3;
var center = rect.Center;
var radius = new Vector(rect.Width / 2, rect.Height / 2);
var x0 = center.X - radius.X;
var x1 = center.X - (radius.X * controlPointRatio);
var x2 = center.X;
var x3 = center.X + (radius.X * controlPointRatio);
var x4 = center.X + radius.X;
var y0 = center.Y - radius.Y;
var y1 = center.Y - (radius.Y * controlPointRatio);
var y2 = center.Y;
var y3 = center.Y + (radius.Y * controlPointRatio);
var y4 = center.Y + radius.Y;
ctx.BeginFigure(new Point(x2, y0), true);
ctx.CubicBezierTo(new Point(x3, y0), new Point(x4, y1), new Point(x4, y2));
ctx.CubicBezierTo(new Point(x4, y3), new Point(x3, y4), new Point(x2, y4));
ctx.CubicBezierTo(new Point(x1, y4), new Point(x0, y3), new Point(x0, y2));
ctx.CubicBezierTo(new Point(x0, y1), new Point(x1, y0), new Point(x2, y0));
ctx.EndFigure(true);
}
return geometry;
return factory.CreateEllipseGeometry(Rect);
}
}
}

10
src/Avalonia.Visuals/Media/LineGeometry.cs

@ -73,16 +73,8 @@ namespace Avalonia.Media
protected override IGeometryImpl CreateDefiningGeometry()
{
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var geometry = factory.CreateStreamGeometry();
using (var context = geometry.Open())
{
context.BeginFigure(StartPoint, false);
context.LineTo(EndPoint);
context.EndFigure(false);
}
return geometry;
return factory.CreateLineGeometry(StartPoint, EndPoint);
}
}
}

28
src/Avalonia.Visuals/Media/RectangleGeometry.cs

@ -16,12 +16,6 @@ namespace Avalonia.Media
public static readonly StyledProperty<Rect> RectProperty =
AvaloniaProperty.Register<RectangleGeometry, Rect>(nameof(Rect));
public Rect Rect
{
get => GetValue(RectProperty);
set => SetValue(RectProperty, value);
}
static RectangleGeometry()
{
AffectsGeometry(RectProperty);
@ -43,25 +37,23 @@ namespace Avalonia.Media
Rect = rect;
}
/// <summary>
/// Gets or sets the bounds of the rectangle.
/// </summary>
public Rect Rect
{
get => GetValue(RectProperty);
set => SetValue(RectProperty, value);
}
/// <inheritdoc/>
public override Geometry Clone() => new RectangleGeometry(Rect);
protected override IGeometryImpl CreateDefiningGeometry()
{
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var geometry = factory.CreateStreamGeometry();
using (var context = geometry.Open())
{
var rect = Rect;
context.BeginFigure(rect.TopLeft, true);
context.LineTo(rect.TopRight);
context.LineTo(rect.BottomRight);
context.LineTo(rect.BottomLeft);
context.EndFigure(true);
}
return geometry;
return factory.CreateRectangleGeometry(Rect);
}
}
}

22
src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs

@ -36,6 +36,28 @@ namespace Avalonia.Platform
Size constraint,
IReadOnlyList<FormattedTextStyleSpan> spans);
/// <summary>
/// Creates an ellipse geometry implementation.
/// </summary>
/// <param name="rect">The bounds of the ellipse.</param>
/// <returns>An ellipse geometry..</returns>
IGeometryImpl CreateEllipseGeometry(Rect rect);
/// <summary>
/// Creates a line geometry implementation.
/// </summary>
/// <param name="p1">The start of the line.</param>
/// <param name="p2">The end of the line.</param>
/// <returns>A line geometry.</returns>
IGeometryImpl CreateLineGeometry(Point p1, Point p2);
/// <summary>
/// Creates a rectangle geometry implementation.
/// </summary>
/// <param name="rect">The bounds of the rectangle.</param>
/// <returns>A rectangle.</returns>
IGeometryImpl CreateRectangleGeometry(Rect rect);
/// <summary>
/// Creates a stream geometry implementation.
/// </summary>

25
src/Skia/Avalonia.Skia/EllipseGeometryImpl.cs

@ -0,0 +1,25 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using SkiaSharp;
namespace Avalonia.Skia
{
/// <summary>
/// A Skia implementation of a <see cref="Avalonia.Media.EllipseGeometry"/>.
/// </summary>
internal class EllipseGeometryImpl : GeometryImpl
{
public override Rect Bounds { get; }
public override SKPath EffectivePath { get; }
public EllipseGeometryImpl(Rect rect)
{
var path = new SKPath();
path.AddOval(rect.ToSKRect());
EffectivePath = path;
Bounds = rect;
}
}
}

29
src/Skia/Avalonia.Skia/LineGeometryImpl.cs

@ -0,0 +1,29 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using SkiaSharp;
namespace Avalonia.Skia
{
/// <summary>
/// A Skia implementation of a <see cref="Avalonia.Media.LineGeometry"/>.
/// </summary>
internal class LineGeometryImpl : GeometryImpl
{
public override Rect Bounds { get; }
public override SKPath EffectivePath { get; }
public LineGeometryImpl(Point p1, Point p2)
{
var path = new SKPath();
path.MoveTo(p1.ToSKPoint());
path.LineTo(p2.ToSKPoint());
EffectivePath = path;
Bounds = new Rect(
new Point(Math.Min(p1.X, p2.X), Math.Min(p1.Y, p2.Y)),
new Point(Math.Max(p1.X, p2.X), Math.Max(p1.Y, p2.Y)));
}
}
}

6
src/Skia/Avalonia.Skia/PlatformRenderInterface.cs

@ -60,6 +60,12 @@ namespace Avalonia.Skia
return new FormattedTextImpl(text, typeface, textAlignment, wrapping, constraint, spans);
}
public IGeometryImpl CreateEllipseGeometry(Rect rect) => new EllipseGeometryImpl(rect);
public IGeometryImpl CreateLineGeometry(Point p1, Point p2) => new LineGeometryImpl(p1, p2);
public IGeometryImpl CreateRectangleGeometry(Rect rect) => new RectangleGeometryImpl(rect);
/// <inheritdoc />
public IStreamGeometryImpl CreateStreamGeometry()
{

25
src/Skia/Avalonia.Skia/RectangleGeometryImpl.cs

@ -0,0 +1,25 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using SkiaSharp;
namespace Avalonia.Skia
{
/// <summary>
/// A Skia implementation of a <see cref="Avalonia.Media.RectangleGeometry"/>.
/// </summary>
internal class RectangleGeometryImpl : GeometryImpl
{
public override Rect Bounds { get; }
public override SKPath EffectivePath { get; }
public RectangleGeometryImpl(Rect rect)
{
var path = new SKPath();
path.AddRect(rect.ToSKRect());
EffectivePath = path;
Bounds = rect;
}
}
}

8
src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs

@ -182,10 +182,10 @@ namespace Avalonia.Direct2D1
return new WriteableWicBitmapImpl(size, dpi, format);
}
public IStreamGeometryImpl CreateStreamGeometry()
{
return new StreamGeometryImpl();
}
public IGeometryImpl CreateEllipseGeometry(Rect rect) => new EllipseGeometryImpl(rect);
public IGeometryImpl CreateLineGeometry(Point p1, Point p2) => new LineGeometryImpl(p1, p2);
public IGeometryImpl CreateRectangleGeometry(Rect rect) => new RectangleGeometryImpl(rect);
public IStreamGeometryImpl CreateStreamGeometry() => new StreamGeometryImpl();
public IBitmapImpl LoadBitmap(string fileName)
{

27
src/Windows/Avalonia.Direct2D1/Media/EllipseGeometryImpl.cs

@ -0,0 +1,27 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using SharpDX.Direct2D1;
namespace Avalonia.Direct2D1.Media
{
/// <summary>
/// A Direct2D implementation of a <see cref="Avalonia.Media.EllipseGeometry"/>.
/// </summary>
internal class EllipseGeometryImpl : GeometryImpl
{
/// <summary>
/// Initializes a new instance of the <see cref="StreamGeometryImpl"/> class.
/// </summary>
public EllipseGeometryImpl(Rect rect)
: base(CreateGeometry(rect))
{
}
private static Geometry CreateGeometry(Rect rect)
{
var ellipse = new Ellipse(rect.Center.ToSharpDX(), (float)rect.Width / 2, (float)rect.Height / 2);
return new EllipseGeometry(Direct2D1Platform.Direct2D1Factory, ellipse);
}
}
}

27
src/Windows/Avalonia.Direct2D1/Media/LineGeometryImpl.cs

@ -0,0 +1,27 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using SharpDX.Direct2D1;
namespace Avalonia.Direct2D1.Media
{
/// <summary>
/// A Direct2D implementation of a <see cref="Avalonia.Media.LineGeometry"/>.
/// </summary>
internal class LineGeometryImpl : StreamGeometryImpl
{
/// <summary>
/// Initializes a new instance of the <see cref="StreamGeometryImpl"/> class.
/// </summary>
public LineGeometryImpl(Point p1, Point p2)
{
using (var sink = ((PathGeometry)Geometry).Open())
{
sink.BeginFigure(p1.ToSharpDX(), FigureBegin.Hollow);
sink.AddLine(p2.ToSharpDX());
sink.EndFigure(FigureEnd.Open);
sink.Close();
}
}
}
}

26
src/Windows/Avalonia.Direct2D1/Media/RectangleGeometryImpl.cs

@ -0,0 +1,26 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using SharpDX.Direct2D1;
namespace Avalonia.Direct2D1.Media
{
/// <summary>
/// A Direct2D implementation of a <see cref="Avalonia.Media.RectangleGeometry"/>.
/// </summary>
internal class RectangleGeometryImpl : GeometryImpl
{
/// <summary>
/// Initializes a new instance of the <see cref="StreamGeometryImpl"/> class.
/// </summary>
public RectangleGeometryImpl(Rect rect)
: base(CreateGeometry(rect))
{
}
private static Geometry CreateGeometry(Rect rect)
{
return new RectangleGeometry(Direct2D1Platform.Direct2D1Factory, rect.ToDirect2D());
}
}
}

2
src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs

@ -50,7 +50,7 @@ namespace Avalonia.Win32.Interop.Wpf
{
_resource = texture.QueryInterface<SharpDX.Direct3D11.Resource>();
Target = new RenderTarget(AvaloniaLocator.Current.GetService<SharpDX.Direct2D1.Factory>(), surface,
Target = new RenderTarget(Direct2D1Platform.Direct2D1Factory, surface,
new RenderTargetProperties
{
DpiX = (float) dpi.X,

15
tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs

@ -22,6 +22,21 @@ namespace Avalonia.UnitTests
return Mock.Of<IFormattedTextImpl>();
}
public IGeometryImpl CreateEllipseGeometry(Rect rect)
{
return Mock.Of<IGeometryImpl>();
}
public IGeometryImpl CreateLineGeometry(Point p1, Point p2)
{
return Mock.Of<IGeometryImpl>();
}
public IGeometryImpl CreateRectangleGeometry(Rect rect)
{
return Mock.Of<IGeometryImpl>();
}
public IRenderTarget CreateRenderTarget(IEnumerable<object> surfaces)
{
return Mock.Of<IRenderTarget>();

15
tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs

@ -56,6 +56,21 @@ namespace Avalonia.Visuals.UnitTests.VisualTree
throw new NotImplementedException();
}
public IGeometryImpl CreateEllipseGeometry(Rect rect)
{
throw new NotImplementedException();
}
public IGeometryImpl CreateLineGeometry(Point p1, Point p2)
{
throw new NotImplementedException();
}
public IGeometryImpl CreateRectangleGeometry(Rect rect)
{
throw new NotImplementedException();
}
class MockStreamGeometry : IStreamGeometryImpl
{
private MockStreamGeometryContext _impl = new MockStreamGeometryContext();

Loading…
Cancel
Save