Browse Source

Replace shared project with Avalonia.PlatformSupport

pull/7347/head
Max Katz 4 years ago
parent
commit
4d866b544c
  1. 41
      Avalonia.sln
  2. 5
      src/Android/Avalonia.Android/AndroidPlatform.cs
  3. 2
      src/Android/Avalonia.Android/AppBuilder.cs
  4. 4
      src/Android/Avalonia.Android/Avalonia.Android.csproj
  5. 18
      src/Android/Avalonia.Android/RuntimeInfo.cs
  6. 5
      src/Avalonia.Base/Platform/IRuntimePlatform.cs
  7. 3
      src/Avalonia.DesktopRuntime/ApiCompatBaseline.txt
  8. 2
      src/Avalonia.DesktopRuntime/AppBuilder.cs
  9. 2
      src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj
  10. 40
      src/Avalonia.DesktopRuntime/RuntimeInfo.cs
  11. 17
      src/Avalonia.PlatformSupport/AssetLoader.cs
  12. 18
      src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj
  13. 65
      src/Avalonia.PlatformSupport/DynLoader.cs
  14. 79
      src/Avalonia.PlatformSupport/StandardRuntimePlatform.cs
  15. 31
      src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs
  16. 17
      src/Shared/PlatformSupport/PlatformSupport.projitems
  17. 11
      src/Shared/PlatformSupport/PlatformSupport.shproj
  18. 28
      src/Shared/PlatformSupport/StandardRuntimePlatformServices.cs
  19. 13
      src/Shared/RenderHelpers/QuadBezierHelper.cs
  20. 14
      src/Shared/RenderHelpers/RenderHelpers.projitems
  21. 13
      src/Shared/RenderHelpers/RenderHelpers.shproj
  22. 84
      src/Shared/WindowResizeDragHelper.cs
  23. 3
      src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
  24. 3
      src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj
  25. 5
      src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs
  26. 61
      src/Web/Avalonia.Web.Blazor/BlazorRuntimePlatform.cs
  27. 1
      src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
  28. 11
      src/iOS/Avalonia.iOS/Avalonia.iOS.csproj
  29. 5
      src/iOS/Avalonia.iOS/Boilerplate/AppBuilder.cs
  30. 19
      src/iOS/Avalonia.iOS/Boilerplate/RuntimePlatform.cs
  31. 595
      src/iOS/Avalonia.iOS/Boilerplate/Shared.cs
  32. 4
      tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs
  33. 2
      tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs
  34. 2
      tests/Avalonia.RenderTests/TestBase.cs
  35. 2
      tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj
  36. 16
      tests/Avalonia.UnitTests/RuntimeInfo.cs
  37. 2
      tests/Avalonia.UnitTests/TestServices.cs
  38. 2
      tests/Avalonia.UnitTests/UnitTestApplication.cs

41
Avalonia.sln

