|
|
|
@ -30,6 +30,10 @@ namespace Avalonia.Skia |
|
|
|
private Matrix _currentTransform; |
|
|
|
private GRContext _grContext; |
|
|
|
private bool _disposed; |
|
|
|
|
|
|
|
private readonly SKPaint _strokePaint = new SKPaint(); |
|
|
|
private readonly SKPaint _fillPaint = new SKPaint(); |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Context create info.
|
|
|
|
/// </summary>
|
|
|
|
@ -153,7 +157,7 @@ namespace Avalonia.Skia |
|
|
|
/// <inheritdoc />
|
|
|
|
public void DrawLine(IPen pen, Point p1, Point p2) |
|
|
|
{ |
|
|
|
using (var paint = CreatePaint(pen, new Size(Math.Abs(p2.X - p1.X), Math.Abs(p2.Y - p1.Y)))) |
|
|
|
using (var paint = CreatePaint(_strokePaint, 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.Paint); |
|
|
|
} |
|
|
|
@ -165,8 +169,8 @@ namespace Avalonia.Skia |
|
|
|
var impl = (GeometryImpl) geometry; |
|
|
|
var size = geometry.Bounds.Size; |
|
|
|
|
|
|
|
using (var fill = brush != null ? CreatePaint(brush, size) : default(PaintWrapper)) |
|
|
|
using (var stroke = pen?.Brush != null ? CreatePaint(pen, size) : default(PaintWrapper)) |
|
|
|
using (var fill = brush != null ? CreatePaint(_fillPaint, brush, size) : default(PaintWrapper)) |
|
|
|
using (var stroke = pen?.Brush != null ? CreatePaint(_strokePaint, pen, size) : default(PaintWrapper)) |
|
|
|
{ |
|
|
|
if (fill.Paint != null) |
|
|
|
{ |
|
|
|
@ -188,7 +192,7 @@ namespace Avalonia.Skia |
|
|
|
|
|
|
|
if (brush != null) |
|
|
|
{ |
|
|
|
using (var paint = CreatePaint(brush, rect.Size)) |
|
|
|
using (var paint = CreatePaint(_fillPaint, brush, rect.Size)) |
|
|
|
{ |
|
|
|
if (isRounded) |
|
|
|
{ |
|
|
|
@ -204,7 +208,7 @@ namespace Avalonia.Skia |
|
|
|
|
|
|
|
if (pen?.Brush != null) |
|
|
|
{ |
|
|
|
using (var paint = CreatePaint(pen, rect.Size)) |
|
|
|
using (var paint = CreatePaint(_strokePaint, pen, rect.Size)) |
|
|
|
{ |
|
|
|
if (isRounded) |
|
|
|
{ |
|
|
|
@ -222,7 +226,7 @@ namespace Avalonia.Skia |
|
|
|
/// <inheritdoc />
|
|
|
|
public void DrawText(IBrush foreground, Point origin, IFormattedTextImpl text) |
|
|
|
{ |
|
|
|
using (var paint = CreatePaint(foreground, text.Bounds.Size)) |
|
|
|
using (var paint = CreatePaint(_fillPaint, foreground, text.Bounds.Size)) |
|
|
|
{ |
|
|
|
var textImpl = (FormattedTextImpl) text; |
|
|
|
textImpl.Draw(this, Canvas, origin.ToSKPoint(), paint, _canTextUseLcdRendering); |
|
|
|
@ -232,14 +236,14 @@ namespace Avalonia.Skia |
|
|
|
/// <inheritdoc />
|
|
|
|
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun, Point baselineOrigin) |
|
|
|
{ |
|
|
|
using (var paint = CreatePaint(foreground, glyphRun.Bounds.Size)) |
|
|
|
using (var paintWrapper = CreatePaint(_fillPaint, foreground, glyphRun.Bounds.Size)) |
|
|
|
{ |
|
|
|
var glyphRunImpl = (GlyphRunImpl)glyphRun.GlyphRunImpl; |
|
|
|
|
|
|
|
paint.ApplyTo(glyphRunImpl.Paint); |
|
|
|
ConfigureTextRendering(paintWrapper); |
|
|
|
|
|
|
|
Canvas.DrawText(glyphRunImpl.TextBlob, (float)baselineOrigin.X, |
|
|
|
(float)baselineOrigin.Y, glyphRunImpl.Paint); |
|
|
|
(float)baselineOrigin.Y, paintWrapper.Paint); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -323,7 +327,7 @@ namespace Avalonia.Skia |
|
|
|
var paint = new SKPaint(); |
|
|
|
|
|
|
|
Canvas.SaveLayer(paint); |
|
|
|
_maskStack.Push(CreatePaint(mask, bounds.Size)); |
|
|
|
_maskStack.Push(CreatePaint(paint, mask, bounds.Size, true)); |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
@ -364,6 +368,15 @@ namespace Avalonia.Skia |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
internal void ConfigureTextRendering(PaintWrapper wrapper) |
|
|
|
{ |
|
|
|
var paint = wrapper.Paint; |
|
|
|
|
|
|
|
paint.IsEmbeddedBitmapText = true; |
|
|
|
paint.SubpixelText = true; |
|
|
|
paint.LcdRenderText = _canTextUseLcdRendering; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Configure paint wrapper for using gradient brush.
|
|
|
|
/// </summary>
|
|
|
|
@ -514,17 +527,16 @@ namespace Avalonia.Skia |
|
|
|
/// <summary>
|
|
|
|
/// Creates paint wrapper for given brush.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="paint">The paint to wrap.</param>
|
|
|
|
/// <param name="brush">Source brush.</param>
|
|
|
|
/// <param name="targetSize">Target size.</param>
|
|
|
|
/// <param name="disposePaint">Optional dispose of the supplied paint.</param>
|
|
|
|
/// <returns>Paint wrapper for given brush.</returns>
|
|
|
|
internal PaintWrapper CreatePaint(IBrush brush, Size targetSize) |
|
|
|
internal PaintWrapper CreatePaint(SKPaint paint, IBrush brush, Size targetSize, bool disposePaint = false) |
|
|
|
{ |
|
|
|
var paint = new SKPaint |
|
|
|
{ |
|
|
|
IsAntialias = true |
|
|
|
}; |
|
|
|
var paintWrapper = new PaintWrapper(paint, disposePaint); |
|
|
|
|
|
|
|
var paintWrapper = new PaintWrapper(paint); |
|
|
|
paint.IsAntialias = true; |
|
|
|
|
|
|
|
double opacity = brush.Opacity * _currentOpacity; |
|
|
|
|
|
|
|
@ -572,10 +584,12 @@ namespace Avalonia.Skia |
|
|
|
/// <summary>
|
|
|
|
/// Creates paint wrapper for given pen.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="paint">The paint to wrap.</param>
|
|
|
|
/// <param name="pen">Source pen.</param>
|
|
|
|
/// <param name="targetSize">Target size.</param>
|
|
|
|
/// <param name="disposePaint">Optional dispose of the supplied paint.</param>
|
|
|
|
/// <returns></returns>
|
|
|
|
private PaintWrapper CreatePaint(IPen pen, Size targetSize) |
|
|
|
private PaintWrapper CreatePaint(SKPaint paint, IPen pen, Size targetSize, bool disposePaint = false) |
|
|
|
{ |
|
|
|
// In Skia 0 thickness means - use hairline rendering
|
|
|
|
// and for us it means - there is nothing rendered.
|
|
|
|
@ -584,8 +598,7 @@ namespace Avalonia.Skia |
|
|
|
return default; |
|
|
|
} |
|
|
|
|
|
|
|
var rv = CreatePaint(pen.Brush, targetSize); |
|
|
|
var paint = rv.Paint; |
|
|
|
var rv = CreatePaint(paint, pen.Brush, targetSize, disposePaint); |
|
|
|
|
|
|
|
paint.IsStroke = true; |
|
|
|
paint.StrokeWidth = (float) pen.Thickness; |
|
|
|
@ -668,7 +681,7 @@ namespace Avalonia.Skia |
|
|
|
/// <summary>
|
|
|
|
/// Skia cached paint state.
|
|
|
|
/// </summary>
|
|
|
|
private struct PaintState : IDisposable |
|
|
|
private readonly struct PaintState : IDisposable |
|
|
|
{ |
|
|
|
private readonly SKColor _color; |
|
|
|
private readonly SKShader _shader; |
|
|
|
@ -696,14 +709,16 @@ namespace Avalonia.Skia |
|
|
|
{ |
|
|
|
//We are saving memory allocations there
|
|
|
|
public readonly SKPaint Paint; |
|
|
|
private readonly bool _disposePaint; |
|
|
|
|
|
|
|
private IDisposable _disposable1; |
|
|
|
private IDisposable _disposable2; |
|
|
|
private IDisposable _disposable3; |
|
|
|
|
|
|
|
public PaintWrapper(SKPaint paint) |
|
|
|
public PaintWrapper(SKPaint paint, bool disposePaint) |
|
|
|
{ |
|
|
|
Paint = paint; |
|
|
|
_disposePaint = disposePaint; |
|
|
|
|
|
|
|
_disposable1 = null; |
|
|
|
_disposable2 = null; |
|
|
|
@ -751,7 +766,15 @@ namespace Avalonia.Skia |
|
|
|
/// <inheritdoc />
|
|
|
|
public void Dispose() |
|
|
|
{ |
|
|
|
Paint?.Dispose(); |
|
|
|
if (_disposePaint) |
|
|
|
{ |
|
|
|
Paint?.Dispose(); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
Paint?.Reset(); |
|
|
|
} |
|
|
|
|
|
|
|
_disposable1?.Dispose(); |
|
|
|
_disposable2?.Dispose(); |
|
|
|
_disposable3?.Dispose(); |
|
|
|
|