Browse Source

Merge branch 'master' into fixes/textAlignmentJustify

pull/17894/head
Julien Lebosquain 3 months ago
committed by GitHub
parent
commit
8ca212a9a1
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 3
      .editorconfig
  2. 5
      .nuke/build.schema.json
  3. 2
      Avalonia.Desktop.slnf
  4. 16
      api/Avalonia.Android.nupkg.xml
  5. 2
      build/AnalyzerProject.targets
  6. 6
      build/HarfBuzzSharp.props
  7. 2
      build/ImageSharp.props
  8. 2
      build/Microsoft.Reactive.Testing.props
  9. 2
      build/Rx.props
  10. 6
      build/SkiaSharp.props
  11. 18
      build/XUnit.props
  12. 2
      global.json
  13. 7
      native/Avalonia.Native/src/OSX/AvnView.mm
  14. 16
      native/Avalonia.Native/src/OSX/automation.mm
  15. 51
      nukebuild/Build.cs
  16. 5
      nukebuild/BuildParameters.cs
  17. 6
      nukebuild/_build.csproj
  18. 1
      samples/Directory.Build.props
  19. 7
      samples/GpuInterop/GpuInterop.csproj
  20. 1
      samples/IntegrationTestApp/MainWindow.axaml.cs
  21. 62
      samples/IntegrationTestApp/Pages/DragDropPage.axaml
  22. 103
      samples/IntegrationTestApp/Pages/DragDropPage.axaml.cs
  23. 3
      samples/IntegrationTestApp/Pages/WindowPage.axaml.cs
  24. 8
      samples/MiniMvvm/MiniCommand.cs
  25. 6
      samples/MiniMvvm/PropertyChangedExtensions.cs
  26. 4
      samples/TextTestApp/InteractiveLineControl.cs
  27. 14
      samples/TextTestApp/MainWindow.axaml.cs
  28. 3
      src/Android/Avalonia.Android/Avalonia.Android.csproj
  29. 9
      src/Android/Avalonia.Android/AvaloniaActivity.cs
  30. 15
      src/Android/Avalonia.Android/BackPressedCallback.cs
  31. 3
      src/Android/Avalonia.Android/ChoreographerTimer.cs
  32. 2
      src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs
  33. 8
      src/Avalonia.Base/Controls/NameScope.cs
  34. 2
      src/Avalonia.Base/Input/DragEventArgs.cs
  35. 2
      src/Avalonia.Base/Input/FocusChangingEventArgs.cs
  36. 2
      src/Avalonia.Base/Input/GotFocusEventArgs.cs
  37. 15
      src/Avalonia.Base/Input/IKeyModifiersEventArgs.cs
  38. 5
      src/Avalonia.Base/Input/KeyEventArgs.cs
  39. 2
      src/Avalonia.Base/Input/Navigation/XYFocus.FindElements.cs
  40. 2
      src/Avalonia.Base/Input/PointerEventArgs.cs
  41. 2
      src/Avalonia.Base/Input/TappedEventArgs.cs
  42. 72
      src/Avalonia.Base/Media/FontFamily.cs
  43. 24
      src/Avalonia.Base/Media/PolylineGeometry.cs
  44. 2
      src/Avalonia.Base/Media/TextFormatting/TextParagraphProperties.cs
  45. 16
      src/Avalonia.Base/Media/TextFormatting/Unicode/BiDi.trie.cs
  46. 2
      src/Avalonia.Base/Media/TextFormatting/Unicode/EastAsianWidth.trie.cs
  47. 2
      src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeBreak.trie.cs
  48. 98
      src/Avalonia.Base/Media/TextFormatting/Unicode/LineBreakEnumerator.cs
  49. 18
      src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeData.trie.cs
  50. 6
      src/Avalonia.Base/Media/TextPathSegmentEllipsis.cs
  51. 4
      src/Avalonia.Base/Platform/Storage/FilePickerOpenOptions.cs
  52. 2
      src/Avalonia.Base/Platform/Storage/NoopStorageProvider.cs
  53. 7
      src/Avalonia.Base/Platform/Storage/SaveFilePickerResult.cs
  54. 4
      src/Avalonia.Base/Rendering/Composition/CompositionDrawingSurface.cs
  55. 6
      src/Avalonia.Base/Styling/Selector.cs
  56. 6
      src/Avalonia.Base/Threading/Dispatcher.MainLoop.cs
  57. 19
      src/Avalonia.Base/Threading/DispatcherPriorityAwaitable.cs
  58. 4
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  59. 2
      src/Avalonia.Controls/Automation/Provider/IRangeValueProvider.cs
  60. 2
      src/Avalonia.Controls/Automation/Provider/IValueProvider.cs
  61. 45
      src/Avalonia.Controls/ComboBox.cs
  62. 22
      src/Avalonia.Controls/ListBox.cs
  63. 76
      src/Avalonia.Controls/ListBoxItem.cs
  64. 2
      src/Avalonia.Controls/MenuItem.cs
  65. 2
      src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
  66. 82
      src/Avalonia.Controls/Primitives/ItemSelectionEventTriggers.cs
  67. 61
      src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
  68. 29
      src/Avalonia.Controls/Primitives/TabStrip.cs
  69. 7
      src/Avalonia.Controls/Primitives/TabStripItem.cs
  70. 16
      src/Avalonia.Controls/Shapes/Polygon.cs
  71. 18
      src/Avalonia.Controls/Shapes/Polyline.cs
  72. 50
      src/Avalonia.Controls/TabControl.cs
  73. 25
      src/Avalonia.Controls/TabItem.cs
  74. 5
      src/Avalonia.Controls/TextBlock.cs
  75. 42
      src/Avalonia.Controls/TreeView.cs
  76. 16
      src/Avalonia.Controls/TreeViewItem.cs
  77. 12
      src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj
  78. 132
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/bun.lock
  79. 1174
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/package-lock.json
  80. 4
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/package.json
  81. 2
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  82. 2
      src/Avalonia.Dialogs/ManagedStorageProvider.cs
  83. 2
      src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj
  84. 11
      src/Avalonia.FreeDesktop/DBusIme/X11DBusImeHelper.cs
  85. 2
      src/Avalonia.FreeDesktop/DBusSystemDialog.cs
  86. 2
      src/Avalonia.Native/GpuHandleWrapFeature.cs
  87. 2
      src/Avalonia.Native/StorageProviderImpl.cs
  88. 2
      src/Avalonia.Native/avn.idl
  89. 2
      src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs
  90. 35
      src/Avalonia.X11/X11Platform.cs
  91. 4
      src/Avalonia.X11/X11Window.cs
  92. 302
      src/Avalonia.X11/XI2Manager.cs
  93. 8
      src/Avalonia.X11/XIStructs.cs
  94. 12
      src/Browser/Avalonia.Browser/Avalonia.Browser.csproj
  95. 2
      src/Browser/Avalonia.Browser/Storage/BrowserStorageProvider.cs
  96. 545
      src/Browser/Avalonia.Browser/webapp/bun.lock
  97. 5575
      src/Browser/Avalonia.Browser/webapp/package-lock.json
  98. 8
      src/Browser/Avalonia.Browser/webapp/package.json
  99. 12
      src/Headless/Avalonia.Headless.Vnc/Avalonia.Headless.Vnc.csproj
  100. 6
      src/Headless/Avalonia.Headless.Vnc/AvaloniaVncLogger.cs

3
.editorconfig

@ -141,9 +141,6 @@ dotnet_analyzer_diagnostic.category-Performance.severity = none #error - Uncomme
# CS0649: Field 'field' is never assigned to, and will always have its default value 'value'
dotnet_diagnostic.CS0649.severity = error
# CS1591: Missing XML comment for publicly visible type or member
dotnet_diagnostic.CS1591.severity = suggestion
# CS0162: Remove unreachable code
dotnet_diagnostic.CS0162.severity = error
# CA1018: Mark attributes with AttributeUsageAttribute

5
.nuke/build.schema.json

@ -30,12 +30,12 @@
"CiAzureWindows",
"Clean",
"Compile",
"CompileHtmlPreviewer",
"CompileNative",
"CreateIntermediateNugetPackages",
"CreateNugetPackages",
"DownloadApiBaselinePackages",
"GenerateCppHeaders",
"InitDnx",
"OutputApiDiff",
"OutputVersion",
"Package",
@ -130,9 +130,6 @@
"force-nuget-version": {
"type": "string"
},
"skip-previewer": {
"type": "boolean"
},
"skip-tests": {
"type": "boolean"
},

2
Avalonia.Desktop.slnf

@ -1,4 +1,4 @@
{
{
"solution": {
"path": "Avalonia.sln",
"projects": [

16
api/Avalonia.Android.nupkg.xml

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Android.AvaloniaActivity</Target>
<Left>baseline/Avalonia.Android/lib/net10.0-android36.0/Avalonia.Android.dll</Left>
<Right>current/Avalonia.Android/lib/net10.0-android36.0/Avalonia.Android.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Android.AvaloniaMainActivity</Target>
<Left>baseline/Avalonia.Android/lib/net10.0-android36.0/Avalonia.Android.dll</Left>
<Right>current/Avalonia.Android/lib/net10.0-android36.0/Avalonia.Android.dll</Right>
</Suppression>
</Suppressions>

2
build/AnalyzerProject.targets

@ -6,7 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all"/>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.5.0" PrivateAssets="all" />
</ItemGroup>

6
build/HarfBuzzSharp.props

@ -1,7 +1,7 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="HarfBuzzSharp" Version="8.3.1.1" />
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="8.3.1.1" />
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="8.3.1.1" />
<PackageReference Include="HarfBuzzSharp" Version="8.3.1.2" />
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="8.3.1.2" />
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="8.3.1.2" />
</ItemGroup>
</Project>

2
build/ImageSharp.props

@ -1,5 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.10" />
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.12" />
</ItemGroup>
</Project>

2
build/Microsoft.Reactive.Testing.props

@ -1,5 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="Microsoft.Reactive.Testing" Version="4.1.6" />
<PackageReference Include="Microsoft.Reactive.Testing" Version="6.1.0" />
</ItemGroup>
</Project>

2
build/Rx.props

@ -1,5 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="System.Reactive" Version="6.0.1" />
<PackageReference Include="System.Reactive" Version="6.1.0" />
</ItemGroup>
</Project>

6
build/SkiaSharp.props

@ -1,7 +1,7 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="SkiaSharp" Version="3.119.0" />
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="3.119.0" />
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="SkiaSharp.NativeAssets.WebAssembly" Version="3.119.0" />
<PackageReference Include="SkiaSharp" Version="3.119.1" />
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="3.119.1" />
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="SkiaSharp.NativeAssets.WebAssembly" Version="3.119.1" />
</ItemGroup>
</Project>

18
build/XUnit.props

@ -1,14 +1,14 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.assert" Version="2.9.2" />
<PackageReference Include="xunit.core" Version="2.9.2" />
<PackageReference Include="xunit.extensibility.core" Version="2.9.2" />
<PackageReference Include="xunit.extensibility.execution" Version="2.9.2" />
<PackageReference Include="xunit.runner.console" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" Condition="'$(TargetFramework)' != 'netstandard2.0'" />
<PackageReference Include="Xunit.SkippableFact" Version="1.4.13" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.assert" Version="2.9.3" />
<PackageReference Include="xunit.core" Version="2.9.3" />
<PackageReference Include="xunit.extensibility.core" Version="2.9.3" />
<PackageReference Include="xunit.extensibility.execution" Version="2.9.3" />
<PackageReference Include="xunit.runner.console" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" Condition="'$(TargetFramework)' != 'netstandard2.0'" />
<PackageReference Include="Xunit.SkippableFact" Version="1.5.23" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
</ItemGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile>

2
global.json

@ -1,6 +1,6 @@
{
"sdk": {
"version": "10.0.100",
"version": "10.0.101",
"rollForward": "latestFeature"
},
"msbuild-sdks": {

7
native/Avalonia.Native/src/OSX/AvnView.mm

@ -854,9 +854,10 @@ static void ConvertTilt(NSPoint tilt, float* xTilt, float* yTilt)
- (NSDragOperation)triggerAvnDragEvent: (AvnDragEventType) type info: (id <NSDraggingInfo>)info
{
auto localPoint = [self convertPoint:[info draggingLocation] toView:self];
auto avnPoint = ToAvnPoint(localPoint);
auto point = [self translateLocalPoint:avnPoint];
NSPoint eventLocation = [info draggingLocation];
auto viewLocation = [self convertPoint:NSMakePoint(0, 0) toView:nil];
auto localPoint = NSMakePoint(eventLocation.x - viewLocation.x, viewLocation.y - eventLocation.y);
auto point = ToAvnPoint(localPoint);
auto modifiers = [self getModifiers:[[NSApp currentEvent] modifierFlags]];
NSDragOperation nsop = [info draggingSourceOperationMask];

16
native/Avalonia.Native/src/OSX/automation.mm

@ -216,6 +216,22 @@
return [super accessibilityValue];
}
- (void)setAccessibilityValue:(id)newValue
{
if (_peer->IsValueProvider())
{
if (newValue == nil)
_peer->ValueProvider_SetValue(nil);
else if ([newValue isKindOfClass:[NSString class]])
_peer->ValueProvider_SetValue([(NSString*)newValue UTF8String]);
}
else if (_peer->IsRangeValueProvider())
{
if ([newValue isKindOfClass:[NSNumber class]])
_peer->RangeValueProvider_SetValue([(NSNumber*)newValue doubleValue]);
}
}
- (id)accessibilityMinValue
{
if (_peer->IsRangeValueProvider())

51
nukebuild/Build.cs

@ -1,20 +1,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Xml.Linq;
using Nuke.Common;
using Nuke.Common.Tooling;
using Nuke.Common.Tools.DotNet;
using Nuke.Common.Tools.Npm;
using Nuke.Common.Utilities;
using static Nuke.Common.EnvironmentInfo;
using static Nuke.Common.IO.PathConstruction;
using static Nuke.Common.Tools.DotNet.DotNetTasks;
using static Serilog.Log;
using MicroCom.CodeGenerator;
@ -41,13 +36,13 @@ partial class Build : NukeBuild
[NuGetPackage("Microsoft.DotNet.ApiCompat.Tool", "Microsoft.DotNet.ApiCompat.Tool.dll", Framework = "net8.0")]
Tool ApiCompatTool;
[NuGetPackage("Microsoft.DotNet.ApiDiff.Tool", "Microsoft.DotNet.ApiDiff.Tool.dll", Framework = "net8.0")]
Tool ApiDiffTool;
[NuGetPackage("dotnet-ilrepack", "ILRepackTool.dll", Framework = "net8.0")]
Tool IlRepackTool;
protected override void OnBuildInitialized()
{
Parameters = new BuildParameters(this, ScheduledTargets.Contains(BuildToNuGetCache));
@ -62,6 +57,7 @@ partial class Build : NukeBuild
Information("Repository Name: " + Parameters.RepositoryName);
Information("Repository Branch: " + Parameters.RepositoryBranch);
}
Information("Configuration: " + Parameters.Configuration);
Information("IsLocalBuild: " + Parameters.IsLocalBuild);
Information("IsRunningOnUnix: " + Parameters.IsRunningOnUnix);
@ -78,8 +74,9 @@ partial class Build : NukeBuild
void ExecWait(string preamble, string command, string args)
{
Console.WriteLine(preamble);
Process.Start(new ProcessStartInfo(command, args) {UseShellExecute = false}).WaitForExit();
Process.Start(new ProcessStartInfo(command, args) { UseShellExecute = false }).WaitForExit();
}
ExecWait("dotnet version:", "dotnet", "--info");
ExecWait("dotnet workloads:", "dotnet", "workload list");
Information("Processor count: " + Environment.ProcessorCount);
@ -104,6 +101,7 @@ partial class Build : NukeBuild
.AddProperty("SkipBuildingTests", "True");
return c;
}
DotNetBuildSettings ApplySetting(DotNetBuildSettings c, Configure<DotNetBuildSettings> configurator = null) =>
ApplySettingCore(c).Build.Apply(configurator);
@ -134,19 +132,15 @@ partial class Build : NukeBuild
}
});
Target CompileHtmlPreviewer => _ => _
.DependsOn(Clean)
.OnlyWhenStatic(() => !Parameters.SkipPreviewer)
// Ensure that Bun.Official.Tool is downloaded at least once on CI to work around https://github.com/dotnet/sdk/issues/51831
Target InitDnx => _ => _
.Executes(() =>
{
var webappDir = RootDirectory / "src" / "Avalonia.DesignerSupport" / "Remote" / "HtmlTransport" / "webapp";
NpmTasks.NpmInstall(c => c
.SetProcessWorkingDirectory(webappDir)
.SetProcessAdditionalArguments("--silent"));
NpmTasks.NpmRun(c => c
.SetProcessWorkingDirectory(webappDir)
.SetCommand("dist"));
var process = ProcessTasks.StartProcess(
"dnx",
"Bun.Unofficial.Tool --yes -- install",
$"{RootDirectory}/src/Browser/Avalonia.Browser/webapp");
process.AssertZeroExitCode();
});
Target CompileNative => _ => _
@ -161,8 +155,7 @@ partial class Build : NukeBuild
});
Target Compile => _ => _
.DependsOn(Clean, CompileNative)
.DependsOn(CompileHtmlPreviewer)
.DependsOn(Clean, CompileNative, InitDnx)
.Executes(() =>
{
DotNetBuild(c => ApplySetting(c)
@ -254,18 +247,14 @@ partial class Build : NukeBuild
.SetResultsDirectory(Parameters.TestResultsRoot));
Target RunHtmlPreviewerTests => _ => _
.DependsOn(CompileHtmlPreviewer)
.OnlyWhenStatic(() => !(Parameters.SkipPreviewer || Parameters.SkipTests))
.OnlyWhenStatic(() => !(Parameters.SkipTests))
.Executes(() =>
{
var webappTestDir = RootDirectory / "tests" / "Avalonia.DesignerSupport.Tests" / "Remote" / "HtmlTransport" / "webapp";
NpmTasks.NpmInstall(c => c
.SetProcessWorkingDirectory(webappTestDir)
.SetProcessAdditionalArguments("--silent"));
NpmTasks.NpmRun(c => c
.SetProcessWorkingDirectory(webappTestDir)
.SetCommand("test"));
var webappTest = RootDirectory / "tests" / "Avalonia.DesignerSupport.Tests";
DotNetMSBuild(o => o
.SetProcessWorkingDirectory(webappTest)
.SetTargets("BunRunTests"));
});
Target RunCoreLibsTests => _ => _

5
nukebuild/BuildParameters.cs

@ -21,9 +21,6 @@ public partial class Build
[Parameter(Name = "force-nuget-version")]
public string? ForceNugetVersion { get; set; }
[Parameter(Name = "skip-previewer")]
public bool SkipPreviewer { get; set; }
[Parameter(Name = "force-api-baseline")]
public string? ForceApiValidationBaseline { get; set; }
@ -37,7 +34,6 @@ public partial class Build
{
public string Configuration { get; }
public bool SkipTests { get; }
public bool SkipPreviewer {get;}
public string MainRepo { get; }
public string MasterBranch { get; }
public string? RepositoryName { get; }
@ -81,7 +77,6 @@ public partial class Build
// ARGUMENTS
Configuration = b.Configuration ?? "Release";
SkipTests = b.SkipTests;
SkipPreviewer = b.SkipPreviewer;
// CONFIGURATION
MainRepo = "https://github.com/AvaloniaUI/Avalonia";

6
nukebuild/_build.csproj

@ -15,9 +15,9 @@
<PackageReference Include="Nuke.Common" Version="9.0.4" />
<PackageReference Include="MicroCom.CodeGenerator" Version="0.11.0" />
<!-- Keep in sync with Avalonia.Build.Tasks -->
<PackageReference Include="Mono.Cecil" Version="0.11.5" />
<PackageReference Include="Microsoft.Build.Framework" Version="17.14.8" PrivateAssets="All" />
<PackageReference Include="NuGet.Protocol" Version="6.14.0" />
<PackageReference Include="Mono.Cecil" Version="0.11.6" />
<PackageReference Include="Microsoft.Build.Framework" Version="18.0.2" PrivateAssets="All" />
<PackageReference Include="NuGet.Protocol" Version="7.0.1" />
<PackageDownload Include="Microsoft.DotNet.ApiCompat.Tool" Version="[10.0.100]" />
<PackageDownload Include="Microsoft.DotNet.ApiDiff.Tool" Version="[10.0.100-rtm.25531.102]" />
<PackageDownload Include="dotnet-ilrepack" Version="[1.0.0]" />

1
samples/Directory.Build.props

@ -4,6 +4,7 @@
<IsPackable>false</IsPackable>
<AvaloniaPreviewerNetCoreToolPath>$(MSBuildThisFileDirectory)..\src\tools\Avalonia.Designer.HostApp\bin\Debug\$(AvsCurrentTargetFramework)\Avalonia.Designer.HostApp.dll</AvaloniaPreviewerNetCoreToolPath>
<EnableNETAnalyzers>false</EnableNETAnalyzers>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<LangVersion>14.0</LangVersion>
<NoWarn>$(NoWarn);CS8002</NoWarn> <!-- ignore signing warnings for samples -->
</PropertyGroup>

7
samples/GpuInterop/GpuInterop.csproj

@ -5,9 +5,14 @@
<TargetFramework>$(AvsCurrentTargetFramework)</TargetFramework>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<UseD3DCompiler>true</UseD3DCompiler>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<!--
Reference to System.Text.Json is explicitly added to avoid a deprecated version,
we don't care about it not being pruned.
-->
<NoWarn>$(NoWarn);NU1510</NoWarn>
</PropertyGroup>
<ItemGroup>

1
samples/IntegrationTestApp/MainWindow.axaml.cs

@ -82,6 +82,7 @@ namespace IntegrationTestApp
new("ComboBox", () => new ComboBoxPage()),
new("ContextMenu", () => new ContextMenuPage()),
new("DesktopPage", () => new DesktopPage()),
new("DragDrop", () => new DragDropPage()),
new("Embedding", () => new EmbeddingPage()),
new("Gestures", () => new GesturesPage()),
new("ListBox", () => new ListBoxPage()),

62
samples/IntegrationTestApp/Pages/DragDropPage.axaml

@ -0,0 +1,62 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="IntegrationTestApp.Pages.DragDropPage">
<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="4">
<Button Name="ResetDragDrop" Click="ResetDragDrop_Click" Margin="0,0,8,0">Reset</Button>
<TextBlock VerticalAlignment="Center">Drop Position: </TextBlock>
<TextBlock Name="DropPosition" VerticalAlignment="Center" Margin="4,0"/>
<TextBlock VerticalAlignment="Center" Margin="8,0,0,0">Status: </TextBlock>
<TextBlock Name="DragDropStatus" VerticalAlignment="Center" Margin="4,0"/>
</StackPanel>
<!-- Use a Grid with row definitions to create offset from window origin -->
<!-- The top spacer ensures the drag/drop controls are NOT at (0,0) -->
<Grid RowDefinitions="100,*">
<!-- Spacer row to offset controls from window origin -->
<Border Grid.Row="0" Background="LightGray">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
Text="Spacer (100px) - Controls below are offset from window origin"/>
</Border>
<!-- Drag and Drop test area -->
<Grid Grid.Row="1" ColumnDefinitions="*,*" Margin="20">
<!-- Drag Source -->
<Border Name="DragSource"
Grid.Column="0"
Background="CornflowerBlue"
Margin="10"
CornerRadius="8"
AutomationProperties.AccessibilityView="Content"
PointerPressed="DragSource_PointerPressed">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="Drag Source"
Foreground="White"
FontWeight="Bold"/>
</Border>
<!-- Drop Target -->
<Border Name="DropTarget"
Grid.Column="1"
Background="LightGreen"
Margin="10"
CornerRadius="8"
AutomationProperties.AccessibilityView="Content"
DragDrop.AllowDrop="True">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="Drop Target"
HorizontalAlignment="Center"
FontWeight="Bold"/>
<TextBlock Name="DropTargetText"
HorizontalAlignment="Center"
Text="Drop items here"/>
</StackPanel>
</Border>
</Grid>
</Grid>
</DockPanel>
</UserControl>

103
samples/IntegrationTestApp/Pages/DragDropPage.axaml.cs

@ -0,0 +1,103 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
namespace IntegrationTestApp.Pages;
public partial class DragDropPage : UserControl
{
public DragDropPage()
{
InitializeComponent();
// Set up drag-drop event handlers
AddHandler(DragDrop.DragOverEvent, DropTarget_DragOver);
AddHandler(DragDrop.DropEvent, DropTarget_Drop);
}
private async void DragSource_PointerPressed(object? sender, PointerPressedEventArgs e)
{
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
{
var dragData = new DataTransfer();
dragData.Add(DataTransferItem.CreateText("TestDragData"));
DragDropStatus.Text = "Dragging...";
var result = await DragDrop.DoDragDropAsync(e, dragData, DragDropEffects.Copy | DragDropEffects.Move);
DragDropStatus.Text = result switch
{
DragDropEffects.Copy => "Copied",
DragDropEffects.Move => "Moved",
DragDropEffects.None => "Cancelled",
_ => $"Result: {result}"
};
}
}
private void DropTarget_DragOver(object? sender, DragEventArgs e)
{
// Only handle events for the drop target
if (e.Source != DropTarget && !IsChildOf(e.Source as Visual, DropTarget))
return;
e.DragEffects = DragDropEffects.Copy;
// Get the position relative to the drop target
var position = e.GetPosition(DropTarget);
DropPosition.Text = $"DragOver: ({position.X:F0}, {position.Y:F0})";
}
private void DropTarget_Drop(object? sender, DragEventArgs e)
{
// Only handle events for the drop target
if (e.Source != DropTarget && !IsChildOf(e.Source as Visual, DropTarget))
return;
// Get the position relative to the drop target
var position = e.GetPosition(DropTarget);
DropPosition.Text = $"Drop: ({position.X:F0}, {position.Y:F0})";
// Check if the position is within reasonable bounds of the drop target
var bounds = DropTarget.Bounds;
var isWithinBounds = position.X >= 0 && position.X <= bounds.Width &&
position.Y >= 0 && position.Y <= bounds.Height;
var text = e.DataTransfer.TryGetText();
if (text != null)
{
DropTargetText.Text = isWithinBounds
? $"Dropped: {text} at ({position.X:F0}, {position.Y:F0})"
: $"ERROR: Position out of bounds! ({position.X:F0}, {position.Y:F0})";
DragDropStatus.Text = isWithinBounds ? "Drop OK" : "Drop position ERROR";
}
e.DragEffects = DragDropEffects.Copy;
}
private static bool IsChildOf(Visual? child, Visual? parent)
{
if (child == null || parent == null)
return false;
var current = child.Parent as Visual;
while (current != null)
{
if (current == parent)
return true;
current = current.Parent as Visual;
}
return false;
}
private void ResetDragDrop_Click(object? sender, RoutedEventArgs e)
{
DropPosition.Text = string.Empty;
DragDropStatus.Text = string.Empty;
DropTargetText.Text = "Drop items here";
}
}

3
samples/IntegrationTestApp/Pages/WindowPage.axaml.cs

@ -136,6 +136,7 @@ public partial class WindowPage : UserControl
Width = 200,
Height = 200,
Background = Brushes.Green,
SystemDecorations = SystemDecorations.None,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Content = new Border
{
@ -145,7 +146,7 @@ public partial class WindowPage : UserControl
}
};
backgroundWindow.PointerPressed += (_, _) => backgroundWindow.Close();
popup.PointerPressed += (_, _) => backgroundWindow.Close();
backgroundWindow.Show(Window);
popup.Open();

8
samples/MiniMvvm/MiniCommand.cs

@ -58,10 +58,10 @@ namespace MiniMvvm
{
public static MiniCommand Create(Action cb) => new MiniCommand<object>(_ => cb());
public static MiniCommand Create<TArg>(Action<TArg> cb) => new MiniCommand<TArg>(cb);
public static MiniCommand CreateFromTask(Func<Task> cb) => new MiniCommand<object>(_ => cb());
public static MiniCommand CreateFromTask(Func<Task> cb) => new MiniCommand<object?>(_ => cb());
public abstract bool CanExecute(object parameter);
public abstract void Execute(object parameter);
public abstract event EventHandler CanExecuteChanged;
public abstract bool CanExecute(object? parameter);
public abstract void Execute(object? parameter);
public abstract event EventHandler? CanExecuteChanged;
}
}

6
samples/MiniMvvm/PropertyChangedExtensions.cs

@ -31,13 +31,13 @@ namespace MiniMvvm
_info = info;
_observer = observer;
_target.PropertyChanged += OnPropertyChanged;
_observer.OnNext((T)_info.GetValue(_target));
_observer.OnNext((T)_info.GetValue(_target)!);
}
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
private void OnPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == _info.Name)
_observer.OnNext((T)_info.GetValue(_target));
_observer.OnNext((T)_info.GetValue(_target)!);
}
public void Dispose()

