diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 00b54e8c5a..9c233426fc 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; using Avalonia.Media; using Avalonia.Media.Imaging; +using Avalonia.RenderHelpers; using SkiaSharp; +using System; +using System.Collections.Generic; using System.Linq; -using Avalonia.RenderHelpers; namespace Avalonia.Skia { @@ -53,14 +53,47 @@ namespace Avalonia.Skia } } - struct PaintWrapper : IDisposable + private struct PaintDisposable : IDisposable + { + private Action _action; + + public PaintDisposable(Action action) + { + _action = action; + } + + public void Dispose() + { + _action?.Invoke(); + } + } + + internal struct PaintWrapper : IDisposable { //We are saving memory allocations there //TODO: add more disposable fields if needed - public readonly SKPaint Paint; private IDisposable _disposable1; + private Func _applyToAction; + + public void SetApplyToAction(Func get, + Action apply, + Action revert) + { + _applyToAction = (from, to) => + { + T state = get(to); + apply(from, to); + return new PaintDisposable(() => revert(to, state)); + }; + } + + public IDisposable ApplyTo(SKPaint paint) + { + return _applyToAction != null ? _applyToAction(Paint, paint) : default(PaintDisposable); + } + public void AddDisposable(IDisposable disposable) { if (_disposable1 == null) @@ -73,6 +106,7 @@ namespace Avalonia.Skia { Paint = paint; _disposable1 = null; + _applyToAction = null; } public void Dispose() @@ -95,13 +129,20 @@ namespace Avalonia.Skia SKColor color = new SKColor(255, 255, 255, 255); - var solid = brush as SolidColorBrush; + var solid = brush as ISolidColorBrush; if (solid != null) color = solid.Color.ToSKColor(); - paint.Color = (new SKColor(color.Red, color.Green, color.Blue, (byte) (color.Alpha*opacity))); + paint.Color = (new SKColor(color.Red, color.Green, color.Blue, (byte)(color.Alpha * opacity))); + if (solid != null) + { + rv.SetApplyToAction(p => p.Color, + (from, to) => to.Color = from.Color, + (p, v) => p.Color = v); return rv; + } + var gradient = brush as GradientBrush; @@ -140,6 +181,9 @@ namespace Avalonia.Skia } } + rv.SetApplyToAction(p => p.Shader, + (from, to) => to.Shader = from.Shader, + (p, v) => p.Shader = v); return rv; } @@ -150,7 +194,7 @@ namespace Avalonia.Skia var bitmap = new BitmapImpl((int)helper.IntermediateSize.Width, (int)helper.IntermediateSize.Height); rv.AddDisposable(bitmap); using (var ctx = bitmap.CreateDrawingContext()) - helper.DrawIntermediate(ctx); + helper.DrawIntermediate(ctx); SKMatrix translation = SKMatrix.MakeTranslation(-(float)helper.DestinationRect.X, -(float)helper.DestinationRect.Y); SKShaderTileMode tileX = tileBrush.TileMode == TileMode.None @@ -167,6 +211,10 @@ namespace Avalonia.Skia : SKShaderTileMode.Repeat; paint.Shader = SKShader.CreateBitmap(bitmap.Bitmap, tileX, tileY, translation); paint.Shader.Dispose(); + + rv.SetApplyToAction(p => p.Shader, + (from, to) => to.Shader = from.Shader, + (p, v) => p.Shader = v); } return rv; @@ -255,7 +303,7 @@ namespace Avalonia.Skia using (var paint = CreatePaint(foreground, text.Measure())) { var textImpl = text.PlatformImpl as FormattedTextImpl; - textImpl.Draw(this.Canvas, origin.ToSKPoint()); + textImpl.Draw(this.Canvas, origin.ToSKPoint(), paint); } } @@ -270,7 +318,7 @@ namespace Avalonia.Skia Canvas.Restore(); } - double _currentOpacity = 1.0f; + private double _currentOpacity = 1.0f; private readonly Stack _opacityStack = new Stack(); public void PushOpacity(double opacity) diff --git a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs index e0c0cdf98e..aee4511d44 100644 --- a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs +++ b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs @@ -254,7 +254,7 @@ namespace Avalonia.Skia } } - internal void Draw(SKCanvas canvas, SKPoint origin) + internal void Draw(SKCanvas canvas, SKPoint origin, DrawingContextImpl.PaintWrapper foreground) { SKPaint paint = Paint; @@ -284,11 +284,14 @@ namespace Avalonia.Skia ctx->Canvas->restore(); */ - for (int c = 0; c < _skiaLines.Count; c++) + using (foreground.ApplyTo(paint)) { - AvaloniaFormattedTextLine line = _skiaLines[c]; - var subString = _text.Substring(line.Start, line.Length); - canvas.DrawText(subString, origin.X, origin.Y + line.Top + LineOffset, paint); + for (int c = 0; c < _skiaLines.Count; c++) + { + AvaloniaFormattedTextLine line = _skiaLines[c]; + var subString = _text.Substring(line.Start, line.Length); + canvas.DrawText(subString, origin.X, origin.Y + line.Top + LineOffset, paint); + } } }