diff --git a/Cairo/Perspex.Cairo/Media/DrawingContext.cs b/Cairo/Perspex.Cairo/Media/DrawingContext.cs index 22b2f9c453..ece359923d 100644 --- a/Cairo/Perspex.Cairo/Media/DrawingContext.cs +++ b/Cairo/Perspex.Cairo/Media/DrawingContext.cs @@ -13,6 +13,8 @@ namespace Perspex.Cairo.Media using Splat; using Cairo = global::Cairo; using IBitmap = Perspex.Media.Imaging.IBitmap; + using System.Collections.Generic; + /// /// Draws using Direct2D1. @@ -114,7 +116,58 @@ namespace Perspex.Cairo.Media /// The geometry. public void DrawGeometry(Perspex.Media.Brush brush, Perspex.Media.Pen pen, Perspex.Media.Geometry geometry) { - // TODO: Implement + var impl = geometry.PlatformImpl as StreamGeometryImpl; + var clone = new Queue(impl.Operations); + + bool useFill = false; + + this.SetPen(pen); + this.SetBrush(brush); + + using (var pop = this.PushTransform(impl.Transform)) + { + while (clone.Count > 0) + { + + var current = clone.Dequeue(); + + if (current is BeginOp) + { + var bo = current as BeginOp; + this.context.MoveTo(bo.Point.ToCairo()); + + useFill = bo.IsFilled; + + System.Diagnostics.Debug.WriteLine("Start"); + } + else if (current is LineToOp) + { + var lto = current as LineToOp; + this.context.LineTo(lto.Point.ToCairo()); + } + else if (current is EndOp) + { + if (((EndOp)current).IsClosed) + this.context.ClosePath(); + + System.Diagnostics.Debug.WriteLine("End"); + } + else if (current is CurveToOp) + { + var cto = current as CurveToOp; + this.context.CurveTo(cto.Point.ToCairo(), cto.Point2.ToCairo(), cto.Point3.ToCairo()); + } + } + + if (useFill) + { + this.context.FillPreserve(); + } + else + { + this.context.StrokePreserve(); + } + } } /// @@ -139,6 +192,7 @@ namespace Perspex.Cairo.Media { var layout = ((FormattedTextImpl)text.PlatformImpl).Layout; this.SetBrush(foreground); + this.context.MoveTo(origin.X, origin.Y); Pango.CairoHelper.ShowLayout(this.context, layout); } diff --git a/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs b/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs index e49c7ab450..8e629283fa 100644 --- a/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs +++ b/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs @@ -8,37 +8,97 @@ namespace Perspex.Cairo.Media { using Perspex.Media; using Perspex.Platform; + using System.Collections.Generic; + using Cairo = global::Cairo; public class StreamGeometryContextImpl : IStreamGeometryContextImpl { - public StreamGeometryContextImpl() + private StreamGeometryImpl impl; + public StreamGeometryContextImpl(StreamGeometryImpl imp) { - // TODO: Implement + this.impl = imp; + points = new List(); } + private List points; + public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection) { - // TODO: Implement + points.Add(point); } public void BeginFigure(Point startPoint, bool isFilled) { - // TODO: Implement + this.impl.Operations.Enqueue(new BeginOp { Point = startPoint, IsFilled = isFilled }); + points.Add(startPoint); } public void BezierTo(Point point1, Point point2, Point point3) { - // TODO: Implement + this.impl.Operations.Enqueue(new CurveToOp { Point = point1, Point2 = point2, Point3 = point3 }); + points.Add(point1); + points.Add(point2); + points.Add(point3); } public void LineTo(Point point) { - // TODO: Implement + this.impl.Operations.Enqueue(new LineToOp { Point = point }); + points.Add(point); } public void EndFigure(bool isClosed) { - // TODO: Implement + this.impl.Operations.Enqueue(new EndOp { IsClosed = isClosed }); + + double maxX = 0; + double maxY = 0; + + foreach (var p in this.points) + { + maxX = System.Math.Max(p.X, maxX); + maxY = System.Math.Max(p.Y, maxY); + } + + + var context = new Cairo.Context(new Cairo.ImageSurface(Cairo.Format.Argb32, (int)maxX, (int)maxY)); + var clone = new Queue(this.impl.Operations); + + context.LineWidth = 2; + + while (clone.Count > 0) + { + var current = clone.Dequeue(); + + if (current is BeginOp) + { + var bo = current as BeginOp; + context.MoveTo(bo.Point.ToCairo()); + } + else if (current is LineToOp) + { + var lto = current as LineToOp; + context.LineTo(lto.Point.ToCairo()); + } + else if (current is EndOp) + { + if (((EndOp)current).IsClosed) + context.ClosePath(); + } + else if (current is CurveToOp) + { + var cto = current as CurveToOp; + context.CurveTo(cto.Point.ToCairo(), cto.Point2.ToCairo(), cto.Point3.ToCairo()); + } + + context.StrokePreserve(); + context.FillPreserve(); + } + + var test = context.StrokeExtents(); + this.impl.Bounds = new Rect(test.X, test.Y, test.Width, test.Height); + + context.Dispose(); } public void Dispose() diff --git a/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs b/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs index 70150a17d9..cf423dbc17 100644 --- a/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs +++ b/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs @@ -9,43 +9,99 @@ namespace Perspex.Cairo.Media using System; using Perspex.Media; using Perspex.Platform; + using Cairo = global::Cairo; using Splat; + using System.Collections.Generic; + + public enum CairoGeometryType + { + Begin, + ArcTo, + LineTo, + End + } + + public class BeginOp : GeometryOp + { + public Point Point { get; set; } + public bool IsFilled { get; set; } + } + + public class EndOp : GeometryOp + { + public bool IsClosed { get; set; } + } + + public class LineToOp : GeometryOp + { + public Point Point { get; set; } + } + + public class CurveToOp : GeometryOp + { + public Point Point { get; set; } + public Point Point2 { get; set; } + public Point Point3 { get; set; } + } + + public abstract class GeometryOp + { + } public class StreamGeometryImpl : IStreamGeometryImpl { public StreamGeometryImpl() { - // TODO: Implement + this.Operations = new Queue(); + } + + public StreamGeometryImpl(Queue ops) + { + this.Operations = ops; + } + + public Queue Operations + { + get; + private set; } public Rect Bounds { - get { return new Rect(); } + get; + set; } // TODO: Implement + private Matrix transform = Matrix.Identity; public Matrix Transform { - get { return Matrix.Identity; } - set { } + get { return this.transform; } + set + { + if (value != this.Transform) + { + if (!value.IsIdentity) + { + this.transform = value; + } + } + } } public IStreamGeometryImpl Clone() { - // TODO: Implement - return new StreamGeometryImpl(); + return new StreamGeometryImpl(this.Operations); } public Rect GetRenderBounds(double strokeThickness) { - // TODO: Implement - return new Rect(); + return this.Bounds; } public IStreamGeometryContextImpl Open() { - // TODO: Implement - return new StreamGeometryContextImpl(); + return new StreamGeometryContextImpl(this); } } }