diff --git a/src/Avalonia.Base/Media/IImageBrush.cs b/src/Avalonia.Base/Media/IImageBrush.cs
index 732f1957d0..07fd2d56fa 100644
--- a/src/Avalonia.Base/Media/IImageBrush.cs
+++ b/src/Avalonia.Base/Media/IImageBrush.cs
@@ -12,6 +12,6 @@ namespace Avalonia.Media
///
/// Gets the image to draw.
///
- IBitmap Source { get; }
+ IBitmap? Source { get; }
}
}
diff --git a/src/Avalonia.Base/Media/ImageBrush.cs b/src/Avalonia.Base/Media/ImageBrush.cs
index 2f2a0fb627..718ebf1686 100644
--- a/src/Avalonia.Base/Media/ImageBrush.cs
+++ b/src/Avalonia.Base/Media/ImageBrush.cs
@@ -11,8 +11,8 @@ namespace Avalonia.Media
///
/// Defines the property.
///
- public static readonly StyledProperty SourceProperty =
- AvaloniaProperty.Register(nameof(Source));
+ public static readonly StyledProperty SourceProperty =
+ AvaloniaProperty.Register(nameof(Source));
static ImageBrush()
{
@@ -30,7 +30,7 @@ namespace Avalonia.Media
/// Initializes a new instance of the class.
///
/// The image to draw.
- public ImageBrush(IBitmap source)
+ public ImageBrush(IBitmap? source)
{
Source = source;
}
@@ -38,7 +38,7 @@ namespace Avalonia.Media
///
/// Gets or sets the image to draw.
///
- public IBitmap Source
+ public IBitmap? Source
{
get { return GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs
index f9892bf60c..668a907fdf 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs
@@ -24,13 +24,13 @@ namespace Avalonia.Media.Immutable
/// The tile mode.
/// The bitmap interpolation mode.
public ImmutableImageBrush(
- IBitmap source,
+ IBitmap? source,
AlignmentX alignmentX = AlignmentX.Center,
AlignmentY alignmentY = AlignmentY.Center,
RelativeRect? destinationRect = null,
double opacity = 1,
ImmutableTransform? transform = null,
- RelativePoint transformOrigin = new RelativePoint(),
+ RelativePoint transformOrigin = default,
RelativeRect? sourceRect = null,
Stretch stretch = Stretch.Uniform,
TileMode tileMode = TileMode.None,
@@ -61,6 +61,6 @@ namespace Avalonia.Media.Immutable
}
///
- public IBitmap Source { get; }
+ public IBitmap? Source { get; }
}
}
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs
index 0b625080e3..e9086eee37 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs
@@ -24,7 +24,7 @@ namespace Avalonia.Media.Immutable
/// The tile mode.
/// Controls the quality of interpolation.
public ImmutableVisualBrush(
- Visual visual,
+ Visual? visual,
AlignmentX alignmentX = AlignmentX.Center,
AlignmentY alignmentY = AlignmentY.Center,
RelativeRect? destinationRect = null,
diff --git a/src/Avalonia.Base/Platform/IGeometryImpl.cs b/src/Avalonia.Base/Platform/IGeometryImpl.cs
index 5826cfb2ff..d1964bf07e 100644
--- a/src/Avalonia.Base/Platform/IGeometryImpl.cs
+++ b/src/Avalonia.Base/Platform/IGeometryImpl.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics.CodeAnalysis;
using Avalonia.Media;
using Avalonia.Metadata;
@@ -47,7 +48,7 @@ namespace Avalonia.Platform
/// The stroke to use.
/// The point.
/// true if the geometry contains the point; otherwise, false.
- bool StrokeContains(IPen pen, Point point);
+ bool StrokeContains(IPen? pen, Point point);
///
/// Makes a clone of the geometry with the specified transform.
@@ -87,6 +88,7 @@ namespace Avalonia.Platform
/// If ture, the resulting snipped path will start with a BeginFigure call.
/// The resulting snipped path.
/// If the snipping operation is successful.
- bool TryGetSegment(double startDistance, double stopDistance, bool startOnBeginFigure, out IGeometryImpl segmentGeometry);
+ bool TryGetSegment(double startDistance, double stopDistance, bool startOnBeginFigure,
+ [NotNullWhen(true)] out IGeometryImpl? segmentGeometry);
}
}
diff --git a/src/Browser/Avalonia.Browser/Skia/BrowserSkiaGpu.cs b/src/Browser/Avalonia.Browser/Skia/BrowserSkiaGpu.cs
index 3c04935f0d..a169966188 100644
--- a/src/Browser/Avalonia.Browser/Skia/BrowserSkiaGpu.cs
+++ b/src/Browser/Avalonia.Browser/Skia/BrowserSkiaGpu.cs
@@ -21,7 +21,7 @@ namespace Avalonia.Browser.Skia
return null;
}
- public ISkiaSurface? TryCreateSurface(PixelSize size, ISkiaGpuRenderSession session)
+ public ISkiaSurface? TryCreateSurface(PixelSize size, ISkiaGpuRenderSession? session)
{
return null;
}
diff --git a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
index 4c3cfe2ef4..ab9f9ea413 100644
--- a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
+++ b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
@@ -19,6 +19,7 @@
+
diff --git a/src/Skia/Avalonia.Skia/CombinedGeometryImpl.cs b/src/Skia/Avalonia.Skia/CombinedGeometryImpl.cs
index 40d7e10ae3..170cc9d420 100644
--- a/src/Skia/Avalonia.Skia/CombinedGeometryImpl.cs
+++ b/src/Skia/Avalonia.Skia/CombinedGeometryImpl.cs
@@ -1,9 +1,6 @@
-using System.Collections.Generic;
using Avalonia.Media;
using SkiaSharp;
-#nullable enable
-
namespace Avalonia.Skia
{
///
@@ -13,23 +10,24 @@ namespace Avalonia.Skia
{
public CombinedGeometryImpl(GeometryCombineMode combineMode, Geometry g1, Geometry g2)
{
- var path1 = ((GeometryImpl)g1.PlatformImpl).EffectivePath;
- var path2 = ((GeometryImpl)g2.PlatformImpl).EffectivePath;
+ var path1 = (g1.PlatformImpl as GeometryImpl)?.EffectivePath;
+ var path2 = (g2.PlatformImpl as GeometryImpl)?.EffectivePath;
+
var op = combineMode switch
{
GeometryCombineMode.Intersect => SKPathOp.Intersect,
GeometryCombineMode.Xor => SKPathOp.Xor,
GeometryCombineMode.Exclude => SKPathOp.Difference,
- _ => SKPathOp.Union,
+ _ => SKPathOp.Union
};
- var path = path1.Op(path2, op);
+ var path = path1?.Op(path2, op);
EffectivePath = path;
- Bounds = path.Bounds.ToAvaloniaRect();
+ Bounds = path?.Bounds.ToAvaloniaRect() ?? default;
}
public override Rect Bounds { get; }
- public override SKPath EffectivePath { get; }
+ public override SKPath? EffectivePath { get; }
}
}
diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
index eededb2836..82d902cbd0 100644
--- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
+++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
@@ -19,27 +19,27 @@ namespace Avalonia.Skia
///
internal class DrawingContextImpl : IDrawingContextImpl, IDrawingContextWithAcrylicLikeSupport
{
- private IDisposable[] _disposables;
+ private IDisposable?[]? _disposables;
private readonly Vector _dpi;
- private readonly Stack _maskStack = new Stack();
- private readonly Stack _opacityStack = new Stack();
- private readonly Stack _blendingModeStack = new Stack();
+ private readonly Stack _maskStack = new();
+ private readonly Stack _opacityStack = new();
+ private readonly Stack _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;
///
/// Context create info.
@@ -49,12 +49,12 @@ namespace Avalonia.Skia
///
/// Canvas to draw to.
///
- public SKCanvas Canvas;
+ public SKCanvas? Canvas;
///
/// Surface to draw to.
///
- public SKSurface Surface;
+ public SKSurface? Surface;
///
/// Dpi of drawings.
@@ -64,7 +64,7 @@ namespace Avalonia.Skia
///
/// Visual brush renderer.
///
- public IVisualBrushRenderer VisualBrushRenderer;
+ public IVisualBrushRenderer? VisualBrushRenderer;
///
/// Render text without Lcd rendering.
@@ -74,17 +74,17 @@ namespace Avalonia.Skia
///
/// GPU-accelerated context (optional)
///
- public GRContext GrContext;
+ public GRContext? GrContext;
///
/// Skia GPU provider context (optional)
///
- 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
///
/// Create info.
/// Array of elements to dispose after drawing has finished.
- 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.
///
public SKCanvas Canvas { get; }
- public SKSurface Surface { get; }
+ public SKSurface? Surface { get; }
private void CheckLease()
{
@@ -205,87 +206,89 @@ namespace Avalonia.Skia
}
///
- 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);
}
}
}
///
- 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
}
///
- 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
}
///
- 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);
}
///
- 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);
}
}
}
///
- public void DrawGlyphRun(IBrush foreground, IRef glyphRun)
+ public void DrawGlyphRun(IBrush? foreground, IRef 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
///
/// Configure paint wrapper for using gradient brush.
@@ -957,9 +952,10 @@ namespace Avalonia.Skia
/// Visual brush.
/// Visual brush renderer.
/// Tile brush image.
- 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
/// Source pen.
/// Target size.
///
- 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)
{
diff --git a/src/Skia/Avalonia.Skia/FontManagerImpl.cs b/src/Skia/Avalonia.Skia/FontManagerImpl.cs
index 90ff9652d8..d53dcd2df3 100644
--- a/src/Skia/Avalonia.Skia/FontManagerImpl.cs
+++ b/src/Skia/Avalonia.Skia/FontManagerImpl.cs
@@ -26,11 +26,11 @@ namespace Avalonia.Skia
return _skFontManager.FontFamilies;
}
- [ThreadStatic] private static string[] t_languageTagBuffer;
+ [ThreadStatic] private static string[]? t_languageTagBuffer;
public bool TryMatchCharacter(int codepoint, FontStyle fontStyle,
FontWeight fontWeight, FontStretch fontStretch,
- FontFamily fontFamily, CultureInfo culture, out Typeface fontKey)
+ FontFamily? fontFamily, CultureInfo? culture, out Typeface fontKey)
{
SKFontStyle skFontStyle;
@@ -53,20 +53,13 @@ namespace Avalonia.Skia
break;
}
- if (culture == null)
- {
- culture = CultureInfo.CurrentUICulture;
- }
-
- if (t_languageTagBuffer == null)
- {
- t_languageTagBuffer = new string[2];
- }
+ culture ??= CultureInfo.CurrentUICulture;
+ t_languageTagBuffer ??= new string[2];
t_languageTagBuffer[0] = culture.TwoLetterISOLanguageName;
t_languageTagBuffer[1] = culture.ThreeLetterISOLanguageName;
- if (fontFamily != null && fontFamily.FamilyNames.HasFallbacks)
+ if (fontFamily is not null && fontFamily.FamilyNames.HasFallbacks)
{
var familyNames = fontFamily.FamilyNames;
@@ -104,9 +97,9 @@ namespace Avalonia.Skia
public IGlyphTypeface CreateGlyphTypeface(Typeface typeface)
{
- SKTypeface skTypeface = null;
+ SKTypeface? skTypeface = null;
- if (typeface.FontFamily.Key == null)
+ if (typeface.FontFamily.Key is null)
{
var defaultName = SKTypeface.Default.FamilyName;
diff --git a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs
index 05fad25f1b..f1216100bc 100644
--- a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs
+++ b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using Avalonia.Reactive;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Platform;
@@ -15,9 +16,9 @@ namespace Avalonia.Skia
private readonly IFramebufferPlatformSurface _platformSurface;
private SKImageInfo _currentImageInfo;
private IntPtr _currentFramebufferAddress;
- private SKSurface _framebufferSurface;
- private PixelFormatConversionShim _conversionShim;
- private IDisposable _preFramebufferCopyHandler;
+ private SKSurface? _framebufferSurface;
+ private PixelFormatConversionShim? _conversionShim;
+ private IDisposable? _preFramebufferCopyHandler;
///
/// Create new framebuffer render target using a target surface.
@@ -35,7 +36,7 @@ namespace Avalonia.Skia
}
///
- public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
+ public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer? visualBrushRenderer)
{
var framebuffer = _platformSurface.Lock();
var framebufferImageInfo = new SKImageInfo(framebuffer.Size.Width, framebuffer.Size.Height,
@@ -81,6 +82,7 @@ namespace Avalonia.Skia
///
/// Desired image info.
/// Backing framebuffer.
+ [MemberNotNull(nameof(_framebufferSurface))]
private void CreateSurface(SKImageInfo desiredImageInfo, ILockedFramebuffer framebuffer)
{
if (_framebufferSurface != null && AreImageInfosCompatible(_currentImageInfo, desiredImageInfo) && _currentFramebufferAddress == framebuffer.Address)
diff --git a/src/Skia/Avalonia.Skia/GeometryGroupImpl.cs b/src/Skia/Avalonia.Skia/GeometryGroupImpl.cs
index d6f19612c1..2828f9a9c1 100644
--- a/src/Skia/Avalonia.Skia/GeometryGroupImpl.cs
+++ b/src/Skia/Avalonia.Skia/GeometryGroupImpl.cs
@@ -2,8 +2,6 @@ using System.Collections.Generic;
using Avalonia.Media;
using SkiaSharp;
-#nullable enable
-
namespace Avalonia.Skia
{
///
@@ -22,8 +20,10 @@ namespace Avalonia.Skia
for (var i = 0; i < count; ++i)
{
- if (children[i]?.PlatformImpl is GeometryImpl child)
- path.AddPath(child.EffectivePath);
+ if (children[i].PlatformImpl is GeometryImpl { EffectivePath: { } effectivePath })
+ {
+ path.AddPath(effectivePath);
+ }
}
EffectivePath = path;
diff --git a/src/Skia/Avalonia.Skia/GeometryImpl.cs b/src/Skia/Avalonia.Skia/GeometryImpl.cs
index 51386d2a45..34270c2078 100644
--- a/src/Skia/Avalonia.Skia/GeometryImpl.cs
+++ b/src/Skia/Avalonia.Skia/GeometryImpl.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using Avalonia.Media;
using Avalonia.Platform;
using SkiaSharp;
@@ -11,20 +12,9 @@ namespace Avalonia.Skia
internal abstract class GeometryImpl : IGeometryImpl
{
private PathCache _pathCache;
- private SKPathMeasure _pathMeasureCache;
+ private SKPathMeasure? _cachedPathMeasure;
- private SKPathMeasure CachedPathMeasure
- {
- get
- {
- if (_pathMeasureCache is null)
- {
- _pathMeasureCache = new SKPathMeasure(EffectivePath);
- }
-
- return _pathMeasureCache;
- }
- }
+ private SKPathMeasure CachedPathMeasure => _cachedPathMeasure ??= new SKPathMeasure(EffectivePath!);
///
public abstract Rect Bounds { get; }
@@ -37,11 +27,11 @@ namespace Avalonia.Skia
if (EffectivePath is null)
return 0;
- return (double)CachedPathMeasure?.Length;
+ return CachedPathMeasure.Length;
}
}
- public abstract SKPath EffectivePath { get; }
+ public abstract SKPath? EffectivePath { get; }
///
public bool FillContains(Point point)
@@ -50,7 +40,7 @@ namespace Avalonia.Skia
}
///
- public bool StrokeContains(IPen pen, Point point)
+ public bool StrokeContains(IPen? pen, Point point)
{
// Skia requires to compute stroke path to check for point containment.
// Due to that we are caching using stroke width.
@@ -98,21 +88,26 @@ namespace Avalonia.Skia
/// Path to check.
/// Point.
/// True, if point is contained in a path.
- private static bool PathContainsCore(SKPath path, Point point)
+ private static bool PathContainsCore(SKPath? path, Point point)
{
- return path.Contains((float)point.X, (float)point.Y);
+ return path is not null && path.Contains((float)point.X, (float)point.Y);
}
///
- public IGeometryImpl Intersect(IGeometryImpl geometry)
+ public IGeometryImpl? Intersect(IGeometryImpl geometry)
{
- var result = EffectivePath.Op(((GeometryImpl)geometry).EffectivePath, SKPathOp.Intersect);
+ if (EffectivePath is { } path
+ && (geometry as GeometryImpl)?.EffectivePath is { } otherPath
+ && path.Op(otherPath, SKPathOp.Intersect) is { } result)
+ {
+ return new StreamGeometryImpl(result);
+ }
- return result == null ? null : new StreamGeometryImpl(result);
+ return null;
}
///
- public Rect GetRenderBounds(IPen pen)
+ public Rect GetRenderBounds(IPen? pen)
{
var strokeWidth = (float)(pen?.Thickness ?? 0);
@@ -161,7 +156,7 @@ namespace Avalonia.Skia
}
public bool TryGetSegment(double startDistance, double stopDistance, bool startOnBeginFigure,
- out IGeometryImpl segmentGeometry)
+ [NotNullWhen(true)] out IGeometryImpl? segmentGeometry)
{
if (EffectivePath is null)
{
@@ -203,7 +198,7 @@ namespace Avalonia.Skia
///
/// Cached contour path.
///
- public SKPath CachedStrokePath { get; private set; }
+ public SKPath? CachedStrokePath { get; private set; }
///
/// Cached geometry render bounds.
@@ -244,6 +239,7 @@ namespace Avalonia.Skia
public void Invalidate()
{
CachedStrokePath?.Dispose();
+ CachedStrokePath = null;
CachedGeometryRenderBounds = default;
_cachedStrokeWidth = default;
}
diff --git a/src/Skia/Avalonia.Skia/GlyphRunImpl.cs b/src/Skia/Avalonia.Skia/GlyphRunImpl.cs
index cfd6fc12f8..079eea7bef 100644
--- a/src/Skia/Avalonia.Skia/GlyphRunImpl.cs
+++ b/src/Skia/Avalonia.Skia/GlyphRunImpl.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using Avalonia.Platform;
using SkiaSharp;
-#nullable enable
namespace Avalonia.Skia
{
@@ -10,7 +9,7 @@ namespace Avalonia.Skia
{
public GlyphRunImpl(SKTextBlob textBlob, Size size, Point baselineOrigin)
{
- TextBlob = textBlob ?? throw new ArgumentNullException (nameof (textBlob));
+ TextBlob = textBlob ?? throw new ArgumentNullException(nameof(textBlob));
Size = size;
diff --git a/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs b/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs
index a8dd289a13..3093455bec 100644
--- a/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs
+++ b/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs
@@ -140,7 +140,7 @@ namespace Avalonia.Skia
return Font.GetHorizontalGlyphAdvances(glyphIndices);
}
- private Blob GetTable(Face face, Tag tag)
+ private Blob? GetTable(Face face, Tag tag)
{
var size = Typeface.GetTableSize(tag);
@@ -166,8 +166,8 @@ namespace Avalonia.Skia
return;
}
- Font?.Dispose();
- Face?.Dispose();
+ Font.Dispose();
+ Face.Dispose();
}
public void Dispose()
diff --git a/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs b/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs
index a5782037f3..e6e30a1203 100644
--- a/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs
+++ b/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs
@@ -15,14 +15,14 @@ namespace Avalonia.Skia
///
/// Surfaces.
/// Created render target or if it fails.
- ISkiaGpuRenderTarget TryCreateRenderTarget(IEnumerable