Browse Source

Added a lot of nullable annotations to Avalonia.Visuals.

Except types related to text and one method in `DrawingContext` which I'm not sure what to do with.
pull/7203/head
Steven Kirk 4 years ago
parent
commit
22a55fed27
  1. 2
      src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs
  2. 2
      src/Avalonia.Visuals/Animation/Animators/BaseBrushAnimator.cs
  3. 4
      src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs
  4. 2
      src/Avalonia.Visuals/Animation/CompositePageTransition.cs
  5. 6
      src/Avalonia.Visuals/Animation/CrossFade.cs
  6. 2
      src/Avalonia.Visuals/Animation/IPageTransition.cs
  7. 10
      src/Avalonia.Visuals/Animation/PageSlide.cs
  8. 4
      src/Avalonia.Visuals/Animation/RenderLoopClock.cs
  9. 1
      src/Avalonia.Visuals/Avalonia.Visuals.csproj
  10. 2
      src/Avalonia.Visuals/CornerRadius.cs
  11. 2
      src/Avalonia.Visuals/Matrix.cs
  12. 11
      src/Avalonia.Visuals/Media/BoxShadow.cs
  13. 6
      src/Avalonia.Visuals/Media/BoxShadows.cs
  14. 22
      src/Avalonia.Visuals/Media/Brush.cs
  15. 8
      src/Avalonia.Visuals/Media/BrushConverter.cs
  16. 6
      src/Avalonia.Visuals/Media/BrushExtensions.cs
  17. 2
      src/Avalonia.Visuals/Media/CharacterHit.cs
  18. 2
      src/Avalonia.Visuals/Media/Color.cs
  19. 2
      src/Avalonia.Visuals/Media/DashStyle.cs
  20. 35
      src/Avalonia.Visuals/Media/DrawingContext.cs
  21. 2
      src/Avalonia.Visuals/Media/DrawingImage.cs
  22. 6
      src/Avalonia.Visuals/Media/EllipseGeometry.cs
  23. 6
      src/Avalonia.Visuals/Media/ExperimentalAcrylicMaterial.cs
  24. 16
      src/Avalonia.Visuals/Media/FontFamily.cs
  25. 2
      src/Avalonia.Visuals/Media/FontManager.cs
  26. 6
      src/Avalonia.Visuals/Media/Fonts/FamilyNameCollection.cs
  27. 10
      src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs
  28. 6
      src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs
  29. 16
      src/Avalonia.Visuals/Media/FormattedText.cs
  30. 4
      src/Avalonia.Visuals/Media/FormattedTextStyleSpan.cs
  31. 24
      src/Avalonia.Visuals/Media/Geometry.cs
  32. 9
      src/Avalonia.Visuals/Media/GlyphRun.cs
  33. 12
      src/Avalonia.Visuals/Media/GradientBrush.cs
  34. 4
      src/Avalonia.Visuals/Media/IPen.cs
  35. 29
      src/Avalonia.Visuals/Media/Imaging/Bitmap.cs
  36. 16
      src/Avalonia.Visuals/Media/Imaging/CroppedBitmap.cs
  37. 5
      src/Avalonia.Visuals/Media/Imaging/RenderTargetBitmap.cs
  38. 14
      src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs
  39. 4
      src/Avalonia.Visuals/Media/Immutable/ImmutableDashStyle.cs
  40. 14
      src/Avalonia.Visuals/Media/Immutable/ImmutablePen.cs
  41. 4
      src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs
  42. 2
      src/Avalonia.Visuals/Media/ImmutableExperimentalAcrylicMaterial.cs
  43. 8
      src/Avalonia.Visuals/Media/KnownColors.cs
  44. 6
      src/Avalonia.Visuals/Media/LineGeometry.cs
  45. 2
      src/Avalonia.Visuals/Media/MaterialExtensions.cs
  46. 35
      src/Avalonia.Visuals/Media/PathGeometry.cs
  47. 4
      src/Avalonia.Visuals/Media/PathGeometryCollections.cs
  48. 34
      src/Avalonia.Visuals/Media/PathMarkupParser.cs
  49. 22
      src/Avalonia.Visuals/Media/Pen.cs
  50. 2
      src/Avalonia.Visuals/Media/PixelPoint.cs
  51. 2
      src/Avalonia.Visuals/Media/PixelRect.cs
  52. 2
      src/Avalonia.Visuals/Media/PixelSize.cs
  53. 2
      src/Avalonia.Visuals/Media/PixelVector.cs
  54. 11
      src/Avalonia.Visuals/Media/PolylineGeometry.cs
  55. 6
      src/Avalonia.Visuals/Media/RectangleGeometry.cs
  56. 12
      src/Avalonia.Visuals/Media/StreamGeometry.cs
  57. 14
      src/Avalonia.Visuals/Media/TextFormatting/GenericTextRunProperties.cs
  58. 2
      src/Avalonia.Visuals/Media/TextFormatting/ITextSource.cs
  59. 4
      src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs
  60. 2
      src/Avalonia.Visuals/Media/TextFormatting/TextFormatter.cs
  61. 18
      src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs
  62. 22
      src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs
  63. 2
      src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs
  64. 4
      src/Avalonia.Visuals/Media/TextFormatting/TextLineBreak.cs
  65. 4
      src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
  66. 2
      src/Avalonia.Visuals/Media/TextFormatting/TextParagraphProperties.cs
  67. 4
      src/Avalonia.Visuals/Media/TextFormatting/TextRun.cs
  68. 12
      src/Avalonia.Visuals/Media/TextFormatting/TextRunProperties.cs
  69. 2
      src/Avalonia.Visuals/Media/TextFormatting/TextShaper.cs
  70. 4
      src/Avalonia.Visuals/Media/TextFormatting/Unicode/UnicodeData.cs
  71. 2
      src/Avalonia.Visuals/Media/Transform.cs
  72. 6
      src/Avalonia.Visuals/Media/TransformConverter.cs
  73. 2
      src/Avalonia.Visuals/Media/TransformGroup.cs
  74. 4
      src/Avalonia.Visuals/Media/Transformation/TransformOperation.cs
  75. 6
      src/Avalonia.Visuals/Media/Typeface.cs
  76. 2
      src/Avalonia.Visuals/Media/UnicodeRange.cs
  77. 6
      src/Avalonia.Visuals/Platform/ExportRenderingSubsystemAttribute.cs
  78. 4
      src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs
  79. 2
      src/Avalonia.Visuals/Platform/IFontManagerImpl.cs
  80. 2
      src/Avalonia.Visuals/Platform/IGeometryImpl.cs
  81. 2
      src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs
  82. 2
      src/Avalonia.Visuals/Platform/IRenderTarget.cs
  83. 2
      src/Avalonia.Visuals/Platform/ITextShaperImpl.cs
  84. 35
      src/Avalonia.Visuals/Platform/PathGeometryContext.cs
  85. 2
      src/Avalonia.Visuals/Point.cs
  86. 2
      src/Avalonia.Visuals/Rect.cs
  87. 2
      src/Avalonia.Visuals/RelativePoint.cs
  88. 2
      src/Avalonia.Visuals/RelativeRect.cs
  89. 16
      src/Avalonia.Visuals/Rendering/DefaultRenderTimer.cs
  90. 72
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  91. 5
      src/Avalonia.Visuals/Rendering/DirtyVisuals.cs
  92. 2
      src/Avalonia.Visuals/Rendering/IDeferredRendererLock.cs
  93. 4
      src/Avalonia.Visuals/Rendering/IRenderer.cs
  94. 16
      src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs
  95. 6
      src/Avalonia.Visuals/Rendering/RenderLayers.cs
  96. 14
      src/Avalonia.Visuals/Rendering/RenderLoop.cs
  97. 2
      src/Avalonia.Visuals/Rendering/SceneGraph/BrushDrawOperation.cs
  98. 48
      src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs
  99. 2
      src/Avalonia.Visuals/Rendering/SceneGraph/ExperimentalAcrylicNode.cs
  100. 2
      src/Avalonia.Visuals/Rendering/SceneGraph/GeometryClipNode.cs

2
src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs

@ -14,7 +14,7 @@ namespace Avalonia.AndroidTestApplication
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "12.1.99.62")]
public partial class Resource
{

2
src/Avalonia.Visuals/Animation/Animators/BaseBrushAnimator.cs

@ -143,7 +143,7 @@ namespace Avalonia.Animation.Animators
if (!match(firstKeyType))
continue;
animator = (IAnimator)Activator.CreateInstance(animatorType);
animator = (IAnimator?)Activator.CreateInstance(animatorType);
if (animator != null)
{
animator.Property = Property;

4
src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs

@ -11,10 +11,10 @@ namespace Avalonia.Animation.Animators
/// </summary>
public class TransformAnimator : Animator<double>
{
DoubleAnimator _doubleAnimator;
DoubleAnimator? _doubleAnimator;
/// <inheritdoc/>
public override IDisposable Apply(Animation animation, Animatable control, IClock clock, IObservable<bool> obsMatch, Action onComplete)
public override IDisposable? Apply(Animation animation, Animatable control, IClock clock, IObservable<bool> obsMatch, Action onComplete)
{
var ctrl = (Visual)control;

2
src/Avalonia.Visuals/Animation/CompositePageTransition.cs

@ -37,7 +37,7 @@ namespace Avalonia.Animation
public List<IPageTransition> PageTransitions { get; set; } = new List<IPageTransition>();
/// <inheritdoc />
public Task Start(Visual from, Visual to, bool forward, CancellationToken cancellationToken)
public Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken)
{
var transitionTasks = PageTransitions
.Select(transition => transition.Start(from, to, forward, cancellationToken))

6
src/Avalonia.Visuals/Animation/CrossFade.cs

@ -100,7 +100,7 @@ namespace Avalonia.Animation
}
/// <inheritdoc cref="Start(Visual, Visual, CancellationToken)" />
public async Task Start(Visual from, Visual to, CancellationToken cancellationToken)
public async Task Start(Visual? from, Visual? to, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
@ -112,7 +112,7 @@ namespace Avalonia.Animation
{
if (to != null)
{
disposables.Add(to.SetValue(Visual.OpacityProperty, 0, Data.BindingPriority.Animation));
disposables.Add(to.SetValue(Visual.OpacityProperty, 0, Data.BindingPriority.Animation)!);
}
if (from != null)
@ -151,7 +151,7 @@ namespace Avalonia.Animation
/// <returns>
/// A <see cref="Task"/> that tracks the progress of the animation.
/// </returns>
Task IPageTransition.Start(Visual from, Visual to, bool forward, CancellationToken cancellationToken)
Task IPageTransition.Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken)
{
return Start(from, to, cancellationToken);
}

2
src/Avalonia.Visuals/Animation/IPageTransition.cs

@ -26,6 +26,6 @@ namespace Avalonia.Animation
/// <returns>
/// A <see cref="Task"/> that tracks the progress of the animation.
/// </returns>
Task Start(Visual from, Visual to, bool forward, CancellationToken cancellationToken);
Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken);
}
}

10
src/Avalonia.Visuals/Animation/PageSlide.cs

@ -62,7 +62,7 @@ namespace Avalonia.Animation
public Easing SlideOutEasing { get; set; } = new LinearEasing();
/// <inheritdoc />
public async Task Start(Visual from, Visual to, bool forward, CancellationToken cancellationToken)
public async Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
@ -155,17 +155,17 @@ namespace Avalonia.Animation
/// <remarks>
/// Any one of the parameters may be null, but not both.
/// </remarks>
private static IVisual GetVisualParent(IVisual from, IVisual to)
private static IVisual GetVisualParent(IVisual? from, IVisual? to)
{
var p1 = (from ?? to).VisualParent;
var p2 = (to ?? from).VisualParent;
var p1 = (from ?? to)!.VisualParent;
var p2 = (to ?? from)!.VisualParent;
if (p1 != null && p2 != null && p1 != p2)
{
throw new ArgumentException("Controls for PageSlide must have same parent.");
}
return p1;
return p1 ?? throw new InvalidOperationException("Cannot determine visual parent.");
}
}
}

4
src/Avalonia.Visuals/Animation/RenderLoopClock.cs

@ -9,7 +9,9 @@ namespace Avalonia.Animation
{
protected override void Stop()
{
AvaloniaLocator.Current.GetService<IRenderLoop>().Remove(this);
var loop = AvaloniaLocator.Current.GetService<IRenderLoop>() ??
throw new InvalidOperationException("Unable to locate IRenderLoop.");
loop.Remove(this);
}
bool IRenderLoopTask.NeedsUpdate => HasSubscriptions;

1
src/Avalonia.Visuals/Avalonia.Visuals.csproj

@ -15,4 +15,5 @@
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\System.Memory.props" />
<Import Project="..\..\build\ApiDiff.props" />
<Import Project="..\..\build\NullableEnable.props" />
</Project>

2
src/Avalonia.Visuals/CornerRadius.cs

@ -91,7 +91,7 @@ namespace Avalonia
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this corner radius; False otherwise.</returns>
public override bool Equals(object obj) => obj is CornerRadius other && Equals(other);
public override bool Equals(object? obj) => obj is CornerRadius other && Equals(other);
public override int GetHashCode()
{

2
src/Avalonia.Visuals/Matrix.cs

@ -272,7 +272,7 @@ namespace Avalonia
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this matrix; False otherwise.</returns>
public override bool Equals(object obj) => obj is Matrix other && Equals(other);
public override bool Equals(object? obj) => obj is Matrix other && Equals(other);
/// <summary>
/// Returns the hash code for this instance.

11
src/Avalonia.Visuals/Media/BoxShadow.cs

@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
using Avalonia.Animation.Animators;
@ -26,7 +27,7 @@ namespace Avalonia.Media
return OffsetX.Equals(other.OffsetX) && OffsetY.Equals(other.OffsetY) && Blur.Equals(other.Blur) && Spread.Equals(other.Spread) && Color.Equals(other.Color);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is BoxShadow other && Equals(other);
}
@ -59,7 +60,7 @@ namespace Avalonia.Media
_index = 0;
}
public bool TryReadString(out string s)
public bool TryReadString([MaybeNullWhen(false)] out string s)
{
s = null;
if (_index >= _arr.Length)
@ -152,11 +153,11 @@ namespace Avalonia.Media
tokenizer.TryReadString(out var token5);
if (token4 != null)
blur = double.Parse(token3, CultureInfo.InvariantCulture);
blur = double.Parse(token3!, CultureInfo.InvariantCulture);
if (token5 != null)
spread = double.Parse(token4, CultureInfo.InvariantCulture);
spread = double.Parse(token4!, CultureInfo.InvariantCulture);
var color = Color.Parse(token5 ?? token4 ?? token3);
var color = Color.Parse(token5 ?? token4 ?? token3!);
return new BoxShadow
{
IsInset = inset,

6
src/Avalonia.Visuals/Media/BoxShadows.cs

@ -8,7 +8,7 @@ namespace Avalonia.Media
public struct BoxShadows
{
private readonly BoxShadow _first;
private readonly BoxShadow[] _list;
private readonly BoxShadow[]? _list;
public int Count { get; }
static BoxShadows()
@ -39,7 +39,7 @@ namespace Avalonia.Media
throw new IndexOutOfRangeException();
if (c == 0)
return _first;
return _list[c - 1];
return _list![c - 1];
}
}
@ -134,7 +134,7 @@ namespace Avalonia.Media
return true;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is BoxShadows other && Equals(other);
}