4
samples/TextTestApp/InteractiveLineControl.cs

@ -233,6 +233,7 @@ namespace TextTestApp
}
private GenericTextRunProperties? _textRunProperties;
public GenericTextRunProperties TextRunProperties
{
get
@ -241,9 +242,6 @@ namespace TextTestApp
}
set
{
if (value == null)
throw new ArgumentNullException(nameof(value));
_textRunProperties = value;
SetCurrentValue(FontFamilyProperty, value.Typeface.FontFamily);
SetCurrentValue(FontFeaturesProperty, value.FontFeatures);

14
samples/TextTestApp/MainWindow.axaml.cs

@ -320,11 +320,17 @@ namespace TextTestApp
private void OnBufferSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
List<Rect> rectangles = new List<Rect>(_buffer.Selection.Count);
if (_selectionAdorner is null)
return;
foreach (var row in _buffer.SelectedItems)
if (row is Control { Tag: Rect rect })
rectangles.Add(rect);
var rectangles = new List<Rect>(_buffer.Selection.Count);
if (_buffer.SelectedItems is { } selectedItems)
{
foreach (var row in selectedItems)
if (row is Control { Tag: Rect rect })
rectangles.Add(rect);
}
_selectionAdorner.Rectangles = rectangles;
}

3
src/Android/Avalonia.Android/Avalonia.Android.csproj

@ -4,6 +4,9 @@
<SupportedOSPlatformVersion>$(AvsMinSupportedAndroidVersion)</SupportedOSPlatformVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AndroidResgenNamespace>Avalonia.Android.Internal</AndroidResgenNamespace>
<!-- Xamarin.AndroidX assemblies are not signed -->
<NoWarn>$(NoWarn);CS8002</NoWarn>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />

9
src/Android/Avalonia.Android/AvaloniaActivity.cs

@ -20,13 +20,14 @@ namespace Avalonia.Android;
/// Common implementation of android activity that is integrated with Avalonia views.
/// If you need a base class for main activity of Avalonia app, see <see cref="AvaloniaMainActivity"/>.
/// </summary>
public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity, IOnBackInvokedCallback
public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity
{
private EventHandler<ActivatedEventArgs>? _onActivated, _onDeactivated;
private GlobalLayoutListener? _listener;
private object? _content;
private bool _contentViewSet;
internal AvaloniaView? _view;
private BackPressedCallback? _currentBackPressedCallback;
public Action<int, Result, Intent?>? ActivityResult { get; set; }
public Action<int, string[], Permission[]>? RequestPermissionsResult { get; set; }
@ -127,7 +128,8 @@ public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity, IOnBackInv
if (OperatingSystem.IsAndroidVersionAtLeast(33))
{
OnBackInvokedDispatcher.UnregisterOnBackInvokedCallback(this);
_currentBackPressedCallback?.Remove();
_currentBackPressedCallback = null;
}
base.OnStop();
}
@ -138,7 +140,8 @@ public class AvaloniaActivity : AppCompatActivity, IAvaloniaActivity, IOnBackInv
if (OperatingSystem.IsAndroidVersionAtLeast(33))
{
OnBackInvokedDispatcher.RegisterOnBackInvokedCallback(IOnBackInvokedDispatcher.PriorityDefault, this);
_currentBackPressedCallback = new BackPressedCallback(this);
OnBackPressedDispatcher.AddCallback(this, _currentBackPressedCallback);
}
base.OnStart();
}

15
src/Android/Avalonia.Android/BackPressedCallback.cs

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
using AndroidX.Activity;
namespace Avalonia.Android
{
internal class BackPressedCallback(AvaloniaActivity activity) : OnBackPressedCallback(true)
{
public override void HandleOnBackPressed()
{
activity.OnBackInvoked();
}
}
}

3
src/Android/Avalonia.Android/ChoreographerTimer.cs

