Browse Source

Warning cleanup 2 (#13696)

pull/13708/head
Julien Lebosquain 2 years ago
committed by GitHub
parent
commit
3fa13d3b64
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      build/XUnit.props
  2. 2
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  3. 45
      samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs
  4. 2
      samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
  5. 7
      samples/Generators.Sandbox/Controls/CustomTextBox.cs
  6. 50
      samples/GpuInterop/D3DDemo/D3D11DemoControl.cs
  7. 9
      samples/GpuInterop/DrawingSurfaceDemoBase.cs
  8. 12
      samples/GpuInterop/GpuDemo.axaml.cs
  9. 4
      samples/GpuInterop/VulkanDemo/VulkanCommandBufferPool.cs
  10. 14
      samples/GpuInterop/VulkanDemo/VulkanContent.cs
  11. 38
      samples/GpuInterop/VulkanDemo/VulkanContext.cs
  12. 30
      samples/GpuInterop/VulkanDemo/VulkanImage.cs
  13. 2
      samples/GpuInterop/VulkanDemo/VulkanSwapchain.cs
  14. 37
      samples/IntegrationTestApp/MainWindow.axaml.cs
  15. 12
      src/Android/Avalonia.Android/AvaloniaMainActivity.App.cs
  16. 15
      src/Android/Avalonia.Android/AvaloniaMainActivity.cs
  17. 2
      src/Android/Avalonia.Android/AvaloniaView.cs
  18. 37
      src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs
  19. 8
      src/Android/Avalonia.Android/Platform/AndroidSystemNavigationManager.cs
  20. 22
      src/Android/Avalonia.Android/Platform/ClipboardImpl.cs
  21. 4
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  22. 8
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs
  23. 45
      src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs
  24. 4
      src/Avalonia.Base/Platform/Interop/Utf8Buffer.cs
  25. 2
      src/Tizen/Avalonia.Tizen/Avalonia.Tizen.csproj
  26. 43
      src/Tizen/Avalonia.Tizen/NuiAvaloniaView.cs
  27. 2
      src/Tizen/Avalonia.Tizen/NuiAvaloniaViewTextEditable.cs
  28. 4
      src/Tizen/Avalonia.Tizen/NuiGlPlatform.cs
  29. 13
      src/Tizen/Avalonia.Tizen/NuiTizenApplication.cs
  30. 34
      src/Tizen/Avalonia.Tizen/Platform/Permissions.cs
  31. 2
      src/Tizen/Avalonia.Tizen/Stubs.cs
  32. 22
      src/Tizen/Avalonia.Tizen/TizenPlatform.cs
  33. 10
      src/Tizen/Avalonia.Tizen/TizenThreadingInterface.cs
  34. 2
      src/Tizen/Avalonia.Tizen/TopLevelImpl.cs
  35. 70
      src/iOS/Avalonia.iOS/AvaloniaView.cs
  36. 2
      src/iOS/Avalonia.iOS/Storage/IOSSecurityScopedStream.cs
  37. 15
      src/iOS/Avalonia.iOS/Storage/IOSStorageItem.cs
  38. 13
      src/iOS/Avalonia.iOS/TextInputResponder.cs
  39. 11
      tests/Avalonia.Base.UnitTests/DispatcherTests.cs
  40. 13
      tests/Avalonia.Base.UnitTests/Media/EffectTests.cs
  41. 6
      tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs
  42. 53
      tests/Avalonia.Controls.UnitTests/Automation/ControlAutomationPeerTests.cs
  43. 2
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs
  44. 3
      tests/Avalonia.Controls.UnitTests/Primitives/ToggleButtonTests.cs
  45. 12
      tests/Avalonia.Markup.Xaml.UnitTests/Converters/AvaloniaPropertyConverterTest.cs
  46. 224
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
  47. 19
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/ResourceIncludeTests.cs
  48. 14
      tests/Avalonia.RenderTests/Media/BitmapTests.cs
  49. 2
      tests/Avalonia.RenderTests/Media/TileBrushTests.cs
  50. 4
      tests/Avalonia.RenderTests/TestBase.cs
  51. 89
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs
  52. 78
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs

2
build/XUnit.props

@ -6,7 +6,7 @@
<PackageReference Include="xunit.extensibility.core" Version="2.4.2" />
<PackageReference Include="xunit.extensibility.execution" Version="2.4.2" />
<PackageReference Include="xunit.runner.console" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" Condition="'$(TargetFramework)' != 'netstandard2.0'" />
<PackageReference Include="Xunit.SkippableFact" Version="1.4.13" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
</ItemGroup>

2
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@ -160,7 +160,7 @@ namespace ControlCatalog.Pages
}
else
{
SetFolder(await GetStorageProvider().TryGetFolderFromPathAsync(result));
SetFolder(await GetStorageProvider().TryGetFolderFromPathAsync(result!));
results.ItemsSource = new[] { result };
resultsVisible.IsVisible = true;
}

45
samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs

@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
@ -14,26 +15,54 @@ namespace ControlCatalog.Pages
private const string CustomFormat = "application/xxx-avalonia-controlcatalog-custom";
public DragAndDropPage()
{
this.InitializeComponent();
InitializeComponent();
_dropState = this.Get<TextBlock>("DropState");
int textCount = 0;
SetupDnd("Text", d => d.Set(DataFormats.Text,
$"Text was dragged {++textCount} times"), DragDropEffects.Copy | DragDropEffects.Move | DragDropEffects.Link);
SetupDnd("Custom", d => d.Set(CustomFormat, "Test123"), DragDropEffects.Move);
SetupDnd("Files", async d => d.Set(DataFormats.Files, new[] { await (VisualRoot as TopLevel)!.StorageProvider.TryGetFileFromPathAsync(Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName) }), DragDropEffects.Copy);
SetupDnd(
"Text",
d => d.Set(DataFormats.Text, $"Text was dragged {++textCount} times"),
DragDropEffects.Copy | DragDropEffects.Move | DragDropEffects.Link);
SetupDnd(
"Custom",
d => d.Set(CustomFormat, "Test123"),
DragDropEffects.Move);
SetupDnd(
"Files",
async d =>
{
if (Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName is { } name &&
TopLevel.GetTopLevel(this) is { } topLevel &&
await topLevel.StorageProvider.TryGetFileFromPathAsync(name) is { } storageFile)
{
d.Set(DataFormats.Files, new[] { storageFile });
}
},
DragDropEffects.Copy);
}
void SetupDnd(string suffix, Action<DataObject> factory, DragDropEffects effects)
private void SetupDnd(string suffix, Action<DataObject> factory, DragDropEffects effects) =>
SetupDnd(
suffix,
o =>
{
factory(o);
return Task.CompletedTask;
},
effects);
private void SetupDnd(string suffix, Func<DataObject, Task> factory, DragDropEffects effects)
{
var dragMe = this.Get<Border>("DragMe" + suffix);
var dragState = this.Get<TextBlock>("DragState" + suffix);
async void DoDrag(object? sender, Avalonia.Input.PointerPressedEventArgs e)
async void DoDrag(object? sender, PointerPressedEventArgs e)
{
var dragData = new DataObject();
factory(dragData);
await factory(dragData);
var result = await DragDrop.DoDragDrop(e, dragData, effects);
switch (result)

2
samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs

@ -48,7 +48,7 @@ namespace ControlCatalog.ViewModels
foreach (var item in items)
{
Items.Remove(item);
Items.Remove(item!);
}
});

7
samples/Generators.Sandbox/Controls/CustomTextBox.cs

@ -1,10 +1,9 @@
using System;
using Avalonia.Controls;
using Avalonia.Styling;
namespace Generators.Sandbox.Controls;
public class CustomTextBox : TextBox, IStyleable
public class CustomTextBox : TextBox
{
Type IStyleable.StyleKey => typeof(TextBox);
}
protected override Type StyleKeyOverride => typeof(TextBox);
}

50
samples/GpuInterop/D3DDemo/D3D11DemoControl.cs