22
src/Avalonia.Visuals/Media/Brush.cs

@ -19,7 +19,7 @@ namespace Avalonia.Media
AvaloniaProperty.Register<Brush, double>(nameof(Opacity), 1.0);
/// <inheritdoc/>
public event EventHandler Invalidated;
public event EventHandler? Invalidated;
static Brush()
{
@ -43,18 +43,20 @@ namespace Avalonia.Media
/// <returns>The <see cref="Color"/>.</returns>
public static IBrush Parse(string s)
{
Contract.Requires<ArgumentNullException>(s != null);
Contract.Requires<FormatException>(s.Length > 0);
_ = s ?? throw new ArgumentNullException(nameof(s));
if (s[0] == '#')
if (s.Length > 0)
{
return new ImmutableSolidColorBrush(Color.Parse(s));
}
if (s[0] == '#')
{
return new ImmutableSolidColorBrush(Color.Parse(s));
}
var brush = KnownColors.GetKnownBrush(s);
if (brush != null)
{
return brush;
var brush = KnownColors.GetKnownBrush(s);
if (brush != null)
{
return brush;
}
}
throw new FormatException($"Invalid brush string: '{s}'.");

8
src/Avalonia.Visuals/Media/BrushConverter.cs

@ -9,14 +9,14 @@ namespace Avalonia.Media
/// </summary>
public class BrushConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object? value)
{
return Brush.Parse((string)value);
return value is string s ? Brush.Parse(s) : null;
}
}
}
}

6
src/Avalonia.Visuals/Media/BrushExtensions.cs

@ -18,7 +18,7 @@ namespace Avalonia.Media
/// </returns>
public static IBrush ToImmutable(this IBrush brush)
{
Contract.Requires<ArgumentNullException>(brush != null);
_ = brush ?? throw new ArgumentNullException(nameof(brush));
return (brush as IMutableBrush)?.ToImmutable() ?? brush;
}
@ -33,7 +33,7 @@ namespace Avalonia.Media
/// </returns>
public static ImmutableDashStyle ToImmutable(this IDashStyle style)
{
Contract.Requires<ArgumentNullException>(style != null);
_ = style ?? throw new ArgumentNullException(nameof(style));
return style as ImmutableDashStyle ?? ((DashStyle)style).ToImmutable();
}
@ -48,7 +48,7 @@ namespace Avalonia.Media
/// </returns>
public static ImmutablePen ToImmutable(this IPen pen)
{
Contract.Requires<ArgumentNullException>(pen != null);
_ = pen ?? throw new ArgumentNullException(nameof(pen));
return pen as ImmutablePen ?? ((Pen)pen).ToImmutable();
}

2
src/Avalonia.Visuals/Media/CharacterHit.cs

@ -41,7 +41,7 @@ namespace Avalonia.Media
return FirstCharacterIndex == other.FirstCharacterIndex && TrailingLength == other.TrailingLength;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is CharacterHit other && Equals(other);
}

2
src/Avalonia.Visuals/Media/Color.cs

@ -280,7 +280,7 @@ namespace Avalonia.Media
return A == other.A && R == other.R && G == other.G && B == other.B;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is Color other && Equals(other);
}

2
src/Avalonia.Visuals/Media/DashStyle.cs

@ -133,7 +133,7 @@ namespace Avalonia.Media
}
}
private void DashesChanged(object sender, NotifyCollectionChangedEventArgs e)
private void DashesChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
Invalidated?.Invoke(this, e);
}

35
src/Avalonia.Visuals/Media/DrawingContext.cs

