From 1ee1509352e6146b6bc4ed114482a6bd18550bcc Mon Sep 17 00:00:00 2001 From: Julien Lebosquain Date: Tue, 27 Jan 2026 12:55:05 +0000 Subject: [PATCH] Fixes several simple TODO12 (#20544) * Remove obsolete TextInputMethodClient.ShowInputPanel method * Merge Move and Move private in KeyboardNavigationHandler * Change Inline.TextDecorations type to AttachedProperty * Change TextSearch.GetText/SetText parameter to Interactive * Remove Design.SetPreviewWith overload * Replace JSWebWorkerClone with JSWebWorker * Remove StringTokenizer * Update API suppressions * Add reflection comment to RenderWorker --- api/Avalonia.nupkg.xml | 108 ++++++++ .../Input/IKeyboardNavigationHandler.cs | 6 +- .../Input/KeyboardNavigationHandler.cs | 22 +- .../Input/TextInput/TextInputMethodClient.cs | 7 - .../Utilities/StringTokenizer.cs | 245 ------------------ .../Avalonia.Build.Tasks.csproj | 3 - src/Avalonia.Controls/Design.cs | 16 -- src/Avalonia.Controls/Documents/Inline.cs | 3 +- .../Primitives/TextSearch.cs | 6 +- .../Rendering/RenderWorker.cs | 111 +------- .../Utilities/StringTokenizerTests.cs | 81 ------ 11 files changed, 134 insertions(+), 474 deletions(-) delete mode 100644 src/Avalonia.Base/Utilities/StringTokenizer.cs delete mode 100644 tests/Avalonia.Base.UnitTests/Utilities/StringTokenizerTests.cs diff --git a/api/Avalonia.nupkg.xml b/api/Avalonia.nupkg.xml index 32ab43f84f..f8b5337574 100644 --- a/api/Avalonia.nupkg.xml +++ b/api/Avalonia.nupkg.xml @@ -19,6 +19,12 @@ baseline/Avalonia/lib/net10.0/Avalonia.Base.dll current/Avalonia/lib/net10.0/Avalonia.Base.dll + + CP0001 + T:Avalonia.Utilities.StringTokenizer + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + CP0001 T:Avalonia.Controls.Primitives.IScrollable @@ -49,6 +55,12 @@ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll current/Avalonia/lib/net8.0/Avalonia.Base.dll + + CP0001 + T:Avalonia.Utilities.StringTokenizer + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + CP0001 T:Avalonia.Controls.Primitives.IScrollable @@ -73,6 +85,24 @@ baseline/Avalonia/lib/net10.0/Avalonia.Base.dll current/Avalonia/lib/net10.0/Avalonia.Base.dll + + CP0002 + M:Avalonia.Input.IKeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Input.KeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Input.TextInput.TextInputMethodClient.ShowInputPanel + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + CP0002 M:Avalonia.Media.DrawingImage.get_Viewbox @@ -181,6 +211,12 @@ baseline/Avalonia/lib/net10.0/Avalonia.Base.dll current/Avalonia/lib/net10.0/Avalonia.Base.dll + + CP0002 + F:Avalonia.Controls.Documents.Inline.TextDecorationsProperty + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + CP0002 F:Avalonia.Controls.TextBlock.LetterSpacingProperty @@ -223,6 +259,12 @@ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + CP0002 + M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.AvaloniaObject,Avalonia.Controls.Control) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + CP0002 M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.AvaloniaObject,Avalonia.Controls.ITemplate{Avalonia.Controls.Control}) @@ -259,6 +301,18 @@ baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + CP0002 + M:Avalonia.Controls.Primitives.TextSearch.GetText(Avalonia.Controls.Control) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Primitives.TextSearch.SetText(Avalonia.Controls.Control,System.String) + baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll + current/Avalonia/lib/net10.0/Avalonia.Controls.dll + CP0002 M:Avalonia.Platform.Screen.#ctor(System.Double,Avalonia.PixelRect,Avalonia.PixelRect,System.Boolean) @@ -343,6 +397,24 @@ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll current/Avalonia/lib/net8.0/Avalonia.Base.dll + + CP0002 + M:Avalonia.Input.IKeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Input.KeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + + + CP0002 + M:Avalonia.Input.TextInput.TextInputMethodClient.ShowInputPanel + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + CP0002 M:Avalonia.Media.DrawingImage.get_Viewbox @@ -451,6 +523,12 @@ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll current/Avalonia/lib/net8.0/Avalonia.Base.dll + + CP0002 + F:Avalonia.Controls.Documents.Inline.TextDecorationsProperty + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + CP0002 F:Avalonia.Controls.TextBlock.LetterSpacingProperty @@ -493,6 +571,12 @@ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + CP0002 + M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.AvaloniaObject,Avalonia.Controls.Control) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + CP0002 M:Avalonia.Controls.Design.SetPreviewWith(Avalonia.AvaloniaObject,Avalonia.Controls.ITemplate{Avalonia.Controls.Control}) @@ -529,6 +613,18 @@ baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + CP0002 + M:Avalonia.Controls.Primitives.TextSearch.GetText(Avalonia.Controls.Control) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + + + CP0002 + M:Avalonia.Controls.Primitives.TextSearch.SetText(Avalonia.Controls.Control,System.String) + baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll + current/Avalonia/lib/net8.0/Avalonia.Controls.dll + CP0002 M:Avalonia.Platform.Screen.#ctor(System.Double,Avalonia.PixelRect,Avalonia.PixelRect,System.Boolean) @@ -619,6 +715,12 @@ baseline/netstandard2.0/Avalonia.Base.dll target/netstandard2.0/Avalonia.Base.dll + + CP0006 + M:Avalonia.Input.IKeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers,System.Nullable{Avalonia.Input.KeyDeviceType}) + baseline/Avalonia/lib/net10.0/Avalonia.Base.dll + current/Avalonia/lib/net10.0/Avalonia.Base.dll + CP0006 M:Avalonia.Platform.IDrawingContextImpl.PopTextOptions @@ -727,6 +829,12 @@ baseline/Avalonia/lib/net6.0/Avalonia.OpenGL.dll current/Avalonia/lib/net6.0/Avalonia.OpenGL.dll + + CP0006 + M:Avalonia.Input.IKeyboardNavigationHandler.Move(Avalonia.Input.IInputElement,Avalonia.Input.NavigationDirection,Avalonia.Input.KeyModifiers,System.Nullable{Avalonia.Input.KeyDeviceType}) + baseline/Avalonia/lib/net8.0/Avalonia.Base.dll + current/Avalonia/lib/net8.0/Avalonia.Base.dll + CP0006 M:Avalonia.Input.Platform.IClipboard.SetDataAsync(Avalonia.Input.IAsyncDataTransfer) diff --git a/src/Avalonia.Base/Input/IKeyboardNavigationHandler.cs b/src/Avalonia.Base/Input/IKeyboardNavigationHandler.cs index 6ab0031f31..e82bb5d216 100644 --- a/src/Avalonia.Base/Input/IKeyboardNavigationHandler.cs +++ b/src/Avalonia.Base/Input/IKeyboardNavigationHandler.cs @@ -24,9 +24,11 @@ namespace Avalonia.Input /// The current element. /// The direction to move. /// Any key modifiers active at the time of focus. - void Move( + /// The device type used to move the focus. + bool Move( IInputElement element, NavigationDirection direction, - KeyModifiers keyModifiers = KeyModifiers.None); + KeyModifiers keyModifiers = KeyModifiers.None, + KeyDeviceType? deviceType = null); } } diff --git a/src/Avalonia.Base/Input/KeyboardNavigationHandler.cs b/src/Avalonia.Base/Input/KeyboardNavigationHandler.cs index 3444a88aba..e5e7eb0699 100644 --- a/src/Avalonia.Base/Input/KeyboardNavigationHandler.cs +++ b/src/Avalonia.Base/Input/KeyboardNavigationHandler.cs @@ -98,22 +98,12 @@ namespace Avalonia.Input return result; } - /// - /// Moves the focus in the specified direction. - /// - /// The current element. - /// The direction to move. - /// Any key modifiers active at the time of focus. - public void Move( + /// + public bool Move( IInputElement? element, NavigationDirection direction, - KeyModifiers keyModifiers = KeyModifiers.None) - { - MovePrivate(element, direction, keyModifiers, null); - } - - // TODO12: remove MovePrivate, and make Move return boolean. Or even remove whole KeyboardNavigationHandler. - private bool MovePrivate(IInputElement? element, NavigationDirection direction, KeyModifiers keyModifiers, KeyDeviceType? deviceType) + KeyModifiers keyModifiers = KeyModifiers.None, + KeyDeviceType? deviceType = null) { var next = GetNextPrivate(element, _owner, direction, deviceType); @@ -140,7 +130,7 @@ namespace Avalonia.Input var current = FocusManager.GetFocusManager(e.Source as IInputElement)?.GetFocusedElement(); var direction = (e.KeyModifiers & KeyModifiers.Shift) == 0 ? NavigationDirection.Next : NavigationDirection.Previous; - e.Handled = MovePrivate(current, direction, e.KeyModifiers, e.KeyDeviceType); + e.Handled = Move(current, direction, e.KeyModifiers, e.KeyDeviceType); } else if (e.Key is Key.Left or Key.Right or Key.Up or Key.Down) { @@ -153,7 +143,7 @@ namespace Avalonia.Input Key.Down => NavigationDirection.Down, _ => throw new ArgumentOutOfRangeException() }; - e.Handled = MovePrivate(current, direction, e.KeyModifiers, e.KeyDeviceType); + e.Handled = Move(current, direction, e.KeyModifiers, e.KeyDeviceType); } } diff --git a/src/Avalonia.Base/Input/TextInput/TextInputMethodClient.cs b/src/Avalonia.Base/Input/TextInput/TextInputMethodClient.cs index 7f9870315b..36e14cd3fd 100644 --- a/src/Avalonia.Base/Input/TextInput/TextInputMethodClient.cs +++ b/src/Avalonia.Base/Input/TextInput/TextInputMethodClient.cs @@ -82,13 +82,6 @@ namespace Avalonia.Input.TextInput { SetPreeditText(preeditText); } - - //TODO12: remove - [Obsolete] - public virtual void ShowInputPanel() - { - RaiseInputPaneActivationRequested(); - } protected virtual void RaiseTextViewVisualChanged() { diff --git a/src/Avalonia.Base/Utilities/StringTokenizer.cs b/src/Avalonia.Base/Utilities/StringTokenizer.cs deleted file mode 100644 index e83ef8c479..0000000000 --- a/src/Avalonia.Base/Utilities/StringTokenizer.cs +++ /dev/null @@ -1,245 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using static System.Char; - -namespace Avalonia.Utilities -{ - // TODO12: Remove this struct in 12.0 (breaking change) - - [Obsolete("This type has been superseded by SpanStringTokenizer.")] -#if !BUILDTASK - public -#endif - record struct StringTokenizer : IDisposable - { - private const char DefaultSeparatorChar = ','; - - private readonly string _s; - private readonly int _length; - private readonly char _separator; - private readonly string? _exceptionMessage; - private readonly IFormatProvider _formatProvider; - private int _index; - private int _tokenIndex; - private int _tokenLength; - - public StringTokenizer(string s, IFormatProvider formatProvider, string? exceptionMessage = null) - : this(s, GetSeparatorFromFormatProvider(formatProvider), exceptionMessage) - { - _formatProvider = formatProvider; - } - - public StringTokenizer(string s, char separator = DefaultSeparatorChar, string? exceptionMessage = null) - { - _s = s ?? throw new ArgumentNullException(nameof(s)); - _length = s?.Length ?? 0; - _separator = separator; - _exceptionMessage = exceptionMessage; - _formatProvider = CultureInfo.InvariantCulture; - _index = 0; - _tokenIndex = -1; - _tokenLength = 0; - - while (_index < _length && IsWhiteSpace(_s, _index)) - { - _index++; - } - } - - public string? CurrentToken => _tokenIndex < 0 ? null : _s.Substring(_tokenIndex, _tokenLength); - - public ReadOnlySpan CurrentTokenSpan => _tokenIndex < 0 ? ReadOnlySpan.Empty : _s.AsSpan().Slice(_tokenIndex, _tokenLength); - - public void Dispose() - { - if (_index != _length) - { - throw GetFormatException(); - } - } - - public bool TryReadInt32(out Int32 result, char? separator = null) - { - if (TryReadSpan(out var stringResult, separator) && - SpanHelpers.TryParseInt(stringResult, NumberStyles.Integer, _formatProvider, out result)) - { - return true; - } - else - { - result = default; - return false; - } - } - - public int ReadInt32(char? separator = null) - { - if (!TryReadInt32(out var result, separator)) - { - throw GetFormatException(); - } - - return result; - } - - public bool TryReadDouble(out double result, char? separator = null) - { - if (TryReadSpan(out var stringResult, separator) && - SpanHelpers.TryParseDouble(stringResult, NumberStyles.Float, _formatProvider, out result)) - { - return true; - } - else - { - result = default; - return false; - } - } - - public double ReadDouble(char? separator = null) - { - if (!TryReadDouble(out var result, separator)) - { - throw GetFormatException(); - } - - return result; - } - - public bool TryReadString([NotNull] out string result, char? separator = null) - { - var success = TryReadToken(separator ?? _separator); - result = CurrentTokenSpan.ToString(); - return success; - } - - public string ReadString(char? separator = null) - { - if (!TryReadString(out var result, separator)) - { - throw GetFormatException(); - } - - return result; - } - - public bool TryReadSpan(out ReadOnlySpan result, char? separator = null) - { - var success = TryReadToken(separator ?? _separator); - result = CurrentTokenSpan; - return success; - } - - public ReadOnlySpan ReadSpan(char? separator = null) - { - if (!TryReadSpan(out var result, separator)) - { - throw GetFormatException(); - } - - return result; - } - - private bool TryReadToken(char separator) - { - _tokenIndex = -1; - - if (_index >= _length) - { - return false; - } - - var c = _s[_index]; - - var index = _index; - var length = 0; - - while (_index < _length) - { - c = _s[_index]; - - if (IsWhiteSpace(c) || c == separator) - { - break; - } - - _index++; - length++; - } - - SkipToNextToken(separator); - - _tokenIndex = index; - _tokenLength = length; - - if (_tokenLength < 1) - { - throw GetFormatException(); - } - - return true; - } - - private void SkipToNextToken(char separator) - { - if (_index < _length) - { - var c = _s[_index]; - - if (c != separator && !IsWhiteSpace(c)) - { - throw GetFormatException(); - } - - var length = 0; - - while (_index < _length) - { - c = _s[_index]; - - if (c == separator) - { - length++; - _index++; - - if (length > 1) - { - throw GetFormatException(); - } - } - else - { - if (!IsWhiteSpace(c)) - { - break; - } - - _index++; - } - } - - if (length > 0 && _index >= _length) - { - throw GetFormatException(); - } - } - } - - private FormatException GetFormatException() => - _exceptionMessage != null ? new FormatException(_exceptionMessage) : new FormatException(); - - private static char GetSeparatorFromFormatProvider(IFormatProvider provider) - { - var c = DefaultSeparatorChar; - - var formatInfo = NumberFormatInfo.GetInstance(provider); - if (formatInfo.NumberDecimalSeparator.Length > 0 && c == formatInfo.NumberDecimalSeparator[0]) - { - c = ';'; - } - - return c; - } - } -} diff --git a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj index 313e66b207..bc6380a012 100644 --- a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj +++ b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj @@ -62,9 +62,6 @@ Markup/%(RecursiveDir)%(FileName)%(Extension) - - Markup/%(RecursiveDir)%(FileName)%(Extension) - Markup/%(RecursiveDir)%(FileName)%(Extension) diff --git a/src/Avalonia.Controls/Design.cs b/src/Avalonia.Controls/Design.cs index 9d6bb93ebb..1e7912d75f 100644 --- a/src/Avalonia.Controls/Design.cs +++ b/src/Avalonia.Controls/Design.cs @@ -127,22 +127,6 @@ namespace Avalonia.Controls /// public static readonly AttachedProperty PreviewWithProperty = AvaloniaProperty .RegisterAttached("PreviewWith", typeof (Design)); - - /// - /// Sets a preview template for the specified at design-time. - /// - /// - /// This method allows you to specify a substitute control to be rendered in the previewer - /// for a given object. - /// - /// The target object. - /// The preview control. - // TODO12: Remove this overload in Avalonia 12 - [Obsolete("Use SetPreviewWith(AvaloniaObject, ITemplate) overload instead. Use from XAML")] - public static void SetPreviewWith(AvaloniaObject target, Control? control) - { - s_previewWith[target] = control is not null ? new FuncTemplate(() => control) : null; - } /// /// Sets a preview template for the specified at design-time. diff --git a/src/Avalonia.Controls/Documents/Inline.cs b/src/Avalonia.Controls/Documents/Inline.cs index 1ededcf81c..fe526e9204 100644 --- a/src/Avalonia.Controls/Documents/Inline.cs +++ b/src/Avalonia.Controls/Documents/Inline.cs @@ -10,11 +10,10 @@ namespace Avalonia.Controls.Documents /// public abstract class Inline : TextElement { - // TODO12: change the field type to an AttachedProperty for consistency (breaking change) /// /// AvaloniaProperty for property. /// - public static readonly StyledProperty TextDecorationsProperty = + public static readonly AttachedProperty TextDecorationsProperty = AvaloniaProperty.RegisterAttached( nameof(TextDecorations), inherits: true); diff --git a/src/Avalonia.Controls/Primitives/TextSearch.cs b/src/Avalonia.Controls/Primitives/TextSearch.cs index 5099567630..aa83266683 100644 --- a/src/Avalonia.Controls/Primitives/TextSearch.cs +++ b/src/Avalonia.Controls/Primitives/TextSearch.cs @@ -24,22 +24,20 @@ namespace Avalonia.Controls.Primitives public static readonly AttachedProperty TextBindingProperty = AvaloniaProperty.RegisterAttached("TextBinding", typeof(TextSearch)); - // TODO12: Control should be Interactive to match the property definition. /// /// Sets the value of the attached property to a given . /// /// The control. /// The search text to set. - public static void SetText(Control control, string? text) + public static void SetText(Interactive control, string? text) => control.SetValue(TextProperty, text); - // TODO12: Control should be Interactive to match the property definition. /// /// Gets the value of the attached property from a given . /// /// The control. /// The search text. - public static string? GetText(Control control) + public static string? GetText(Interactive control) => control.GetValue(TextProperty); /// diff --git a/src/Browser/Avalonia.Browser/Rendering/RenderWorker.cs b/src/Browser/Avalonia.Browser/Rendering/RenderWorker.cs index f854e922f8..91495ea0ea 100644 --- a/src/Browser/Avalonia.Browser/Rendering/RenderWorker.cs +++ b/src/Browser/Avalonia.Browser/Rendering/RenderWorker.cs @@ -1,10 +1,7 @@ using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.JavaScript; -using System.Threading; using System.Threading.Tasks; using Avalonia.Browser.Interop; @@ -19,11 +16,14 @@ internal partial class RenderWorker private static partial void InitializeRenderTargets(); internal static int WorkerThreadId; + + // The worker task needs to be rooted otherwise the web worker will exit. + private static Task? s_workerTask; public static Task InitializeAsync() { var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - var workerTask = JSWebWorkerClone.RunAsync(async () => + s_workerTask = JSWebWorkerRunAsync(null, async () => { try { @@ -41,103 +41,18 @@ internal partial class RenderWorker } }); - workerTask.ContinueWith(_ => + s_workerTask.ContinueWith(_ => { - if (workerTask.IsFaulted) - tcs.TrySetException(workerTask.Exception); + if (s_workerTask.IsFaulted) + tcs.TrySetException(s_workerTask.Exception); }); return tcs.Task; } - public static class JSWebWorkerClone - { - private static readonly MethodInfo _setExtLoop; - private static readonly MethodInfo _intallInterop; - - [DynamicDependency(DynamicallyAccessedMemberTypes.All, "System.Runtime.InteropServices.JavaScript.JSSynchronizationContext", - "System.Runtime.InteropServices.JavaScript")] - [DynamicDependency(DynamicallyAccessedMemberTypes.All, "System.Runtime.InteropServices.JavaScript.JSHostImplementation", - "System.Runtime.InteropServices.JavaScript")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Private runtime API")] - [UnconditionalSuppressMessage("Trimming", "IL2036", Justification = "Private runtime API")] - [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Private runtime API")] - [UnconditionalSuppressMessage("Trimming", "IL2111", Justification = "Private runtime API")] - static JSWebWorkerClone() - { - var syncContext = typeof(System.Runtime.InteropServices.JavaScript.JSHost) - .Assembly!.GetType("System.Runtime.InteropServices.JavaScript.JSSynchronizationContext")!; - var hostImpl = typeof(System.Runtime.InteropServices.JavaScript.JSHost) - .Assembly!.GetType("System.Runtime.InteropServices.JavaScript.JSHostImplementation")!; - - _setExtLoop = hostImpl.GetMethod("SetHasExternalEventLoop")!; - _intallInterop = syncContext.GetMethod("InstallWebWorkerInterop")!; - } - - public static Task RunAsync(Func run) - { - var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - var th = new Thread(_ => - { - _intallInterop.Invoke(null, [false, CancellationToken.None]); - try - { - run().ContinueWith(t => - { - if (t.IsFaulted) - tcs.TrySetException(t.Exception); - else if (t.IsCanceled) - tcs.TrySetCanceled(); - else - tcs.TrySetResult(); - }); - } - catch(Exception e) - { - tcs.TrySetException(e); - } - }) - { - Name = "Manual JS worker" - }; - _setExtLoop.Invoke(null, [th]); -#pragma warning disable CA1416 - th.Start(); -#pragma warning restore CA1416 - return tcs.Task; - } - - } - - // TODO: Use this class instead of JSWebWorkerClone once https://github.com/dotnet/runtime/issues/102010 is fixed - // TODO12: It was fixed in .NET 10 - class JSWebWorkerWrapper - { - [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, "System.Runtime.InteropServices.JavaScript.JSWebWorker", - "System.Runtime.InteropServices.JavaScript")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Private runtime API")] - [UnconditionalSuppressMessage("Trimming", "IL2036", Justification = "Private runtime API")] - [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Private runtime API")] - [UnconditionalSuppressMessage("Trimming", "IL2111", Justification = "Private runtime API")] - static JSWebWorkerWrapper() - { - var type = typeof(System.Runtime.InteropServices.JavaScript.JSHost) - .Assembly!.GetType("System.Runtime.InteropServices.JavaScript.JSWebWorker"); -#pragma warning disable IL2075 - var m = type! - - .GetMethods(BindingFlags.Static | BindingFlags.Public - ).First(m => m.Name == "RunAsync" - && m.ReturnType == typeof(Task) - && m.GetParameters() is { } parameters - && parameters.Length == 1 - && parameters[0].ParameterType == typeof(Func)); - -#pragma warning restore IL2075 - RunAsync = (Func, Task>) Delegate.CreateDelegate(typeof(Func, Task>), m); - - } - - public static Func, Task> RunAsync { get; set; } - } + // Even though this API is public in the .NET code, it's not part of ref assemblies and is not a stable API. + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "RunAsync")] + private static extern Task JSWebWorkerRunAsync( + [UnsafeAccessorType("System.Runtime.InteropServices.JavaScript.JSWebWorker, System.Runtime.InteropServices.JavaScript")] object? instance, + Func body); } diff --git a/tests/Avalonia.Base.UnitTests/Utilities/StringTokenizerTests.cs b/tests/Avalonia.Base.UnitTests/Utilities/StringTokenizerTests.cs deleted file mode 100644 index b7d09a40d7..0000000000 --- a/tests/Avalonia.Base.UnitTests/Utilities/StringTokenizerTests.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using Avalonia.Utilities; -using Xunit; - -#pragma warning disable CS0618 // Type or member is obsolete - -namespace Avalonia.Base.UnitTests.Utilities -{ - public class StringTokenizerTests - { - [Fact] - public void ReadInt32_Reads_Values() - { - var target = new StringTokenizer("123,456"); - - Assert.Equal(123, target.ReadInt32()); - Assert.Equal(456, target.ReadInt32()); - Assert.Throws(() => target.ReadInt32()); - } - - [Fact] - public void ReadDouble_Reads_Values() - { - var target = new StringTokenizer("12.3,45.6"); - - Assert.Equal(12.3, target.ReadDouble()); - Assert.Equal(45.6, target.ReadDouble()); - Assert.Throws(() => target.ReadDouble()); - } - - [Fact] - public void TryReadInt32_Reads_Values() - { - var target = new StringTokenizer("123,456"); - - Assert.True(target.TryReadInt32(out var value)); - Assert.Equal(123, value); - Assert.True(target.TryReadInt32(out value)); - Assert.Equal(456, value); - Assert.False(target.TryReadInt32(out value)); - } - - [Fact] - public void TryReadInt32_Doesnt_Throw() - { - var target = new StringTokenizer("abc"); - - Assert.False(target.TryReadInt32(out var value)); - } - - [Fact] - public void TryReadDouble_Reads_Values() - { - var target = new StringTokenizer("12.3,45.6"); - - Assert.True(target.TryReadDouble(out var value)); - Assert.Equal(12.3, value); - Assert.True(target.TryReadDouble(out value)); - Assert.Equal(45.6, value); - Assert.False(target.TryReadDouble(out value)); - } - - [Fact] - public void TryReadDouble_Doesnt_Throw() - { - var target = new StringTokenizer("abc"); - - Assert.False(target.TryReadDouble(out var value)); - } - - [Fact] - public void ReadSpan_And_ReadString_Reads_Same() - { - var target1 = new StringTokenizer("abc,def"); - var target2 = new StringTokenizer("abc,def"); - - Assert.Equal(target1.ReadString(), target2.ReadSpan().ToString()); - Assert.True(target1.ReadSpan().SequenceEqual(target2.ReadString())); - } - } -}