@ -20,21 +20,21 @@ namespace GpuInterop.D3DDemo;
public class D3D11DemoControl : DrawingSurfaceDemoBase
{
private D3DDevice _device;
private D3D11Swapchain _swapchain;
private SharpDX.Direct3D11.DeviceContext _context;
private D3DDevice? _device;
private D3D11Swapchain? _swapchain;
private DeviceContext? _context;
private Matrix _view;
private PixelSize _lastSize;
private Texture2D _depthBuffer;
private DepthStencilView _depthView;
private Texture2D? _depthBuffer;
private DepthStencilView? _depthView;
private Matrix _proj;
private Buffer _constantBuffer;
private Stopwatch _st = Stopwatch.StartNew();
private Buffer? _constantBuffer;
private readonly Stopwatch _st = Stopwatch.StartNew();
protected override (bool success, string info) InitializeGraphicsResources(Compositor compositor,
CompositionDrawingSurface surface, ICompositionGpuInterop interop)
{
if (interop?.SupportedImageHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes
if (interop.SupportedImageHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes
.D3D11TextureGlobalSharedHandle) != true)
return (false, "DXGI shared handle import is not supported by the current graphics backend");
@ -60,8 +60,12 @@ public class D3D11DemoControl : DrawingSurfaceDemoBase
protected override void FreeGraphicsResources()
{
_swapchain.DisposeAsync();
_swapchain = null!;
if (_swapchain is not null)
{
_swapchain.DisposeAsync().GetAwaiter().GetResult();
_swapchain = null;
}
Utilities.Dispose(ref _depthView);
Utilities.Dispose(ref _depthBuffer);
Utilities.Dispose(ref _constantBuffer);
@ -80,10 +84,10 @@ public class D3D11DemoControl : DrawingSurfaceDemoBase
_lastSize = pixelSize;
Resize(pixelSize);
}
using (_swapchain.BeginDraw(pixelSize, out var renderView))
using (_swapchain!.BeginDraw(pixelSize, out var renderView))
{
_device.ImmediateContext.OutputMerger.SetTargets(_depthView, renderView);
_device!.ImmediateContext.OutputMerger.SetTargets(_depthView, renderView);
var viewProj = Matrix.Multiply(_view, _proj);
var context = _device.ImmediateContext;
@ -101,10 +105,10 @@ public class D3D11DemoControl : DrawingSurfaceDemoBase
var ypr = Matrix4x4.CreateFromYawPitchRoll(Yaw, Pitch, Roll);
// Update WorldViewProj Matrix
var worldViewProj = Matrix.RotationX((float)Yaw) * Matrix.RotationY((float)Pitch)
* Matrix.RotationZ((float)Roll)
* Matrix.Scaling(new Vector3(scaleX, scaleY, 1))
* viewProj;
var worldViewProj = Matrix.RotationX(Yaw) * Matrix.RotationY(Pitch)
* Matrix.RotationZ(Roll)
* Matrix.Scaling(new Vector3(scaleX, scaleY, 1))
* viewProj;
worldViewProj.Transpose();
context.UpdateSubresource(ref worldViewProj, _constantBuffer);
@ -112,21 +116,25 @@ public class D3D11DemoControl : DrawingSurfaceDemoBase
context.Draw(36, 0);
_context.Flush();
_context!.Flush();
}
}
private void Resize(PixelSize size)
{
Utilities.Dispose(ref _depthBuffer);
if (_device is null)
return;
_depthBuffer = new Texture2D(_device,
new Texture2DDescription()
{
Format = Format.D32_Float_S8X24_UInt,
ArraySize = 1,
MipLevels = 1,
Width = (int)size.Width,
Height = (int)size.Height,
Width = size.Width,
Height = size.Height,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
BindFlags = BindFlags.DepthStencil,
@ -138,9 +146,9 @@ public class D3D11DemoControl : DrawingSurfaceDemoBase
_depthView = new DepthStencilView(_device, _depthBuffer);
// Setup targets and viewport for rendering
_device.ImmediateContext.Rasterizer.SetViewport(new Viewport(0, 0, (int)size.Width, (int)size.Height, 0.0f, 1.0f));
_device.ImmediateContext.Rasterizer.SetViewport(new Viewport(0, 0, size.Width, size.Height, 0.0f, 1.0f));
// Setup new projection matrix with correct aspect ratio
_proj = Matrix.PerspectiveFovLH((float)Math.PI / 4.0f, (float)(size.Width / size.Height), 0.1f, 100.0f);
_proj = Matrix.PerspectiveFovLH((float)Math.PI / 4.0f, size.Width / (float) size.Height, 0.1f, 100.0f);
}
}

9
samples/GpuInterop/DrawingSurfaceDemoBase.cs

@ -1,5 +1,4 @@
using System;
using System.Numerics;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
@ -13,12 +12,12 @@ public abstract class DrawingSurfaceDemoBase : Control, IGpuDemo
{
private CompositionSurfaceVisual? _visual;
private Compositor? _compositor;
private Action _update;
private string _info;
private readonly Action _update;
private string _info = string.Empty;
private bool _updateQueued;
private bool _initialized;
protected CompositionDrawingSurface Surface { get; private set; }
protected CompositionDrawingSurface? Surface { get; private set; }
public DrawingSurfaceDemoBase()
{
@ -113,7 +112,7 @@ public abstract class DrawingSurfaceDemoBase : Control, IGpuDemo
protected abstract void RenderFrame(PixelSize pixelSize);
protected virtual bool SupportsDisco => false;
public void Update(GpuDemo parent, float yaw, float pitch, float roll, float disco)
public void Update(GpuDemo? parent, float yaw, float pitch, float roll, float disco)
{
ParentControl = parent;
if (ParentControl != null)

12
samples/GpuInterop/GpuDemo.axaml.cs

@ -80,13 +80,13 @@ public class GpuDemo : UserControl
set => SetAndRaise(DiscoVisibleProperty, ref _discoVisible, value);
}
private IGpuDemo _demo;
private IGpuDemo? _demo;
public static readonly DirectProperty<GpuDemo, IGpuDemo> DemoProperty =
AvaloniaProperty.RegisterDirect<GpuDemo, IGpuDemo>("Demo", o => o.Demo,
public static readonly DirectProperty<GpuDemo, IGpuDemo?> DemoProperty =
AvaloniaProperty.RegisterDirect<GpuDemo, IGpuDemo?>("Demo", o => o.Demo,
(o, v) => o._demo = v);
public IGpuDemo Demo
public IGpuDemo? Demo
{
get => _demo;
set => SetAndRaise(DemoProperty, ref _demo, value);
@ -102,7 +102,7 @@ public class GpuDemo : UserControl
)
{
if (change.Property == DemoProperty)
((IGpuDemo)change.OldValue)?.Update(null, 0, 0, 0, 0);
((IGpuDemo?)change.OldValue)?.Update(null, 0, 0, 0, 0);
_demo?.Update(this, Yaw, Pitch, Roll, Disco);
}
@ -112,5 +112,5 @@ public class GpuDemo : UserControl
public interface IGpuDemo
{
void Update(GpuDemo parent, float yaw, float pitch, float roll, float disco);
void Update(GpuDemo? parent, float yaw, float pitch, float roll, float disco);
}

4
samples/GpuInterop/VulkanDemo/VulkanCommandBufferPool.cs

@ -13,7 +13,7 @@ namespace Avalonia.Vulkan
private readonly CommandPool _commandPool;
private readonly List<VulkanCommandBuffer> _usedCommandBuffers = new();
private object _lock = new object();
private readonly object _lock = new();
public unsafe VulkanCommandBufferPool(Vk api, Device device, Queue queue, uint queueFamilyIndex)
{
@ -167,7 +167,7 @@ namespace Avalonia.Vulkan
ReadOnlySpan<PipelineStageFlags> waitDstStageMask = default,
ReadOnlySpan<Semaphore> signalSemaphores = default,
Fence? fence = null,
KeyedMutexSubmitInfo keyedMutex = null)
KeyedMutexSubmitInfo? keyedMutex = null)
{
EndRecording();

14
samples/GpuInterop/VulkanDemo/VulkanContent.cs

@ -39,7 +39,7 @@ unsafe class VulkanContent : IDisposable
{
_context = context;
var name = typeof(VulkanContent).Assembly.GetManifestResourceNames().First(x => x.Contains("teapot.bin"));
using (var sr = new BinaryReader(typeof(VulkanContent).Assembly.GetManifestResourceStream(name)))
using (var sr = new BinaryReader(typeof(VulkanContent).Assembly.GetManifestResourceStream(name)!))
{
var buf = new byte[sr.ReadInt32()];
sr.Read(buf, 0, buf.Length);
@ -115,7 +115,7 @@ unsafe class VulkanContent : IDisposable
{
var name = typeof(VulkanContent).Assembly.GetManifestResourceNames()
.First(x => x.Contains((fragment ? "frag" : "vert") + ".spirv"));
using (var sr = typeof(VulkanContent).Assembly.GetManifestResourceStream(name))
using (var sr = typeof(VulkanContent).Assembly.GetManifestResourceStream(name)!)
{
using (var mem = new MemoryStream())
{
@ -158,7 +158,7 @@ unsafe class VulkanContent : IDisposable
var commandBuffer = _context.Pool.CreateCommandBuffer();
commandBuffer.BeginRecording();
_colorAttachment.TransitionLayout(commandBuffer.InternalHandle,
_colorAttachment!.TransitionLayout(commandBuffer.InternalHandle,
ImageLayout.Undefined, AccessFlags.None,
ImageLayout.ColorAttachmentOptimal, AccessFlags.ColorAttachmentWriteBit);
@ -251,9 +251,9 @@ unsafe class VulkanContent : IDisposable
}
};
api.CmdBlitImage(commandBuffer.InternalHandle, _colorAttachment.InternalHandle.Value,
api.CmdBlitImage(commandBuffer.InternalHandle, _colorAttachment.InternalHandle,
ImageLayout.TransferSrcOptimal,
image.InternalHandle.Value, ImageLayout.TransferDstOptimal, 1, srcBlitRegion, Filter.Linear);
image.InternalHandle, ImageLayout.TransferDstOptimal, 1, srcBlitRegion, Filter.Linear);
commandBuffer.Submit();
}
@ -393,7 +393,7 @@ unsafe class VulkanContent : IDisposable
var view = Matrix4x4.CreateLookAt(new Vector3(25, 25, 25), new Vector3(), new Vector3(0, -1, 0));
var projection =
Matrix4x4.CreatePerspectiveFieldOfView((float)(Math.PI / 4), (float)((float)size.Width / size.Height),
Matrix4x4.CreatePerspectiveFieldOfView((float)(Math.PI / 4), (float)size.Width / size.Height,
0.01f, 1000);
_colorAttachment = new VulkanImage(_context, (uint)Format.R8G8B8A8Unorm, size, false);
@ -808,7 +808,7 @@ unsafe class VulkanContent : IDisposable
static Stopwatch St = Stopwatch.StartNew();
private bool _isInit;
private VulkanImage _colorAttachment;
private VulkanImage? _colorAttachment;
private DescriptorSet _descriptorSet;
[StructLayout(LayoutKind.Sequential, Pack = 4)]

38
samples/GpuInterop/VulkanDemo/VulkanContext.cs

@ -2,34 +2,31 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Platform;
using Avalonia.Rendering.Composition;
using Avalonia.Vulkan;
using Silk.NET.Core;
using Silk.NET.Core.Native;
using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.EXT;
using Silk.NET.Vulkan.Extensions.KHR;
using SilkNetDemo;
using SkiaSharp;
using D3DDevice = SharpDX.Direct3D11.Device;
using DxgiDevice = SharpDX.DXGI.Device;
namespace GpuInterop.VulkanDemo;
public unsafe class VulkanContext : IDisposable
{
public Vk Api { get; init; }
public Instance Instance { get; init; }
public PhysicalDevice PhysicalDevice { get; init; }
public Device Device { get; init; }
public Queue Queue { get; init; }
public uint QueueFamilyIndex { get; init; }
public VulkanCommandBufferPool Pool { get; init; }
public GRContext GrContext { get; init; }
public DescriptorPool DescriptorPool { get; init; }
public D3DDevice? D3DDevice { get; init; }
public required Vk Api { get; init; }
public required Instance Instance { get; init; }
public required PhysicalDevice PhysicalDevice { get; init; }
public required Device Device { get; init; }
public required Queue Queue { get; init; }
public required uint QueueFamilyIndex { get; init; }
public required VulkanCommandBufferPool Pool { get; init; }
public required GRContext GrContext { get; init; }
public required DescriptorPool DescriptorPool { get; init; }
public required D3DDevice? D3DDevice { get; init; }
public static (VulkanContext? result, string info) TryCreate(ICompositionGpuInterop gpuInterop)
{
@ -58,10 +55,8 @@ public unsafe class VulkanContext : IDisposable
enabledExtensions.Add("VK_EXT_debug_utils");
if (IsLayerAvailable(api, "VK_LAYER_KHRONOS_validation"))
enabledLayers.Add("VK_LAYER_KHRONOS_validation");
Instance vkInstance = default;
Silk.NET.Vulkan.PhysicalDevice physicalDevice = default;
Device device = default;
DescriptorPool descriptorPool = default;
VulkanCommandBufferPool? pool = null;
@ -78,7 +73,7 @@ public unsafe class VulkanContext : IDisposable
EnabledExtensionCount = pRequiredExtensions.UCount,
PpEnabledLayerNames = pEnabledLayers,
EnabledLayerCount = pEnabledLayers.UCount
}, null, out vkInstance).ThrowOnError();
}, null, out var vkInstance).ThrowOnError();
if (api.TryGetInstanceExtension(vkInstance, out ExtDebugUtils debugUtils))
@ -95,7 +90,7 @@ public unsafe class VulkanContext : IDisposable
PfnUserCallback = new PfnDebugUtilsMessengerCallbackEXT(LogCallback),
};
debugUtils.CreateDebugUtilsMessenger(vkInstance, debugCreateInfo, null, out var messenger);
debugUtils.CreateDebugUtilsMessenger(vkInstance, debugCreateInfo, null, out _);
}
var requireDeviceExtensions = new List<string>
@ -158,11 +153,11 @@ public unsafe class VulkanContext : IDisposable
else if (gpuInterop.DeviceUuid != null)
{
if (!new Span<byte>(physicalDeviceIDProperties.DeviceUuid, 16)
.SequenceEqual(gpuInterop?.DeviceUuid))
.SequenceEqual(gpuInterop.DeviceUuid))
continue;
}
physicalDevice = physicalDevices[c];
var physicalDevice = physicalDevices[c];
var name = Marshal.PtrToStringAnsi(new IntPtr(physicalDeviceProperties2.Properties.DeviceName))!;
@ -251,8 +246,7 @@ public unsafe class VulkanContext : IDisposable
RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
d3dDevice = D3DMemoryHelper.CreateDeviceByLuid(
new Span<byte>(physicalDeviceIDProperties.DeviceLuid, 8));
var dxgiDevice = d3dDevice?.QueryInterface<DxgiDevice>();
return (new VulkanContext
{
Api = api,

30
samples/GpuInterop/VulkanDemo/VulkanImage.cs

@ -24,23 +24,23 @@ public unsafe class VulkanImage : IDisposable
private ImageLayout _currentLayout;
private AccessFlags _currentAccessFlags;
private ImageUsageFlags _imageUsageFlags { get; }
private ImageView? _imageView { get; set; }
private ImageView _imageView { get; set; }
private DeviceMemory _imageMemory { get; set; }
private SharpDX.Direct3D11.Texture2D? _d3dTexture2D;
private readonly SharpDX.Direct3D11.Texture2D? _d3dTexture2D;
internal Image? InternalHandle { get; private set; }
internal Image InternalHandle { get; private set; }
internal Format Format { get; }
internal ImageAspectFlags AspectFlags { get; private set; }
internal ImageAspectFlags AspectFlags { get; }
public ulong Handle => InternalHandle?.Handle ?? 0;
public ulong ViewHandle => _imageView?.Handle ?? 0;
public ulong Handle => InternalHandle.Handle;
public ulong ViewHandle => _imageView.Handle;
public uint UsageFlags => (uint) _imageUsageFlags;
public ulong MemoryHandle => _imageMemory.Handle;
public DeviceMemory DeviceMemory => _imageMemory;
public uint MipLevels { get; private set; }
public uint MipLevels { get; }
public Vk Api { get; }
public PixelSize Size { get; }
public ulong MemorySize { get; private set; }
public ulong MemorySize { get; }
public uint CurrentLayout => (uint) _currentLayout;
public VulkanImage(VulkanContext vk, uint format, PixelSize size,
@ -93,7 +93,7 @@ public unsafe class VulkanImage : IDisposable
.CreateImage(_device, imageCreateInfo, null, out var image).ThrowOnError();
InternalHandle = image;
Api.GetImageMemoryRequirements(_device, InternalHandle.Value,
Api.GetImageMemoryRequirements(_device, InternalHandle,
out var memoryRequirements);
@ -109,7 +109,7 @@ public unsafe class VulkanImage : IDisposable
ImportMemoryWin32HandleInfoKHR handleImport = default;
if (exportable && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
_d3dTexture2D = D3DMemoryHelper.CreateMemoryHandle(vk.D3DDevice, size, Format);
_d3dTexture2D = D3DMemoryHelper.CreateMemoryHandle(vk.D3DDevice!, size, Format);
using var dxgi = _d3dTexture2D.QueryInterface<SharpDX.DXGI.Resource1>();
handleImport = new ImportMemoryWin32HandleInfoKHR
@ -141,7 +141,7 @@ public unsafe class VulkanImage : IDisposable
MemorySize = memoryRequirements.Size;
Api.BindImageMemory(_device, InternalHandle.Value, _imageMemory, 0).ThrowOnError();
Api.BindImageMemory(_device, InternalHandle, _imageMemory, 0).ThrowOnError();
var componentMapping = new ComponentMapping(
ComponentSwizzle.Identity,
ComponentSwizzle.Identity,
@ -155,7 +155,7 @@ public unsafe class VulkanImage : IDisposable
var imageViewCreateInfo = new ImageViewCreateInfo
{
SType = StructureType.ImageViewCreateInfo,
Image = InternalHandle.Value,
Image = InternalHandle,
ViewType = ImageViewType.Type2D,
Format = Format,
Components = componentMapping,
@ -209,7 +209,7 @@ public unsafe class VulkanImage : IDisposable
ImageLayout fromLayout, AccessFlags fromAccessFlags,
ImageLayout destinationLayout, AccessFlags destinationAccessFlags)
{
VulkanMemoryHelper.TransitionLayout(Api, commandBuffer, InternalHandle.Value,
VulkanMemoryHelper.TransitionLayout(Api, commandBuffer, InternalHandle,
fromLayout,
fromAccessFlags,
destinationLayout, destinationAccessFlags,
@ -241,8 +241,8 @@ public unsafe class VulkanImage : IDisposable
public unsafe void Dispose()
{
Api.DestroyImageView(_device, _imageView.Value, null);
Api.DestroyImage(_device, InternalHandle.Value, null);
Api.DestroyImageView(_device, _imageView, null);
Api.DestroyImage(_device, InternalHandle, null);
Api.FreeMemory(_device, _imageMemory, null);
_imageView = default;

2
samples/GpuInterop/VulkanDemo/VulkanSwapchain.cs

@ -146,6 +146,6 @@ class VulkanSwapchainImage : ISwapchainImage
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
_lastPresent = _target.UpdateWithKeyedMutexAsync(_importedImage, 1, 0);
else
_lastPresent = _target.UpdateWithSemaphoresAsync(_importedImage, _renderCompletedSemaphore, _availableSemaphore);
_lastPresent = _target.UpdateWithSemaphoresAsync(_importedImage, _renderCompletedSemaphore!, _availableSemaphore!);
}
}

37
samples/IntegrationTestApp/MainWindow.axaml.cs

@ -42,23 +42,20 @@ namespace IntegrationTestApp
private void InitializeViewMenu()
{
var mainTabs = this.Get<TabControl>("MainTabs");
var viewMenu = (NativeMenuItem)NativeMenu.GetMenu(this).Items[1];
var viewMenu = (NativeMenuItem?)NativeMenu.GetMenu(this)?.Items[1];
if (mainTabs.Items is not null)
foreach (var tabItem in mainTabs.Items.Cast<TabItem>())
{
foreach (TabItem tabItem in mainTabs.Items)
var menuItem = new NativeMenuItem
{
var menuItem = new NativeMenuItem
{
Header = (string)tabItem.Header!,
ToolTip = (string)tabItem.Header!,
IsChecked = tabItem.IsSelected,
ToggleType = NativeMenuItemToggleType.Radio,
};
menuItem.Click += (s, e) => tabItem.IsSelected = true;
viewMenu?.Menu?.Items.Add(menuItem);
}
Header = (string?)tabItem.Header,
ToolTip = (string?)tabItem.Header,
IsChecked = tabItem.IsSelected,
ToggleType = NativeMenuItemToggleType.Radio,
};
menuItem.Click += (_, _) => tabItem.IsSelected = true;
viewMenu?.Menu?.Items.Add(menuItem);
}
}
@ -77,7 +74,7 @@ namespace IntegrationTestApp
var window = new ShowWindowTest
{
WindowStartupLocation = (WindowStartupLocation)locationComboBox.SelectedIndex,
CanResize = canResizeCheckBox.IsChecked.Value,
CanResize = canResizeCheckBox.IsChecked ?? false,
};
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime)
@ -227,9 +224,9 @@ namespace IntegrationTestApp
var gestureBorder2 = this.GetControl<Border>("GestureBorder2");
var lastGesture = this.GetControl<TextBlock>("LastGesture");
var resetGestures = this.GetControl<Button>("ResetGestures");
gestureBorder.Tapped += (s, e) => lastGesture.Text = "Tapped";
gestureBorder.Tapped += (_, _) => lastGesture.Text = "Tapped";
gestureBorder.DoubleTapped += (s, e) =>
gestureBorder.DoubleTapped += (_, _) =>
{
lastGesture.Text = "DoubleTapped";
@ -238,14 +235,14 @@ namespace IntegrationTestApp
gestureBorder2.IsVisible = true;
};
gestureBorder2.DoubleTapped += (s, e) =>
gestureBorder2.DoubleTapped += (_, _) =>
{
lastGesture.Text = "DoubleTapped2";
};
Gestures.AddRightTappedHandler(gestureBorder, (s, e) => lastGesture.Text = "RightTapped");
Gestures.AddRightTappedHandler(gestureBorder, (_, _) => lastGesture.Text = "RightTapped");
resetGestures.Click += (s, e) =>
resetGestures.Click += (_, _) =>
{
lastGesture.Text = string.Empty;
gestureBorder.IsVisible = true;

12
src/Android/Avalonia.Android/AvaloniaMainActivity.App.cs

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
#nullable enable
namespace Avalonia.Android
{
@ -11,9 +7,9 @@ namespace Avalonia.Android
protected virtual AppBuilder CustomizeAppBuilder(AppBuilder builder) => builder.UseAndroid();
private static AppBuilder? s_appBuilder;
internal static object ViewContent;
internal static object? ViewContent;
public object Content
public object? Content
{
get
{
@ -51,7 +47,7 @@ namespace Avalonia.Android
View.Content = ViewContent;
}
if (Avalonia.Application.Current.ApplicationLifetime is SingleViewLifetime lifetime)
if (Avalonia.Application.Current?.ApplicationLifetime is SingleViewLifetime lifetime)
{
lifetime.View = View;
}

15
src/Android/Avalonia.Android/AvaloniaMainActivity.cs

@ -1,9 +1,8 @@
using System;
using System.Diagnostics;
using System.Runtime.Versioning;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Content.Res;
using Android.OS;
using Android.Runtime;
using Android.Views;
@ -37,6 +36,7 @@ namespace Avalonia.Android
ActivityResult?.Invoke(requestCode, resultCode, data);
}
[SupportedOSPlatform("android23.0")]
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
@ -47,7 +47,8 @@ namespace Avalonia.Android
public abstract partial class AvaloniaMainActivity<TApp> : AvaloniaMainActivity where TApp : Application, new()
{
internal AvaloniaView View;
internal AvaloniaView View { get; set; }
private GlobalLayoutListener _listener;
protected override void OnCreate(Bundle savedInstanceState)
@ -68,9 +69,9 @@ namespace Avalonia.Android
base.OnResume();
// Android only respects LayoutInDisplayCutoutMode value if it has been set once before window becomes visible.
if (Build.VERSION.SdkInt >= BuildVersionCodes.P)
if (OperatingSystem.IsAndroidVersionAtLeast(28) && Window is { Attributes: { } attributes })
{
Window.Attributes.LayoutInDisplayCutoutMode = LayoutInDisplayCutoutMode.ShortEdges;
attributes.LayoutInDisplayCutoutMode = LayoutInDisplayCutoutMode.ShortEdges;
}
}
@ -83,9 +84,9 @@ namespace Avalonia.Android
base.OnDestroy();
}
class GlobalLayoutListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
private class GlobalLayoutListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
{
private AvaloniaView _view;
private readonly AvaloniaView _view;
public GlobalLayoutListener(AvaloniaView view)
{

2
src/Android/Avalonia.Android/AvaloniaView.cs

@ -1,4 +1,5 @@
using System;
using System.Runtime.Versioning;
using Android.Content;
using Android.Content.Res;
using Android.Runtime;
@ -46,6 +47,7 @@ namespace Avalonia.Android
return _view.View.DispatchKeyEvent(e);
}
[SupportedOSPlatform("android24.0")]
public override void OnVisibilityAggregated(bool isVisible)
{
base.OnVisibilityAggregated(isVisible);

37
src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs

@ -30,17 +30,25 @@ namespace Avalonia.Android.Platform
{
_displayEdgeToEdge = value;
if(Build.VERSION.SdkInt >= BuildVersionCodes.P)
var window = _activity.Window;
if (OperatingSystem.IsAndroidVersionAtLeast(28) && window?.Attributes is { } attributes)
{
_activity.Window.Attributes.LayoutInDisplayCutoutMode = value ? LayoutInDisplayCutoutMode.ShortEdges : LayoutInDisplayCutoutMode.Default;
attributes.LayoutInDisplayCutoutMode = value ? LayoutInDisplayCutoutMode.ShortEdges : LayoutInDisplayCutoutMode.Default;
}
WindowCompat.SetDecorFitsSystemWindows(_activity.Window, !value);
if (window is not null)
{
WindowCompat.SetDecorFitsSystemWindows(_activity.Window, !value);
}
if(value)
{
_activity.Window.AddFlags(WindowManagerFlags.TranslucentStatus);
_activity.Window.AddFlags(WindowManagerFlags.TranslucentNavigation);
if (window is not null)
{
window.AddFlags(WindowManagerFlags.TranslucentStatus);
window.AddFlags(WindowManagerFlags.TranslucentNavigation);
}
}
else
{
@ -57,14 +65,17 @@ namespace Avalonia.Android.Platform
_callback.InsetsManager = this;
ViewCompat.SetOnApplyWindowInsetsListener(_activity.Window.DecorView, this);
if (_activity.Window is { } window)
{
ViewCompat.SetOnApplyWindowInsetsListener(window.DecorView, this);
ViewCompat.SetWindowInsetsAnimationCallback(_activity.Window.DecorView, _callback);
ViewCompat.SetWindowInsetsAnimationCallback(window.DecorView, _callback);
}
if(Build.VERSION.SdkInt < BuildVersionCodes.R)
if (Build.VERSION.SdkInt < BuildVersionCodes.R)
{
_usesLegacyLayouts = true;
_activity.Window.DecorView.ViewTreeObserver.AddOnGlobalLayoutListener(this);
_activity.Window?.DecorView.ViewTreeObserver?.AddOnGlobalLayoutListener(this);
}
DisplayEdgeToEdge = false;
@ -74,7 +85,7 @@ namespace Avalonia.Android.Platform
{
get
{
var insets = ViewCompat.GetRootWindowInsets(_activity.Window.DecorView);
var insets = _activity.Window is { } window ? ViewCompat.GetRootWindowInsets(window.DecorView) : null;
if (insets != null)
{
@ -127,7 +138,7 @@ namespace Avalonia.Android.Platform
return compat.AppearanceLightStatusBars ? Controls.Platform.SystemBarTheme.Light : Controls.Platform.SystemBarTheme.Dark;
}
catch (Exception _)
catch (Exception)
{
return Controls.Platform.SystemBarTheme.Light;
}
@ -136,8 +147,6 @@ namespace Avalonia.Android.Platform
{
_statusBarTheme = value;
var isDefault = _statusBarTheme == null;
if (!_topLevel.View.IsShown)
{
return;
@ -150,7 +159,7 @@ namespace Avalonia.Android.Platform
_isDefaultSystemBarLightTheme = compat.AppearanceLightStatusBars;
}
if (value == null && _isDefaultSystemBarLightTheme != null)
if (value == null)
{
value = (bool)_isDefaultSystemBarLightTheme ? Controls.Platform.SystemBarTheme.Light : Controls.Platform.SystemBarTheme.Dark;
}

8
src/Android/Avalonia.Android/Platform/AndroidSystemNavigationManager.cs

@ -1,4 +1,6 @@
using System;
#nullable enable
using System;
using Avalonia.Interactivity;
using Avalonia.Platform;
@ -6,7 +8,7 @@ namespace Avalonia.Android.Platform
{
internal class AndroidSystemNavigationManagerImpl : ISystemNavigationManagerImpl
{
public event EventHandler<RoutedEventArgs> BackRequested;
public event EventHandler<RoutedEventArgs>? BackRequested;
public AndroidSystemNavigationManagerImpl(IActivityNavigationService? navigationService)
{
@ -16,7 +18,7 @@ namespace Avalonia.Android.Platform
}
}
private void OnBackRequested(object sender, AndroidBackRequestedEventArgs e)
private void OnBackRequested(object? sender, AndroidBackRequestedEventArgs e)
{
var routedEventArgs = new RoutedEventArgs();

22
src/Android/Avalonia.Android/Platform/ClipboardImpl.cs

@ -1,8 +1,8 @@
#nullable enable
using System;
using System.Threading.Tasks;
using Android.Content;
using Avalonia.Input;
using Avalonia.Input.Platform;
@ -10,34 +10,34 @@ namespace Avalonia.Android.Platform
{
internal class ClipboardImpl : IClipboard
{
private ClipboardManager? _clipboardManager;
private readonly ClipboardManager? _clipboardManager;
internal ClipboardImpl(ClipboardManager? value)
{
_clipboardManager = value;
}
public Task<string> GetTextAsync()
public Task<string?> GetTextAsync()
{
if (_clipboardManager?.HasPrimaryClip == true)
{
return Task.FromResult<string>(_clipboardManager.PrimaryClip.GetItemAt(0).Text);
return Task.FromResult(_clipboardManager.PrimaryClip?.GetItemAt(0)?.Text);
}
return Task.FromResult<string>(null);
return Task.FromResult<string?>(null);
}
public Task SetTextAsync(string text)
public Task SetTextAsync(string? text)
{
if(_clipboardManager == null)
{
return Task.CompletedTask;
}
ClipData clip = ClipData.NewPlainText("text", text);
var clip = ClipData.NewPlainText("text", text);
_clipboardManager.PrimaryClip = clip;
return Task.FromResult<object>(null);
return Task.CompletedTask;
}
public Task ClearAsync()
@ -49,13 +49,13 @@ namespace Avalonia.Android.Platform
_clipboardManager.PrimaryClip = null;
return Task.FromResult<object>(null);
return Task.CompletedTask;
}
public Task SetDataObjectAsync(IDataObject data) => throw new PlatformNotSupportedException();
public Task<string[]> GetFormatsAsync() => throw new PlatformNotSupportedException();
public Task<object> GetDataAsync(string format) => throw new PlatformNotSupportedException();
public Task<object?> GetDataAsync(string format) => throw new PlatformNotSupportedException();
}
}

4
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -347,7 +347,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
{
activity.SetTranslucent(true);
SetBlurBehind(activity, 0);
activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
activity.Window?.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
}
}
else if (level == WindowTransparencyLevel.Blur)
@ -448,8 +448,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform
{
private readonly AvaloniaInputConnection _inputConnection;
public event EventHandler<int> SelectionChanged;
public EditableWrapper(AvaloniaInputConnection inputConnection)
{
_inputConnection = inputConnection;

8
src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs

@ -55,7 +55,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers
var keySymbol = GetKeySymbol(e.UnicodeChar, physicalKey);
var rawKeyEvent = new RawKeyEventArgs(
AndroidKeyboardDevice.Instance,
AndroidKeyboardDevice.Instance!,
Convert.ToUInt64(e.EventTime),
_view.InputRoot,
e.Action == KeyEventActions.Down ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
@ -64,18 +64,18 @@ namespace Avalonia.Android.Platform.Specific.Helpers
physicalKey,
keySymbol);
_view.Input(rawKeyEvent);
_view.Input?.Invoke(rawKeyEvent);
if ((e.Action == KeyEventActions.Down && e.UnicodeChar >= 32)
|| unicodeTextInput != null)
{
var rawTextEvent = new RawTextInputEventArgs(
AndroidKeyboardDevice.Instance,
AndroidKeyboardDevice.Instance!,
Convert.ToUInt64(e.EventTime),
_view.InputRoot,
unicodeTextInput ?? Convert.ToChar(e.UnicodeChar).ToString()
);
_view.Input(rawTextEvent);
_view.Input?.Invoke(rawTextEvent);
}
if (e.Action == KeyEventActions.Up)

45
src/Android/Avalonia.Android/Platform/Storage/AndroidStorageItem.cs

@ -172,29 +172,29 @@ internal class AndroidStorageFolder : AndroidStorageItem, IStorageBookmarkFolder
{
}
public async Task<IStorageFile?> CreateFileAsync(string name)
public Task<IStorageFile?> CreateFileAsync(string name)
{
var mimeType = MimeTypeMap.Singleton?.GetMimeTypeFromExtension(MimeTypeMap.GetFileExtensionFromUrl(name)) ?? "application/octet-stream";
var newFile = Document.CreateFile(mimeType, name);
var newFile = Document?.CreateFile(mimeType, name);
if(newFile == null)
{
return null;
return Task.FromResult<IStorageFile?>(null);
}
return new AndroidStorageFile(Activity, newFile.Uri, this);
return Task.FromResult<IStorageFile?>(new AndroidStorageFile(Activity, newFile.Uri, this));
}
public async Task<IStorageFolder?> CreateFolderAsync(string name)
public Task<IStorageFolder?> CreateFolderAsync(string name)
{
var newFolder = Document?.CreateDirectory(name);
if (newFolder == null)
{
return null;
return Task.FromResult<IStorageFolder?>(null);
}
return new AndroidStorageFolder(Activity, newFolder.Uri, false, this, PermissionRoot);
return Task.FromResult<IStorageFolder?>(new AndroidStorageFolder(Activity, newFolder.Uri, false, this, PermissionRoot));
}
public override async Task DeleteAsync()
@ -286,15 +286,15 @@ internal class AndroidStorageFolder : AndroidStorageItem, IStorageBookmarkFolder
return null;
async Task<AndroidStorageFolder?> MoveRecursively(AndroidStorageFolder storageFolder, AndroidStorageFolder destination)
static async Task<AndroidStorageFolder?> MoveRecursively(AndroidStorageFolder storageFolder, AndroidStorageFolder destination)
{
destination = await destination.CreateFolderAsync(storageFolder.Name) as AndroidStorageFolder;
if (destination == null)
if (await destination.CreateFolderAsync(storageFolder.Name) is not AndroidStorageFolder newDestination)
{
return null;
}
destination = newDestination;
await foreach (var file in storageFolder.GetItemsAsync())
{
if (file is AndroidStorageFolder folder)
@ -477,25 +477,32 @@ internal sealed class AndroidStorageFile : AndroidStorageItem, IStorageBookmarkF
if (Activity != null && destination is AndroidStorageFolder storageFolder)
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.N)
AndroidUri? movedUri = null;
if (OperatingSystem.IsAndroidVersionAtLeast(24))
{
try
{
var uri = DocumentsContract.MoveDocument(Activity.ContentResolver!, Uri, ((await GetParentAsync()) as AndroidStorageFolder)!.Uri, storageFolder.Document!.Uri);
return new AndroidStorageFile(Activity, uri, storageFolder);
if (Activity.ContentResolver is { } contentResolver &&
storageFolder.Document?.Uri is { } targetParentUri &&
await GetParentAsync() is AndroidStorageFolder parentFolder)
{
movedUri = DocumentsContract.MoveDocument(contentResolver, Uri, parentFolder.Uri, targetParentUri);
}
}
catch (Exception ex)
catch (Exception)
{
// There are many reason why DocumentContract will fail to move a file. We fallback to copying.
return await MoveFileByCopy();
}
}
else
if (movedUri is not null)
{
return await MoveFileByCopy();
return new AndroidStorageFile(Activity, movedUri, storageFolder);
}
return await MoveFileByCopy();
}
async Task<AndroidStorageFile?> MoveFileByCopy()

4
src/Avalonia.Base/Platform/Interop/Utf8Buffer.cs

@ -1,4 +1,6 @@
using System;
#nullable enable
using System;
using System.Buffers;
using System.Runtime.InteropServices;
using System.Text;

2
src/Tizen/Avalonia.Tizen/Avalonia.Tizen.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0-tizen</TargetFrameworks>
<TargetFramework>net6.0-tizen</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<MSBuildEnableWorkloadResolver>true</MSBuildEnableWorkloadResolver>

43
src/Tizen/Avalonia.Tizen/NuiAvaloniaView.cs

@ -3,11 +3,9 @@ using Avalonia.Controls.Embedding;
using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Input.TextInput;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using Avalonia.Rendering.Composition.Server;
using Avalonia.Threading;
using Tizen.NUI;
using Tizen.NUI.BaseComponents;
@ -22,21 +20,32 @@ public class NuiAvaloniaView : GLView, ITizenView, ITextInputMethodImpl
private readonly NuiTouchHandler _touchHandler;
private readonly NuiAvaloniaViewTextEditable _textEditor;
private TizenRenderTimer? _renderTimer;
private TopLevelImpl _topLevelImpl;
private EmbeddableControlRoot _topLevel;
private TouchDevice _device = new();
private ServerCompositionTarget _compositionTargetServer;
private TopLevelImpl? _topLevelImpl;
private EmbeddableControlRoot? _topLevel;
private readonly TouchDevice _device = new();
private ServerCompositionTarget? _compositionTargetServer;
private IInputRoot? _inputRoot;
public IInputRoot InputRoot { get; set; }
public INativeControlHostImpl NativeControlHost { get; }
internal TopLevelImpl TopLevelImpl => _topLevelImpl;
public double Scaling => 1;
public Size ClientSize => new(Size.Width, Size.Height);
public IInputRoot InputRoot
{
get => _inputRoot ?? throw new InvalidOperationException($"{nameof(InputRoot)} hasn't been set");
set => _inputRoot = value;
}
private TopLevel TopLevel
=> _topLevel ?? throw new InvalidOperationException($"{nameof(NuiAvaloniaView)} hasn't been initialized");
internal TopLevelImpl TopLevelImpl
=> _topLevelImpl ?? throw new InvalidOperationException($"{nameof(NuiAvaloniaView)} hasn't been initialized");
public Control? Content
{
get => _topLevel.Content as Control;
set => _topLevel.Content = value;
get => TopLevel.Content as Control;
set => TopLevel.Content = value;
}
internal NuiAvaloniaViewTextEditable TextEditor => _textEditor;
@ -44,7 +53,7 @@ public class NuiAvaloniaView : GLView, ITizenView, ITextInputMethodImpl
#region Setup
public event Action OnSurfaceInit;
public event Action? OnSurfaceInit;
public NuiAvaloniaView() : base(ColorFormat.RGBA8888)
{
@ -73,7 +82,7 @@ public class NuiAvaloniaView : GLView, ITizenView, ITextInputMethodImpl
private int GlRenderFrame()
{
if (_renderTimer == null || _topLevel == null)
if (_renderTimer == null || _compositionTargetServer == null)
return 0;
var rev = _compositionTargetServer.Revision;
@ -141,13 +150,13 @@ public class NuiAvaloniaView : GLView, ITizenView, ITextInputMethodImpl
private bool OnTouchEvent(object source, TouchEventArgs e)
{
_touchHandler?.Handle(e);
_touchHandler.Handle(e);
return true;
}
private bool OnWheelEvent(object source, WheelEventArgs e)
{
_touchHandler?.Handle(e);
_touchHandler.Handle(e);
return true;
}
@ -169,9 +178,9 @@ public class NuiAvaloniaView : GLView, ITizenView, ITextInputMethodImpl
{
if (disposing)
{
_topLevel.StopRendering();
_topLevel.Dispose();
_topLevelImpl.Dispose();
_topLevel?.StopRendering();
_topLevel?.Dispose();
_topLevelImpl?.Dispose();
_device.Dispose();
}
base.Dispose(disposing);

2
src/Tizen/Avalonia.Tizen/NuiAvaloniaViewTextEditable.cs

@ -20,9 +20,7 @@ internal class NuiAvaloniaViewTextEditable
public bool IsActive => _client != null && _keyboardPresented;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public NuiAvaloniaViewTextEditable(NuiAvaloniaView avaloniaView)
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
{
_avaloniaView = avaloniaView;
_singleLineTextInput = new NuiSingleLineTextInput

4
src/Tizen/Avalonia.Tizen/NuiGlPlatform.cs

@ -54,7 +54,7 @@ class GlContext : IGlContext
public bool IsSharedWith(IGlContext context) => true;
public bool CanCreateSharedContext => true;
public IGlContext CreateSharedContext(IEnumerable<GlVersion> preferredVersions = null)
public IGlContext CreateSharedContext(IEnumerable<GlVersion>? preferredVersions = null)
{
return this;
}
@ -78,7 +78,7 @@ class GlContext : IGlContext
}
}
public object TryGetFeature(Type featureType) => null;
public object? TryGetFeature(Type featureType) => null;
public IntPtr GetProcAddress(string procName)
{

13
src/Tizen/Avalonia.Tizen/NuiTizenApplication.cs

@ -3,7 +3,6 @@ using Avalonia.Controls.ApplicationLifetimes;
using Tizen.NUI;
using Window = Tizen.NUI.Window;
using Avalonia.Logging;
using Avalonia.Threading;
namespace Avalonia.Tizen;
@ -23,7 +22,7 @@ public class NuiTizenApplication<TApp> : NUIApplication
View = view;
}
public Control MainView
public Control? MainView
{
get => View.Content;
set => View.Content = value;
@ -37,9 +36,7 @@ public class NuiTizenApplication<TApp> : NUIApplication
Logger.TryGet(LogEventLevel.Debug, LogKey)?.Log(null, "Creating application");
base.OnCreate();
#pragma warning disable CS8601 // Possible null reference assignment.
TizenThreadingInterface.MainloopContext = SynchronizationContext.Current;
#pragma warning restore CS8601 // Possible null reference assignment.
TizenThreadingInterface.MainloopContext = SynchronizationContext.Current!;
Logger.TryGet(LogEventLevel.Debug, LogKey)?.Log(null, "Setup view");
_lifetime = new SingleViewLifetime(new NuiAvaloniaView());
@ -50,7 +47,7 @@ public class NuiTizenApplication<TApp> : NUIApplication
Window.Instance.RenderingBehavior = RenderingBehaviorType.Continuously;
Window.Instance.GetDefaultLayer().Add(_lifetime.View);
Window.Instance.KeyEvent += (s, e) => _lifetime?.View?.KeyboardHandler.Handle(e);
Window.Instance.KeyEvent += (_, e) => _lifetime?.View.KeyboardHandler.Handle(e);
}
private void ContinueSetupApplication()
@ -64,10 +61,10 @@ public class NuiTizenApplication<TApp> : NUIApplication
{
CustomizeAppBuilder(builder);
builder.AfterSetup(_ => _lifetime.View.Initialise());
builder.AfterSetup(_ => _lifetime!.View.Initialise());
Logger.TryGet(LogEventLevel.Debug, LogKey)?.Log(null, "Setup lifetime");
builder.SetupWithLifetime(_lifetime);
builder.SetupWithLifetime(_lifetime!);
}, null);
}
}

34
src/Tizen/Avalonia.Tizen/Platform/Permissions.cs

@ -1,5 +1,4 @@
using System.Security;
using System.Security.Permissions;
using Tizen.Applications;
using Tizen.Security;
@ -33,7 +32,7 @@ internal class Permissions
}
}
public static bool IsPrivilegeDeclared(string tizenPrivilege)
public static bool IsPrivilegeDeclared(string? tizenPrivilege)
{
var tizenPrivileges = tizenPrivilege;
@ -48,21 +47,21 @@ internal class Permissions
return true;
}
public static void EnsureDeclared(params Privilege[] requiredPrivileges)
public static void EnsureDeclared(params Privilege[]? requiredPrivileges)
{
if (requiredPrivileges?.Any() != true)
return;
foreach (var (tizenPrivilege, isRuntime) in requiredPrivileges)
foreach (var (tizenPrivilege, _) in requiredPrivileges)
{
if (!IsPrivilegeDeclared(tizenPrivilege))
throw new SecurityException($"You need to declare the privilege: `{tizenPrivilege}` in your tizen-manifest.xml");
}
}
public static Task<bool> CheckPrivilegeAsync(params Privilege[] requiredPrivileges) => CheckPrivilegeAsync(requiredPrivileges, false);
public static Task<bool> RequestPrivilegeAsync(params Privilege[] requiredPrivileges) => CheckPrivilegeAsync(requiredPrivileges, true);
private static async Task<bool> CheckPrivilegeAsync(Privilege[] requiredPrivileges, bool ask)
public static Task<bool> CheckPrivilegeAsync(params Privilege[]? requiredPrivileges) => CheckPrivilegeAsync(requiredPrivileges, false);
public static Task<bool> RequestPrivilegeAsync(params Privilege[]? requiredPrivileges) => CheckPrivilegeAsync(requiredPrivileges, true);
private static async Task<bool> CheckPrivilegeAsync(Privilege[]? requiredPrivileges, bool ask)
{
var ret = global::Tizen.System.Information.TryGetValue("http://tizen.org/feature/profile", out string profile);
if (!ret || (ret && (!profile.Equals("mobile") || !profile.Equals("wearable"))))
@ -77,7 +76,7 @@ internal class Permissions
var tizenPrivileges = requiredPrivileges.Where(p => p.IsRuntime);
foreach (var (tizenPrivilege, isRuntime) in tizenPrivileges)
foreach (var (tizenPrivilege, _) in tizenPrivileges)
{
var checkResult = PrivacyPrivilegeManager.CheckPermission(tizenPrivilege);
if (checkResult == CheckResult.Ask)
@ -87,16 +86,21 @@ internal class Permissions
var tcs = new TaskCompletionSource<bool>();
PrivacyPrivilegeManager.GetResponseContext(tizenPrivilege)
.TryGetTarget(out var context);
void OnResponseFetched(object sender, RequestResponseEventArgs e)
void OnResponseFetched(object? sender, RequestResponseEventArgs e)
{
tcs.TrySetResult(e.result == RequestResult.AllowForever);
}
context.ResponseFetched += OnResponseFetched;
PrivacyPrivilegeManager.RequestPermission(tizenPrivilege);
var result = await tcs.Task;
context.ResponseFetched -= OnResponseFetched;
if (result)
continue;
if (context != null)
{
context.ResponseFetched += OnResponseFetched;
PrivacyPrivilegeManager.RequestPermission(tizenPrivilege);
var result = await tcs.Task;
context.ResponseFetched -= OnResponseFetched;
if (result)
continue;
}
}
return false;
}

2
src/Tizen/Avalonia.Tizen/Stubs.cs

@ -9,7 +9,7 @@ internal class WindowingPlatformStub : IWindowingPlatform
public IWindowImpl CreateEmbeddableWindow() => throw new NotSupportedException();
public ITrayIconImpl CreateTrayIcon() => null;
public ITrayIconImpl? CreateTrayIcon() => null;
}
internal class PlatformIconLoaderStub : IPlatformIconLoader

22
src/Tizen/Avalonia.Tizen/TizenPlatform.cs

@ -1,21 +1,33 @@
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using Avalonia.Tizen.Platform.Input;
using Avalonia.Tizen.Platform;
using Avalonia.Threading;
namespace Avalonia.Tizen;
internal class TizenPlatform
{
public static readonly TizenPlatform Instance = new();
internal static NuiGlPlatform GlPlatform { get; set; }
internal static Compositor Compositor { get; private set; }
internal static TizenThreadingInterface ThreadingInterface { get; private set; } = new();
private static NuiGlPlatform? s_glPlatform;
private static Compositor? s_compositor;
internal static NuiGlPlatform GlPlatform
{
get => s_glPlatform ?? throw new InvalidOperationException($"{nameof(TizenPlatform)} hasn't been initialized");
private set => s_glPlatform = value;
}
internal static Compositor Compositor
{
get => s_compositor ?? throw new InvalidOperationException($"{nameof(TizenPlatform)} hasn't been initialized");
private set => s_compositor = value;
}
internal static TizenThreadingInterface ThreadingInterface { get; } = new();
public static void Initialize()
{

10
src/Tizen/Avalonia.Tizen/TizenThreadingInterface.cs

@ -7,9 +7,13 @@ internal class TizenThreadingInterface : IPlatformThreadingInterface
internal event Action? TickExecuted;
private bool _signaled;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
internal static SynchronizationContext MainloopContext { get; set; }
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
private static SynchronizationContext? s_mainloopContext;
internal static SynchronizationContext MainloopContext
{
get => s_mainloopContext ?? throw new InvalidOperationException($"{nameof(MainloopContext)} hasn't been set");
set => s_mainloopContext = value;
}
public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
{

2
src/Tizen/Avalonia.Tizen/TopLevelImpl.cs

@ -110,7 +110,7 @@ internal class TopLevelImpl : ITopLevelImpl
internal void TextInput(string text)
{
if (Input == null) return;
var args = new RawTextInputEventArgs(TizenKeyboardDevice.Instance, (ulong)DateTime.Now.Ticks, _view.InputRoot, text);
var args = new RawTextInputEventArgs(TizenKeyboardDevice.Instance!, (ulong)DateTime.Now.Ticks, _view.InputRoot, text);
Input(args);
}

70
src/iOS/Avalonia.iOS/AvaloniaView.cs

@ -1,3 +1,5 @@
#nullable enable
using System;
using System.Collections.Generic;
using Avalonia.Controls;
@ -12,7 +14,6 @@ using Avalonia.Input.TextInput;
using Avalonia.iOS.Storage;
using Avalonia.Platform;
using Avalonia.Platform.Storage;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using CoreAnimation;
using Foundation;
@ -25,12 +26,15 @@ namespace Avalonia.iOS
{
public partial class AvaloniaView : UIView, ITextInputMethodImpl
{
internal IInputRoot InputRoot { get; private set; }
private TopLevelImpl _topLevelImpl;
private EmbeddableControlRoot _topLevel;
private TouchHandler _touches;
private TextInputMethodClient _client;
private IAvaloniaViewController _controller;
internal IInputRoot InputRoot
=> _inputRoot ?? throw new InvalidOperationException($"{nameof(IWindowImpl.SetInputRoot)} must have been called");
private readonly TopLevelImpl _topLevelImpl;
private readonly EmbeddableControlRoot _topLevel;
private readonly TouchHandler _touches;
private TextInputMethodClient? _client;
private IAvaloniaViewController? _controller;
private IInputRoot? _inputRoot;
public AvaloniaView()
{
@ -60,7 +64,7 @@ namespace Avalonia.iOS
public override bool CanResignFirstResponder => true;
/// <inheritdoc />
public override void TraitCollectionDidChange(UITraitCollection previousTraitCollection)
public override void TraitCollectionDidChange(UITraitCollection? previousTraitCollection)
{
base.TraitCollectionDidChange(previousTraitCollection);
@ -91,7 +95,7 @@ namespace Avalonia.iOS
private readonly IStorageProvider _storageProvider;
internal readonly InsetsManager _insetsManager;
private readonly ClipboardImpl _clipboard;
private IDisposable _paddingInsets;
private IDisposable? _paddingInsets;
public AvaloniaView View => _view;
@ -101,17 +105,17 @@ namespace Avalonia.iOS
_nativeControlHost = new NativeControlHostImpl(view);
_storageProvider = new IOSStorageProvider(view);
_insetsManager = new InsetsManager(view);
_insetsManager.DisplayEdgeToEdgeChanged += (sender, edgeToEdge) =>
_insetsManager.DisplayEdgeToEdgeChanged += (_, edgeToEdge) =>
{
// iOS doesn't add any paddings/margins to the application by itself.
// Application is fully responsible for safe area paddings.
// So, unlikely to android, we need to "fake" safe area insets when edge to edge is disabled.
// So, unlikely to android, we need to "fake" safe area insets when edge to edge is disabled.
_paddingInsets?.Dispose();
if (!edgeToEdge)
if (!edgeToEdge && view._controller is { } controller)
{
_paddingInsets = view._topLevel.SetValue(
TemplatedControl.PaddingProperty,
view._controller.SafeAreaPadding,
controller.SafeAreaPadding,
BindingPriority.Style); // lower priority, so it can be redefined by user
}
};
@ -132,19 +136,19 @@ namespace Avalonia.iOS
public void SetInputRoot(IInputRoot inputRoot)
{
_view.InputRoot = inputRoot;
_view._inputRoot = inputRoot;
}
public Point PointToClient(PixelPoint point) => new Point(point.X, point.Y);
public PixelPoint PointToScreen(Point point) => new PixelPoint((int)point.X, (int)point.Y);
public void SetCursor(ICursorImpl _)
public void SetCursor(ICursorImpl? cursor)
{
// no-op
}
public IPopupImpl CreatePopup()
public IPopupImpl? CreatePopup()
{
// In-window popups
return null;
@ -158,18 +162,16 @@ namespace Avalonia.iOS
public Size ClientSize => new Size(_view.Bounds.Width, _view.Bounds.Height);
public Size? FrameSize => null;
public double RenderScaling => _view.ContentScaleFactor;
public IEnumerable<object> Surfaces { get; set; }
public Action<RawInputEventArgs> Input { get; set; }
public Action<Rect> Paint { get; set; }
public Action<Size, WindowResizeReason> Resized { get; set; }
public Action<double> ScalingChanged { get; set; }
public Action<WindowTransparencyLevel> TransparencyLevelChanged { get; set; }
public Action Closed { get; set; }
public Action LostFocus { get; set; }
// legacy no-op
public IMouseDevice MouseDevice { get; } = new MouseDevice();
public IEnumerable<object> Surfaces { get; set; } = Array.Empty<object>();
public Action<RawInputEventArgs>? Input { get; set; }
public Action<Rect>? Paint { get; set; }
public Action<Size, WindowResizeReason>? Resized { get; set; }
public Action<double>? ScalingChanged { get; set; }
public Action<WindowTransparencyLevel>? TransparencyLevelChanged { get; set; }
public Action? Closed { get; set; }
public Action? LostFocus { get; set; }
public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None;
public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
@ -226,13 +228,13 @@ namespace Avalonia.iOS
return new Class(typeof(CAEAGLLayer));
}
public override void TouchesBegan(NSSet touches, UIEvent evt) => _touches.Handle(touches, evt);
public override void TouchesBegan(NSSet touches, UIEvent? evt) => _touches.Handle(touches, evt);
public override void TouchesMoved(NSSet touches, UIEvent evt) => _touches.Handle(touches, evt);
public override void TouchesMoved(NSSet touches, UIEvent? evt) => _touches.Handle(touches, evt);
public override void TouchesEnded(NSSet touches, UIEvent evt) => _touches.Handle(touches, evt);
public override void TouchesEnded(NSSet touches, UIEvent? evt) => _touches.Handle(touches, evt);
public override void TouchesCancelled(NSSet touches, UIEvent evt) => _touches.Handle(touches, evt);
public override void TouchesCancelled(NSSet touches, UIEvent? evt) => _touches.Handle(touches, evt);
public override void LayoutSubviews()
{
@ -240,9 +242,9 @@ namespace Avalonia.iOS
base.LayoutSubviews();
}
public Control Content
public Control? Content
{
get => (Control)_topLevel.Content;
get => (Control?)_topLevel.Content;
set => _topLevel.Content = value;
}
}

2
src/iOS/Avalonia.iOS/Storage/IOSSecurityScopedStream.cs

@ -17,7 +17,7 @@ internal sealed class IOSSecurityScopedStream : Stream
internal IOSSecurityScopedStream(NSUrl url, FileAccess access)
{
_document = new UIDocument(url);
var path = _document.FileUrl.Path;
var path = _document.FileUrl.Path!;
_url = url;
_url.StartAccessingSecurityScopedResource();
_stream = File.Open(path, FileMode.Open, access);

15
src/iOS/Avalonia.iOS/Storage/IOSStorageItem.cs

@ -47,7 +47,12 @@ internal abstract class IOSStorageItem : IStorageBookmarkItem
Logger.TryGet(LogEventLevel.Error, LogArea.IOSPlatform)?.
Log(this, "GetBasicPropertiesAsync returned an error: {ErrorCode} {ErrorMessage}", error.Code, error.LocalizedFailureReason);
}
return Task.FromResult(new StorageItemProperties(attributes?.Size, (DateTime)attributes?.CreationDate, (DateTime)attributes?.ModificationDate));
var properties = attributes is null ?
new StorageItemProperties() :
new StorageItemProperties(attributes.Size, (DateTime)attributes.CreationDate, (DateTime)attributes.ModificationDate);
return Task.FromResult(properties);
}
public Task<IStorageFolder?> GetParentAsync()
@ -62,7 +67,7 @@ internal abstract class IOSStorageItem : IStorageBookmarkItem
: Task.FromException(new NSErrorException(error));
}
public async Task<IStorageItem?> MoveAsync(IStorageFolder destination)
public Task<IStorageItem?> MoveAsync(IStorageFolder destination)
{
if (destination is not IOSStorageFolder folder)
{
@ -75,8 +80,8 @@ internal abstract class IOSStorageItem : IStorageBookmarkItem
if (NSFileManager.DefaultManager.Move(folder.Url, newPath, out var error))
{
return isDir
? new IOSStorageFolder(newPath)
: new IOSStorageFile(newPath);
? Task.FromResult<IStorageItem?>(new IOSStorageFolder(newPath))
: Task.FromResult<IStorageItem?>(new IOSStorageFile(newPath));
}
if (error is not null)
@ -84,7 +89,7 @@ internal abstract class IOSStorageItem : IStorageBookmarkItem
throw new NSErrorException(error);
}
return null;
return Task.FromResult<IStorageItem?>(null);
}
public Task ReleaseBookmarkAsync()

13
src/iOS/Avalonia.iOS/TextInputResponder.cs

@ -159,17 +159,20 @@ partial class AvaloniaView
{
Logger.TryGet(LogEventLevel.Debug, ImeLog)?.Log(null, "Triggering key press {key}", key);
_view._topLevelImpl.Input(new RawKeyEventArgs(KeyboardDevice.Instance!, 0, _view.InputRoot,
RawKeyEventType.KeyDown, key, RawInputModifiers.None, physicalKey, keySymbol));
if (_view._topLevelImpl.Input is { } input)
{
input.Invoke(new RawKeyEventArgs(KeyboardDevice.Instance!, 0, _view.InputRoot,
RawKeyEventType.KeyDown, key, RawInputModifiers.None, physicalKey, keySymbol));
_view._topLevelImpl.Input(new RawKeyEventArgs(KeyboardDevice.Instance!, 0, _view.InputRoot,
RawKeyEventType.KeyUp, key, RawInputModifiers.None, physicalKey, keySymbol));
input.Invoke(new RawKeyEventArgs(KeyboardDevice.Instance!, 0, _view.InputRoot,
RawKeyEventType.KeyUp, key, RawInputModifiers.None, physicalKey, keySymbol));
}
}
private void TextInput(string text)
{
Logger.TryGet(LogEventLevel.Debug, ImeLog)?.Log(null, "Triggering text input {text}", text);
_view._topLevelImpl.Input(new RawTextInputEventArgs(KeyboardDevice.Instance!, 0, _view.InputRoot, text));
_view._topLevelImpl.Input?.Invoke(new RawTextInputEventArgs(KeyboardDevice.Instance!, 0, _view.InputRoot, text));
}
void IUIKeyInput.InsertText(string text)

11
tests/Avalonia.Base.UnitTests/DispatcherTests.cs

@ -14,8 +14,8 @@ public class DispatcherTests
{
class SimpleDispatcherImpl : IDispatcherImpl, IDispatcherImplWithPendingInput
{
private Thread _loopThread = Thread.CurrentThread;
private object _lock = new();
private readonly Thread _loopThread = Thread.CurrentThread;
private readonly object _lock = new();
public bool CurrentThreadIsLoopThread => Thread.CurrentThread == _loopThread;
public void Signal()
{
@ -221,7 +221,8 @@ public class DispatcherTests
0 => 1,
1 => 4,
2 => 8,
3 => 10
3 => 10,
_ => throw new InvalidOperationException($"Unexpected value {c}")
};
Assert.Equal(Enumerable.Range(0, expectedCount), actions);
@ -380,7 +381,7 @@ public class DispatcherTests
class WaitHelper : SynchronizationContext, NonPumpingLockHelper.IHelperImpl
{
public int WaitCount;
public int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
public override int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
{
WaitCount++;
return base.Wait(waitHandles, waitAll, millisecondsTimeout);
@ -502,4 +503,4 @@ public class DispatcherTests
t.GetAwaiter().GetResult();
}
}
}
}

13
tests/Avalonia.Base.UnitTests/Media/EffectTests.cs

@ -25,9 +25,8 @@ public class EffectTests
InlineData("drop-shadow ( 10 20 30 #ffff00ff ) ", 10, 20, 30, 0xffff00ff),
InlineData("drop-shadow(10 20 30 red)", 10, 20, 30, 0xffff0000),
InlineData("drop-shadow ( 10 20 30 red ) ", 10, 20, 30, 0xffff0000),
InlineData("drop-shadow(10 20 30 rgba(100, 30, 45, 90%))", 10, 20, 30, 0x90641e2d),
InlineData("drop-shadow(10 20 30 rgba(100, 30, 45, 90%) ) ", 10, 20, 30, 0x90641e2d),
InlineData("drop-shadow(10 20 30 rgba(100, 30, 45, 90%))", 10, 20, 30, 0xe6641e2d),
InlineData("drop-shadow(10 20 30 rgba(100, 30, 45, 90%) ) ", 10, 20, 30, 0xe6641e2d)
]
public void Parse_Parses_DropShadow(string s, double x, double y, double r, uint color)
{
@ -36,6 +35,7 @@ public class EffectTests
Assert.Equal(y, effect.OffsetY);
Assert.Equal(r, effect.BlurRadius);
Assert.Equal(1, effect.Opacity);
Assert.Equal(color, effect.Color.ToUInt32());
}
[Theory,
@ -44,7 +44,7 @@ public class EffectTests
InlineData("blur()"),
InlineData("blur(123"),
InlineData("blur(aaab)"),
InlineData("drop-shadow(-10 -20 -30)"),
InlineData("drop-shadow(-10 -20 -30)")
]
public void Invalid_Effect_Parse_Fails(string b)
{
@ -58,10 +58,7 @@ public class EffectTests
InlineData("drop-shadow(10 15 5)", 0, 0, 16, 21),
InlineData("drop-shadow(0 0 5)", 6, 6, 6, 6),
InlineData("drop-shadow(3 3 5)", 3, 3, 9, 9)
]
public static void PaddingIsCorrectlyCalculated(string effect, double left, double top, double right, double bottom)
{
var padding = Effect.Parse(effect).GetEffectOutputPadding();
@ -70,4 +67,4 @@ public class EffectTests
Assert.Equal(right, padding.Right);
Assert.Equal(bottom, padding.Bottom);
}
}
}

6
tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs

@ -525,12 +525,12 @@ namespace Avalonia.Base.UnitTests.Styling
private class TestConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return value.ToString() + "bar";
return value + "bar";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotImplementedException();
}

53
tests/Avalonia.Controls.UnitTests/Automation/ControlAutomationPeerTests.cs

@ -1,11 +1,7 @@
using System;
using System.Linq;
using System.Linq;
using Avalonia.Automation.Peers;
using Avalonia.Automation.Provider;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
using Avalonia.Platform;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using Xunit;
@ -41,7 +37,7 @@ namespace Avalonia.Controls.UnitTests.Automation
{
var contentControl = new ContentControl
{
Template = new FuncControlTemplate<ContentControl>((o, ns) =>
Template = new FuncControlTemplate<ContentControl>((o, _) =>
new ContentPresenter
{
Name = "PART_ContentPresenter",
@ -180,50 +176,5 @@ namespace Avalonia.Controls.UnitTests.Automation
{
return ControlAutomationPeer.CreatePeerForElement(control);
}
private class TestControl : Control
{
protected override AutomationPeer OnCreateAutomationPeer()
{
return new TestAutomationPeer(this);
}
}
private class AutomationTestRoot : TestRoot
{
protected override AutomationPeer OnCreateAutomationPeer()
{
return new TestRootAutomationPeer(this);
}
}
private class TestAutomationPeer : ControlAutomationPeer
{
public TestAutomationPeer( Control owner)
: base(owner)
{
}
}
private class TestRootAutomationPeer : ControlAutomationPeer, IRootProvider
{
public TestRootAutomationPeer(Control owner)
: base(owner)
{
}
public ITopLevelImpl PlatformImpl => throw new System.NotImplementedException();
public event EventHandler? FocusChanged;
public AutomationPeer GetFocus()
{
throw new System.NotImplementedException();
}
public AutomationPeer GetPeerFromPoint(Point p)
{
throw new System.NotImplementedException();
}
}
}
}

2
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs

@ -2424,7 +2424,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
set => base.SelectionMode = value;
}
public new bool MoveSelection(NavigationDirection direction, bool wrap)
public bool MoveSelection(NavigationDirection direction, bool wrap)
{
return base.MoveSelection(direction, wrap);
}

3
tests/Avalonia.Controls.UnitTests/Primitives/ToggleButtonTests.cs

@ -1,8 +1,9 @@
using Avalonia.Data;
using Avalonia.UnitTests;
using Xunit;
#pragma warning disable CS0618 // Type or member is obsolete -- we're testing these members
namespace Avalonia.Controls.Primitives.UnitTests
{
public class ToggleButtonTests

12
tests/Avalonia.Markup.Xaml.UnitTests/Converters/AvaloniaPropertyConverterTest.cs

@ -1,4 +1,3 @@
using System;
using System.ComponentModel;
using Avalonia.Markup.Xaml.Converters;
using Avalonia.Markup.Xaml.XamlIl.Runtime;
@ -13,8 +12,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.Converters
public AvaloniaPropertyConverterTest()
{
// Ensure properties are registered.
var foo = Class1.FooProperty;
var attached = AttachedOwner.AttachedProperty;
_ = Class1.FooProperty;
_ = AttachedOwner.AttachedProperty;
}
[Fact]
@ -114,13 +113,6 @@ namespace Avalonia.Markup.Xaml.UnitTests.Converters
{
public static readonly StyledProperty<string> FooProperty =
AvaloniaProperty.Register<Class1, string>("Foo");
public ThemeVariant ThemeVariant
{
get => throw new NotImplementedException();
}
public event EventHandler ThemeVariantChanged;
}
private class AttachedOwner

224
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs

@ -1,4 +1,6 @@
using System;
#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@ -48,7 +50,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding StringProperty}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext
{
@ -74,7 +76,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding StringProperty}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext
{
@ -100,7 +102,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding Path=StringProperty}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext
{
@ -132,7 +134,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
</ItemsControl>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<ItemsControl>("itemsControl");
var textBlock = window.GetControl<ItemsControl>("itemsControl");
var dataContext = new TestDataContext
{
@ -162,7 +164,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding StaticProperty}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
textBlock.DataContext = new TestDataContext();
Assert.Equal(TestDataContext.StaticProperty, textBlock.Text);
@ -181,7 +183,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding StringProperty, DataType=local:TestDataContext}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext
{
@ -206,7 +208,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding StringProperty, DataType={x:Type local:TestDataContext}}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext
{
@ -232,7 +234,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding TaskProperty^}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext
{
@ -258,7 +260,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding ObservableProperty^}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
DelayedBinding.ApplyBindings(textBlock);
@ -289,7 +291,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding ListProperty[3]}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext
{
@ -315,7 +317,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding ArrayProperty[3]}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext
{
@ -341,7 +343,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding ObservableCollectionProperty[3]}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext
{
@ -371,10 +373,10 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock DataContext='{CompiledBinding StringProperty}' Text='{CompiledBinding}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
window.ApplyTemplate();
window.Presenter.ApplyTemplate();
window.Presenter!.ApplyTemplate();
var dataContext = new TestDataContext
{
@ -400,7 +402,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding NonIntegerIndexerProperty[Test]}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext();
@ -429,7 +431,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding NonIntegerIndexerInterfaceProperty[Test]}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext();
@ -463,7 +465,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<ContentControl Name='target' Content='{CompiledBinding StringProperty}' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.FindControl<ContentControl>("target");
var target = window.GetControl<ContentControl>("target");
var dataContext = new TestDataContext();
@ -473,9 +475,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
window.ApplyTemplate();
target.ApplyTemplate();
target.Presenter.UpdateChild();
target.Presenter!.UpdateChild();
Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child).Text);
Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child!).Text);
}
}
@ -560,7 +562,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
</ItemsControl>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.FindControl<ItemsControl>("target");
var target = window.GetControl<ItemsControl>("target");
var dataContext = new TestDataContext();
@ -570,9 +572,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
window.ApplyTemplate();
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
target.Presenter!.ApplyTemplate();
Assert.Equal(dataContext.ListProperty[0], (string)((ContentPresenter)target.Presenter.Panel.Children[0]).Content);
Assert.Equal(dataContext.ListProperty[0], (string?)((ContentPresenter)target.Presenter.Panel!.Children[0]).Content);
}
}
@ -598,8 +600,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
</local:DataGridLikeControl.Columns>
</local:DataGridLikeControl>
</Window>");
var target = window.FindControl<DataGridLikeControl>("target");
var column = target!.Columns.Single();
var target = window.GetControl<DataGridLikeControl>("target");
var column = target.Columns.Single();
var dataContext = new TestDataContext();
@ -611,13 +613,13 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
target.ApplyTemplate();
// Assert DataGridLikeColumn.Binding data type.
var compiledPath = ((CompiledBindingExtension)column.Binding).Path;
var compiledPath = ((CompiledBindingExtension)column.Binding!).Path;
var node = Assert.IsType<PropertyElement>(Assert.Single(compiledPath.Elements));
Assert.Equal(typeof(int), node.Property.PropertyType);
// Assert DataGridLikeColumn.Template data type by evaluating the template.
var firstItem = dataContext.ListProperty[0];
var textBlockFromTemplate = (TextBlock)column.Template.Build(firstItem);
var textBlockFromTemplate = (TextBlock)column.Template!.Build(firstItem)!;
textBlockFromTemplate.DataContext = firstItem;
Assert.Equal(firstItem.Length.ToString(), textBlockFromTemplate.Text);
}
@ -645,8 +647,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
</local:DataGridLikeControl.Columns>
</local:DataGridLikeControl>
</Window>");
var target = window.FindControl<DataGridLikeControl>("target");
var column = target!.Columns.Single();
var target = window.GetControl<DataGridLikeControl>("target");
var column = target.Columns.Single();
var dataContext = new TestDataContext();
dataContext.ListProperty.Add("Test");
@ -656,13 +658,13 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
target.ApplyTemplate();
// Assert DataGridLikeColumn.Binding data type.
var compiledPath = ((CompiledBindingExtension)column.Binding).Path;
var compiledPath = ((CompiledBindingExtension)column.Binding!).Path;
var node = Assert.IsType<PropertyElement>(Assert.Single(compiledPath.Elements));
Assert.Equal(typeof(int), node.Property.PropertyType);
// Assert DataGridLikeColumn.Template data type by evaluating the template.
var firstItem = dataContext.ListProperty[0];
var textBlockFromTemplate = (TextBlock)column.Template.Build(firstItem);
var textBlockFromTemplate = (TextBlock)column.Template!.Build(firstItem)!;
textBlockFromTemplate.DataContext = firstItem;
Assert.Equal(firstItem.Length.ToString(), textBlockFromTemplate.Text);
}
@ -707,7 +709,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<ContentControl x:DataType='local:TestDataContext' Name='target' Content='{CompiledBinding}' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.FindControl<ContentControl>("target");
var target = window.GetControl<ContentControl>("target");
var dataContext = new TestDataContext();
@ -717,9 +719,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
window.ApplyTemplate();
target.ApplyTemplate();
target.Presenter.UpdateChild();
target.Presenter!.UpdateChild();
Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child).Text);
Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child!).Text);
}
}
@ -740,7 +742,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<ContentControl x:DataType='local:TestDataContext' Name='target' Content='{CompiledBinding}' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.FindControl<ContentControl>("target");
var target = window.GetControl<ContentControl>("target");
var dataContext = new TestDataContext();
@ -750,9 +752,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
window.ApplyTemplate();
target.ApplyTemplate();
target.Presenter.UpdateChild();
target.Presenter!.UpdateChild();
Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child).Text);
Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child!).Text);
}
}
@ -773,7 +775,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<ContentControl x:DataType='local:TestDataContext' Name='target' Content='{CompiledBinding}' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.FindControl<ContentControl>("target");
var target = window.GetControl<ContentControl>("target");
var dataContext = new TestDataContext();
@ -783,9 +785,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
window.ApplyTemplate();
target.ApplyTemplate();
target.Presenter.UpdateChild();
target.Presenter!.UpdateChild();
Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child).Text);
Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child!).Text);
}
}
@ -805,7 +807,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
</StackPanel>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("text2");
var textBlock = window.GetControl<TextBlock>("text2");
var dataContext = new TestDataContext
{
@ -834,7 +836,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
</StackPanel>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("text2");
var textBlock = window.GetControl<TextBlock>("text2");
var dataContext = new TestDataContext
{
@ -861,10 +863,10 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding Title, RelativeSource={RelativeSource AncestorType=Window}}' x:Name='text'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.FindControl<TextBlock>("text");
var target = window.GetControl<TextBlock>("text");
window.ApplyTemplate();
window.Presenter.ApplyTemplate();
window.Presenter!.ApplyTemplate();
target.ApplyTemplate();
Assert.Equal("test", target.Text);
@ -885,10 +887,10 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}' x:Name='text'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.FindControl<TextBlock>("text");
var target = window.GetControl<TextBlock>("text");
window.ApplyTemplate();
window.Presenter.ApplyTemplate();
window.Presenter!.ApplyTemplate();
target.ApplyTemplate();
Assert.Equal("test", target.Text);
@ -1003,10 +1005,10 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding Length, Source=Test}' x:Name='text'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.FindControl<TextBlock>("text");
var target = window.GetControl<TextBlock>("text");
window.ApplyTemplate();
window.Presenter.ApplyTemplate();
window.Presenter!.ApplyTemplate();
target.ApplyTemplate();
Assert.Equal("Test".Length.ToString(), target.Text);
@ -1030,7 +1032,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
Assert.Equal("foobar", textBlock.Text);
}
@ -1054,7 +1056,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
Assert.Equal("foobar", textBlock.Text);
}
@ -1079,7 +1081,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
Assert.Equal("foobar", textBlock.Text);
}
@ -1105,7 +1107,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
Assert.Equal("foobar", textBlock.Text);
}
@ -1125,7 +1127,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var contentControl = window.FindControl<ContentControl>("contentControl");
var contentControl = window.GetControl<ContentControl>("contentControl");
Assert.Equal(Brushes.Red.Color, contentControl.Content);
}
@ -1145,7 +1147,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{Binding StringProperty}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext
{
@ -1188,7 +1190,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<ContentControl Content='{CompiledBinding $parent.Title}' Name='contentControl' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var contentControl = window.FindControl<ContentControl>("contentControl");
var contentControl = window.GetControl<ContentControl>("contentControl");
Assert.Equal("foo", contentControl.Content);
}
@ -1208,7 +1210,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
window.DataContext = new TestDataContext() { StringProperty = "Foo" };
@ -1230,7 +1232,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
window.DataContext = new TestDataContext() { StringProperty = "Foo" };
@ -1267,7 +1269,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<ContentControl Content='{CompiledBinding $parent.((local:TestDataContext)DataContext)}' Name='contentControl' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var contentControl = window.FindControl<ContentControl>("contentControl");
var contentControl = window.GetControl<ContentControl>("contentControl");
var dataContext = new TestDataContext();
@ -1290,7 +1292,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<ContentControl Content='{CompiledBinding $parent.((local:TestDataContext)DataContext)}' Name='contentControl' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var contentControl = window.FindControl<ContentControl>("contentControl");
var contentControl = window.GetControl<ContentControl>("contentControl");
var dataContext = "foo";
@ -1313,7 +1315,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<ContentControl Content='{CompiledBinding $parent.((local:TestDataContext)DataContext).StringProperty}' Name='contentControl' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var contentControl = window.FindControl<ContentControl>("contentControl");
var contentControl = window.GetControl<ContentControl>("contentControl");
var dataContext = new TestDataContext
{
@ -1339,7 +1341,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<ContentControl Content='{CompiledBinding $parent.DataContext(local:TestDataContext).StringProperty}' Name='contentControl' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var contentControl = window.FindControl<ContentControl>("contentControl");
var contentControl = window.GetControl<ContentControl>("contentControl");
var dataContext = new TestDataContext
{
@ -1365,7 +1367,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<ContentControl Content='{CompiledBinding ((local:TestData)ObjectsArrayProperty[0]).StringProperty}' Name='contentControl' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var contentControl = window.FindControl<ContentControl>("contentControl");
var contentControl = window.GetControl<ContentControl>("contentControl");
var data = new TestData()
{
@ -1395,7 +1397,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<ContentControl Content='{CompiledBinding $parent.((local:TestDataContext)DataContext).StringProperty}' Name='contentControl' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var contentControl = window.FindControl<ContentControl>("contentControl");
var contentControl = window.GetControl<ContentControl>("contentControl");
var dataContext = new TestDataContext
{
@ -1425,7 +1427,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext
{
@ -1451,7 +1453,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding StringFormat=bar-\{0\}}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext
{
@ -1477,7 +1479,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding .}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext
{
@ -1503,7 +1505,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Text='{CompiledBinding Path=., StringFormat=bar-\{0\}}' Name='textBlock' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext
{
@ -1550,10 +1552,10 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Name='textBlock' Text='{CompiledBinding $self.Name}' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
window.ApplyTemplate();
window.Presenter.ApplyTemplate();
window.Presenter!.ApplyTemplate();
Assert.Equal(textBlock.Name, textBlock.Text);
}
@ -1577,10 +1579,10 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<Button Name='button' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var button = window.FindControl<Button>("button");
var button = window.GetControl<Button>("button");
window.ApplyTemplate();
window.Presenter.ApplyTemplate();
window.Presenter!.ApplyTemplate();
Assert.True(button.IsVisible);
@ -1612,12 +1614,12 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
window.DataContext = new MethodDataContext();
Assert.IsAssignableFrom(typeof(Action), window.FindControl<ContentControl>("action").Content);
Assert.IsAssignableFrom(typeof(Func<int>), window.FindControl<ContentControl>("func").Content);
Assert.IsAssignableFrom(typeof(Action<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>), window.FindControl<ContentControl>("action16").Content);
Assert.IsAssignableFrom(typeof(Func<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>), window.FindControl<ContentControl>("func16").Content);
Assert.True(typeof(Delegate).IsAssignableFrom(window.FindControl<ContentControl>("customvoid").Content.GetType()));
Assert.True(typeof(Delegate).IsAssignableFrom(window.FindControl<ContentControl>("customint").Content.GetType()));
Assert.IsAssignableFrom(typeof(Action), window.GetControl<ContentControl>("action").Content);
Assert.IsAssignableFrom(typeof(Func<int>), window.GetControl<ContentControl>("func").Content);
Assert.IsAssignableFrom(typeof(Action<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>), window.GetControl<ContentControl>("action16").Content);
Assert.IsAssignableFrom(typeof(Func<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>), window.GetControl<ContentControl>("func16").Content);
Assert.True(typeof(Delegate).IsAssignableFrom(window.GetControl<ContentControl>("customvoid").Content!.GetType()));
Assert.True(typeof(Delegate).IsAssignableFrom(window.GetControl<ContentControl>("customint").Content!.GetType()));
}
}
@ -1634,7 +1636,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<Button Name='button' Command='{CompiledBinding Method}'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var button = window.FindControl<Button>("button");
var button = window.GetControl<Button>("button");
var vm = new MethodAsCommandDataContext();
button.DataContext = vm;
@ -1659,7 +1661,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<Button Name='button' Command='{CompiledBinding Method1}' CommandParameter='5'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var button = window.FindControl<Button>("button");
var button = window.GetControl<Button>("button");
var vm = new MethodAsCommandDataContext();
button.DataContext = vm;
@ -1684,7 +1686,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Name='textBlock' Text='{CompiledBinding Method}'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var vm = new MethodAsCommandDataContext();
textBlock.DataContext = vm;
@ -1710,7 +1712,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<Button Name='button' Command='{CompiledBinding Do}' CommandParameter='{CompiledBinding Parameter, Mode=OneTime}'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var button = window.FindControl<Button>("button");
var button = window.GetControl<Button>("button");
var vm = new MethodAsCommandDataContext()
{
Parameter = commandParameter
@ -1738,7 +1740,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<Button Name='button' Command='{CompiledBinding Do}'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var button = window.FindControl<Button>("button");
var button = window.GetControl<Button>("button");
var vm = new MethodAsCommandDataContext()
{
Parameter = null,
@ -1770,7 +1772,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
x:DataType='local:TestDataContext'
X='{CompiledBinding StringProperty}' />";
var control = (AssignBindingControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var compiledPath = ((CompiledBindingExtension)control.X).Path;
var compiledPath = ((CompiledBindingExtension)control.X!).Path;
var node = Assert.IsType<PropertyElement>(Assert.Single(compiledPath.Elements));
Assert.Equal(typeof(string), node.Property.PropertyType);
@ -1788,7 +1790,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
X='{CompiledBinding StringProperty, DataType=local:TestDataContext}' />";
var control = (AssignBindingControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var compiledPath = ((CompiledBindingExtension)control.X).Path;
var compiledPath = ((CompiledBindingExtension)control.X!).Path;
var node = Assert.IsType<PropertyElement>(Assert.Single(compiledPath.Elements));
Assert.Equal(typeof(string), node.Property.PropertyType);
@ -1807,7 +1809,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
X='{CompiledBinding StringProperty, DataType=local:TestDataContext}' />";
var control = (AssignBindingControl)AvaloniaRuntimeXamlLoader.Load(new RuntimeXamlLoaderDocument(xaml),
new RuntimeXamlLoaderConfiguration { UseCompiledBindingsByDefault = true });
var compiledPath = ((CompiledBindingExtension)control.X).Path;
var compiledPath = ((CompiledBindingExtension)control.X!).Path;
var node = Assert.IsType<PropertyElement>(Assert.Single(compiledPath.Elements));
Assert.Equal(typeof(string), node.Property.PropertyType);
@ -1830,7 +1832,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<ComboBox x:Name='comboBox' ItemsSource='{Binding GenericProperty}' SelectedItem='{Binding GenericProperty.CurrentItem}' />
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var comboBox = window.FindControl<ComboBox>("comboBox");
var comboBox = window.GetControl<ComboBox>("comboBox");
var dataContext = new TestDataContext();
dataContext.GenericProperty.Add(123);
@ -1857,7 +1859,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
<TextBlock Name='textBlock' Text='{{Binding DecimalValue, StringFormat=c2}}'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
var textBlock = window.GetControl<TextBlock>("textBlock");
var dataContext = new TestDataContext();
window.DataContext = dataContext;
@ -1887,7 +1889,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
public interface IHasProperty
{
string StringProperty { get; set; }
string? StringProperty { get; set; }
}
public interface IHasPropertyDerived : IHasProperty
@ -1902,34 +1904,34 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
{
public static IValueConverter Instance { get; } = new AppendConverter();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
=> string.Format("{0}+{1}+{2}", value, parameter, culture);
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
=> throw new NotImplementedException();
}
public class TestData
{
public string StringProperty { get; set; }
public string? StringProperty { get; set; }
}
public class TestDataContextBaseClass {}
public class TestDataContext : TestDataContextBaseClass, IHasPropertyDerived, IHasExplicitProperty
{
public string StringProperty { get; set; }
public string? StringProperty { get; set; }
public Task<string> TaskProperty { get; set; }
public Task<string>? TaskProperty { get; set; }
public IObservable<string> ObservableProperty { get; set; }
public IObservable<string>? ObservableProperty { get; set; }
public ObservableCollection<string> ObservableCollectionProperty { get; set; } = new ObservableCollection<string>();
public string[] ArrayProperty { get; set; }
public string[]? ArrayProperty { get; set; }
public object[] ObjectsArrayProperty { get; set; }
public object[]? ObjectsArrayProperty { get; set; }
public List<string> ListProperty { get; set; } = new List<string>();
@ -1966,7 +1968,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
public class ListItemCollectionView<T> : List<T>
{
public T CurrentItem { get; set; }
public T? CurrentItem { get; set; }
}
public class MethodDataContext
@ -1983,15 +1985,16 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
public class MethodAsCommandDataContext : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangedEventHandler? PropertyChanged;
public string Method() => Value = "Called";
public string Method1(int i) => Value = $"Called {i}";
public string Method2(int i, int j) => Value = $"Called {i},{j}";
public string Value { get; private set; } = "Not called";
object _parameter;
public object Parameter
private object? _parameter;
public object? Parameter
{
get => _parameter;
set
@ -2010,7 +2013,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
Value = $"Do {parameter}";
}
[Metadata.DependsOn(nameof(Parameter))]
[DependsOn(nameof(Parameter))]
public bool CanDo(object parameter)
{
return ReferenceEquals(null, Parameter) == false;
@ -2020,22 +2023,22 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
public class CustomDataTemplate : IDataTemplate
{
[DataType]
public Type FancyDataType { get; set; }
public Type? FancyDataType { get; set; }
[Content]
[TemplateContent]
public object Content { get; set; }
public object? Content { get; set; }
public bool Match(object data) => FancyDataType?.IsInstanceOfType(data) ?? true;
public bool Match(object? data) => FancyDataType?.IsInstanceOfType(data) ?? true;
public Control Build(object data) => TemplateContent.Load(Content)?.Result;
public Control? Build(object? data) => TemplateContent.Load(Content)?.Result;
}
public class CustomDataTemplateInherit : CustomDataTemplate { }
public class AssignBindingControl : Control
{
[AssignBinding] public IBinding X { get; set; }
[AssignBinding] public IBinding? X { get; set; }
}
public class DataGridLikeControl : Control
@ -2046,8 +2049,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
x => x.Items,
(x, v) => x.Items = v);
private IEnumerable _items;
public IEnumerable Items
private IEnumerable? _items;
public IEnumerable? Items
{
get => _items;
set => SetAndRaise(ItemsProperty, ref _items, value);
@ -2060,9 +2064,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
{
[AssignBinding]
[InheritDataTypeFromItems(nameof(DataGridLikeControl.Items), AncestorType = typeof(DataGridLikeControl))]
public IBinding Binding { get; set; }
public IBinding? Binding { get; set; }
[InheritDataTypeFromItems(nameof(DataGridLikeControl.Items), AncestorType = typeof(DataGridLikeControl))]
public IDataTemplate Template { get; set; }
public IDataTemplate? Template { get; set; }
}
}

19
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/ResourceIncludeTests.cs

@ -1,8 +1,9 @@
using System;
#nullable enable
using System;
using System.Collections.Generic;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Metadata;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Xunit;
@ -40,9 +41,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
{
var compiled = AvaloniaRuntimeXamlLoader.LoadGroup(documents);
var userControl = Assert.IsType<UserControl>(compiled[1]);
var border = userControl.FindControl<Border>("border");
var border = userControl.GetControl<Border>("border");
var brush = (ISolidColorBrush)border.Background;
var brush = (ISolidColorBrush)border.Background!;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
}
@ -130,17 +131,21 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
{
private readonly Dictionary<object, IResourceProvider> _langs = new();
public IResourceHost Owner { get; private set; }
public IResourceHost? Owner { get; private set; }
public bool HasResources => true;
public event EventHandler OwnerChanged;
public event EventHandler? OwnerChanged
{
add { }
remove { }
}
public void AddOwner(IResourceHost owner) => Owner = owner;
public void RemoveOwner(IResourceHost owner) => Owner = null;
public bool TryGetResource(object key, ThemeVariant theme, out object? value)
public bool TryGetResource(object key, ThemeVariant? theme, out object? value)
{
if (_langs.TryGetValue("English", out var res))
{

14
tests/Avalonia.RenderTests/Media/BitmapTests.cs

@ -1,16 +1,16 @@
#nullable enable
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Avalonia.Controls;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Controls.Shapes;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Xunit;
using Path = System.IO.Path;
#pragma warning disable CS0649
#if AVALONIA_SKIA
@ -69,7 +69,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
var fmt = new PixelFormat(fmte);
var testName = nameof(FramebufferRenderResultsShouldBeUsableAsBitmap) + "_" + fmt;
var fb = new Framebuffer(fmt, new PixelSize(80, 80));
var r = Avalonia.AvaloniaLocator.Current.GetRequiredService<IPlatformRenderInterface>();
var r = AvaloniaLocator.Current.GetRequiredService<IPlatformRenderInterface>();
using(var cpuContext = r.CreateBackendContext(null))
using (var target = cpuContext.CreateRenderTarget(new object[] { fb }))
using (var ctx = target.CreateDrawingContext())
@ -94,7 +94,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
var rc = new Rect(0, 0, 60, 60);
ctx.DrawBitmap(bmp.PlatformImpl, 1, rc, rc);
}
rtb.Save(System.IO.Path.Combine(OutputPath, testName + ".out.png"));
rtb.Save(Path.Combine(OutputPath, testName + ".out.png"));
}
CompareImagesNoRenderer(testName);
}
@ -123,7 +123,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
var name = nameof(WriteableBitmapShouldBeUsable) + "_" + fmt;
writeableBitmap.Save(System.IO.Path.Combine(OutputPath, name + ".out.png"));
writeableBitmap.Save(Path.Combine(OutputPath, name + ".out.png"));
CompareImagesNoRenderer(name);
}
@ -177,7 +177,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
var testName = nameof(BitmapsShouldSupportTranscoders_Lenna) + "_" + formatName + names[step];
var path = System.IO.Path.Combine(OutputPath, testName + ".out.png");
var path = Path.Combine(OutputPath, testName + ".out.png");
fixed (byte* pData = data)
{
Bitmap? b = null;

2
tests/Avalonia.RenderTests/Media/TileBrushTests.cs

@ -44,7 +44,6 @@ public class DrawingBrushTests: TestBase
#if AVALONIA_SKIA
[Fact]
#endif
public async Task DrawingBrushIsProperlyUpscaled()
{
Decorator target = new Decorator
@ -66,6 +65,7 @@ public class DrawingBrushTests: TestBase
await RenderToFile(target);
CompareImages();
}
#endif
GeometryDrawing CreateDrawing()
{

4
tests/Avalonia.RenderTests/TestBase.cs

@ -83,7 +83,7 @@ namespace Avalonia.Direct2D1.RenderTests
get;
}
protected async Task RenderToFile(Control target, [CallerMemberName] string testName = "", double dpi = 96)
protected Task RenderToFile(Control target, [CallerMemberName] string testName = "", double dpi = 96)
{
if (!Directory.Exists(OutputPath))
{
@ -124,6 +124,8 @@ namespace Avalonia.Direct2D1.RenderTests
}
writableBitmap.Save(compositedPath);
}
return Task.CompletedTask;
}
class BitmapFramebufferSurface : IFramebufferPlatformSurface

89
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs

@ -1,8 +1,9 @@
using System;
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Media.TextFormatting;
using Avalonia.Media.TextFormatting.Unicode;
using Avalonia.UnitTests;
@ -30,10 +31,14 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine = formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
Assert.Single(textLine.TextRuns);
var textRun = textLine.TextRuns[0];
Assert.NotNull(textRun.Properties);
Assert.Equal(defaultProperties.Typeface, textRun.Properties.Typeface);
Assert.Equal(defaultProperties.ForegroundBrush, textRun.Properties.ForegroundBrush);
@ -57,6 +62,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine = formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
Assert.Equal(5, textLine.TextRuns.Count);
Assert.Equal(50, textLine.Length);
@ -120,6 +127,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine = formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
Assert.Equal(5, textLine.TextRuns.Count);
Assert.Equal(14, textLine.Length);
@ -153,6 +162,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine = formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
Assert.Equal(text.Length, textLine.Length);
for (var i = 0; i < GenericTextRunPropertiesRuns.Length; i++)
@ -186,6 +197,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
Assert.Equal(numberOfRuns, textLine.TextRuns.Count);
}
}
@ -207,6 +220,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
Assert.Equal(1, textLine.TextRuns.Count);
}
}
@ -228,6 +243,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var firstRun = textLine.TextRuns[0];
Assert.Equal(4, firstRun.Length);
@ -249,7 +266,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var formatter = new TextFormatterImpl();
var line = formatter.FormatLine(textSource, 0, 33, paragraphProperties);
formatter.FormatLine(textSource, 0, 33, paragraphProperties);
textSource = new SingleBufferTextSource(text, defaultProperties);
@ -262,6 +279,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine =
formatter.FormatLine(textSource, currentPosition, 1, paragraphProperties);
Assert.NotNull(textLine);
if (text.Length - currentPosition > expectedCharactersPerLine)
{
Assert.Equal(expectedCharactersPerLine, textLine.Length);
@ -318,6 +337,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, currentPosition, paragraphWidth,
new GenericTextParagraphProperties(defaultProperties, textWrap: TextWrapping.Wrap));
Assert.NotNull(textLine);
var end = textLine.FirstTextSourceIndex + textLine.Length - 1;
Assert.True(expected.Contains(end));
@ -351,6 +372,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties, lineHeight: 50));
Assert.NotNull(textLine);
Assert.Equal(50, textLine.Height);
}
}
@ -381,6 +404,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine =
formatter.FormatLine(textSource, textSourceIndex, 200, paragraphProperties);
Assert.NotNull(textLine);
Assert.True(textLine.Width <= 200);
textSourceIndex += textLine.Length;
@ -407,6 +432,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine =
formatter.FormatLine(textSource, textSourceIndex, 3, paragraphProperties);
Assert.NotNull(textLine);
Assert.NotEqual(0, textLine.Length);
textSourceIndex += textLine.Length;
@ -454,6 +481,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, currentPosition, 300,
new GenericTextParagraphProperties(defaultProperties, textWrap: TextWrapping.WrapWithOverflow));
Assert.NotNull(textLine);
currentPosition += textLine.Length;
if (textLine.Width > 300 || currentHeight + textLine.Height > 240)
@ -502,6 +531,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine =
formatter.FormatLine(textSource, 0, 100, paragraphProperties);
Assert.NotNull(textLine);
var expectedOffset = 0d;
switch (textAlignment)
@ -534,13 +565,15 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var formatter = new TextFormatterImpl();
var textPosition = 87;
TextLineBreak lastBreak = null;
TextLineBreak? lastBreak = null;
while (textPosition < text.Length)
{
var textLine =
formatter.FormatLine(textSource, textPosition, 50, paragraphProperties, lastBreak);
Assert.NotNull(textLine);
Assert.Equal(textLine.Length, textLine.TextRuns.Sum(x => x.Length));
textPosition += textLine.Length;
@ -564,6 +597,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine =
formatter.FormatLine(textSource, 0, 33, paragraphProperties);
Assert.NotNull(textLine);
var remainingRunsLineBreak = Assert.IsType<WrappingTextLineBreak>(textLine.TextLineBreak);
var remainingRuns = remainingRunsLineBreak.AcquireRemainingRuns();
Assert.NotNull(remainingRuns);
@ -592,6 +627,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var expectedTextLine = formatter.FormatLine(new SingleBufferTextSource(text, defaultProperties),
0, double.PositiveInfinity, paragraphProperties);
Assert.NotNull(expectedTextLine);
var expectedRuns = expectedTextLine.TextRuns.Cast<ShapedTextRun>().ToList();
var expectedGlyphs = expectedRuns
@ -613,6 +650,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine =
formatter.FormatLine(textSource, 0, double.PositiveInfinity, paragraphProperties);
Assert.NotNull(textLine);
var shapedRuns = textLine.TextRuns.Cast<ShapedTextRun>().ToList();
var actualGlyphs = shapedRuns
@ -637,6 +676,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine =
TextFormatter.Current.FormatLine(textSource, 0, double.PositiveInfinity, paragraphProperties);
Assert.NotNull(textLine);
Assert.Equal(3, textLine.TextRuns.Count);
Assert.True(textLine.TextRuns[1] is RectangleRun);
@ -655,6 +696,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine =
TextFormatter.Current.FormatLine(textSource, 0, double.PositiveInfinity, paragraphProperties);
Assert.NotNull(textLine);
Assert.NotNull(textLine.TextLineBreak);
Assert.Equal(TextRun.DefaultTextSourceLength, textLine.Length);
@ -690,20 +733,22 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var pos = 0;
TextLineBreak previousLineBreak = null;
TextLine textLine = null;
TextLineBreak? previousLineBreak = null;
TextLine? textLine = null;
while (pos < text.Length)
{
textLine = TextFormatter.Current.FormatLine(textSource, pos, 30, paragraphProperties, previousLineBreak);
Assert.NotNull(textLine);
pos += textLine.Length;
previousLineBreak = textLine.TextLineBreak;
}
Assert.NotNull(textLine);
Assert.NotNull(textLine.TextLineBreak);
Assert.NotNull(textLine.TextLineBreak.TextEndOfLine);
}
}
@ -729,6 +774,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine =
TextFormatter.Current.FormatLine(source, 0, double.PositiveInfinity, paragraphProperties);
Assert.NotNull(textLine);
void VerifyHit(int offset)
{
var glyphCenter = textLine.GetTextBounds(offset, 1)[0].Rectangle.Center;
@ -756,6 +803,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine =
TextFormatter.Current.FormatLine(source, 0, double.PositiveInfinity, paragraphProperties);
Assert.NotNull(textLine);
var bounds = textLine.GetTextBounds(0, 3);
Assert.Equal(1, bounds.Count);
@ -779,6 +828,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{
var source = new ListTextSource(new RectangleRun(new Rect(0, 0, 200, 10), Brushes.Aqua));
var textLine = TextFormatter.Current.FormatLine(source, 0, 100, paragraphProperties);
Assert.NotNull(textLine);
Assert.Equal(200d, textLine.WidthIncludingTrailingWhitespace);
}
}
@ -822,6 +872,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
if (textLine.TextLineBreak is {} eol && eol.TextEndOfLine is TextEndOfParagraph)
break;
}
Assert.NotEmpty(lines);
}
}
@ -832,13 +884,13 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
DefaultTextRunProperties = defaultTextRunProperties;
}
public override FlowDirection FlowDirection { get; }
public override TextAlignment TextAlignment { get; }
public override double LineHeight { get; }
public override bool FirstLineInParagraph { get; }
public override FlowDirection FlowDirection => default;
public override TextAlignment TextAlignment => default;
public override double LineHeight => default;
public override bool FirstLineInParagraph => default;
public override TextRunProperties DefaultTextRunProperties { get; }
public override TextWrapping TextWrapping { get; }
public override double Indent { get; }
public override TextWrapping TextWrapping => default;
public override double Indent => default;
public override double DefaultIncrementalTab => 64;
}
@ -858,12 +910,12 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var source = new ListTextSource(text);
var textLine = TextFormatter.Current.FormatLine(source, 0, double.PositiveInfinity, paragraphProperties);
Assert.NotNull(textLine);
var backspaceHit = textLine.GetBackspaceCaretCharacterHit(new CharacterHit(2));
Assert.Equal(1, backspaceHit.FirstCharacterIndex);
Assert.Equal(0, backspaceHit.TrailingLength);
}
}
[Fact]
@ -878,6 +930,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
var textLine = TextFormatter.Current.FormatLine(new SimpleTextSource(text, defaultRunProperties), 0, 120, paragraphProperties);
Assert.NotNull(textLine);
Assert.Equal(3, textLine.TextRuns.Count);
}
}
@ -913,7 +966,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
private class EmptyTextSource : ITextSource
{
public TextRun GetTextRun(int textSourceIndex)
public TextRun? GetTextRun(int textSourceIndex)
{
return null;
}
@ -936,7 +989,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
_text = text;
}
public TextRun GetTextRun(int textSourceIndex)
public TextRun? GetTextRun(int textSourceIndex)
{
if (textSourceIndex >= _text.Length + TextRun.DefaultTextSourceLength + _text.Length)
{
@ -954,7 +1007,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
private class ListTextSource : ITextSource
{
private List<TextRun> _runs = new();
private readonly List<TextRun> _runs;
public ListTextSource(params TextRun[] runs) : this((IEnumerable<TextRun>)runs)
{
@ -966,7 +1019,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
_runs = runs.ToList();
}
public TextRun GetTextRun(int textSourceIndex)
public TextRun? GetTextRun(int textSourceIndex)
{
var off = 0;
for (var c = 0; c < _runs.Count; c++)

78
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs

@ -1,4 +1,6 @@
using System;
#nullable enable
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@ -33,6 +35,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, currentIndex, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var firstCharacterHit = textLine.GetPreviousCaretCharacterHit(new CharacterHit(int.MinValue));
Assert.Equal(textLine.FirstTextSourceIndex, firstCharacterHit.FirstCharacterIndex);
@ -61,6 +65,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, currentIndex, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var lastCharacterHit = textLine.GetNextCaretCharacterHit(new CharacterHit(int.MaxValue));
Assert.Equal(textLine.FirstTextSourceIndex + textLine.Length,
@ -88,6 +94,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var clusters = new List<int>();
foreach (var textRun in textLine.TextRuns.OrderBy(x => TextTestHelper.GetStartCharIndex(x.Text)))
@ -135,6 +143,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var clusters = new List<int>();
foreach (var textRun in textLine.TextRuns.OrderBy(x => TextTestHelper.GetStartCharIndex(x.Text)))
@ -187,6 +197,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var clusters = BuildGlyphClusters(textLine);
var nextCharacterHit = new CharacterHit(0);
@ -246,6 +258,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var clusters = textLine.TextRuns
.Cast<ShapedTextRun>()
.SelectMany(x => x.ShapedBuffer, (_, glyph) => glyph.GlyphCluster)
@ -296,6 +310,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var currentDistance = 0.0;
foreach (var run in textLine.TextRuns)
@ -341,6 +357,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var isRightToLeft = IsRightToLeft(textLine);
var rects = BuildRects(textLine);
var glyphClusters = BuildGlyphClusters(textLine);
@ -394,6 +412,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
Assert.False(textLine.HasCollapsed);
TextCollapsingProperties collapsingProperties = trimming.CreateCollapsingProperties(new TextCollapsingCreateInfo(width, defaultProperties, FlowDirection.LeftToRight));
@ -427,6 +447,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
Assert.Equal(4, textLine.TextRuns.Count);
var currentHit = textLine.GetNextCaretCharacterHit(new CharacterHit(0));
@ -465,6 +487,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
Assert.Equal(4, textLine.TextRuns.Count);
var currentHit = textLine.GetPreviousCaretCharacterHit(new CharacterHit(3, 1));
@ -503,6 +527,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var characterHit = textLine.GetCharacterHitFromDistance(50);
Assert.Equal(5, characterHit.FirstCharacterIndex);
@ -529,6 +555,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var distance = textLine.GetDistanceFromCharacterHit(new CharacterHit(1));
Assert.Equal(14, distance);
@ -553,6 +581,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var distance = textLine.GetDistanceFromCharacterHit(new CharacterHit(10));
Assert.Equal(72.01171875, distance);
@ -585,6 +615,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var textBounds = textLine.GetTextBounds(0, 10);
Assert.Equal(1, textBounds.Count);
@ -625,6 +657,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var textBounds = textLine.GetTextBounds(0, Environment.NewLine.Length);
Assert.Equal(1, textBounds.Count);
@ -652,13 +686,15 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var textRuns = textLine.TextRuns.Cast<ShapedTextRun>().ToList();
var lineWidth = textLine.WidthIncludingTrailingWhitespace;
var textBounds = textLine.GetTextBounds(0, text.Length);
TextBounds lastBounds = null;
TextBounds? lastBounds = null;
var runBounds = textBounds.SelectMany(x => x.TextRunBounds).ToList();
@ -711,6 +747,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, 1000,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var characterHit = textLine.GetCharacterHitFromDistance(1000);
Assert.Equal(10, characterHit.FirstCharacterIndex);
@ -732,6 +770,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var characterHit = textLine.GetNextCaretCharacterHit(new CharacterHit(9, 1));
Assert.Equal(10, characterHit.FirstCharacterIndex);
@ -784,6 +824,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var characterHit = textLine.GetPreviousCaretCharacterHit(new CharacterHit(20, 1));
Assert.Equal(20, characterHit.FirstCharacterIndex);
@ -836,6 +878,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 20, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var characterHit = textLine.GetCharacterHitFromDistance(double.PositiveInfinity);
Assert.Equal(40, characterHit.FirstCharacterIndex + characterHit.TrailingLength);
@ -866,7 +910,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
{
private const string Text = "_A_A";
public TextRun GetTextRun(int textSourceIndex)
public TextRun? GetTextRun(int textSourceIndex)
{
switch (textSourceIndex)
{
@ -1004,6 +1048,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(defaultProperties));
Assert.NotNull(textLine);
var textBounds = textLine.GetTextBounds(0, textLine.Length);
Assert.Equal(1, textBounds.Count);
@ -1047,16 +1093,18 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
new GenericTextParagraphProperties(FlowDirection.LeftToRight, TextAlignment.Left,
true, true, defaultProperties, TextWrapping.NoWrap, 0, 0, 0));
Assert.NotNull(textLine);
var textBounds = textLine.GetTextBounds(0, 3);
var firstRun = textLine.TextRuns[0] as ShapedTextRun;
var firstRun = Assert.IsType<ShapedTextRun>(textLine.TextRuns[0]);
Assert.Equal(1, textBounds.Count);
Assert.Equal(firstRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width));
textBounds = textLine.GetTextBounds(3, 4);
var secondRun = textLine.TextRuns[1] as ShapedTextRun;
var secondRun = Assert.IsType<ShapedTextRun>(textLine.TextRuns[1]);
Assert.Equal(1, textBounds.Count);
Assert.Equal(secondRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width));
@ -1094,16 +1142,18 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
new GenericTextParagraphProperties(FlowDirection.RightToLeft, TextAlignment.Left,
true, true, defaultProperties, TextWrapping.NoWrap, 0, 0, 0));
Assert.NotNull(textLine);
var textBounds = textLine.GetTextBounds(0, 4);
var secondRun = textLine.TextRuns[1] as ShapedTextRun;
var secondRun = Assert.IsType<ShapedTextRun>(textLine.TextRuns[1]);
Assert.Equal(1, textBounds.Count);
Assert.Equal(secondRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width));
textBounds = textLine.GetTextBounds(4, 3);
var firstRun = textLine.TextRuns[0] as ShapedTextRun;
var firstRun = Assert.IsType<ShapedTextRun>(textLine.TextRuns[0]);
Assert.Equal(1, textBounds.Count);
@ -1146,6 +1196,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
new GenericTextParagraphProperties(FlowDirection.LeftToRight, TextAlignment.Left,
true, true, defaultProperties, TextWrapping.NoWrap, 0, 0, 0));
Assert.NotNull(textLine);
var textBounds = textLine.GetTextBounds(0, 1);
Assert.Equal(1, textBounds.Count);
@ -1173,6 +1225,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
new GenericTextParagraphProperties(FlowDirection.LeftToRight, TextAlignment.Left,
true, true, defaultProperties, TextWrapping.NoWrap, 0, 0, 0));
Assert.NotNull(textLine);
var textBounds = textLine.GetTextBounds(3, 1);
Assert.Equal(1, textBounds.Count);
@ -1200,6 +1254,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
new GenericTextParagraphProperties(FlowDirection.LeftToRight, TextAlignment.Left,
true, true, defaultProperties, TextWrapping.NoWrap, 0, 0, 0));
Assert.NotNull(textLine);
var bounds = textLine.GetTextBounds(6, 1);
Assert.Equal(1, bounds.Count);
@ -1249,6 +1305,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
new GenericTextParagraphProperties(FlowDirection.LeftToRight, TextAlignment.Left,
true, true, defaultProperties, TextWrapping.NoWrap, 0, 0, 0));
Assert.NotNull(textLine);
var bounds = textLine.GetTextBounds(0, text.Length);
Assert.Equal(4, bounds.Count);
@ -1259,8 +1317,6 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
}
}
[Fact]
public void Should_GetPreviousCharacterHit_Non_Trailing()
{
@ -1278,6 +1334,8 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
new GenericTextParagraphProperties(FlowDirection.LeftToRight, TextAlignment.Left,
true, true, defaultProperties, TextWrapping.NoWrap, 0, 0, 0));
Assert.NotNull(textLine);
var characterHit = textLine.GetPreviousCaretCharacterHit(new CharacterHit(10, 1));
}
}
@ -1291,7 +1349,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
_textRuns = textRuns;
}
public TextRun GetTextRun(int textSourceIndex)
public TextRun? GetTextRun(int textSourceIndex)
{
var currentPosition = 0;

Loading…
Cancel
Save