|
|
|
@ -19,27 +19,27 @@ namespace Avalonia.Skia |
|
|
|
/// </summary>
|
|
|
|
internal class DrawingContextImpl : IDrawingContextImpl, IDrawingContextWithAcrylicLikeSupport |
|
|
|
{ |
|
|
|
private IDisposable[] _disposables; |
|
|
|
private IDisposable?[]? _disposables; |
|
|
|
private readonly Vector _dpi; |
|
|
|
private readonly Stack<PaintWrapper> _maskStack = new Stack<PaintWrapper>(); |
|
|
|
private readonly Stack<double> _opacityStack = new Stack<double>(); |
|
|
|
private readonly Stack<BitmapBlendingMode> _blendingModeStack = new Stack<BitmapBlendingMode>(); |
|
|
|
private readonly Stack<PaintWrapper> _maskStack = new(); |
|
|
|
private readonly Stack<double> _opacityStack = new(); |
|
|
|
private readonly Stack<BitmapBlendingMode> _blendingModeStack = new(); |
|
|
|
private readonly Matrix? _postTransform; |
|
|
|
private readonly IVisualBrushRenderer _visualBrushRenderer; |
|
|
|
private readonly IVisualBrushRenderer? _visualBrushRenderer; |
|
|
|
private double _currentOpacity = 1.0f; |
|
|
|
private BitmapBlendingMode _currentBlendingMode = BitmapBlendingMode.SourceOver; |
|
|
|
private readonly bool _canTextUseLcdRendering; |
|
|
|
private Matrix _currentTransform; |
|
|
|
private bool _disposed; |
|
|
|
private GRContext _grContext; |
|
|
|
public GRContext GrContext => _grContext; |
|
|
|
private ISkiaGpu _gpu; |
|
|
|
private GRContext? _grContext; |
|
|
|
public GRContext? GrContext => _grContext; |
|
|
|
private readonly ISkiaGpu? _gpu; |
|
|
|
private readonly SKPaint _strokePaint = SKPaintCache.Shared.Get(); |
|
|
|
private readonly SKPaint _fillPaint = SKPaintCache.Shared.Get(); |
|
|
|
private readonly SKPaint _boxShadowPaint = SKPaintCache.Shared.Get(); |
|
|
|
private static SKShader s_acrylicNoiseShader; |
|
|
|
private readonly ISkiaGpuRenderSession _session; |
|
|
|
private bool _leased = false; |
|
|
|
private static SKShader? s_acrylicNoiseShader; |
|
|
|
private readonly ISkiaGpuRenderSession? _session; |
|
|
|
private bool _leased; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Context create info.
|
|
|
|
@ -49,12 +49,12 @@ namespace Avalonia.Skia |
|
|
|
/// <summary>
|
|
|
|
/// Canvas to draw to.
|
|
|
|
/// </summary>
|
|
|
|
public SKCanvas Canvas; |
|
|
|
public SKCanvas? Canvas; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Surface to draw to.
|
|
|
|
/// </summary>
|
|
|
|
public SKSurface Surface; |
|
|
|
public SKSurface? Surface; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Dpi of drawings.
|
|
|
|
@ -64,7 +64,7 @@ namespace Avalonia.Skia |
|
|
|
/// <summary>
|
|
|
|
/// Visual brush renderer.
|
|
|
|
/// </summary>
|
|
|
|
public IVisualBrushRenderer VisualBrushRenderer; |
|
|
|
public IVisualBrushRenderer? VisualBrushRenderer; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Render text without Lcd rendering.
|
|
|
|
@ -74,17 +74,17 @@ namespace Avalonia.Skia |
|
|
|
/// <summary>
|
|
|
|
/// GPU-accelerated context (optional)
|
|
|
|
/// </summary>
|
|
|
|
public GRContext GrContext; |
|
|
|
public GRContext? GrContext; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Skia GPU provider context (optional)
|
|
|
|
/// </summary>
|
|
|
|
public ISkiaGpu Gpu; |
|
|
|
public ISkiaGpu? Gpu; |
|
|
|
|
|
|
|
public ISkiaGpuRenderSession CurrentSession; |
|
|
|
public ISkiaGpuRenderSession? CurrentSession; |
|
|
|
} |
|
|
|
|
|
|
|
class SkiaLeaseFeature : ISkiaSharpApiLeaseFeature |
|
|
|
private class SkiaLeaseFeature : ISkiaSharpApiLeaseFeature |
|
|
|
{ |
|
|
|
private readonly DrawingContextImpl _context; |
|
|
|
|
|
|
|
@ -99,10 +99,11 @@ namespace Avalonia.Skia |
|
|
|
return new ApiLease(_context); |
|
|
|
} |
|
|
|
|
|
|
|
class ApiLease : ISkiaSharpApiLease |
|
|
|
private class ApiLease : ISkiaSharpApiLease |
|
|
|
{ |
|
|
|
private DrawingContextImpl _context; |
|
|
|
private readonly DrawingContextImpl _context; |
|
|
|
private readonly SKMatrix _revertTransform; |
|
|
|
private bool _isDisposed; |
|
|
|
|
|
|
|
public ApiLease(DrawingContextImpl context) |
|
|
|
{ |
|
|
|
@ -112,15 +113,18 @@ namespace Avalonia.Skia |
|
|
|
} |
|
|
|
|
|
|
|
public SKCanvas SkCanvas => _context.Canvas; |
|
|
|
public GRContext GrContext => _context.GrContext; |
|
|
|
public SKSurface SkSurface => _context.Surface; |
|
|
|
public GRContext? GrContext => _context.GrContext; |
|
|
|
public SKSurface? SkSurface => _context.Surface; |
|
|
|
public double CurrentOpacity => _context._currentOpacity; |
|
|
|
|
|
|
|
public void Dispose() |
|
|
|
{ |
|
|
|
_context.Canvas.SetMatrix(_revertTransform); |
|
|
|
_context._leased = false; |
|
|
|
_context = null; |
|
|
|
if (!_isDisposed) |
|
|
|
{ |
|
|
|
_context.Canvas.SetMatrix(_revertTransform); |
|
|
|
_context._leased = false; |
|
|
|
_isDisposed = true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -130,8 +134,11 @@ namespace Avalonia.Skia |
|
|
|
/// </summary>
|
|
|
|
/// <param name="createInfo">Create info.</param>
|
|
|
|
/// <param name="disposables">Array of elements to dispose after drawing has finished.</param>
|
|
|
|
public DrawingContextImpl(CreateInfo createInfo, params IDisposable[] disposables) |
|
|
|
public DrawingContextImpl(CreateInfo createInfo, params IDisposable?[]? disposables) |
|
|
|
{ |
|
|
|
Canvas = createInfo.Canvas ?? createInfo.Surface?.Canvas |
|
|
|
?? throw new ArgumentException("Invalid create info - no Canvas provided", nameof(createInfo)); |
|
|
|
|
|
|
|
_dpi = createInfo.Dpi; |
|
|
|
_visualBrushRenderer = createInfo.VisualBrushRenderer; |
|
|
|
_disposables = disposables; |
|
|
|
@ -141,15 +148,9 @@ namespace Avalonia.Skia |
|
|
|
if (_grContext != null) |
|
|
|
Monitor.Enter(_grContext); |
|
|
|
Surface = createInfo.Surface; |
|
|
|
Canvas = createInfo.Canvas ?? createInfo.Surface?.Canvas; |
|
|
|
|
|
|
|
_session = createInfo.CurrentSession; |
|
|
|
|
|
|
|
if (Canvas == null) |
|
|
|
{ |
|
|
|
throw new ArgumentException("Invalid create info - no Canvas provided", nameof(createInfo)); |
|
|
|
} |
|
|
|
|
|
|
|
if (!_dpi.NearlyEquals(SkiaPlatform.DefaultDpi)) |
|
|
|
{ |
|
|
|
_postTransform = |
|
|
|
@ -163,7 +164,7 @@ namespace Avalonia.Skia |
|
|
|
/// Skia canvas.
|
|
|
|
/// </summary>
|
|
|
|
public SKCanvas Canvas { get; } |
|
|
|
public SKSurface Surface { get; } |
|
|
|
public SKSurface? Surface { get; } |
|
|
|
|
|
|
|
private void CheckLease() |
|
|
|
{ |
|
|
|
@ -205,87 +206,89 @@ namespace Avalonia.Skia |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
public void DrawLine(IPen pen, Point p1, Point p2) |
|
|
|
public void DrawLine(IPen? pen, Point p1, Point p2) |
|
|
|
{ |
|
|
|
CheckLease(); |
|
|
|
|
|
|
|
if (pen is null) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
using (var paint = CreatePaint(_strokePaint, pen, new Size(Math.Abs(p2.X - p1.X), Math.Abs(p2.Y - p1.Y)))) |
|
|
|
if (pen is not null |
|
|
|
&& TryCreatePaint(_strokePaint, pen, new Size(Math.Abs(p2.X - p1.X), Math.Abs(p2.Y - p1.Y))) is { } stroke) |
|
|
|
{ |
|
|
|
if (paint.Paint is object) |
|
|
|
using (stroke) |
|
|
|
{ |
|
|
|
Canvas.DrawLine((float)p1.X, (float)p1.Y, (float)p2.X, (float)p2.Y, paint.Paint); |
|
|
|
Canvas.DrawLine((float)p1.X, (float)p1.Y, (float)p2.X, (float)p2.Y, stroke.Paint); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
public void DrawGeometry(IBrush brush, IPen pen, IGeometryImpl geometry) |
|
|
|
public void DrawGeometry(IBrush? brush, IPen? pen, IGeometryImpl geometry) |
|
|
|
{ |
|
|
|
CheckLease(); |
|
|
|
var impl = (GeometryImpl) geometry; |
|
|
|
var size = geometry.Bounds.Size; |
|
|
|
|
|
|
|
using (var fill = brush != null ? CreatePaint(_fillPaint, brush, size) : default) |
|
|
|
using (var stroke = pen?.Brush != null ? CreatePaint(_strokePaint, pen, |
|
|
|
size.Inflate(new Thickness(pen?.Thickness / 2 ?? 0))) : default) |
|
|
|
if (brush is not null) |
|
|
|
{ |
|
|
|
if (fill.Paint != null) |
|
|
|
using (var fill = CreatePaint(_fillPaint, brush, size)) |
|
|
|
{ |
|
|
|
Canvas.DrawPath(impl.EffectivePath, fill.Paint); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (stroke.Paint != null) |
|
|
|
if (pen is not null |
|
|
|
&& TryCreatePaint(_strokePaint, pen, size.Inflate(new Thickness(pen.Thickness / 2))) is { } stroke) |
|
|
|
{ |
|
|
|
using (stroke) |
|
|
|
{ |
|
|
|
Canvas.DrawPath(impl.EffectivePath, stroke.Paint); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
struct BoxShadowFilter : IDisposable |
|
|
|
private struct BoxShadowFilter : IDisposable |
|
|
|
{ |
|
|
|
public SKPaint Paint; |
|
|
|
private SKImageFilter _filter; |
|
|
|
public SKClipOperation ClipOperation; |
|
|
|
public readonly SKPaint Paint; |
|
|
|
private readonly SKImageFilter? _filter; |
|
|
|
public readonly SKClipOperation ClipOperation; |
|
|
|
|
|
|
|
private BoxShadowFilter(SKPaint paint, SKImageFilter? filter, SKClipOperation clipOperation) |
|
|
|
{ |
|
|
|
Paint = paint; |
|
|
|
_filter = filter; |
|
|
|
ClipOperation = clipOperation; |
|
|
|
} |
|
|
|
|
|
|
|
static float SkBlurRadiusToSigma(double radius) { |
|
|
|
private static float SkBlurRadiusToSigma(double radius) { |
|
|
|
if (radius <= 0) |
|
|
|
return 0.0f; |
|
|
|
return 0.288675f * (float)radius + 0.5f; |
|
|
|
} |
|
|
|
|
|
|
|
public static BoxShadowFilter Create(SKPaint paint, BoxShadow shadow, double opacity) |
|
|
|
{ |
|
|
|
var ac = shadow.Color; |
|
|
|
|
|
|
|
SKImageFilter filter = null; |
|
|
|
filter = SKImageFilter.CreateBlur(SkBlurRadiusToSigma(shadow.Blur), SkBlurRadiusToSigma(shadow.Blur)); |
|
|
|
var filter = SKImageFilter.CreateBlur(SkBlurRadiusToSigma(shadow.Blur), SkBlurRadiusToSigma(shadow.Blur)); |
|
|
|
var color = new SKColor(ac.R, ac.G, ac.B, (byte)(ac.A * opacity)); |
|
|
|
|
|
|
|
paint.Reset(); |
|
|
|
paint.IsAntialias = true; |
|
|
|
paint.Color = color; |
|
|
|
paint.ImageFilter = filter; |
|
|
|
|
|
|
|
return new BoxShadowFilter |
|
|
|
{ |
|
|
|
Paint = paint, _filter = filter, |
|
|
|
ClipOperation = shadow.IsInset ? SKClipOperation.Intersect : SKClipOperation.Difference |
|
|
|
}; |
|
|
|
|
|
|
|
var clipOperation = shadow.IsInset ? SKClipOperation.Intersect : SKClipOperation.Difference; |
|
|
|
|
|
|
|
return new BoxShadowFilter(paint, filter, clipOperation); |
|
|
|
} |
|
|
|
|
|
|
|
public void Dispose() |
|
|
|
{ |
|
|
|
Paint.Reset(); |
|
|
|
Paint = null; |
|
|
|
Paint?.Reset(); |
|
|
|
_filter?.Dispose(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static SKRect AreaCastingShadowInHole( |
|
|
|
private static SKRect AreaCastingShadowInHole( |
|
|
|
SKRect hole_rect, |
|
|
|
float shadow_blur, |
|
|
|
float shadow_spread, |
|
|
|
@ -306,18 +309,16 @@ namespace Avalonia.Skia |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
public void DrawRectangle(IExperimentalAcrylicMaterial material, RoundedRect rect) |
|
|
|
public void DrawRectangle(IExperimentalAcrylicMaterial? material, RoundedRect rect) |
|
|
|
{ |
|
|
|
if (rect.Rect.Height <= 0 || rect.Rect.Width <= 0) |
|
|
|
return; |
|
|
|
CheckLease(); |
|
|
|
|
|
|
|
var rc = rect.Rect.ToSKRect(); |
|
|
|
var isRounded = rect.IsRounded; |
|
|
|
var needRoundRect = rect.IsRounded; |
|
|
|
SKRoundRect skRoundRect = null; |
|
|
|
SKRoundRect? skRoundRect = null; |
|
|
|
|
|
|
|
if (needRoundRect) |
|
|
|
if (rect.IsRounded) |
|
|
|
{ |
|
|
|
skRoundRect = SKRoundRectCache.Shared.Get(); |
|
|
|
skRoundRect.SetRectRadii(rc, |
|
|
|
@ -334,7 +335,7 @@ namespace Avalonia.Skia |
|
|
|
{ |
|
|
|
using (var paint = CreateAcrylicPaint(_fillPaint, material)) |
|
|
|
{ |
|
|
|
if (isRounded) |
|
|
|
if (skRoundRect is not null) |
|
|
|
{ |
|
|
|
Canvas.DrawRoundRect(skRoundRect, paint.Paint); |
|
|
|
SKRoundRectCache.Shared.Return(skRoundRect); |
|
|
|
@ -349,7 +350,7 @@ namespace Avalonia.Skia |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
public void DrawRectangle(IBrush brush, IPen pen, RoundedRect rect, BoxShadows boxShadows = default) |
|
|
|
public void DrawRectangle(IBrush? brush, IPen? pen, RoundedRect rect, BoxShadows boxShadows = default) |
|
|
|
{ |
|
|
|
if (rect.Rect.Height <= 0 || rect.Rect.Width <= 0) |
|
|
|
return; |
|
|
|
@ -362,7 +363,7 @@ namespace Avalonia.Skia |
|
|
|
var rc = rect.Rect.ToSKRect(); |
|
|
|
var isRounded = rect.IsRounded; |
|
|
|
var needRoundRect = rect.IsRounded || (boxShadows.HasInsetShadows); |
|
|
|
SKRoundRect skRoundRect = null; |
|
|
|
SKRoundRect? skRoundRect = null; |
|
|
|
if (needRoundRect) |
|
|
|
{ |
|
|
|
skRoundRect = SKRoundRectCache.Shared.GetAndSetRadii(rc, rect); |
|
|
|
@ -412,15 +413,15 @@ namespace Avalonia.Skia |
|
|
|
|
|
|
|
if (brush != null) |
|
|
|
{ |
|
|
|
using (var paint = CreatePaint(_fillPaint, brush, rect.Rect.Size)) |
|
|
|
using (var fill = CreatePaint(_fillPaint, brush, rect.Rect.Size)) |
|
|
|
{ |
|
|
|
if (isRounded) |
|
|
|
{ |
|
|
|
Canvas.DrawRoundRect(skRoundRect, paint.Paint); |
|
|
|
Canvas.DrawRoundRect(skRoundRect, fill.Paint); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
Canvas.DrawRect(rc, paint.Paint); |
|
|
|
Canvas.DrawRect(rc, fill.Paint); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -454,30 +455,28 @@ namespace Avalonia.Skia |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (pen?.Brush != null) |
|
|
|
if (pen is not null |
|
|
|
&& TryCreatePaint(_strokePaint, pen, rect.Rect.Size.Inflate(new Thickness(pen.Thickness / 2))) is { } stroke) |
|
|
|
{ |
|
|
|
using (var paint = CreatePaint(_strokePaint, pen, rect.Rect.Size.Inflate(new Thickness(pen?.Thickness / 2 ?? 0)))) |
|
|
|
using (stroke) |
|
|
|
{ |
|
|
|
if (paint.Paint is object) |
|
|
|
if (isRounded) |
|
|
|
{ |
|
|
|
if (isRounded) |
|
|
|
{ |
|
|
|
Canvas.DrawRoundRect(skRoundRect, paint.Paint); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
Canvas.DrawRect(rc, paint.Paint); |
|
|
|
} |
|
|
|
Canvas.DrawRoundRect(skRoundRect, stroke.Paint); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
Canvas.DrawRect(rc, stroke.Paint); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if(isRounded) |
|
|
|
if (skRoundRect is not null) |
|
|
|
SKRoundRectCache.Shared.Return(skRoundRect); |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
public void DrawEllipse(IBrush brush, IPen pen, Rect rect) |
|
|
|
public void DrawEllipse(IBrush? brush, IPen? pen, Rect rect) |
|
|
|
{ |
|
|
|
if (rect.Height <= 0 || rect.Width <= 0) |
|
|
|
return; |
|
|
|
@ -487,26 +486,24 @@ namespace Avalonia.Skia |
|
|
|
|
|
|
|
if (brush != null) |
|
|
|
{ |
|
|
|
using (var paint = CreatePaint(_fillPaint, brush, rect.Size)) |
|
|
|
using (var fill = CreatePaint(_fillPaint, brush, rect.Size)) |
|
|
|
{ |
|
|
|
Canvas.DrawOval(rc, paint.Paint); |
|
|
|
Canvas.DrawOval(rc, fill.Paint); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (pen?.Brush != null) |
|
|
|
if (pen is not null |
|
|
|
&& TryCreatePaint(_strokePaint, pen, rect.Size.Inflate(new Thickness(pen.Thickness / 2))) is { } stroke) |
|
|
|
{ |
|
|
|
using (var paint = CreatePaint(_strokePaint, pen, rect.Size.Inflate(new Thickness(pen?.Thickness / 2 ?? 0)))) |
|
|
|
using (stroke) |
|
|
|
{ |
|
|
|
if (paint.Paint is object) |
|
|
|
{ |
|
|
|
Canvas.DrawOval(rc, paint.Paint); |
|
|
|
} |
|
|
|
Canvas.DrawOval(rc, stroke.Paint); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
public void DrawGlyphRun(IBrush foreground, IRef<IGlyphRunImpl> glyphRun) |
|
|
|
public void DrawGlyphRun(IBrush? foreground, IRef<IGlyphRunImpl> glyphRun) |
|
|
|
{ |
|
|
|
CheckLease(); |
|
|
|
|
|
|
|
@ -711,14 +708,12 @@ namespace Avalonia.Skia |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#nullable enable |
|
|
|
public object? GetFeature(Type t) |
|
|
|
{ |
|
|
|
if (t == typeof(ISkiaSharpApiLeaseFeature)) |
|
|
|
return new SkiaLeaseFeature(this); |
|
|
|
return null; |
|
|
|
} |
|
|
|
#nullable restore |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Configure paint wrapper for using gradient brush.
|
|
|
|
@ -957,9 +952,10 @@ namespace Avalonia.Skia |
|
|
|
/// <param name="visualBrush">Visual brush.</param>
|
|
|
|
/// <param name="visualBrushRenderer">Visual brush renderer.</param>
|
|
|
|
/// <param name="tileBrushImage">Tile brush image.</param>
|
|
|
|
private void ConfigureVisualBrush(ref PaintWrapper paintWrapper, IVisualBrush visualBrush, IVisualBrushRenderer visualBrushRenderer, ref IDrawableBitmapImpl tileBrushImage) |
|
|
|
private void ConfigureVisualBrush(ref PaintWrapper paintWrapper, IVisualBrush visualBrush, |
|
|
|
IVisualBrushRenderer? visualBrushRenderer, ref IDrawableBitmapImpl? tileBrushImage) |
|
|
|
{ |
|
|
|
if (_visualBrushRenderer == null) |
|
|
|
if (visualBrushRenderer == null) |
|
|
|
{ |
|
|
|
throw new NotSupportedException("No IVisualBrushRenderer was supplied to DrawingContextImpl."); |
|
|
|
} |
|
|
|
@ -982,7 +978,7 @@ namespace Avalonia.Skia |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static SKColorFilter CreateAlphaColorFilter(double opacity) |
|
|
|
private static SKColorFilter CreateAlphaColorFilter(double opacity) |
|
|
|
{ |
|
|
|
if (opacity > 1) |
|
|
|
opacity = 1; |
|
|
|
@ -997,7 +993,7 @@ namespace Avalonia.Skia |
|
|
|
return SKColorFilter.CreateTable(a, c, c, c); |
|
|
|
} |
|
|
|
|
|
|
|
static byte Blend(byte leftColor, byte leftAlpha, byte rightColor, byte rightAlpha) |
|
|
|
private static byte Blend(byte leftColor, byte leftAlpha, byte rightColor, byte rightAlpha) |
|
|
|
{ |
|
|
|
var ca = leftColor / 255d; |
|
|
|
var aa = leftAlpha / 255d; |
|
|
|
@ -1007,7 +1003,7 @@ namespace Avalonia.Skia |
|
|
|
return (byte)(r * 255); |
|
|
|
} |
|
|
|
|
|
|
|
static Color Blend(Color left, Color right) |
|
|
|
private static Color Blend(Color left, Color right) |
|
|
|
{ |
|
|
|
var aa = left.A / 255d; |
|
|
|
var ab = right.A / 255d; |
|
|
|
@ -1103,7 +1099,7 @@ namespace Avalonia.Skia |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
tileBrushImage = (IDrawableBitmapImpl)(tileBrush as IImageBrush)?.Source?.PlatformImpl.Item; |
|
|
|
tileBrushImage = (tileBrush as IImageBrush)?.Source?.PlatformImpl.Item as IDrawableBitmapImpl; |
|
|
|
} |
|
|
|
|
|
|
|
if (tileBrush != null && tileBrushImage != null) |
|
|
|
@ -1125,16 +1121,16 @@ namespace Avalonia.Skia |
|
|
|
/// <param name="pen">Source pen.</param>
|
|
|
|
/// <param name="targetSize">Target size.</param>
|
|
|
|
/// <returns></returns>
|
|
|
|
private PaintWrapper CreatePaint(SKPaint paint, IPen pen, Size targetSize) |
|
|
|
private PaintWrapper? TryCreatePaint(SKPaint paint, IPen pen, Size targetSize) |
|
|
|
{ |
|
|
|
// In Skia 0 thickness means - use hairline rendering
|
|
|
|
// and for us it means - there is nothing rendered.
|
|
|
|
if (pen.Thickness == 0d) |
|
|
|
if (pen.Brush is not { } brush || pen.Thickness == 0d) |
|
|
|
{ |
|
|
|
return default; |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
var rv = CreatePaint(paint, pen.Brush, targetSize); |
|
|
|
var rv = CreatePaint(paint, brush, targetSize); |
|
|
|
|
|
|
|
paint.IsStroke = true; |
|
|
|
paint.StrokeWidth = (float) pen.Thickness; |
|
|
|
@ -1253,9 +1249,9 @@ namespace Avalonia.Skia |
|
|
|
//We are saving memory allocations there
|
|
|
|
public readonly SKPaint Paint; |
|
|
|
|
|
|
|
private IDisposable _disposable1; |
|
|
|
private IDisposable _disposable2; |
|
|
|
private IDisposable _disposable3; |
|
|
|
private IDisposable? _disposable1; |
|
|
|
private IDisposable? _disposable2; |
|
|
|
private IDisposable? _disposable3; |
|
|
|
|
|
|
|
public PaintWrapper(SKPaint paint) |
|
|
|
{ |
|
|
|
|