From 415c9c6e180befa1a347f87847dd76690ce3747f Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sun, 24 Jan 2016 16:10:06 +0300 Subject: [PATCH] Implemented StreamGeometryContext.SetFillRule --- src/Gtk/Perspex.Cairo/Media/DrawingContext.cs | 4 ++++ .../Perspex.Cairo/Media/StreamGeometryContextImpl.cs | 12 ++++++++++-- src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs | 4 +++- src/Perspex.SceneGraph/Media/FillRule.cs | 8 ++++++++ .../Media/StreamGeometryContext.cs | 10 ++++++++++ src/Perspex.SceneGraph/Perspex.SceneGraph.csproj | 1 + .../Platform/IStreamGeometryContextImpl.cs | 2 ++ src/Skia/Perspex.Skia/DrawingContextImpl.cs | 2 +- src/Skia/Perspex.Skia/MethodTable.cs | 2 +- src/Skia/Perspex.Skia/StreamGeometryImpl.cs | 7 +++++++ src/Skia/native.url | 2 +- .../Media/StreamGeometryContextImpl.cs | 7 +++++++ 12 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 src/Perspex.SceneGraph/Media/FillRule.cs diff --git a/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs b/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs index a1fee1a2e3..afb024b4cb 100644 --- a/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs +++ b/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs @@ -148,6 +148,10 @@ namespace Perspex.Cairo.Media _context.AppendPath(impl.Path); using (var b = SetBrush(brush, geometry.Bounds.Size)) { + _context.FillRule = impl.FillRule == FillRule.EvenOdd + ? Cairo.FillRule.EvenOdd + : Cairo.FillRule.Winding; + if (pen != null) _context.FillPreserve(); else diff --git a/src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs b/src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs index 2c5cce2653..f4cf9294dc 100644 --- a/src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs +++ b/src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs @@ -13,11 +13,13 @@ namespace Perspex.Cairo.Media public class StreamGeometryContextImpl : IStreamGeometryContextImpl { + private readonly StreamGeometryImpl _target; private Point _currentPoint; - public StreamGeometryContextImpl(Cairo.Path path = null) + public StreamGeometryContextImpl(StreamGeometryImpl target, Cairo.Path path) { + _target = target; - _surf = new Cairo.ImageSurface (Cairo.Format.Argb32, 0, 0); + _surf = new Cairo.ImageSurface (Cairo.Format.Argb32, 0, 0); _context = new Cairo.Context (_surf); this.Path = path; @@ -86,6 +88,12 @@ namespace Perspex.Cairo.Media } } + public void SetFillRule(FillRule fillRule) + { + _target.FillRule = fillRule; + } + + public void Dispose() { _context.Dispose (); diff --git a/src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs b/src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs index a408cba039..2dd844c687 100644 --- a/src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs +++ b/src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs @@ -14,7 +14,7 @@ namespace Perspex.Cairo.Media { public StreamGeometryImpl() { - _impl = new StreamGeometryContextImpl(null); + _impl = new StreamGeometryContextImpl(this, null); } public StreamGeometryImpl(StreamGeometryContextImpl impl) @@ -50,6 +50,8 @@ namespace Perspex.Cairo.Media } } + public FillRule FillRule { get; set; } + public IStreamGeometryImpl Clone() { return new StreamGeometryImpl(_impl); diff --git a/src/Perspex.SceneGraph/Media/FillRule.cs b/src/Perspex.SceneGraph/Media/FillRule.cs new file mode 100644 index 0000000000..5e2eb078c9 --- /dev/null +++ b/src/Perspex.SceneGraph/Media/FillRule.cs @@ -0,0 +1,8 @@ +namespace Perspex.Media +{ + public enum FillRule + { + EvenOdd, + NonZero + } +} \ No newline at end of file diff --git a/src/Perspex.SceneGraph/Media/StreamGeometryContext.cs b/src/Perspex.SceneGraph/Media/StreamGeometryContext.cs index dcb000544f..8e32debb21 100644 --- a/src/Perspex.SceneGraph/Media/StreamGeometryContext.cs +++ b/src/Perspex.SceneGraph/Media/StreamGeometryContext.cs @@ -28,6 +28,16 @@ namespace Perspex.Media _impl = impl; } + /// + /// Sets path's winding rule (default is EvenOdd). You should call this method before any calls to BeginFigure. If you wonder why, ask Direct2D guys about their design decisions. + /// + /// + + public void SetFillRule(FillRule fillRule) + { + _impl.SetFillRule(fillRule); + } + /// /// Draws an arc to the specified point. /// diff --git a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj index f3079729e3..05f22c4ccf 100644 --- a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj +++ b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj @@ -67,6 +67,7 @@ + diff --git a/src/Perspex.SceneGraph/Platform/IStreamGeometryContextImpl.cs b/src/Perspex.SceneGraph/Platform/IStreamGeometryContextImpl.cs index 182a3ec174..33c2285730 100644 --- a/src/Perspex.SceneGraph/Platform/IStreamGeometryContextImpl.cs +++ b/src/Perspex.SceneGraph/Platform/IStreamGeometryContextImpl.cs @@ -56,5 +56,7 @@ namespace Perspex.Platform /// /// Whether the figure is closed. void EndFigure(bool isClosed); + + void SetFillRule(FillRule fillRule); } } diff --git a/src/Skia/Perspex.Skia/DrawingContextImpl.cs b/src/Skia/Perspex.Skia/DrawingContextImpl.cs index fee6499f01..405f021515 100644 --- a/src/Skia/Perspex.Skia/DrawingContextImpl.cs +++ b/src/Skia/Perspex.Skia/DrawingContextImpl.cs @@ -46,7 +46,7 @@ namespace Perspex.Skia using (var stroke = pen?.Brush != null ? CreateBrush(pen, size) : null) { MethodTable.Instance.DrawGeometry(Handle, impl.Path.Handle, fill != null ? fill.Brush : null, - stroke != null ? stroke.Brush : null); + stroke != null ? stroke.Brush : null, impl.FillRule == FillRule.EvenOdd); } Transform = oldTransform; } diff --git a/src/Skia/Perspex.Skia/MethodTable.cs b/src/Skia/Perspex.Skia/MethodTable.cs index cee36bbded..ba21588333 100644 --- a/src/Skia/Perspex.Skia/MethodTable.cs +++ b/src/Skia/Perspex.Skia/MethodTable.cs @@ -67,7 +67,7 @@ namespace Perspex.Skia public _DisposePath DisposePath; [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void _DrawGeometry(IntPtr ctx, IntPtr path, void* fill, void* stroke); + public delegate void _DrawGeometry(IntPtr ctx, IntPtr path, void* fill, void* stroke, bool useEvenOdd); public _DrawGeometry DrawGeometry; diff --git a/src/Skia/Perspex.Skia/StreamGeometryImpl.cs b/src/Skia/Perspex.Skia/StreamGeometryImpl.cs index d18a3c55c5..3c62e65e7d 100644 --- a/src/Skia/Perspex.Skia/StreamGeometryImpl.cs +++ b/src/Skia/Perspex.Skia/StreamGeometryImpl.cs @@ -140,6 +140,13 @@ namespace Perspex.Skia Flag = isClosed }); } + + public void SetFillRule(FillRule fillRule) + { + _geometryImpl.FillRule = fillRule; + } } + + public FillRule FillRule { get; set; } } } diff --git a/src/Skia/native.url b/src/Skia/native.url index 697513ae7a..737e1d3d06 100644 --- a/src/Skia/native.url +++ b/src/Skia/native.url @@ -1 +1 @@ -https://dl.dropboxusercontent.com/u/18301199/Perspex.Skia/abi-0002.zip +https://dl.dropboxusercontent.com/u/18301199/Perspex.Skia/abi-0003.zip diff --git a/src/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs b/src/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs index e18e61f94a..8dc3c6231d 100644 --- a/src/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs +++ b/src/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs @@ -1,8 +1,10 @@ // 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.Media; using Perspex.Platform; using SharpDX.Direct2D1; +using SweepDirection = SharpDX.Direct2D1.SweepDirection; namespace Perspex.Direct2D1.Media { @@ -66,6 +68,11 @@ namespace Perspex.Direct2D1.Media _sink.EndFigure(isClosed ? FigureEnd.Closed : FigureEnd.Open); } + public void SetFillRule(FillRule fillRule) + { + _sink.SetFillMode(fillRule == FillRule.EvenOdd ? FillMode.Alternate : FillMode.Winding); + } + public void Dispose() { _sink.Close();