@ -13,7 +13,6 @@ namespace Avalonia.Android
{
internal sealed class ChoreographerTimer : IRenderTimer
{
private static readonly bool s_supports64Callback = OperatingSystem.IsAndroidVersionAtLeast(29);
private readonly object _lock = new();
private readonly TaskCompletionSource<IntPtr> _choreographer = new();
private readonly AutoResetEvent _event = new(false);
@ -126,7 +125,7 @@ namespace Avalonia.Android
private static unsafe void PostFrameCallback(IntPtr choreographer, IntPtr data)
{
// AChoreographer_postFrameCallback is deprecated on 10.0+.
if (s_supports64Callback)
if (OperatingSystem.IsAndroidVersionAtLeast(29))
{
AChoreographer_postFrameCallback64(choreographer, &FrameCallback64, data);
}

2
src/Android/Avalonia.Android/Platform/Storage/AndroidStorageProvider.cs

@ -202,7 +202,7 @@ internal class AndroidStorageProvider : IStorageProvider
public async Task<SaveFilePickerResult> SaveFilePickerWithResultAsync(FilePickerSaveOptions options)
{
var file = await SaveFilePickerAsync(options).ConfigureAwait(false);
return new SaveFilePickerResult(file);
return new SaveFilePickerResult { File = file };
}
public async Task<IReadOnlyList<IStorageFolder>> OpenFolderPickerAsync(FolderPickerOpenOptions options)

8
src/Avalonia.Base/Controls/NameScope.cs

@ -14,8 +14,8 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the NameScope attached property.
/// </summary>
public static readonly AttachedProperty<INameScope> NameScopeProperty =
AvaloniaProperty.RegisterAttached<NameScope, StyledElement, INameScope>("NameScope");
public static readonly AttachedProperty<INameScope?> NameScopeProperty =
AvaloniaProperty.RegisterAttached<NameScope, StyledElement, INameScope?>("NameScope");
/// <inheritdoc/>
public bool IsCompleted { get; private set; }
@ -30,7 +30,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="styled">The styled element.</param>
/// <returns>The value of the NameScope attached property.</returns>
public static INameScope GetNameScope(StyledElement styled)
public static INameScope? GetNameScope(StyledElement styled)
{
_ = styled ?? throw new ArgumentNullException(nameof(styled));
@ -42,7 +42,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="styled">The styled element.</param>
/// <param name="value">The value to set.</param>
public static void SetNameScope(StyledElement styled, INameScope value)
public static void SetNameScope(StyledElement styled, INameScope? value)
{
_ = styled ?? throw new ArgumentNullException(nameof(styled));

2
src/Avalonia.Base/Input/DragEventArgs.cs

@ -5,7 +5,7 @@ using Avalonia.Metadata;
namespace Avalonia.Input
{
public class DragEventArgs : RoutedEventArgs
public class DragEventArgs : RoutedEventArgs, IKeyModifiersEventArgs
{
private readonly Interactive _target;
private readonly Point _targetLocation;

2
src/Avalonia.Base/Input/FocusChangingEventArgs.cs

@ -7,7 +7,7 @@ using Avalonia.Interactivity;
namespace Avalonia.Input
{
public class FocusChangingEventArgs : RoutedEventArgs
public class FocusChangingEventArgs : RoutedEventArgs, IKeyModifiersEventArgs
{
/// <summary>
/// Provides data for focus changing.

2
src/Avalonia.Base/Input/GotFocusEventArgs.cs

@ -5,7 +5,7 @@ namespace Avalonia.Input
/// <summary>
/// Holds arguments for a <see cref="InputElement.GotFocusEvent"/>.
/// </summary>
public class GotFocusEventArgs : RoutedEventArgs
public class GotFocusEventArgs : RoutedEventArgs, IKeyModifiersEventArgs
{
public GotFocusEventArgs() : base(InputElement.GotFocusEvent)
{

15
src/Avalonia.Base/Input/IKeyModifiersEventArgs.cs

@ -0,0 +1,15 @@
using Avalonia.Metadata;
namespace Avalonia.Input;
/// <summary>
/// Represents an event associated with a set of <see cref="Input.KeyModifiers"/>.
/// </summary>
[NotClientImplementable]
public interface IKeyModifiersEventArgs
{
/// <summary>
/// Gets the key modifiers associated with this event.
/// </summary>
KeyModifiers KeyModifiers { get; }
}

5
src/Avalonia.Base/Input/KeyEventArgs.cs

@ -5,7 +5,7 @@ namespace Avalonia.Input;
/// <summary>
/// Provides information specific to a keyboard event.
/// </summary>
public class KeyEventArgs : RoutedEventArgs
public class KeyEventArgs : RoutedEventArgs, IKeyModifiersEventArgs
{
/// <summary>
/// <para>
@ -33,9 +33,6 @@ public class KeyEventArgs : RoutedEventArgs
/// <seealso cref="KeySymbol"/>
public Key Key { get; init; }
/// <summary>
/// Gets the key modifiers for the associated event.
/// </summary>
public KeyModifiers KeyModifiers { get; init; }
/// <summary>

2
src/Avalonia.Base/Input/Navigation/XYFocus.FindElements.cs

@ -65,7 +65,7 @@ public partial class XYFocus
private static bool IsValidCandidate(InputElement candidate, KeyDeviceType? inputKeyDeviceType)
{
return candidate.Focusable && candidate.IsEnabled && candidate.IsVisible
return candidate.Focusable && candidate.IsEffectivelyEnabled && candidate.IsEffectivelyVisible
// Only allow candidate focus, if original key device type could focus it.
&& XYFocusHelpers.IsAllowedXYNavigationMode(candidate, inputKeyDeviceType);
}

2
src/Avalonia.Base/Input/PointerEventArgs.cs

@ -7,7 +7,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Input
{
public class PointerEventArgs : RoutedEventArgs
public class PointerEventArgs : RoutedEventArgs, IKeyModifiersEventArgs
{
private readonly Visual? _rootVisual;
private readonly Point _rootVisualPosition;

2
src/Avalonia.Base/Input/TappedEventArgs.cs

@ -4,7 +4,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Input
{
public class TappedEventArgs : RoutedEventArgs
public class TappedEventArgs : RoutedEventArgs, IKeyModifiersEventArgs
{
private readonly PointerEventArgs lastPointerEventArgs;

72
src/Avalonia.Base/Media/FontFamily.cs

@ -131,53 +131,55 @@ namespace Avalonia.Media
{
var result = new FrugalStructList<FontSourceIdentifier>(1);
var segments = name.Split(',');
for (int i = 0; i < segments.Length; i++)
int commaIndex = -1;
do
{
var segment = segments[i];
var innerSegments = segment.Split('#');
// Look for a comma separator to carve out a single segment.
int segmentStart = commaIndex + 1;
commaIndex = name.IndexOf(',', segmentStart);
int segmentEnd = commaIndex == -1
? name.Length
: commaIndex;
var segment = name.AsSpan(segmentStart..segmentEnd).Trim();
FontSourceIdentifier identifier = new FontSourceIdentifier(name, null);
FontSourceIdentifier? identifier = null;
switch (innerSegments.Length)
// Check if there is exactly one '#' (i.e., segment is in the format "path#innerName").
int separatorIndex = segment.IndexOf('#');
if (separatorIndex != -1 && segment[(separatorIndex + 1)..].IndexOf('#') == -1)
{
case 1:
var pathSpan = segment[..separatorIndex].Trim();
var innerName = segment[(separatorIndex + 1)..].Trim();
if (pathSpan.IsEmpty)
{
identifier = new FontSourceIdentifier(innerName.ToString(), null);
}
else
{
string path = pathSpan.ToString();
if (pathSpan.Contains('/') && Uri.TryCreate(path, UriKind.Relative, out var source))
{
identifier = new FontSourceIdentifier(innerSegments[0].Trim(), null);
break;
identifier = new FontSourceIdentifier(innerName.ToString(), source);
}
case 2:
else
{
var path = innerSegments[0].Trim();
var innerName = innerSegments[1].Trim();
if (string.IsNullOrEmpty(path))
{
identifier = new FontSourceIdentifier(innerName, null);
}
else
if (Uri.TryCreate(path, UriKind.Absolute, out source))
{
if (path.Contains('/') && Uri.TryCreate(path, UriKind.Relative, out var source))
{
identifier = new FontSourceIdentifier(innerName, source);
}
else
{
if (Uri.TryCreate(path, UriKind.Absolute, out source))
{
identifier = new FontSourceIdentifier(innerName, source);
}
}
identifier = new FontSourceIdentifier(innerName.ToString(), source);
}
break;
}
}
}
result.Add(identifier);
}
// If we didn't manage to match it to any known format, treat the entire segment as the font name.
identifier ??= new FontSourceIdentifier(
segment.Length == name.Length ? name : segment.ToString(),
null);
result.Add(identifier.Value);
} while (commaIndex != -1);
return result;
}

24
src/Avalonia.Base/Media/PolylineGeometry.cs

@ -27,6 +27,7 @@ namespace Avalonia.Media
private IList<Point> _points;
private IDisposable? _pointsObserver;
private readonly FillRule _fillRule;
static PolylineGeometry()
{
@ -40,6 +41,7 @@ namespace Avalonia.Media
public PolylineGeometry()
{
_points = new Points();
_fillRule = FillRule.EvenOdd;
}
/// <summary>
@ -49,6 +51,17 @@ namespace Avalonia.Media
{
_points = new Points(points);
IsFilled = isFilled;
_fillRule = FillRule.EvenOdd;
}
/// <summary>
/// Initializes a new instance of the <see cref="PolylineGeometry"/> class.
/// </summary>
public PolylineGeometry(IEnumerable<Point> points, bool isFilled, FillRule fillRule)
{
_points = new Points(points);
IsFilled = isFilled;
_fillRule = fillRule;
}
/// <summary>
@ -70,10 +83,18 @@ namespace Avalonia.Media
set => SetValue(IsFilledProperty, value);
}
/// <summary>
/// Gets how the intersecting areas of the polyline are combined.
/// </summary>
public FillRule FillRule => _fillRule;
/// <inheritdoc/>
public override Geometry Clone()
{
return new PolylineGeometry(Points, IsFilled);
return new PolylineGeometry(Points, IsFilled, _fillRule)
{
Transform = Transform
};
}
private protected sealed override IGeometryImpl? CreateDefiningGeometry()
@ -83,6 +104,7 @@ namespace Avalonia.Media
using (var context = geometry.Open())
{
context.SetFillRule(_fillRule);
var points = Points;
var isFilled = IsFilled;
if (points.Count > 0)

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

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

16
src/Avalonia.Base/Media/TextFormatting/Unicode/BiDi.trie.cs

@ -16,10 +16,18 @@ internal static class BidiTrie
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new(Data, 0x00100000, 0x00000000);
}
}
private static ReadOnlySpan<uint> Data => new uint[]
{
// For Debug builds, we store the data in a separate uint[] field to avoid RuntimeFieldInfoStub allocations.
// See also: https://github.com/AvaloniaUI/Avalonia/pull/20175
#if DEBUG
public static ReadOnlySpan<uint> Data => s_data;
private static uint[] s_data =
#else
public static ReadOnlySpan<uint> Data =>
#endif
[
0x0000038D, 0x00000395, 0x0000039D, 0x000003A5, 0x000003BD, 0x000003C5, 0x000003CD, 0x000003D5, 0x000003AD, 0x000003B5, 0x000003AD, 0x000003B5,
0x000003AD, 0x000003B5, 0x000003AD, 0x000003B5, 0x000003AD, 0x000003B5, 0x000003AD, 0x000003B5, 0x000003DB, 0x000003E3, 0x000003EB, 0x000003F3,
0x000003FB, 0x00000403, 0x000003FF, 0x00000407, 0x0000040F, 0x00000417, 0x00000412, 0x0000041A, 0x000003AD, 0x000003B5, 0x000003AD, 0x000003B5,
@ -1104,5 +1112,5 @@ internal static class BidiTrie
0x00000000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00000000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040000,
0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
};
];
}

2
src/Avalonia.Base/Media/TextFormatting/Unicode/EastAsianWidth.trie.cs

@ -18,7 +18,7 @@ internal static class EastAsianWidthTrie
get => new(Data, 0x00110000, 0x00000000);
}
private static ReadOnlySpan<uint> Data => new uint[]
private static readonly uint[] Data = new uint[]
{
0x000003E7, 0x000003EF, 0x000003F7, 0x000003FF, 0x0000041F, 0x00000427, 0x0000042F, 0x00000437, 0x0000043F, 0x00000447, 0x0000044F, 0x00000457,
0x00000417, 0x0000041F, 0x0000045C, 0x00000464, 0x00000417, 0x0000041F, 0x00000468, 0x00000470, 0x00000417, 0x0000041F, 0x00000477, 0x0000047F,

2
src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeBreak.trie.cs

@ -18,7 +18,7 @@ internal static class GraphemeBreakTrie
get => new(Data, 0x000E1000, 0x00000000);
}
private static ReadOnlySpan<uint> Data => new uint[]
private static readonly uint[] Data = new uint[]
{
0x0000035A, 0x00000362, 0x0000036A, 0x00000372, 0x0000038A, 0x00000392, 0x00000362, 0x0000036A, 0x00000362, 0x0000036A, 0x00000362, 0x0000036A,
0x00000362, 0x0000036A, 0x00000362, 0x0000036A, 0x00000362, 0x0000036A, 0x00000362, 0x0000036A, 0x00000362, 0x0000036A, 0x00000362, 0x0000036A,

98
src/Avalonia.Base/Media/TextFormatting/Unicode/LineBreakEnumerator.cs

@ -12,7 +12,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
private static readonly BreakUnit s_eot = new() { EndOfText = true };
public readonly ReadOnlySpan<char> _text;
private readonly LineBreakState _state;
private LineBreakState _state;
public LineBreakEnumerator(ReadOnlySpan<char> text)
{
@ -20,7 +20,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
_state = new LineBreakState();
}
public readonly bool MoveNext([NotNullWhen(true)] out LineBreak lineBreak)
public bool MoveNext([NotNullWhen(true)] out LineBreak lineBreak)
{
lineBreak = default;
@ -35,7 +35,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
{
_state.Read(_text);
result = ExecuteRules(_text, _state);
result = ExecuteRules(_text, ref _state);
}
if (result == null)
@ -120,11 +120,11 @@ namespace Avalonia.Media.TextFormatting.Unicode
return from;
}
private static LineBreak? ExecuteRules(ReadOnlySpan<char> text, LineBreakState state)
private static LineBreak? ExecuteRules(ReadOnlySpan<char> text, ref LineBreakState state)
{
foreach (var rule in s_rules)
{
var res = rule.Invoke(text, state);
var res = rule.Invoke(text, ref state);
switch (res)
{
@ -143,7 +143,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
return null;
}
private static RuleResult QuotationAndRegionalIndicator(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult QuotationAndRegionalIndicator(ReadOnlySpan<char> text, ref LineBreakState state)
{
if (state.Current.Inherited)
{
@ -176,7 +176,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB3: Always break at the end of text.
/// </summary>
private static RuleResult LB03(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB03(ReadOnlySpan<char> text, ref LineBreakState state)
{
if (state.Current.EndOfText)
{
@ -189,7 +189,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB4: Always break after hard line breaks.
/// </summary>
private static RuleResult LB04(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB04(ReadOnlySpan<char> text, ref LineBreakState state)
{
// BK !
if (state.Current.LineBreakClass == LineBreakClass.MandatoryBreak)
@ -203,7 +203,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB5: Treat CR followed by LF, as well as CR, LF, and NL as hard line
/// </summary>
private static RuleResult LB05(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB05(ReadOnlySpan<char> text, ref LineBreakState state)
{
switch (state.Current.LineBreakClass)
{
@ -227,7 +227,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// LB6: Do not break before hard line breaks.
/// </summary>
/// <returns></returns>
private static RuleResult LB06(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB06(ReadOnlySpan<char> text, ref LineBreakState state)
{
// × ( BK | CR | LF | NL )
if (IsBreakClass(state.Next(text).LineBreakClass))
@ -241,7 +241,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB7: Do not break before spaces or zero width space.
/// </summary>
private static RuleResult LB07(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB07(ReadOnlySpan<char> text, ref LineBreakState state)
{
// × SP
// × ZW
@ -261,7 +261,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB8: Break before any character following a zero-width space, even if one or more spaces intervene.
/// </summary>
private static RuleResult LB08(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB08(ReadOnlySpan<char> text, ref LineBreakState state)
{
if (state.LastBeforeSpace.LineBreakClass == LineBreakClass.ZWSpace && state.Next(text).LineBreakClass != LineBreakClass.Space)
{
@ -274,7 +274,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB8a: Do not break after a zero width joiner.
/// </summary>
private static RuleResult LB08a(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB08a(ReadOnlySpan<char> text, ref LineBreakState state)
{
// ZWJ ×
if (state.Current.LineBreakClass == LineBreakClass.ZWJ)
@ -290,7 +290,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// treat it as if it has the line breaking class of the base character in all of the following rules.
/// Treat ZWJ as if it were CM.
/// </summary>
private static RuleResult LB09(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB09(ReadOnlySpan<char> text, ref LineBreakState state)
{
// Treat X (CM | ZWJ)* as if it were X.
// where X is any line break class except BK, CR, LF, NL, SP, or ZW.
@ -319,7 +319,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB10: Treat any remaining combining mark or ZWJ as AL.
/// </summary>
private static RuleResult LB10(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB10(ReadOnlySpan<char> text, ref LineBreakState state)
{
if (state.Current.LineBreakClass == LineBreakClass.CombiningMark)
{
@ -338,7 +338,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB11: Do not break before or after Word joiner and related characters.
/// </summary>
private static RuleResult LB11(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB11(ReadOnlySpan<char> text, ref LineBreakState state)
{
if (state.Next(text).LineBreakClass == LineBreakClass.WordJoiner /* × WJ */
|| state.Current.LineBreakClass == LineBreakClass.WordJoiner /* WJ × */)
@ -352,7 +352,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB12: Do not break after NBSP and related characters.
/// </summary>
private static RuleResult LB12(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB12(ReadOnlySpan<char> text, ref LineBreakState state)
{
// GL ×
if (state.Current.LineBreakClass == LineBreakClass.Glue)
@ -366,7 +366,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB12a: Do not break before NBSP and related characters, except after spaces and hyphens.
/// </summary>
private static RuleResult LB12a(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB12a(ReadOnlySpan<char> text, ref LineBreakState state)
{
// [^SP BA HY] × GL
if (state.Next(text).LineBreakClass == LineBreakClass.Glue)
@ -388,7 +388,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB13: Do not break before ‘]’ or ‘!’ or ‘;’ or ‘/’, even after spaces.
/// </summary>
private static RuleResult LB13(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB13(ReadOnlySpan<char> text, ref LineBreakState state)
{
// × CL
// × CP
@ -409,7 +409,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB14: Do not break after ‘[’, even after spaces.
/// </summary>
private static RuleResult LB14(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB14(ReadOnlySpan<char> text, ref LineBreakState state)
{
// OP SP* ×
if (state.LastBeforeWhitespace.LineBreakClass == LineBreakClass.OpenPunctuation)
@ -424,7 +424,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// LB15a: Do not break after an unresolved initial punctuation that lies at the start of the line,
/// after a space, after opening punctuation, or after an unresolved quotation mark, even after spaces.
/// </summary>
private static RuleResult LB15a(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB15a(ReadOnlySpan<char> text, ref LineBreakState state)
{
// (sot | BK | CR | LF | NL | OP | QU | GL | SP | ZW) [\p{Pi}&QU] SP* ×
if (state.Quotation > 0 && state.LastBeforeWhitespace.Codepoint.GeneralCategory == GeneralCategory.InitialPunctuation &&
@ -487,7 +487,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// LB15b: Do not break before an unresolved final punctuation that lies at the end of the line,
/// before a space, before a prohibited break, or before an unresolved quotation mark, even after spaces.
/// </summary>
private static RuleResult LB15b(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB15b(ReadOnlySpan<char> text, ref LineBreakState state)
{
// × [\p{Pf}&QU] ( SP | GL | WJ | CL | QU | CP | EX | IS | SY | BK | CR | LF | NL | ZW | eot)
if (state.Next(text).Codepoint.GeneralCategory == GeneralCategory.FinalPunctuation && (state.Next(text).LineBreakClass == LineBreakClass.Quotation))
@ -526,7 +526,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB15c: Break before a decimal mark that follows a space, for instance, in ‘subtract .5’.
/// </summary>
private static RuleResult LB15c(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB15c(ReadOnlySpan<char> text, ref LineBreakState state)
{
// SP ÷ IS NU
if (state.Current.LineBreakClass == LineBreakClass.Space)
@ -546,7 +546,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB15d: Otherwise, do not break before ‘;’, ‘,’, or ‘.’, even after spaces.
/// </summary>
private static RuleResult LB15d(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB15d(ReadOnlySpan<char> text, ref LineBreakState state)
{
// × IS
if (state.Next(text).LineBreakClass == LineBreakClass.InfixNumeric)
@ -562,7 +562,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// LB16: Do not break between closing punctuation and a nonstarter (lb=NS),
/// even with intervening spaces.
/// </summary>
private static RuleResult LB16(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB16(ReadOnlySpan<char> text, ref LineBreakState state)
{
switch (state.LastBeforeWhitespace.LineBreakClass)
{
@ -590,7 +590,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB17: Do not break within ‘——’, even with intervening spaces.
/// </summary>
private static RuleResult LB17(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB17(ReadOnlySpan<char> text, ref LineBreakState state)
{
// B2 SP* × B2
if (state.LastBeforeWhitespace.LineBreakClass == LineBreakClass.BreakBoth)
@ -607,7 +607,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB18: Break after spaces.
/// </summary>
private static RuleResult LB18(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB18(ReadOnlySpan<char> text, ref LineBreakState state)
{
// SP ÷
if (state.Current.LineBreakClass == LineBreakClass.Space)
@ -621,7 +621,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB19: Do not break before or after quotation marks, such as ‘ ” ’.
/// </summary>
private static RuleResult LB19(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB19(ReadOnlySpan<char> text, ref LineBreakState state)
{
var next = state.Next(text);
@ -677,7 +677,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB20: Break before and after unresolved CB.
/// </summary>
private static RuleResult LB20(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB20(ReadOnlySpan<char> text, ref LineBreakState state)
{
// ÷ CB
// CB ÷
@ -692,7 +692,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB20a: Do not break after a word-initial hyphen.
/// </summary>
private static RuleResult LB20a(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB20a(ReadOnlySpan<char> text, ref LineBreakState state)
{
// (sot | BK | CR | LF | NL | SP | ZW | CB | GL)(HY | [\u2010]) × AL
if (IsMatch(state.Previous) && state.Next(text).LineBreakClass == LineBreakClass.Alphabetic)
@ -733,7 +733,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB21: Do not break before hyphen-minus, other hyphens, fixed-width spaces, small kana, and other non-starters, or after acute accents.
/// </summary>
private static RuleResult LB21(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB21(ReadOnlySpan<char> text, ref LineBreakState state)
{
// × (BA | HY | NS)
switch (state.Next(text).LineBreakClass)
@ -760,7 +760,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB21a: Don't break after Hebrew + Hyphen.
/// </summary>
private static RuleResult LB21a(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB21a(ReadOnlySpan<char> text, ref LineBreakState state)
{
if(state.Next(text).LineBreakClass != LineBreakClass.HebrewLetter)
{
@ -778,7 +778,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB21b: Don’t break between Solidus and Hebrew letters.
/// </summary>
private static RuleResult LB21b(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB21b(ReadOnlySpan<char> text, ref LineBreakState state)
{
// [21.2] SY × HL
if ((state.Current.LineBreakClass == LineBreakClass.BreakSymbols) && (state.Next(text).LineBreakClass == LineBreakClass.HebrewLetter))
@ -792,7 +792,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB22: Do not break before ellipses.
/// </summary>
private static RuleResult LB22(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB22(ReadOnlySpan<char> text, ref LineBreakState state)
{
// × IN
if (state.Next(text).LineBreakClass == LineBreakClass.Inseparable)
@ -806,7 +806,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB23: Do not break between digits and letters.
/// </summary>
private static RuleResult LB23(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB23(ReadOnlySpan<char> text, ref LineBreakState state)
{
switch (state.Current.LineBreakClass)
{
@ -842,7 +842,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// LB23a: Do not break between numeric prefixes and ideographs, or between
/// ideographs and numeric postfixes.
/// </summary>
private static RuleResult LB23a(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB23a(ReadOnlySpan<char> text, ref LineBreakState state)
{
// PR × (ID | EB | EM)
if ((state.Current.LineBreakClass == LineBreakClass.PrefixNumeric)
@ -878,7 +878,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// LB24: Do not break between numeric prefix/postfix and letters, or between
/// letters and prefix/postfix.
/// </summary>
private static RuleResult LB24(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB24(ReadOnlySpan<char> text, ref LineBreakState state)
{
// (PR | PO) × (AL | HL)
if (state.Current.LineBreakClass is LineBreakClass.PrefixNumeric or LineBreakClass.PostfixNumeric
@ -900,7 +900,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB25: Do not break between the following pairs of classes relevant to numbers
/// </summary>
private static RuleResult LB25(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB25(ReadOnlySpan<char> text, ref LineBreakState state)
{
switch (state.Next(text).LineBreakClass)
{
@ -1128,7 +1128,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB26: Do not break a Korean syllable.
/// </summary>
private static RuleResult LB26(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB26(ReadOnlySpan<char> text, ref LineBreakState state)
{
switch (state.Current.LineBreakClass)
{
@ -1176,7 +1176,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB27: Treat a Korean Syllable Block the same as ID.
/// </summary>
private static RuleResult LB27(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB27(ReadOnlySpan<char> text, ref LineBreakState state)
{
switch (state.Current.LineBreakClass)
{
@ -1216,7 +1216,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB28: Do not break between alphabetics (“at”).
/// </summary>
private static RuleResult LB28(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB28(ReadOnlySpan<char> text, ref LineBreakState state)
{
// [28.0] (AL | HL) × (AL | HL)
switch (state.Current.LineBreakClass)
@ -1243,7 +1243,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB28a: Do not break inside the orthographic syllables of Brahmic scripts.
/// </summary>
private static RuleResult LB28a(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB28a(ReadOnlySpan<char> text, ref LineBreakState state)
{
// [28.11] AP × (AK | DottedCircle | AS)
if ((state.Current.LineBreakClass == LineBreakClass.AksaraPrebase) && isMatch(state.Next(text)))
@ -1286,7 +1286,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB29: Do not break between numeric punctuation and alphabetics (“e.g.”).
/// </summary>
private static RuleResult LB29(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB29(ReadOnlySpan<char> text, ref LineBreakState state)
{
// IS × (AL | HL)
if ((state.Current.LineBreakClass == LineBreakClass.InfixNumeric)
@ -1301,7 +1301,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB30: Do not break between letters, numbers, or ordinary symbols and opening or closing parentheses.
/// </summary>
private static RuleResult LB30(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB30(ReadOnlySpan<char> text, ref LineBreakState state)
{
switch (state.Current.LineBreakClass)
{
@ -1346,7 +1346,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// break.
/// </summary>
/// <returns></returns>
private static RuleResult LB30a(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB30a(ReadOnlySpan<char> text, ref LineBreakState state)
{
if (state.RegionalIndicator > 0 && state.Next(text).LineBreakClass == LineBreakClass.RegionalIndicator)
{
@ -1363,7 +1363,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// LB30b: Do not break between an emoji base (or potential emoji) and an emoji modifier.
/// </summary>
/// <returns></returns>
private static RuleResult LB30b(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB30b(ReadOnlySpan<char> text, ref LineBreakState state)
{
// EB × EM
if ((state.Current.LineBreakClass == LineBreakClass.EBase) && (state.Next(text).LineBreakClass == LineBreakClass.EModifier))
@ -1392,7 +1392,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <summary>
/// LB31: Break everywhere else.
/// </summary>
private static RuleResult LB31(ReadOnlySpan<char> text, LineBreakState state)
private static RuleResult LB31(ReadOnlySpan<char> text, ref LineBreakState state)
{
return RuleResult.MayBreak;
}
@ -1491,7 +1491,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
}
}
private class LineBreakState
private ref struct LineBreakState
{
private BreakUnit? _next;
private BreakUnit _previous;
@ -1651,7 +1651,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
}
}
private delegate RuleResult BreakUnitDelegate(ReadOnlySpan<char> text, LineBreakState state);
private delegate RuleResult BreakUnitDelegate(ReadOnlySpan<char> text, ref LineBreakState state);
private static readonly BreakUnitDelegate[] s_rules = [
QuotationAndRegionalIndicator,

18
src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeData.trie.cs

@ -16,10 +16,18 @@ internal static class UnicodeDataTrie
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new(Data, 0x00100000, 0x00000000);
}
private static ReadOnlySpan<uint> Data => new uint[]
{
}
// For Debug builds, we store the data in a separate uint[] field to avoid RuntimeFieldInfoStub allocations.
// See also: https://github.com/AvaloniaUI/Avalonia/pull/20175
#if DEBUG
public static ReadOnlySpan<uint> Data => s_data;
private static uint[] s_data =
#else
public static ReadOnlySpan<uint> Data =>
#endif
[
0x00000482, 0x0000048A, 0x00000492, 0x0000049A, 0x000004B2, 0x000004BA, 0x000004C2, 0x000004CA, 0x000004D2, 0x000004DA, 0x000004E0, 0x000004E8,
0x000004F0, 0x000004F8, 0x00000500, 0x00000508, 0x0000050E, 0x00000516, 0x0000051E, 0x00000526, 0x00000529, 0x00000531, 0x00000539, 0x00000541,
0x00000549, 0x00000551, 0x00000556, 0x0000055E, 0x00000566, 0x0000056E, 0x00000573, 0x0000057B, 0x00000583, 0x0000058B, 0x0000058F, 0x00000597,
@ -2351,5 +2359,5 @@ internal static class UnicodeDataTrie
0x00038061, 0x00038061, 0x00038061, 0x00038061, 0x00038061, 0x00074061, 0x00074061, 0x00074061, 0x00038061, 0x00074061, 0x00074061, 0x00074061,
0x00074061, 0x00074061, 0x00074061, 0x00074061, 0x00074061, 0x00074061, 0x00074061, 0x00074061, 0x00074061, 0x00074061, 0x00038061, 0x00038061,
0x00000000, 0x00000000, 0x00000000, 0x00000000
};
];
}

6
src/Avalonia.Base/Media/TextPathSegmentEllipsis.cs

@ -415,12 +415,6 @@ namespace Avalonia.Media
return false;
}
/// <summary>
/// Finds the index of the text run and the offset within that run corresponding to the specified character
/// index.
/// </summary>
/// <remarks>If the specified character index does not fall within any run, the method returns
/// <summary>
/// Calculates the total width of a specified segment within a sequence of text runs.
/// </summary>

4
src/Avalonia.Base/Platform/Storage/FilePickerOpenOptions.cs

@ -11,8 +11,8 @@ public class FilePickerOpenOptions : PickerOptions
/// Gets or sets the file type that should be preselected when the dialog is opened.
/// </summary>
/// <remarks>
/// This value should reference one of the items in <see cref="FileTypeChoices"/>.
/// If not set, the first file type in <see cref="FileTypeChoices"/> may be selected by default.
/// This value should reference one of the items in <see cref="FileTypeFilter"/>.
/// If not set, the first file type in <see cref="FileTypeFilter"/> may be selected by default.
/// </remarks>
public FilePickerFileType? SuggestedFileType { get; set; }

2
src/Avalonia.Base/Platform/Storage/NoopStorageProvider.cs

@ -21,7 +21,7 @@ internal class NoopStorageProvider : BclStorageProvider
public override Task<SaveFilePickerResult> SaveFilePickerWithResultAsync(FilePickerSaveOptions options)
{
return Task.FromResult(new SaveFilePickerResult(null));
return Task.FromResult(new SaveFilePickerResult());
}
public override bool CanPickFolder => false;

7
src/Avalonia.Base/Platform/Storage/SaveFilePickerResult.cs

@ -3,13 +3,8 @@ namespace Avalonia.Platform.Storage;
/// <summary>
/// Extended result of the <see cref="IStorageProvider.SaveFilePickerWithResultAsync(FilePickerSaveOptions)"/> operation.
/// </summary>
public readonly struct SaveFilePickerResult
public readonly record struct SaveFilePickerResult
{
internal SaveFilePickerResult(IStorageFile? file)
{
File = file;
}
/// <summary>
/// Saved <see cref="IStorageFile"/> or null if user canceled the dialog.
/// </summary>

4
src/Avalonia.Base/Rendering/Composition/CompositionDrawingSurface.cs

@ -41,13 +41,15 @@ public sealed class CompositionDrawingSurface : CompositionSurface, IDisposable
var signal = (CompositionImportedGpuSemaphore)signalSemaphore;
return Compositor.InvokeServerJobAsync(() => Server.UpdateWithSemaphores(img, wait, signal));
}
/// <summary>
/// Updates the surface contents using an imported memory image using a semaphore pair as the means of synchronization
/// </summary>
/// <param name="image">GPU image with new surface contents</param>
/// <param name="waitForSemaphore">The semaphore to wait for before accessing the image</param>
/// <param name="waitForValue">The value to wait for before accessing the image</param>
/// <param name="signalSemaphore">The semaphore to signal after accessing the image</param>
/// <param name="signalValue">The value to signal after accessing the image</param>
/// <returns>A task that completes when update operation is completed and user code is free to destroy or dispose the image</returns>
public Task UpdateWithTimelineSemaphoresAsync(ICompositionImportedGpuImage image,
ICompositionImportedGpuSemaphore waitForSemaphore, ulong waitForValue,

6
src/Avalonia.Base/Styling/Selector.cs

@ -76,7 +76,11 @@ namespace Avalonia.Styling
/// <param name="owner">The owner style.</param>
public abstract string ToString(Style? owner);
/// <inheritdoc cref="ToString(Style?)"/>
/// <summary>
/// Gets a string representing the selector, with the nesting separator (`^`) replaced with
/// the parent selector.
/// </summary>
/// <param name="owner">The owner style.</param>
/// <param name="hasNext">Whether there is a selector that comes after this one.</param>
internal virtual string ToString(Style? owner, bool hasNext) => ToString(owner);

6
src/Avalonia.Base/Threading/Dispatcher.MainLoop.cs

@ -141,6 +141,8 @@ public partial class Dispatcher
else
{
operation = null;
_impl.UpdateTimer(null);
_hasShutdownFinished = true;
}
}
@ -150,8 +152,6 @@ public partial class Dispatcher
}
} while (operation != null);
_impl.UpdateTimer(null);
_hasShutdownFinished = true;
ShutdownFinished?.Invoke(this, EventArgs.Empty);
}
@ -213,4 +213,4 @@ public partial class Dispatcher
return new DispatcherProcessingDisabled(this, oldContext);
}
}
}

19
src/Avalonia.Base/Threading/DispatcherPriorityAwaitable.cs

@ -1,4 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
@ -8,6 +9,10 @@ namespace Avalonia.Threading;
/// <summary>
/// A simple awaitable type that will return a DispatcherPriorityAwaiter.
/// </summary>
[UnconditionalSuppressMessage(
"Performance",
"CA1815:Override equals and operator equals on value types",
Justification = "This struct is not supposed to be used directly and should not be compared.")]
public struct DispatcherPriorityAwaitable
{
private readonly Dispatcher _dispatcher;
@ -30,6 +35,10 @@ public struct DispatcherPriorityAwaitable
/// <remarks>
/// This is returned from DispatcherPriorityAwaitable.GetAwaiter()
/// </remarks>
[UnconditionalSuppressMessage(
"Performance",
"CA1815:Override equals and operator equals on value types",
Justification = "This struct is not supposed to be used directly and should not be compared.")]
public struct DispatcherPriorityAwaiter : INotifyCompletion
{
private readonly Dispatcher _dispatcher;
@ -72,6 +81,10 @@ public struct DispatcherPriorityAwaiter : INotifyCompletion
/// <summary>
/// A simple awaitable type that will return a DispatcherPriorityAwaiter&lt;T&gt;.
/// </summary>
[UnconditionalSuppressMessage(
"Performance",
"CA1815:Override equals and operator equals on value types",
Justification = "This struct is not supposed to be used directly and should not be compared.")]
public struct DispatcherPriorityAwaitable<T>
{
private readonly Dispatcher _dispatcher;
@ -94,6 +107,10 @@ public struct DispatcherPriorityAwaitable<T>
/// <remarks>
/// This is returned from DispatcherPriorityAwaitable&lt;T&gt;.GetAwaiter()
/// </remarks>
[UnconditionalSuppressMessage(
"Performance",
"CA1815:Override equals and operator equals on value types",
Justification = "This struct is not supposed to be used directly and should not be compared.")]
public struct DispatcherPriorityAwaiter<T> : INotifyCompletion
{
private readonly Dispatcher _dispatcher;
@ -127,4 +144,4 @@ public struct DispatcherPriorityAwaiter<T> : INotifyCompletion
public bool IsCompleted => false;
public void GetResult() => _task.GetAwaiter().GetResult();
}
}

4
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@ -131,9 +131,9 @@
<Compile Include="../Avalonia.Base/Diagnostics/TrimmingMessages.cs" Link="Diagnostics/TrimmingMessages.cs" />
<Compile Include="../Shared/StringCompatibilityExtensions.cs" Link="Compatibility/StringCompatibilityExtensions.cs" />
<Compile Include="../Shared/IsExternalInit.cs" Link="Compatibility/IsExternalInit.cs" />
<PackageReference Include="Mono.Cecil" Version="0.11.5" />
<PackageReference Include="Mono.Cecil" Version="0.11.6" />
<PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" PrivateAssets="All" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
<PackageReference Include="System.Numerics.Vectors" Version="4.6.1" />
</ItemGroup>
<Import Project="../../build/SourceGenerators.props" />
<Import Project="../../build/NullableEnable.props" />

2
src/Avalonia.Controls/Automation/Provider/IRangeValueProvider.cs

@ -127,7 +127,7 @@
/// <item>
/// <term>macOS</term>
/// <description>
/// <c>NSAccessibilityProtocol.setAccessibilityValue</c> (not implemented)
/// <c>NSAccessibilityProtocol.setAccessibilityValue</c>
/// </description>
/// </item>
/// </list>

2
src/Avalonia.Controls/Automation/Provider/IValueProvider.cs

@ -57,7 +57,7 @@
/// <item>
/// <term>macOS</term>
/// <description>
/// <c>NSAccessibilityProtocol.setAccessibilityValue</c> (not implemented)
/// <c>NSAccessibilityProtocol.setAccessibilityValue</c>
/// </description>
/// </item>
/// </list>

45
src/Avalonia.Controls/ComboBox.cs

@ -8,6 +8,7 @@ using Avalonia.Controls.Templates;
using Avalonia.Controls.Utils;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Metadata;
@ -270,12 +271,6 @@ namespace Avalonia.Controls
SetCurrentValue(IsDropDownOpenProperty, true);
e.Handled = true;
}
else if (IsDropDownOpen && (e.Key == Key.Enter || e.Key == Key.Space))
{
SelectFocusedItem();
SetCurrentValue(IsDropDownOpenProperty, false);
e.Handled = true;
}
else if (IsDropDownOpen && e.Key == Key.Tab)
{
SetCurrentValue(IsDropDownOpenProperty, false);
@ -366,15 +361,7 @@ namespace Avalonia.Controls
if (!e.Handled && e.Source is Visual source)
{
if (_popup?.IsInsidePopup(source) == true)
{
if (UpdateSelectionFromEventSource(e.Source))
{
_popup?.Close();
e.Handled = true;
}
}
else if (PseudoClasses.Contains(pcPressed))
if (_popup?.IsInsidePopup(source) != true && PseudoClasses.Contains(pcPressed))
{
SetCurrentValue(IsDropDownOpenProperty, !IsDropDownOpen);
e.Handled = true;
@ -385,6 +372,22 @@ namespace Avalonia.Controls
base.OnPointerReleased(e);
}
public override bool UpdateSelectionFromEvent(Control container, RoutedEventArgs eventArgs)
{
if (base.UpdateSelectionFromEvent(container, eventArgs))
{
_popup?.Close();
return true;
}
return false;
}
protected override bool ShouldTriggerSelection(Visual selectable, PointerEventArgs eventArgs) =>
ItemSelectionEventTriggers.IsPointerEventWithinBounds(selectable, eventArgs) &&
eventArgs is { Properties.PointerUpdateKind: PointerUpdateKind.LeftButtonReleased or PointerUpdateKind.RightButtonReleased } &&
eventArgs.RoutedEvent == PointerReleasedEvent;
/// <inheritdoc/>
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
@ -602,18 +605,6 @@ namespace Avalonia.Controls
SetCurrentValue(TextProperty, GetItemTextValue(item));
}
private void SelectFocusedItem()
{
foreach (var dropdownItem in GetRealizedContainers())
{
if (dropdownItem.IsFocused)
{
SelectedIndex = IndexFromContainer(dropdownItem);
break;
}
}
}
private bool SelectNext() => MoveSelection(SelectedIndex, 1, WrapSelection);
private bool SelectPrevious() => MoveSelection(SelectedIndex, -1, WrapSelection);

22
src/Avalonia.Controls/ListBox.cs

@ -146,14 +146,6 @@ namespace Avalonia.Controls
Selection.SelectAll();
e.Handled = true;
}
else if (e.Key == Key.Space || e.Key == Key.Enter)
{
UpdateSelectionFromEventSource(
e.Source,
true,
e.KeyModifiers.HasFlag(KeyModifiers.Shift),
ctrl);
}
base.OnKeyDown(e);
}
@ -163,19 +155,5 @@ namespace Avalonia.Controls
base.OnApplyTemplate(e);
Scroll = e.NameScope.Find<IScrollable>("PART_ScrollViewer");
}
internal bool UpdateSelectionFromPointerEvent(Control source, PointerEventArgs e)
{
// TODO: use TopLevel.PlatformSettings here, but first need to update our tests to use TopLevels.
var hotkeys = Application.Current!.PlatformSettings?.HotkeyConfiguration;
var toggle = hotkeys is not null && e.KeyModifiers.HasAllFlags(hotkeys.CommandModifiers);
return UpdateSelectionFromEventSource(
source,
true,
e.KeyModifiers.HasAllFlags(KeyModifiers.Shift),
toggle,
e.GetCurrentPoint(source).Properties.IsRightButtonPressed);
}
}
}

76
src/Avalonia.Controls/ListBoxItem.cs

@ -4,7 +4,7 @@ using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Platform;
using Avalonia.Interactivity;
namespace Avalonia.Controls
{
@ -20,9 +20,6 @@ namespace Avalonia.Controls
public static readonly StyledProperty<bool> IsSelectedProperty =
SelectingItemsControl.IsSelectedProperty.AddOwner<ListBoxItem>();
private static readonly Point s_invalidPoint = new Point(double.NaN, double.NaN);
private Point _pointerDownPoint = s_invalidPoint;
/// <summary>
/// Initializes static members of the <see cref="ListBoxItem"/> class.
/// </summary>
@ -51,76 +48,21 @@ namespace Avalonia.Controls
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
_pointerDownPoint = s_invalidPoint;
if (e.Handled)
return;
if (!e.Handled && ItemsControl.ItemsControlFromItemContainer(this) is ListBox owner)
{
var p = e.GetCurrentPoint(this);
if (p.Properties.PointerUpdateKind is PointerUpdateKind.LeftButtonPressed or
PointerUpdateKind.RightButtonPressed)
{
if (p.Pointer.Type == PointerType.Mouse
|| (p.Pointer.Type == PointerType.Pen && p.Properties.IsRightButtonPressed))
{
// If the pressed point comes from a mouse or right-click pen, perform the selection immediately.
// In case of pen, only right-click is accepted, as left click (a tip touch) is used for scrolling.
e.Handled = owner.UpdateSelectionFromPointerEvent(this, e);
}
else
{
// Otherwise perform the selection when the pointer is released as to not
// interfere with gestures.
_pointerDownPoint = p.Position;
// Ideally we'd set handled here, but that would prevent the scroll gesture
// recognizer from working.
////e.Handled = true;
}
}
}
UpdateSelectionFromEvent(e);
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);
UpdateSelectionFromEvent(e);
}
if (!e.Handled &&
!double.IsNaN(_pointerDownPoint.X) &&
e.InitialPressMouseButton is MouseButton.Left or MouseButton.Right)
{
var point = e.GetCurrentPoint(this);
var settings = TopLevel.GetTopLevel(e.Source as Visual)?.PlatformSettings;
var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4);
var tapRect = new Rect(_pointerDownPoint, new Size())
.Inflate(new Thickness(tapSize.Width, tapSize.Height));
if (new Rect(Bounds.Size).ContainsExclusive(point.Position) &&
tapRect.ContainsExclusive(point.Position) &&
ItemsControl.ItemsControlFromItemContainer(this) is ListBox owner)
{
if (owner.UpdateSelectionFromPointerEvent(this, e))
{
// As we only update selection from touch/pen on pointer release, we need to raise
// the pointer event on the owner to trigger a commit.
if (e.Pointer.Type != PointerType.Mouse)
{
var sourceBackup = e.Source;
owner.RaiseEvent(e);
e.Source = sourceBackup;
}
e.Handled = true;
}
}
}
_pointerDownPoint = s_invalidPoint;
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
UpdateSelectionFromEvent(e);
}
protected bool UpdateSelectionFromEvent(RoutedEventArgs e) => SelectingItemsControl.ItemsControlFromItemContainer(this)?.UpdateSelectionFromEvent(this, e) ?? false;
}
}

2
src/Avalonia.Controls/MenuItem.cs

@ -484,7 +484,7 @@ namespace Avalonia.Controls
protected override void OnGotFocus(GotFocusEventArgs e)
{
base.OnGotFocus(e);
e.Handled = UpdateSelectionFromEventSource(e.Source, true);
ItemsControlFromItemContainer(this)?.UpdateSelectionFromEvent(this, e);
}
/// <inheritdoc/>

2
src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs

@ -450,7 +450,7 @@ namespace Avalonia.Controls
{
if (IsInitialized)
{
SyncTextAndValueProperties(false, null);
SyncTextAndValueProperties(false, null, true);
}
}

82
src/Avalonia.Controls/Primitives/ItemSelectionEventTriggers.cs

@ -0,0 +1,82 @@
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
namespace Avalonia.Controls.Primitives;
/// <summary>
/// Defines standard logic for selecting items via user input. Behaviour differs between input devices.
/// </summary>
public static class ItemSelectionEventTriggers
{
/// <summary>
/// Analyses an input event received by a selectable element, and determines whether the action should trigger selection on press, on release, or not at all.
/// </summary>
/// <param name="selectable">The selectable element which is processing the event.</param>
/// <param name="eventArgs">The event to analyse.</param>
public static bool ShouldTriggerSelection(Visual selectable, PointerEventArgs eventArgs)
{
if (!IsPointerEventWithinBounds(selectable, eventArgs))
{
return false; // don't select if the pointer has moved away from the element since being pressed
}
return eventArgs switch
{
// Only select for left/right button events
{
Properties.PointerUpdateKind: not (PointerUpdateKind.LeftButtonPressed or PointerUpdateKind.RightButtonPressed or
PointerUpdateKind.LeftButtonReleased or PointerUpdateKind.RightButtonReleased)
} => false,
// Select on mouse press, unless the mouse can generate gestures
{ Pointer.Type: PointerType.Mouse } => eventArgs.RoutedEvent == (Gestures.GetIsHoldWithMouseEnabled(selectable) ?
InputElement.PointerReleasedEvent : (RoutedEvent)InputElement.PointerPressedEvent),
// Pen "right clicks" are used for context menus, and gestures are only processed for primary input
{ Pointer.Type: PointerType.Pen, Properties.PointerUpdateKind: PointerUpdateKind.RightButtonPressed or PointerUpdateKind.RightButtonReleased } =>
eventArgs.RoutedEvent == InputElement.PointerPressedEvent,
// For all other pen input, select on release
{ Pointer.Type: PointerType.Pen } => eventArgs.RoutedEvent == InputElement.PointerReleasedEvent,
// Select on touch release
{ Pointer.Type: PointerType.Touch } => eventArgs.RoutedEvent == InputElement.PointerReleasedEvent,
// Don't select in any other case
_ => false,
};
}
internal static bool IsPointerEventWithinBounds(Visual selectable, PointerEventArgs eventArgs) =>
new Rect(selectable.Bounds.Size).Contains(eventArgs.GetPosition(selectable));
/// <inheritdoc cref="ShouldTriggerSelection(Visual, PointerEventArgs)"/>
public static bool ShouldTriggerSelection(Visual selectable, KeyEventArgs eventArgs)
{
// Only accept space/enter key presses directly from the selectable, otherwise key input can become unpredictable
return eventArgs.Source == selectable && eventArgs.Key is Key.Space or Key.Enter ? eventArgs.RoutedEvent == InputElement.KeyDownEvent : false;
}
/// <summary>
/// Analyses an input event received by a selectable element, and determines whether the action should trigger range selection.
/// </summary>
/// <param name="selectable">The selectable element which is processing the event.</param>
/// <param name="eventArgs">The event to analyse.</param>
/// <seealso cref="PlatformHotkeyConfiguration.SelectionModifiers"/>
public static bool HasRangeSelectionModifier(Visual selectable, RoutedEventArgs eventArgs) => HasModifiers(eventArgs, Hotkeys(selectable)?.SelectionModifiers);
/// <summary>
/// Analyses an input event received by a selectable element, and determines whether the action should trigger toggle selection.
/// </summary>
/// <param name="selectable">The selectable element which is processing the event.</param>
/// <param name="eventArgs">The event to analyse.</param>
/// <seealso cref="PlatformHotkeyConfiguration.CommandModifiers"/>
public static bool HasToggleSelectionModifier(Visual selectable, RoutedEventArgs eventArgs) => HasModifiers(eventArgs, Hotkeys(selectable)?.CommandModifiers);
private static PlatformHotkeyConfiguration? Hotkeys(Visual element) =>
(TopLevel.GetTopLevel(element)?.PlatformSettings ?? Application.Current?.PlatformSettings)?.HotkeyConfiguration;
private static bool HasModifiers(RoutedEventArgs eventArgs, KeyModifiers? modifiers) =>
modifiers != null && eventArgs is IKeyModifiersEventArgs { KeyModifiers: { } eventModifiers } && eventModifiers.HasAllFlags(modifiers.Value);
}

61
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@ -8,6 +8,7 @@ using Avalonia.Controls.Selection;
using Avalonia.Controls.Utils;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
using Avalonia.Metadata;
using Avalonia.Threading;
@ -115,7 +116,7 @@ namespace Avalonia.Controls.Primitives
/// </summary>
public static readonly StyledProperty<bool> IsTextSearchEnabledProperty =
AvaloniaProperty.Register<SelectingItemsControl, bool>(nameof(IsTextSearchEnabled), false);
/// <summary>
/// Event that should be raised by containers when their selection state changes to notify
/// the parent <see cref="SelectingItemsControl"/> that their selection state has changed.
@ -445,6 +446,9 @@ namespace Avalonia.Controls.Primitives
return null;
}
/// <inheritdoc cref="ItemsControl.ItemsControlFromItemContainer(Control)"/>
public new static SelectingItemsControl? ItemsControlFromItemContainer(Control container) => ItemsControl.ItemsControlFromItemContainer(container) as SelectingItemsControl;
private protected override void OnItemsViewCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
base.OnItemsViewCollectionChanged(sender!, e);
@ -594,7 +598,7 @@ namespace Avalonia.Controls.Primitives
{
SelectedIndex = newIndex;
}
StartTextSearchTimer();
e.Handled = true;
@ -813,6 +817,7 @@ namespace Avalonia.Controls.Primitives
/// <param name="toggleModifier">Whether the toggle modifier is enabled (i.e. ctrl key).</param>
/// <param name="rightButton">Whether the event is a right-click.</param>
/// <param name="fromFocus">Wheter the event is a focus event</param>
[Obsolete($"Call {nameof(UpdateSelectionFromEvent)} instead.")]
protected void UpdateSelection(
Control container,
bool select = true,
@ -829,10 +834,7 @@ namespace Avalonia.Controls.Primitives
}
}
/// <summary>
/// Updates the selection based on an event that may have originated in a container that
/// belongs to the control.
/// </summary>
/// <inheritdoc cref="UpdateSelectionFromEvent"/>
/// <param name="eventSource">The control that raised the event.</param>
/// <param name="select">Whether the container should be selected or unselected.</param>
/// <param name="rangeModifier">Whether the range modifier is enabled (i.e. shift key).</param>
@ -843,6 +845,7 @@ namespace Avalonia.Controls.Primitives
/// True if the event originated from a container that belongs to the control; otherwise
/// false.
/// </returns>
[Obsolete($"Call {nameof(UpdateSelectionFromEvent)} instead.")]
protected bool UpdateSelectionFromEventSource(
object? eventSource,
bool select = true,
@ -861,6 +864,52 @@ namespace Avalonia.Controls.Primitives
return false;
}
/// <inheritdoc cref="ItemSelectionEventTriggers.ShouldTriggerSelection(Visual, PointerEventArgs)"/>
/// <seealso cref="UpdateSelectionFromEvent"/>
protected virtual bool ShouldTriggerSelection(Visual selectable, PointerEventArgs eventArgs) => ItemSelectionEventTriggers.ShouldTriggerSelection(selectable, eventArgs);
/// <inheritdoc cref="ItemSelectionEventTriggers.ShouldTriggerSelection(Visual, KeyEventArgs)"/>
protected virtual bool ShouldTriggerSelection(Visual selectable, KeyEventArgs eventArgs) => ItemSelectionEventTriggers.ShouldTriggerSelection(selectable, eventArgs);
/// <summary>
/// Updates the selection based on an event that may have originated in a container that
/// belongs to the control.
/// </summary>
/// <returns>True if the event was accepted and handled, otherwise false.</returns>
/// <seealso cref="ShouldTriggerSelection(Visual, PointerEventArgs)"/>
/// <seealso cref="ShouldTriggerSelection(Visual, KeyEventArgs)"/>
public virtual bool UpdateSelectionFromEvent(Control container, RoutedEventArgs eventArgs)
{
if (eventArgs.Handled)
{
return false;
}
var containerIndex = IndexFromContainer(container);
if (containerIndex == -1)
{
return false;
}
switch (eventArgs)
{
case PointerEventArgs pointerEvent when ShouldTriggerSelection(container, pointerEvent):
case KeyEventArgs keyEvent when ShouldTriggerSelection(container, keyEvent):
case GotFocusEventArgs:
UpdateSelection(containerIndex, true,
ItemSelectionEventTriggers.HasRangeSelectionModifier(container, eventArgs),
ItemSelectionEventTriggers.HasToggleSelectionModifier(container, eventArgs),
eventArgs is PointerEventArgs { Properties.IsRightButtonPressed: true },
eventArgs is GotFocusEventArgs);
eventArgs.Handled = true;
return true;
default:
return false;
}
}
private ISelectionModel GetOrCreateSelectionModel()
{

29
src/Avalonia.Controls/Primitives/TabStrip.cs

@ -1,5 +1,6 @@
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Layout;
namespace Avalonia.Controls.Primitives
@ -26,31 +27,17 @@ namespace Avalonia.Controls.Primitives
return NeedsContainer<TabStripItem>(item, out recycleKey);
}
/// <inheritdoc/>
protected override void OnGotFocus(GotFocusEventArgs e)
{
base.OnGotFocus(e);
if (e.NavigationMethod == NavigationMethod.Directional)
{
e.Handled = UpdateSelectionFromEventSource(e.Source);
}
}
protected override bool ShouldTriggerSelection(Visual selectable, PointerEventArgs e) =>
e.Properties.PointerUpdateKind is PointerUpdateKind.LeftButtonPressed or PointerUpdateKind.LeftButtonReleased && base.ShouldTriggerSelection(selectable, e);
/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressedEventArgs e)
public override bool UpdateSelectionFromEvent(Control container, RoutedEventArgs eventArgs)
{
base.OnPointerPressed(e);
if (e.Source is Visual source)
if (eventArgs is GotFocusEventArgs { NavigationMethod: not NavigationMethod.Directional })
{
var point = e.GetCurrentPoint(source);
if (point.Properties.IsLeftButtonPressed)
{
e.Handled = UpdateSelectionFromEventSource(e.Source);
}
return false;
}
return base.UpdateSelectionFromEvent(container, eventArgs);
}
}
}

7
src/Avalonia.Controls/Primitives/TabStripItem.cs

@ -1,3 +1,5 @@
using Avalonia.Input;
namespace Avalonia.Controls.Primitives
{
/// <summary>
@ -5,5 +7,10 @@ namespace Avalonia.Controls.Primitives
/// </summary>
public class TabStripItem : ListBoxItem
{
protected override void OnGotFocus(GotFocusEventArgs e)
{
base.OnGotFocus(e);
UpdateSelectionFromEvent(e);
}
}
}

16
src/Avalonia.Controls/Shapes/Polygon.cs

@ -9,9 +9,12 @@ namespace Avalonia.Controls.Shapes
public static readonly StyledProperty<IList<Point>> PointsProperty =
AvaloniaProperty.Register<Polygon, IList<Point>>("Points");
public static readonly StyledProperty<FillRule> FillRuleProperty =
AvaloniaProperty.Register<Polygon, FillRule>(nameof(FillRule));
static Polygon()
{
AffectsGeometry<Polygon>(PointsProperty);
AffectsGeometry<Polygon>(PointsProperty, FillRuleProperty);
}
public Polygon()
@ -25,9 +28,18 @@ namespace Avalonia.Controls.Shapes
set => SetValue(PointsProperty, value);
}
/// <summary>
/// Gets or sets how the interior of the polygon is determined when a <see cref="Shape.Fill"/> is applied.
/// </summary>
public FillRule FillRule
{
get => GetValue(FillRuleProperty);
set => SetValue(FillRuleProperty, value);
}
protected override Geometry CreateDefiningGeometry()
{
return new PolylineGeometry { Points = Points, IsFilled = true };
return new PolylineGeometry(Points, isFilled: true, fillRule: FillRule);
}
}
}

18
src/Avalonia.Controls/Shapes/Polyline.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Avalonia;
using Avalonia.Media;
using Avalonia.Data;
@ -10,10 +11,13 @@ namespace Avalonia.Controls.Shapes
public static readonly StyledProperty<IList<Point>> PointsProperty =
AvaloniaProperty.Register<Polyline, IList<Point>>("Points");
public static readonly StyledProperty<FillRule> FillRuleProperty =
AvaloniaProperty.Register<Polyline, FillRule>(nameof(FillRule));
static Polyline()
{
StrokeThicknessProperty.OverrideDefaultValue<Polyline>(1);
AffectsGeometry<Polyline>(PointsProperty);
AffectsGeometry<Polyline>(PointsProperty, FillRuleProperty);
}
public Polyline()
@ -27,9 +31,19 @@ namespace Avalonia.Controls.Shapes
set => SetValue(PointsProperty, value);
}
/// <summary>
/// Gets or sets how the interior of the polyline is determined when a <see cref="Shape.Fill"/> is applied.
/// </summary>
public FillRule FillRule
{
get => GetValue(FillRuleProperty);
set => SetValue(FillRuleProperty, value);
}
protected override Geometry CreateDefiningGeometry()
{
return new PolylineGeometry { Points = Points, IsFilled = false };
var isFilled = Fill != null;
return new PolylineGeometry(Points, isFilled, FillRule);
}
}
}

50
src/Avalonia.Controls/TabControl.cs

@ -11,6 +11,7 @@ using Avalonia.VisualTree;
using Avalonia.Automation;
using Avalonia.Controls.Metadata;
using Avalonia.Reactive;
using Avalonia.Interactivity;
namespace Avalonia.Controls
{
@ -193,6 +194,19 @@ namespace Avalonia.Controls
UpdateSelectedContent();
}
protected override bool ShouldTriggerSelection(Visual selectable, PointerEventArgs eventArgs) =>
eventArgs.Properties.PointerUpdateKind is PointerUpdateKind.LeftButtonPressed or PointerUpdateKind.LeftButtonReleased && base.ShouldTriggerSelection(selectable, eventArgs);
public override bool UpdateSelectionFromEvent(Control container, RoutedEventArgs eventArgs)
{
if (eventArgs is GotFocusEventArgs { NavigationMethod: not NavigationMethod.Directional })
{
return false;
}
return base.UpdateSelectionFromEvent(container, eventArgs);
}
private void UpdateSelectedContent(Control? container = null)
{
_selectedItemSubscriptions?.Dispose();
@ -262,42 +276,6 @@ namespace Avalonia.Controls
}
}
/// <inheritdoc/>
protected override void OnGotFocus(GotFocusEventArgs e)
{
base.OnGotFocus(e);
if (e.NavigationMethod == NavigationMethod.Directional && e.Source is TabItem)
{
e.Handled = UpdateSelectionFromEventSource(e.Source);
}
}
/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed && e.Pointer.Type == PointerType.Mouse)
{
e.Handled = UpdateSelectionFromEventSource(e.Source);
}
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
if (e.InitialPressMouseButton == MouseButton.Left && e.Pointer.Type != PointerType.Mouse)
{
var container = GetContainerFromEventSource(e.Source);
if (container != null
&& container.GetVisualsAt(e.GetPosition(container))
.Any(c => container == c || container.IsVisualAncestorOf(c)))
{
e.Handled = UpdateSelectionFromEventSource(e.Source);
}
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);

25
src/Avalonia.Controls/TabItem.cs

@ -71,7 +71,6 @@ namespace Avalonia.Controls
protected override AutomationPeer OnCreateAutomationPeer() => new ListItemAutomationPeer(this);
[Obsolete("Owner manages its children properties by itself")]
protected void SubscribeToOwnerProperties(AvaloniaObject owner)
{
@ -79,13 +78,33 @@ namespace Avalonia.Controls
private static void OnAccessKeyPressed(TabItem tabItem, AccessKeyPressedEventArgs e)
{
if (e.Handled || (e.Target != null && tabItem.IsSelected))
if (e.Handled || (e.Target != null && tabItem.IsSelected))
return;
e.Target = tabItem;
e.Handled = true;
}
protected override void OnGotFocus(GotFocusEventArgs e)
{
base.OnGotFocus(e);
UpdateSelectionFromEvent(e);
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
UpdateSelectionFromEvent(e);
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);
UpdateSelectionFromEvent(e);
}
protected bool UpdateSelectionFromEvent(RoutedEventArgs e) => SelectingItemsControl.ItemsControlFromItemContainer(this)?.UpdateSelectionFromEvent(this, e) ?? false;
private void UpdateHeader(AvaloniaPropertyChangedEventArgs obj)
{
if (Header == null)

5
src/Avalonia.Controls/TextBlock.cs

@ -97,11 +97,6 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="LetterSpacing"/> property.
/// </summary>
/// <remarks>
/// This property uses <see cref="AvaloniaProperty.AddOwner{TOwner}(AvaloniaProperty)"/> to share the same
/// definition as <see cref="TextElement.LetterSpacingProperty"/>, ensuring consistent behavior across text
/// elements and templated controls.
/// </remarks>
public static readonly StyledProperty<double> LetterSpacingProperty =
TextElement.LetterSpacingProperty.AddOwner<TextBlock>();

42
src/Avalonia.Controls/TreeView.cs

@ -11,6 +11,7 @@ using Avalonia.Collections;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Threading;
@ -662,25 +663,36 @@ namespace Avalonia.Controls
return result;
}
/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressedEventArgs e)
/// <inheritdoc cref="ItemSelectionEventTriggers.ShouldTriggerSelection(Visual, PointerEventArgs)"/>
/// <seealso cref="UpdateSelectionFromEvent"/>
protected virtual bool ShouldTriggerSelection(Visual selectable, PointerEventArgs eventArgs) => ItemSelectionEventTriggers.ShouldTriggerSelection(selectable, eventArgs);
/// <inheritdoc cref="ItemSelectionEventTriggers.ShouldTriggerSelection(Visual, PointerEventArgs)"/>
protected virtual bool ShouldTriggerSelection(Visual selectable, KeyEventArgs eventArgs) => ItemSelectionEventTriggers.ShouldTriggerSelection(selectable, eventArgs);
/// <inheritdoc cref="SelectingItemsControl.UpdateSelectionFromEvent"/>
/// <seealso cref="SelectingItemsControl.UpdateSelectionFromEvent"/>
public virtual bool UpdateSelectionFromEvent(Control container, RoutedEventArgs eventArgs)
{
base.OnPointerPressed(e);
if (eventArgs.Handled)
{
return false;
}
if (e.Source is Visual source)
switch (eventArgs)
{
var point = e.GetCurrentPoint(source);
case PointerEventArgs pointerEvent when ShouldTriggerSelection(container, pointerEvent):
case KeyEventArgs keyEvent when ShouldTriggerSelection(container, keyEvent):
UpdateSelectionFromContainer(container, true,
ItemSelectionEventTriggers.HasRangeSelectionModifier(container, eventArgs),
ItemSelectionEventTriggers.HasToggleSelectionModifier(container, eventArgs),
eventArgs is PointerEventArgs { Properties.IsRightButtonPressed: true });
if (point.Properties.IsLeftButtonPressed || point.Properties.IsRightButtonPressed)
{
var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration;
e.Handled = UpdateSelectionFromEventSource(
e.Source,
true,
e.KeyModifiers.HasAllFlags(KeyModifiers.Shift),
e.KeyModifiers.HasAllFlags(keymap.CommandModifiers),
point.Properties.IsRightButtonPressed);
}
eventArgs.Handled = true;
return true;
default:
return false;
}
}

16
src/Avalonia.Controls/TreeViewItem.cs

@ -229,6 +229,10 @@ namespace Avalonia.Controls
{
e.Handled = handler(this);
}
else
{
TreeViewOwner?.UpdateSelectionFromEvent(this, e);
}
// NOTE: these local functions do not use the TreeView.Expand/CollapseSubtree
// function because we want to know if any items were in fact expanded to set the
@ -304,6 +308,18 @@ namespace Avalonia.Controls
// Don't call base.OnKeyDown - let events bubble up to containing TreeView.
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
TreeViewOwner?.UpdateSelectionFromEvent(this, e);
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);
TreeViewOwner?.UpdateSelectionFromEvent(this, e);
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
if (_headerPresenter is InputElement previousInputMethod)

12
src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj

@ -10,6 +10,7 @@
<NoWarn>$(NoWarn);CS1591</NoWarn>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NugetPackageName>Avalonia</NugetPackageName>
<WebAppDir>$(MSBuildThisFileDirectory)Remote/HtmlTransport/webapp</WebAppDir>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="Remote\HtmlTransport\webapp\build\**\*.gz" />
@ -19,4 +20,15 @@
<ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj" />
</ItemGroup>
<Target Name="BunInstall" Inputs="$(WebAppDir)\package.json" Outputs="$(WebAppDir)\node_modules\.install-stamp">
<!-- We use bun packages as .NET tool, to avoid preinstalled node.js dependency -->
<Exec Command="dnx Bun.Unofficial.Tool --yes -- install" WorkingDirectory="$(WebAppDir)" />
<!-- Write the stamp file, so incremental builds work -->
<Touch Files="$(WebAppDir)\node_modules\.install-stamp" AlwaysCreate="true" />
</Target>
<Target Name="BunRunBuild" DependsOnTargets="BunInstall" BeforeTargets="DispatchToInnerBuilds">
<Exec Command="dnx Bun.Unofficial.Tool build.js" WorkingDirectory="$(WebAppDir)" />
</Target>
</Project>

132
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/bun.lock

@ -0,0 +1,132 @@
{
"lockfileVersion": 1,
"configVersion": 1,
"workspaces": {
"": {
"name": "previewer",
"dependencies": {
"@types/react": "^17.0.38",
"@types/react-dom": "^17.0.11",
"mobx": "^6.3.13",
"mobx-react": "^7.2.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
},
"devDependencies": {
"@chialab/esbuild-plugin-html": "^0.17.0",
"esbuild": "^0.14.54",
"esbuild-plugin-compress": "^0.4.0",
"typescript": "^4.7.4",
},
},
},
"packages": {
"@chialab/esbuild-plugin-html": ["@chialab/esbuild-plugin-html@0.17.3", "", { "dependencies": { "@chialab/esbuild-rna": "^0.17.8", "@chialab/node-resolve": "^0.17.1" } }, "sha512-Q9ztdU/wJ0em7LHA+CeB/xqmhIoI5Gk4Y+gCiGmxVrHaT6AkkfAjYVojlyAA91JlpvXmtDIhUaVcJyhtmcip7g=="],
"@chialab/esbuild-rna": ["@chialab/esbuild-rna@0.17.8", "", { "dependencies": { "@chialab/estransform": "^0.17.4", "@chialab/node-resolve": "^0.17.1" } }, "sha512-hovU4W5zlyMnbJjexdczpQ9mcUfFsJuv9FWUhzpXiQwPprlp5lul+frTed9s8AyVDTDq2yq3Gx2Ac411QsXYGA=="],
"@chialab/estransform": ["@chialab/estransform@0.17.5", "", { "dependencies": { "@parcel/source-map": "^2.0.0" } }, "sha512-maJUFkwk0ie0L4VvDO74NDYyRvaTQAI0qmSmrms8bZxUkZ+zQZd1ByWKDCYTRwtR6AOzTvgEOl2ZvEG+OUKv/A=="],
"@chialab/node-resolve": ["@chialab/node-resolve@0.17.1", "", {}, "sha512-YWaK0MKKeB0FILI6j7qiAlGoSC9MqJZDFXzlAgfOaMCbn8Feqh6njxv7mI3oVkdi7QwV6zPRaTN6hKig/NriMA=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.14.54", "", { "os": "linux", "cpu": "none" }, "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw=="],
"@parcel/source-map": ["@parcel/source-map@2.1.1", "", { "dependencies": { "detect-libc": "^1.0.3" } }, "sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew=="],
"@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="],
"@types/react": ["@types/react@17.0.90", "", { "dependencies": { "@types/prop-types": "*", "@types/scheduler": "^0.16", "csstype": "^3.2.2" } }, "sha512-P9beVR/x06U9rCJzSxtENnOr4BrbJ6VrsrDTc+73TtHv9XHhryXKbjGRB+6oooB2r0G/pQkD/S4dHo/7jUfwFw=="],
"@types/react-dom": ["@types/react-dom@17.0.26", "", { "peerDependencies": { "@types/react": "^17.0.0" } }, "sha512-Z+2VcYXJwOqQ79HreLU/1fyQ88eXSSFh6I3JdrEHQIfYSI0kCQpTGvOrbE6jFGGYXKsHuwY9tBa/w5Uo6KzrEg=="],
"@types/scheduler": ["@types/scheduler@0.16.8", "", {}, "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A=="],
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
"detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="],
"esbuild": ["esbuild@0.14.54", "", { "optionalDependencies": { "@esbuild/linux-loong64": "0.14.54", "esbuild-android-64": "0.14.54", "esbuild-android-arm64": "0.14.54", "esbuild-darwin-64": "0.14.54", "esbuild-darwin-arm64": "0.14.54", "esbuild-freebsd-64": "0.14.54", "esbuild-freebsd-arm64": "0.14.54", "esbuild-linux-32": "0.14.54", "esbuild-linux-64": "0.14.54", "esbuild-linux-arm": "0.14.54", "esbuild-linux-arm64": "0.14.54", "esbuild-linux-mips64le": "0.14.54", "esbuild-linux-ppc64le": "0.14.54", "esbuild-linux-riscv64": "0.14.54", "esbuild-linux-s390x": "0.14.54", "esbuild-netbsd-64": "0.14.54", "esbuild-openbsd-64": "0.14.54", "esbuild-sunos-64": "0.14.54", "esbuild-windows-32": "0.14.54", "esbuild-windows-64": "0.14.54", "esbuild-windows-arm64": "0.14.54" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA=="],
"esbuild-android-64": ["esbuild-android-64@0.14.54", "", { "os": "android", "cpu": "x64" }, "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ=="],
"esbuild-android-arm64": ["esbuild-android-arm64@0.14.54", "", { "os": "android", "cpu": "arm64" }, "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg=="],
"esbuild-darwin-64": ["esbuild-darwin-64@0.14.54", "", { "os": "darwin", "cpu": "x64" }, "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug=="],
"esbuild-darwin-arm64": ["esbuild-darwin-arm64@0.14.54", "", { "os": "darwin", "cpu": "arm64" }, "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw=="],
"esbuild-freebsd-64": ["esbuild-freebsd-64@0.14.54", "", { "os": "freebsd", "cpu": "x64" }, "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg=="],
"esbuild-freebsd-arm64": ["esbuild-freebsd-arm64@0.14.54", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q=="],
"esbuild-linux-32": ["esbuild-linux-32@0.14.54", "", { "os": "linux", "cpu": "ia32" }, "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw=="],
"esbuild-linux-64": ["esbuild-linux-64@0.14.54", "", { "os": "linux", "cpu": "x64" }, "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg=="],
"esbuild-linux-arm": ["esbuild-linux-arm@0.14.54", "", { "os": "linux", "cpu": "arm" }, "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw=="],
"esbuild-linux-arm64": ["esbuild-linux-arm64@0.14.54", "", { "os": "linux", "cpu": "arm64" }, "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig=="],
"esbuild-linux-mips64le": ["esbuild-linux-mips64le@0.14.54", "", { "os": "linux", "cpu": "none" }, "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw=="],
"esbuild-linux-ppc64le": ["esbuild-linux-ppc64le@0.14.54", "", { "os": "linux", "cpu": "ppc64" }, "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ=="],
"esbuild-linux-riscv64": ["esbuild-linux-riscv64@0.14.54", "", { "os": "linux", "cpu": "none" }, "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg=="],
"esbuild-linux-s390x": ["esbuild-linux-s390x@0.14.54", "", { "os": "linux", "cpu": "s390x" }, "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA=="],
"esbuild-netbsd-64": ["esbuild-netbsd-64@0.14.54", "", { "os": "none", "cpu": "x64" }, "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w=="],
"esbuild-openbsd-64": ["esbuild-openbsd-64@0.14.54", "", { "os": "openbsd", "cpu": "x64" }, "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw=="],
"esbuild-plugin-compress": ["esbuild-plugin-compress@0.4.0", "", { "dependencies": { "chalk": "^4.1.2", "fs-extra": "^10.0.0" }, "peerDependencies": { "esbuild": "^0.14.0" } }, "sha512-W9L9f9ClfJe32y9850vkSpd2ib7klFszOyVoMa5imI3CSdW/UbxPBhb1ZaVKPnNCZqZisw8KtTiJTQdVawPB9w=="],
"esbuild-sunos-64": ["esbuild-sunos-64@0.14.54", "", { "os": "sunos", "cpu": "x64" }, "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw=="],
"esbuild-windows-32": ["esbuild-windows-32@0.14.54", "", { "os": "win32", "cpu": "ia32" }, "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w=="],
"esbuild-windows-64": ["esbuild-windows-64@0.14.54", "", { "os": "win32", "cpu": "x64" }, "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ=="],
"esbuild-windows-arm64": ["esbuild-windows-arm64@0.14.54", "", { "os": "win32", "cpu": "arm64" }, "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg=="],
"fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
"mobx": ["mobx@6.15.0", "", {}, "sha512-UczzB+0nnwGotYSgllfARAqWCJ5e/skuV2K/l+Zyck/H6pJIhLXuBnz+6vn2i211o7DtbE78HQtsYEKICHGI+g=="],
"mobx-react": ["mobx-react@7.6.0", "", { "dependencies": { "mobx-react-lite": "^3.4.0" }, "peerDependencies": { "mobx": "^6.1.0", "react": "^16.8.0 || ^17 || ^18" } }, "sha512-+HQUNuh7AoQ9ZnU6c4rvbiVVl+wEkb9WqYsVDzGLng+Dqj1XntHu79PvEWKtSMoMj67vFp/ZPXcElosuJO8ckA=="],
"mobx-react-lite": ["mobx-react-lite@3.4.3", "", { "peerDependencies": { "mobx": "^6.1.0", "react": "^16.8.0 || ^17 || ^18" } }, "sha512-NkJREyFTSUXR772Qaai51BnE1voWx56LOL80xG7qkZr6vo8vEaLF3sz1JNUVh+rxmUzxYaqOhfuxTfqUh0FXUg=="],
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
"react": ["react@17.0.2", "", { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA=="],
"react-dom": ["react-dom@17.0.2", "", { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "scheduler": "^0.20.2" }, "peerDependencies": { "react": "17.0.2" } }, "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA=="],
"scheduler": ["scheduler@0.20.2", "", { "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ=="],
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"typescript": ["typescript@4.9.5", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g=="],
"universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
}
}

1174
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/package-lock.json

File diff suppressed because it is too large

4
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/package.json

@ -1,9 +1,5 @@
{
"name": "previewer",
"scripts": {
"predist": "tsc -noEmit",
"dist": "node build.js"
},
"devDependencies": {
"@chialab/esbuild-plugin-html": "^0.17.0",
"esbuild": "^0.14.54",

2
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@ -309,7 +309,7 @@ namespace Avalonia.DesignerSupport.Remote
public override Task<SaveFilePickerResult> SaveFilePickerWithResultAsync(FilePickerSaveOptions options)
{
return Task.FromResult<SaveFilePickerResult>(new SaveFilePickerResult(null));
return Task.FromResult(new SaveFilePickerResult());
}
public override bool CanPickFolder => false;

2
src/Avalonia.Dialogs/ManagedStorageProvider.cs

@ -56,7 +56,7 @@ internal class ManagedStorageProvider : BclStorageProvider
options.FileTypeChoices[index] :
null;
return new SaveFilePickerResult(file) { SelectedFileType = filterType };
return new SaveFilePickerResult { File = file, SelectedFileType = filterType };
}
public override async Task<IReadOnlyList<IStorageFolder>> OpenFolderPickerAsync(FolderPickerOpenOptions options)

2
src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj

@ -14,7 +14,7 @@
<ItemGroup>
<PackageReference Include="Tmds.DBus.Protocol" Version="0.21.2" />
<PackageReference Include="Tmds.DBus.SourceGenerator" Version="0.0.21" PrivateAssets="all" />
<PackageReference Include="Tmds.DBus.SourceGenerator" Version="0.0.22" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>

11
src/Avalonia.FreeDesktop/DBusIme/X11DBusImeHelper.cs

@ -31,6 +31,17 @@ namespace Avalonia.FreeDesktop.DBusIme
return factory;
}
var modifiers = Environment.GetEnvironmentVariable("XMODIFIERS");
if (modifiers is not null && modifiers.Contains("@im="))
{
int imNameStart = modifiers.IndexOf("@im=") + "@im=".Length;
int imNameEnd = modifiers.IndexOf("@", imNameStart);
string imName = imNameEnd == -1 ? modifiers.Substring(imNameStart) : modifiers.Substring(imNameStart, imNameEnd - imNameStart);
if (KnownMethods.TryGetValue(imName, out var factory))
return factory;
}
return null;
}

2
src/Avalonia.FreeDesktop/DBusSystemDialog.cs

@ -102,7 +102,7 @@ namespace Avalonia.FreeDesktop
public override async Task<SaveFilePickerResult> SaveFilePickerWithResultAsync(FilePickerSaveOptions options)
{
var (file, selectedType) = await SaveFilePickerCoreAsync(options).ConfigureAwait(false);
return new SaveFilePickerResult(file) { SelectedFileType = selectedType };
return new SaveFilePickerResult { File = file, SelectedFileType = selectedType };
}
private async Task<(IStorageFile? file, FilePickerFileType? selectedType)> SaveFilePickerCoreAsync(

2
src/Avalonia.Native/GpuHandleWrapFeature.cs

@ -1,3 +1,5 @@
#nullable enable
using System;
using Avalonia.Native.Interop;
using Avalonia.Platform;

2
src/Avalonia.Native/StorageProviderImpl.cs

@ -30,7 +30,7 @@ internal sealed class StorageProviderImpl(TopLevelImpl topLevel, StorageProvider
public async Task<SaveFilePickerResult> SaveFilePickerWithResultAsync(FilePickerSaveOptions options)
{
var (file, selectedType) = await native.SaveFileDialog(topLevel, options).ConfigureAwait(false);
return new SaveFilePickerResult(file) { SelectedFileType = selectedType };
return new SaveFilePickerResult { File = file, SelectedFileType = selectedType };
}
public Task<IReadOnlyList<IStorageFolder>> OpenFolderPickerAsync(FolderPickerOpenOptions options)

2
src/Avalonia.Native/avn.idl

@ -1317,7 +1317,7 @@ interface IAvnAutomationPeer : IUnknown
bool IsValueProvider();
IAvnString* ValueProvider_GetValue();
void ValueProvider_SetValue(char* value);
void ValueProvider_SetValue([const] char* value);
IAvnString* GetHelpText();

2
src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs

@ -86,7 +86,7 @@ namespace Avalonia.X11.NativeDialogs
? new BclStorageFile(new FileInfo(path))
: null;
return new SaveFilePickerResult(file) { SelectedFileType = selectedFilter };
return new SaveFilePickerResult { File = file, SelectedFileType = selectedFilter };
});
}

35
src/Avalonia.X11/X11Platform.cs

@ -166,27 +166,26 @@ namespace Avalonia.X11
private static bool ShouldUseXim()
{
// Priority: AVALONIA_IM_MODULE > GTK_IM_MODULE >= QT_IM_MODULE
string? imeOverride = Environment.GetEnvironmentVariable("AVALONIA_IM_MODULE");
if (string.IsNullOrEmpty(imeOverride))
imeOverride = Environment.GetEnvironmentVariable("GTK_IM_MODULE");
if (string.IsNullOrEmpty(imeOverride))
imeOverride = Environment.GetEnvironmentVariable("QT_IM_MODULE");
// Check if we are forbidden from using IME
if (Environment.GetEnvironmentVariable("AVALONIA_IM_MODULE") == "none"
|| Environment.GetEnvironmentVariable("GTK_IM_MODULE") == "none"
|| Environment.GetEnvironmentVariable("QT_IM_MODULE") == "none")
return true;
if (imeOverride == "none")
return false;
// Check if XIM is configured
var modifiers = Environment.GetEnvironmentVariable("XMODIFIERS");
if (modifiers == null)
return false;
if (modifiers.Contains("@im=none") || modifiers.Contains("@im=null"))
return false;
if (!modifiers.Contains("@im="))
return false;
// Check if we are configured to use it
if (Environment.GetEnvironmentVariable("GTK_IM_MODULE") == "xim"
|| Environment.GetEnvironmentVariable("QT_IM_MODULE") == "xim"
|| Environment.GetEnvironmentVariable("AVALONIA_IM_MODULE") == "xim")
return true;
if (modifiers is not null && modifiers.Contains("@im="))
{
// If XIM is explicitly requested, or no IME override is configured
if (imeOverride == "xim" || string.IsNullOrEmpty(imeOverride))
return true;
}
return false;
}

4
src/Avalonia.X11/X11Window.cs

@ -44,6 +44,7 @@ namespace Avalonia.X11
private bool _triggeredExpose;
private IInputRoot? _inputRoot;
private readonly MouseDevice _mouse;
private readonly PenDevice _pen;
private readonly TouchDevice _touch;
private readonly IKeyboardDevice _keyboard;
private readonly ITopLevelNativeMenuExporter? _nativeMenuExporter;
@ -97,6 +98,7 @@ namespace Avalonia.X11
_overrideRedirect = _popup || overrideRedirect;
_x11 = platform.Info;
_mouse = Avalonia.Input.MouseDevice.Primary;
_pen = new PenDevice();
_touch = new TouchDevice();
_keyboard = platform.KeyboardDevice;
@ -1072,6 +1074,7 @@ namespace Avalonia.X11
_platform.XI2?.OnWindowDestroyed(_handle);
var handle = _handle;
_handle = IntPtr.Zero;
_pen.Dispose();
_touch.Dispose();
if (!fromDestroyNotification)
XDestroyWindow(_x11.Display, handle);
@ -1238,6 +1241,7 @@ namespace Avalonia.X11
}
public IMouseDevice MouseDevice => _mouse;
public IPenDevice PenDevice => _pen;
public TouchDevice TouchDevice => _touch;
public IPopupImpl? CreatePopup()

302
src/Avalonia.X11/XI2Manager.cs

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Avalonia.Input;
using Avalonia.Input.Raw;
using static Avalonia.X11.XLib;
@ -16,7 +17,6 @@ namespace Avalonia.X11
XiEventType.XI_ButtonRelease,
XiEventType.XI_Leave,
XiEventType.XI_Enter,
};
private static readonly XiEventType[] MultiTouchEventTypes = new XiEventType[]
@ -35,13 +35,14 @@ namespace Avalonia.X11
public int Id { get; }
public XIValuatorClassInfo[] Valuators { get; private set; } = [];
public XIScrollClassInfo[] Scrollers { get; private set; } = [];
public DeviceInfo(XIDeviceInfo info)
{
Id = info.Deviceid;
UpdateCore(info.Classes, info.NumClasses);
}
public virtual void Update(XIAnyClassInfo** classes, int num)
public virtual void Update(XIAnyClassInfo** classes, int num, int? slaveId)
{
UpdateCore(classes, num);
}
@ -66,7 +67,7 @@ namespace Avalonia.X11
{
foreach (var v in valuators)
{
if (Valuators.Length > v.Key)
if (Valuators.Length > v.Key)
Valuators[v.Key].Value = v.Value;
}
}
@ -74,13 +75,16 @@ namespace Avalonia.X11
private class PointerDeviceInfo : DeviceInfo
{
private string? _currentSlaveName = null;
private bool _currentSlaveIsEraser = false;
public PointerDeviceInfo(XIDeviceInfo info, X11Info x11Info) : base(info)
{
_x11 = x11Info;
UpdateKnownValuator();
}
private readonly X11Info _x11;
private void UpdateKnownValuator()
@ -91,6 +95,9 @@ namespace Avalonia.X11
var touchMinorAtom = XInternAtom(_x11.Display, "Abs MT Touch Minor", false);
var pressureAtom = XInternAtom(_x11.Display, "Abs MT Pressure", false);
var pressureAtomPen = XInternAtom(_x11.Display, "Abs Pressure", false);
var absTiltXAtom = XInternAtom(_x11.Display, "Abs Tilt X", false);
var absTiltYAtom = XInternAtom(_x11.Display, "Abs Tilt Y", false);
PressureXIValuatorClassInfo = null;
TouchMajorXIValuatorClassInfo = null;
@ -98,7 +105,8 @@ namespace Avalonia.X11
foreach (var xiValuatorClassInfo in Valuators)
{
if (xiValuatorClassInfo.Label == pressureAtom)
if (xiValuatorClassInfo.Label == pressureAtom ||
xiValuatorClassInfo.Label == pressureAtomPen)
{
PressureXIValuatorClassInfo = xiValuatorClassInfo;
}
@ -110,15 +118,52 @@ namespace Avalonia.X11
{
TouchMinorXIValuatorClassInfo = xiValuatorClassInfo;
}
else if (xiValuatorClassInfo.Label == absTiltXAtom)
{
TiltXXIValuatorClassInfo = xiValuatorClassInfo;
}
else if (xiValuatorClassInfo.Label == absTiltYAtom)
{
TiltYXIValuatorClassInfo = xiValuatorClassInfo;
}
}
}
public override void Update(XIAnyClassInfo** classes, int num)
public override void Update(XIAnyClassInfo** classes, int num, int? slaveId)
{
base.Update(classes, num);
base.Update(classes, num, slaveId);
if (slaveId != null)
{
_currentSlaveName = null;
_currentSlaveIsEraser = false;
var devices = (XIDeviceInfo*)XIQueryDevice(_x11.Display,
(int)XiPredefinedDeviceId.XIAllDevices, out int deviceNum);
for (var c = 0; c < deviceNum; c++)
{
if (devices[c].Deviceid == slaveId)
{
_currentSlaveName = Marshal.PtrToStringAnsi(devices[c].Name);
_currentSlaveIsEraser =
_currentSlaveName?.IndexOf("eraser", StringComparison.OrdinalIgnoreCase) >= 0;
break;
}
}
XIFreeDeviceInfo(devices);
}
UpdateKnownValuator();
}
public bool HasPressureValuator()
{
return PressureXIValuatorClassInfo is not null;
}
public bool IsEraser => _currentSlaveIsEraser;
public string? Name => _currentSlaveName;
public bool HasScroll(ParsedDeviceEvent ev)
{
foreach (var val in ev.Valuators)
@ -127,7 +172,7 @@ namespace Avalonia.X11
return false;
}
public bool HasMotion(ParsedDeviceEvent ev)
{
foreach (var val in ev.Valuators)
@ -140,8 +185,10 @@ namespace Avalonia.X11
public XIValuatorClassInfo? PressureXIValuatorClassInfo { get; private set; }
public XIValuatorClassInfo? TouchMajorXIValuatorClassInfo { get; private set; }
public XIValuatorClassInfo? TouchMinorXIValuatorClassInfo { get; private set; }
public XIValuatorClassInfo? TiltXXIValuatorClassInfo { get; private set; }
public XIValuatorClassInfo? TiltYXIValuatorClassInfo { get; private set; }
}
private readonly PointerDeviceInfo _pointerDevice;
private readonly AvaloniaX11Platform _platform;
@ -157,7 +204,7 @@ namespace Avalonia.X11
{
var x11 = platform.Info;
var devices = (XIDeviceInfo*) XIQueryDevice(x11.Display,
var devices = (XIDeviceInfo*)XIQueryDevice(x11.Display,
(int)XiPredefinedDeviceId.XIAllMasterDevices, out int num);
PointerDeviceInfo? pointerDevice = null;
@ -202,8 +249,8 @@ namespace Avalonia.X11
events.AddRange(MultiTouchEventTypes);
XiSelectEvents(_x11.Display, xid,
new Dictionary<int, List<XiEventType>> {[_pointerDevice.Id] = events});
new Dictionary<int, List<XiEventType>> { [_pointerDevice.Id] = events });
// We are taking over mouse input handling from here
return XEventMask.PointerMotionMask
| XEventMask.ButtonMotionMask
@ -219,16 +266,15 @@ namespace Avalonia.X11
}
public void OnWindowDestroyed(IntPtr xid) => _clients.Remove(xid);
public void OnEvent(XIEvent* xev)
{
if (xev->evtype == XiEventType.XI_DeviceChanged)
{
var changed = (XIDeviceChangedEvent*)xev;
_pointerDevice.Update(changed->Classes, changed->NumClasses);
_pointerDevice.Update(changed->Classes, changed->NumClasses, changed->Reason == XiDeviceChangeReason.XISlaveSwitch ? changed->Sourceid : null);
}
if ((xev->evtype >= XiEventType.XI_ButtonPress && xev->evtype <= XiEventType.XI_Motion)
|| (xev->evtype >= XiEventType.XI_TouchBegin && xev->evtype <= XiEventType.XI_TouchEnd))
{
@ -258,9 +304,9 @@ namespace Avalonia.X11
{
foreach (var scroller in _pointerDevice.Scrollers)
{
_pointerDevice.Valuators[scroller.Number].Value = 0;
_pointerDevice.Valuators[scroller.Number].Value = 0;
}
client.ScheduleXI2Input(new RawPointerEventArgs(client.MouseDevice, (ulong)ev.time.ToInt64(),
client.InputRoot,
RawPointerEventType.LeaveWindow, new Point(ev.event_x, ev.event_y), buttons));
@ -270,8 +316,8 @@ namespace Avalonia.X11
private void OnDeviceEvent(IXI2Client client, ParsedDeviceEvent ev)
{
if (ev.Type == XiEventType.XI_TouchBegin
|| ev.Type == XiEventType.XI_TouchUpdate
if (ev.Type == XiEventType.XI_TouchBegin
|| ev.Type == XiEventType.XI_TouchUpdate
|| ev.Type == XiEventType.XI_TouchEnd)
{
var type = ev.Type == XiEventType.XI_TouchBegin ?
@ -280,22 +326,20 @@ namespace Avalonia.X11
RawPointerEventType.TouchUpdate :
RawPointerEventType.TouchEnd);
var rawPointerPoint = new RawPointerPoint()
{
Position = ev.Position
};
var rawPointerPoint = new RawPointerPoint() { Position = ev.Position };
if (_pointerDevice.PressureXIValuatorClassInfo is {} valuatorClassInfo)
if (_pointerDevice.PressureXIValuatorClassInfo is { } valuatorClassInfo)
{
if (ev.Valuators.TryGetValue(valuatorClassInfo.Number, out var pressureValue))
{
// In our API we use range from 0.0 to 1.0.
var pressure = (pressureValue - valuatorClassInfo.Min) / (valuatorClassInfo.Max - valuatorClassInfo.Min);
var pressure = (pressureValue - valuatorClassInfo.Min) /
(valuatorClassInfo.Max - valuatorClassInfo.Min);
rawPointerPoint.Pressure = (float)pressure;
}
}
if(_pointerDevice.TouchMajorXIValuatorClassInfo is {} touchMajorXIValuatorClassInfo)
if (_pointerDevice.TouchMajorXIValuatorClassInfo is { } touchMajorXIValuatorClassInfo)
{
double? touchMajor = null;
double? touchMinor = null;
@ -310,18 +354,20 @@ namespace Avalonia.X11
// As https://www.kernel.org/doc/html/latest/input/multi-touch-protocol.html says, using `screenBounds.Width` is not accurate enough.
touchMajor = (touchMajorValue - touchMajorXIValuatorClassInfo.Min) /
(touchMajorXIValuatorClassInfo.Max - touchMajorXIValuatorClassInfo.Min) * screenBounds.Width;
(touchMajorXIValuatorClassInfo.Max - touchMajorXIValuatorClassInfo.Min) *
screenBounds.Width;
}
}
if (touchMajor != null)
{
if(_pointerDevice.TouchMinorXIValuatorClassInfo is {} touchMinorXIValuatorClassInfo)
if (_pointerDevice.TouchMinorXIValuatorClassInfo is { } touchMinorXIValuatorClassInfo)
{
if (ev.Valuators.TryGetValue(touchMinorXIValuatorClassInfo.Number, out var touchMinorValue))
{
touchMinor = (touchMinorValue - touchMinorXIValuatorClassInfo.Min) /
(touchMinorXIValuatorClassInfo.Max - touchMinorXIValuatorClassInfo.Min) * screenBounds.Height;
(touchMinorXIValuatorClassInfo.Max - touchMinorXIValuatorClassInfo.Min) *
screenBounds.Height;
}
}
@ -351,10 +397,17 @@ namespace Avalonia.X11
if (!client.IsEnabled || (_multitouch && ev.Emulated))
return;
var eventModifiers = ev.Modifiers;
if (_pointerDevice.IsEraser)
eventModifiers |= RawInputModifiers.PenEraser;
if (ev.Type == XiEventType.XI_Motion)
{
Vector scrollDelta = default;
var rawPointerPoint = new RawPointerPoint() { Position = ev.Position };
IInputDevice device = _pointerDevice.HasPressureValuator() ? client.PenDevice : client.MouseDevice;
foreach (var v in ev.Valuators)
{
foreach (var scroller in _pointerDevice.Scrollers)
@ -374,15 +427,15 @@ namespace Avalonia.X11
}
}
SetPenSpecificValues(v, ref rawPointerPoint);
}
if (scrollDelta != default)
client.ScheduleXI2Input(new RawMouseWheelEventArgs(client.MouseDevice, ev.Timestamp,
client.InputRoot, ev.Position, scrollDelta, ev.Modifiers));
client.ScheduleXI2Input(new RawMouseWheelEventArgs(device, ev.Timestamp,
client.InputRoot, ev.Position, scrollDelta, eventModifiers));
if (_pointerDevice.HasMotion(ev))
client.ScheduleXI2Input(new RawPointerEventArgs(client.MouseDevice, ev.Timestamp, client.InputRoot,
RawPointerEventType.Move, ev.Position, ev.Modifiers));
client.ScheduleXI2Input(new RawPointerEventArgs(device, ev.Timestamp, client.InputRoot,
RawPointerEventType.Move, rawPointerPoint, eventModifiers));
}
if (ev.Type == XiEventType.XI_ButtonPress && ev.Button >= 4 && ev.Button <= 7 && !ev.Emulated)
@ -395,10 +448,10 @@ namespace Avalonia.X11
7 => new Vector(-1, 0),
_ => (Vector?)null
};
if (scrollDelta.HasValue)
client.ScheduleXI2Input(new RawMouseWheelEventArgs(client.MouseDevice, ev.Timestamp,
client.InputRoot, ev.Position, scrollDelta.Value, ev.Modifiers));
client.InputRoot, ev.Position, scrollDelta.Value, eventModifiers));
}
if (ev.Type == XiEventType.XI_ButtonPress || ev.Type == XiEventType.XI_ButtonRelease)
@ -413,87 +466,134 @@ namespace Avalonia.X11
9 => down ? RawPointerEventType.XButton2Down : RawPointerEventType.XButton2Up,
_ => (RawPointerEventType?)null
};
if (type.HasValue)
client.ScheduleXI2Input(new RawPointerEventArgs(client.MouseDevice, ev.Timestamp, client.InputRoot,
type.Value, ev.Position, ev.Modifiers));
{
IInputDevice device = _pointerDevice.HasPressureValuator() ? client.PenDevice : client.MouseDevice;
var pointerPoint = new RawPointerPoint() { Position = ev.Position };
SetPenSpecificValues(ev, ref pointerPoint);
client.ScheduleXI2Input(new RawPointerEventArgs(device, ev.Timestamp, client.InputRoot,
type.Value, pointerPoint, eventModifiers));
}
}
_pointerDevice.UpdateValuators(ev.Valuators);
}
}
private void SetPenSpecificValues(ParsedDeviceEvent ev, ref RawPointerPoint pointerPoint)
{
foreach (var evValuator in ev.Valuators)
{
SetPenSpecificValues(evValuator, ref pointerPoint);
}
}
internal unsafe class ParsedDeviceEvent
{
public XiEventType Type { get; }
public RawInputModifiers Modifiers { get; }
public ulong Timestamp { get; }
public Point Position { get; }
public Point RootPosition { get; }
public int Button { get; set; }
public int Detail { get; set; }
public bool Emulated { get; set; }
public Dictionary<int, double> Valuators { get; }
public static RawInputModifiers ParseButtonState(int len, byte* buttons)
private void SetPenSpecificValues(KeyValuePair<int, double> item, ref RawPointerPoint rawPointerPoint)
{
RawInputModifiers rv = default;
if (len > 0)
if (_pointerDevice.PressureXIValuatorClassInfo is { } valuatorClassInfo)
{
if (item.Key == valuatorClassInfo.Number)
{
var pressure = (item.Value - valuatorClassInfo.Min) /
(valuatorClassInfo.Max - valuatorClassInfo.Min);
rawPointerPoint.Pressure = (float)pressure;
}
}
if (_pointerDevice.TiltXXIValuatorClassInfo is { } tiltXValuatorClassInfo)
{
if (item.Key == tiltXValuatorClassInfo.Number)
{
rawPointerPoint.XTilt = (float)item.Value;
}
}
if (_pointerDevice.TiltYXIValuatorClassInfo is { } tiltYValuatorClassInfo)
{
if (XIMaskIsSet(buttons, 1))
rv |= RawInputModifiers.LeftMouseButton;
if (XIMaskIsSet(buttons, 2))
rv |= RawInputModifiers.MiddleMouseButton;
if (XIMaskIsSet(buttons, 3))
rv |= RawInputModifiers.RightMouseButton;
if (len > 1)
if (item.Key == tiltYValuatorClassInfo.Number)
{
if (XIMaskIsSet(buttons, 8))
rv |= RawInputModifiers.XButton1MouseButton;
if (XIMaskIsSet(buttons, 9))
rv |= RawInputModifiers.XButton2MouseButton;
rawPointerPoint.YTilt = (float)item.Value;
}
}
return rv;
}
public ParsedDeviceEvent(XIDeviceEvent* ev)
internal unsafe class ParsedDeviceEvent
{
Type = ev->evtype;
Timestamp = (ulong)ev->time.ToInt64();
var state = (XModifierMask)ev->mods.Effective;
if (state.HasAllFlags(XModifierMask.ShiftMask))
Modifiers |= RawInputModifiers.Shift;
if (state.HasAllFlags(XModifierMask.ControlMask))
Modifiers |= RawInputModifiers.Control;
if (state.HasAllFlags(XModifierMask.Mod1Mask))
Modifiers |= RawInputModifiers.Alt;
if (state.HasAllFlags(XModifierMask.Mod4Mask))
Modifiers |= RawInputModifiers.Meta;
Modifiers |= ParseButtonState(ev->buttons.MaskLen, ev->buttons.Mask);
Valuators = new Dictionary<int, double>();
Position = new Point(ev->event_x, ev->event_y);
RootPosition = new Point(ev->root_x, ev->root_y);
var values = ev->valuators.Values;
if(ev->valuators.Mask != null)
for (var c = 0; c < ev->valuators.MaskLen * 8; c++)
if (XIMaskIsSet(ev->valuators.Mask, c))
Valuators[c] = *values++;
if (Type == XiEventType.XI_ButtonPress || Type == XiEventType.XI_ButtonRelease)
Button = ev->detail;
Detail = ev->detail;
Emulated = ev->flags.HasAllFlags(XiDeviceEventFlags.XIPointerEmulated);
public XiEventType Type { get; }
public RawInputModifiers Modifiers { get; }
public ulong Timestamp { get; }
public Point Position { get; }
public Point RootPosition { get; }
public int Button { get; set; }
public int Detail { get; set; }
public bool Emulated { get; set; }
public Dictionary<int, double> Valuators { get; }
public static RawInputModifiers ParseButtonState(int len, byte* buttons)
{
RawInputModifiers rv = default;
if (len > 0)
{
if (XIMaskIsSet(buttons, 1))
rv |= RawInputModifiers.LeftMouseButton;
if (XIMaskIsSet(buttons, 2))
rv |= RawInputModifiers.MiddleMouseButton;
if (XIMaskIsSet(buttons, 3))
rv |= RawInputModifiers.RightMouseButton;
if (len > 1)
{
if (XIMaskIsSet(buttons, 8))
rv |= RawInputModifiers.XButton1MouseButton;
if (XIMaskIsSet(buttons, 9))
rv |= RawInputModifiers.XButton2MouseButton;
}
}
return rv;
}
public ParsedDeviceEvent(XIDeviceEvent* ev)
{
Type = ev->evtype;
Timestamp = (ulong)ev->time.ToInt64();
var state = (XModifierMask)ev->mods.Effective;
if (state.HasAllFlags(XModifierMask.ShiftMask))
Modifiers |= RawInputModifiers.Shift;
if (state.HasAllFlags(XModifierMask.ControlMask))
Modifiers |= RawInputModifiers.Control;
if (state.HasAllFlags(XModifierMask.Mod1Mask))
Modifiers |= RawInputModifiers.Alt;
if (state.HasAllFlags(XModifierMask.Mod4Mask))
Modifiers |= RawInputModifiers.Meta;
Modifiers |= ParseButtonState(ev->buttons.MaskLen, ev->buttons.Mask);
Valuators = new Dictionary<int, double>();
Position = new Point(ev->event_x, ev->event_y);
RootPosition = new Point(ev->root_x, ev->root_y);
var values = ev->valuators.Values;
if (ev->valuators.Mask != null)
for (var c = 0; c < ev->valuators.MaskLen * 8; c++)
if (XIMaskIsSet(ev->valuators.Mask, c))
Valuators[c] = *values++;
if (Type == XiEventType.XI_ButtonPress || Type == XiEventType.XI_ButtonRelease)
Button = ev->detail;
Detail = ev->detail;
Emulated = ev->flags.HasAllFlags(XiDeviceEventFlags.XIPointerEmulated);
}
}
}
internal interface IXI2Client
{
bool IsEnabled { get; }
IInputRoot InputRoot { get; }
void ScheduleXI2Input(RawInputEventArgs args);
IMouseDevice MouseDevice { get; }
TouchDevice TouchDevice { get; }
bool IsEnabled { get; }
IInputRoot InputRoot { get; }
void ScheduleXI2Input(RawInputEventArgs args);
IMouseDevice MouseDevice { get; }
IPenDevice PenDevice { get; }
TouchDevice TouchDevice { get; }
}
}

8
src/Avalonia.X11/XIStructs.cs

@ -205,7 +205,7 @@ namespace Avalonia.X11
public IntPtr Time;
public int Deviceid; /* id of the device that changed */
public int Sourceid; /* Source for the new classes. */
public int Reason; /* Reason for the change */
public XiDeviceChangeReason Reason; /* Reason for the change */
public int NumClasses;
public XIAnyClassInfo** Classes; /* same as in XIDeviceInfo */
}
@ -272,6 +272,12 @@ namespace Avalonia.X11
XIPointerEmulated = (1 << 16)
}
internal enum XiDeviceChangeReason : int
{
XISlaveSwitch = 1,
XIDeviceChange = 2
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct XIEvent
{

12
src/Browser/Avalonia.Browser/Avalonia.Browser.csproj

@ -3,6 +3,7 @@
<TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsCurrentBrowserTargetFramework)</TargetFrameworks>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<WebAppDir>$(MSBuildThisFileDirectory)webapp</WebAppDir>
</PropertyGroup>
<ItemGroup>
@ -41,13 +42,14 @@
</Content>
</ItemGroup>
<Target Name="NpmInstall" Inputs="webapp/package.json" Outputs="webapp/node_modules/.install-stamp">
<Exec Command="npm install" WorkingDirectory="webapp" />
<Target Name="BunInstall" Inputs="$(WebAppDir)/package.json" Outputs="$(WebAppDir)/node_modules/.install-stamp">
<!-- We use bun packages as .NET tool, to avoid preinstalled node.js dependency -->
<Exec Command="dnx Bun.Unofficial.Tool --yes -- install" WorkingDirectory="$(WebAppDir)" />
<!-- Write the stamp file, so incremental builds work -->
<Touch Files="webapp/node_modules/.install-stamp" AlwaysCreate="true" />
<Touch Files="$(WebAppDir)/node_modules/.install-stamp" AlwaysCreate="true" />
</Target>
<Target Name="NpmRunBuild" DependsOnTargets="NpmInstall" BeforeTargets="DispatchToInnerBuilds">
<Exec Command="npm run build" WorkingDirectory="webapp" />
<Target Name="BunRunBuild" DependsOnTargets="BunInstall" BeforeTargets="DispatchToInnerBuilds">
<Exec Command="dnx Bun.Unofficial.Tool build.js" WorkingDirectory="$(WebAppDir)" />
</Target>
<ItemGroup>

2
src/Browser/Avalonia.Browser/Storage/BrowserStorageProvider.cs

@ -93,7 +93,7 @@ internal class BrowserStorageProvider : IStorageProvider
public async Task<SaveFilePickerResult> SaveFilePickerWithResultAsync(FilePickerSaveOptions options)
{
var file = await SaveFilePickerAsync(options).ConfigureAwait(false);
return new SaveFilePickerResult(file);
return new SaveFilePickerResult { File = file };
}
public async Task<IReadOnlyList<IStorageFolder>> OpenFolderPickerAsync(FolderPickerOpenOptions options)

545
src/Browser/Avalonia.Browser/webapp/bun.lock

@ -0,0 +1,545 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "avalonia.browser",
"dependencies": {
"native-file-system-adapter": "github:jimmywarting/native-file-system-adapter",
},
"devDependencies": {
"@types/emscripten": "^1.39.6",
"@types/offscreencanvas": "2019.7.1",
"@types/webscreens-window-placement": "^0.1.3",
"@typescript-eslint/eslint-plugin": "^5.38.1",
"esbuild": "^0.15.7",
"eslint": "^8.24.0",
"eslint-config-standard-with-typescript": "^23.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.3.0",
"eslint-plugin-promise": "^6.0.1",
"npm-run-all": "^4.1.5",
"typescript": "^5.8.3",
},
},
},
"packages": {
"@esbuild/android-arm": ["@esbuild/android-arm@0.15.9", "", { "os": "android", "cpu": "arm" }, "sha512-VZPy/ETF3fBG5PiinIkA0W/tlsvlEgJccyN2DzWZEl0DlVKRbu91PvY2D6Lxgluj4w9QtYHjOWjAT44C+oQ+EQ=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.15.9", "", { "os": "linux", "cpu": "none" }, "sha512-O+NfmkfRrb3uSsTa4jE3WApidSe3N5++fyOVGP1SmMZi4A3BZELkhUUvj5hwmMuNdlpzAZ8iAPz2vmcR7DCFQA=="],
"@eslint/eslintrc": ["@eslint/eslintrc@1.3.2", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.4.0", "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ=="],
"@humanwhocodes/config-array": ["@humanwhocodes/config-array@0.10.5", "", { "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", "minimatch": "^3.0.4" } }, "sha512-XVVDtp+dVvRxMoxSiSfasYaG02VEe1qH5cKgMQJWhol6HwzbcqoCMJi8dAGoYAO57jhUyhI6cWuRiTcRaDaYug=="],
"@humanwhocodes/gitignore-to-minimatch": ["@humanwhocodes/gitignore-to-minimatch@1.0.2", "", {}, "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA=="],
"@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
"@humanwhocodes/object-schema": ["@humanwhocodes/object-schema@1.2.1", "", {}, "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
"@types/emscripten": ["@types/emscripten@1.39.6", "", {}, "sha512-H90aoynNhhkQP6DRweEjJp5vfUVdIj7tdPLsu7pq89vODD/lcugKfZOsfgwpvM6XUewEp2N5dCg1Uf3Qe55Dcg=="],
"@types/json-schema": ["@types/json-schema@7.0.11", "", {}, "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ=="],
"@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="],
"@types/offscreencanvas": ["@types/offscreencanvas@2019.7.1", "", {}, "sha512-+HSrJgjBW77ALieQdMJvXhRZUIRN1597L+BKvsyeiIlHHERnqjcuOLyodK3auJ3Y3zRezNKtKAhuQWYJfEgFHQ=="],
"@types/webscreens-window-placement": ["@types/webscreens-window-placement@0.1.3", "", {}, "sha512-OunHLGJkmAuNlvd7PrRbQy/VleLyxxP3NKwuUo9OS412vO/tzKGwW2K3FqvnM1yebTkCM0W+gszr08m9oDz0lg=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@5.38.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "5.38.1", "@typescript-eslint/type-utils": "5.38.1", "@typescript-eslint/utils": "5.38.1", "debug": "^4.3.4", "ignore": "^5.2.0", "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" }, "peerDependencies": { "@typescript-eslint/parser": "^5.0.0", "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-ky7EFzPhqz3XlhS7vPOoMDaQnQMn+9o5ICR9CPr/6bw8HrFkzhMSxuA3gRfiJVvs7geYrSeawGJjZoZQKCOglQ=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@5.38.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "5.38.1", "@typescript-eslint/types": "5.38.1", "@typescript-eslint/typescript-estree": "5.38.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-LDqxZBVFFQnQRz9rUZJhLmox+Ep5kdUmLatLQnCRR6523YV+XhRjfYzStQ4MheFA8kMAfUlclHSbu+RKdRwQKw=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@5.38.1", "", { "dependencies": { "@typescript-eslint/types": "5.38.1", "@typescript-eslint/visitor-keys": "5.38.1" } }, "sha512-BfRDq5RidVU3RbqApKmS7RFMtkyWMM50qWnDAkKgQiezRtLKsoyRKIvz1Ok5ilRWeD9IuHvaidaLxvGx/2eqTQ=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@5.38.1", "", { "dependencies": { "@typescript-eslint/typescript-estree": "5.38.1", "@typescript-eslint/utils": "5.38.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, "peerDependencies": { "eslint": "*" } }, "sha512-UU3j43TM66gYtzo15ivK2ZFoDFKKP0k03MItzLdq0zV92CeGCXRfXlfQX5ILdd4/DSpHkSjIgLLLh1NtkOJOAw=="],
"@typescript-eslint/types": ["@typescript-eslint/types@5.38.1", "", {}, "sha512-QTW1iHq1Tffp9lNfbfPm4WJabbvpyaehQ0SrvVK2yfV79SytD9XDVxqiPvdrv2LK7DGSFo91TB2FgWanbJAZXg=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@5.38.1", "", { "dependencies": { "@typescript-eslint/types": "5.38.1", "@typescript-eslint/visitor-keys": "5.38.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", "semver": "^7.3.7", "tsutils": "^3.21.0" } }, "sha512-99b5e/Enoe8fKMLdSuwrfH/C0EIbpUWmeEKHmQlGZb8msY33qn1KlkFww0z26o5Omx7EVjzVDCWEfrfCDHfE7g=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@5.38.1", "", { "dependencies": { "@types/json-schema": "^7.0.9", "@typescript-eslint/scope-manager": "5.38.1", "@typescript-eslint/types": "5.38.1", "@typescript-eslint/typescript-estree": "5.38.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-oIuUiVxPBsndrN81oP8tXnFa/+EcZ03qLqPDfSZ5xIJVm7A9V0rlkQwwBOAGtrdN70ZKDlKv+l1BeT4eSFxwXA=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@5.38.1", "", { "dependencies": { "@typescript-eslint/types": "5.38.1", "eslint-visitor-keys": "^3.3.0" } }, "sha512-bSHr1rRxXt54+j2n4k54p4fj8AHJ49VDWtjpImOpzQj4qjAiOpPni+V1Tyajh19Api1i844F757cur8wH3YvOA=="],
"acorn": ["acorn@8.8.0", "", { "bin": "bin/acorn" }, "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w=="],
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
"array-includes": ["array-includes@3.1.5", "", { "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", "es-abstract": "^1.19.5", "get-intrinsic": "^1.1.1", "is-string": "^1.0.7" } }, "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ=="],
"array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="],
"array.prototype.flat": ["array.prototype.flat@1.3.0", "", { "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", "es-abstract": "^1.19.2", "es-shim-unscopables": "^1.0.0" } }, "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
"builtins": ["builtins@5.0.1", "", { "dependencies": { "semver": "^7.0.0" } }, "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ=="],
"call-bind": ["call-bind@1.0.2", "", { "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" } }, "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA=="],
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
"color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"cross-spawn": ["cross-spawn@7.0.3", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w=="],
"debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="],
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
"define-properties": ["define-properties@1.1.4", "", { "dependencies": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA=="],
"dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="],
"doctrine": ["doctrine@3.0.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w=="],
"error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="],
"es-abstract": ["es-abstract@1.20.3", "", { "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", "is-callable": "^1.2.6", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", "is-weakref": "^1.0.2", "object-inspect": "^1.12.2", "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", "safe-regex-test": "^1.0.0", "string.prototype.trimend": "^1.0.5", "string.prototype.trimstart": "^1.0.5", "unbox-primitive": "^1.0.2" } }, "sha512-AyrnaKVpMzljIdwjzrj+LxGmj8ik2LckwXacHqrJJ/jxz6dDDBcZ7I7nlHM0FvEW8MfbWJwOd+yT2XzYW49Frw=="],
"es-shim-unscopables": ["es-shim-unscopables@1.0.0", "", { "dependencies": { "has": "^1.0.3" } }, "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w=="],
"es-to-primitive": ["es-to-primitive@1.2.1", "", { "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", "is-symbol": "^1.0.2" } }, "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA=="],
"esbuild": ["esbuild@0.15.9", "", { "optionalDependencies": { "@esbuild/android-arm": "0.15.9", "@esbuild/linux-loong64": "0.15.9", "esbuild-android-64": "0.15.9", "esbuild-android-arm64": "0.15.9", "esbuild-darwin-64": "0.15.9", "esbuild-darwin-arm64": "0.15.9", "esbuild-freebsd-64": "0.15.9", "esbuild-freebsd-arm64": "0.15.9", "esbuild-linux-32": "0.15.9", "esbuild-linux-64": "0.15.9", "esbuild-linux-arm": "0.15.9", "esbuild-linux-arm64": "0.15.9", "esbuild-linux-mips64le": "0.15.9", "esbuild-linux-ppc64le": "0.15.9", "esbuild-linux-riscv64": "0.15.9", "esbuild-linux-s390x": "0.15.9", "esbuild-netbsd-64": "0.15.9", "esbuild-openbsd-64": "0.15.9", "esbuild-sunos-64": "0.15.9", "esbuild-windows-32": "0.15.9", "esbuild-windows-64": "0.15.9", "esbuild-windows-arm64": "0.15.9" }, "bin": "bin/esbuild" }, "sha512-OnYr1rkMVxtmMHIAKZLMcEUlJmqcbxBz9QoBU8G9v455na0fuzlT/GLu6l+SRghrk0Mm2fSSciMmzV43Q8e0Gg=="],
"esbuild-android-64": ["esbuild-android-64@0.15.9", "", { "os": "android", "cpu": "x64" }, "sha512-HQCX7FJn9T4kxZQkhPjNZC7tBWZqJvhlLHPU2SFzrQB/7nDXjmTIFpFTjt7Bd1uFpeXmuwf5h5fZm+x/hLnhbw=="],
"esbuild-android-arm64": ["esbuild-android-arm64@0.15.9", "", { "os": "android", "cpu": "arm64" }, "sha512-E6zbLfqbFVCNEKircSHnPiSTsm3fCRxeIMPfrkS33tFjIAoXtwegQfVZqMGR0FlsvVxp2NEDOUz+WW48COCjSg=="],
"esbuild-darwin-64": ["esbuild-darwin-64@0.15.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-gI7dClcDN/HHVacZhTmGjl0/TWZcGuKJ0I7/xDGJwRQQn7aafZGtvagOFNmuOq+OBFPhlPv1T6JElOXb0unkSQ=="],
"esbuild-darwin-arm64": ["esbuild-darwin-arm64@0.15.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VZIMlcRN29yg/sv7DsDwN+OeufCcoTNaTl3Vnav7dL/nvsApD7uvhVRbgyMzv0zU/PP0xRhhIpTyc7lxEzHGSw=="],
"esbuild-freebsd-64": ["esbuild-freebsd-64@0.15.9", "", { "os": "freebsd", "cpu": "x64" }, "sha512-uM4z5bTvuAXqPxrI204txhlsPIolQPWRMLenvGuCPZTnnGlCMF2QLs0Plcm26gcskhxewYo9LkkmYSS5Czrb5A=="],
"esbuild-freebsd-arm64": ["esbuild-freebsd-arm64@0.15.9", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-HHDjT3O5gWzicGdgJ5yokZVN9K9KG05SnERwl9nBYZaCjcCgj/sX8Ps1jvoFSfNCO04JSsHSOWo4qvxFuj8FoA=="],
"esbuild-linux-32": ["esbuild-linux-32@0.15.9", "", { "os": "linux", "cpu": "ia32" }, "sha512-AQIdE8FugGt1DkcekKi5ycI46QZpGJ/wqcMr7w6YUmOmp2ohQ8eO4sKUsOxNOvYL7hGEVwkndSyszR6HpVHLFg=="],
"esbuild-linux-64": ["esbuild-linux-64@0.15.9", "", { "os": "linux", "cpu": "x64" }, "sha512-4RXjae7g6Qs7StZyiYyXTZXBlfODhb1aBVAjd+ANuPmMhWthQilWo7rFHwJwL7DQu1Fjej2sODAVwLbcIVsAYQ=="],
"esbuild-linux-arm": ["esbuild-linux-arm@0.15.9", "", { "os": "linux", "cpu": "arm" }, "sha512-3Zf2GVGUOI7XwChH3qrnTOSqfV1V4CAc/7zLVm4lO6JT6wbJrTgEYCCiNSzziSju+J9Jhf9YGWk/26quWPC6yQ=="],
"esbuild-linux-arm64": ["esbuild-linux-arm64@0.15.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-a+bTtxJmYmk9d+s2W4/R1SYKDDAldOKmWjWP0BnrWtDbvUBNOm++du0ysPju4mZVoEFgS1yLNW+VXnG/4FNwdQ=="],
"esbuild-linux-mips64le": ["esbuild-linux-mips64le@0.15.9", "", { "os": "linux", "cpu": "none" }, "sha512-Zn9HSylDp89y+TRREMDoGrc3Z4Hs5u56ozZLQCiZAUx2+HdbbXbWdjmw3FdTJ/i7t5Cew6/Q+6kfO3KCcFGlyw=="],
"esbuild-linux-ppc64le": ["esbuild-linux-ppc64le@0.15.9", "", { "os": "linux", "cpu": "ppc64" }, "sha512-OEiOxNAMH9ENFYqRsWUj3CWyN3V8P3ZXyfNAtX5rlCEC/ERXrCEFCJji/1F6POzsXAzxvUJrTSTCy7G6BhA6Fw=="],
"esbuild-linux-riscv64": ["esbuild-linux-riscv64@0.15.9", "", { "os": "linux", "cpu": "none" }, "sha512-ukm4KsC3QRausEFjzTsOZ/qqazw0YvJsKmfoZZm9QW27OHjk2XKSQGGvx8gIEswft/Sadp03/VZvAaqv5AIwNA=="],
"esbuild-linux-s390x": ["esbuild-linux-s390x@0.15.9", "", { "os": "linux", "cpu": "s390x" }, "sha512-uDOQEH55wQ6ahcIKzQr3VyjGc6Po/xblLGLoUk3fVL1qjlZAibtQr6XRfy5wPJLu/M2o0vQKLq4lyJ2r1tWKcw=="],
"esbuild-netbsd-64": ["esbuild-netbsd-64@0.15.9", "", { "os": "none", "cpu": "x64" }, "sha512-yWgxaYTQz+TqX80wXRq6xAtb7GSBAp6gqLKfOdANg9qEmAI1Bxn04IrQr0Mzm4AhxvGKoHzjHjMgXbCCSSDxcw=="],
"esbuild-openbsd-64": ["esbuild-openbsd-64@0.15.9", "", { "os": "openbsd", "cpu": "x64" }, "sha512-JmS18acQl4iSAjrEha1MfEmUMN4FcnnrtTaJ7Qg0tDCOcgpPPQRLGsZqhes0vmx8VA6IqRyScqXvaL7+Q0Uf3A=="],
"esbuild-sunos-64": ["esbuild-sunos-64@0.15.9", "", { "os": "sunos", "cpu": "x64" }, "sha512-UKynGSWpzkPmXW3D2UMOD9BZPIuRaSqphxSCwScfEE05Be3KAmvjsBhht1fLzKpiFVJb0BYMd4jEbWMyJ/z1hQ=="],
"esbuild-windows-32": ["esbuild-windows-32@0.15.9", "", { "os": "win32", "cpu": "ia32" }, "sha512-aqXvu4/W9XyTVqO/hw3rNxKE1TcZiEYHPsXM9LwYmKSX9/hjvfIJzXwQBlPcJ/QOxedfoMVH0YnhhQ9Ffb0RGA=="],
"esbuild-windows-64": ["esbuild-windows-64@0.15.9", "", { "os": "win32", "cpu": "x64" }, "sha512-zm7h91WUmlS4idMtjvCrEeNhlH7+TNOmqw5dJPJZrgFaxoFyqYG6CKDpdFCQXdyKpD5yvzaQBOMVTCBVKGZDEg=="],
"esbuild-windows-arm64": ["esbuild-windows-arm64@0.15.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-yQEVIv27oauAtvtuhJVfSNMztJJX47ismRS6Sv2QMVV9RM+6xjbMWuuwM2nxr5A2/gj/mu2z9YlQxiwoFRCfZA=="],
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"eslint": ["eslint@8.24.0", "", { "dependencies": { "@eslint/eslintrc": "^1.3.2", "@humanwhocodes/config-array": "^0.10.5", "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", "@humanwhocodes/module-importer": "^1.0.1", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", "espree": "^9.4.0", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.1", "globals": "^13.15.0", "globby": "^11.1.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": "bin/eslint.js" }, "sha512-dWFaPhGhTAiPcCgm3f6LI2MBWbogMnTJzFBbhXVRQDJPkr9pGZvVjlVfXd+vyDcWPA2Ic9L2AXPIQM0+vk/cSQ=="],
"eslint-config-standard": ["eslint-config-standard@17.0.0", "", { "peerDependencies": { "eslint": "^8.0.1", "eslint-plugin-import": "^2.25.2", "eslint-plugin-n": "^15.0.0", "eslint-plugin-promise": "^6.0.0" } }, "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg=="],
"eslint-config-standard-with-typescript": ["eslint-config-standard-with-typescript@23.0.0", "", { "dependencies": { "@typescript-eslint/parser": "^5.0.0", "eslint-config-standard": "17.0.0" }, "peerDependencies": { "@typescript-eslint/eslint-plugin": "^5.0.0", "eslint": "^8.0.1", "eslint-plugin-import": "^2.25.2", "eslint-plugin-n": "^15.0.0", "eslint-plugin-promise": "^6.0.0", "typescript": "*" } }, "sha512-iaaWifImn37Z1OXbNW1es7KI+S7D408F9ys0bpaQf2temeBWlvb0Nc5qHkOgYaRb5QxTZT32GGeN1gtswASOXA=="],
"eslint-import-resolver-node": ["eslint-import-resolver-node@0.3.6", "", { "dependencies": { "debug": "^3.2.7", "resolve": "^1.20.0" } }, "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw=="],
"eslint-module-utils": ["eslint-module-utils@2.7.4", "", { "dependencies": { "debug": "^3.2.7" } }, "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA=="],
"eslint-plugin-es": ["eslint-plugin-es@4.1.0", "", { "dependencies": { "eslint-utils": "^2.0.0", "regexpp": "^3.0.0" }, "peerDependencies": { "eslint": ">=4.19.1" } }, "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ=="],
"eslint-plugin-import": ["eslint-plugin-import@2.26.0", "", { "dependencies": { "array-includes": "^3.1.4", "array.prototype.flat": "^1.2.5", "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", "eslint-module-utils": "^2.7.3", "has": "^1.0.3", "is-core-module": "^2.8.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", "object.values": "^1.1.5", "resolve": "^1.22.0", "tsconfig-paths": "^3.14.1" }, "peerDependencies": { "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA=="],
"eslint-plugin-n": ["eslint-plugin-n@15.3.0", "", { "dependencies": { "builtins": "^5.0.1", "eslint-plugin-es": "^4.1.0", "eslint-utils": "^3.0.0", "ignore": "^5.1.1", "is-core-module": "^2.10.0", "minimatch": "^3.1.2", "resolve": "^1.22.1", "semver": "^7.3.7" }, "peerDependencies": { "eslint": ">=7.0.0" } }, "sha512-IyzPnEWHypCWasDpxeJnim60jhlumbmq0pubL6IOcnk8u2y53s5QfT8JnXy7skjHJ44yWHRb11PLtDHuu1kg/Q=="],
"eslint-plugin-promise": ["eslint-plugin-promise@6.0.1", "", { "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0" } }, "sha512-uM4Tgo5u3UWQiroOyDEsYcVMOo7re3zmno0IZmB5auxoaQNIceAbXEkSt8RNrKtaYehARHG06pYK6K1JhtP0Zw=="],
"eslint-scope": ["eslint-scope@7.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw=="],
"eslint-utils": ["eslint-utils@3.0.0", "", { "dependencies": { "eslint-visitor-keys": "^2.0.0" }, "peerDependencies": { "eslint": ">=5" } }, "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA=="],
"eslint-visitor-keys": ["eslint-visitor-keys@3.3.0", "", {}, "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA=="],
"espree": ["espree@9.4.0", "", { "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.3.0" } }, "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw=="],
"esquery": ["esquery@1.4.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w=="],
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
"estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
"fast-glob": ["fast-glob@3.2.12", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w=="],
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
"fastq": ["fastq@1.13.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw=="],
"fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
"file-entry-cache": ["file-entry-cache@6.0.1", "", { "dependencies": { "flat-cache": "^3.0.4" } }, "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg=="],
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
"flat-cache": ["flat-cache@3.0.4", "", { "dependencies": { "flatted": "^3.1.0", "rimraf": "^3.0.2" } }, "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg=="],
"flatted": ["flatted@3.2.7", "", {}, "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ=="],
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
"function-bind": ["function-bind@1.1.1", "", {}, "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="],
"function.prototype.name": ["function.prototype.name@1.1.5", "", { "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", "es-abstract": "^1.19.0", "functions-have-names": "^1.2.2" } }, "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA=="],
"functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="],
"get-intrinsic": ["get-intrinsic@1.1.3", "", { "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.3" } }, "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A=="],
"get-symbol-description": ["get-symbol-description@1.0.0", "", { "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" } }, "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw=="],
"glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
"globals": ["globals@13.17.0", "", { "dependencies": { "type-fest": "^0.20.2" } }, "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw=="],
"globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="],
"graceful-fs": ["graceful-fs@4.2.10", "", {}, "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="],
"grapheme-splitter": ["grapheme-splitter@1.0.4", "", {}, "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ=="],
"has": ["has@1.0.3", "", { "dependencies": { "function-bind": "^1.1.1" } }, "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw=="],
"has-bigints": ["has-bigints@1.0.2", "", {}, "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ=="],
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"has-property-descriptors": ["has-property-descriptors@1.0.0", "", { "dependencies": { "get-intrinsic": "^1.1.1" } }, "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ=="],
"has-symbols": ["has-symbols@1.0.3", "", {}, "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="],
"has-tostringtag": ["has-tostringtag@1.0.0", "", { "dependencies": { "has-symbols": "^1.0.2" } }, "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ=="],
"hosted-git-info": ["hosted-git-info@2.8.9", "", {}, "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="],
"ignore": ["ignore@5.2.0", "", {}, "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ=="],
"import-fresh": ["import-fresh@3.3.0", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw=="],
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
"inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="],
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
"internal-slot": ["internal-slot@1.0.3", "", { "dependencies": { "get-intrinsic": "^1.1.0", "has": "^1.0.3", "side-channel": "^1.0.4" } }, "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA=="],
"is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="],
"is-bigint": ["is-bigint@1.0.4", "", { "dependencies": { "has-bigints": "^1.0.1" } }, "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg=="],
"is-boolean-object": ["is-boolean-object@1.1.2", "", { "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" } }, "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA=="],
"is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="],
"is-core-module": ["is-core-module@2.10.0", "", { "dependencies": { "has": "^1.0.3" } }, "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg=="],
"is-date-object": ["is-date-object@1.0.5", "", { "dependencies": { "has-tostringtag": "^1.0.0" } }, "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
"is-negative-zero": ["is-negative-zero@2.0.2", "", {}, "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA=="],
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
"is-number-object": ["is-number-object@1.0.7", "", { "dependencies": { "has-tostringtag": "^1.0.0" } }, "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ=="],
"is-regex": ["is-regex@1.1.4", "", { "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" } }, "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg=="],
"is-shared-array-buffer": ["is-shared-array-buffer@1.0.2", "", { "dependencies": { "call-bind": "^1.0.2" } }, "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA=="],
"is-string": ["is-string@1.0.7", "", { "dependencies": { "has-tostringtag": "^1.0.0" } }, "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg=="],
"is-symbol": ["is-symbol@1.0.4", "", { "dependencies": { "has-symbols": "^1.0.2" } }, "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg=="],
"is-weakref": ["is-weakref@1.0.2", "", { "dependencies": { "call-bind": "^1.0.2" } }, "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ=="],
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"js-sdsl": ["js-sdsl@4.1.4", "", {}, "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw=="],
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": "bin/js-yaml.js" }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
"json-parse-better-errors": ["json-parse-better-errors@1.0.2", "", {}, "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="],
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
"json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": "lib/cli.js" }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="],
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
"load-json-file": ["load-json-file@4.0.0", "", { "dependencies": { "graceful-fs": "^4.1.2", "parse-json": "^4.0.0", "pify": "^3.0.0", "strip-bom": "^3.0.0" } }, "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw=="],
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
"memorystream": ["memorystream@0.3.1", "", {}, "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
"micromatch": ["micromatch@4.0.5", "", { "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" } }, "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA=="],
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"minimist": ["minimist@1.2.6", "", {}, "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="],
"ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
"native-file-system-adapter": ["native-file-system-adapter@github:jimmywarting/native-file-system-adapter#d1a158f", { "optionalDependencies": { "fetch-blob": "^3.2.0" } }, "jimmywarting-native-file-system-adapter-d1a158f"],
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
"nice-try": ["nice-try@1.0.5", "", {}, "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="],
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
"normalize-package-data": ["normalize-package-data@2.5.0", "", { "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA=="],
"npm-run-all": ["npm-run-all@4.1.5", "", { "dependencies": { "ansi-styles": "^3.2.1", "chalk": "^2.4.1", "cross-spawn": "^6.0.5", "memorystream": "^0.3.1", "minimatch": "^3.0.4", "pidtree": "^0.3.0", "read-pkg": "^3.0.0", "shell-quote": "^1.6.1", "string.prototype.padend": "^3.0.0" }, "bin": { "npm-run-all": "bin/npm-run-all/index.js", "run-p": "bin/run-p/index.js", "run-s": "bin/run-s/index.js" } }, "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ=="],
"object-inspect": ["object-inspect@1.12.2", "", {}, "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ=="],
"object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="],
"object.assign": ["object.assign@4.1.4", "", { "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", "has-symbols": "^1.0.3", "object-keys": "^1.1.1" } }, "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ=="],
"object.values": ["object.values@1.1.5", "", { "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", "es-abstract": "^1.19.1" } }, "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg=="],
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
"optionator": ["optionator@0.9.1", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.3" } }, "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw=="],
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
"parse-json": ["parse-json@4.0.0", "", { "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" } }, "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw=="],
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
"path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
"path-type": ["path-type@3.0.0", "", { "dependencies": { "pify": "^3.0.0" } }, "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg=="],
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"pidtree": ["pidtree@0.3.1", "", { "bin": "bin/pidtree.js" }, "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA=="],
"pify": ["pify@3.0.0", "", {}, "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg=="],
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
"punycode": ["punycode@2.1.1", "", {}, "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="],
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"read-pkg": ["read-pkg@3.0.0", "", { "dependencies": { "load-json-file": "^4.0.0", "normalize-package-data": "^2.3.2", "path-type": "^3.0.0" } }, "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA=="],
"regexp.prototype.flags": ["regexp.prototype.flags@1.4.3", "", { "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", "functions-have-names": "^1.2.2" } }, "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA=="],
"regexpp": ["regexpp@3.2.0", "", {}, "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg=="],
"resolve": ["resolve@1.22.1", "", { "dependencies": { "is-core-module": "^2.9.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw=="],
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
"reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="],
"rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": "bin.js" }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="],
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
"safe-regex-test": ["safe-regex-test@1.0.0", "", { "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", "is-regex": "^1.1.4" } }, "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA=="],
"semver": ["semver@7.6.2", "", { "bin": "bin/semver.js" }, "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"shell-quote": ["shell-quote@1.7.3", "", {}, "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw=="],
"side-channel": ["side-channel@1.0.4", "", { "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", "object-inspect": "^1.9.0" } }, "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw=="],
"slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
"spdx-correct": ["spdx-correct@3.1.1", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w=="],
"spdx-exceptions": ["spdx-exceptions@2.3.0", "", {}, "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A=="],
"spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="],
"spdx-license-ids": ["spdx-license-ids@3.0.12", "", {}, "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA=="],
"string.prototype.padend": ["string.prototype.padend@3.1.3", "", { "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", "es-abstract": "^1.19.1" } }, "sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg=="],
"string.prototype.trimend": ["string.prototype.trimend@1.0.5", "", { "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", "es-abstract": "^1.19.5" } }, "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog=="],
"string.prototype.trimstart": ["string.prototype.trimstart@1.0.5", "", { "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", "es-abstract": "^1.19.5" } }, "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg=="],
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="],
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
"text-table": ["text-table@0.2.0", "", {}, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="],
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
"tsconfig-paths": ["tsconfig-paths@3.14.1", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.1", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ=="],
"tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
"tsutils": ["tsutils@3.21.0", "", { "dependencies": { "tslib": "^1.8.1" }, "peerDependencies": { "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA=="],
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
"type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="],
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"unbox-primitive": ["unbox-primitive@1.0.2", "", { "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" } }, "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw=="],
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
"validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="],
"web-streams-polyfill": ["web-streams-polyfill@3.2.1", "", {}, "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"which-boxed-primitive": ["which-boxed-primitive@1.0.2", "", { "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", "is-number-object": "^1.0.4", "is-string": "^1.0.5", "is-symbol": "^1.0.3" } }, "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg=="],
"word-wrap": ["word-wrap@1.2.4", "", {}, "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA=="],
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
"@typescript-eslint/utils/eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="],
"chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"dir-glob/path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
"eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"eslint-plugin-es/eslint-utils": ["eslint-utils@2.1.0", "", { "dependencies": { "eslint-visitor-keys": "^1.1.0" } }, "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg=="],
"eslint-plugin-import/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
"eslint-plugin-import/doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="],
"eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@2.1.0", "", {}, "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw=="],
"esquery/estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
"esrecurse/estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"normalize-package-data/semver": ["semver@5.7.2", "", { "bin": "bin/semver" }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="],
"npm-run-all/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="],
"npm-run-all/cross-spawn": ["cross-spawn@6.0.5", "", { "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" } }, "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ=="],
"@typescript-eslint/utils/eslint-scope/estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="],
"chalk/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"eslint-plugin-es/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@1.3.0", "", {}, "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="],
"eslint-plugin-import/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
"npm-run-all/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
"npm-run-all/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
"npm-run-all/cross-spawn/path-key": ["path-key@2.0.1", "", {}, "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw=="],
"npm-run-all/cross-spawn/semver": ["semver@5.7.2", "", { "bin": "bin/semver" }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="],
"npm-run-all/cross-spawn/shebang-command": ["shebang-command@1.2.0", "", { "dependencies": { "shebang-regex": "^1.0.0" } }, "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg=="],
"npm-run-all/cross-spawn/which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": "bin/which" }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="],
"chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"npm-run-all/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
"npm-run-all/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@1.0.0", "", {}, "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ=="],
}
}

5575
src/Browser/Avalonia.Browser/webapp/package-lock.json

File diff suppressed because it is too large

8
src/Browser/Avalonia.Browser/webapp/package.json

@ -1,11 +1,5 @@
{
"name": "avalonia.browser",
"scripts": {
"typecheck": "npx tsc -noEmit",
"eslint": "npx eslint . --fix",
"prebuild": "npm-run-all typecheck eslint",
"build": "node build.js"
},
"devDependencies": {
"@types/emscripten": "^1.39.6",
"@types/offscreencanvas": "2019.7.1",
@ -21,6 +15,6 @@
"typescript": "^5.8.3"
},
"dependencies": {
"native-file-system-adapter": "github:jimmywarting/native-file-system-adapter#d43ad841581c2cc3ce47bbd1e8f11950ebdff027"
"native-file-system-adapter": "github:jimmywarting/native-file-system-adapter"
}
}

12
src/Headless/Avalonia.Headless.Vnc/Avalonia.Headless.Vnc.csproj

@ -6,8 +6,16 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Headless\Avalonia.Headless.csproj" />
<PackageReference Include="Quamotion.RemoteViewing" Version="1.1.179" />
<ProjectReference Include="../Avalonia.Headless/Avalonia.Headless.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Quamotion.RemoteViewing" Version="1.1.211" />
<PackageReference Include="SharpCompress" Version="0.41.0" />
</ItemGroup>
<ItemGroup>
<Compile Include="../../Avalonia.Base/Reactive/Disposable.cs" />
</ItemGroup>
<Import Project="..\..\..\build\DevAnalyzers.props" />

6
src/Headless/Avalonia.Headless.Vnc/AvaloniaVncLogger.cs

@ -1,13 +1,13 @@
using System;
using Avalonia.Logging;
using Avalonia.Reactive;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions.Internal;
namespace Avalonia.Headless.Vnc;
internal class AvaloniaVncLogger : ILogger
{
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
Logger.TryGet(ToLogEventLevel(logLevel), LogArea.VncPlatform)
?.Log(state, formatter(state,exception));
@ -20,7 +20,7 @@ internal class AvaloniaVncLogger : ILogger
public IDisposable BeginScope<TState>(TState state)
{
return NullScope.Instance;
return Disposable.Empty;
}
private static LogEventLevel ToLogEventLevel(LogLevel logLevel)

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

Loading…
Cancel
Save