From ff8a1794416745954cde013f34b619e7f8c72bec Mon Sep 17 00:00:00 2001 From: ncarrillo Date: Tue, 21 Apr 2015 18:12:44 -0400 Subject: [PATCH] Initial geometry testing --- Cairo/Perspex.Cairo/Media/DrawingContext.cs | 53 ++++++++++++++ .../Media/StreamGeometryContextImpl.cs | 73 +++++++++++++++++-- .../Perspex.Cairo/Media/StreamGeometryImpl.cs | 73 +++++++++++++++++-- Perspex.Controls/Shapes/Shape.cs | 2 + .../Media/StreamGeometryContextImpl.cs | 1 + 5 files changed, 190 insertions(+), 12 deletions(-) diff --git a/Cairo/Perspex.Cairo/Media/DrawingContext.cs b/Cairo/Perspex.Cairo/Media/DrawingContext.cs index 1d6d2a146a..8349da6bde 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. @@ -115,6 +117,57 @@ namespace Perspex.Cairo.Media public void DrawGeometry(Perspex.Media.Brush brush, Perspex.Media.Pen pen, Perspex.Media.Geometry geometry) { // TODO: Implement + System.Diagnostics.Debug.WriteLine("Geometry {0}", geometry.GetType()); + var impl = geometry.PlatformImpl as StreamGeometryImpl; + var clone = new Queue(impl.Operations); + bool useFill = false; + + //this.context.Save(); + var pop = this.PushTransform(impl.Transform); + + while (clone.Count > 0) + { + // this.SetBrush(brush); + this.SetPen(new Pen(brush, 0.5)); + + var current = clone.Dequeue(); + + if (current is BeginOp) + { + var bo = current as BeginOp; + this.context.MoveTo(bo.Point.ToCairo()); + + useFill = bo.IsFilled; + } + 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(); + } + 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.StrokePreserve(); + this.context.Fill(); + } + else + { + this.context.Stroke(); + } + + pop.Dispose(); } /// diff --git a/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs b/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs index e49c7ab450..3b04123481 100644 --- a/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs +++ b/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs @@ -8,37 +8,100 @@ 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 Queue ops; + private StreamGeometryImpl impl; + public StreamGeometryContextImpl(Queue ops, StreamGeometryImpl imp) { - // TODO: Implement + this.ops = ops; + this.impl = imp; + points = new List(); } + private List points; + public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection) { // TODO: Implement + int i = 10; + points.Add(point); } public void BeginFigure(Point startPoint, bool isFilled) { - // TODO: Implement + System.Diagnostics.Debug.WriteLine("IS filled {0}", isFilled); + ops.Enqueue(new BeginOp { Point = startPoint, IsFilled = isFilled }); + points.Add(startPoint); } public void BezierTo(Point point1, Point point2, Point point3) { // TODO: Implement + ops.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 + ops.Enqueue(new LineToOp { Point = point }); + points.Add(point); } public void EndFigure(bool isClosed) { - // TODO: Implement + this.ops.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.ops); + bool useFill = false; + + 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(); + } + + 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..f949d7382b 100644 --- a/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs +++ b/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs @@ -9,43 +9,102 @@ 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 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.Operations, this); } } } diff --git a/Perspex.Controls/Shapes/Shape.cs b/Perspex.Controls/Shapes/Shape.cs index 3f296c6b00..530bc0f6a6 100644 --- a/Perspex.Controls/Shapes/Shape.cs +++ b/Perspex.Controls/Shapes/Shape.cs @@ -39,6 +39,8 @@ namespace Perspex.Controls.Shapes Control.AffectsRender(StrokeProperty); Control.AffectsRender(StrokeDashArrayProperty); Control.AffectsMeasure(StrokeThicknessProperty); + + } public abstract Geometry DefiningGeometry diff --git a/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs b/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs index 15fb88d7d0..17b5105ba2 100644 --- a/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs +++ b/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs @@ -37,6 +37,7 @@ namespace Perspex.Direct2D1.Media public void BeginFigure(Point startPoint, bool isFilled) { + System.Diagnostics.Debug.WriteLine("IS FILLED {0}", isFilled); this.sink.BeginFigure(startPoint.ToSharpDX(), isFilled ? FigureBegin.Filled : FigureBegin.Hollow); }