@ -20,9 +20,9 @@ namespace Avalonia.Media
private static ThreadSafeObjectPool<Stack<TransformContainer>> TransformStackPool { get; } =
ThreadSafeObjectPool<Stack<TransformContainer>>.Default;
private Stack<PushedState> _states = StateStackPool.Get();
private Stack<PushedState>? _states = StateStackPool.Get();
private Stack<TransformContainer> _transformContainers = TransformStackPool.Get();
private Stack<TransformContainer>? _transformContainers = TransformStackPool.Get();
readonly struct TransformContainer
{
@ -80,7 +80,7 @@ namespace Avalonia.Media
/// <param name="rect">The rect in the output to draw to.</param>
public void DrawImage(IImage source, Rect rect)
{
Contract.Requires<ArgumentNullException>(source != null);
_ = source ?? throw new ArgumentNullException(nameof(source));
DrawImage(source, new Rect(source.Size), rect);
}
@ -94,7 +94,7 @@ namespace Avalonia.Media
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
public void DrawImage(IImage source, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = default)
{
Contract.Requires<ArgumentNullException>(source != null);
_ = source ?? throw new ArgumentNullException(nameof(source));
source.Draw(this, sourceRect, destRect, bitmapInterpolationMode);
}
@ -121,7 +121,8 @@ namespace Avalonia.Media
/// <param name="geometry">The geometry.</param>
public void DrawGeometry(IBrush brush, IPen pen, Geometry geometry)
{
DrawGeometry(brush, pen, geometry.PlatformImpl);
if (geometry.PlatformImpl is not null)
DrawGeometry(brush, pen, geometry.PlatformImpl);
}
/// <summary>
@ -132,7 +133,7 @@ namespace Avalonia.Media
/// <param name="geometry">The geometry.</param>
public void DrawGeometry(IBrush brush, IPen pen, IGeometryImpl geometry)
{
Contract.Requires<ArgumentNullException>(geometry != null);
_ = geometry ?? throw new ArgumentNullException(nameof(geometry));
if (brush != null || PenIsVisible(pen))
{
@ -157,7 +158,7 @@ namespace Avalonia.Media
/// The brush and the pen can both be null. If the brush is null, then no fill is performed.
/// If the pen is null, then no stoke is performed. If both the pen and the brush are null, then the drawing is not visible.
/// </remarks>
public void DrawRectangle(IBrush brush, IPen pen, Rect rect, double radiusX = 0, double radiusY = 0,
public void DrawRectangle(IBrush? brush, IPen? pen, Rect rect, double radiusX = 0, double radiusY = 0,
BoxShadows boxShadows = default)
{
if (brush == null && !PenIsVisible(pen))
@ -230,7 +231,7 @@ namespace Avalonia.Media
/// <param name="text">The text.</param>
public void DrawText(IBrush foreground, Point origin, FormattedText text)
{
Contract.Requires<ArgumentNullException>(text != null);
_ = text ?? throw new ArgumentNullException(nameof(text));
if (foreground != null)
{
@ -245,7 +246,7 @@ namespace Avalonia.Media
/// <param name="glyphRun">The glyph run.</param>
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
Contract.Requires<ArgumentNullException>(glyphRun != null);
_ = glyphRun ?? throw new ArgumentNullException(nameof(glyphRun));
if (foreground != null)
{
@ -279,11 +280,14 @@ namespace Avalonia.Media
Clip,
MatrixContainer,
GeometryClip,
OpacityMask
OpacityMask,
}
public PushedState(DrawingContext context, PushedStateType type, Matrix matrix = default(Matrix))
{
if (context._states is null)
throw new ObjectDisposedException(nameof(DrawingContext));
_context = context;
_type = type;
_matrix = matrix;
@ -293,6 +297,8 @@ namespace Avalonia.Media
public void Dispose()
{
if (_context._states is null || _context._transformContainers is null)
throw new ObjectDisposedException(nameof(DrawingContext));
if (_type == PushedStateType.None)
return;
if (_context._currentLevel != _level)
@ -343,7 +349,8 @@ namespace Avalonia.Media
/// <returns>A disposable used to undo the clip geometry.</returns>
public PushedState PushGeometryClip(Geometry clip)
{
Contract.Requires<ArgumentNullException>(clip != null);
_ = clip ?? throw new ArgumentNullException(nameof(clip));
PlatformImpl.PushGeometryClip(clip.PlatformImpl);
return new PushedState(this, PushedState.PushedStateType.GeometryClip);
}
@ -407,6 +414,8 @@ namespace Avalonia.Media
/// <returns>A disposable used to undo the transformation.</returns>
public PushedState PushTransformContainer()
{
if (_transformContainers is null)
throw new ObjectDisposedException(nameof(DrawingContext));
_transformContainers.Push(new TransformContainer(CurrentTransform, _currentContainerTransform));
_currentContainerTransform = CurrentTransform * _currentContainerTransform;
_currentTransform = Matrix.Identity;
@ -418,6 +427,8 @@ namespace Avalonia.Media
/// </summary>
public void Dispose()
{
if (_states is null || _transformContainers is null)
throw new ObjectDisposedException(nameof(DrawingContext));
while (_states.Count != 0)
_states.Peek().Dispose();
StateStackPool.Return(_states);
@ -430,7 +441,7 @@ namespace Avalonia.Media
PlatformImpl.Dispose();
}
private static bool PenIsVisible(IPen pen)
private static bool PenIsVisible(IPen? pen)
{
return pen?.Brush != null && pen.Thickness > 0;
}

2
src/Avalonia.Visuals/Media/DrawingImage.cs

@ -26,7 +26,7 @@ namespace Avalonia.Media
AvaloniaProperty.Register<DrawingImage, Drawing>(nameof(Drawing));
/// <inheritdoc/>
public event EventHandler Invalidated;
public event EventHandler? Invalidated;
/// <summary>
/// Gets or sets the drawing content.

6
src/Avalonia.Visuals/Media/EllipseGeometry.cs

@ -1,3 +1,4 @@
using System;
using Avalonia.Platform;
namespace Avalonia.Media
@ -95,9 +96,10 @@ namespace Avalonia.Media
}
/// <inheritdoc/>
protected override IGeometryImpl CreateDefiningGeometry()
protected override IGeometryImpl? CreateDefiningGeometry()
{
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() ??
throw new InvalidOperationException("Unable to locate IPlatformRenderInterface.");
if (Rect != default) return factory.CreateEllipseGeometry(Rect);

6
src/Avalonia.Visuals/Media/ExperimentalAcrylicMaterial.cs

@ -78,7 +78,7 @@ namespace Avalonia.Media
AvaloniaProperty.Register<ExperimentalAcrylicMaterial, Color>(nameof(FallbackColor));
/// <inheritdoc/>
public event EventHandler Invalidated;
public event EventHandler? Invalidated;
/// <summary>
/// Gets or Sets the BackgroundSource <seealso cref="AcrylicBackgroundSource"/>.
@ -299,14 +299,14 @@ namespace Avalonia.Media
var lightness = (max + min) / 2.0;
lightness = 1 - ((1 - lightness) * luminosityOpacity.Value);
lightness = 1 - ((1 - lightness) * (luminosityOpacity ?? 1));
lightness = 0.13 + (lightness * 0.74);
var luminosityColor = new Color(255, Trim(lightness), Trim(lightness), Trim(lightness));
var compensationMultiplier = 1 - PlatformTransparencyCompensationLevel;
return new Color((byte)(255 * Math.Max(Math.Min(PlatformTransparencyCompensationLevel + (luminosityOpacity.Value * compensationMultiplier), 1.0), 0.0)), luminosityColor.R, luminosityColor.G, luminosityColor.B);
return new Color((byte)(255 * Math.Max(Math.Min(PlatformTransparencyCompensationLevel + ((luminosityOpacity ?? 1) * compensationMultiplier), 1.0), 0.0)), luminosityColor.R, luminosityColor.G, luminosityColor.B);
}
/// <summary>

16
src/Avalonia.Visuals/Media/FontFamily.cs

@ -27,7 +27,7 @@ namespace Avalonia.Media
/// <param name="baseUri">Specifies the base uri that is used to resolve font family assets.</param>
/// <param name="name">The name of the <see cref="T:Avalonia.Media.FontFamily" />.</param>
/// <exception cref="T:System.ArgumentException">Base uri must be an absolute uri.</exception>
public FontFamily(Uri baseUri, string name)
public FontFamily(Uri? baseUri, string name)
{
if (string.IsNullOrEmpty(name))
{
@ -77,7 +77,7 @@ namespace Avalonia.Media
/// The family key.
/// </value>
/// <remarks>Key is only used for custom fonts.</remarks>
public FontFamilyKey Key { get; }
public FontFamilyKey? Key { get; }
/// <summary>
/// Returns <c>True</c> if this instance is the system's default.
@ -95,7 +95,7 @@ namespace Avalonia.Media
private struct FontFamilyIdentifier
{
public FontFamilyIdentifier(string name, Uri source)
public FontFamilyIdentifier(string name, Uri? source)
{
Name = name;
Source = source;
@ -103,7 +103,7 @@ namespace Avalonia.Media
public string Name { get; }
public Uri Source { get; }
public Uri? Source { get; }
}
private static FontFamilyIdentifier GetFontFamilyIdentifier(string name)
@ -152,7 +152,7 @@ namespace Avalonia.Media
/// <exception cref="ArgumentException">
/// Specified family is not supported.
/// </exception>
public static FontFamily Parse(string s, Uri baseUri)
public static FontFamily Parse(string s, Uri? baseUri)
{
if (string.IsNullOrEmpty(s))
{
@ -192,12 +192,12 @@ namespace Avalonia.Media
}
}
public static bool operator !=(FontFamily a, FontFamily b)
public static bool operator !=(FontFamily? a, FontFamily? b)
{
return !(a == b);
}
public static bool operator ==(FontFamily a, FontFamily b)
public static bool operator ==(FontFamily? a, FontFamily? b)
{
if (ReferenceEquals(a, b))
{
@ -207,7 +207,7 @@ namespace Avalonia.Media
return !(a is null) && a.Equals(b);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (ReferenceEquals(this, obj))
{

2
src/Avalonia.Visuals/Media/FontManager.cs

@ -87,7 +87,7 @@ namespace Avalonia.Media
/// <returns>
/// The <see cref="GlyphTypeface"/>.
/// </returns>
public GlyphTypeface GetOrAddGlyphTypeface(Typeface typeface)
public GlyphTypeface? GetOrAddGlyphTypeface(Typeface typeface)
{
while (true)
{

6
src/Avalonia.Visuals/Media/Fonts/FamilyNameCollection.cs

@ -122,12 +122,12 @@ namespace Avalonia.Media.Fonts
}
}
public static bool operator !=(FamilyNameCollection a, FamilyNameCollection b)
public static bool operator !=(FamilyNameCollection? a, FamilyNameCollection? b)
{
return !(a == b);
}
public static bool operator ==(FamilyNameCollection a, FamilyNameCollection b)
public static bool operator ==(FamilyNameCollection? a, FamilyNameCollection? b)
{
if (ReferenceEquals(a, b))
{
@ -144,7 +144,7 @@ namespace Avalonia.Media.Fonts
/// <returns>
/// <c>true</c> if the specified <see cref="object" /> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (!(obj is FamilyNameCollection other))
{

10
src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs

@ -12,7 +12,7 @@ namespace Avalonia.Media.Fonts
/// </summary>
/// <param name="source"></param>
/// <param name="baseUri"></param>
public FontFamilyKey(Uri source, Uri baseUri = null)
public FontFamilyKey(Uri source, Uri? baseUri = null)
{
Source = source ?? throw new ArgumentNullException(nameof(source));
@ -27,7 +27,7 @@ namespace Avalonia.Media.Fonts
/// <summary>
/// A base URI to use if <see cref="Source"/> is relative
/// </summary>
public Uri BaseUri { get; }
public Uri? BaseUri { get; }
/// <summary>
/// Returns a hash code for this instance.
@ -55,12 +55,12 @@ namespace Avalonia.Media.Fonts
}
}
public static bool operator !=(FontFamilyKey a, FontFamilyKey b)
public static bool operator !=(FontFamilyKey? a, FontFamilyKey? b)
{
return !(a == b);
}
public static bool operator ==(FontFamilyKey a, FontFamilyKey b)
public static bool operator ==(FontFamilyKey? a, FontFamilyKey? b)
{
if (ReferenceEquals(a, b))
{
@ -77,7 +77,7 @@ namespace Avalonia.Media.Fonts
/// <returns>
/// <c>true</c> if the specified <see cref="object" /> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (!(obj is FontFamilyKey other))
{

6
src/Avalonia.Visuals/Media/Fonts/FontFamilyLoader.cs

@ -32,7 +32,8 @@ namespace Avalonia.Media.Fonts
/// <returns></returns>
private static IEnumerable<Uri> GetFontAssetsBySource(FontFamilyKey fontFamilyKey)
{
var assetLoader = AvaloniaLocator.Current.GetService<IAssetLoader>();
var assetLoader = AvaloniaLocator.Current.GetService<IAssetLoader>() ??
throw new InvalidOperationException("Unable to locate IAssetLoader.");
var availableAssets = assetLoader.GetAssets(fontFamilyKey.Source, fontFamilyKey.BaseUri);
@ -50,7 +51,8 @@ namespace Avalonia.Media.Fonts
/// <returns></returns>
private static IEnumerable<Uri> GetFontAssetsByExpression(FontFamilyKey fontFamilyKey)
{
var assetLoader = AvaloniaLocator.Current.GetService<IAssetLoader>();
var assetLoader = AvaloniaLocator.Current.GetService<IAssetLoader>() ??
throw new InvalidOperationException("Unable to locate IAssetLoader.");
var fileName = GetFileName(fontFamilyKey, out var fileExtension, out var location);

16
src/Avalonia.Visuals/Media/FormattedText.cs

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using Avalonia.Platform;
@ -10,11 +11,11 @@ namespace Avalonia.Media
{
private readonly IPlatformRenderInterface _platform;
private Size _constraint = Size.Infinity;
private IFormattedTextImpl _platformImpl;
private IReadOnlyList<FormattedTextStyleSpan> _spans;
private IFormattedTextImpl? _platformImpl;
private IReadOnlyList<FormattedTextStyleSpan>? _spans;
private Typeface _typeface;
private double _fontSize;
private string _text;
private string? _text;
private TextAlignment _textAlignment;
private TextWrapping _textWrapping;
@ -23,7 +24,8 @@ namespace Avalonia.Media
/// </summary>
public FormattedText()
{
_platform = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
_platform = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() ??
throw new InvalidOperationException("Unable to locate IPlatformRenderInterface.");
}
/// <summary>
@ -98,7 +100,7 @@ namespace Avalonia.Media
/// Gets or sets a collection of spans that describe the formatting of subsections of the
/// text.
/// </summary>
public IReadOnlyList<FormattedTextStyleSpan> Spans
public IReadOnlyList<FormattedTextStyleSpan>? Spans
{
get => _spans;
set => Set(ref _spans, value);
@ -107,7 +109,7 @@ namespace Avalonia.Media
/// <summary>
/// Gets or sets the text.
/// </summary>
public string Text
public string? Text
{
get => _text;
set => Set(ref _text, value);
@ -141,7 +143,7 @@ namespace Avalonia.Media
if (_platformImpl == null)
{
_platformImpl = _platform.CreateFormattedText(
_text,
_text ?? string.Empty,
_typeface,
_fontSize,
_textAlignment,

4
src/Avalonia.Visuals/Media/FormattedTextStyleSpan.cs

@ -14,7 +14,7 @@
public FormattedTextStyleSpan(
int startIndex,
int length,
IBrush foregroundBrush = null)
IBrush? foregroundBrush = null)
{
StartIndex = startIndex;
Length = length;
@ -34,6 +34,6 @@
/// <summary>
/// Gets the span's foreground brush.
/// </summary>
public IBrush ForegroundBrush { get; }
public IBrush? ForegroundBrush { get; }
}
}

24
src/Avalonia.Visuals/Media/Geometry.cs

@ -11,11 +11,11 @@ namespace Avalonia.Media
/// <summary>
/// Defines the <see cref="Transform"/> property.
/// </summary>
public static readonly StyledProperty<Transform> TransformProperty =
AvaloniaProperty.Register<Geometry, Transform>(nameof(Transform));
public static readonly StyledProperty<Transform?> TransformProperty =
AvaloniaProperty.Register<Geometry, Transform?>(nameof(Transform));
private bool _isDirty = true;
private IGeometryImpl _platformImpl;
private IGeometryImpl? _platformImpl;
static Geometry()
{
@ -25,7 +25,7 @@ namespace Avalonia.Media
/// <summary>
/// Raised when the geometry changes.
/// </summary>
public event EventHandler Changed;
public event EventHandler? Changed;
/// <summary>
/// Gets the geometry's bounding rectangle.
@ -35,7 +35,7 @@ namespace Avalonia.Media
/// <summary>
/// Gets the platform-specific implementation of the geometry.
/// </summary>
public IGeometryImpl PlatformImpl
public IGeometryImpl? PlatformImpl
{
get
{
@ -60,7 +60,7 @@ namespace Avalonia.Media
/// <summary>
/// Gets or sets a transform to apply to the geometry.
/// </summary>
public Transform Transform
public Transform? Transform
{
get { return GetValue(TransformProperty); }
set { SetValue(TransformProperty, value); }
@ -127,7 +127,7 @@ namespace Avalonia.Media
/// Creates the platform implementation of the geometry, without the transform applied.
/// </summary>
/// <returns></returns>
protected abstract IGeometryImpl CreateDefiningGeometry();
protected abstract IGeometryImpl? CreateDefiningGeometry();
/// <summary>
/// Invalidates the platform implementation of the geometry.
@ -141,8 +141,8 @@ namespace Avalonia.Media
private void TransformChanged(AvaloniaPropertyChangedEventArgs e)
{
var oldValue = (Transform)e.OldValue;
var newValue = (Transform)e.NewValue;
var oldValue = (Transform?)e.OldValue;
var newValue = (Transform?)e.NewValue;
if (oldValue != null)
{
@ -157,9 +157,9 @@ namespace Avalonia.Media
TransformChanged(newValue, EventArgs.Empty);
}
private void TransformChanged(object sender, EventArgs e)
private void TransformChanged(object? sender, EventArgs e)
{
var transform = ((Transform)sender)?.Value;
var transform = ((Transform?)sender)?.Value;
if (_platformImpl is ITransformedGeometryImpl t)
{
@ -174,7 +174,7 @@ namespace Avalonia.Media
}
else if (_platformImpl != null && transform != null && transform != Matrix.Identity)
{
_platformImpl = PlatformImpl.WithTransform(transform.Value);
_platformImpl = _platformImpl.WithTransform(transform.Value);
}
Changed?.Invoke(this, EventArgs.Empty);

9
src/Avalonia.Visuals/Media/GlyphRun.cs

@ -14,7 +14,7 @@ namespace Avalonia.Media
private static readonly IComparer<ushort> s_ascendingComparer = Comparer<ushort>.Default;
private static readonly IComparer<ushort> s_descendingComparer = new ReverseComparer<ushort>();
private IGlyphRunImpl _glyphRunImpl;
private IGlyphRunImpl? _glyphRunImpl;
private GlyphTypeface _glyphTypeface;
private double _fontRenderingEmSize;
private int _biDiLevel;
@ -199,7 +199,7 @@ namespace Avalonia.Media
Initialize();
}
return _glyphRunImpl;
return _glyphRunImpl!;
}
}
@ -639,7 +639,8 @@ namespace Avalonia.Media
throw new InvalidOperationException();
}
var platformRenderInterface = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var platformRenderInterface = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() ??
throw new InvalidOperationException("Unable to locate IPlatformRenderInterface");
_glyphRunImpl = platformRenderInterface.CreateGlyphRun(this);
}
@ -651,7 +652,7 @@ namespace Avalonia.Media
private class ReverseComparer<T> : IComparer<T>
{
public int Compare(T x, T y)
public int Compare(T? x, T? y)
{
return Comparer<T>.Default.Compare(y, x);
}

12
src/Avalonia.Visuals/Media/GradientBrush.cs

@ -26,7 +26,7 @@ namespace Avalonia.Media
public static readonly StyledProperty<GradientStops> GradientStopsProperty =
AvaloniaProperty.Register<GradientBrush, GradientStops>(nameof(GradientStops));
private IDisposable _gradientStopsSubscription;
private IDisposable? _gradientStopsSubscription;
static GradientBrush()
{
@ -64,13 +64,13 @@ namespace Avalonia.Media
{
if (e.Sender is GradientBrush brush)
{
var oldValue = (GradientStops)e.OldValue;
var newValue = (GradientStops)e.NewValue;
var oldValue = (GradientStops?)e.OldValue;
var newValue = (GradientStops?)e.NewValue;
if (oldValue != null)
{
oldValue.CollectionChanged -= brush.GradientStopsChanged;
brush._gradientStopsSubscription.Dispose();
brush._gradientStopsSubscription?.Dispose();
}
if (newValue != null)
@ -83,12 +83,12 @@ namespace Avalonia.Media
}
}
private void GradientStopsChanged(object sender, NotifyCollectionChangedEventArgs e)
private void GradientStopsChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
RaiseInvalidated(EventArgs.Empty);
}
private void GradientStopChanged(Tuple<object, PropertyChangedEventArgs> e)
private void GradientStopChanged(Tuple<object?, PropertyChangedEventArgs> e)
{
RaiseInvalidated(EventArgs.Empty);
}

4
src/Avalonia.Visuals/Media/IPen.cs

@ -8,12 +8,12 @@
/// <summary>
/// Gets the brush used to draw the stroke.
/// </summary>
IBrush Brush { get; }
IBrush? Brush { get; }
/// <summary>
/// Gets the style of dashed lines drawn with a <see cref="Pen"/> object.
/// </summary>
IDashStyle DashStyle { get; }
IDashStyle? DashStyle { get; }
/// <summary>
/// Gets the type of shape to use on both ends of a line.

29
src/Avalonia.Visuals/Media/Imaging/Bitmap.cs

@ -21,8 +21,7 @@ namespace Avalonia.Media.Imaging
/// <returns>An instance of the <see cref="Bitmap"/> class.</returns>
public static Bitmap DecodeToWidth(Stream stream, int width, BitmapInterpolationMode interpolationMode = BitmapInterpolationMode.HighQuality)
{
IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
return new Bitmap(factory.LoadBitmapToWidth(stream, width, interpolationMode));
return new Bitmap(GetFactory().LoadBitmapToWidth(stream, width, interpolationMode));
}
/// <summary>
@ -35,8 +34,7 @@ namespace Avalonia.Media.Imaging
/// <returns>An instance of the <see cref="Bitmap"/> class.</returns>
public static Bitmap DecodeToHeight(Stream stream, int height, BitmapInterpolationMode interpolationMode = BitmapInterpolationMode.HighQuality)
{
IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
return new Bitmap(factory.LoadBitmapToHeight(stream, height, interpolationMode));
return new Bitmap(GetFactory().LoadBitmapToHeight(stream, height, interpolationMode));
}
/// <summary>
@ -47,8 +45,7 @@ namespace Avalonia.Media.Imaging
/// <returns>An instance of the <see cref="Bitmap"/> class.</returns>
public Bitmap CreateScaledBitmap(PixelSize destinationSize, BitmapInterpolationMode interpolationMode = BitmapInterpolationMode.HighQuality)
{
IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
return new Bitmap(factory.ResizeBitmap(PlatformImpl.Item, destinationSize, interpolationMode));
return new Bitmap(GetFactory().ResizeBitmap(PlatformImpl.Item, destinationSize, interpolationMode));
}
/// <summary>
@ -57,8 +54,7 @@ namespace Avalonia.Media.Imaging
/// <param name="fileName">The filename of the bitmap.</param>
public Bitmap(string fileName)
{
IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
PlatformImpl = RefCountable.Create(factory.LoadBitmap(fileName));
PlatformImpl = RefCountable.Create(GetFactory().LoadBitmap(fileName));
}
/// <summary>
@ -67,8 +63,7 @@ namespace Avalonia.Media.Imaging
/// <param name="stream">The stream to read the bitmap from.</param>
public Bitmap(Stream stream)
{
IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
PlatformImpl = RefCountable.Create(factory.LoadBitmap(stream));
PlatformImpl = RefCountable.Create(GetFactory().LoadBitmap(stream));
}
/// <summary>
@ -106,9 +101,8 @@ namespace Avalonia.Media.Imaging
[Obsolete("Use overload taking an AlphaFormat.")]
public Bitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride)
{
var ri = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
PlatformImpl = RefCountable.Create(AvaloniaLocator.Current.GetService<IPlatformRenderInterface>()
var ri = GetFactory();
PlatformImpl = RefCountable.Create(ri
.LoadBitmap(format, ri.DefaultAlphaFormat, data, size, dpi, stride));
}
@ -123,8 +117,7 @@ namespace Avalonia.Media.Imaging
/// <param name="stride">The number of bytes per row.</param>
public Bitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride)
{
PlatformImpl = RefCountable.Create(AvaloniaLocator.Current.GetService<IPlatformRenderInterface>()
.LoadBitmap(format, alphaFormat, data, size, dpi, stride));
PlatformImpl = RefCountable.Create(GetFactory().LoadBitmap(format, alphaFormat, data, size, dpi, stride));
}
/// <inheritdoc/>
@ -173,5 +166,11 @@ namespace Avalonia.Media.Imaging
destRect,
bitmapInterpolationMode);
}
private static IPlatformRenderInterface GetFactory()
{
return AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() ??
throw new InvalidOperationException("Unable to locate IPlatformRenderInterface.");
}
}
}

16
src/Avalonia.Visuals/Media/Imaging/CroppedBitmap.cs

@ -11,8 +11,8 @@ namespace Avalonia.Media.Imaging
/// <summary>
/// Defines the <see cref="Source"/> property.
/// </summary>
public static readonly StyledProperty<IImage> SourceProperty =
AvaloniaProperty.Register<CroppedBitmap, IImage>(nameof(Source));
public static readonly StyledProperty<IImage?> SourceProperty =
AvaloniaProperty.Register<CroppedBitmap, IImage?>(nameof(Source));
/// <summary>
/// Defines the <see cref="SourceRect"/> property.
@ -20,7 +20,7 @@ namespace Avalonia.Media.Imaging
public static readonly StyledProperty<PixelRect> SourceRectProperty =
AvaloniaProperty.Register<CroppedBitmap, PixelRect>(nameof(SourceRect));
public event EventHandler Invalidated;
public event EventHandler? Invalidated;
static CroppedBitmap()
{
@ -31,7 +31,7 @@ namespace Avalonia.Media.Imaging
/// <summary>
/// Gets or sets the source for the bitmap.
/// </summary>
public IImage Source
public IImage? Source
{
get => GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
@ -77,19 +77,19 @@ namespace Avalonia.Media.Imaging
public Size Size {
get
{
if (Source == null)
if (Source is not IBitmap bmp)
return Size.Empty;
if (SourceRect.IsEmpty)
return Source.Size;
return SourceRect.Size.ToSizeWithDpi((Source as IBitmap).Dpi);
return SourceRect.Size.ToSizeWithDpi(bmp.Dpi);
}
}
public void Draw(DrawingContext context, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
{
if (Source == null)
if (Source is not IBitmap bmp)
return;
var topLeft = SourceRect.TopLeft.ToPointWithDpi((Source as IBitmap).Dpi);
var topLeft = SourceRect.TopLeft.ToPointWithDpi(bmp.Dpi);
Source.Draw(context, sourceRect.Translate(new Vector(topLeft.X, topLeft.Y)), destRect, bitmapInterpolationMode);
}
}

5
src/Avalonia.Visuals/Media/Imaging/RenderTargetBitmap.cs

@ -54,11 +54,12 @@ namespace Avalonia.Media.Imaging
/// <returns>The platform-specific implementation.</returns>
private static IRenderTargetBitmapImpl CreateImpl(PixelSize size, Vector dpi)
{
IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() ??
throw new InvalidOperationException("Unable to locate IPlatformRenderInterface.");
return factory.CreateRenderTargetBitmap(size, dpi);
}
/// <inheritdoc/>
public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer vbr) => PlatformImpl.Item.CreateDrawingContext(vbr);
public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer? vbr) => PlatformImpl.Item.CreateDrawingContext(vbr);
}
}

14
src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs

@ -46,7 +46,7 @@ namespace Avalonia.Media.Imaging
public static WriteableBitmap Decode(Stream stream)
{
var ri = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var ri = GetFactory();
return new WriteableBitmap(ri.LoadWriteableBitmap(stream));
}
@ -61,7 +61,7 @@ namespace Avalonia.Media.Imaging
/// <returns>An instance of the <see cref="WriteableBitmap"/> class.</returns>
public new static WriteableBitmap DecodeToWidth(Stream stream, int width, BitmapInterpolationMode interpolationMode = BitmapInterpolationMode.HighQuality)
{
var ri = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var ri = GetFactory();
return new WriteableBitmap(ri.LoadWriteableBitmapToWidth(stream, width, interpolationMode));
}
@ -76,19 +76,25 @@ namespace Avalonia.Media.Imaging
/// <returns>An instance of the <see cref="WriteableBitmap"/> class.</returns>
public new static WriteableBitmap DecodeToHeight(Stream stream, int height, BitmapInterpolationMode interpolationMode = BitmapInterpolationMode.HighQuality)
{
var ri = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var ri = GetFactory();
return new WriteableBitmap(ri.LoadWriteableBitmapToHeight(stream, height, interpolationMode));
}
private static IBitmapImpl CreatePlatformImpl(PixelSize size, in Vector dpi, PixelFormat? format, AlphaFormat? alphaFormat)
{
var ri = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var ri = GetFactory();
PixelFormat finalFormat = format ?? ri.DefaultPixelFormat;
AlphaFormat finalAlphaFormat = alphaFormat ?? ri.DefaultAlphaFormat;
return ri.CreateWriteableBitmap(size, dpi, finalFormat, finalAlphaFormat);
}
private static IPlatformRenderInterface GetFactory()
{
return AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() ??
throw new InvalidOperationException("Unable to locate IPlatformRenderInterface.");
}
}
}

4
src/Avalonia.Visuals/Media/Immutable/ImmutableDashStyle.cs

@ -30,10 +30,10 @@ namespace Avalonia.Media.Immutable
public double Offset { get; }
/// <inheritdoc/>
public override bool Equals(object obj) => Equals(obj as IDashStyle);
public override bool Equals(object? obj) => Equals(obj as IDashStyle);
/// <inheritdoc/>
public bool Equals(IDashStyle other)
public bool Equals(IDashStyle? other)
{
if (ReferenceEquals(this, other))
{

14
src/Avalonia.Visuals/Media/Immutable/ImmutablePen.cs

@ -21,7 +21,7 @@ namespace Avalonia.Media.Immutable
public ImmutablePen(
uint color,
double thickness = 1.0,
ImmutableDashStyle dashStyle = null,
ImmutableDashStyle? dashStyle = null,
PenLineCap lineCap = PenLineCap.Flat,
PenLineJoin lineJoin = PenLineJoin.Miter,
double miterLimit = 10.0) : this(new ImmutableSolidColorBrush(color), thickness, dashStyle, lineCap, lineJoin, miterLimit)
@ -38,9 +38,9 @@ namespace Avalonia.Media.Immutable
/// <param name="lineJoin">The line join.</param>
/// <param name="miterLimit">The miter limit.</param>
public ImmutablePen(
IBrush brush,
IBrush? brush,
double thickness = 1.0,
ImmutableDashStyle dashStyle = null,
ImmutableDashStyle? dashStyle = null,
PenLineCap lineCap = PenLineCap.Flat,
PenLineJoin lineJoin = PenLineJoin.Miter,
double miterLimit = 10.0)
@ -58,7 +58,7 @@ namespace Avalonia.Media.Immutable
/// <summary>
/// Gets the brush used to draw the stroke.
/// </summary>
public IBrush Brush { get; }
public IBrush? Brush { get; }
/// <summary>
/// Gets the stroke thickness.
@ -68,7 +68,7 @@ namespace Avalonia.Media.Immutable
/// <summary>
/// Specifies the style of dashed lines drawn with a <see cref="Pen"/> object.
/// </summary>
public IDashStyle DashStyle { get; }
public IDashStyle? DashStyle { get; }
/// <summary>
/// Specifies the type of graphic shape to use on both ends of a line.
@ -87,10 +87,10 @@ namespace Avalonia.Media.Immutable
public double MiterLimit { get; }
/// <inheritdoc/>
public override bool Equals(object obj) => Equals(obj as IPen);
public override bool Equals(object? obj) => Equals(obj as IPen);
/// <inheritdoc/>
public bool Equals(IPen other)
public bool Equals(IPen? other)
{
if (ReferenceEquals(this, other))
{

4
src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs

@ -46,14 +46,14 @@ namespace Avalonia.Media.Immutable
/// </summary>
public double Opacity { get; }
public bool Equals(ImmutableSolidColorBrush other)
public bool Equals(ImmutableSolidColorBrush? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Color.Equals(other.Color) && Opacity.Equals(other.Opacity);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is ImmutableSolidColorBrush other && Equals(other);
}

2
src/Avalonia.Visuals/Media/ImmutableExperimentalAcrylicMaterial.cs

@ -34,7 +34,7 @@ namespace Avalonia.Media
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is ImmutableExperimentalAcrylicMaterial other && Equals(other);
}

8
src/Avalonia.Visuals/Media/KnownColors.cs

@ -20,7 +20,7 @@ namespace Avalonia.Media
foreach (var field in typeof(KnownColor).GetRuntimeFields())
{
if (field.FieldType != typeof(KnownColor)) continue;
var knownColor = (KnownColor)field.GetValue(null);
var knownColor = (KnownColor)field.GetValue(null)!;
if (knownColor == KnownColor.None) continue;
knownColorNames.Add(field.Name, knownColor);
@ -41,7 +41,7 @@ namespace Avalonia.Media
}
#if !BUILDTASK
public static ISolidColorBrush GetKnownBrush(string s)
public static ISolidColorBrush? GetKnownBrush(string s)
{
var color = GetKnownColor(s);
return color != KnownColor.None ? color.ToBrush() : null;
@ -58,7 +58,7 @@ namespace Avalonia.Media
return KnownColor.None;
}
public static string GetKnownColorName(uint rgb)
public static string? GetKnownColorName(uint rgb)
{
return _knownColors.TryGetValue(rgb, out var name) ? name : null;
}
@ -230,4 +230,4 @@ namespace Avalonia.Media
Yellow = 0xffffff00,
YellowGreen = 0xff9acd32
}
}
}

6
src/Avalonia.Visuals/Media/LineGeometry.cs

@ -1,3 +1,4 @@
using System;
using Avalonia.Platform;
namespace Avalonia.Media
@ -67,9 +68,10 @@ namespace Avalonia.Media
}
/// <inheritdoc/>
protected override IGeometryImpl CreateDefiningGeometry()
protected override IGeometryImpl? CreateDefiningGeometry()
{
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() ??
throw new InvalidOperationException("Unable to locate IPlatformRenderInterface.");
return factory.CreateLineGeometry(StartPoint, EndPoint);
}

2
src/Avalonia.Visuals/Media/MaterialExtensions.cs

@ -14,7 +14,7 @@ namespace Avalonia.Media
/// </returns>
public static IExperimentalAcrylicMaterial ToImmutable(this IExperimentalAcrylicMaterial material)
{
Contract.Requires<ArgumentNullException>(material != null);
_ = material ?? throw new ArgumentNullException(nameof(material));
return (material as IMutableExperimentalAcrylicMaterial)?.ToImmutable() ?? material;
}

35
src/Avalonia.Visuals/Media/PathGeometry.cs

@ -11,8 +11,8 @@ namespace Avalonia.Media
/// <summary>
/// Defines the <see cref="Figures"/> property.
/// </summary>
public static readonly DirectProperty<PathGeometry, PathFigures> FiguresProperty =
AvaloniaProperty.RegisterDirect<PathGeometry, PathFigures>(nameof(Figures), g => g.Figures, (g, f) => g.Figures = f);
public static readonly DirectProperty<PathGeometry, PathFigures?> FiguresProperty =
AvaloniaProperty.RegisterDirect<PathGeometry, PathFigures?>(nameof(Figures), g => g.Figures, (g, f) => g.Figures = f);
/// <summary>
/// Defines the <see cref="FillRule"/> property.
@ -20,9 +20,9 @@ namespace Avalonia.Media
public static readonly StyledProperty<FillRule> FillRuleProperty =
AvaloniaProperty.Register<PathGeometry, FillRule>(nameof(FillRule));
private PathFigures _figures;
private IDisposable _figuresObserver;
private IDisposable _figuresPropertiesObserver;
private PathFigures? _figures;
private IDisposable? _figuresObserver;
private IDisposable? _figuresPropertiesObserver;
static PathGeometry()
{
@ -35,7 +35,7 @@ namespace Avalonia.Media
/// </summary>
public PathGeometry()
{
Figures = new PathFigures();
_figures = new PathFigures();
}
/// <summary>
@ -63,7 +63,7 @@ namespace Avalonia.Media
/// The figures.
/// </value>
[Content]
public PathFigures Figures
public PathFigures? Figures
{
get { return _figures; }
set { SetAndRaise(FiguresProperty, ref _figures, value); }
@ -81,15 +81,21 @@ namespace Avalonia.Media
set { SetValue(FillRuleProperty, value); }
}
protected override IGeometryImpl CreateDefiningGeometry()
protected override IGeometryImpl? CreateDefiningGeometry()
{
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var figures = Figures;
if (figures is null)
return null;
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() ??
throw new InvalidOperationException("Unable to locate IPlatformRenderInterface.");
var geometry = factory.CreateStreamGeometry();
using (var ctx = new StreamGeometryContext(geometry.Open()))
{
ctx.SetFillRule(FillRule);
foreach (var f in Figures)
foreach (var f in figures)
{
f.ApplyTo(ctx);
}
@ -98,7 +104,7 @@ namespace Avalonia.Media
return geometry;
}
private void OnFiguresChanged(PathFigures figures)
private void OnFiguresChanged(PathFigures? figures)
{
_figuresObserver?.Dispose();
_figuresPropertiesObserver?.Dispose();
@ -120,12 +126,15 @@ namespace Avalonia.Media
}
private void InvalidateGeometryFromSegments(object _, EventArgs __)
private void InvalidateGeometryFromSegments(object? _, EventArgs __)
{
InvalidateGeometry();
}
public override string ToString()
=> $"{(FillRule != FillRule.EvenOdd ? "F1 " : "")}{(string.Join(" ", Figures))}";
{
var figuresString = _figures is not null ? string.Join(" ", _figures) : string.Empty;
return $"{(FillRule != FillRule.EvenOdd ? "F1 " : "")}{figuresString}";
}
}
}

4
src/Avalonia.Visuals/Media/PathGeometryCollections.cs

@ -20,11 +20,11 @@ namespace Avalonia.Media
parser.Parse(pathData);
}
return pathGeometry.Figures;
return pathGeometry.Figures!;
}
}
public sealed class PathSegments : AvaloniaList<PathSegment>
{
}
}
}

34
src/Avalonia.Visuals/Media/PathMarkupParser.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using Avalonia.Platform;
@ -27,7 +28,7 @@ namespace Avalonia.Media
{ 'Z', Command.Close },
};
private IGeometryContext _geometryContext;
private IGeometryContext? _geometryContext;
private Point _currentPoint;
private Point? _beginFigurePoint;
private Point? _previousControlPoint;
@ -98,6 +99,8 @@ namespace Avalonia.Media
/// <param name="pathData">The path data.</param>
public void Parse(string pathData)
{
ThrowIfDisposed();
var span = pathData.AsSpan();
_currentPoint = new Point();
@ -171,6 +174,8 @@ namespace Avalonia.Media
private void CreateFigure()
{
ThrowIfDisposed();
if (_isOpen)
{
_geometryContext.EndFigure(false);
@ -185,6 +190,8 @@ namespace Avalonia.Media
private void SetFillRule(ref ReadOnlySpan<char> span)
{
ThrowIfDisposed();
if (!ReadArgument(ref span, out var fillRule) || fillRule.Length != 1)
{
throw new InvalidDataException("Invalid fill rule.");
@ -209,6 +216,8 @@ namespace Avalonia.Media
private void CloseFigure()
{
ThrowIfDisposed();
if (_isOpen)
{
_geometryContext.EndFigure(true);
@ -244,6 +253,8 @@ namespace Avalonia.Media
private void AddLine(ref ReadOnlySpan<char> span, bool relative)
{
ThrowIfDisposed();
_currentPoint = relative
? ReadRelativePoint(ref span, _currentPoint)
: ReadPoint(ref span);
@ -258,6 +269,8 @@ namespace Avalonia.Media
private void AddHorizontalLine(ref ReadOnlySpan<char> span, bool relative)
{
ThrowIfDisposed();
_currentPoint = relative
? new Point(_currentPoint.X + ReadDouble(ref span), _currentPoint.Y)
: _currentPoint.WithX(ReadDouble(ref span));
@ -272,6 +285,8 @@ namespace Avalonia.Media
private void AddVerticalLine(ref ReadOnlySpan<char> span, bool relative)
{
ThrowIfDisposed();
_currentPoint = relative
? new Point(_currentPoint.X, _currentPoint.Y + ReadDouble(ref span))
: _currentPoint.WithY(ReadDouble(ref span));
@ -286,6 +301,8 @@ namespace Avalonia.Media
private void AddCubicBezierCurve(ref ReadOnlySpan<char> span, bool relative)
{
ThrowIfDisposed();
var point1 = relative
? ReadRelativePoint(ref span, _currentPoint)
: ReadPoint(ref span);
@ -316,6 +333,8 @@ namespace Avalonia.Media
private void AddQuadraticBezierCurve(ref ReadOnlySpan<char> span, bool relative)
{
ThrowIfDisposed();
var start = relative
? ReadRelativePoint(ref span, _currentPoint)
: ReadPoint(ref span);
@ -340,6 +359,8 @@ namespace Avalonia.Media
private void AddSmoothCubicBezierCurve(ref ReadOnlySpan<char> span, bool relative)
{
ThrowIfDisposed();
var point2 = relative
? ReadRelativePoint(ref span, _currentPoint)
: ReadPoint(ref span);
@ -369,6 +390,8 @@ namespace Avalonia.Media
private void AddSmoothQuadraticBezierCurve(ref ReadOnlySpan<char> span, bool relative)
{
ThrowIfDisposed();
var end = relative
? ReadRelativePoint(ref span, _currentPoint)
: ReadPoint(ref span);
@ -390,6 +413,8 @@ namespace Avalonia.Media
private void AddArc(ref ReadOnlySpan<char> span, bool relative)
{
ThrowIfDisposed();
var size = ReadSize(ref span);
span = ReadSeparator(span);
@ -570,5 +595,12 @@ namespace Avalonia.Media
span = span.Slice(1);
return true;
}
[MemberNotNull(nameof(_geometryContext))]
private void ThrowIfDisposed()
{
if (_isDisposed || _geometryContext is null)
throw new ObjectDisposedException(nameof(PathMarkupParser));
}
}
}

22
src/Avalonia.Visuals/Media/Pen.cs

@ -12,8 +12,8 @@ namespace Avalonia.Media
/// <summary>
/// Defines the <see cref="Brush"/> property.
/// </summary>
public static readonly StyledProperty<IBrush> BrushProperty =
AvaloniaProperty.Register<Pen, IBrush>(nameof(Brush));
public static readonly StyledProperty<IBrush?> BrushProperty =
AvaloniaProperty.Register<Pen, IBrush?>(nameof(Brush));
/// <summary>
/// Defines the <see cref="Thickness"/> property.
@ -24,8 +24,8 @@ namespace Avalonia.Media
/// <summary>
/// Defines the <see cref="DashStyle"/> property.
/// </summary>
public static readonly StyledProperty<IDashStyle> DashStyleProperty =
AvaloniaProperty.Register<Pen, IDashStyle>(nameof(DashStyle));
public static readonly StyledProperty<IDashStyle?> DashStyleProperty =
AvaloniaProperty.Register<Pen, IDashStyle?>(nameof(DashStyle));
/// <summary>
/// Defines the <see cref="LineCap"/> property.
@ -64,7 +64,7 @@ namespace Avalonia.Media
public Pen(
uint color,
double thickness = 1.0,
IDashStyle dashStyle = null,
IDashStyle? dashStyle = null,
PenLineCap lineCap = PenLineCap.Flat,
PenLineJoin lineJoin = PenLineJoin.Miter,
double miterLimit = 10.0) : this(new SolidColorBrush(color), thickness, dashStyle, lineCap, lineJoin, miterLimit)
@ -81,9 +81,9 @@ namespace Avalonia.Media
/// <param name="lineJoin">The line join.</param>
/// <param name="miterLimit">The miter limit.</param>
public Pen(
IBrush brush,
IBrush? brush,
double thickness = 1.0,
IDashStyle dashStyle = null,
IDashStyle? dashStyle = null,
PenLineCap lineCap = PenLineCap.Flat,
PenLineJoin lineJoin = PenLineJoin.Miter,
double miterLimit = 10.0)
@ -110,7 +110,7 @@ namespace Avalonia.Media
/// <summary>
/// Gets or sets the brush used to draw the stroke.
/// </summary>
public IBrush Brush
public IBrush? Brush
{
get => GetValue(BrushProperty);
set => SetValue(BrushProperty, value);
@ -128,7 +128,7 @@ namespace Avalonia.Media
/// <summary>
/// Gets or sets the style of dashed lines drawn with a <see cref="Pen"/> object.
/// </summary>
public IDashStyle DashStyle
public IDashStyle? DashStyle
{
get => GetValue(DashStyleProperty);
set => SetValue(DashStyleProperty, value);
@ -165,7 +165,7 @@ namespace Avalonia.Media
/// <summary>
/// Raised when the pen changes.
/// </summary>
public event EventHandler Invalidated;
public event EventHandler? Invalidated;
/// <summary>
/// Creates an immutable clone of the brush.
@ -244,6 +244,6 @@ namespace Avalonia.Media
/// <param name="e">The event args.</param>
protected void RaiseInvalidated(EventArgs e) => Invalidated?.Invoke(this, e);
private void AffectsRenderInvalidated(object sender, EventArgs e) => RaiseInvalidated(EventArgs.Empty);
private void AffectsRenderInvalidated(object? sender, EventArgs e) => RaiseInvalidated(EventArgs.Empty);
}
}

2
src/Avalonia.Visuals/Media/PixelPoint.cs

@ -144,7 +144,7 @@ namespace Avalonia
/// <returns>
/// True if <paramref name="obj"/> is a point that equals the current point.
/// </returns>
public override bool Equals(object obj) => obj is PixelPoint other && Equals(other);
public override bool Equals(object? obj) => obj is PixelPoint other && Equals(other);
/// <summary>
/// Returns a hash code for a <see cref="PixelPoint"/>.

2
src/Avalonia.Visuals/Media/PixelRect.cs

@ -208,7 +208,7 @@ namespace Avalonia
/// </summary>
/// <param name="obj">The object to compare against.</param>
/// <returns>True if the object is equal to this rectangle; false otherwise.</returns>
public override bool Equals(object obj) => obj is PixelRect other && Equals(other);
public override bool Equals(object? obj) => obj is PixelRect other && Equals(other);
/// <summary>
/// Returns the hash code for this instance.

2
src/Avalonia.Visuals/Media/PixelSize.cs

@ -94,7 +94,7 @@ namespace Avalonia
/// <returns>
/// True if <paramref name="obj"/> is a size that equals the current size.
/// </returns>
public override bool Equals(object obj) => obj is PixelSize other && Equals(other);
public override bool Equals(object? obj) => obj is PixelSize other && Equals(other);
/// <summary>
/// Returns a hash code for a <see cref="PixelSize"/>.

2
src/Avalonia.Visuals/Media/PixelVector.cs

@ -143,7 +143,7 @@ namespace Avalonia
return Math.Abs(_x - other._x) < tolerance && Math.Abs(_y - other._y) < tolerance;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;

11
src/Avalonia.Visuals/Media/PolylineGeometry.cs

@ -24,7 +24,7 @@ namespace Avalonia.Media
AvaloniaProperty.Register<PolylineGeometry, bool>(nameof(IsFilled));
private Points _points;
private IDisposable _pointsObserver;
private IDisposable? _pointsObserver;
static PolylineGeometry()
{
@ -37,7 +37,7 @@ namespace Avalonia.Media
/// </summary>
public PolylineGeometry()
{
Points = new Points();
_points = new Points();
}
/// <summary>
@ -74,9 +74,10 @@ namespace Avalonia.Media
return new PolylineGeometry(Points, IsFilled);
}
protected override IGeometryImpl CreateDefiningGeometry()
protected override IGeometryImpl? CreateDefiningGeometry()
{
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() ??
throw new InvalidOperationException("Unable to locate IPlatformRenderInterface.");
var geometry = factory.CreateStreamGeometry();
using (var context = geometry.Open())
@ -97,7 +98,7 @@ namespace Avalonia.Media
return geometry;
}
private void OnPointsChanged(Points newValue)
private void OnPointsChanged(Points? newValue)
{
_pointsObserver?.Dispose();
_pointsObserver = newValue?.ForEachItem(

6
src/Avalonia.Visuals/Media/RectangleGeometry.cs

@ -1,3 +1,4 @@
using System;
using Avalonia.Platform;
namespace Avalonia.Media
@ -46,9 +47,10 @@ namespace Avalonia.Media
/// <inheritdoc/>
public override Geometry Clone() => new RectangleGeometry(Rect);
protected override IGeometryImpl CreateDefiningGeometry()
protected override IGeometryImpl? CreateDefiningGeometry()
{
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() ??
throw new InvalidOperationException("Unable to locate IPlatformRenderInterface.");
return factory.CreateRectangleGeometry(Rect);
}

12
src/Avalonia.Visuals/Media/StreamGeometry.cs

@ -1,3 +1,4 @@
using System;
using Avalonia.Platform;
namespace Avalonia.Media
@ -7,7 +8,7 @@ namespace Avalonia.Media
/// </summary>
public class StreamGeometry : Geometry
{
IStreamGeometryImpl _impl;
IStreamGeometryImpl? _impl;
/// <summary>
/// Initializes a new instance of the <see cref="StreamGeometry"/> class.
@ -46,7 +47,7 @@ namespace Avalonia.Media
/// <inheritdoc/>
public override Geometry Clone()
{
return new StreamGeometry(((IStreamGeometryImpl)PlatformImpl).Clone());
return new StreamGeometry(((IStreamGeometryImpl)PlatformImpl!).Clone());
}
/// <summary>
@ -57,15 +58,16 @@ namespace Avalonia.Media
/// </returns>
public StreamGeometryContext Open()
{
return new StreamGeometryContext(((IStreamGeometryImpl)PlatformImpl).Open());
return new StreamGeometryContext(((IStreamGeometryImpl)PlatformImpl!).Open());
}
/// <inheritdoc/>
protected override IGeometryImpl CreateDefiningGeometry()
protected override IGeometryImpl? CreateDefiningGeometry()
{
if (_impl == null)
{
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() ??
throw new InvalidOperationException("Unable to locate IPlatformRenderInterface.");
_impl = factory.CreateStreamGeometry();
}

14
src/Avalonia.Visuals/Media/TextFormatting/GenericTextRunProperties.cs

@ -10,9 +10,9 @@ namespace Avalonia.Media.TextFormatting
private const double DefaultFontRenderingEmSize = 12;
public GenericTextRunProperties(Typeface typeface, double fontRenderingEmSize = DefaultFontRenderingEmSize,
TextDecorationCollection textDecorations = null, IBrush foregroundBrush = null,
IBrush backgroundBrush = null, BaselineAlignment baselineAlignment = BaselineAlignment.Baseline,
CultureInfo cultureInfo = null)
TextDecorationCollection? textDecorations = null, IBrush? foregroundBrush = null,
IBrush? backgroundBrush = null, BaselineAlignment baselineAlignment = BaselineAlignment.Baseline,
CultureInfo? cultureInfo = null)
{
Typeface = typeface;
FontRenderingEmSize = fontRenderingEmSize;
@ -30,18 +30,18 @@ namespace Avalonia.Media.TextFormatting
public override double FontRenderingEmSize { get; }
/// <inheritdoc />
public override TextDecorationCollection TextDecorations { get; }
public override TextDecorationCollection? TextDecorations { get; }
/// <inheritdoc />
public override IBrush ForegroundBrush { get; }
public override IBrush? ForegroundBrush { get; }
/// <inheritdoc />
public override IBrush BackgroundBrush { get; }
public override IBrush? BackgroundBrush { get; }
/// <inheritdoc />
public override BaselineAlignment BaselineAlignment { get; }
/// <inheritdoc />
public override CultureInfo CultureInfo { get; }
public override CultureInfo? CultureInfo { get; }
}
}

2
src/Avalonia.Visuals/Media/TextFormatting/ITextSource.cs

@ -10,6 +10,6 @@
/// </summary>
/// <param name="textSourceIndex">The text source index.</param>
/// <returns>The text run.</returns>
TextRun GetTextRun(int textSourceIndex);
TextRun? GetTextRun(int textSourceIndex);
}
}

4
src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs

@ -166,7 +166,7 @@ namespace Avalonia.Media.TextFormatting
public readonly struct SplitTextCharactersResult
{
public SplitTextCharactersResult(ShapedTextCharacters first, ShapedTextCharacters second)
public SplitTextCharactersResult(ShapedTextCharacters first, ShapedTextCharacters? second)
{
First = first;
@ -187,7 +187,7 @@ namespace Avalonia.Media.TextFormatting
/// <value>
/// The second text run.
/// </value>
public ShapedTextCharacters Second { get; }
public ShapedTextCharacters? Second { get; }
}
}
}

2
src/Avalonia.Visuals/Media/TextFormatting/TextFormatter.cs

@ -41,6 +41,6 @@ namespace Avalonia.Media.TextFormatting
/// in terms of where the previous line in the paragraph was broken by the text formatting process.</param>
/// <returns>The formatted line.</returns>
public abstract TextLine FormatLine(ITextSource textSource, int firstTextSourceIndex, double paragraphWidth,
TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak = null);
TextParagraphProperties paragraphProperties, TextLineBreak? previousLineBreak = null);
}
}

18
src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs

@ -8,7 +8,7 @@ namespace Avalonia.Media.TextFormatting
{
/// <inheritdoc cref="TextFormatter.FormatLine"/>
public override TextLine FormatLine(ITextSource textSource, int firstTextSourceIndex, double paragraphWidth,
TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak = null)
TextParagraphProperties paragraphProperties, TextLineBreak? previousLineBreak = null)
{
var textWrapping = paragraphProperties.TextWrapping;
@ -241,7 +241,7 @@ namespace Avalonia.Media.TextFormatting
first.Add(split.First);
second.Add(split.Second);
second.Add(split.Second!);
if (secondCount > 0)
{
@ -269,7 +269,7 @@ namespace Avalonia.Media.TextFormatting
/// The formatted text runs.
/// </returns>
private static List<ShapedTextCharacters> FetchTextRuns(ITextSource textSource,
int firstTextSourceIndex, TextLineBreak previousLineBreak, out TextLineBreak nextLineBreak)
int firstTextSourceIndex, TextLineBreak? previousLineBreak, out TextLineBreak? nextLineBreak)
{
nextLineBreak = default;
@ -298,11 +298,11 @@ namespace Avalonia.Media.TextFormatting
{
for (; index < previousLineBreak.RemainingCharacters.Count; index++)
{
splitResult.Second.Add(previousLineBreak.RemainingCharacters[index]);
splitResult.Second!.Add(previousLineBreak.RemainingCharacters[index]);
}
}
nextLineBreak = new TextLineBreak(splitResult.Second);
nextLineBreak = new TextLineBreak(splitResult.Second!);
return splitResult.First;
}
@ -346,7 +346,7 @@ namespace Avalonia.Media.TextFormatting
{
var splitResult = SplitTextRuns(textRuns, currentLength + runLineBreak.PositionWrap);
nextLineBreak = new TextLineBreak(splitResult.Second);
nextLineBreak = new TextLineBreak(splitResult.Second!);
return splitResult.First;
}
@ -553,7 +553,7 @@ namespace Avalonia.Media.TextFormatting
internal readonly struct SplitTextRunsResult
{
public SplitTextRunsResult(List<ShapedTextCharacters> first, List<ShapedTextCharacters> second)
public SplitTextRunsResult(List<ShapedTextCharacters> first, List<ShapedTextCharacters>? second)
{
First = first;
@ -574,7 +574,7 @@ namespace Avalonia.Media.TextFormatting
/// <value>
/// The second text runs.
/// </value>
public List<ShapedTextCharacters> Second { get; }
public List<ShapedTextCharacters>? Second { get; }
}
private struct TextRunEnumerator
@ -586,7 +586,7 @@ namespace Avalonia.Media.TextFormatting
{
_textSource = textSource;
_pos = firstTextSourceIndex;
Current = null;
Current = null!;
}
// ReSharper disable once MemberHidesStaticFromOuterClass

22
src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Avalonia.Utilities;
@ -14,7 +15,7 @@ namespace Avalonia.Media.TextFormatting
private readonly ReadOnlySlice<char> _text;
private readonly TextParagraphProperties _paragraphProperties;
private readonly IReadOnlyList<ValueSpan<TextRunProperties>> _textStyleOverrides;
private readonly IReadOnlyList<ValueSpan<TextRunProperties>>? _textStyleOverrides;
private readonly TextTrimming _textTrimming;
/// <summary>
@ -41,12 +42,12 @@ namespace Avalonia.Media.TextFormatting
TextAlignment textAlignment = TextAlignment.Left,
TextWrapping textWrapping = TextWrapping.NoWrap,
TextTrimming textTrimming = TextTrimming.None,
TextDecorationCollection textDecorations = null,
TextDecorationCollection? textDecorations = null,
double maxWidth = double.PositiveInfinity,
double maxHeight = double.PositiveInfinity,
double lineHeight = double.NaN,
int maxLines = 0,
IReadOnlyList<ValueSpan<TextRunProperties>> textStyleOverrides = null)
IReadOnlyList<ValueSpan<TextRunProperties>>? textStyleOverrides = null)
{
_text = string.IsNullOrEmpty(text) ?
new ReadOnlySlice<char>() :
@ -228,7 +229,7 @@ namespace Avalonia.Media.TextFormatting
var currentY = 0d;
var lineIndex = 0;
TextLine currentLine = null;
TextLine? currentLine = null;
CharacterHit characterHit;
for (; lineIndex < TextLines.Count; lineIndex++)
@ -289,7 +290,7 @@ namespace Avalonia.Media.TextFormatting
/// <returns></returns>
private static TextParagraphProperties CreateTextParagraphProperties(Typeface typeface, double fontSize,
IBrush foreground, TextAlignment textAlignment, TextWrapping textWrapping,
TextDecorationCollection textDecorations, double lineHeight)
TextDecorationCollection? textDecorations, double lineHeight)
{
var textRunStyle = new GenericTextRunProperties(typeface, fontSize, textDecorations, foreground);
@ -339,6 +340,7 @@ namespace Avalonia.Media.TextFormatting
/// <summary>
/// Updates the layout and applies specified text style overrides.
/// </summary>
[MemberNotNull(nameof(TextLines))]
private void UpdateLayout()
{
if (_text.IsEmpty || MathUtilities.IsZero(MaxWidth) || MathUtilities.IsZero(MaxHeight))
@ -360,7 +362,7 @@ namespace Avalonia.Media.TextFormatting
var textSource = new FormattedTextSource(_text,
_paragraphProperties.DefaultTextRunProperties, _textStyleOverrides);
TextLine previousLine = null;
TextLine? previousLine = null;
while (currentPosition < _text.Length)
{
@ -558,17 +560,17 @@ namespace Avalonia.Media.TextFormatting
{
private readonly ReadOnlySlice<char> _text;
private readonly TextRunProperties _defaultProperties;
private readonly IReadOnlyList<ValueSpan<TextRunProperties>> _textModifier;
private readonly IReadOnlyList<ValueSpan<TextRunProperties>>? _textModifier;
public FormattedTextSource(ReadOnlySlice<char> text, TextRunProperties defaultProperties,
IReadOnlyList<ValueSpan<TextRunProperties>> textModifier)
IReadOnlyList<ValueSpan<TextRunProperties>>? textModifier)
{
_text = text;
_defaultProperties = defaultProperties;
_textModifier = textModifier;
}
public TextRun GetTextRun(int textSourceIndex)
public TextRun? GetTextRun(int textSourceIndex)
{
if (textSourceIndex > _text.Length)
{
@ -597,7 +599,7 @@ namespace Avalonia.Media.TextFormatting
/// The created text style run.
/// </returns>
private static ValueSpan<TextRunProperties> CreateTextStyleRun(ReadOnlySlice<char> text,
TextRunProperties defaultProperties, IReadOnlyList<ValueSpan<TextRunProperties>> textModifier)
TextRunProperties defaultProperties, IReadOnlyList<ValueSpan<TextRunProperties>>? textModifier)
{
if (textModifier == null || textModifier.Count == 0)
{

2
src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs

@ -29,7 +29,7 @@ namespace Avalonia.Media.TextFormatting
/// <returns>
/// A <see cref="TextLineBreak"/> value that represents the line break.
/// </returns>
public abstract TextLineBreak TextLineBreak { get; }
public abstract TextLineBreak? TextLineBreak { get; }
/// <summary>
/// Gets the distance from the top to the baseline of the current TextLine object.

4
src/Avalonia.Visuals/Media/TextFormatting/TextLineBreak.cs

@ -17,11 +17,11 @@ namespace Avalonia.Media.TextFormatting
/// <summary>
/// Get the
/// </summary>
public TextEndOfLine TextEndOfLine { get; }
public TextEndOfLine? TextEndOfLine { get; }
/// <summary>
/// Get the remaining shaped characters that were split up by the <see cref="TextFormatter"/> during the formatting process.
/// </summary>
public IReadOnlyList<ShapedTextCharacters> RemainingCharacters { get; }
public IReadOnlyList<ShapedTextCharacters>? RemainingCharacters { get; }
}
}

4
src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs

@ -13,7 +13,7 @@ namespace Avalonia.Media.TextFormatting
private readonly TextLineMetrics _textLineMetrics;
public TextLineImpl(List<ShapedTextCharacters> textRuns, TextRange textRange, double paragraphWidth,
TextParagraphProperties paragraphProperties, TextLineBreak lineBreak = null, bool hasCollapsed = false)
TextParagraphProperties paragraphProperties, TextLineBreak? lineBreak = null, bool hasCollapsed = false)
{
TextRange = textRange;
TextLineBreak = lineBreak;
@ -33,7 +33,7 @@ namespace Avalonia.Media.TextFormatting
public override TextRange TextRange { get; }
/// <inheritdoc/>
public override TextLineBreak TextLineBreak { get; }
public override TextLineBreak? TextLineBreak { get; }
/// <inheritdoc/>
public override bool HasCollapsed { get; }

2
src/Avalonia.Visuals/Media/TextFormatting/TextParagraphProperties.cs

@ -44,7 +44,7 @@
/// If not null, text decorations to apply to all runs in the line. This is in addition
/// to any text decorations specified by the TextRunProperties for individual text runs.
/// </summary>
public virtual TextDecorationCollection TextDecorations => null;
public virtual TextDecorationCollection? TextDecorations => null;
/// <summary>
/// Gets the text wrapping.

4
src/Avalonia.Visuals/Media/TextFormatting/TextRun.cs

@ -24,7 +24,7 @@ namespace Avalonia.Media.TextFormatting
/// <summary>
/// A set of properties shared by every characters in the run
/// </summary>
public virtual TextRunProperties Properties => null;
public virtual TextRunProperties? Properties => null;
private class TextRunDebuggerProxy
{
@ -49,7 +49,7 @@ namespace Avalonia.Media.TextFormatting
}
}
public TextRunProperties Properties => _textRun.Properties;
public TextRunProperties? Properties => _textRun.Properties;
}
}
}

12
src/Avalonia.Visuals/Media/TextFormatting/TextRunProperties.cs

@ -25,29 +25,29 @@ namespace Avalonia.Media.TextFormatting
///<summary>
/// Run TextDecorations.
///</summary>
public abstract TextDecorationCollection TextDecorations { get; }
public abstract TextDecorationCollection? TextDecorations { get; }
/// <summary>
/// Brush used to fill text.
/// </summary>
public abstract IBrush ForegroundBrush { get; }
public abstract IBrush? ForegroundBrush { get; }
/// <summary>
/// Brush used to paint background of run.
/// </summary>
public abstract IBrush BackgroundBrush { get; }
public abstract IBrush? BackgroundBrush { get; }
/// <summary>
/// Run text culture.
/// </summary>
public abstract CultureInfo CultureInfo { get; }
public abstract CultureInfo? CultureInfo { get; }
/// <summary>
/// Run vertical box alignment
/// </summary>
public abstract BaselineAlignment BaselineAlignment { get; }
public bool Equals(TextRunProperties other)
public bool Equals(TextRunProperties? other)
{
if (ReferenceEquals(null, other))
return false;
@ -62,7 +62,7 @@ namespace Avalonia.Media.TextFormatting
Equals(CultureInfo, other.CultureInfo);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return ReferenceEquals(this, obj) || obj is TextRunProperties other && Equals(other);
}

2
src/Avalonia.Visuals/Media/TextFormatting/TextShaper.cs

@ -46,7 +46,7 @@ namespace Avalonia.Media.TextFormatting
/// <inheritdoc cref="ITextShaperImpl.ShapeText"/>
public GlyphRun ShapeText(ReadOnlySlice<char> text, Typeface typeface, double fontRenderingEmSize,
CultureInfo culture)
CultureInfo? culture)
{
return _platformImpl.ShapeText(text, typeface, fontRenderingEmSize, culture);
}

4
src/Avalonia.Visuals/Media/TextFormatting/Unicode/UnicodeData.cs

@ -24,8 +24,8 @@
static UnicodeData()
{
s_unicodeDataTrie = new UnicodeTrie(typeof(UnicodeData).Assembly.GetManifestResourceStream("Avalonia.Assets.UnicodeData.trie"));
s_graphemeBreakTrie = new UnicodeTrie(typeof(UnicodeData).Assembly.GetManifestResourceStream("Avalonia.Assets.GraphemeBreak.trie"));
s_unicodeDataTrie = new UnicodeTrie(typeof(UnicodeData).Assembly.GetManifestResourceStream("Avalonia.Assets.UnicodeData.trie")!);
s_graphemeBreakTrie = new UnicodeTrie(typeof(UnicodeData).Assembly.GetManifestResourceStream("Avalonia.Assets.GraphemeBreak.trie")!);
}
/// <summary>

2
src/Avalonia.Visuals/Media/Transform.cs

@ -19,7 +19,7 @@ namespace Avalonia.Media
/// <summary>
/// Raised when the transform changes.
/// </summary>
public event EventHandler Changed;
public event EventHandler? Changed;
/// <summary>
/// Gets the transform's <see cref="Matrix"/>.

6
src/Avalonia.Visuals/Media/TransformConverter.cs

@ -10,14 +10,14 @@ namespace Avalonia.Media
/// </summary>
public class TransformConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object? value)
{
return TransformOperations.Parse((string)value);
return value is string s ? TransformOperations.Parse(s) : null;
}
}
}

2
src/Avalonia.Visuals/Media/TransformGroup.cs

@ -24,7 +24,7 @@ namespace Avalonia.Media
};
}
private void ChildTransform_Changed(object sender, System.EventArgs e)
private void ChildTransform_Changed(object? sender, System.EventArgs e)
{
this.RaiseChanged();
}

4
src/Avalonia.Visuals/Media/Transformation/TransformOperation.cs

@ -92,8 +92,8 @@ namespace Avalonia.Media.Transformation
}
// ReSharper disable PossibleInvalidOperationException
TransformOperation fromValue = fromIdentity ? Identity : from.Value;
TransformOperation toValue = toIdentity ? Identity : to.Value;
TransformOperation fromValue = fromIdentity ? Identity : from!.Value;
TransformOperation toValue = toIdentity ? Identity : to!.Value;
// ReSharper restore PossibleInvalidOperationException
var interpolationType = toIdentity ? fromValue.Type : toValue.Type;

6
src/Avalonia.Visuals/Media/Typeface.cs

@ -48,7 +48,7 @@ namespace Avalonia.Media
/// <summary>
/// Gets the font family.
/// </summary>
public FontFamily FontFamily { get; }
public FontFamily? FontFamily { get; }
/// <summary>
/// Gets the font style.
@ -66,7 +66,7 @@ namespace Avalonia.Media
/// <value>
/// The glyph typeface.
/// </value>
public GlyphTypeface GlyphTypeface => FontManager.Current.GetOrAddGlyphTypeface(this);
public GlyphTypeface? GlyphTypeface => FontManager.Current.GetOrAddGlyphTypeface(this);
public static bool operator !=(Typeface a, Typeface b)
{
@ -78,7 +78,7 @@ namespace Avalonia.Media
return a.Equals(b);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is Typeface typeface && Equals(typeface);
}

2
src/Avalonia.Visuals/Media/UnicodeRange.cs

@ -12,7 +12,7 @@ namespace Avalonia.Media
public static UnicodeRange Default = Parse("0-10FFFD");
private readonly UnicodeRangeSegment _single;
private readonly IReadOnlyList<UnicodeRangeSegment> _segments = null;
private readonly IReadOnlyList<UnicodeRangeSegment>? _segments = null;
public UnicodeRange(int start, int end)
{

6
src/Avalonia.Visuals/Platform/ExportRenderingSubsystemAttribute.cs

@ -6,7 +6,7 @@ namespace Avalonia.Platform
public class ExportRenderingSubsystemAttribute : Attribute
{
public ExportRenderingSubsystemAttribute(OperatingSystemType requiredOS, int priority, string name, Type initializationType, string initializationMethod,
Type environmentChecker = null)
Type? environmentChecker = null)
{
Name = name;
InitializationType = initializationType;
@ -17,11 +17,11 @@ namespace Avalonia.Platform
}
public string InitializationMethod { get; private set; }
public Type EnvironmentChecker { get; }
public Type? EnvironmentChecker { get; }
public Type InitializationType { get; private set; }
public string Name { get; private set; }
public int Priority { get; private set; }
public OperatingSystemType RequiredOS { get; private set; }
public string RequiresWindowingSubsystem { get; set; }
public string? RequiresWindowingSubsystem { get; set; }
}
}

4
src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs

@ -55,7 +55,7 @@ namespace Avalonia.Platform
/// <param name="brush">The fill brush.</param>
/// <param name="pen">The stroke pen.</param>
/// <param name="geometry">The geometry.</param>
void DrawGeometry(IBrush brush, IPen pen, IGeometryImpl geometry);
void DrawGeometry(IBrush? brush, IPen? pen, IGeometryImpl geometry);
/// <summary>
/// Draws a rectangle with the specified Brush and Pen.
@ -68,7 +68,7 @@ namespace Avalonia.Platform
/// The brush and the pen can both be null. If the brush is null, then no fill is performed.
/// If the pen is null, then no stoke is performed. If both the pen and the brush are null, then the drawing is not visible.
/// </remarks>
void DrawRectangle(IBrush brush, IPen pen, RoundedRect rect,
void DrawRectangle(IBrush? brush, IPen? pen, RoundedRect rect,
BoxShadows boxShadows = default);
/// <summary>

2
src/Avalonia.Visuals/Platform/IFontManagerImpl.cs

@ -31,7 +31,7 @@ namespace Avalonia.Platform
/// </returns>
bool TryMatchCharacter(int codepoint, FontStyle fontStyle,
FontWeight fontWeight,
FontFamily fontFamily, CultureInfo culture, out Typeface typeface);
FontFamily? fontFamily, CultureInfo? culture, out Typeface typeface);
/// <summary>
/// Creates a glyph typeface.

2
src/Avalonia.Visuals/Platform/IGeometryImpl.cs

@ -23,7 +23,7 @@ namespace Avalonia.Platform
/// </summary>
/// <param name="pen">The pen to use. May be null.</param>
/// <returns>The bounding rectangle.</returns>
Rect GetRenderBounds(IPen pen);
Rect GetRenderBounds(IPen? pen);
/// <summary>
/// Indicates whether the geometry's fill contains the specified point.

2
src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs

@ -29,7 +29,7 @@ namespace Avalonia.Platform
TextAlignment textAlignment,
TextWrapping wrapping,
Size constraint,
IReadOnlyList<FormattedTextStyleSpan> spans);
IReadOnlyList<FormattedTextStyleSpan>? spans);
/// <summary>
/// Creates an ellipse geometry implementation.

2
src/Avalonia.Visuals/Platform/IRenderTarget.cs

@ -18,7 +18,7 @@ namespace Avalonia.Platform
/// A render to be used to render visual brushes. May be null if no visual brushes are
/// to be drawn.
/// </param>
IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer);
IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer? visualBrushRenderer);
}
public interface IRenderTargetWithCorruptionInfo : IRenderTarget

2
src/Avalonia.Visuals/Platform/ITextShaperImpl.cs

@ -17,6 +17,6 @@ namespace Avalonia.Platform
/// <param name="fontRenderingEmSize">The font rendering em size.</param>
/// <param name="culture">The culture.</param>
/// <returns>A shaped glyph run.</returns>
GlyphRun ShapeText(ReadOnlySlice<char> text, Typeface typeface, double fontRenderingEmSize, CultureInfo culture);
GlyphRun ShapeText(ReadOnlySlice<char> text, Typeface typeface, double fontRenderingEmSize, CultureInfo? culture);
}
}

35
src/Avalonia.Visuals/Platform/PathGeometryContext.cs

@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Media;
using Avalonia.Platform;
@ -6,8 +7,8 @@ namespace Avalonia.Visuals.Platform
{
public class PathGeometryContext : IGeometryContext
{
private PathFigure _currentFigure;
private PathGeometry _pathGeometry;
private PathFigure? _currentFigure;
private PathGeometry? _pathGeometry;
public PathGeometryContext(PathGeometry pathGeometry)
{
@ -30,13 +31,16 @@ namespace Avalonia.Visuals.Platform
Point = point
};
_currentFigure.Segments.Add(arcSegment);
CurrentFigureSegments().Add(arcSegment);
}
public void BeginFigure(Point startPoint, bool isFilled)
{
ThrowIfDisposed();
_currentFigure = new PathFigure { StartPoint = startPoint, IsClosed = false, IsFilled = isFilled };
_pathGeometry.Figures ??= new();
_pathGeometry.Figures.Add(_currentFigure);
}
@ -44,14 +48,14 @@ namespace Avalonia.Visuals.Platform
{
var bezierSegment = new BezierSegment { Point1 = point1, Point2 = point2, Point3 = point3 };
_currentFigure.Segments.Add(bezierSegment);
CurrentFigureSegments().Add(bezierSegment);
}
public void QuadraticBezierTo(Point control, Point endPoint)
{
var quadraticBezierSegment = new QuadraticBezierSegment { Point1 = control, Point2 = endPoint };
_currentFigure.Segments.Add(quadraticBezierSegment);
CurrentFigureSegments().Add(quadraticBezierSegment);
}
public void LineTo(Point point)
@ -61,7 +65,7 @@ namespace Avalonia.Visuals.Platform
Point = point
};
_currentFigure.Segments.Add(lineSegment);
CurrentFigureSegments().Add(lineSegment);
}
public void EndFigure(bool isClosed)
@ -76,7 +80,26 @@ namespace Avalonia.Visuals.Platform
public void SetFillRule(FillRule fillRule)
{
ThrowIfDisposed();
_pathGeometry.FillRule = fillRule;
}
[MemberNotNull(nameof(_pathGeometry))]
private void ThrowIfDisposed()
{
if (_pathGeometry is null)
throw new ObjectDisposedException(nameof(PathGeometryContext));
}
private PathSegments CurrentFigureSegments()
{
ThrowIfDisposed();
if (_currentFigure is null)
throw new InvalidOperationException("No figure in progress.");
if (_currentFigure.Segments is null)
throw new InvalidOperationException("Current figure's segments cannot be null.");
return _currentFigure.Segments;
}
}
}

2
src/Avalonia.Visuals/Point.cs

@ -211,7 +211,7 @@ namespace Avalonia
/// <returns>
/// True if <paramref name="obj"/> is a point that equals the current point.
/// </returns>
public override bool Equals(object obj) => obj is Point other && Equals(other);
public override bool Equals(object? obj) => obj is Point other && Equals(other);
/// <summary>
/// Returns a hash code for a <see cref="Point"/>.

2
src/Avalonia.Visuals/Rect.cs

@ -341,7 +341,7 @@ namespace Avalonia
/// </summary>
/// <param name="obj">The object to compare against.</param>
/// <returns>True if the object is equal to this rectangle; false otherwise.</returns>
public override bool Equals(object obj) => obj is Rect other && Equals(other);
public override bool Equals(object? obj) => obj is Rect other && Equals(other);
/// <summary>
/// Returns the hash code for this instance.

2
src/Avalonia.Visuals/RelativePoint.cs

@ -111,7 +111,7 @@ namespace Avalonia
/// </summary>
/// <param name="obj">The other object.</param>
/// <returns>True if the objects are equal, otherwise false.</returns>
public override bool Equals(object obj) => obj is RelativePoint other && Equals(other);
public override bool Equals(object? obj) => obj is RelativePoint other && Equals(other);
/// <summary>
/// Checks if the <see cref="RelativePoint"/> equals another point.

2
src/Avalonia.Visuals/RelativeRect.cs

@ -113,7 +113,7 @@ namespace Avalonia
/// </summary>
/// <param name="obj">The other object.</param>
/// <returns>True if the objects are equal, otherwise false.</returns>
public override bool Equals(object obj) => obj is RelativeRect other && Equals(other);
public override bool Equals(object? obj) => obj is RelativeRect other && Equals(other);
/// <summary>
/// Checks if the <see cref="RelativeRect"/> equals another rectangle.

16
src/Avalonia.Visuals/Rendering/DefaultRenderTimer.cs

@ -14,10 +14,10 @@ namespace Avalonia.Rendering
/// </remarks>
public class DefaultRenderTimer : IRenderTimer
{
private IRuntimePlatform _runtime;
private IRuntimePlatform? _runtime;
private int _subscriberCount;
private Action<TimeSpan> _tick;
private IDisposable _subscription;
private Action<TimeSpan>? _tick;
private IDisposable? _subscription;
/// <summary>
/// Initializes a new instance of the <see cref="DefaultRenderTimer"/> class.
@ -77,10 +77,8 @@ namespace Avalonia.Rendering
/// </remarks>
protected virtual IDisposable StartCore(Action<TimeSpan> tick)
{
if (_runtime == null)
{
_runtime = AvaloniaLocator.Current.GetService<IRuntimePlatform>();
}
_runtime ??= AvaloniaLocator.Current.GetService<IRuntimePlatform>() ??
throw new InvalidOperationException("Unable to locate IRuntimePlatform.");
return _runtime.StartSystemTimer(
TimeSpan.FromSeconds(1.0 / FramesPerSecond),
@ -92,13 +90,13 @@ namespace Avalonia.Rendering
/// </summary>
protected void Stop()
{
_subscription.Dispose();
_subscription?.Dispose();
_subscription = null;
}
private void InternalTick(TimeSpan tickCount)
{
_tick(tickCount);
_tick?.Invoke(tickCount);
}
}
}

72
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using Avalonia.Logging;
@ -19,20 +20,20 @@ namespace Avalonia.Rendering
/// </summary>
public class DeferredRenderer : RendererBase, IRenderer, IRenderLoopTask, IVisualBrushRenderer
{
private readonly IDispatcher _dispatcher;
private readonly IRenderLoop _renderLoop;
private readonly IDispatcher? _dispatcher;
private readonly IRenderLoop? _renderLoop;
private readonly IVisual _root;
private readonly ISceneBuilder _sceneBuilder;
private bool _running;
private bool _disposed;
private volatile IRef<Scene> _scene;
private DirtyVisuals _dirty;
private HashSet<IVisual> _recalculateChildren;
private IRef<IRenderTargetBitmapImpl> _overlay;
private volatile IRef<Scene>? _scene;
private DirtyVisuals? _dirty;
private HashSet<IVisual>? _recalculateChildren;
private IRef<IRenderTargetBitmapImpl>? _overlay;
private int _lastSceneId = -1;
private DisplayDirtyRects _dirtyRectsDisplay = new DisplayDirtyRects();
private IRef<IDrawOperation> _currentDraw;
private IRef<IDrawOperation>? _currentDraw;
private readonly IDeferredRendererLock _lock;
private readonly object _sceneLock = new object();
private readonly object _startStopLock = new object();
@ -50,14 +51,12 @@ namespace Avalonia.Rendering
public DeferredRenderer(
IRenderRoot root,
IRenderLoop renderLoop,
ISceneBuilder sceneBuilder = null,
IDispatcher dispatcher = null,
IDeferredRendererLock rendererLock = null) : base(true)
ISceneBuilder? sceneBuilder = null,
IDispatcher? dispatcher = null,
IDeferredRendererLock? rendererLock = null) : base(true)
{
Contract.Requires<ArgumentNullException>(root != null);
_dispatcher = dispatcher ?? Dispatcher.UIThread;
_root = root;
_root = root ?? throw new ArgumentNullException(nameof(root));
_sceneBuilder = sceneBuilder ?? new SceneBuilder();
Layers = new RenderLayers();
_renderLoop = renderLoop;
@ -77,13 +76,10 @@ namespace Avalonia.Rendering
public DeferredRenderer(
IVisual root,
IRenderTarget renderTarget,
ISceneBuilder sceneBuilder = null) : base(true)
ISceneBuilder? sceneBuilder = null) : base(true)
{
Contract.Requires<ArgumentNullException>(root != null);
Contract.Requires<ArgumentNullException>(renderTarget != null);
_root = root;
RenderTarget = renderTarget;
_root = root ?? throw new ArgumentNullException(nameof(root));
RenderTarget = renderTarget ?? throw new ArgumentNullException(nameof(renderTarget));
_sceneBuilder = sceneBuilder ?? new SceneBuilder();
Layers = new RenderLayers();
_lock = new ManagedDeferredRendererLock();
@ -99,7 +95,7 @@ namespace Avalonia.Rendering
/// <summary>
/// Gets or sets a path to which rendered frame should be rendered for debugging.
/// </summary>
public string DebugFramesPath { get; set; }
public string? DebugFramesPath { get; set; }
/// <summary>
/// Forces the renderer to only draw frames on the render thread. Makes Paint to wait until frame is rendered
@ -107,7 +103,7 @@ namespace Avalonia.Rendering
public bool RenderOnlyOnRenderThread { get; set; }
/// <inheritdoc/>
public event EventHandler<SceneInvalidatedEventArgs> SceneInvalidated;
public event EventHandler<SceneInvalidatedEventArgs>? SceneInvalidated;
/// <summary>
/// Gets the render layers.
@ -117,7 +113,7 @@ namespace Avalonia.Rendering
/// <summary>
/// Gets the current render target.
/// </summary>
internal IRenderTarget RenderTarget { get; private set; }
internal IRenderTarget? RenderTarget { get; private set; }
/// <inheritdoc/>
public void AddDirty(IVisual visual)
@ -167,7 +163,7 @@ namespace Avalonia.Rendering
}
/// <inheritdoc/>
public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool> filter)
public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool>? filter)
{
EnsureCanHitTest();
@ -177,7 +173,7 @@ namespace Avalonia.Rendering
}
/// <inheritdoc/>
public IVisual HitTestFirst(Point p, IVisual root, Func<IVisual, bool> filter)
public IVisual? HitTestFirst(Point p, IVisual root, Func<IVisual, bool>? filter)
{
EnsureCanHitTest();
@ -199,7 +195,7 @@ namespace Avalonia.Rendering
while (true)
{
Scene scene;
Scene? scene;
bool? updated;
lock (_sceneLock)
{
@ -297,7 +293,7 @@ namespace Avalonia.Rendering
internal void UnitTestRender() => Render(false);
internal Scene UnitTestScene() => _scene.Item;
internal Scene? UnitTestScene() => _scene?.Item;
private void EnsureCanHitTest()
{
@ -315,7 +311,7 @@ namespace Avalonia.Rendering
if (l == null)
return;
IDrawingContextImpl context = null;
IDrawingContextImpl? context = null;
try
{
try
@ -358,10 +354,10 @@ namespace Avalonia.Rendering
}
}
private (IRef<Scene> scene, bool updated) UpdateRenderLayersAndConsumeSceneIfNeeded(ref IDrawingContextImpl context,
private (IRef<Scene>? scene, bool updated) UpdateRenderLayersAndConsumeSceneIfNeeded(ref IDrawingContextImpl? context,
bool recursiveCall = false)
{
IRef<Scene> sceneRef;
IRef<Scene>? sceneRef;
lock (_sceneLock)
sceneRef = _scene?.Clone();
if (sceneRef == null)
@ -416,7 +412,7 @@ namespace Avalonia.Rendering
}
private void Render(IDrawingContextImpl context, VisualNode node, IVisual layer, Rect clipBounds)
private void Render(IDrawingContextImpl context, VisualNode node, IVisual? layer, Rect clipBounds)
{
if (layer == null || node.LayerRoot == layer)
{
@ -459,7 +455,7 @@ namespace Avalonia.Rendering
if (layer.Dirty.IsEmpty && !renderLayer.IsEmpty)
continue;
var renderTarget = renderLayer.Bitmap;
var node = (VisualNode)scene.FindNode(layer.LayerRoot);
var node = (VisualNode?)scene.FindNode(layer.LayerRoot);
if (node != null)
{
@ -515,7 +511,7 @@ namespace Avalonia.Rendering
Math.Ceiling(rect.Bottom * scale) / scale));
}
private void RenderOverlay(Scene scene, ref IDrawingContextImpl parentContent)
private void RenderOverlay(Scene scene, ref IDrawingContextImpl? parentContent)
{
EnsureDrawingContext(ref parentContent);
@ -545,7 +541,7 @@ namespace Avalonia.Rendering
}
}
private void RenderComposite(Scene scene, ref IDrawingContextImpl context)
private void RenderComposite(Scene scene, ref IDrawingContextImpl? context)
{
EnsureDrawingContext(ref context);
@ -596,7 +592,7 @@ namespace Avalonia.Rendering
}
}
private void EnsureDrawingContext(ref IDrawingContextImpl context)
private void EnsureDrawingContext([NotNull] ref IDrawingContextImpl? context)
{
if (context != null)
{
@ -605,7 +601,7 @@ namespace Avalonia.Rendering
if ((RenderTarget as IRenderTargetWithCorruptionInfo)?.IsCorrupted == true)
{
RenderTarget.Dispose();
RenderTarget!.Dispose();
RenderTarget = null;
}
@ -647,10 +643,10 @@ namespace Avalonia.Rendering
}
else
{
foreach (var visual in _recalculateChildren)
foreach (var visual in _recalculateChildren!)
{
var node = scene.FindNode(visual);
((VisualNode)node)?.SortChildren(scene);
((VisualNode?)node)?.SortChildren(scene);
}
_recalculateChildren.Clear();
@ -724,7 +720,7 @@ namespace Avalonia.Rendering
foreach (var layer in Layers)
{
var fileName = Path.Combine(DebugFramesPath, $"frame-{id}-layer-{index++}.png");
var fileName = Path.Combine(DebugFramesPath ?? string.Empty, $"frame-{id}-layer-{index++}.png");
layer.Bitmap.Item.Save(fileName);
}
}

5
src/Avalonia.Visuals/Rendering/DirtyVisuals.cs

@ -31,6 +31,11 @@ namespace Avalonia.Rendering
/// <param name="visual">The dirty visual.</param>
public void Add(IVisual visual)
{
if (visual.VisualRoot is null)
{
return;
}
if (_deferring > 0)
{
_deferredChanges.Add(visual);

2
src/Avalonia.Visuals/Rendering/IDeferredRendererLock.cs

@ -4,6 +4,6 @@ namespace Avalonia.Rendering
{
public interface IDeferredRendererLock
{
IDisposable TryLock();
IDisposable? TryLock();
}
}

4
src/Avalonia.Visuals/Rendering/IRenderer.cs

@ -27,7 +27,7 @@ namespace Avalonia.Rendering
/// Indicates that the underlying low-level scene information has been updated. Used to
/// signal that an update to the current pointer-over state may be required.
/// </remarks>
event EventHandler<SceneInvalidatedEventArgs> SceneInvalidated;
event EventHandler<SceneInvalidatedEventArgs>? SceneInvalidated;
/// <summary>
/// Mark a visual as dirty and needing re-rendering.
@ -57,7 +57,7 @@ namespace Avalonia.Rendering
/// children will be excluded from the results.
/// </param>
/// <returns>The visual at the specified point, topmost first.</returns>
IVisual HitTestFirst(Point p, IVisual root, Func<IVisual, bool> filter);
IVisual? HitTestFirst(Point p, IVisual root, Func<IVisual, bool> filter);
/// <summary>
/// Informs the renderer that the z-ordering of a visual's children has changed.

16
src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs

@ -19,9 +19,9 @@ namespace Avalonia.Rendering
public class ImmediateRenderer : RendererBase, IRenderer, IVisualBrushRenderer
{
private readonly IVisual _root;
private readonly IRenderRoot _renderRoot;
private readonly IRenderRoot? _renderRoot;
private bool _updateTransformedBounds = true;
private IRenderTarget _renderTarget;
private IRenderTarget? _renderTarget;
/// <summary>
/// Initializes a new instance of the <see cref="ImmediateRenderer"/> class.
@ -29,9 +29,7 @@ namespace Avalonia.Rendering
/// <param name="root">The control to render.</param>
public ImmediateRenderer(IVisual root)
{
Contract.Requires<ArgumentNullException>(root != null);
_root = root;
_root = root ?? throw new ArgumentNullException(nameof(root));
_renderRoot = root as IRenderRoot;
}
@ -49,7 +47,7 @@ namespace Avalonia.Rendering
public bool DrawDirtyRects { get; set; }
/// <inheritdoc/>
public event EventHandler<SceneInvalidatedEventArgs> SceneInvalidated;
public event EventHandler<SceneInvalidatedEventArgs>? SceneInvalidated;
/// <inheritdoc/>
public void Paint(Rect rect)
@ -169,7 +167,7 @@ namespace Avalonia.Rendering
return HitTest(root, p, filter);
}
public IVisual HitTestFirst(Point p, IVisual root, Func<IVisual, bool> filter)
public IVisual? HitTestFirst(Point p, IVisual root, Func<IVisual, bool> filter)
{
return HitTest(root, p, filter).FirstOrDefault();
}
@ -233,9 +231,9 @@ namespace Avalonia.Rendering
private static IEnumerable<IVisual> HitTest(
IVisual visual,
Point p,
Func<IVisual, bool> filter)
Func<IVisual, bool>? filter)
{
Contract.Requires<ArgumentNullException>(visual != null);
_ = visual ?? throw new ArgumentNullException(nameof(visual));
if (filter?.Invoke(visual) != false)
{

6
src/Avalonia.Visuals/Rendering/RenderLayers.cs

@ -1,5 +1,6 @@
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Platform;
using Avalonia.Rendering.SceneGraph;
using Avalonia.VisualTree;
@ -19,9 +20,8 @@ namespace Avalonia.Rendering
for (var i = scene.Layers.Count - 1; i >= 0; --i)
{
var src = scene.Layers[i];
RenderLayer layer;
if (!_index.TryGetValue(src.LayerRoot, out layer))
if (!_index.TryGetValue(src.LayerRoot, out var layer))
{
layer = new RenderLayer(context, scene.Size, scene.Scaling, src.LayerRoot);
_inner.Add(layer);
@ -59,7 +59,7 @@ namespace Avalonia.Rendering
_inner.Clear();
}
public bool TryGetValue(IVisual layerRoot, out RenderLayer value)
public bool TryGetValue(IVisual layerRoot, [NotNullWhen(true)] out RenderLayer? value)
{
return _index.TryGetValue(layerRoot, out value);
}

14
src/Avalonia.Visuals/Rendering/RenderLoop.cs

@ -19,7 +19,7 @@ namespace Avalonia.Rendering
private readonly IDispatcher _dispatcher;
private List<IRenderLoopTask> _items = new List<IRenderLoopTask>();
private List<IRenderLoopTask> _itemsCopy = new List<IRenderLoopTask>();
private IRenderTimer _timer;
private IRenderTimer? _timer;
private int _inTick;
private int _inUpdate;
@ -49,19 +49,15 @@ namespace Avalonia.Rendering
{
get
{
if (_timer == null)
{
_timer = AvaloniaLocator.Current.GetService<IRenderTimer>();
}
return _timer;
return _timer ??= AvaloniaLocator.Current.GetService<IRenderTimer>() ??
throw new InvalidOperationException("Cannot locate IRenderTimer.");
}
}
/// <inheritdoc/>
public void Add(IRenderLoopTask i)
{
Contract.Requires<ArgumentNullException>(i != null);
_ = i ?? throw new ArgumentNullException(nameof(i));
Dispatcher.UIThread.VerifyAccess();
lock (_items)
@ -78,7 +74,7 @@ namespace Avalonia.Rendering
/// <inheritdoc/>
public void Remove(IRenderLoopTask i)
{
Contract.Requires<ArgumentNullException>(i != null);
_ = i ?? throw new ArgumentNullException(nameof(i));
Dispatcher.UIThread.VerifyAccess();
lock (_items)
{

2
src/Avalonia.Visuals/Rendering/SceneGraph/BrushDrawOperation.cs

@ -17,6 +17,6 @@ namespace Avalonia.Rendering.SceneGraph
/// <summary>
/// Gets a collection of child scenes that are needed to draw visual brushes.
/// </summary>
public abstract IDictionary<IVisual, Scene> ChildScenes { get; }
public abstract IDictionary<IVisual, Scene>? ChildScenes { get; }
}
}

48
src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs

@ -14,7 +14,7 @@ namespace Avalonia.Rendering.SceneGraph
internal class DeferredDrawingContextImpl : IDrawingContextImpl, IDrawingContextWithAcrylicLikeSupport
{
private readonly ISceneBuilder _sceneBuilder;
private VisualNode _node;
private VisualNode? _node;
private int _childIndex;
private int _drawOperationindex;
@ -48,22 +48,19 @@ namespace Avalonia.Rendering.SceneGraph
/// </returns>
public UpdateState BeginUpdate(VisualNode node)
{
Contract.Requires<ArgumentNullException>(node != null);
_ = _node ?? throw new ArgumentNullException(nameof(node));
if (_node != null)
if (_childIndex < _node.Children.Count)
{
if (_childIndex < _node.Children.Count)
{
_node.ReplaceChild(_childIndex, node);
}
else
{
_node.AddChild(node);
}
++_childIndex;
_node.ReplaceChild(_childIndex, node);
}
else
{
_node.AddChild(node);
}
++_childIndex;
var state = new UpdateState(this, _node, _childIndex, _drawOperationindex);
_node = node;
_childIndex = _drawOperationindex = 0;
@ -93,11 +90,11 @@ namespace Avalonia.Rendering.SceneGraph
/// </remarks>
public void TrimChildren()
{
_node.TrimChildren(_childIndex);
_node!.TrimChildren(_childIndex);
}
/// <inheritdoc/>
public void DrawGeometry(IBrush brush, IPen pen, IGeometryImpl geometry)
public void DrawGeometry(IBrush? brush, IPen? pen, IGeometryImpl geometry)
{
var next = NextDrawAs<GeometryNode>();
@ -149,7 +146,7 @@ namespace Avalonia.Rendering.SceneGraph
}
/// <inheritdoc/>
public void DrawRectangle(IBrush brush, IPen pen, RoundedRect rect,
public void DrawRectangle(IBrush? brush, IPen? pen, RoundedRect rect,
BoxShadows boxShadows = default)
{
var next = NextDrawAs<RectangleNode>();
@ -259,7 +256,7 @@ namespace Avalonia.Rendering.SceneGraph
if (next == null || !next.Item.Equals(null))
{
Add((new GeometryClipNode()));
Add(new GeometryClipNode());
}
else
{
@ -343,8 +340,11 @@ namespace Avalonia.Rendering.SceneGraph
}
/// <inheritdoc/>
public void PushGeometryClip(IGeometryImpl clip)
public void PushGeometryClip(IGeometryImpl? clip)
{
if (clip is null)
return;
var next = NextDrawAs<GeometryClipNode>();
if (next == null || !next.Item.Equals(Transform, clip))
@ -418,9 +418,9 @@ namespace Avalonia.Rendering.SceneGraph
public void Dispose()
{
Owner._node.TrimDrawOperations(Owner._drawOperationindex);
Owner._node!.TrimDrawOperations(Owner._drawOperationindex);
var dirty = Owner.Layers.GetOrAdd(Owner._node.LayerRoot).Dirty;
var dirty = Owner.Layers.GetOrAdd(Owner._node.LayerRoot!).Dirty;
var drawOperations = Owner._node.DrawOperations;
var drawOperationsCount = drawOperations.Count;
@ -451,7 +451,7 @@ namespace Avalonia.Rendering.SceneGraph
private void Add(IRef<IDrawOperation> node)
{
if (_drawOperationindex < _node.DrawOperations.Count)
if (_drawOperationindex < _node!.DrawOperations.Count)
{
_node.ReplaceDrawOperation(_drawOperationindex, node);
}
@ -463,12 +463,12 @@ namespace Avalonia.Rendering.SceneGraph
++_drawOperationindex;
}
private IRef<T> NextDrawAs<T>() where T : class, IDrawOperation
private IRef<T>? NextDrawAs<T>() where T : class, IDrawOperation
{
return _drawOperationindex < _node.DrawOperations.Count ? _node.DrawOperations[_drawOperationindex] as IRef<T> : null;
return _drawOperationindex < _node!.DrawOperations.Count ? _node.DrawOperations[_drawOperationindex] as IRef<T> : null;
}
private IDictionary<IVisual, Scene> CreateChildScene(IBrush brush)
private IDictionary<IVisual, Scene>? CreateChildScene(IBrush? brush)
{
var visualBrush = brush as VisualBrush;

2
src/Avalonia.Visuals/Rendering/SceneGraph/ExperimentalAcrylicNode.cs

@ -23,7 +23,7 @@ namespace Avalonia.Rendering.SceneGraph
: base(rect.Rect, transform)
{
Transform = transform;
Material = material?.ToImmutable();
Material = material.ToImmutable();
Rect = rect;
}

2
src/Avalonia.Visuals/Rendering/SceneGraph/GeometryClipNode.cs

@ -33,7 +33,7 @@ namespace Avalonia.Rendering.SceneGraph
/// <summary>
/// Gets the clip to be pushed or null if the operation represents a pop.
/// </summary>
public IGeometryImpl Clip { get; }
public IGeometryImpl? Clip { get; }
/// <summary>
/// Gets the transform with which the node will be drawn.

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save