@ -60,20 +60,17 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DEF5-D50F-4975-8B72-124C9EB54066}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
src\Shared\ModuleInitializer.cs = src\Shared\ModuleInitializer.cs
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI", "src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj", "{6417B24E-49C2-4985-8DB2-3AB9D898EC91}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PlatformSupport", "src\Shared\PlatformSupport\PlatformSupport.shproj", "{E4D9629C-F168-4224-3F51-A5E482FFBC42}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup", "src\Markup\Avalonia.Markup\Avalonia.Markup.csproj", "{6417E941-21BC-467B-A771-0DE389353CE6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.UnitTests", "tests\Avalonia.Markup.UnitTests\Avalonia.Markup.UnitTests.csproj", "{8EF392D5-1416-45AA-9956-7CBBC3229E8A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BindingDemo", "samples\BindingDemo\BindingDemo.csproj", "{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "RenderHelpers", "src\Shared\RenderHelpers\RenderHelpers.shproj", "{3C4C0CB4-0C0F-4450-A37B-148C84FF905F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Skia", "Skia", "{3743B0F2-CC41-4F14-A8C8-267F579BF91E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Android", "Android", "{7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}"
@ -235,15 +232,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsInteropTest", "sampl
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlSamples", "samples\SampleControls\ControlSamples.csproj", "{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.PlatformSupport", "src\Avalonia.PlatformSupport\Avalonia.PlatformSupport.csproj", "{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 5
src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 5
src\Shared\RenderHelpers\RenderHelpers.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 5
src\Shared\PlatformSupport\PlatformSupport.projitems*{88060192-33d5-4932-b0f9-8bd2763e857d}*SharedItemsImports = 5
src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
Ad-Hoc|iPhone = Ad-Hoc|iPhone
@ -2169,6 +2160,30 @@ Global
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhone.Build.0 = Release|Any CPU
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhone.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhone.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|Any CPU.Build.0 = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhone.ActiveCfg = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhone.Build.0 = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -2187,11 +2202,9 @@ Global
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{99135EAB-653D-47E4-A378-C96E1278CA44} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{3E53A01A-B331-47F3-B828-4A5717E77A24} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{E4D9629C-F168-4224-3F51-A5E482FFBC42} = {A689DEF5-D50F-4975-8B72-124C9EB54066}
{6417E941-21BC-467B-A771-0DE389353CE6} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{8EF392D5-1416-45AA-9956-7CBBC3229E8A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{3C4C0CB4-0C0F-4450-A37B-148C84FF905F} = {A689DEF5-D50F-4975-8B72-124C9EB54066}
{7B92AF71-6287-4693-9DCB-BD5B6E927E23} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}
{FF69B927-C545-49AE-8E16-3D14D621AA12} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}
{4488AD85-1495-4809-9AA4-DDFE0A48527E} = {0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}

5
src/Android/Avalonia.Android/AndroidPlatform.cs

@ -10,7 +10,7 @@ using Avalonia.Input.Platform;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Shared.PlatformSupport;
using Avalonia.PlatformSupport;
using Avalonia.Skia;
namespace Avalonia
@ -59,8 +59,7 @@ namespace Avalonia.Android
.Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoaderStub>()
.Bind<IRenderTimer>().ToConstant(new ChoreographerTimer())
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IAssetLoader>().ToConstant(new AssetLoader(appType.Assembly));
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();
SkiaPlatform.Initialize();

2
src/Android/Avalonia.Android/AppBuilder.cs

@ -1,5 +1,5 @@
using Avalonia.Controls;
using Avalonia.Shared.PlatformSupport;
using Avalonia.PlatformSupport;
namespace Avalonia
{

4
src/Android/Avalonia.Android/Avalonia.Android.csproj

@ -5,9 +5,11 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\..\Avalonia.PlatformSupport\Avalonia.PlatformSupport.csproj">
<SetTargetFramework>TargetFramework=netstandard2.0</SetTargetFramework>
</ProjectReference>
<ProjectReference Include="..\..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
</ItemGroup>
<Import Project="..\..\Shared\PlatformSupport\PlatformSupport.projitems" Label="Shared" />
<Import Project="..\..\..\build\Rx.props" />
<Import Project="..\..\..\build\AndroidWorkarounds.props" />
</Project>

18
src/Android/Avalonia.Android/RuntimeInfo.cs

@ -1,18 +0,0 @@
using Avalonia.Platform;
namespace Avalonia.Shared.PlatformSupport
{
internal partial class StandardRuntimePlatform
{
public RuntimePlatformInfo GetRuntimeInfo() => new RuntimePlatformInfo
{
IsCoreClr = false,
IsDesktop = false,
IsMobile = true,
IsDotNetFramework = false,
IsMono = true,
IsUnix = true,
OperatingSystem = OperatingSystemType.Android
};
}
}

5
src/Avalonia.Base/Platform/IRuntimePlatform.cs

@ -1,5 +1,4 @@
using System;
using System.Reflection;
namespace Avalonia.Platform
{
@ -23,6 +22,7 @@ namespace Avalonia.Platform
public OperatingSystemType OperatingSystem { get; set; }
public bool IsDesktop { get; set; }
public bool IsMobile { get; set; }
public bool IsBrowser { get; set; }
public bool IsCoreClr { get; set; }
public bool IsMono { get; set; }
public bool IsDotNetFramework { get; set; }
@ -36,6 +36,7 @@ namespace Avalonia.Platform
Linux,
OSX,
Android,
iOS
iOS,
Browser
}
}

3
src/Avalonia.DesktopRuntime/ApiCompatBaseline.txt

@ -0,0 +1,3 @@
Compat issues with assembly Avalonia.DesktopRuntime:
TypesMustExist : Type 'Avalonia.Shared.PlatformSupport.AssetLoader' does not exist in the implementation but it does exist in the contract.
Total Issues: 1

2
src/Avalonia.DesktopRuntime/AppBuilder.cs

@ -4,7 +4,7 @@ using System.Linq;
using System.Reflection;
using Avalonia.Controls;
using Avalonia.Platform;
using Avalonia.Shared.PlatformSupport;
using Avalonia.PlatformSupport;
namespace Avalonia
{

2
src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj

@ -8,6 +8,7 @@
<ProjectReference Include="../Avalonia.Base/Avalonia.Base.csproj" />
<ProjectReference Include="../Avalonia.Visuals/Avalonia.Visuals.csproj" />
<ProjectReference Include="../Avalonia.Controls/Avalonia.Controls.csproj" />
<ProjectReference Include="../Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj" />
</ItemGroup>
<ItemGroup>
@ -16,6 +17,5 @@
<Import Project="..\..\build\NetCore.props" />
<Import Project="..\..\build\NetFX.props" />
<Import Project="..\Shared\PlatformSupport\PlatformSupport.projitems" />
<Import Project="..\..\build\ApiDiff.props" />
</Project>

40
src/Avalonia.DesktopRuntime/RuntimeInfo.cs

@ -1,40 +0,0 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Platform;
namespace Avalonia.Shared.PlatformSupport
{
internal partial class StandardRuntimePlatform
{
private static readonly Lazy<RuntimePlatformInfo> Info = new Lazy<RuntimePlatformInfo>(() =>
{
OperatingSystemType os;
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
os = OperatingSystemType.OSX;
else if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
os = OperatingSystemType.Linux;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
os = OperatingSystemType.WinNT;
else
throw new Exception("Unknown OS platform " + RuntimeInformation.OSDescription);
return new RuntimePlatformInfo
{
#if NETCOREAPP2_0
IsCoreClr = true,
#elif NET461
IsDotNetFramework = false,
#endif
IsDesktop = true,
IsMono = false,
IsMobile = false,
IsUnix = os != OperatingSystemType.WinNT,
OperatingSystem = os,
};
});
public RuntimePlatformInfo GetRuntimeInfo() => Info.Value;
}
}

17
src/Shared/PlatformSupport/AssetLoader.cs → src/Avalonia.PlatformSupport/AssetLoader.cs

@ -6,9 +6,7 @@ using System.Reflection;
using Avalonia.Platform;
using Avalonia.Utilities;
#nullable enable
namespace Avalonia.Shared.PlatformSupport
namespace Avalonia.PlatformSupport
{
/// <summary>
/// Loads assets compiled into the application binary.
@ -233,14 +231,15 @@ namespace Avalonia.Shared.PlatformSupport
else
{
// iOS does not support loading assemblies dynamically!
//
#if __IOS__
throw new InvalidOperationException(
$"Assembly {name} needs to be referenced and explicitly loaded before loading resources");
#else
#if NET6_0_OR_GREATER
if (OperatingSystem.IsIOS())
{
throw new InvalidOperationException(
$"Assembly {name} needs to be referenced and explicitly loaded before loading resources");
}
#endif
name = Uri.UnescapeDataString(name);
AssemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(name));
#endif
}
}

18
src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net461;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../Avalonia.Base/Avalonia.Base.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" Condition="'$(TargetFramework)' == 'net461'" />
</ItemGroup>
<Import Project="..\..\build\NetCore.props" />
<Import Project="..\..\build\NetFX.props" />
<Import Project="..\..\build\NullableEnable.props" />
</Project>

65
src/Shared/PlatformSupport/DynLoader.cs → src/Avalonia.PlatformSupport/DynLoader.cs

@ -1,35 +1,40 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
namespace Avalonia.Shared.PlatformSupport
// ReSharper disable InconsistentNaming
namespace Avalonia.PlatformSupport
{
#if !__IOS__
class UnixLoader : IDynamicLibraryLoader
{
// ReSharper disable InconsistentNaming
static class LinuxImports
{
#if __ANDROID__
[DllImport("libdl.so")]
#else
[DllImport("libdl.so.2")]
#endif
private static extern IntPtr dlopen(string path, int flags);
#if __ANDROID__
[DllImport("libdl.so")]
#else
[DllImport("libdl.so.2")]
#endif
private static extern IntPtr dlsym(IntPtr handle, string symbol);
#if __ANDROID__
[DllImport("libdl.so")]
#else
[DllImport("libdl.so.2")]
#endif
private static extern IntPtr dlerror();
public static void Init()
{
DlOpen = dlopen;
DlSym = dlsym;
DlError = dlerror;
}
}
static class AndroidImports
{
[DllImport("libdl.so")]
private static extern IntPtr dlopen(string path, int flags);
[DllImport("libdl.so")]
private static extern IntPtr dlsym(IntPtr handle, string symbol);
[DllImport("libdl.so")]
private static extern IntPtr dlerror();
public static void Init()
@ -42,8 +47,6 @@ namespace Avalonia.Shared.PlatformSupport
static class OsXImports
{
[DllImport("/usr/lib/libSystem.dylib")]
private static extern IntPtr dlopen(string path, int flags);
@ -72,32 +75,36 @@ namespace Avalonia.Shared.PlatformSupport
uname(buffer);
var unixName = Marshal.PtrToStringAnsi(buffer);
Marshal.FreeHGlobal(buffer);
if(unixName == "Darwin")
if (unixName == "Darwin")
OsXImports.Init();
#if NET6_0_OR_GREATER
else if (OperatingSystem.IsAndroid())
AndroidImports.Init();
#endif
else
LinuxImports.Init();
}
private static Func<string, int, IntPtr> DlOpen;
private static Func<IntPtr, string, IntPtr> DlSym;
private static Func<IntPtr> DlError;
private static Func<string, int, IntPtr>? DlOpen;
private static Func<IntPtr, string, IntPtr>? DlSym;
private static Func<IntPtr>? DlError;
// ReSharper restore InconsistentNaming
static string DlErrorString() => Marshal.PtrToStringAnsi(DlError());
static string? DlErrorString() => Marshal.PtrToStringAnsi(DlError!.Invoke());
public IntPtr LoadLibrary(string dll)
{
var handle = DlOpen(dll, 1);
var handle = DlOpen!.Invoke(dll, 1);
if (handle == IntPtr.Zero)
throw new DynamicLibraryLoaderException(DlErrorString());
throw new DynamicLibraryLoaderException(DlErrorString()!);
return handle;
}
public IntPtr GetProcAddress(IntPtr dll, string proc, bool optional)
{
var ptr = DlSym(dll, proc);
var ptr = DlSym!.Invoke(dll, proc);
if (ptr == IntPtr.Zero && !optional)
throw new DynamicLibraryLoaderException(DlErrorString());
throw new DynamicLibraryLoaderException(DlErrorString()!);
return ptr;
}
}
@ -129,8 +136,7 @@ namespace Avalonia.Shared.PlatformSupport
}
}
#else
internal class IOSLoader : IDynamicLibraryLoader
internal class NotSupportedLoader : IDynamicLibraryLoader
{
IntPtr IDynamicLibraryLoader.LoadLibrary(string dll)
{
@ -142,5 +148,4 @@ namespace Avalonia.Shared.PlatformSupport
throw new PlatformNotSupportedException();
}
}
#endif
}

79
src/Shared/PlatformSupport/StandardRuntimePlatform.cs → src/Avalonia.PlatformSupport/StandardRuntimePlatform.cs

@ -1,14 +1,13 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia.Platform;
namespace Avalonia.Shared.PlatformSupport
namespace Avalonia.PlatformSupport
{
internal partial class StandardRuntimePlatform : IRuntimePlatform
public class StandardRuntimePlatform : IRuntimePlatform
{
public IDisposable StartSystemTimer(TimeSpan interval, Action tick)
{
@ -16,15 +15,15 @@ namespace Avalonia.Shared.PlatformSupport
}
public IUnmanagedBlob AllocBlob(int size) => new UnmanagedBlob(this, size);
class UnmanagedBlob : IUnmanagedBlob
private class UnmanagedBlob : IUnmanagedBlob
{
private readonly StandardRuntimePlatform _plat;
private IntPtr _address;
private readonly object _lock = new object();
#if DEBUG
private static readonly List<string> Backtraces = new List<string>();
private static Thread GCThread;
private static Thread? GCThread;
private readonly string _backtrace;
private static readonly object _btlock = new object();
@ -38,15 +37,14 @@ namespace Avalonia.Shared.PlatformSupport
[MethodImpl(MethodImplOptions.NoInlining)]
static void Spawn() => new GCThreadDetector();
static UnmanagedBlob()
{
Spawn();
GC.WaitForPendingFinalizers();
}
#endif
public UnmanagedBlob(StandardRuntimePlatform plat, int size)
{
try
@ -117,14 +115,12 @@ namespace Avalonia.Shared.PlatformSupport
DoDispose();
}
public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address;
public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address;
public int Size { get; private set; }
public bool IsDisposed { get; private set; }
}
#if NET461 || NETCOREAPP2_0
#if NET461 || NETCOREAPP2_0_OR_GREATER
[DllImport("libc", SetLastError = true)]
private static extern IntPtr mmap(IntPtr addr, IntPtr length, int prot, int flags, int fd, IntPtr offset);
[DllImport("libc", SetLastError = true)]
@ -133,15 +129,15 @@ namespace Avalonia.Shared.PlatformSupport
private static extern long sysconf(int name);
private bool? _useMmap;
private bool UseMmap
private bool UseMmap
=> _useMmap ?? ((_useMmap = GetRuntimeInfo().OperatingSystem == OperatingSystemType.Linux)).Value;
IntPtr Alloc(int size)
{
if (UseMmap)
{
var rv = mmap(IntPtr.Zero, new IntPtr(size), 3, 0x22, -1, IntPtr.Zero);
if (rv.ToInt64() == -1 || (ulong) rv.ToInt64() == 0xffffffff)
if (rv.ToInt64() == -1 || (ulong)rv.ToInt64() == 0xffffffff)
{
var errno = Marshal.GetLastWin32Error();
throw new Exception("Unable to allocate memory: " + errno);
@ -169,5 +165,54 @@ namespace Avalonia.Shared.PlatformSupport
IntPtr Alloc(int size) => Marshal.AllocHGlobal(size);
void Free(IntPtr ptr, int len) => Marshal.FreeHGlobal(ptr);
#endif
private static readonly Lazy<RuntimePlatformInfo> Info = new Lazy<RuntimePlatformInfo>(() =>
{
OperatingSystemType os;
#if NET5_0_OR_GREATER
if (OperatingSystem.IsWindows())
os = OperatingSystemType.WinNT;
else if (OperatingSystem.IsMacOS())
os = OperatingSystemType.OSX;
else if (OperatingSystem.IsLinux() || OperatingSystem.IsFreeBSD())
os = OperatingSystemType.Linux;
else if (OperatingSystem.IsAndroid())
os = OperatingSystemType.Android;
else if (OperatingSystem.IsIOS())
os = OperatingSystemType.iOS;
else if (OperatingSystem.IsBrowser())
os = OperatingSystemType.Browser;
else
throw new Exception("Unknown OS platform " + RuntimeInformation.OSDescription);
#else
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
os = OperatingSystemType.OSX;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
os = OperatingSystemType.Linux;
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
os = OperatingSystemType.WinNT;
else
throw new Exception("Unknown OS platform " + RuntimeInformation.OSDescription);
#endif
return new RuntimePlatformInfo
{
#if NETCOREAPP
IsCoreClr = true,
#elif NETFRAMEWORK
IsDotNetFramework = false,
#endif
IsDesktop = os == OperatingSystemType.Linux || os == OperatingSystemType.OSX || os == OperatingSystemType.WinNT,
IsMono = os == OperatingSystemType.Android || os == OperatingSystemType.iOS || os == OperatingSystemType.Browser,
IsMobile = os == OperatingSystemType.Android || os == OperatingSystemType.iOS,
IsUnix = os == OperatingSystemType.Linux || os == OperatingSystemType.OSX || os == OperatingSystemType.Android,
IsBrowser = os == OperatingSystemType.Browser,
OperatingSystem = os,
};
});
public virtual RuntimePlatformInfo GetRuntimeInfo() => Info.Value;
}
}

31
src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs

@ -0,0 +1,31 @@
using System.Reflection;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
namespace Avalonia.PlatformSupport
{
public static class StandardRuntimePlatformServices
{
public static void Register(Assembly? assembly = null)
{
var standardPlatform = new StandardRuntimePlatform();
var os = standardPlatform.GetRuntimeInfo().OperatingSystem;
AssetLoader.RegisterResUriParsers();
AvaloniaLocator.CurrentMutable
.Bind<IRuntimePlatform>().ToConstant(standardPlatform)
.Bind<IAssetLoader>().ToConstant(new AssetLoader(assembly))
.Bind<IDynamicLibraryLoader>().ToConstant(
os switch
{
OperatingSystemType.WinNT => new Win32Loader(),
OperatingSystemType.OSX => new UnixLoader(),
OperatingSystemType.Linux => new UnixLoader(),
OperatingSystemType.Android => new UnixLoader(),
// iOS, WASM, ...
_ => (IDynamicLibraryLoader)new NotSupportedLoader()
}
);
}
}
}

17
src/Shared/PlatformSupport/PlatformSupport.projitems

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>{E4D9629C-F168-4224-8F51-F5E482FFEC42}</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>Avalonia.Shared.PlatformSupport</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)AssetLoader.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DynLoader.cs" />
<Compile Include="$(MSBuildThisFileDirectory)StandardRuntimePlatform.cs" />
<Compile Include="$(MSBuildThisFileDirectory)StandardRuntimePlatformServices.cs" />
</ItemGroup>
</Project>

11
src/Shared/PlatformSupport/PlatformSupport.shproj

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{E4D9629C-F168-4224-3F51-A5E482FFBC42}</ProjectGuid>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<Import Project="PlatformSupport.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>

28
src/Shared/PlatformSupport/StandardRuntimePlatformServices.cs

@ -1,28 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
namespace Avalonia.Shared.PlatformSupport
{
static class StandardRuntimePlatformServices
{
public static void Register(Assembly assembly = null)
{
var standardPlatform = new StandardRuntimePlatform();
AssetLoader.RegisterResUriParsers();
AvaloniaLocator.CurrentMutable
.Bind<IRuntimePlatform>().ToConstant(standardPlatform)
.Bind<IAssetLoader>().ToConstant(new AssetLoader(assembly))
.Bind<IDynamicLibraryLoader>().ToConstant(
#if __IOS__
new IOSLoader()
#else
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? (IDynamicLibraryLoader)new Win32Loader()
: new UnixLoader()
#endif
);
}
}
}

13
src/Shared/RenderHelpers/QuadBezierHelper.cs

@ -1,13 +0,0 @@
using Avalonia.Platform;
namespace Avalonia.RenderHelpers
{
static class QuadBezierHelper
{
public static void QuadraticBezierTo(IStreamGeometryContextImpl context, Point current, Point controlPoint, Point endPoint)
{
//(s, (s + 2c)/ 3, (e + 2c)/ 3, e)
context.CubicBezierTo((current + 2*controlPoint)/3, (endPoint + 2*controlPoint)/3, endPoint);
}
}
}

14
src/Shared/RenderHelpers/RenderHelpers.projitems

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>3c4c0cb4-0c0f-4450-a37b-148c84ff905f</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>Avalonia.RenderHelpers</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)QuadBezierHelper.cs" />
</ItemGroup>
</Project>

13
src/Shared/RenderHelpers/RenderHelpers.shproj

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>3c4c0cb4-0c0f-4450-a37b-148c84ff905f</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="RenderHelpers.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>

84
src/Shared/WindowResizeDragHelper.cs

@ -1,84 +0,0 @@
using System;
using Avalonia.Controls;
using Avalonia.Input.Raw;
using Avalonia.Platform;
namespace Avalonia
{
internal class ManagedWindowResizeDragHelper
{
private readonly IWindowBaseImpl _window;
private readonly Action<bool> _captureMouse;
private readonly Action<Rect> _resize;
private WindowEdge? _edge;
private Point _prevPoint;
public ManagedWindowResizeDragHelper(IWindowBaseImpl window, Action<bool> captureMouse, Action<Rect> resize = null)
{
_window = window;
_captureMouse = captureMouse;
_resize = resize;
}
public void BeginResizeDrag(WindowEdge edge, Point currentMousePosition)
{
_captureMouse(true);
_prevPoint = currentMousePosition;
_edge = edge;
}
public bool PreprocessInputEvent(ref RawInputEventArgs e)
{
if (_edge == null)
return false;
if (e is RawMouseEventArgs args)
{
if (args.Type == RawMouseEventType.LeftButtonUp)
{
_edge = null;
_captureMouse(false);
}
if (args.Type == RawMouseEventType.Move)
{
MoveWindow(args.Position);
return true;
}
_edge = null;
}
return false;
}
private void MoveWindow(Point position)
{
var diff = position - _prevPoint;
var edge = _edge.Value;
var rc = new Rect(_window.Position, _window.ClientSize);
if (edge == WindowEdge.East || edge == WindowEdge.NorthEast || edge == WindowEdge.SouthEast)
{
rc = rc.WithWidth(rc.Width + diff.X);
_prevPoint = _prevPoint.WithX(position.X);
}
if (edge == WindowEdge.West || edge == WindowEdge.NorthWest || edge == WindowEdge.SouthWest)
rc = rc.WithX(rc.X + diff.X).WithWidth(rc.Width - diff.X);
if (edge == WindowEdge.South || edge == WindowEdge.SouthWest || edge == WindowEdge.SouthEast)
{
rc = rc.WithHeight(rc.Height + diff.Y);
_prevPoint = _prevPoint.WithY(position.Y);
}
if (edge == WindowEdge.North || edge == WindowEdge.NorthWest || edge == WindowEdge.NorthEast)
rc = rc.WithY(rc.Y + diff.Y).WithHeight(rc.Height - diff.Y);
if (_resize != null)
_resize(rc);
else
{
if (_window.Position != rc.Position)
_window.Position = rc.Position;
if (_window.ClientSize != rc.Size)
_window.Resize(rc.Size);
}
}
}
}

3
src/Skia/Avalonia.Skia/Avalonia.Skia.csproj

@ -16,6 +16,5 @@
</ItemGroup>
<Import Project="..\..\..\build\SkiaSharp.props" />
<Import Project="..\..\..\build\HarfBuzzSharp.props" />
<Import Project="..\..\Shared\RenderHelpers\RenderHelpers.projitems" Label="Shared" />
<Import Project="..\..\..\build\HarfBuzzSharp.props" />
</Project>

3
src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj

@ -10,7 +10,6 @@
<ItemGroup>
<SupportedPlatform Include="browser" />
<Compile Include="..\..\Shared\PlatformSupport\AssetLoader.cs" />
</ItemGroup>
<PropertyGroup>
@ -51,7 +50,7 @@
<ItemGroup>
<ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\..\Avalonia.Controls\Avalonia.Controls.csproj" />
<ProjectReference Include="..\..\Avalonia.PlatformSupport\Avalonia.PlatformSupport.csproj" />
<ProjectReference Include="..\..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
</ItemGroup>
</Project>

5
src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs

@ -1,5 +1,6 @@
using Avalonia.Controls;
using Avalonia.Platform;
using Avalonia.PlatformSupport;
namespace Avalonia.Web.Blazor
{
@ -10,7 +11,9 @@ namespace Avalonia.Web.Blazor
{
}
public AvaloniaBlazorAppBuilder() : base(BlazorRuntimePlatform.Instance, BlazorRuntimePlatform.RegisterServices)
public AvaloniaBlazorAppBuilder()
: base(new StandardRuntimePlatform(),
builder => StandardRuntimePlatformServices.Register(builder.ApplicationType.Assembly))
{
UseWindowingSubsystem(BlazorWindowingPlatform.Register);
}

61
src/Web/Avalonia.Web.Blazor/BlazorRuntimePlatform.cs

@ -1,61 +0,0 @@
using System.Runtime.InteropServices;
using Avalonia.Platform;
using Avalonia.Shared.PlatformSupport;
namespace Avalonia.Web.Blazor
{
internal class BlazorRuntimePlatform : IRuntimePlatform
{
public static readonly IRuntimePlatform Instance = new BlazorRuntimePlatform();
public IDisposable StartSystemTimer(TimeSpan interval, Action tick)
{
return new Timer(_ => tick(), null, interval, interval);
}
public RuntimePlatformInfo GetRuntimeInfo()
{
return new RuntimePlatformInfo
{
IsDesktop = false,
IsMobile = false,
IsMono = true,
IsUnix = false,
IsCoreClr = false,
IsDotNetFramework = false
};
}
private class BasicBlob : IUnmanagedBlob
{
public BasicBlob(int size)
{
Address = Marshal.AllocHGlobal(size);
Size = size;
}
public void Dispose()
{
if (Address != IntPtr.Zero)
Marshal.FreeHGlobal(Address);
Address = IntPtr.Zero;
}
public IntPtr Address { get; private set; }
public int Size { get; }
public bool IsDisposed => Address == IntPtr.Zero;
}
public IUnmanagedBlob AllocBlob(int size)
{
return new BasicBlob(size);
}
public static void RegisterServices(AvaloniaBlazorAppBuilder builder)
{
AssetLoader.RegisterResUriParsers();
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>().ToConstant(Instance);
AvaloniaLocator.CurrentMutable.Bind<IAssetLoader>().ToConstant(new AssetLoader());
}
}
}

1
src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj

@ -17,6 +17,5 @@
<Import Project="..\..\..\build\Rx.props" />
<Import Project="..\..\..\build\SharpDX.props" />
<Import Project="..\..\..\build\HarfBuzzSharp.props" />
<Import Project="..\..\Shared\RenderHelpers\RenderHelpers.projitems" Label="Shared" />
<Import Project="..\..\..\build\JetBrains.Annotations.props" />
</Project>

11
src/iOS/Avalonia.iOS/Avalonia.iOS.csproj

@ -4,19 +4,14 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<Compile Update="Boilerplate\Shared.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Boilerplate\RuntimePlatform.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Reference Include="OpenTK-1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\..\Avalonia.PlatformSupport\Avalonia.PlatformSupport.csproj">
<SetTargetFramework>TargetFramework=netstandard2.0</SetTargetFramework>
</ProjectReference>
<ProjectReference Include="..\..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
</ItemGroup>
</Project>

5
src/iOS/Avalonia.iOS/Boilerplate/AppBuilder.cs

@ -1,6 +1,5 @@
using Avalonia.Controls;
using Avalonia.iOS;
using Avalonia.Shared.PlatformSupport;
using Avalonia.PlatformSupport;
namespace Avalonia
{
@ -12,4 +11,4 @@ namespace Avalonia
this.UseSkia().UseWindowingSubsystem(iOS.Platform.Register);
}
}
}
}

19
src/iOS/Avalonia.iOS/Boilerplate/RuntimePlatform.cs

@ -1,19 +0,0 @@
using Avalonia.Platform;
namespace Avalonia.Shared.PlatformSupport
{
partial class StandardRuntimePlatform
{
public RuntimePlatformInfo GetRuntimeInfo()
{
return new RuntimePlatformInfo
{
IsDesktop = false,
IsMobile = true,
IsMono = true,
IsUnix = true,
OperatingSystem = OperatingSystemType.iOS
};
}
}
}

595
src/iOS/Avalonia.iOS/Boilerplate/Shared.cs

@ -1,595 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
using Avalonia.Utilities;
namespace Avalonia.Shared.PlatformSupport
{
static class StandardRuntimePlatformServices
{
public static void Register(Assembly assembly = null)
{
var standardPlatform = new StandardRuntimePlatform();
AssetLoader.RegisterResUriParsers();
AvaloniaLocator.CurrentMutable
.Bind<IRuntimePlatform>().ToConstant(standardPlatform)
.Bind<IAssetLoader>().ToConstant(new AssetLoader(assembly))
.Bind<IDynamicLibraryLoader>().ToConstant(
#if __IOS__
new IOSLoader()
#else
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? (IDynamicLibraryLoader)new Win32Loader()
: new UnixLoader()
#endif
);
}
}
internal partial class StandardRuntimePlatform : IRuntimePlatform
{
public IDisposable StartSystemTimer(TimeSpan interval, Action tick)
{
return new Timer(_ => tick(), null, interval, interval);
}
public IUnmanagedBlob AllocBlob(int size) => new UnmanagedBlob(this, size);
class UnmanagedBlob : IUnmanagedBlob
{
private readonly StandardRuntimePlatform _plat;
private IntPtr _address;
private readonly object _lock = new object();
#if DEBUG
private static readonly List<string> Backtraces = new List<string>();
private static Thread GCThread;
private readonly string _backtrace;
private static readonly object _btlock = new object();
class GCThreadDetector
{
~GCThreadDetector()
{
GCThread = Thread.CurrentThread;
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void Spawn() => new GCThreadDetector();
static UnmanagedBlob()
{
Spawn();
GC.WaitForPendingFinalizers();
}
#endif
public UnmanagedBlob(StandardRuntimePlatform plat, int size)
{
if (size <= 0)
throw new ArgumentException("Positive number required", nameof(size));
_plat = plat;
_address = plat.Alloc(size);
GC.AddMemoryPressure(size);
Size = size;
#if DEBUG
_backtrace = Environment.StackTrace;
lock (_btlock)
Backtraces.Add(_backtrace);
#endif
}
void DoDispose()
{
lock (_lock)
{
if (!IsDisposed)
{
#if DEBUG
lock (_btlock)
Backtraces.Remove(_backtrace);
#endif
_plat?.Free(_address, Size);
GC.RemoveMemoryPressure(Size);
IsDisposed = true;
_address = IntPtr.Zero;
Size = 0;
}
}
}
public void Dispose()
{
#if DEBUG
if (Thread.CurrentThread.ManagedThreadId == GCThread?.ManagedThreadId)
{
lock (_lock)
{
if (!IsDisposed)
{
Console.Error.WriteLine("Native blob disposal from finalizer thread\nBacktrace: "
+ Environment.StackTrace
+ "\n\nBlob created by " + _backtrace);
}
}
}
#endif
DoDispose();
GC.SuppressFinalize(this);
}
~UnmanagedBlob()
{
#if DEBUG
Console.Error.WriteLine("Undisposed native blob created by " + _backtrace);
#endif
DoDispose();
}
public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address;
public int Size { get; private set; }
public bool IsDisposed { get; private set; }
}
#if NET461 || NETCOREAPP2_0
[DllImport("libc", SetLastError = true)]
private static extern IntPtr mmap(IntPtr addr, IntPtr length, int prot, int flags, int fd, IntPtr offset);
[DllImport("libc", SetLastError = true)]
private static extern int munmap(IntPtr addr, IntPtr length);
[DllImport("libc", SetLastError = true)]
private static extern long sysconf(int name);
private bool? _useMmap;
private bool UseMmap
=> _useMmap ?? ((_useMmap = GetRuntimeInfo().OperatingSystem == OperatingSystemType.Linux)).Value;
IntPtr Alloc(int size)
{
if (UseMmap)
{
var rv = mmap(IntPtr.Zero, new IntPtr(size), 3, 0x22, -1, IntPtr.Zero);
if (rv.ToInt64() == -1 || (ulong) rv.ToInt64() == 0xffffffff)
{
var errno = Marshal.GetLastWin32Error();
throw new Exception("Unable to allocate memory: " + errno);
}
return rv;
}
else
return Marshal.AllocHGlobal(size);
}
void Free(IntPtr ptr, int len)
{
if (UseMmap)
{
if (munmap(ptr, new IntPtr(len)) == -1)
{
var errno = Marshal.GetLastWin32Error();
throw new Exception("Unable to free memory: " + errno);
}
}
else
Marshal.FreeHGlobal(ptr);
}
#else
IntPtr Alloc(int size) => Marshal.AllocHGlobal(size);
void Free(IntPtr ptr, int len) => Marshal.FreeHGlobal(ptr);
#endif
}
internal class IOSLoader : IDynamicLibraryLoader
{
IntPtr IDynamicLibraryLoader.LoadLibrary(string dll)
{
throw new PlatformNotSupportedException();
}
IntPtr IDynamicLibraryLoader.GetProcAddress(IntPtr dll, string proc, bool optional)
{
throw new PlatformNotSupportedException();
}
}
public class AssetLoader : IAssetLoader
{
private const string AvaloniaResourceName = "!AvaloniaResources";
private static readonly Dictionary<string, AssemblyDescriptor> AssemblyNameCache
= new Dictionary<string, AssemblyDescriptor>();
private AssemblyDescriptor _defaultResmAssembly;
/// <summary>
/// Initializes a new instance of the <see cref="AssetLoader"/> class.
/// </summary>
/// <param name="assembly">
/// The default assembly from which to load resm: assets for which no assembly is specified.
/// </param>
public AssetLoader(Assembly assembly = null)
{
if (assembly == null)
assembly = Assembly.GetEntryAssembly();
if (assembly != null)
_defaultResmAssembly = new AssemblyDescriptor(assembly);
}
/// <summary>
/// Sets the default assembly from which to load assets for which no assembly is specified.
/// </summary>
/// <param name="assembly">The default assembly.</param>
public void SetDefaultAssembly(Assembly assembly)
{
_defaultResmAssembly = new AssemblyDescriptor(assembly);
}
/// <summary>
/// Checks if an asset with the specified URI exists.
/// </summary>
/// <param name="uri">The URI.</param>
/// <param name="baseUri">
/// A base URI to use if <paramref name="uri"/> is relative.
/// </param>
/// <returns>True if the asset could be found; otherwise false.</returns>
public bool Exists(Uri uri, Uri baseUri = null)
{
return GetAsset(uri, baseUri) != null;
}
/// <summary>
/// Opens the asset with the requested URI.
/// </summary>
/// <param name="uri">The URI.</param>
/// <param name="baseUri">
/// A base URI to use if <paramref name="uri"/> is relative.
/// </param>
/// <returns>A stream containing the asset contents.</returns>
/// <exception cref="FileNotFoundException">
/// The asset could not be found.
/// </exception>
public Stream Open(Uri uri, Uri baseUri = null) => OpenAndGetAssembly(uri, baseUri).Item1;
/// <summary>
/// Opens the asset with the requested URI and returns the asset stream and the
/// assembly containing the asset.
/// </summary>
/// <param name="uri">The URI.</param>
/// <param name="baseUri">
/// A base URI to use if <paramref name="uri"/> is relative.
/// </param>
/// <returns>
/// The stream containing the resource contents together with the assembly.
/// </returns>
/// <exception cref="FileNotFoundException">
/// The asset could not be found.
/// </exception>
public (Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri baseUri = null)
{
var asset = GetAsset(uri, baseUri);
if (asset == null)
{
throw new FileNotFoundException($"The resource {uri} could not be found.");
}
return (asset.GetStream(), asset.Assembly);
}
public Assembly GetAssembly(Uri uri, Uri baseUri)
{
if (!uri.IsAbsoluteUri && baseUri != null)
uri = new Uri(baseUri, uri);
return GetAssembly(uri).Assembly;
}
/// <summary>
/// Gets all assets of a folder and subfolders that match specified uri.
/// </summary>
/// <param name="uri">The URI.</param>
/// <param name="baseUri">Base URI that is used if <paramref name="uri"/> is relative.</param>
/// <returns>All matching assets as a tuple of the absolute path to the asset and the assembly containing the asset</returns>
public IEnumerable<Uri> GetAssets(Uri uri, Uri baseUri)
{
if (uri.IsAbsoluteUri && uri.Scheme == "resm")
{
var assembly = GetAssembly(uri);
return assembly?.Resources.Where(x => x.Key.Contains(uri.AbsolutePath))
.Select(x =>new Uri($"resm:{x.Key}?assembly={assembly.Name}")) ??
Enumerable.Empty<Uri>();
}
uri = EnsureAbsolute(uri, baseUri);
if (uri.Scheme == "avares")
{
var (asm, path) = GetResAsmAndPath(uri);
if (asm == null)
{
throw new ArgumentException(
"No default assembly, entry assembly or explicit assembly specified; " +
"don't know where to look up for the resource, try specifying assembly explicitly.");
}
if (asm?.AvaloniaResources == null)
return Enumerable.Empty<Uri>();
path = path.TrimEnd('/') + '/';
return asm.AvaloniaResources.Where(r => r.Key.StartsWith(path))
.Select(x => new Uri($"avares://{asm.Name}{x.Key}"));
}
return Enumerable.Empty<Uri>();
}
private Uri EnsureAbsolute(Uri uri, Uri baseUri)
{
if (uri.IsAbsoluteUri)
return uri;
if(baseUri == null)
throw new ArgumentException($"Relative uri {uri} without base url");
if (!baseUri.IsAbsoluteUri)
throw new ArgumentException($"Base uri {baseUri} is relative");
if (baseUri.Scheme == "resm")
throw new ArgumentException(
$"Relative uris for 'resm' scheme aren't supported; {baseUri} uses resm");
return new Uri(baseUri, uri);
}
private IAssetDescriptor GetAsset(Uri uri, Uri baseUri)
{
if (uri.IsAbsoluteUri && uri.Scheme == "resm")
{
var asm = GetAssembly(uri) ?? GetAssembly(baseUri) ?? _defaultResmAssembly;
if (asm == null)
{
throw new ArgumentException(
"No default assembly, entry assembly or explicit assembly specified; " +
"don't know where to look up for the resource, try specifying assembly explicitly.");
}
IAssetDescriptor rv;
var resourceKey = uri.AbsolutePath;
asm.Resources.TryGetValue(resourceKey, out rv);
return rv;
}
uri = EnsureAbsolute(uri, baseUri);
if (uri.Scheme == "avares")
{
var (asm, path) = GetResAsmAndPath(uri);
if (asm.AvaloniaResources == null)
return null;
asm.AvaloniaResources.TryGetValue(path, out var desc);
return desc;
}
throw new ArgumentException($"Unsupported url type: " + uri.Scheme, nameof(uri));
}
private (AssemblyDescriptor asm, string path) GetResAsmAndPath(Uri uri)
{
var asm = GetAssembly(uri.Authority);
return (asm, uri.AbsolutePath);
}
private AssemblyDescriptor GetAssembly(Uri uri)
{
if (uri != null)
{
if (!uri.IsAbsoluteUri)
return null;
if (uri.Scheme == "avares")
return GetResAsmAndPath(uri).asm;
if (uri.Scheme == "resm")
{
var qs = ParseQueryString(uri);
string assemblyName;
if (qs.TryGetValue("assembly", out assemblyName))
{
return GetAssembly(assemblyName);
}
}
}
return null;
}
private AssemblyDescriptor GetAssembly(string name)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
AssemblyDescriptor rv;
if (!AssemblyNameCache.TryGetValue(name, out rv))
{
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
var match = loadedAssemblies.FirstOrDefault(a => a.GetName().Name == name);
if (match != null)
{
AssemblyNameCache[name] = rv = new AssemblyDescriptor(match);
}
else
{
// iOS does not support loading assemblies dynamically!
//
#if __IOS__
throw new InvalidOperationException(
$"Assembly {name} needs to be referenced and explicitly loaded before loading resources");
#else
name = Uri.UnescapeDataString(name);
AssemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(name));
#endif
}
}
return rv;
}
private Dictionary<string, string> ParseQueryString(Uri uri)
{
return uri.Query.TrimStart('?')
.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries)
.Select(p => p.Split('='))
.ToDictionary(p => p[0], p => p[1]);
}
private interface IAssetDescriptor
{
Stream GetStream();
Assembly Assembly { get; }
}
private class AssemblyResourceDescriptor : IAssetDescriptor
{
private readonly Assembly _asm;
private readonly string _name;
public AssemblyResourceDescriptor(Assembly asm, string name)
{
_asm = asm;
_name = name;
}
public Stream GetStream()
{
return _asm.GetManifestResourceStream(_name);
}
public Assembly Assembly => _asm;
}
private class AvaloniaResourceDescriptor : IAssetDescriptor
{
private readonly int _offset;
private readonly int _length;
public Assembly Assembly { get; }
public AvaloniaResourceDescriptor(Assembly asm, int offset, int length)
{
_offset = offset;
_length = length;
Assembly = asm;
}
public Stream GetStream()
{
return new SlicedStream(Assembly.GetManifestResourceStream(AvaloniaResourceName), _offset, _length);
}
}
class SlicedStream : Stream
{
private readonly Stream _baseStream;
private readonly int _from;
public SlicedStream(Stream baseStream, int from, int length)
{
Length = length;
_baseStream = baseStream;
_from = from;
_baseStream.Position = from;
}
public override void Flush()
{
}
public override int Read(byte[] buffer, int offset, int count)
{
return _baseStream.Read(buffer, offset, (int)Math.Min(count, Length - Position));
}
public override long Seek(long offset, SeekOrigin origin)
{
if (origin == SeekOrigin.Begin)
Position = offset;
if (origin == SeekOrigin.End)
Position = _from + Length + offset;
if (origin == SeekOrigin.Current)
Position = Position + offset;
return Position;
}
public override void SetLength(long value) => throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
public override bool CanRead => true;
public override bool CanSeek => _baseStream.CanRead;
public override bool CanWrite => false;
public override long Length { get; }
public override long Position
{
get => _baseStream.Position - _from;
set => _baseStream.Position = value + _from;
}
protected override void Dispose(bool disposing)
{
if (disposing)
_baseStream.Dispose();
}
public override void Close() => _baseStream.Close();
}
private class AssemblyDescriptor
{
public AssemblyDescriptor(Assembly assembly)
{
Assembly = assembly;
if (assembly != null)
{
Resources = assembly.GetManifestResourceNames()
.ToDictionary(n => n, n => (IAssetDescriptor)new AssemblyResourceDescriptor(assembly, n));
Name = assembly.GetName().Name;
using (var resources = assembly.GetManifestResourceStream(AvaloniaResourceName))
{
if (resources != null)
{
Resources.Remove(AvaloniaResourceName);
var indexLength = new BinaryReader(resources).ReadInt32();
var index = AvaloniaResourcesIndexReaderWriter.Read(new SlicedStream(resources, 4, indexLength));
var baseOffset = indexLength + 4;
AvaloniaResources = index.ToDictionary(r => "/" + r.Path.TrimStart('/'), r => (IAssetDescriptor)
new AvaloniaResourceDescriptor(assembly, baseOffset + r.Offset, r.Size));
}
}
}
}
public Assembly Assembly { get; }
public Dictionary<string, IAssetDescriptor> Resources { get; }
public Dictionary<string, IAssetDescriptor> AvaloniaResources { get; }
public string Name { get; }
}
public static void RegisterResUriParsers()
{
if (!UriParser.IsKnownScheme("avares"))
UriParser.Register(new GenericUriParser(
GenericUriParserOptions.GenericAuthority |
GenericUriParserOptions.NoUserInfo |
GenericUriParserOptions.NoPort |
GenericUriParserOptions.NoQuery |
GenericUriParserOptions.NoFragment), "avares", -1);
}
}
}

4
tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs

@ -1,9 +1,7 @@
using System;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Platform;
using Avalonia.Shared.PlatformSupport;
using Avalonia.PlatformSupport;
using Avalonia.Styling;
using Avalonia.UnitTests;
using BenchmarkDotNet.Attributes;

2
tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs

@ -2,7 +2,7 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Shared.PlatformSupport;
using Avalonia.PlatformSupport;
using Avalonia.Styling;
using Avalonia.UnitTests;

2
tests/Avalonia.RenderTests/TestBase.cs

@ -24,7 +24,7 @@ namespace Avalonia.Skia.RenderTests
namespace Avalonia.Direct2D1.RenderTests
#endif
{
using Avalonia.Shared.PlatformSupport;
using Avalonia.PlatformSupport;
public class TestBase
{

2
tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj

@ -13,6 +13,7 @@
<EmbeddedResource Include="..\Avalonia.UnitTests\Assets\*.ttf" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.PlatformSupport\Avalonia.PlatformSupport.csproj" />
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj" />
@ -25,7 +26,6 @@
<ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
</ItemGroup>
<Import Project="..\..\src\Shared\PlatformSupport\PlatformSupport.projitems" Label="Shared" />
<Import Project="..\..\build\Moq.props" />
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\SharedVersion.props" />

16
tests/Avalonia.UnitTests/RuntimeInfo.cs

@ -1,16 +0,0 @@
using Avalonia.Platform;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace Avalonia.Shared.PlatformSupport
{
internal partial class StandardRuntimePlatform : IRuntimePlatform
{
public RuntimePlatformInfo GetRuntimeInfo()
{
return new RuntimePlatformInfo();
}
}
}

2
tests/Avalonia.UnitTests/TestServices.cs

@ -5,7 +5,7 @@ using Avalonia.Layout;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Shared.PlatformSupport;
using Avalonia.PlatformSupport;
using Avalonia.Styling;
using Avalonia.Themes.Default;
using Avalonia.Rendering;

2
tests/Avalonia.UnitTests/UnitTestApplication.cs

@ -10,7 +10,7 @@ using System.Reactive.Disposables;
using System.Reactive.Concurrency;
using Avalonia.Input.Platform;
using Avalonia.Animation;
using Avalonia.Shared.PlatformSupport;
using Avalonia.PlatformSupport;
namespace Avalonia.UnitTests
{

Loading…
Cancel
Save