From 38251d330779ae72af07d3c1a42d4f129527bc01 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 18 Apr 2016 22:43:49 +0300 Subject: [PATCH] Implemented tile brushes for new skia backend --- src/Skia/Perspex.Skia/DrawingContextImpl.cs | 90 ++++++++++++++++----- 1 file changed, 71 insertions(+), 19 deletions(-) diff --git a/src/Skia/Perspex.Skia/DrawingContextImpl.cs b/src/Skia/Perspex.Skia/DrawingContextImpl.cs index 88df7aecdc..78049c50ea 100644 --- a/src/Skia/Perspex.Skia/DrawingContextImpl.cs +++ b/src/Skia/Perspex.Skia/DrawingContextImpl.cs @@ -4,6 +4,7 @@ using Perspex.Media; using Perspex.Media.Imaging; using SkiaSharp; using System.Linq; +using Perspex.RenderHelpers; namespace Perspex.Skia { @@ -29,7 +30,7 @@ namespace Perspex.Skia { using (var paint = CreatePaint(pen, new Size(Math.Abs(p2.X - p1.X), Math.Abs(p2.Y - p1.Y)))) { - Canvas.DrawLine((float)p1.X, (float)p1.Y, (float)p2.X, (float)p2.Y, paint); + Canvas.DrawLine((float)p1.X, (float)p1.Y, (float)p2.X, (float)p2.Y, paint.Paint); } } @@ -38,24 +39,53 @@ namespace Perspex.Skia var impl = ((StreamGeometryImpl)geometry.PlatformImpl); var size = geometry.Bounds.Size; - using (var fill = brush != null ? CreatePaint(brush, size) : null) - using (var stroke = pen?.Brush != null ? CreatePaint(pen, size) : null) + using (var fill = brush != null ? CreatePaint(brush, size) : default(PaintWrapper)) + using (var stroke = pen?.Brush != null ? CreatePaint(pen, size) : default(PaintWrapper)) { - if (fill != null) + if (fill.Paint != null) { - Canvas.DrawPath(impl.EffectivePath, fill); + Canvas.DrawPath(impl.EffectivePath, fill.Paint); } - if (stroke != null) + if (stroke.Paint != null) { - Canvas.DrawPath(impl.EffectivePath, stroke); + Canvas.DrawPath(impl.EffectivePath, stroke.Paint); } } } - private SKPaint CreatePaint(IBrush brush, Size targetSize) + struct PaintWrapper : IDisposable { - SKPaint paint = new SKPaint(); + //We are saving memory allocations there + //TODO: add more disposable fields if needed + + public readonly SKPaint Paint; + private IDisposable _disposable1; + + public void AddDisposable(IDisposable disposable) + { + if (_disposable1 == null) + _disposable1 = disposable; + else + throw new InvalidOperationException(); + } + + public PaintWrapper(SKPaint paint) + { + Paint = paint; + _disposable1 = null; + } + + public void Dispose() + { + Paint?.Dispose(); + _disposable1?.Dispose(); + } + } + private PaintWrapper CreatePaint(IBrush brush, Size targetSize) + { + SKPaint paint = new SKPaint(); + var rv = new PaintWrapper(paint); paint.IsStroke = false; // TODO: SkiaSharp does not contain alpha yet! @@ -67,7 +97,7 @@ namespace Perspex.Skia if (solid != null) { paint.Color = solid.Color.ToSKColor(); - return paint; + return rv; } var gradient = brush as GradientBrush; @@ -104,12 +134,33 @@ namespace Perspex.Skia } } - return paint; + return rv; } var tileBrush = brush as TileBrush; if (tileBrush != null) { + var helper = new TileBrushImplHelper(tileBrush, targetSize); + var bitmap = new BitmapImpl((int)helper.IntermediateSize.Width, (int)helper.IntermediateSize.Height); + rv.AddDisposable(bitmap); + using (var ctx = bitmap.CreateDrawingContext()) + helper.DrawIntermediate(ctx); + SKMatrix translation = SKMatrix.MakeTranslation(-(float)helper.DestinationRect.X, -(float)helper.DestinationRect.Y); + SKShaderTileMode tileX = + tileBrush.TileMode == TileMode.None + ? SKShaderTileMode.Clamp + : tileBrush.TileMode == TileMode.FlipX || tileBrush.TileMode == TileMode.FlipXY + ? SKShaderTileMode.Mirror + : SKShaderTileMode.Repeat; + + SKShaderTileMode tileY = + tileBrush.TileMode == TileMode.None + ? SKShaderTileMode.Clamp + : tileBrush.TileMode == TileMode.FlipY || tileBrush.TileMode == TileMode.FlipXY + ? SKShaderTileMode.Mirror + : SKShaderTileMode.Repeat; + paint.Shader = SKShader.CreateBitmap(bitmap.Bitmap, tileX, tileY, translation); + // TODO: Get Tile Brushes working!!! // //throw new NotImplementedException(); @@ -134,12 +185,13 @@ namespace Perspex.Skia // paint.setShader(SkShader::CreateBitmapShader(brush->Bitmap->Bitmap, tileX, tileY, &matrix))->unref(); } - return paint; + return rv; } - private SKPaint CreatePaint(Pen pen, Size targetSize) + private PaintWrapper CreatePaint(Pen pen, Size targetSize) { - var paint = CreatePaint(pen.Brush, targetSize); + var rv = CreatePaint(pen.Brush, targetSize); + var paint = rv.Paint; paint.IsStroke = true; paint.StrokeWidth = (float)pen.Thickness; @@ -179,7 +231,7 @@ namespace Perspex.Skia // paint.setPathEffect(SkDashPathEffect::Create(brush->StrokeDashes, brush->StrokeDashCount, brush->StrokeDashOffset))->unref(); //} - return paint; + return rv; } public void DrawRectangle(Pen pen, Rect rect, float cornerRadius = 0) @@ -189,13 +241,13 @@ namespace Perspex.Skia var rc = rect.ToSKRect(); if (cornerRadius == 0) { - Canvas.DrawRect(rc, paint); + Canvas.DrawRect(rc, paint.Paint); } else { // TODO: DrawRRect (ore DrawRoundedRect) is not accesible in SkiaSharp yet. We should add that // to SkiaSharp and initiate a PR.... - Canvas.DrawRect(rc, paint); + Canvas.DrawRect(rc, paint.Paint); //Canvas.DrawRoundedRect(rc, cornerRadius, cornerRadius, paint); } } @@ -208,14 +260,14 @@ namespace Perspex.Skia var rc = rect.ToSKRect(); if (cornerRadius == 0) { - Canvas.DrawRect(rc, paint); + Canvas.DrawRect(rc, paint.Paint); } else { // TODO: this does not exist in SkiaSharp yet //throw new NotImplementedException(); //Canvas.DrawRoundedRect(rc, cornerRadius, cornerRadius, paint); - Canvas.DrawRect(rc, paint); + Canvas.DrawRect(rc, paint.Paint); } } }