From 08c711cad661bd8fb6d926b6597a9ab28651dc74 Mon Sep 17 00:00:00 2001 From: lindexi Date: Wed, 31 Jan 2024 14:45:40 +0800 Subject: [PATCH 01/40] Avoid async void in SKXamlCanvas. (#2720) The async void will terminate here. And we can ignore the Dispatcher.RunAsync result and we can receive the exception from TaskScheduler.UnobservedTaskException. See https://github.com/dotnet/runtime/issues/76367 --- .../SkiaSharp.Views.Uno.WinUI.Shared/SKXamlCanvas.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.WinUI.Shared/SKXamlCanvas.cs b/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.WinUI.Shared/SKXamlCanvas.cs index 2697be3009..9fb3626263 100644 --- a/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.WinUI.Shared/SKXamlCanvas.cs +++ b/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.WinUI.Shared/SKXamlCanvas.cs @@ -125,12 +125,12 @@ private void OnUnloaded(object sender, RoutedEventArgs e) display.DpiChanged -= OnDpiChanged; } - public new async void Invalidate() + public new void Invalidate() { if (Dispatcher.HasThreadAccess) DoInvalidate(); else - await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, DoInvalidate); + _ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, DoInvalidate); } partial void DoLoaded(); From 8c296e556d1cd308ce63dc68f8673c2810ecb6e0 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Fri, 2 Feb 2024 08:04:01 -0800 Subject: [PATCH 02/40] Make PlatformConfiguration properties trimmable (#2717) --- .../Binding.Shared/PlatformConfiguration.cs | 64 +++++++++++-------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/binding/Binding.Shared/PlatformConfiguration.cs b/binding/Binding.Shared/PlatformConfiguration.cs index e3c3b8b481..7a1fbdf18f 100644 --- a/binding/Binding.Shared/PlatformConfiguration.cs +++ b/binding/Binding.Shared/PlatformConfiguration.cs @@ -18,42 +18,52 @@ public static class PlatformConfiguration { private const string LibCLibrary = "libc"; - public static bool IsUnix { get; } + public static bool IsUnix => IsMac || IsLinux; - public static bool IsWindows { get; } - - public static bool IsMac { get; } - - public static bool IsLinux { get; } - - public static bool IsArm { get; } - - public static bool Is64Bit { get; } + public static bool IsWindows { +#if WINDOWS_UWP + get => true; +#elif NET6_0_OR_GREATER + get => OperatingSystem.IsWindows (); +#else + get => RuntimeInformation.IsOSPlatform (OSPlatform.Windows); +#endif + } - static PlatformConfiguration () - { + public static bool IsMac { #if WINDOWS_UWP - IsMac = false; - IsLinux = false; - IsUnix = false; - IsWindows = true; - - var arch = Package.Current.Id.Architecture; - const ProcessorArchitecture arm64 = (ProcessorArchitecture)12; - IsArm = arch == ProcessorArchitecture.Arm || arch == arm64; + get => false; +#elif NET6_0_OR_GREATER + get => OperatingSystem.IsMacOS (); #else - IsMac = RuntimeInformation.IsOSPlatform (OSPlatform.OSX); - IsLinux = RuntimeInformation.IsOSPlatform (OSPlatform.Linux); - IsUnix = IsMac || IsLinux; - IsWindows = RuntimeInformation.IsOSPlatform (OSPlatform.Windows); + get => RuntimeInformation.IsOSPlatform (OSPlatform.OSX); +#endif + } - var arch = RuntimeInformation.ProcessArchitecture; - IsArm = arch == Architecture.Arm || arch == Architecture.Arm64; + public static bool IsLinux { +#if WINDOWS_UWP + get => false; +#elif NET6_0_OR_GREATER + get => OperatingSystem.IsLinux (); +#else + get => RuntimeInformation.IsOSPlatform (OSPlatform.Linux); #endif + } - Is64Bit = IntPtr.Size == 8; + public static bool IsArm { +#if WINDOWS_UWP + get { + var arch = Package.Current.Id.Architecture; + const ProcessorArchitecture arm64 = (ProcessorArchitecture)12; + return arch == ProcessorArchitecture.Arm || arch == arm64; + } +#else + get => RuntimeInformation.ProcessArchitecture is Architecture.Arm or Architecture.Arm64; +#endif } + public static bool Is64Bit => IntPtr.Size == 8; + private static string linuxFlavor; public static string LinuxFlavor From 14b451c6dad8121d7d6feb1b0ef6a7f96a531d6d Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Sat, 3 Feb 2024 12:16:53 +0200 Subject: [PATCH 03/40] Pin the Tizen workload (#2736) --- scripts/azure-pipelines-variables.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/azure-pipelines-variables.yml b/scripts/azure-pipelines-variables.yml index 53e405a4af..ed2716e7c4 100644 --- a/scripts/azure-pipelines-variables.yml +++ b/scripts/azure-pipelines-variables.yml @@ -16,7 +16,7 @@ variables: VISUAL_STUDIO_VERSION: '' DOTNET_VERSION_PREVIEW: '' DOTNET_WORKLOAD_SOURCE: '' - DOTNET_WORKLOAD_TIZEN: '' + DOTNET_WORKLOAD_TIZEN: '7.0.123' CONFIGURATION: 'Release' DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true NUGET_DIFF_PRERELEASE: false From 79162b3cc3216a47a5ac175788e80458838cb4d8 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Sat, 3 Feb 2024 12:25:18 +0200 Subject: [PATCH 04/40] Add support for WinUI accelerated views (#2733) Adds the GPU views for WinUI, but there are a few othe things it need to do: - Builds ANGLE as this is the primary interop between SkiaSharp and DirectX - Builds an interop library that extends types needed for interacting with ANGLE - Enables AngleSwapChainPanel as this is the WinUI view that sets up the GL context - Enables the SKSwapChainPanel as this is the SkiaSharp accelerated view - Add a new NativeAssets package for WinUI native files --- ...ncludeNativeAssets.SkiaSharp.WinUI.targets | 19 ++ .../SkiaSharp.NativeAssets.WinUI.csproj | 16 ++ build.cake | 1 + externals/.gitignore | 1 + native/.gitignore | 1 + native/winui/ANGLE.cake | 75 +++++++ .../Directory.Build.props | 5 + .../Directory.Build.targets | 5 + ...Sharp.Views.WinUI.Native.Projection.csproj | 26 +++ .../SkiaSharp.Views.WinUI.Native.sln | 61 ++++++ .../PropertySetExtensions.cpp | 19 ++ .../PropertySetExtensions.h | 24 +++ .../PropertySetExtensions.idl | 8 + .../SkiaSharp.Views.WinUI.Native.vcxproj | 183 ++++++++++++++++++ ...iaSharp.Views.WinUI.Native.vcxproj.filters | 30 +++ .../SkiaSharp_Views_WinUI_Native.def | 3 + .../packages.config | 7 + .../SkiaSharp.Views.WinUI.Native/pch.cpp | 1 + .../SkiaSharp.Views.WinUI.Native/pch.h | 26 +++ .../SkiaSharp.Views.WinUI.Native/readme.txt | 27 +++ native/winui/build.cake | 93 +++++++++ .../SkiaSharpSample/SkiaSharpSample.csproj | 3 +- scripts/VERSIONS.txt | 2 + scripts/azure-templates-stages.yml | 30 +++ scripts/cake/native-shared.cake | 40 ++-- scripts/get-build-type.ps1 | 40 ++-- scripts/vcvarsall.bat | 33 ++++ source/SkiaSharp.Build.targets | 3 + .../AngleSwapChainPanel.cs | 22 ++- .../SkiaSharp.Views.WinUI/GlesInterop/Egl.cs | 4 +- .../GlesInterop/GlesContext.cs | 4 +- .../Interop/PropertySetExtensions.cs | 42 ---- .../SkiaSharp.Views.WinUI/SKSwapChainPanel.cs | 10 +- .../SkiaSharp.Views.WinUI.csproj | 6 + source/SkiaSharpSource.Windows.slnf | 1 + source/SkiaSharpSource.sln | 7 + 36 files changed, 784 insertions(+), 94 deletions(-) create mode 100644 binding/IncludeNativeAssets.SkiaSharp.WinUI.targets create mode 100644 binding/SkiaSharp.NativeAssets.WinUI/SkiaSharp.NativeAssets.WinUI.csproj create mode 100644 native/winui/ANGLE.cake create mode 100644 native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.Projection/Directory.Build.props create mode 100644 native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.Projection/Directory.Build.targets create mode 100644 native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.Projection/SkiaSharp.Views.WinUI.Native.Projection.csproj create mode 100644 native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.sln create mode 100644 native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/PropertySetExtensions.cpp create mode 100644 native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/PropertySetExtensions.h create mode 100644 native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/PropertySetExtensions.idl create mode 100644 native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.vcxproj create mode 100644 native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.vcxproj.filters create mode 100644 native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp_Views_WinUI_Native.def create mode 100644 native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/packages.config create mode 100644 native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/pch.cpp create mode 100644 native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/pch.h create mode 100644 native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/readme.txt create mode 100644 native/winui/build.cake create mode 100644 scripts/vcvarsall.bat delete mode 100644 source/SkiaSharp.Views/SkiaSharp.Views.WinUI/Interop/PropertySetExtensions.cs diff --git a/binding/IncludeNativeAssets.SkiaSharp.WinUI.targets b/binding/IncludeNativeAssets.SkiaSharp.WinUI.targets new file mode 100644 index 0000000000..89e4c652b7 --- /dev/null +++ b/binding/IncludeNativeAssets.SkiaSharp.WinUI.targets @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/binding/SkiaSharp.NativeAssets.WinUI/SkiaSharp.NativeAssets.WinUI.csproj b/binding/SkiaSharp.NativeAssets.WinUI/SkiaSharp.NativeAssets.WinUI.csproj new file mode 100644 index 0000000000..07bac2c33b --- /dev/null +++ b/binding/SkiaSharp.NativeAssets.WinUI/SkiaSharp.NativeAssets.WinUI.csproj @@ -0,0 +1,16 @@ + + + $(WindowsTargetFrameworks) + SkiaSharp + $(PackagingGroup) - Native Assets for Windows UI (WinUI 3) + true + + + + + + + + + + \ No newline at end of file diff --git a/build.cake b/build.cake index 2812886d6d..6d36c029bf 100644 --- a/build.cake +++ b/build.cake @@ -101,6 +101,7 @@ var TRACKED_NUGETS = new Dictionary { { "SkiaSharp.NativeAssets.Tizen", new Version (1, 60, 0) }, { "SkiaSharp.NativeAssets.tvOS", new Version (1, 60, 0) }, { "SkiaSharp.NativeAssets.Win32", new Version (1, 60, 0) }, + { "SkiaSharp.NativeAssets.WinUI", new Version (1, 60, 0) }, { "SkiaSharp.Views", new Version (1, 60, 0) }, { "SkiaSharp.Views.Desktop.Common", new Version (1, 60, 0) }, { "SkiaSharp.Views.Gtk3", new Version (1, 60, 0) }, diff --git a/externals/.gitignore b/externals/.gitignore index df5b644fa9..d83a461853 100644 --- a/externals/.gitignore +++ b/externals/.gitignore @@ -1,3 +1,4 @@ angle/ package_cache/ vcpkg/ +winappsdk/ diff --git a/native/.gitignore b/native/.gitignore index 2a4fe393c9..2f11c1ce72 100644 --- a/native/.gitignore +++ b/native/.gitignore @@ -1,3 +1,4 @@ xcuserdata/ project.xcworkspace/ uwp/ANGLE/triplets +Generated Files/ diff --git a/native/winui/ANGLE.cake b/native/winui/ANGLE.cake new file mode 100644 index 0000000000..88c33903e6 --- /dev/null +++ b/native/winui/ANGLE.cake @@ -0,0 +1,75 @@ +void InitializeAngle(string branch, DirectoryPath ANGLE_PATH, DirectoryPath WINAPPSDK_PATH) +{ + if (!DirectoryExists(ANGLE_PATH)) { + RunProcess("git", $"clone https://github.com/google/angle.git --branch {branch} --depth 1 --single-branch --shallow-submodules {ANGLE_PATH}"); + } + + var submodules = new[] { + "build", + "testing", + "third_party/zlib", + "third_party/jsoncpp", + "third_party/vulkan-deps", + "third_party/astc-encoder/src", + "tools/clang", + }; + foreach (var submodule in submodules) { + var sub = ANGLE_PATH.Combine(submodule); + if (FileExists(sub.CombineWithFilePath("BUILD.gn")) || FileExists(sub.CombineWithFilePath(".gitignore"))) + continue; + + RunProcess("git", new ProcessSettings { + Arguments = $"submodule update --init --recursive {submodule}", + WorkingDirectory = ANGLE_PATH.FullPath, + }); + } + + { + var toolchain = ANGLE_PATH.CombineWithFilePath("build/toolchain/win/toolchain.gni"); + var contents = System.IO.File.ReadAllText(toolchain.FullPath); + var newContents = contents + .Replace("\"${dllname}.lib\"", "\"{{output_dir}}/{{target_output_name}}.lib\"") + .Replace("\"${dllname}.pdb\"", "\"{{output_dir}}/{{target_output_name}}.pdb\""); + if (contents != newContents) + System.IO.File.WriteAllText(toolchain.FullPath, newContents); + } + + if (!FileExists(ANGLE_PATH.CombineWithFilePath("build/config/gclient_args.gni"))) { + var lines = new[] { + "checkout_angle_internal = false", + "checkout_angle_mesa = false", + "checkout_angle_restricted_traces = false", + "generate_location_tags = false" + }; + System.IO.File.WriteAllLines(ANGLE_PATH.CombineWithFilePath("build/config/gclient_args.gni").FullPath, lines); + } + + if (!FileExists(ANGLE_PATH.CombineWithFilePath("build/util/LASTCHANGE"))) { + var lastchange = ANGLE_PATH.CombineWithFilePath("build/util/LASTCHANGE"); + RunPython(ANGLE_PATH, ANGLE_PATH.CombineWithFilePath("build/util/lastchange.py"), $"-o {lastchange}"); + } + + if (!FileExists(ANGLE_PATH.CombineWithFilePath("build/toolchain/win/rc/win/rc.exe"))) { + var oldPath = EnvironmentVariable("PATH"); + try { + System.Environment.SetEnvironmentVariable("PATH", DEPOT_PATH.FullPath + System.IO.Path.PathSeparator + oldPath); + + RunPython(ANGLE_PATH, + DEPOT_PATH.CombineWithFilePath("download_from_google_storage.py"), + $"--no_resume --no_auth --bucket chromium-browser-clang/rc -s build/toolchain/win/rc/win/rc.exe.sha1"); + } finally { + System.Environment.SetEnvironmentVariable("PATH", oldPath); + } + } + + if (!FileExists(ANGLE_PATH.CombineWithFilePath("third_party/llvm-build/Release+Asserts/cr_build_revision"))) { + RunPython(ANGLE_PATH, ANGLE_PATH.CombineWithFilePath("tools/clang/scripts/update.py")); + } + + if (!FileExists(WINAPPSDK_PATH.CombineWithFilePath("Microsoft.WindowsAppSDK.nuspec"))) { + var setup = ANGLE_PATH.CombineWithFilePath("scripts/winappsdk_setup.py"); + RunProcess( + ROOT_PATH.CombineWithFilePath("scripts/vcvarsall.bat"), + $"\"{VS_INSTALL}\" \"x64\" \"{PYTHON_EXE}\" \"{setup}\" --output \"{WINAPPSDK_PATH}\""); + } +} diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.Projection/Directory.Build.props b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.Projection/Directory.Build.props new file mode 100644 index 0000000000..67ea2536c9 --- /dev/null +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.Projection/Directory.Build.props @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.Projection/Directory.Build.targets b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.Projection/Directory.Build.targets new file mode 100644 index 0000000000..3d8b24a04d --- /dev/null +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.Projection/Directory.Build.targets @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.Projection/SkiaSharp.Views.WinUI.Native.Projection.csproj b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.Projection/SkiaSharp.Views.WinUI.Native.Projection.csproj new file mode 100644 index 0000000000..85615cef2f --- /dev/null +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.Projection/SkiaSharp.Views.WinUI.Native.Projection.csproj @@ -0,0 +1,26 @@ + + + + net7.0-windows10.0.19041.0 + 10.0.17763.0 + SkiaSharp.Views.WinUI + SkiaSharp.Views.WinUI + false + enable + enable + + + + None + SkiaSharp.Views.WinUI.Native + + + + + + + + + + + diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.sln b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.sln new file mode 100644 index 0000000000..0435478c90 --- /dev/null +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.sln @@ -0,0 +1,61 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34310.174 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SkiaSharp.Views.WinUI.Native", "SkiaSharp.Views.WinUI.Native\SkiaSharp.Views.WinUI.Native.vcxproj", "{730AF4C9-82D2-4FA7-AA32-154F3524EBD2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Views.WinUI.Native.Projection", "SkiaSharp.Views.WinUI.Native.Projection\SkiaSharp.Views.WinUI.Native.Projection.csproj", "{95E9FEB4-DCD3-4514-8208-A87688788BB2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Debug|Any CPU.ActiveCfg = Debug|x64 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Debug|Any CPU.Build.0 = Debug|x64 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Debug|ARM64.Build.0 = Debug|ARM64 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Debug|x64.ActiveCfg = Debug|x64 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Debug|x64.Build.0 = Debug|x64 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Debug|x86.ActiveCfg = Debug|Win32 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Debug|x86.Build.0 = Debug|Win32 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Release|Any CPU.ActiveCfg = Release|x64 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Release|Any CPU.Build.0 = Release|x64 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Release|ARM64.ActiveCfg = Release|ARM64 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Release|ARM64.Build.0 = Release|ARM64 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Release|x64.ActiveCfg = Release|x64 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Release|x64.Build.0 = Release|x64 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Release|x86.ActiveCfg = Release|Win32 + {730AF4C9-82D2-4FA7-AA32-154F3524EBD2}.Release|x86.Build.0 = Release|Win32 + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Debug|ARM64.Build.0 = Debug|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Debug|x64.ActiveCfg = Debug|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Debug|x64.Build.0 = Debug|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Debug|x86.ActiveCfg = Debug|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Debug|x86.Build.0 = Debug|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Release|Any CPU.Build.0 = Release|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Release|ARM64.ActiveCfg = Release|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Release|ARM64.Build.0 = Release|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Release|x64.ActiveCfg = Release|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Release|x64.Build.0 = Release|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Release|x86.ActiveCfg = Release|Any CPU + {95E9FEB4-DCD3-4514-8208-A87688788BB2}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FB8DA12F-84B5-4D7F-A6E1-7F0A53AA4535} + EndGlobalSection +EndGlobal diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/PropertySetExtensions.cpp b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/PropertySetExtensions.cpp new file mode 100644 index 0000000000..c2174e6cf7 --- /dev/null +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/PropertySetExtensions.cpp @@ -0,0 +1,19 @@ +#include "pch.h" +#include "PropertySetExtensions.h" +#include "PropertySetExtensions.g.cpp" + +using namespace winrt::Windows::Foundation; +using namespace winrt::Windows::Foundation::Collections; + +namespace winrt::SkiaSharp::Views::WinUI::Native::implementation +{ + void PropertySetExtensions::AddSingle(PropertySet const& propertySet, hstring const& key, float value) + { + propertySet.Insert(key, PropertyValue::CreateSingle(value)); + } + + void PropertySetExtensions::AddSize(PropertySet const& propertySet, hstring const& key, Size const& height) + { + propertySet.Insert(key, PropertyValue::CreateSize(height)); + } +} diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/PropertySetExtensions.h b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/PropertySetExtensions.h new file mode 100644 index 0000000000..de60e32b45 --- /dev/null +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/PropertySetExtensions.h @@ -0,0 +1,24 @@ +#pragma once + +#include "PropertySetExtensions.g.h" + +using namespace winrt::Windows::Foundation; +using namespace winrt::Windows::Foundation::Collections; + +namespace winrt::SkiaSharp::Views::WinUI::Native::implementation +{ + struct PropertySetExtensions + { + PropertySetExtensions() = default; + + static void AddSingle(PropertySet const& propertySet, hstring const& key, float value); + static void AddSize(PropertySet const& propertySet, hstring const& key, Size const& value); + }; +} + +namespace winrt::SkiaSharp::Views::WinUI::Native::factory_implementation +{ + struct PropertySetExtensions : PropertySetExtensionsT + { + }; +} diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/PropertySetExtensions.idl b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/PropertySetExtensions.idl new file mode 100644 index 0000000000..278b3c896c --- /dev/null +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/PropertySetExtensions.idl @@ -0,0 +1,8 @@ +namespace SkiaSharp.Views.WinUI.Native +{ + static runtimeclass PropertySetExtensions + { + static void AddSingle(Windows.Foundation.Collections.PropertySet propertySet, String key, Single value); + static void AddSize(Windows.Foundation.Collections.PropertySet propertySet, String key, Windows.Foundation.Size value); + } +} diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.vcxproj b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.vcxproj new file mode 100644 index 0000000000..44c4f7dfda --- /dev/null +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.vcxproj @@ -0,0 +1,183 @@ + + + + + + + true + true + true + {730af4c9-82d2-4fa7-aa32-154f3524ebd2} + SkiaSharp.Views.WinUI.Native + SkiaSharp.Views.WinUI.Native + en-US + 16.0 + false + Windows Store + 10.0 + 10.0.22621.0 + 10.0.17763.0 + true + true + + + + + Debug + Win32 + + + Debug + x64 + + + Debug + ARM64 + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + DynamicLibrary + v143 + Unicode + false + true + + + true + true + + + false + true + false + + + + + + + + + + + + + false + $(ProjectDir)bin\$(Platform)\$(Configuration)\ + $(ProjectDir)obj\$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)bin\$(Platform)\$(Configuration)\ + $(ProjectDir)obj\$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)bin\$(Platform)\$(Configuration)\ + $(ProjectDir)obj\$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)bin\$(Platform)\$(Configuration)\ + $(ProjectDir)obj\$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)bin\$(Platform)\$(Configuration)\ + $(ProjectDir)obj\$(Platform)\$(Configuration)\ + + + false + $(ProjectDir)bin\$(Platform)\$(Configuration)\ + $(ProjectDir)obj\$(Platform)\$(Configuration)\ + + + + Use + pch.h + $(IntDir)pch.pch + Level4 + %(AdditionalOptions) /bigobj + _WINRT_DLL;%(PreprocessorDefinitions) + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + + + Console + true + SkiaSharp_Views_WinUI_Native.def + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + NDEBUG;%(PreprocessorDefinitions) + + + true + true + + + + + + PropertySetExtensions.cpp + + + + + Create + + + + + + + Code + PropertySetExtensions.cpp + + + + + + + + + false + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + \ No newline at end of file diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.vcxproj.filters b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.vcxproj.filters new file mode 100644 index 0000000000..099f47d334 --- /dev/null +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + accd3aa8-1ba0-4223-9bbe-0c431709210b + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms + + + {926ab91d-31b4-48c3-b9a4-e681349f27f0} + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp_Views_WinUI_Native.def b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp_Views_WinUI_Native.def new file mode 100644 index 0000000000..24e7c1235c --- /dev/null +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp_Views_WinUI_Native.def @@ -0,0 +1,3 @@ +EXPORTS +DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE +DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/packages.config b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/packages.config new file mode 100644 index 0000000000..152b1d8ec4 --- /dev/null +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/pch.cpp b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/pch.cpp new file mode 100644 index 0000000000..1d9f38c57d --- /dev/null +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/pch.h b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/pch.h new file mode 100644 index 0000000000..1533d96bb2 --- /dev/null +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/pch.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include +#include +#include + +// Undefine GetCurrentTime macro to prevent +// conflict with Storyboard::GetCurrentTime +#undef GetCurrentTime + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/readme.txt b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/readme.txt new file mode 100644 index 0000000000..fd4c59a522 --- /dev/null +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/readme.txt @@ -0,0 +1,27 @@ +======================================================================== + SkiaSharp.Views.WinUI.Native Project Overview +======================================================================== + +This project demonstrates how to get started authoring Windows Runtime +classes directly with standard C++, using the Windows App SDK and +C++/WinRT packages to generate implementation headers from interface +(IDL) files. The generated Windows Runtime component binary and WinMD +files should then be bundled with the app consuming them. + +Steps: +1. Create an interface (IDL) file to define your Windows Runtime class, + its default interface, and any other interfaces it implements. +2. Build the project once to generate module.g.cpp, module.h.cpp, and + implementation templates under the "Generated Files" folder, as + well as skeleton class definitions under "Generated Files\sources". +3. Use the skeleton class definitions for reference to implement your + Windows Runtime classes. + +======================================================================== +Learn more about Windows App SDK here: +https://docs.microsoft.com/windows/apps/windows-app-sdk/ +Learn more about WinUI3 here: +https://docs.microsoft.com/windows/apps/winui/winui3/ +Learn more about C++/WinRT here: +http://aka.ms/cppwinrt/ +======================================================================== diff --git a/native/winui/build.cake b/native/winui/build.cake new file mode 100644 index 0000000000..7409df544f --- /dev/null +++ b/native/winui/build.cake @@ -0,0 +1,93 @@ +DirectoryPath ROOT_PATH = MakeAbsolute(Directory("../..")); +DirectoryPath OUTPUT_PATH = MakeAbsolute(ROOT_PATH.Combine("output/native/winui")); + +#load "../../scripts/cake/native-shared.cake" +#load "../../scripts/cake/msbuild.cake" + +#load "ANGLE.cake" + +Task("ANGLE") + .IsDependentOn("git-sync-deps") + .WithCriteria(IsRunningOnWindows()) + .Does(() => +{ + var ANGLE_PATH = ROOT_PATH.Combine("externals/angle"); + var WINAPPSDK_PATH = ROOT_PATH.Combine("externals/winappsdk"); + + var branch = GetVersion("ANGLE", "release"); + + InitializeAngle(branch, ANGLE_PATH, WINAPPSDK_PATH); + + Build("x86"); + Build("x64"); + Build("arm64"); + + void Build(string arch) + { + if (Skip(arch)) return; + + try { + System.Environment.SetEnvironmentVariable("DEPOT_TOOLS_WIN_TOOLCHAIN", "0"); + + RunGn(ANGLE_PATH, $"out/winui/{arch}", + $"target_cpu='{arch}' " + + $"is_component_build=false " + + $"is_debug=false " + + $"is_clang=false " + + $"angle_is_winappsdk=true " + + $"winappsdk_dir='{WINAPPSDK_PATH}' " + + $"enable_precompiled_headers=false " + + $"angle_enable_null=false " + + $"angle_enable_wgpu=false " + + $"angle_enable_gl_desktop_backend=false " + + $"angle_enable_vulkan=false"); + + RunNinja(ANGLE_PATH, $"out/winui/{arch}", "libEGL libGLESv2"); + } finally { + System.Environment.SetEnvironmentVariable("DEPOT_TOOLS_WIN_TOOLCHAIN", ""); + } + + var outDir = OUTPUT_PATH.Combine(arch); + EnsureDirectoryExists(outDir); + CopyFileToDirectory(ANGLE_PATH.CombineWithFilePath($"out/winui/{arch}/libEGL.dll"), outDir); + CopyFileToDirectory(ANGLE_PATH.CombineWithFilePath($"out/winui/{arch}/libEGL.pdb"), outDir); + CopyFileToDirectory(ANGLE_PATH.CombineWithFilePath($"out/winui/{arch}/libGLESv2.dll"), outDir); + CopyFileToDirectory(ANGLE_PATH.CombineWithFilePath($"out/winui/{arch}/libGLESv2.pdb"), outDir); + } +}); + +Task("SkiaSharp.Views.WinUI.Native") + .WithCriteria(IsRunningOnWindows()) + .Does(() => +{ + Build("x86", "Win32"); + Build("x64", "x64"); + Build("arm64", "arm64"); + + void Build(string arch, string nativeArch) + { + if (Skip(arch)) return; + + RunProcess("nuget", "restore SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.sln"); + RunMSBuild("SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.sln", arch); + + var name = "SkiaSharp.Views.WinUI.Native"; + + var outDir = OUTPUT_PATH.Combine(arch); + EnsureDirectoryExists(outDir); + CopyFileToDirectory($"{name}/{name}/bin/{nativeArch}/{CONFIGURATION}/{name}.dll", outDir); + CopyFileToDirectory($"{name}/{name}/bin/{nativeArch}/{CONFIGURATION}/{name}.pdb", outDir); + CopyFileToDirectory($"{name}/{name}/bin/{nativeArch}/{CONFIGURATION}/{name}.winmd", outDir); + + var anyOutDir = OUTPUT_PATH.Combine("any"); + EnsureDirectoryExists(anyOutDir); + CopyFileToDirectory($"{name}/{name}.Projection/bin/{CONFIGURATION}/net7.0-windows10.0.19041.0/{name}.Projection.dll", anyOutDir); + CopyFileToDirectory($"{name}/{name}.Projection/bin/{CONFIGURATION}/net7.0-windows10.0.19041.0/{name}.Projection.pdb", anyOutDir); + } +}); + +Task("Default") + .IsDependentOn("ANGLE") + .IsDependentOn("SkiaSharp.Views.WinUI.Native"); + +RunTarget(TARGET); diff --git a/samples/Basic/WinUI/SkiaSharpSample/SkiaSharpSample.csproj b/samples/Basic/WinUI/SkiaSharpSample/SkiaSharpSample.csproj index c46e450c1e..40fc8e00b0 100644 --- a/samples/Basic/WinUI/SkiaSharpSample/SkiaSharpSample.csproj +++ b/samples/Basic/WinUI/SkiaSharpSample/SkiaSharpSample.csproj @@ -12,7 +12,7 @@ - + @@ -32,5 +32,6 @@ + diff --git a/scripts/VERSIONS.txt b/scripts/VERSIONS.txt index a7c9249bfa..234b8e0f5a 100644 --- a/scripts/VERSIONS.txt +++ b/scripts/VERSIONS.txt @@ -17,6 +17,7 @@ Microsoft.WindowsAppSDK release 1.3.230602002 Microsoft.Maui.Graphics release 7.0.92 Microsoft.Windows.SDK.NET.Ref release 10.0.19041.27 Microsoft.AspNetCore.Components.Web release 6.0.0 +ANGLE release chromium/6275 # native milestones # this is related to the API versions, not the library versions @@ -53,6 +54,7 @@ SkiaSharp.NativeAssets.macOS nuget 3.0.0 SkiaSharp.NativeAssets.Tizen nuget 3.0.0 SkiaSharp.NativeAssets.tvOS nuget 3.0.0 SkiaSharp.NativeAssets.Win32 nuget 3.0.0 +SkiaSharp.NativeAssets.WinUI nuget 3.0.0 SkiaSharp.Views nuget 3.0.0 SkiaSharp.Views.Desktop.Common nuget 3.0.0 SkiaSharp.Views.Gtk3 nuget 3.0.0 diff --git a/scripts/azure-templates-stages.yml b/scripts/azure-templates-stages.yml index 3095f48a26..9e36d4430f 100644 --- a/scripts/azure-templates-stages.yml +++ b/scripts/azure-templates-stages.yml @@ -128,6 +128,36 @@ stages: target: externals-windows additionalArgs: --buildarch=arm64 artifactName: native + - template: azure-templates-bootstrapper.yml # Build Native WinUI|x86 (Win) + parameters: + name: native_winui_x86_windows + displayName: WinUI x86 + buildExternals: ${{ parameters.buildExternals }} + buildPipelineType: ${{ parameters.buildPipelineType }} + vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + target: externals-winui + additionalArgs: --buildarch=x86 + artifactName: native + - template: azure-templates-bootstrapper.yml # Build Native WinUI|x64 (Win) + parameters: + name: native_winui_x64_windows + displayName: WinUI x64 + buildExternals: ${{ parameters.buildExternals }} + buildPipelineType: ${{ parameters.buildPipelineType }} + vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + target: externals-winui + additionalArgs: --buildarch=x64 + artifactName: native + - template: azure-templates-bootstrapper.yml # Build Native WinUI|arm64 (Win) + parameters: + name: native_winui_arm64_windows + displayName: WinUI arm64 + buildExternals: ${{ parameters.buildExternals }} + buildPipelineType: ${{ parameters.buildPipelineType }} + vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + target: externals-winui + additionalArgs: --buildarch=arm64 + artifactName: native - template: azure-templates-bootstrapper.yml # Build Native NanoServer|x64 (Win) parameters: name: native_win32_x64_nanoserver_windows diff --git a/scripts/cake/native-shared.cake b/scripts/cake/native-shared.cake index 17ea4f05e6..8c3703e3e5 100644 --- a/scripts/cake/native-shared.cake +++ b/scripts/cake/native-shared.cake @@ -38,23 +38,43 @@ Task("git-sync-deps") if (actualIncrement != expectedIncrement) throw new Exception($"The libSkiaSharp C API version did not match the expected '{expectedIncrement}', instead was '{actualIncrement}'."); - RunProcess(PYTHON_EXE, new ProcessSettings { - Arguments = SKIA_PATH.CombineWithFilePath("tools/git-sync-deps").FullPath, - WorkingDirectory = SKIA_PATH.FullPath, - }); + RunPython(SKIA_PATH, SKIA_PATH.CombineWithFilePath("tools/git-sync-deps")); }); //////////////////////////////////////////////////////////////////////////////////////////////////// // HELPERS //////////////////////////////////////////////////////////////////////////////////////////////////// -void GnNinja(DirectoryPath outDir, string target, string skiaArgs) +void RunPython(DirectoryPath working, FilePath script, string args = "") +{ + RunProcess(PYTHON_EXE, new ProcessSettings { + Arguments = $"{script.FullPath} {args}", + WorkingDirectory = working.FullPath, + }); +} + +void RunGn(DirectoryPath working, DirectoryPath outDir, string args = "") { var isCore = Context.Environment.Runtime.IsCoreClr; var quote = IsRunningOnWindows() || isCore ? "\"" : "'"; var innerQuote = IsRunningOnWindows() || isCore ? "\\\"" : "\""; + RunProcess(GN_EXE, new ProcessSettings { + Arguments = $"gen {outDir} --script-executable={quote}{PYTHON_EXE}{quote} --args={quote}{args.Replace("'", innerQuote)}{quote}", + WorkingDirectory = working.FullPath, + }); +} + +void RunNinja(DirectoryPath working, DirectoryPath outDir, string target = "") +{ + var script = DEPOT_PATH.CombineWithFilePath("ninja.py"); + + RunPython(working, script, $"-C {outDir} {target}"); +} + +void GnNinja(DirectoryPath outDir, string target, string skiaArgs) +{ // override win_vc with the command line args if (!string.IsNullOrEmpty(VS_INSTALL)) { DirectoryPath win_vc = VS_INSTALL; @@ -67,16 +87,10 @@ void GnNinja(DirectoryPath outDir, string target, string skiaArgs) $" is_official_build={CONFIGURATION.ToLower() == "release"} ".ToLower(); // generate native skia build files - RunProcess(GN_EXE, new ProcessSettings { - Arguments = $"gen out/{outDir} --script-executable={quote}{PYTHON_EXE}{quote} --args={quote}{skiaArgs.Replace("'", innerQuote)}{quote}", - WorkingDirectory = SKIA_PATH.FullPath, - }); + RunGn(SKIA_PATH, $"out/{outDir}", skiaArgs); // build native skia - RunProcess(PYTHON_EXE, new ProcessSettings { - Arguments = DEPOT_PATH.CombineWithFilePath("ninja.py").FullPath + $" -C out/{outDir} {target}", - WorkingDirectory = SKIA_PATH.FullPath, - }); + RunNinja(SKIA_PATH, $"out/{outDir}", target); } bool Skip(string arch) diff --git a/scripts/get-build-type.ps1 b/scripts/get-build-type.ps1 index 0274f9008b..ba6ccdbb36 100644 --- a/scripts/get-build-type.ps1 +++ b/scripts/get-build-type.ps1 @@ -23,26 +23,30 @@ if ($intBuildId -gt 0) { if (("$ExternalsBuildId" -eq 'latest') -and ("$env:BUILD_REASON" -eq 'PullRequest')) { Write-Host "All changes:" $all = (git diff-tree --no-commit-id --name-only -r HEAD~ HEAD) - foreach ($d in $all) { - Write-Host " - $d" - } + if ($?) { + foreach ($d in $all) { + Write-Host " - $d" + } - Write-Host "Matching changes:" - $matching = @( - 'externals', - 'native', - 'scripts', - '.gitmodules' - ) - $requiresFull = (git diff-tree --no-commit-id --name-only -r HEAD~ HEAD @matching) - foreach ($d in $requiresFull) { - Write-Host " - $d" - } + Write-Host "Matching changes:" + $matching = @( + 'externals', + 'native', + 'scripts', + '.gitmodules' + ) + $requiresFull = (git diff-tree --no-commit-id --name-only -r HEAD~ HEAD @matching) + if ($?) { + foreach ($d in $requiresFull) { + Write-Host " - $d" + } - if (-not $requiresFull) { - Write-Host "Download-only build." - Write-Host "##vso[task.setvariable variable=DOWNLOAD_EXTERNALS]latest" - exit 0 + if (-not $requiresFull) { + Write-Host "Download-only build." + Write-Host "##vso[task.setvariable variable=DOWNLOAD_EXTERNALS]latest" + exit 0 + } + } } } diff --git a/scripts/vcvarsall.bat b/scripts/vcvarsall.bat new file mode 100644 index 0000000000..52a6e62855 --- /dev/null +++ b/scripts/vcvarsall.bat @@ -0,0 +1,33 @@ +@echo off + +REM Check if all three arguments are provided +if "%~2"=="" ( + echo Usage: %0 ^ ^ ^ + exit /b 1 +) + +set __VSCMD_ARG_NO_LOGO=1 +set VSCMD_START_DIR=%CD% + +REM Run vcvarsall.bat script +call "%~1\VC\Auxiliary\Build\vcvarsall.bat" %~2 +shift +shift + +REM drop the path to the VS install +set "args=" +:getRemainingArgs +if "%~1" neq "" ( + set ^"args=%args% %1" + shift /1 + goto :getRemainingArgs +) + +REM Check if vcvarsall.bat ran successfully +if %errorlevel% neq 0 ( + echo Error: Failed to run vcvarsall.bat + exit /b 1 +) + +REM Run the provided command +%args% diff --git a/source/SkiaSharp.Build.targets b/source/SkiaSharp.Build.targets index 94ccde57bc..b610868313 100644 --- a/source/SkiaSharp.Build.targets +++ b/source/SkiaSharp.Build.targets @@ -149,6 +149,9 @@ internal partial class VersionConstants { <_SignAssemblyAfterTargets> CoreCompile + <_SignAssemblyAfterTargets Condition="'$(CsWinRTIncludes)' != ''"> + CsWinRTReplaceForPatchedRuntime + + { + RenderFrame(); + tcs.SetResult(); + }); + tcs.Task.Wait(); } } } } } - -#endif diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/GlesInterop/Egl.cs b/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/GlesInterop/Egl.cs index ecd7d27168..957a824600 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/GlesInterop/Egl.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/GlesInterop/Egl.cs @@ -6,7 +6,7 @@ using EGLConfig = System.IntPtr; using EGLSurface = System.IntPtr; using EGLNativeDisplayType = System.IntPtr; -using EGLNativeWindowType = System.Object; +using EGLNativeWindowType = System.IntPtr; using glbool = System.Int32; namespace SkiaSharp.Views.GlesInterop @@ -94,7 +94,7 @@ internal static class Egl [DllImport(libEGL)] public static extern EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list); [DllImport(libEGL)] - public static extern EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, [MarshalAs(UnmanagedType.IInspectable)] EGLNativeWindowType win, int[] attrib_list); + public static extern EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, int[] attrib_list); [DllImport(libEGL)] public static extern glbool eglQuerySurface(EGLDisplay dpy, EGLSurface surface, int attribute, out int value); [DllImport(libEGL)] diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/GlesInterop/GlesContext.cs b/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/GlesInterop/GlesContext.cs index 8acfaa520e..6d39bfebc3 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/GlesInterop/GlesContext.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/GlesInterop/GlesContext.cs @@ -19,6 +19,8 @@ using EGLContext = System.IntPtr; using EGLConfig = System.IntPtr; using EGLSurface = System.IntPtr; +using SkiaSharp.Views.WinUI.Native; +using WinRT; namespace SkiaSharp.Views.GlesInterop { @@ -102,7 +104,7 @@ public void CreateSurface(SwapChainPanel panel, Size? renderSurfaceSize, float? PropertySetExtensions.AddSingle(surfaceCreationProperties, Egl.EGLRenderResolutionScaleProperty, resolutionScale.Value); } - surface = Egl.eglCreateWindowSurface(eglDisplay, eglConfig, surfaceCreationProperties, surfaceAttributes); + surface = Egl.eglCreateWindowSurface(eglDisplay, eglConfig, surfaceCreationProperties.As().ThisPtr, surfaceAttributes); if (surface == Egl.EGL_NO_SURFACE) { throw new Exception("Failed to create EGL surface"); diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/Interop/PropertySetExtensions.cs b/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/Interop/PropertySetExtensions.cs deleted file mode 100644 index 6b4ef50030..0000000000 --- a/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/Interop/PropertySetExtensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Runtime.InteropServices; -using Windows.Foundation; -using Windows.Foundation.Collections; - -#if WINDOWS -namespace SkiaSharp.Views.Windows -#else -namespace SkiaSharp.Views.UWP -#endif -{ - internal static class PropertySetExtensions - { - private const string libInterop = "SkiaSharp.Views.Interop.UWP.dll"; - - public static void AddSingle(this PropertySet properties, string key, float value) - { - PropertySet_AddSingle(properties, key, value); - } - - public static void AddSize(this PropertySet properties, string key, Size size) - { - PropertySet_AddSize(properties, key, (float)size.Width, (float)size.Height); - } - - public static void AddSize(this PropertySet properties, string key, float width, float height) - { - PropertySet_AddSize(properties, key, width, height); - } - - [DllImport(libInterop)] - private static extern void PropertySet_AddSingle( - [MarshalAs(UnmanagedType.IInspectable)] object properties, - [MarshalAs(UnmanagedType.HString)] string key, - float value); - - [DllImport(libInterop)] - private static extern void PropertySet_AddSize( - [MarshalAs(UnmanagedType.IInspectable)] object properties, - [MarshalAs(UnmanagedType.HString)] string key, - float width, float height); - } -} diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/SKSwapChainPanel.cs b/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/SKSwapChainPanel.cs index d82f07fd3c..ce872b5db0 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/SKSwapChainPanel.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/SKSwapChainPanel.cs @@ -1,6 +1,4 @@ -#if !WINDOWS - -using System; +using System; using SkiaSharp.Views.GlesInterop; using Windows.Foundation; @@ -91,9 +89,7 @@ protected override void OnRenderFrame(Rect rect) using (new SKAutoCanvasRestore(canvas, true)) { // start drawing -#pragma warning disable CS0612 // Type or member is obsolete - OnPaintSurface(new SKPaintGLSurfaceEventArgs(surface, renderTarget, surfaceOrigin, colorType, glInfo)); -#pragma warning restore CS0612 // Type or member is obsolete + OnPaintSurface(new SKPaintGLSurfaceEventArgs(surface, renderTarget, surfaceOrigin, colorType)); } // update the control @@ -127,5 +123,3 @@ protected override void OnDestroyingContext() } } } - -#endif diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/SkiaSharp.Views.WinUI.csproj b/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/SkiaSharp.Views.WinUI.csproj index 76514d596b..61d49d9946 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/SkiaSharp.Views.WinUI.csproj +++ b/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/SkiaSharp.Views.WinUI.csproj @@ -20,6 +20,12 @@ + + + + + + diff --git a/source/SkiaSharpSource.Windows.slnf b/source/SkiaSharpSource.Windows.slnf index 3fc282a63b..b90c7f0fcf 100644 --- a/source/SkiaSharpSource.Windows.slnf +++ b/source/SkiaSharpSource.Windows.slnf @@ -20,6 +20,7 @@ "..\\binding\\SkiaSharp.NativeAssets.Tizen\\SkiaSharp.NativeAssets.Tizen.csproj", "..\\binding\\SkiaSharp.NativeAssets.WebAssembly\\SkiaSharp.NativeAssets.WebAssembly.csproj", "..\\binding\\SkiaSharp.NativeAssets.Win32\\SkiaSharp.NativeAssets.Win32.csproj", + "..\\binding\\SkiaSharp.NativeAssets.WinUI\\SkiaSharp.NativeAssets.WinUI.csproj", "..\\binding\\SkiaSharp.NativeAssets.iOS\\SkiaSharp.NativeAssets.iOS.csproj", "..\\binding\\SkiaSharp.NativeAssets.macOS\\SkiaSharp.NativeAssets.macOS.csproj", "..\\binding\\SkiaSharp.NativeAssets.tvOS\\SkiaSharp.NativeAssets.tvOS.csproj", diff --git a/source/SkiaSharpSource.sln b/source/SkiaSharpSource.sln index 0586d94f8f..20380709a4 100644 --- a/source/SkiaSharpSource.sln +++ b/source/SkiaSharpSource.sln @@ -85,6 +85,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.NativeAssets.WebA EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.NativeAssets.Win32", "..\binding\SkiaSharp.NativeAssets.Win32\SkiaSharp.NativeAssets.Win32.csproj", "{3D2711DC-EAD2-4EE8-8A4D-950A4FC9CC5C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.NativeAssets.WinUI", "..\binding\SkiaSharp.NativeAssets.WinUI\SkiaSharp.NativeAssets.WinUI.csproj", "{3D2711DC-EAD2-4EE8-8A4D-83FB64897435}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HarfBuzzSharp.NativeAssets.Android", "..\binding\HarfBuzzSharp.NativeAssets.Android\HarfBuzzSharp.NativeAssets.Android.csproj", "{BAF3A8BA-AC8A-4D28-811B-6A60F818E75B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HarfBuzzSharp.NativeAssets.iOS", "..\binding\HarfBuzzSharp.NativeAssets.iOS\HarfBuzzSharp.NativeAssets.iOS.csproj", "{8C8F8386-9359-42F9-A5F5-83FB64897435}" @@ -233,6 +235,10 @@ Global {3D2711DC-EAD2-4EE8-8A4D-950A4FC9CC5C}.Debug|Any CPU.Build.0 = Debug|Any CPU {3D2711DC-EAD2-4EE8-8A4D-950A4FC9CC5C}.Release|Any CPU.ActiveCfg = Release|Any CPU {3D2711DC-EAD2-4EE8-8A4D-950A4FC9CC5C}.Release|Any CPU.Build.0 = Release|Any CPU + {3D2711DC-EAD2-4EE8-8A4D-83FB64897435}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D2711DC-EAD2-4EE8-8A4D-83FB64897435}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D2711DC-EAD2-4EE8-8A4D-83FB64897435}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D2711DC-EAD2-4EE8-8A4D-83FB64897435}.Release|Any CPU.Build.0 = Release|Any CPU {BAF3A8BA-AC8A-4D28-811B-6A60F818E75B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BAF3A8BA-AC8A-4D28-811B-6A60F818E75B}.Debug|Any CPU.Build.0 = Debug|Any CPU {BAF3A8BA-AC8A-4D28-811B-6A60F818E75B}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -315,6 +321,7 @@ Global {4A0AF7AC-E18D-41A9-801D-F2BA659B20EB} = {C335869B-7CC8-4239-B4A5-8031AA9758D3} {694D48BE-B381-45A3-BF94-4E3D439145D8} = {C335869B-7CC8-4239-B4A5-8031AA9758D3} {3D2711DC-EAD2-4EE8-8A4D-950A4FC9CC5C} = {C335869B-7CC8-4239-B4A5-8031AA9758D3} + {3D2711DC-EAD2-4EE8-8A4D-83FB64897435} = {C335869B-7CC8-4239-B4A5-8031AA9758D3} {BAF3A8BA-AC8A-4D28-811B-6A60F818E75B} = {2F28C1EB-D020-4A3A-948F-DF0AD0FDCC53} {8C8F8386-9359-42F9-A5F5-83FB64897435} = {2F28C1EB-D020-4A3A-948F-DF0AD0FDCC53} {59D12575-1395-4D08-BA5B-73A614F2AF6B} = {2F28C1EB-D020-4A3A-948F-DF0AD0FDCC53} From 81edb6a62f1700ad68259b1a277dd655ea58aa4d Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Sat, 3 Feb 2024 19:31:33 +0200 Subject: [PATCH 05/40] Split the packaging job (#2737) Some smaller agents run out of storage with all the symbols. --- scripts/azure-templates-stages.yml | 41 ++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/scripts/azure-templates-stages.yml b/scripts/azure-templates-stages.yml index 9e36d4430f..6f985c0f37 100644 --- a/scripts/azure-templates-stages.yml +++ b/scripts/azure-templates-stages.yml @@ -422,11 +422,11 @@ stages: jobs: - template: azure-templates-bootstrapper.yml # Package NuGets parameters: - name: package_windows + name: package_normal_windows displayName: Package NuGets buildPipelineType: ${{ parameters.buildPipelineType }} vmImage: ${{ parameters.VM_IMAGE_WINDOWS}} - target: nuget + target: nuget-normal additionalArgs: --skipExternals="all" requiredArtifacts: - name: native @@ -437,22 +437,42 @@ stages: artifactName: nuget pathToPublish: 'output/nugets' - task: PublishBuildArtifacts@1 - displayName: Publish the special nuget artifacts + displayName: Publish the SignList.xml into nuget artifacts inputs: - artifactName: nuget_special - pathToPublish: 'output/nugets-special' + artifactName: nuget + pathToPublish: 'scripts\SignList.xml' - task: PublishBuildArtifacts@1 - displayName: Publish the special nuget artifacts + displayName: Publish the symbols nuget artifacts inputs: artifactName: nuget_symbols pathToPublish: 'output/nugets-symbols' + - pwsh: | + Remove-Item ./output/native/ -Recurse -Force + Remove-Item ./output/nugets/ -Recurse -Force + Remove-Item ./output/nugets-symbols/ -Recurse -Force + displayName: Delete the pre-published folders + - template: azure-templates-bootstrapper.yml # Package Special NuGets + parameters: + name: package_special_windows + displayName: Package Special NuGets + buildPipelineType: ${{ parameters.buildPipelineType }} + vmImage: ${{ parameters.VM_IMAGE_WINDOWS}} + dependsOn: + - package_normal_windows + target: nuget-special + additionalArgs: --skipExternals="all" --exclusive + requiredArtifacts: + - name: nuget + dir: nugets + - name: nuget_symbols + dir: nugets-symbols + postBuildSteps: - task: PublishBuildArtifacts@1 - displayName: Publish the SignList.xml into nuget artifacts + displayName: Publish the special nuget artifacts inputs: - artifactName: nuget - pathToPublish: 'scripts\SignList.xml' + artifactName: nuget_special + pathToPublish: 'output/nugets-special' - pwsh: | - Remove-Item ./output/native/ -Recurse -Force Remove-Item ./output/nugets/ -Recurse -Force Remove-Item ./output/nugets-special/ -Recurse -Force Remove-Item ./output/nugets-symbols/ -Recurse -Force @@ -476,7 +496,6 @@ stages: additionalArgs: --nugetDiffPrerelease=$(NUGET_DIFF_PRERELEASE) shouldPublish: false requiredArtifacts: - - name: package_windows - name: nuget dir: nugets preBuildSteps: From 04ff977ac09c2cd8d1e31e526cfce755d90f60f3 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Sun, 4 Feb 2024 13:32:21 +0200 Subject: [PATCH 06/40] Implemented SKGLView (#2598) - Mac Catalyst does not support OpenGL and will need a new Metal-based view - Tizen needs the support in the native view --- .../SkiaSharpSample/SkiaSharpSample.csproj | 1 + .../AppHostBuilderExtensions.cs | 1 + .../SKCanvasView.HandlerImpl.cs | 38 --- .../SKCanvasView.cs | 81 ++----- .../SkiaSharp.Views.Maui.Controls/SKGLView.cs | 108 +++------ .../SKImageSource.HandlerImpl.cs | 20 -- .../SKImageSource.cs | 8 +- .../SKCanvasViewHandler.Android.cs | 7 +- ...er.iOS.cs => SKCanvasViewHandler.Apple.cs} | 7 +- .../SKCanvasView/SKCanvasViewHandler.Tizen.cs | 7 +- .../SKCanvasViewHandler.Windows.cs | 5 +- .../SKCanvasView/SKCanvasViewHandler.cs | 2 +- .../SKGLView/SKGLViewHandler.Android.cs | 136 +++++++++++ .../SKGLView/SKGLViewHandler.MacCatalyst.cs | 19 ++ .../Handlers/SKGLView/SKGLViewHandler.Ref.cs | 18 ++ .../SKGLView/SKGLViewHandler.Tizen.cs | 21 ++ .../SKGLView/SKGLViewHandler.Windows.cs | 129 +++++++++++ .../Handlers/SKGLView/SKGLViewHandler.cs | 35 +++ .../Handlers/SKGLView/SKGLViewHandler.iOS.cs | 219 ++++++++++++++++++ ...e.iOS.cs => SKImageSourceService.Apple.cs} | 0 .../SkiaSharp.Views.Maui.Core/ISKGLView.cs | 27 +++ .../Android/SKCanvasViewExtensions.cs | 10 - .../Platform/{iOS => Apple}/SKTouchHandler.cs | 0 .../Platform/Tizen/SKCanvasViewExtensions.cs | 10 - .../Windows/SKCanvasViewExtensions.cs | 10 - .../Platform/iOS/SKCanvasViewExtensions.cs | 10 - .../SKPaintGLSurfaceEventArgs.cs | 21 ++ .../SkiaSharp.Views.Maui.Core.csproj | 12 + .../SkiaSharp.Views/Platform/iOS/SKGLLayer.cs | 7 + .../SkiaSharp.Views/Platform/iOS/SKGLView.cs | 7 + 30 files changed, 710 insertions(+), 266 deletions(-) delete mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.HandlerImpl.cs delete mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.HandlerImpl.cs rename source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/{SKCanvasViewHandler.iOS.cs => SKCanvasViewHandler.Apple.cs} (92%) create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Android.cs create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Ref.cs create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Tizen.cs create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Windows.cs create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.cs create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.iOS.cs rename source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKImageSourceService/{SKImageSourceService.iOS.cs => SKImageSourceService.Apple.cs} (100%) create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/ISKGLView.cs delete mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Android/SKCanvasViewExtensions.cs rename source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/{iOS => Apple}/SKTouchHandler.cs (100%) delete mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Tizen/SKCanvasViewExtensions.cs delete mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Windows/SKCanvasViewExtensions.cs delete mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/iOS/SKCanvasViewExtensions.cs diff --git a/samples/Basic/Maui/SkiaSharpSample/SkiaSharpSample.csproj b/samples/Basic/Maui/SkiaSharpSample/SkiaSharpSample.csproj index 1fea779096..9b5b1c5498 100644 --- a/samples/Basic/Maui/SkiaSharpSample/SkiaSharpSample.csproj +++ b/samples/Basic/Maui/SkiaSharpSample/SkiaSharpSample.csproj @@ -37,5 +37,6 @@ + diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/AppHostBuilderExtensions.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/AppHostBuilderExtensions.cs index 9fb132aba5..cc28dcf9e6 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/AppHostBuilderExtensions.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/AppHostBuilderExtensions.cs @@ -13,6 +13,7 @@ public static MauiAppBuilder UseSkiaSharp(this MauiAppBuilder builder) => .ConfigureMauiHandlers(handlers => { handlers.AddHandler(); + handlers.AddHandler(); }) .ConfigureImageSources(sources => { diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.HandlerImpl.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.HandlerImpl.cs deleted file mode 100644 index e1c4b27bde..0000000000 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.HandlerImpl.cs +++ /dev/null @@ -1,38 +0,0 @@ -#nullable enable - -using System; - -namespace SkiaSharp.Views.Maui.Controls -{ - public partial class SKCanvasView : ISKCanvasView - { - private SKSizeI lastCanvasSize; - - public SKCanvasView() - { - var controller = (ISKCanvasViewController)this; - - controller.GetCanvasSize += OnGetCanvasSize; - controller.SurfaceInvalidated += OnSurfaceInvalidated; - - void OnGetCanvasSize(object? sender, GetPropertyValueEventArgs e) - { - e.Value = lastCanvasSize; - } - - void OnSurfaceInvalidated(object? sender, EventArgs e) - { - Handler?.Invoke(nameof(ISKCanvasView.InvalidateSurface)); - } - } - - void ISKCanvasView.OnCanvasSizeChanged(SKSizeI size) => - lastCanvasSize = size; - - void ISKCanvasView.OnPaintSurface(SKPaintSurfaceEventArgs e) => - OnPaintSurface(e); - - void ISKCanvasView.OnTouch(SKTouchEventArgs e) => - OnTouch(e); - } -} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.cs index e1b21e1082..9f4cb6172a 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.cs @@ -8,7 +8,7 @@ namespace SkiaSharp.Views.Maui.Controls { - public partial class SKCanvasView : View, ISKCanvasViewController + public partial class SKCanvasView : View, ISKCanvasView { public static readonly BindableProperty IgnorePixelScalingProperty = BindableProperty.Create(nameof(IgnorePixelScaling), typeof(bool), typeof(SKCanvasView), false); @@ -16,99 +16,52 @@ public partial class SKCanvasView : View, ISKCanvasViewController public static readonly BindableProperty EnableTouchEventsProperty = BindableProperty.Create(nameof(EnableTouchEvents), typeof(bool), typeof(SKCanvasView), false); - // the user can subscribe to repaint + private SKSizeI lastCanvasSize; + + public SKCanvasView() + { + } + public event EventHandler? PaintSurface; - // the user can subscribe to touch events public event EventHandler? Touch; - // the native listens to this event - private event EventHandler? SurfaceInvalidated; - private event EventHandler>? GetCanvasSize; - - // the user asks the for the size - public SKSize CanvasSize - { - get - { - // send a mesage to the native view - var args = new GetPropertyValueEventArgs(); - GetCanvasSize?.Invoke(this, args); - return args.Value; - } - } + public SKSize CanvasSize => lastCanvasSize; public bool IgnorePixelScaling { - get { return (bool)GetValue(IgnorePixelScalingProperty); } - set { SetValue(IgnorePixelScalingProperty, value); } + get => (bool)GetValue(IgnorePixelScalingProperty); + set => SetValue(IgnorePixelScalingProperty, value); } public bool EnableTouchEvents { - get { return (bool)GetValue(EnableTouchEventsProperty); } - set { SetValue(EnableTouchEventsProperty, value); } + get => (bool)GetValue(EnableTouchEventsProperty); + set => SetValue(EnableTouchEventsProperty, value); } - // the user asks to repaint public void InvalidateSurface() { - // send a mesage to the native view - SurfaceInvalidated?.Invoke(this, EventArgs.Empty); + Handler?.Invoke(nameof(ISKCanvasView.InvalidateSurface)); } - // the native view tells the user to repaint protected virtual void OnPaintSurface(SKPaintSurfaceEventArgs e) { PaintSurface?.Invoke(this, e); } - // the native view responds to a touch protected virtual void OnTouch(SKTouchEventArgs e) { Touch?.Invoke(this, e); } - // ISKViewController implementation - - event EventHandler ISKCanvasViewController.SurfaceInvalidated - { - add { SurfaceInvalidated += value; } - remove { SurfaceInvalidated -= value; } - } - - event EventHandler> ISKCanvasViewController.GetCanvasSize - { - add { GetCanvasSize += value; } - remove { GetCanvasSize -= value; } - } + void ISKCanvasView.OnCanvasSizeChanged(SKSizeI size) => + lastCanvasSize = size; - void ISKCanvasViewController.OnPaintSurface(SKPaintSurfaceEventArgs e) - { + void ISKCanvasView.OnPaintSurface(SKPaintSurfaceEventArgs e) => OnPaintSurface(e); - } - void ISKCanvasViewController.OnTouch(SKTouchEventArgs e) - { + void ISKCanvasView.OnTouch(SKTouchEventArgs e) => OnTouch(e); - } - - protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint) - { - return new SizeRequest(new Size(40.0, 40.0)); - } - } - - public interface ISKCanvasViewController : IViewController - { - // the native listens to this event - event EventHandler SurfaceInvalidated; - event EventHandler> GetCanvasSize; - - // the native view tells the user to repaint - void OnPaintSurface(SKPaintSurfaceEventArgs e); - - // the native view responds to a touch - void OnTouch(SKTouchEventArgs e); } } diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKGLView.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKGLView.cs index 519cbfc92d..373f1a6ed2 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKGLView.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKGLView.cs @@ -8,127 +8,71 @@ namespace SkiaSharp.Views.Maui.Controls { - public partial class SKGLView : View, ISKGLViewController + public partial class SKGLView : View, ISKGLView { + public static readonly BindableProperty IgnorePixelScalingProperty = + BindableProperty.Create(nameof(IgnorePixelScaling), typeof(bool), typeof(SKGLView), false); + public static readonly BindableProperty HasRenderLoopProperty = BindableProperty.Create(nameof(HasRenderLoop), typeof(bool), typeof(SKGLView), false); public static readonly BindableProperty EnableTouchEventsProperty = BindableProperty.Create(nameof(EnableTouchEvents), typeof(bool), typeof(SKGLView), false); + private SKSizeI lastCanvasSize; + private GRContext? lastGRContext; + + public bool IgnorePixelScaling + { + get => (bool)GetValue(IgnorePixelScalingProperty); + set => SetValue(IgnorePixelScalingProperty, value); + } + public bool HasRenderLoop { - get { return (bool)GetValue(HasRenderLoopProperty); } - set { SetValue(HasRenderLoopProperty, value); } + get => (bool)GetValue(HasRenderLoopProperty); + set => SetValue(HasRenderLoopProperty, value); } public bool EnableTouchEvents { - get { return (bool)GetValue(EnableTouchEventsProperty); } - set { SetValue(EnableTouchEventsProperty, value); } + get => (bool)GetValue(EnableTouchEventsProperty); + set => SetValue(EnableTouchEventsProperty, value); } - // the user can subscribe to repaint public event EventHandler? PaintSurface; - // the user can subscribe to touch events public event EventHandler? Touch; - // the native listens to this event - private event EventHandler? SurfaceInvalidated; - private event EventHandler>? GetCanvasSize; - private event EventHandler>? GetGRContext; + public SKSize CanvasSize => lastCanvasSize; - // the user asks the for the size - public SKSize CanvasSize - { - get - { - // send a mesage to the native view - var args = new GetPropertyValueEventArgs(); - GetCanvasSize?.Invoke(this, args); - return args.Value; - } - } + public GRContext? GRContext => lastGRContext; - // the user asks the for the current GRContext - public GRContext GRContext - { - get - { - // send a mesage to the native view - var args = new GetPropertyValueEventArgs(); - GetGRContext?.Invoke(this, args); - return args.Value; - } - } - - // the user asks to repaint public void InvalidateSurface() { - // send a mesage to the native view - SurfaceInvalidated?.Invoke(this, EventArgs.Empty); + Handler?.Invoke(nameof(ISKGLView.InvalidateSurface)); } - // the native view tells the user to repaint protected virtual void OnPaintSurface(SKPaintGLSurfaceEventArgs e) { PaintSurface?.Invoke(this, e); } - // the native view responds to a touch protected virtual void OnTouch(SKTouchEventArgs e) { Touch?.Invoke(this, e); } - // ISKViewController implementation - - event EventHandler ISKGLViewController.SurfaceInvalidated - { - add { SurfaceInvalidated += value; } - remove { SurfaceInvalidated -= value; } - } - - event EventHandler> ISKGLViewController.GetCanvasSize - { - add { GetCanvasSize += value; } - remove { GetCanvasSize -= value; } - } + void ISKGLView.OnCanvasSizeChanged(SKSizeI size) => + lastCanvasSize = size; - event EventHandler> ISKGLViewController.GetGRContext - { - add { GetGRContext += value; } - remove { GetGRContext -= value; } - } + void ISKGLView.OnGRContextChanged(GRContext? context) => + lastGRContext = context; - void ISKGLViewController.OnPaintSurface(SKPaintGLSurfaceEventArgs e) - { + void ISKGLView.OnPaintSurface(SKPaintGLSurfaceEventArgs e) => OnPaintSurface(e); - } - void ISKGLViewController.OnTouch(SKTouchEventArgs e) - { + void ISKGLView.OnTouch(SKTouchEventArgs e) => OnTouch(e); - } - - protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint) - { - return new SizeRequest(new Size(40.0, 40.0)); - } - } - - public interface ISKGLViewController : IViewController - { - // the native listens to this event - event EventHandler SurfaceInvalidated; - event EventHandler> GetCanvasSize; - event EventHandler> GetGRContext; - - // the native view tells the user to repaint - void OnPaintSurface(SKPaintGLSurfaceEventArgs e); - - // the native view responds to a touch - void OnTouch(SKTouchEventArgs e); } } diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.HandlerImpl.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.HandlerImpl.cs deleted file mode 100644 index 695fa33f77..0000000000 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.HandlerImpl.cs +++ /dev/null @@ -1,20 +0,0 @@ -#nullable enable - -namespace SkiaSharp.Views.Maui.Controls -{ - partial class SKImageImageSource : ISKImageImageSource - { - } - - partial class SKBitmapImageSource : ISKBitmapImageSource - { - } - - partial class SKPixmapImageSource : ISKPixmapImageSource - { - } - - partial class SKPictureImageSource : ISKPictureImageSource - { - } -} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.cs index 86bcb3e2fb..aa0ad8b876 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.cs @@ -5,7 +5,7 @@ namespace SkiaSharp.Views.Maui.Controls { - public sealed partial class SKImageImageSource : ImageSource + public sealed partial class SKImageImageSource : ImageSource, ISKImageImageSource { public static readonly BindableProperty ImageProperty = BindableProperty.Create(nameof(Image), typeof(SKImage), typeof(SKImageImageSource), default(SKImage)); @@ -41,7 +41,7 @@ protected override void OnPropertyChanged(string propertyName = null) } } - public sealed partial class SKBitmapImageSource : ImageSource + public sealed partial class SKBitmapImageSource : ImageSource, ISKBitmapImageSource { public static readonly BindableProperty BitmapProperty = BindableProperty.Create(nameof(Bitmap), typeof(SKBitmap), typeof(SKBitmapImageSource), default(SKBitmap)); @@ -77,7 +77,7 @@ protected override void OnPropertyChanged(string propertyName = null) } } - public sealed partial class SKPixmapImageSource : ImageSource + public sealed partial class SKPixmapImageSource : ImageSource, ISKPixmapImageSource { public static readonly BindableProperty PixmapProperty = BindableProperty.Create(nameof(Pixmap), typeof(SKPixmap), typeof(SKPixmapImageSource), default(SKPixmap)); @@ -113,7 +113,7 @@ protected override void OnPropertyChanged(string propertyName = null) } } - public sealed partial class SKPictureImageSource : ImageSource + public sealed partial class SKPictureImageSource : ImageSource, ISKPictureImageSource { public static readonly BindableProperty PictureProperty = BindableProperty.Create(nameof(Picture), typeof(SKPicture), typeof(SKPictureImageSource), default(SKPicture)); diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Android.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Android.cs index 82bf3bd614..d9d67f8fa6 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Android.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Android.cs @@ -34,19 +34,16 @@ protected override void DisconnectHandler(SKCanvasView platformView) public static void OnInvalidateSurface(SKCanvasViewHandler handler, ISKCanvasView canvasView, object? args) { - handler.PlatformView?.Invalidate(); + handler.PlatformView.Invalidate(); } public static void MapIgnorePixelScaling(SKCanvasViewHandler handler, ISKCanvasView canvasView) { - handler.PlatformView?.UpdateIgnorePixelScaling(canvasView); + handler.PlatformView.IgnorePixelScaling = canvasView.IgnorePixelScaling; } public static void MapEnableTouchEvents(SKCanvasViewHandler handler, ISKCanvasView canvasView) { - if (handler.PlatformView == null) - return; - handler.touchHandler ??= new SKTouchHandler( args => canvasView.OnTouch(args), (x, y) => handler.OnGetScaledCoord(x, y)); diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.iOS.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Apple.cs similarity index 92% rename from source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.iOS.cs rename to source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Apple.cs index 33c3025314..a40ac0b1a2 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.iOS.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Apple.cs @@ -33,19 +33,16 @@ protected override void DisconnectHandler(SKCanvasView platformView) public static void OnInvalidateSurface(SKCanvasViewHandler handler, ISKCanvasView canvasView, object? args) { - handler.PlatformView?.SetNeedsDisplay(); + handler.PlatformView.SetNeedsDisplay(); } public static void MapIgnorePixelScaling(SKCanvasViewHandler handler, ISKCanvasView canvasView) { - handler.PlatformView?.UpdateIgnorePixelScaling(canvasView); + handler.PlatformView.IgnorePixelScaling = canvasView.IgnorePixelScaling; } public static void MapEnableTouchEvents(SKCanvasViewHandler handler, ISKCanvasView canvasView) { - if (handler.PlatformView == null) - return; - handler.touchHandler ??= new SKTouchHandler( args => canvasView.OnTouch(args), (x, y) => handler.OnGetScaledCoord(x, y)); diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Tizen.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Tizen.cs index 08cd85f944..ad5bd55ce1 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Tizen.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Tizen.cs @@ -33,19 +33,16 @@ protected override void DisconnectHandler(SKCanvasView platformView) public static void OnInvalidateSurface(SKCanvasViewHandler handler, ISKCanvasView canvasView, object? args) { - handler.PlatformView?.Invalidate(); + handler.PlatformView.Invalidate(); } public static void MapIgnorePixelScaling(SKCanvasViewHandler handler, ISKCanvasView canvasView) { - handler.PlatformView?.UpdateIgnorePixelScaling(canvasView); + handler.PlatformView.IgnorePixelScaling = canvasView.IgnorePixelScaling; } public static void MapEnableTouchEvents(SKCanvasViewHandler handler, ISKCanvasView canvasView) { - if (handler.PlatformView == null) - return; - handler.touchHandler ??= new SKTouchHandler( args => canvasView.OnTouch(args), (x, y) => handler.OnGetScaledCoord(x, y)); diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Windows.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Windows.cs index 9b6ba30935..8518413d5d 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Windows.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Windows.cs @@ -1,4 +1,5 @@ using Microsoft.Maui.Handlers; +using Microsoft.UI.Xaml; using SkiaSharp.Views.Maui.Platform; using SkiaSharp.Views.Windows; @@ -32,12 +33,12 @@ protected override void DisconnectHandler(SKXamlCanvas platformView) public static void OnInvalidateSurface(SKCanvasViewHandler handler, ISKCanvasView canvasView, object? args) { - handler.PlatformView?.Invalidate(); + handler.PlatformView.Invalidate(); } public static void MapIgnorePixelScaling(SKCanvasViewHandler handler, ISKCanvasView canvasView) { - handler.PlatformView?.UpdateIgnorePixelScaling(canvasView); + handler.PlatformView.IgnorePixelScaling = canvasView.IgnorePixelScaling; } public static void MapEnableTouchEvents(SKCanvasViewHandler handler, ISKCanvasView canvasView) diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.cs index dd9deea98e..90ea1bcd4f 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.cs @@ -13,7 +13,7 @@ public partial class SKCanvasViewHandler }; public static CommandMapper SKCanvasViewCommandMapper = - new CommandMapper() + new CommandMapper(ViewHandler.ViewCommandMapper) { [nameof(ISKCanvasView.InvalidateSurface)] = OnInvalidateSurface, }; diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Android.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Android.cs new file mode 100644 index 0000000000..aff64caa15 --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Android.cs @@ -0,0 +1,136 @@ +using Android.Content; +using Android.Opengl; +using Microsoft.Maui; +using Microsoft.Maui.Handlers; +using Microsoft.Maui.Platform; +using SkiaSharp.Views.Android; +using SkiaSharp.Views.Maui.Platform; + +namespace SkiaSharp.Views.Maui.Handlers +{ + public partial class SKGLViewHandler : ViewHandler + { + private SKSizeI lastCanvasSize; + private GRContext? lastGRContext; + private SKTouchHandler? touchHandler; + + protected override SKGLTextureView CreatePlatformView() + { + var view = new MauiSKGLTextureView(Context); + view.SetOpaque(false); + return view; + } + + protected override void ConnectHandler(SKGLTextureView platformView) + { + platformView.PaintSurface += OnPaintSurface; + + base.ConnectHandler(platformView); + } + + protected override void DisconnectHandler(SKGLTextureView platformView) + { + touchHandler?.Detach(platformView); + touchHandler = null; + + platformView.PaintSurface -= OnPaintSurface; + + base.DisconnectHandler(platformView); + } + + // Mapper actions / properties + + public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) + { + if (handler.PlatformView.RenderMode == Rendermode.WhenDirty) + handler.PlatformView.RequestRender(); + } + + public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) + { + if (handler.PlatformView is not MauiSKGLTextureView pv) + return; + + pv.IgnorePixelScaling = view.IgnorePixelScaling; + pv.RequestRender(); + } + + public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) + { + handler.PlatformView.RenderMode = view.HasRenderLoop + ? Rendermode.Continuously + : Rendermode.WhenDirty; + } + + public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) + { + handler.touchHandler ??= new SKTouchHandler( + args => view.OnTouch(args), + (x, y) => handler.OnGetScaledCoord(x, y)); + + handler.touchHandler?.SetEnabled(handler.PlatformView, view.EnableTouchEvents); + } + + // helper methods + + private void OnPaintSurface(object? sender, Android.SKPaintGLSurfaceEventArgs e) + { + var newCanvasSize = e.Info.Size; + if (lastCanvasSize != newCanvasSize) + { + lastCanvasSize = newCanvasSize; + VirtualView?.OnCanvasSizeChanged(newCanvasSize); + } + if (sender is SKGLTextureView platformView) + { + var newGRContext = platformView.GRContext; + if (lastGRContext != newGRContext) + { + lastGRContext = newGRContext; + VirtualView?.OnGRContextChanged(newGRContext); + } + } + + VirtualView?.OnPaintSurface(new SKPaintGLSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info, e.RawInfo)); + } + + private SKPoint OnGetScaledCoord(double x, double y) + { + if (VirtualView?.IgnorePixelScaling == true && Context != null) + { + x = Context.FromPixels(x); + y = Context.FromPixels(y); + } + + return new SKPoint((float)x, (float)y); + } + + private class MauiSKGLTextureView : SKGLTextureView + { + private float density; + + public MauiSKGLTextureView(Context context) + : base(context) + { + density = Resources?.DisplayMetrics?.Density ?? 1; + } + + public bool IgnorePixelScaling { get; set; } + + protected override void OnPaintSurface(Android.SKPaintGLSurfaceEventArgs e) + { + if (IgnorePixelScaling) + { + var userVisibleSize = new SKSizeI((int)(e.Info.Width / density), (int)(e.Info.Height / density)); + var canvas = e.Surface.Canvas; + canvas.Scale(density); + canvas.Save(); + + e = new Android.SKPaintGLSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info.WithSize(userVisibleSize), e.Info); + } + + base.OnPaintSurface(e); + } + } + } +} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs new file mode 100644 index 0000000000..81e91378e3 --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs @@ -0,0 +1,19 @@ +using System; +using Microsoft.Maui.Handlers; +using UIKit; + +namespace SkiaSharp.Views.Maui.Handlers +{ + public partial class SKGLViewHandler : ViewHandler + { + protected override UIView CreatePlatformView() => throw new PlatformNotSupportedException("OpenGL-based views (such as SKGLView) are not supported on Mac Catalyst. Instead, use Metal-based views."); + + public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) { } + + public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) { } + + public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) { } + + public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) { } + } +} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Ref.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Ref.cs new file mode 100644 index 0000000000..c9ef2d859f --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Ref.cs @@ -0,0 +1,18 @@ +using System; +using Microsoft.Maui.Handlers; + +namespace SkiaSharp.Views.Maui.Handlers +{ + public partial class SKGLViewHandler : ViewHandler + { + protected override object CreatePlatformView() => throw new NotImplementedException(); + + public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) { } + + public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) { } + + public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) { } + + public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) { } + } +} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Tizen.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Tizen.cs new file mode 100644 index 0000000000..42a948c453 --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Tizen.cs @@ -0,0 +1,21 @@ +using System; +using Microsoft.Maui.Handlers; +using SkiaSharp.Views.Maui.Platform; +using SkiaSharp.Views.Tizen.NUI; +using ScalingInfo = SkiaSharp.Views.Tizen.ScalingInfo; + +namespace SkiaSharp.Views.Maui.Handlers +{ + public partial class SKGLViewHandler : ViewHandler + { + protected override SKGLSurfaceView CreatePlatformView() => throw new PlatformNotSupportedException("SKGLView is not yet implemented for Tizen."); + + public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) { } + + public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) { } + + public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) { } + + public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) { } + } +} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Windows.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Windows.cs new file mode 100644 index 0000000000..58026f6a59 --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Windows.cs @@ -0,0 +1,129 @@ +using Microsoft.Maui.Handlers; +using SkiaSharp.Views.Maui.Platform; +using SkiaSharp.Views.Windows; + +namespace SkiaSharp.Views.Maui.Handlers +{ + public partial class SKGLViewHandler : ViewHandler + { + private SKSizeI lastCanvasSize; + private GRContext? lastGRContext; + private SKTouchHandler? touchHandler; + + protected override SKSwapChainPanel CreatePlatformView() => new MauiSKSwapChainPanel(); + + protected override void ConnectHandler(SKSwapChainPanel platformView) + { + platformView.PaintSurface += OnPaintSurface; + + base.ConnectHandler(platformView); + } + + protected override void DisconnectHandler(SKSwapChainPanel platformView) + { + touchHandler?.Detach(platformView); + touchHandler = null; + + platformView.PaintSurface -= OnPaintSurface; + + base.DisconnectHandler(platformView); + } + + // Mapper actions / properties + + public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) + { + if (!handler.PlatformView.EnableRenderLoop) + handler.PlatformView.Invalidate(); + } + + public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) + { + if (handler.PlatformView is not MauiSKSwapChainPanel pv) + return; + + pv.IgnorePixelScaling = view.IgnorePixelScaling; + pv.Invalidate(); + } + + public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) + { + handler.PlatformView.EnableRenderLoop = view.HasRenderLoop; + } + + public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) + { + if (handler.PlatformView == null) + return; + + handler.touchHandler ??= new SKTouchHandler( + args => view.OnTouch(args), + (x, y) => handler.OnGetScaledCoord(x, y)); + + handler.touchHandler?.SetEnabled(handler.PlatformView, view.EnableTouchEvents); + } + + public static void MapBackground(SKGLViewHandler handler, ISKGLView view) + { + // WinUI 3 limitation: + // Setting 'Background' property is not supported on SwapChainPanel.'. + } + + // helper methods + + private void OnPaintSurface(object? sender, Windows.SKPaintGLSurfaceEventArgs e) + { + var newCanvasSize = e.Info.Size; + if (lastCanvasSize != newCanvasSize) + { + lastCanvasSize = newCanvasSize; + VirtualView?.OnCanvasSizeChanged(newCanvasSize); + } + if (sender is SKSwapChainPanel platformView) + { + var newGRContext = platformView.GRContext; + if (lastGRContext != newGRContext) + { + lastGRContext = newGRContext; + VirtualView?.OnGRContextChanged(newGRContext); + } + } + + VirtualView?.OnPaintSurface(new SKPaintGLSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info, e.RawInfo)); + } + + private SKPoint OnGetScaledCoord(double x, double y) + { + if (VirtualView?.IgnorePixelScaling == false && PlatformView != null) + { + var scale = PlatformView.ContentsScale; + + x *= scale; + y *= scale; + } + + return new SKPoint((float)x, (float)y); + } + + private class MauiSKSwapChainPanel : SKSwapChainPanel + { + public bool IgnorePixelScaling { get; set; } + + protected override void OnPaintSurface(Windows.SKPaintGLSurfaceEventArgs e) + { + if (IgnorePixelScaling) + { + var density = (float)ContentsScale; + var userVisibleSize = new SKSizeI((int)(e.Info.Width / density), (int)(e.Info.Height / density)); + var canvas = e.Surface.Canvas; + canvas.Scale(density); + canvas.Save(); + + e = new Windows.SKPaintGLSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info.WithSize(userVisibleSize), e.Info); + } + + base.OnPaintSurface(e); + } + } + } +} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.cs new file mode 100644 index 0000000000..493691e456 --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.cs @@ -0,0 +1,35 @@ +using Microsoft.Maui; +using Microsoft.Maui.Handlers; + +namespace SkiaSharp.Views.Maui.Handlers +{ + public partial class SKGLViewHandler + { + public static PropertyMapper SKGLViewMapper = + new PropertyMapper(ViewHandler.ViewMapper) + { + [nameof(ISKGLView.EnableTouchEvents)] = MapEnableTouchEvents, + [nameof(ISKGLView.IgnorePixelScaling)] = MapIgnorePixelScaling, + [nameof(ISKGLView.HasRenderLoop)] = MapHasRenderLoop, +#if WINDOWS + [nameof(ISKGLView.Background)] = MapBackground, +#endif + }; + + public static CommandMapper SKGLViewCommandMapper = + new CommandMapper(ViewHandler.ViewCommandMapper) + { + [nameof(ISKGLView.InvalidateSurface)] = OnInvalidateSurface, + }; + + public SKGLViewHandler() + : base(SKGLViewMapper, SKGLViewCommandMapper) + { + } + + public SKGLViewHandler(PropertyMapper? mapper, CommandMapper? commands) + : base(mapper ?? SKGLViewMapper, commands ?? SKGLViewCommandMapper) + { + } + } +} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.iOS.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.iOS.cs new file mode 100644 index 0000000000..c19a2463a6 --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.iOS.cs @@ -0,0 +1,219 @@ +using System; +using System.Runtime.Versioning; +using CoreAnimation; +using Foundation; +using Microsoft.Maui.Handlers; +using SkiaSharp.Views.iOS; +using SkiaSharp.Views.Maui.Platform; +using UIKit; + +namespace SkiaSharp.Views.Maui.Handlers +{ + [ObsoletedOSPlatform("ios12.0", "Use 'Metal' instead.")] + [ObsoletedOSPlatform("tvos12.0", "Use 'Metal' instead.")] + [SupportedOSPlatform("ios")] + [SupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("macos")] + public partial class SKGLViewHandler : ViewHandler + { + private SKSizeI lastCanvasSize; + private GRContext? lastGRContext; + private SKTouchHandler? touchHandler; + private RenderLoopManager? renderLoopManager; + + protected override SKGLView CreatePlatformView() => + new MauiSKGLView + { + BackgroundColor = UIColor.Clear, + Opaque = false, + }; + + protected override void ConnectHandler(SKGLView platformView) + { + renderLoopManager = new RenderLoopManager(this); + + platformView.PaintSurface += OnPaintSurface; + + base.ConnectHandler(platformView); + } + + protected override void DisconnectHandler(SKGLView platformView) + { + renderLoopManager?.StopRenderLoop(); + + touchHandler?.Detach(platformView); + touchHandler = null; + + platformView.PaintSurface -= OnPaintSurface; + + base.DisconnectHandler(platformView); + } + + // Mapper actions / properties + + public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) + { + handler.renderLoopManager?.RequestDisplay(); + } + + public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) + { + if (handler.PlatformView is MauiSKGLView pv) + { + pv.IgnorePixelScaling = view.IgnorePixelScaling; + handler.renderLoopManager?.RequestDisplay(); + } + } + + public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) + { + if (view.HasRenderLoop) + handler.renderLoopManager?.RequestRenderLoop(); + else + handler.renderLoopManager?.StopRenderLoop(); + } + + public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) + { + handler.touchHandler ??= new SKTouchHandler( + args => view.OnTouch(args), + (x, y) => handler.OnGetScaledCoord(x, y)); + + handler.touchHandler?.SetEnabled(handler.PlatformView, view.EnableTouchEvents); + } + + // helper methods + + private void OnPaintSurface(object? sender, iOS.SKPaintGLSurfaceEventArgs e) + { + var newCanvasSize = e.Info.Size; + if (lastCanvasSize != newCanvasSize) + { + lastCanvasSize = newCanvasSize; + VirtualView?.OnCanvasSizeChanged(newCanvasSize); + } + if (sender is SKGLView platformView) + { + var newGRContext = platformView.GRContext; + if (lastGRContext != newGRContext) + { + lastGRContext = newGRContext; + VirtualView?.OnGRContextChanged(newGRContext); + } + } + + VirtualView?.OnPaintSurface(new SKPaintGLSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info, e.RawInfo)); + } + + private SKPoint OnGetScaledCoord(double x, double y) + { + if (VirtualView?.IgnorePixelScaling == false && PlatformView != null) + { + var scale = PlatformView.ContentScaleFactor; + + x *= scale; + y *= scale; + } + + return new SKPoint((float)x, (float)y); + } + + private class MauiSKGLView : SKGLView + { + public bool IgnorePixelScaling { get; set; } + + protected override void OnPaintSurface(iOS.SKPaintGLSurfaceEventArgs e) + { + if (IgnorePixelScaling) + { + var userVisibleSize = new SKSizeI((int)Bounds.Width, (int)Bounds.Height); + var canvas = e.Surface.Canvas; + canvas.Scale((float)ContentScaleFactor); + canvas.Save(); + + e = new iOS.SKPaintGLSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info.WithSize(userVisibleSize), e.Info); + } + + base.OnPaintSurface(e); + } + } + + private class RenderLoopManager + { + private CADisplayLink? displayLink; + private WeakReference weakHandler; + + public RenderLoopManager(SKGLViewHandler handler) + { + weakHandler = new WeakReference(handler); + } + + public SKGLViewHandler? Handler + { + get + { + if (weakHandler.TryGetTarget(out var handler)) + return handler; + return null; + } + } + + public SKGLView? PlatformView => Handler?.PlatformView; + + public ISKGLView? VirtualView => Handler?.VirtualView; + + public void RequestDisplay() + { + // skip if there is a render loop + if (displayLink is not null) + return; + + var nativeView = PlatformView; + nativeView?.BeginInvokeOnMainThread(() => + { + if (nativeView is not null && nativeView.Handle != IntPtr.Zero) + nativeView.Display(); + }); + } + + public void RequestRenderLoop() + { + // skip if there is already a render loop + if (displayLink is not null) + return; + + // bail out if we are requesting something that the view doesn't want to + if (VirtualView?.HasRenderLoop != true) + return; + + displayLink = CADisplayLink.Create(() => + { + var nativeView = PlatformView; + var virtualView = VirtualView; + + // stop the render loop if the loop was disabled, or the views are disposed + if (nativeView is null || virtualView is null || nativeView.Handle == IntPtr.Zero || !virtualView.HasRenderLoop) + { + StopRenderLoop(); + return; + } + + // redraw the view + nativeView.Display(); + }); + displayLink.AddToRunLoop(NSRunLoop.Current, NSRunLoopMode.Default); + } + + public void StopRenderLoop() + { + // skip if there is no render loop + if (displayLink is null) + return; + + displayLink.Invalidate(); + displayLink.Dispose(); + displayLink = null; + } + } + } +} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKImageSourceService/SKImageSourceService.iOS.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKImageSourceService/SKImageSourceService.Apple.cs similarity index 100% rename from source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKImageSourceService/SKImageSourceService.iOS.cs rename to source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKImageSourceService/SKImageSourceService.Apple.cs diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/ISKGLView.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/ISKGLView.cs new file mode 100644 index 0000000000..55d517a5f0 --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/ISKGLView.cs @@ -0,0 +1,27 @@ +using Microsoft.Maui; + +namespace SkiaSharp.Views.Maui +{ + public interface ISKGLView : IView + { + SKSize CanvasSize { get; } + + GRContext? GRContext { get; } + + bool HasRenderLoop { get; } + + bool IgnorePixelScaling { get; } + + bool EnableTouchEvents { get; } + + void InvalidateSurface(); + + void OnCanvasSizeChanged(SKSizeI size); + + void OnGRContextChanged(GRContext? context); + + void OnPaintSurface(SKPaintGLSurfaceEventArgs e); + + void OnTouch(SKTouchEventArgs e); + } +} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Android/SKCanvasViewExtensions.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Android/SKCanvasViewExtensions.cs deleted file mode 100644 index c292e76bed..0000000000 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Android/SKCanvasViewExtensions.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SkiaSharp.Views.Android; - -namespace SkiaSharp.Views.Maui.Platform -{ - public static class SKCanvasViewExtensions - { - public static void UpdateIgnorePixelScaling(this SKCanvasView nativeView, ISKCanvasView canvasView) => - nativeView.IgnorePixelScaling = canvasView?.IgnorePixelScaling ?? false; - } -} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/iOS/SKTouchHandler.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Apple/SKTouchHandler.cs similarity index 100% rename from source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/iOS/SKTouchHandler.cs rename to source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Apple/SKTouchHandler.cs diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Tizen/SKCanvasViewExtensions.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Tizen/SKCanvasViewExtensions.cs deleted file mode 100644 index fa6ba11eef..0000000000 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Tizen/SKCanvasViewExtensions.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SkiaSharp.Views.Tizen.NUI; - -namespace SkiaSharp.Views.Maui.Platform -{ - public static class SKCanvasViewExtensions - { - public static void UpdateIgnorePixelScaling(this SKCanvasView nativeView, ISKCanvasView canvasView) => - nativeView.IgnorePixelScaling = canvasView?.IgnorePixelScaling ?? false; - } -} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Windows/SKCanvasViewExtensions.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Windows/SKCanvasViewExtensions.cs deleted file mode 100644 index 5977efb5a8..0000000000 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Windows/SKCanvasViewExtensions.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SkiaSharp.Views.Windows; - -namespace SkiaSharp.Views.Maui.Platform -{ - public static class SKCanvasViewExtensions - { - public static void UpdateIgnorePixelScaling(this SKXamlCanvas nativeView, ISKCanvasView canvasView) => - nativeView.IgnorePixelScaling = canvasView?.IgnorePixelScaling ?? false; - } -} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/iOS/SKCanvasViewExtensions.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/iOS/SKCanvasViewExtensions.cs deleted file mode 100644 index 8a495cc783..0000000000 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/iOS/SKCanvasViewExtensions.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SkiaSharp.Views.iOS; - -namespace SkiaSharp.Views.Maui.Platform -{ - public static class SKCanvasViewExtensions - { - public static void UpdateIgnorePixelScaling(this SKCanvasView nativeView, ISKCanvasView canvasView) => - nativeView.IgnorePixelScaling = canvasView?.IgnorePixelScaling ?? false; - } -} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SKPaintGLSurfaceEventArgs.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SKPaintGLSurfaceEventArgs.cs index de5039c76e..f1b7e3bc3d 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SKPaintGLSurfaceEventArgs.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SKPaintGLSurfaceEventArgs.cs @@ -18,6 +18,23 @@ public SKPaintGLSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget render BackendRenderTarget = renderTarget; ColorType = colorType; Origin = origin; + Info = new SKImageInfo(renderTarget.Width, renderTarget.Height, ColorType); + RawInfo = Info; + } + + public SKPaintGLSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget renderTarget, GRSurfaceOrigin origin, SKImageInfo info) + : this(surface, renderTarget, origin, info, info) + { + } + + public SKPaintGLSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget renderTarget, GRSurfaceOrigin origin, SKImageInfo info, SKImageInfo rawInfo) + { + Surface = surface; + BackendRenderTarget = renderTarget; + ColorType = info.ColorType; + Origin = origin; + Info = info; + RawInfo = rawInfo; } public SKSurface Surface { get; private set; } @@ -27,5 +44,9 @@ public SKPaintGLSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget render public SKColorType ColorType { get; private set; } public GRSurfaceOrigin Origin { get; private set; } + + public SKImageInfo Info { get; private set; } + + public SKImageInfo RawInfo { get; private set; } } } diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SkiaSharp.Views.Maui.Core.csproj b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SkiaSharp.Views.Maui.Core.csproj index c9c164a391..ee09f8be26 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SkiaSharp.Views.Maui.Core.csproj +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SkiaSharp.Views.Maui.Core.csproj @@ -27,11 +27,23 @@ + + + + + + + + + + + + diff --git a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLLayer.cs b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLLayer.cs index ee1a8eba55..f27b363442 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLLayer.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLLayer.cs @@ -2,6 +2,7 @@ using System; using System.ComponentModel; +using System.Runtime.Versioning; using CoreAnimation; using CoreGraphics; using OpenGLES; @@ -13,6 +14,12 @@ namespace SkiaSharp.Views.tvOS namespace SkiaSharp.Views.iOS #endif { + [ObsoletedOSPlatform("tvos12.0", "Use 'Metal' instead.")] + [ObsoletedOSPlatform("ios12.0", "Use 'Metal' instead.")] + [SupportedOSPlatform("ios")] + [SupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("macos")] + [UnsupportedOSPlatform("maccatalyst")] public class SKGLLayer : CAEAGLLayer { private const SKColorType colorType = SKColorType.Rgba8888; diff --git a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLView.cs b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLView.cs index 58e10521ee..de4b9d2455 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLView.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLView.cs @@ -2,6 +2,8 @@ using System; using System.ComponentModel; +using System.Runtime.Versioning; +using CoreAnimation; using CoreGraphics; using Foundation; using GLKit; @@ -18,6 +20,11 @@ namespace SkiaSharp.Views.tvOS namespace SkiaSharp.Views.iOS #endif { + [ObsoletedOSPlatform("ios12.0", "Use 'Metal' instead.")] + [ObsoletedOSPlatform("tvos12.0", "Use 'Metal' instead.")] + [SupportedOSPlatform("ios")] + [SupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("macos")] [DesignTimeVisible(true)] #if HAS_UNO internal From 54e8a3f3d53aa9c45a1a30967fc45ce7b62cc5df Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Mon, 5 Feb 2024 13:59:58 +0200 Subject: [PATCH 07/40] Reduce checkout size of submodules (#2739) --- native/winui/ANGLE.cake | 2 +- scripts/azure-templates-bootstrapper.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/native/winui/ANGLE.cake b/native/winui/ANGLE.cake index 88c33903e6..5fe7e4285d 100644 --- a/native/winui/ANGLE.cake +++ b/native/winui/ANGLE.cake @@ -19,7 +19,7 @@ void InitializeAngle(string branch, DirectoryPath ANGLE_PATH, DirectoryPath WINA continue; RunProcess("git", new ProcessSettings { - Arguments = $"submodule update --init --recursive {submodule}", + Arguments = $"submodule update --init --recursive --depth 1 --single-branch {submodule}", WorkingDirectory = ANGLE_PATH.FullPath, }); } diff --git a/scripts/azure-templates-bootstrapper.yml b/scripts/azure-templates-bootstrapper.yml index ab003209e0..8e43dce46a 100644 --- a/scripts/azure-templates-bootstrapper.yml +++ b/scripts/azure-templates-bootstrapper.yml @@ -338,7 +338,7 @@ jobs: inputs: artifactName: ${{ parameters.artifactName }} pathToPublish: 'output' - - ${{ if eq(variables['System.TeamProject'], 'devdiv') }}: + - ${{ if and(eq(variables['System.TeamProject'], 'devdiv'), ne(parameters.buildPipelineType, 'tests'), ne(variables['System.PullRequest.IsFork'], 'true'), or(and(eq(variables['Build.Reason'], 'Schedule'), or(eq(variables['Build.SourceBranch'], 'refs/heads/main'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'))), parameters.runCompliance)) }}: - task: ComponentGovernanceComponentDetection@0 displayName: Run component detection condition: always() From 7e4dc6959d61ee8749a68c500aa487b75d1bf472 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Mon, 5 Feb 2024 21:43:23 +0200 Subject: [PATCH 08/40] Update changelogs --- .../SkiaSharp.Views.Maui.Controls.breaking.md | 29 +++++++++ .../3.0.0/SkiaSharp.Views.Maui.Controls.md | 53 ++++++++++++++++ .../3.0.0/SkiaSharp.Views.Maui.Core.md | 61 +++++++++++++++++++ .../3.0.0/SkiaSharp.Views.Windows.md | 35 +++++++++++ 4 files changed, 178 insertions(+) create mode 100644 changelogs/SkiaSharp.Views.Maui.Controls/3.0.0/SkiaSharp.Views.Maui.Controls.breaking.md diff --git a/changelogs/SkiaSharp.Views.Maui.Controls/3.0.0/SkiaSharp.Views.Maui.Controls.breaking.md b/changelogs/SkiaSharp.Views.Maui.Controls/3.0.0/SkiaSharp.Views.Maui.Controls.breaking.md new file mode 100644 index 0000000000..7ea6364fcb --- /dev/null +++ b/changelogs/SkiaSharp.Views.Maui.Controls/3.0.0/SkiaSharp.Views.Maui.Controls.breaking.md @@ -0,0 +1,29 @@ +# API diff: SkiaSharp.Views.Maui.Controls.dll + +## SkiaSharp.Views.Maui.Controls.dll + +> Assembly Version Changed: 3.0.0.0 vs 2.88.0.0 + +### Namespace SkiaSharp.Views.Maui.Controls + +#### Type Changed: SkiaSharp.Views.Maui.Controls.SKCanvasView + +Removed interface: + +```csharp +ISKCanvasViewController +``` + + +#### Type Changed: SkiaSharp.Views.Maui.Controls.SKGLView + +Removed interface: + +```csharp +ISKGLViewController +``` + + +#### Removed Type SkiaSharp.Views.Maui.Controls.ISKCanvasViewController +#### Removed Type SkiaSharp.Views.Maui.Controls.ISKGLViewController + diff --git a/changelogs/SkiaSharp.Views.Maui.Controls/3.0.0/SkiaSharp.Views.Maui.Controls.md b/changelogs/SkiaSharp.Views.Maui.Controls/3.0.0/SkiaSharp.Views.Maui.Controls.md index a650e725a6..99d1553c0f 100644 --- a/changelogs/SkiaSharp.Views.Maui.Controls/3.0.0/SkiaSharp.Views.Maui.Controls.md +++ b/changelogs/SkiaSharp.Views.Maui.Controls/3.0.0/SkiaSharp.Views.Maui.Controls.md @@ -4,3 +4,56 @@ > Assembly Version Changed: 3.0.0.0 vs 2.88.0.0 +### Namespace SkiaSharp.Views.Maui.Controls + +#### Type Changed: SkiaSharp.Views.Maui.Controls.SKCanvasView + +Removed interface: + +```csharp +ISKCanvasViewController +``` + +Removed method: + +```csharp +protected override Microsoft.Maui.SizeRequest OnMeasure (double widthConstraint, double heightConstraint); +``` + + +#### Type Changed: SkiaSharp.Views.Maui.Controls.SKGLView + +Removed interface: + +```csharp +ISKGLViewController +``` + +Added interface: + +```csharp +SkiaSharp.Views.Maui.ISKGLView +``` + +Added field: + +```csharp +public static Microsoft.Maui.Controls.BindableProperty IgnorePixelScalingProperty; +``` + +Added property: + +```csharp +public override bool IgnorePixelScaling { get; set; } +``` + +Removed method: + +```csharp +protected override Microsoft.Maui.SizeRequest OnMeasure (double widthConstraint, double heightConstraint); +``` + + +#### Removed Type SkiaSharp.Views.Maui.Controls.ISKCanvasViewController +#### Removed Type SkiaSharp.Views.Maui.Controls.ISKGLViewController + diff --git a/changelogs/SkiaSharp.Views.Maui.Core/3.0.0/SkiaSharp.Views.Maui.Core.md b/changelogs/SkiaSharp.Views.Maui.Core/3.0.0/SkiaSharp.Views.Maui.Core.md index c6137a6a83..c33e810f4c 100644 --- a/changelogs/SkiaSharp.Views.Maui.Core/3.0.0/SkiaSharp.Views.Maui.Core.md +++ b/changelogs/SkiaSharp.Views.Maui.Core/3.0.0/SkiaSharp.Views.Maui.Core.md @@ -4,3 +4,64 @@ > Assembly Version Changed: 3.0.0.0 vs 2.88.0.0 +### Namespace SkiaSharp.Views.Maui + +#### Type Changed: SkiaSharp.Views.Maui.SKPaintGLSurfaceEventArgs + +Added constructors: + +```csharp +public SKPaintGLSurfaceEventArgs (SkiaSharp.SKSurface surface, SkiaSharp.GRBackendRenderTarget renderTarget, SkiaSharp.GRSurfaceOrigin origin, SkiaSharp.SKImageInfo info); +public SKPaintGLSurfaceEventArgs (SkiaSharp.SKSurface surface, SkiaSharp.GRBackendRenderTarget renderTarget, SkiaSharp.GRSurfaceOrigin origin, SkiaSharp.SKImageInfo info, SkiaSharp.SKImageInfo rawInfo); +``` + +Added properties: + +```csharp +public SkiaSharp.SKImageInfo Info { get; } +public SkiaSharp.SKImageInfo RawInfo { get; } +``` + + +#### New Type: SkiaSharp.Views.Maui.ISKGLView + +```csharp +public interface ISKGLView : Microsoft.Maui.IElement, Microsoft.Maui.ITransform, Microsoft.Maui.IView { + // properties + public virtual SkiaSharp.SKSize CanvasSize { get; } + public virtual bool EnableTouchEvents { get; } + public virtual SkiaSharp.GRContext GRContext { get; } + public virtual bool HasRenderLoop { get; } + public virtual bool IgnorePixelScaling { get; } + // methods + public virtual void InvalidateSurface (); + public virtual void OnCanvasSizeChanged (SkiaSharp.SKSizeI size); + public virtual void OnGRContextChanged (SkiaSharp.GRContext context); + public virtual void OnPaintSurface (SKPaintGLSurfaceEventArgs e); + public virtual void OnTouch (SKTouchEventArgs e); +} +``` + + +### Namespace SkiaSharp.Views.Maui.Handlers + +#### New Type: SkiaSharp.Views.Maui.Handlers.SKGLViewHandler + +```csharp +public class SKGLViewHandler : Microsoft.Maui.Handlers.ViewHandler`2[SkiaSharp.Views.Maui.ISKGLView,System.Object], Microsoft.Maui.IElementHandler, Microsoft.Maui.IPlatformViewHandler, Microsoft.Maui.IViewHandler { + // constructors + public SKGLViewHandler (); + public SKGLViewHandler (Microsoft.Maui.PropertyMapper mapper, Microsoft.Maui.CommandMapper commands); + // fields + public static Microsoft.Maui.CommandMapper SKGLViewCommandMapper; + public static Microsoft.Maui.PropertyMapper SKGLViewMapper; + // methods + protected override object CreatePlatformView (); + public static void MapEnableTouchEvents (SKGLViewHandler handler, SkiaSharp.Views.Maui.ISKGLView view); + public static void MapHasRenderLoop (SKGLViewHandler handler, SkiaSharp.Views.Maui.ISKGLView view); + public static void MapIgnorePixelScaling (SKGLViewHandler handler, SkiaSharp.Views.Maui.ISKGLView view); + public static void OnInvalidateSurface (SKGLViewHandler handler, SkiaSharp.Views.Maui.ISKGLView view, object args); +} +``` + + diff --git a/changelogs/SkiaSharp.Views.WinUI/3.0.0/SkiaSharp.Views.Windows.md b/changelogs/SkiaSharp.Views.WinUI/3.0.0/SkiaSharp.Views.Windows.md index 82249503c2..bff6e56995 100644 --- a/changelogs/SkiaSharp.Views.WinUI/3.0.0/SkiaSharp.Views.Windows.md +++ b/changelogs/SkiaSharp.Views.WinUI/3.0.0/SkiaSharp.Views.Windows.md @@ -27,4 +27,39 @@ public SkiaSharp.GRBackendRenderTargetDesc RenderTarget { get; } #### Removed Type SkiaSharp.Views.Windows.Extensions +#### New Type: SkiaSharp.Views.Windows.AngleSwapChainPanel + +```csharp +public class AngleSwapChainPanel : Microsoft.UI.Xaml.Controls.SwapChainPanel { + // constructors + public AngleSwapChainPanel (); + // properties + public double ContentsScale { get; } + public bool DrawInBackground { get; set; } + public bool EnableRenderLoop { get; set; } + // methods + public void Invalidate (); + protected virtual void OnDestroyingContext (); + protected virtual void OnRenderFrame (Windows.Foundation.Rect rect); +} +``` + +#### New Type: SkiaSharp.Views.Windows.SKSwapChainPanel + +```csharp +public class SKSwapChainPanel : SkiaSharp.Views.Windows.AngleSwapChainPanel { + // constructors + public SKSwapChainPanel (); + // properties + public SkiaSharp.SKSize CanvasSize { get; } + public SkiaSharp.GRContext GRContext { get; } + // events + public event System.EventHandler PaintSurface; + // methods + protected override void OnDestroyingContext (); + protected virtual void OnPaintSurface (SKPaintGLSurfaceEventArgs e); + protected override void OnRenderFrame (Windows.Foundation.Rect rect); +} +``` + From 8396031c40a7e1bad11128a4a1ffa74496046a69 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Mon, 5 Feb 2024 23:31:09 +0200 Subject: [PATCH 09/40] Correctly package managed runtime-only files (#2741) --- binding/NativeAssets.Build.targets | 12 ++++++++---- .../SkiaSharp.NativeAssets.WinUI.csproj | 6 +++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/binding/NativeAssets.Build.targets b/binding/NativeAssets.Build.targets index cd68c556fa..d34c35f239 100644 --- a/binding/NativeAssets.Build.targets +++ b/binding/NativeAssets.Build.targets @@ -33,16 +33,20 @@ - + <_NativeWindowsPackageFileToUse Include="@(NativeWindowsPackageFile->HasMetadata('Folder'))" /> + <_NativeWindowsPackageFileWithNoFolder Include="@(NativeWindowsPackageFile)" /> + <_NativeWindowsPackageFileWithNoFolder Remove="@(_NativeWindowsPackageFileToUse)" /> + <_NativeWindowsPackageFileToUse Include="@(_NativeWindowsPackageFileWithNoFolder)" Folder="native" /> + <_CompletedNativeWindowsPackageFile - Include="@(NativeWindowsPackageFile)" + Include="@(_NativeWindowsPackageFileToUse)" TargetFramework="%(RuntimeIdentifier)" - TargetPath="native\%(Filename)%(Extension)" - PackagePath="runtimes\%(RuntimeIdentifier)\native\%(Filename)%(Extension)" /> + TargetPath="%(Folder)\%(Filename)%(Extension)" + PackagePath="runtimes\%(RuntimeIdentifier)\%(Folder)\%(Filename)%(Extension)" /> <_BuildOutputInPackage Remove="@(_BuildOutputInPackage)" /> <_BuildOutputInPackage Include="@(_CompletedNativeWindowsPackageFile)" Condition="'%(Extension)' != '.pdb'" /> <_TargetPathsToSymbols Remove="@(_TargetPathsToSymbols)" /> diff --git a/binding/SkiaSharp.NativeAssets.WinUI/SkiaSharp.NativeAssets.WinUI.csproj b/binding/SkiaSharp.NativeAssets.WinUI/SkiaSharp.NativeAssets.WinUI.csproj index 07bac2c33b..fab3a0d1e0 100644 --- a/binding/SkiaSharp.NativeAssets.WinUI/SkiaSharp.NativeAssets.WinUI.csproj +++ b/binding/SkiaSharp.NativeAssets.WinUI/SkiaSharp.NativeAssets.WinUI.csproj @@ -6,11 +6,11 @@ true - + - + - + \ No newline at end of file From 39d0829f8dcea01c7a3a0866a4b73b0482daecc9 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Tue, 6 Feb 2024 02:35:13 +0200 Subject: [PATCH 10/40] Don't put metadata in package versions (#2743) --- source/SkiaSharp.Build.targets | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/SkiaSharp.Build.targets b/source/SkiaSharp.Build.targets index b610868313..7336df8e1f 100644 --- a/source/SkiaSharp.Build.targets +++ b/source/SkiaSharp.Build.targets @@ -104,9 +104,9 @@ $(_VersionNuGetMatch) $(Version)-$(VersionSuffix) - $(Version)+$(AssemblyVersionGitBranch.Replace('/', '-').Replace('\', '-')) - $(Version).$(AssemblyVersionGitSha) $(Version) + $(InformationalVersion)+$(AssemblyVersionGitBranch.Replace('/', '-').Replace('\', '-')) + $(InformationalVersion).$(AssemblyVersionGitSha) $(_VersionAssemblyMatch) $(_VersionFileMatch) From b79905450dd636981c04da3e14a505d659bfe0f9 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Tue, 6 Feb 2024 02:35:52 +0200 Subject: [PATCH 11/40] Run APIScan after packaging on the packages (#2730) --- native/windows/build.cake | 2 +- .../libHarfBuzzSharp/libHarfBuzzSharp.vcxproj | 6 +++++ scripts/azure-pipelines-variables.yml | 1 + scripts/azure-pipelines.yml | 4 +++ scripts/azure-templates-stages.yml | 26 ++++++++++++------- 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/native/windows/build.cake b/native/windows/build.cake index 98f1bd2b8c..afe61fb8d3 100644 --- a/native/windows/build.cake +++ b/native/windows/build.cake @@ -54,7 +54,7 @@ Task("libSkiaSharp") clang + win_vcvars_version + $"extra_cflags=[ '-DSKIA_C_DLL', '/MT{d}', '/EHsc', '/Z7', '-D_HAS_AUTO_PTR_ETC=1' ] " + - $"extra_ldflags=[ '/DEBUG:FULL' ] " + + $"extra_ldflags=[ '/DEBUG:FULL', '/DEBUGTYPE:CV,FIXUP' ] " + ADDITIONAL_GN_ARGS); var outDir = OUTPUT_PATH.Combine($"{VARIANT}/{dir}"); diff --git a/native/windows/libHarfBuzzSharp/libHarfBuzzSharp.vcxproj b/native/windows/libHarfBuzzSharp/libHarfBuzzSharp.vcxproj index 0589d79fb2..bd752caa19 100644 --- a/native/windows/libHarfBuzzSharp/libHarfBuzzSharp.vcxproj +++ b/native/windows/libHarfBuzzSharp/libHarfBuzzSharp.vcxproj @@ -148,6 +148,7 @@ Windows + /DEBUGTYPE:CV,FIXUP @@ -163,6 +164,7 @@ Windows + /DEBUGTYPE:CV,FIXUP @@ -178,6 +180,7 @@ Windows + /DEBUGTYPE:CV,FIXUP @@ -197,6 +200,7 @@ Windows true true + /DEBUGTYPE:CV,FIXUP @@ -216,6 +220,7 @@ Windows true true + /DEBUGTYPE:CV,FIXUP @@ -235,6 +240,7 @@ Windows true true + /DEBUGTYPE:CV,FIXUP diff --git a/scripts/azure-pipelines-variables.yml b/scripts/azure-pipelines-variables.yml index ed2716e7c4..ef6f1c7c03 100644 --- a/scripts/azure-pipelines-variables.yml +++ b/scripts/azure-pipelines-variables.yml @@ -1,4 +1,5 @@ variables: + SKIASHARP_MAJOR_VERSION: 3 SKIASHARP_VERSION: 3.0.0 FEATURE_NAME_PREFIX: 'feature/' VERBOSITY: normal diff --git a/scripts/azure-pipelines.yml b/scripts/azure-pipelines.yml index 3b72b46332..0575203ec3 100644 --- a/scripts/azure-pipelines.yml +++ b/scripts/azure-pipelines.yml @@ -37,6 +37,9 @@ parameters: pool: name: Azure Pipelines vmImage: ubuntu-20.04 + - name: runCompliance + type: boolean + default: false variables: - template: azure-pipelines-variables.yml @@ -54,6 +57,7 @@ stages: parameters: buildPipelineType: 'build' buildExternals: ${{ parameters.buildExternals }} + runCompliance: ${{ parameters.runCompliance }} VM_IMAGE_HOST: ${{ parameters.VM_IMAGE_HOST }} VM_IMAGE_WINDOWS: ${{ parameters.VM_IMAGE_WINDOWS }} VM_IMAGE_WINDOWS_NATIVE: ${{ parameters.VM_IMAGE_WINDOWS }} diff --git a/scripts/azure-templates-stages.yml b/scripts/azure-templates-stages.yml index 6f985c0f37..1fe8102085 100644 --- a/scripts/azure-templates-stages.yml +++ b/scripts/azure-templates-stages.yml @@ -880,18 +880,14 @@ stages: - template: security/full/v1.yml@xamarin-templates parameters: stageDependsOn: - - managed - - native_windows - - native_macos - - native_linux - - native_wasm + - package complianceEnabled: true complianceTimeoutInMinutes: 480 scanArtifacts: - - managed - - native + - nuget + - nuget_symbols antiMalwareEnabled: true - binSkimEnabled: true + binSkimEnabled: false policheckExclusionFile: $(Build.SourcesDirectory)\scripts\guardian\PoliCheckExclusions.xml policheckGdnSuppressionFilesFolder: $(Build.SourcesDirectory)\scripts\guardian credScanEnabled: true @@ -902,7 +898,19 @@ stages: enableCodeInspector: true apiScanEnabled: true apiScanSoftwareName: 'SkiaSharp' - apiScanSoftwareVersionNum: $(Build.BuildNumber) + apiScanSoftwareVersionNum: $(SKIASHARP_MAJOR_VERSION) + apiScanPreserveLogsFolder: true + preScanSteps: + - pwsh: | + $nupkgs = (Get-ChildItem "$(Build.ArtifactStagingDirectory)\binaries-to-scan\*\*.*nupkg") + foreach ($nupkg in $nupkgs) { + $filename = $nupkg.Name.TrimEnd('.nupkg') + $dest = "$(Build.ArtifactStagingDirectory)\binaries-to-scan\nuget_symbols-extracted\$filename" + Write-Host "Extracting '$nupkg' to '$dest'..." + Expand-Archive $nupkg $dest + Remove-Item $nupkg + } + displayName: Extract all the .nupkg files - ${{ if eq(parameters.buildPipelineType, 'tests') }}: - stage: finalize From 9bb8b235fa203adc9cbe456433c66ccbb1b52992 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Sat, 13 Jan 2024 02:25:36 +0800 Subject: [PATCH 12/40] Do not provide invalid externs (#2710) --- .../GlesInterop/Gles.cs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.Shared/GlesInterop/Gles.cs b/source/SkiaSharp.Views/SkiaSharp.Views.Shared/GlesInterop/Gles.cs index ab79c6bd4a..2630aca7dd 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.Shared/GlesInterop/Gles.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.Shared/GlesInterop/Gles.cs @@ -73,6 +73,18 @@ internal static class Gles public const int GL_UNSIGNED_INT_24_8_OES = 0x84FA; public const int GL_DEPTH24_STENCIL8_OES = 0x88F0; + [DllImport(libGLESv2)] + public static extern void glGetIntegerv(uint pname, out int data); + [DllImport(libGLESv2)] + public static extern System.IntPtr glGetString(uint value); + [DllImport(libGLESv2)] + public static extern void glViewport(int x, int y, int width, int height); + [DllImport(libGLESv2)] + public static extern void glClearColor(float red, float green, float blue, float alpha); + [DllImport(libGLESv2)] + public static extern void glClear(uint mask); + +#if !__DESKTOP__ [DllImport(libGLESv2)] public static extern void glGenRenderbuffers(int n, [In, Out] uint[] buffers); [DllImport(libGLESv2)] @@ -82,18 +94,10 @@ internal static class Gles [DllImport(libGLESv2)] public static extern void glGenFramebuffers(int n, ref uint buffer); [DllImport(libGLESv2)] - public static extern void glGetIntegerv(uint pname, out int data); - [DllImport(libGLESv2)] public static extern void glGetRenderbufferParameteriv(uint target, int pname, out int param); [DllImport(libGLESv2)] public static extern void glBindRenderbuffer(uint target, uint buffer); [DllImport(libGLESv2)] - public static extern void glViewport(int x, int y, int width, int height); - [DllImport(libGLESv2)] - public static extern void glClearColor(float red, float green, float blue, float alpha); - [DllImport(libGLESv2)] - public static extern void glClear(uint mask); - [DllImport(libGLESv2)] public static extern void glBindFramebuffer(uint target, uint framebuffer); [DllImport(libGLESv2)] public static extern void glDeleteFramebuffers(int n, [In, Out] uint[] framebuffers); @@ -105,8 +109,7 @@ internal static class Gles public static extern void glDeleteRenderbuffers(int n, ref uint renderbuffer); [DllImport(libGLESv2)] public static extern void glFramebufferRenderbuffer(uint target, uint attachment, uint renderbuffertarget, uint renderbuffer); - [DllImport(libGLESv2)] - public static extern System.IntPtr glGetString(uint value); +#endif } } #endif From 0176323d7ea47005027ce3761b527306c676b61e Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Fri, 9 Feb 2024 20:46:21 +0200 Subject: [PATCH 13/40] Add SKImage.ToRawShader (#2748) --- binding/SkiaSharp/SKImage.cs | 20 ++++++++++++++++++++ binding/SkiaSharp/SkiaApi.generated.cs | 14 ++++++++++++++ externals/skia | 2 +- tests/Tests/SkiaSharp/SKImageTest.cs | 25 +++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/binding/SkiaSharp/SKImage.cs b/binding/SkiaSharp/SKImage.cs index 834b05519b..4f4f3ff612 100644 --- a/binding/SkiaSharp/SKImage.cs +++ b/binding/SkiaSharp/SKImage.cs @@ -415,6 +415,26 @@ public SKShader ToShader (SKShaderTileMode tileX, SKShaderTileMode tileY, SKSamp private SKShader ToShader (SKShaderTileMode tileX, SKShaderTileMode tileY, SKSamplingOptions sampling, SKMatrix* localMatrix) => SKShader.GetObject (SkiaApi.sk_image_make_shader (Handle, tileX, tileY, &sampling, localMatrix)); + // ToRawShader + + public SKShader ToRawShader () => + ToRawShader (SKShaderTileMode.Clamp, SKShaderTileMode.Clamp, SKSamplingOptions.Default, null); + + public SKShader ToRawShader (SKShaderTileMode tileX, SKShaderTileMode tileY) => + ToRawShader (tileX, tileY, SKSamplingOptions.Default, null); + + public SKShader ToRawShader (SKShaderTileMode tileX, SKShaderTileMode tileY, SKMatrix localMatrix) => + ToRawShader (tileX, tileY, SKSamplingOptions.Default, &localMatrix); + + public SKShader ToRawShader (SKShaderTileMode tileX, SKShaderTileMode tileY, SKSamplingOptions sampling) => + ToRawShader (tileX, tileY, sampling, null); + + public SKShader ToRawShader (SKShaderTileMode tileX, SKShaderTileMode tileY, SKSamplingOptions sampling, SKMatrix localMatrix) => + ToRawShader (tileX, tileY, sampling, &localMatrix); + + private SKShader ToRawShader (SKShaderTileMode tileX, SKShaderTileMode tileY, SKSamplingOptions sampling, SKMatrix* localMatrix) => + SKShader.GetObject (SkiaApi.sk_image_make_raw_shader (Handle, tileX, tileY, &sampling, localMatrix)); + // PeekPixels public bool PeekPixels (SKPixmap pixmap) diff --git a/binding/SkiaSharp/SkiaApi.generated.cs b/binding/SkiaSharp/SkiaApi.generated.cs index 662eb8cb8c..96d4351d7e 100644 --- a/binding/SkiaSharp/SkiaApi.generated.cs +++ b/binding/SkiaSharp/SkiaApi.generated.cs @@ -4960,6 +4960,20 @@ internal static sk_shader_t sk_image_make_shader (sk_image_t image, SKShaderTile (sk_image_make_shader_delegate ??= GetSymbol ("sk_image_make_shader")).Invoke (image, tileX, tileY, sampling, cmatrix); #endif + // sk_shader_t* sk_image_make_raw_shader(const sk_image_t* image, sk_shader_tilemode_t tileX, sk_shader_tilemode_t tileY, const sk_sampling_options_t* sampling, const sk_matrix_t* cmatrix) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern sk_shader_t sk_image_make_raw_shader (sk_image_t image, SKShaderTileMode tileX, SKShaderTileMode tileY, SKSamplingOptions* sampling, SKMatrix* cmatrix); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate sk_shader_t sk_image_make_raw_shader (sk_image_t image, SKShaderTileMode tileX, SKShaderTileMode tileY, SKSamplingOptions* sampling, SKMatrix* cmatrix); + } + private static Delegates.sk_image_make_raw_shader sk_image_make_raw_shader_delegate; + internal static sk_shader_t sk_image_make_raw_shader (sk_image_t image, SKShaderTileMode tileX, SKShaderTileMode tileY, SKSamplingOptions* sampling, SKMatrix* cmatrix) => + (sk_image_make_raw_shader_delegate ??= GetSymbol ("sk_image_make_raw_shader")).Invoke (image, tileX, tileY, sampling, cmatrix); + #endif + // sk_image_t* sk_image_make_subset(const sk_image_t* cimage, gr_direct_context_t* context, const sk_irect_t* subset) #if !USE_DELEGATES [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] diff --git a/externals/skia b/externals/skia index 519e4b3025..8990028b2f 160000 --- a/externals/skia +++ b/externals/skia @@ -1 +1 @@ -Subproject commit 519e4b302588722e71ca71c2531749747a789cf0 +Subproject commit 8990028b2f3a70104c4db924e614f5bccbb2c637 diff --git a/tests/Tests/SkiaSharp/SKImageTest.cs b/tests/Tests/SkiaSharp/SKImageTest.cs index ce350854a3..e8942b5ef2 100644 --- a/tests/Tests/SkiaSharp/SKImageTest.cs +++ b/tests/Tests/SkiaSharp/SKImageTest.cs @@ -900,5 +900,30 @@ public void CanDecodePotentiallyCorruptPngFiles(string filename, int x, int y, u Assert.Equal((SKColor)color, pixmap.GetPixelColor(x, y)); } + + [SkippableFact] + public void CanCreateRawShader() + { + var path = Path.Combine(PathToImages, "baboon.png"); + + using var image = SKImage.FromEncodedData(path); + Assert.NotNull(image); + + using var shader = image.ToRawShader(); + Assert.NotNull(shader); + } + + [SkippableFact] + public void CannotCreateRawShaderWithBicubicSampling() + { + var path = Path.Combine(PathToImages, "baboon.png"); + + using var image = SKImage.FromEncodedData(path); + Assert.NotNull(image); + + var sampling = new SKSamplingOptions(SKCubicResampler.Mitchell); + using var shader = image.ToRawShader(SKShaderTileMode.Clamp, SKShaderTileMode.Clamp, sampling); + Assert.Null(shader); + } } } From 01a3218c38f5a66e217109194ea4f7887ee2d404 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Sat, 10 Feb 2024 08:25:32 +0200 Subject: [PATCH 14/40] Use Metal as a backend on Mac Catalyst (#2747) --- .../SKGLView/SKGLViewHandler.MacCatalyst.cs | 120 +++++++++++++++++- .../SkiaSharp.Views.Uno.WinUI.csproj | 2 +- .../GlesInterop/Gles.cs | 2 +- .../SKPaintGLSurfaceEventArgs.cs | 4 +- .../Apple/SKPaintMetalSurfaceEventArgs.cs | 21 +++ 5 files changed, 140 insertions(+), 9 deletions(-) diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs index 81e91378e3..8b1a067929 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs @@ -1,19 +1,127 @@ using System; using Microsoft.Maui.Handlers; +using SkiaSharp.Views.iOS; +using SkiaSharp.Views.Maui.Platform; using UIKit; namespace SkiaSharp.Views.Maui.Handlers { - public partial class SKGLViewHandler : ViewHandler + public partial class SKGLViewHandler : ViewHandler { - protected override UIView CreatePlatformView() => throw new PlatformNotSupportedException("OpenGL-based views (such as SKGLView) are not supported on Mac Catalyst. Instead, use Metal-based views."); + private SKSizeI lastCanvasSize; + private GRContext? lastGRContext; + private SKTouchHandler? touchHandler; - public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) { } + protected override SKMetalView CreatePlatformView() => + new MauiSKMetalView + { + BackgroundColor = UIColor.Clear, + Opaque = false, + }; - public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) { } + protected override void ConnectHandler(SKMetalView platformView) + { + platformView.PaintSurface += OnPaintSurface; - public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) { } + base.ConnectHandler(platformView); + } - public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) { } + protected override void DisconnectHandler(SKMetalView platformView) + { + touchHandler?.Detach(platformView); + touchHandler = null; + + platformView.PaintSurface -= OnPaintSurface; + + base.DisconnectHandler(platformView); + } + + // Mapper actions / properties + + public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) + { + if (handler.PlatformView.Paused && handler.PlatformView.EnableSetNeedsDisplay) + handler.PlatformView.SetNeedsDisplay(); + } + + public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) + { + if (handler.PlatformView is MauiSKMetalView pv) + { + pv.IgnorePixelScaling = view.IgnorePixelScaling; + handler.PlatformView.SetNeedsDisplay(); + } + } + + public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) + { + handler.PlatformView.Paused = !view.HasRenderLoop; + handler.PlatformView.EnableSetNeedsDisplay = !view.HasRenderLoop; + } + + public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) + { + handler.touchHandler ??= new SKTouchHandler( + args => view.OnTouch(args), + (x, y) => handler.OnGetScaledCoord(x, y)); + + handler.touchHandler?.SetEnabled(handler.PlatformView, view.EnableTouchEvents); + } + + // helper methods + + private void OnPaintSurface(object? sender, iOS.SKPaintMetalSurfaceEventArgs e) + { + var newCanvasSize = e.Info.Size; + if (lastCanvasSize != newCanvasSize) + { + lastCanvasSize = newCanvasSize; + VirtualView?.OnCanvasSizeChanged(newCanvasSize); + } + if (sender is SKMetalView platformView) + { + var newGRContext = platformView.GRContext; + if (lastGRContext != newGRContext) + { + lastGRContext = newGRContext; + VirtualView?.OnGRContextChanged(newGRContext); + } + } + + VirtualView?.OnPaintSurface(new SKPaintGLSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info, e.RawInfo)); + } + + private SKPoint OnGetScaledCoord(double x, double y) + { + if (VirtualView?.IgnorePixelScaling == false && PlatformView != null) + { + var scale = PlatformView.ContentScaleFactor; + + x *= scale; + y *= scale; + } + + return new SKPoint((float)x, (float)y); + } + + private class MauiSKMetalView : SKMetalView + { + public bool IgnorePixelScaling { get; set; } + + protected override void OnPaintSurface(iOS.SKPaintMetalSurfaceEventArgs e) + { + if (IgnorePixelScaling) + { + var userVisibleSize = new SKSizeI((int)Bounds.Width, (int)Bounds.Height); + var canvas = e.Surface.Canvas; + canvas.Scale((float)ContentScaleFactor); + canvas.Save(); + + e = new iOS.SKPaintMetalSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info.WithSize(userVisibleSize), e.Info); + } + + base.OnPaintSurface(e); + } + } } } diff --git a/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.WinUI/SkiaSharp.Views.Uno.WinUI.csproj b/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.WinUI/SkiaSharp.Views.Uno.WinUI.csproj index d325665ab0..2fd3ed249a 100644 --- a/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.WinUI/SkiaSharp.Views.Uno.WinUI.csproj +++ b/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.WinUI/SkiaSharp.Views.Uno.WinUI.csproj @@ -65,7 +65,7 @@ - + diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.Shared/GlesInterop/Gles.cs b/source/SkiaSharp.Views/SkiaSharp.Views.Shared/GlesInterop/Gles.cs index 2630aca7dd..4df486b4e5 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.Shared/GlesInterop/Gles.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.Shared/GlesInterop/Gles.cs @@ -1,4 +1,4 @@ -#if !__WASM__ && (!UNO_REFERENCE_API || (NET6_0_OR_GREATER && (__IOS__ || __MACOS__))) +#if !__WASM__ && (!UNO_REFERENCE_API || (NET6_0_OR_GREATER && (__IOS__ || __MACOS__))) && !MACCATALYST // Note that `(!UNO_REFERENCE_API || (NET6_0_OR_GREATER && (__IOS__ || __MACOS__)))` is required // because of https://github.com/unoplatform/uno/issues/8814, where !UNO_REFERENCE_API should be enough. diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.Shared/SKPaintGLSurfaceEventArgs.cs b/source/SkiaSharp.Views/SkiaSharp.Views.Shared/SKPaintGLSurfaceEventArgs.cs index 08122bdccf..cc86bfb368 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.Shared/SKPaintGLSurfaceEventArgs.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.Shared/SKPaintGLSurfaceEventArgs.cs @@ -1,4 +1,5 @@ -using System; +#if !MACCATALYST || HAS_UNO_WINUI +using System; using System.ComponentModel; #if HAS_UNO_WINUI @@ -68,3 +69,4 @@ public SKPaintGLSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget render public SKImageInfo RawInfo { get; private set; } } } +#endif diff --git a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKPaintMetalSurfaceEventArgs.cs b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKPaintMetalSurfaceEventArgs.cs index b81803f403..fa840facd4 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKPaintMetalSurfaceEventArgs.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKPaintMetalSurfaceEventArgs.cs @@ -20,6 +20,23 @@ public SKPaintMetalSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget ren BackendRenderTarget = renderTarget; ColorType = colorType; Origin = origin; + Info = new SKImageInfo(renderTarget.Width, renderTarget.Height, ColorType); + RawInfo = Info; + } + + public SKPaintMetalSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget renderTarget, GRSurfaceOrigin origin, SKImageInfo info) + : this(surface, renderTarget, origin, info, info) + { + } + + public SKPaintMetalSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget renderTarget, GRSurfaceOrigin origin, SKImageInfo info, SKImageInfo rawInfo) + { + Surface = surface; + BackendRenderTarget = renderTarget; + ColorType = info.ColorType; + Origin = origin; + Info = info; + RawInfo = rawInfo; } public SKSurface Surface { get; private set; } @@ -29,6 +46,10 @@ public SKPaintMetalSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget ren public SKColorType ColorType { get; private set; } public GRSurfaceOrigin Origin { get; private set; } + + public SKImageInfo Info { get; private set; } + + public SKImageInfo RawInfo { get; private set; } } } #endif From bc27021530456b132df8906f8446e016b6fdffd4 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Mon, 12 Feb 2024 21:18:10 +0200 Subject: [PATCH 15/40] Fix the script for mac (#2749) --- scripts/install-android-package.ps1 | 2 +- scripts/install-android-platform.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/install-android-package.ps1 b/scripts/install-android-package.ps1 index d646abfb89..eda63e2606 100644 --- a/scripts/install-android-package.ps1 +++ b/scripts/install-android-package.ps1 @@ -21,7 +21,7 @@ $sdkmanager = Join-Path "$latest" "bin" "sdkmanager$ext" Set-Content -Value "y" -Path "yes.txt" try { if ($IsMacOS -or $IsLinux) { - sh -c "`"$sdkmanager`" `"$($Package.Replace(';', '\;'))`" < yes.txt" + sh -c "'$sdkmanager' '$Package' < yes.txt" } else { cmd /c "`"$sdkmanager`" `"$Package`" < yes.txt" } diff --git a/scripts/install-android-platform.ps1 b/scripts/install-android-platform.ps1 index 3876ae015e..0e418e1cef 100644 --- a/scripts/install-android-platform.ps1 +++ b/scripts/install-android-platform.ps1 @@ -27,7 +27,7 @@ $sdkmanager = Join-Path "$latest" "bin" "sdkmanager$ext" Set-Content -Value "y" -Path "yes.txt" try { if ($IsMacOS -or $IsLinux) { - sh -c "`"$sdkmanager`" `"platforms\;android-$API`" < yes.txt" + sh -c "'$sdkmanager' 'platforms;android-$API' < yes.txt" } else { cmd /c "`"$sdkmanager`" `"platforms;android-$API`" < yes.txt" } From c4fd517f647b179ee895680e529eeede2103356e Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Mon, 12 Feb 2024 21:19:45 +0200 Subject: [PATCH 16/40] Add the Vulcanized compiler options (#2753) --- .../SkiaSharp.Views.WinUI.Native.vcxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.vcxproj b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.vcxproj index 44c4f7dfda..3906b7d76f 100644 --- a/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.vcxproj +++ b/native/winui/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native/SkiaSharp.Views.WinUI.Native.vcxproj @@ -117,6 +117,7 @@ Console true SkiaSharp_Views_WinUI_Native.def + /DEBUGTYPE:CV,FIXUP From 42fc0181e0f9d2cda2d7f4f9359de2dd5252fcc1 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Sun, 18 Feb 2024 17:33:24 +0200 Subject: [PATCH 17/40] Bind Skottie's Animation Builder (#2630) --- benchmarks/SkiaSharp.Benchmarks.sln | 2 + .../SkiaSharpResourcesAssemblyInfo.cs | 36 +++ .../SkiaSharp.Resources/ResourceProvider.cs | 64 +++++ binding/SkiaSharp.Resources/ResourcesApi.cs | 23 ++ .../ResourcesApi.generated.cs | 267 ++++++++++++++++++ .../SkiaSharp.Resources.csproj | 18 ++ .../SceneGraphApi.generated.cs | 4 + binding/SkiaSharp.Skottie/Animation.cs | 7 + binding/SkiaSharp.Skottie/AnimationBuilder.cs | 88 ++++++ .../AnimationBuilderStats.cs | 21 ++ .../SkiaSharp.Skottie.csproj | 1 + .../SkiaSharp.Skottie/SkottieApi.generated.cs | 200 ++++++++++++- .../Properties/SkiaSharpAssemblyInfo.cs | 7 + binding/SkiaSharp/SKData.cs | 18 +- binding/SkiaSharp/SKObject.cs | 16 +- binding/SkiaSharp/SkiaApi.generated.cs | 4 + binding/libSkiaSharp.Resources.json | 86 ++++++ binding/libSkiaSharp.SceneGraph.json | 3 + binding/libSkiaSharp.Skottie.json | 7 + binding/libSkiaSharp.json | 3 + build.cake | 1 + externals/skia | 2 +- native/linux/libSkiaSharp/libSkiaSharp.map | 1 + scripts/VERSIONS.txt | 1 + source/SkiaSharpSource.Linux.slnf | 1 + source/SkiaSharpSource.Mac.slnf | 1 + source/SkiaSharpSource.Windows.slnf | 1 + source/SkiaSharpSource.sln | 10 + .../images/lottie-base64_dotnet-bot.json | 1 + .../images/lottie-base64_women-thinking.json | 1 + tests/SkiaSharp.Tests.Console.sln | 15 + .../SkiaSharp.Tests.Console.csproj | 1 + .../SkiaSharp/SKBitmapThreadingTest.cs | 1 + tests/SkiaSharp.Tests.Devices.sln | 7 + .../SkiaSharp.Tests.Devices.csproj | 1 + tests/SkiaSharp.Tests.Wasm.sln | 7 + .../SkiaSharp.Tests.Wasm.csproj | 1 + tests/SkiaSharp.Tests/SkiaSharp.Tests.csproj | 1 + tests/Tests/Resources/ResourceProviderTest.cs | 81 ++++++ tests/Tests/SkiaSharp/SKDrawableTest.cs | 35 +++ tests/Tests/Skottie/AnimationBuilderTest.cs | 141 +++++++++ tests/Tests/Skottie/AnimationTest.cs | 41 ++- utils/README.md | 5 +- .../SkiaSharpGenerator.csproj | 8 +- utils/generate.ps1 | 5 + 45 files changed, 1219 insertions(+), 26 deletions(-) create mode 100644 binding/SkiaSharp.Resources/Properties/SkiaSharpResourcesAssemblyInfo.cs create mode 100644 binding/SkiaSharp.Resources/ResourceProvider.cs create mode 100644 binding/SkiaSharp.Resources/ResourcesApi.cs create mode 100644 binding/SkiaSharp.Resources/ResourcesApi.generated.cs create mode 100644 binding/SkiaSharp.Resources/SkiaSharp.Resources.csproj create mode 100644 binding/SkiaSharp.Skottie/AnimationBuilder.cs create mode 100644 binding/SkiaSharp.Skottie/AnimationBuilderStats.cs create mode 100644 binding/libSkiaSharp.Resources.json create mode 100644 tests/Content/images/lottie-base64_dotnet-bot.json create mode 100644 tests/Content/images/lottie-base64_women-thinking.json create mode 100644 tests/Tests/Resources/ResourceProviderTest.cs create mode 100644 tests/Tests/Skottie/AnimationBuilderTest.cs create mode 100644 utils/generate.ps1 diff --git a/benchmarks/SkiaSharp.Benchmarks.sln b/benchmarks/SkiaSharp.Benchmarks.sln index aea131389d..12dcd8fba7 100644 --- a/benchmarks/SkiaSharp.Benchmarks.sln +++ b/benchmarks/SkiaSharp.Benchmarks.sln @@ -13,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Benchmarks", "Ski EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.SceneGraph", "..\binding\SkiaSharp.SceneGraph\SkiaSharp.SceneGraph.csproj", "{42B5D998-A676-4B50-B558-1D3ACA7D3FC4}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Resources", "..\binding\SkiaSharp.Resources\SkiaSharp.Resources.csproj", "{AD2C6978-4F5E-E592-B565-26C357877B2C}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Skottie", "..\binding\SkiaSharp.Skottie\SkiaSharp.Skottie.csproj", "{DD03EAA1-A85D-4588-8B84-8285EC1979C8}" EndProject Global diff --git a/binding/SkiaSharp.Resources/Properties/SkiaSharpResourcesAssemblyInfo.cs b/binding/SkiaSharp.Resources/Properties/SkiaSharpResourcesAssemblyInfo.cs new file mode 100644 index 0000000000..32dd31681e --- /dev/null +++ b/binding/SkiaSharp.Resources/Properties/SkiaSharpResourcesAssemblyInfo.cs @@ -0,0 +1,36 @@ +using System; +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; + +[assembly: AssemblyTitle("SkiaSharp.Resources")] +[assembly: AssemblyDescription("This package adds lottie support to SkiaSharp via skottie.")] +[assembly: AssemblyCompany("Microsoft Corporation")] +[assembly: AssemblyProduct("SkiaSharp")] +[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] +[assembly: NeutralResourcesLanguage("en")] + +[assembly: InternalsVisibleTo("SkiaSharp.Tests, PublicKey=" + + "002400000480000094000000060200000024000052534131000400000100010079159977d2d03a" + + "8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c" + + "3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fd" + + "dafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef00" + + "65d016df")] + +[assembly: InternalsVisibleTo("SkiaSharp.Benchmarks, PublicKey=" + + "002400000480000094000000060200000024000052534131000400000100010079159977d2d03a" + + "8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c" + + "3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fd" + + "dafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef00" + + "65d016df")] + +[assembly: AssemblyMetadata("IsTrimmable", "True")] + +#if __IOS__ || __TVOS__ || __MACOS__ +// This attribute allows you to mark your assemblies as “safe to link”. +// When the attribute is present, the linker—if enabled—will process the assembly +// even if you’re using the “Link SDK assemblies only” option, which is the default for device builds. +#pragma warning disable CS0618 // Type or member is obsolete +[assembly: Foundation.LinkerSafe] +#pragma warning restore CS0618 // Type or member is obsolete +#endif diff --git a/binding/SkiaSharp.Resources/ResourceProvider.cs b/binding/SkiaSharp.Resources/ResourceProvider.cs new file mode 100644 index 0000000000..5b22bc5c7d --- /dev/null +++ b/binding/SkiaSharp.Resources/ResourceProvider.cs @@ -0,0 +1,64 @@ +using System; + +namespace SkiaSharp.Resources +{ + public abstract unsafe class ResourceProvider : SKObject, ISKReferenceCounted, ISKSkipObjectRegistration + { + internal ResourceProvider (IntPtr handle, bool owns) + : base (handle, owns) + { + } + + public SKData? Load (string resourceName) => + Load ("", resourceName); + + public SKData? Load (string resourcePath, string resourceName) => + SKData.GetObject (ResourcesApi.skresources_resource_provider_load (Handle, resourcePath, resourceName)); + } + + public sealed class CachingResourceProvider : ResourceProvider + { + public CachingResourceProvider (ResourceProvider resourceProvider) + : base (Create (resourceProvider), true) + { + Referenced(this, resourceProvider); + } + + private static IntPtr Create (ResourceProvider resourceProvider) + { + _ = resourceProvider ?? throw new ArgumentNullException (nameof (resourceProvider)); + return ResourcesApi.skresources_caching_resource_provider_proxy_make (resourceProvider.Handle); + } + } + + public sealed class DataUriResourceProvider : ResourceProvider + { + public DataUriResourceProvider (bool preDecode = false) + : this (null, preDecode) + { + } + + public DataUriResourceProvider (ResourceProvider? fallbackProvider, bool preDecode = false) + : base (Create (fallbackProvider, preDecode), true) + { + Referenced (this, fallbackProvider); + } + + private static IntPtr Create (ResourceProvider? fallbackProvider, bool preDecode = false) => + ResourcesApi.skresources_data_uri_resource_provider_proxy_make (fallbackProvider?.Handle ?? IntPtr.Zero, preDecode); + } + + public sealed class FileResourceProvider : ResourceProvider + { + public FileResourceProvider (string baseDirectory, bool preDecode = false) + : base (Create (baseDirectory, preDecode), true) + { + } + + private static IntPtr Create (string baseDirectory, bool preDecode) + { + using var baseDir = new SKString(baseDirectory ?? throw new ArgumentNullException (nameof (baseDirectory))); + return ResourcesApi.skresources_file_resource_provider_make (baseDir.Handle, preDecode); + } + } +} diff --git a/binding/SkiaSharp.Resources/ResourcesApi.cs b/binding/SkiaSharp.Resources/ResourcesApi.cs new file mode 100644 index 0000000000..06438cd026 --- /dev/null +++ b/binding/SkiaSharp.Resources/ResourcesApi.cs @@ -0,0 +1,23 @@ +#nullable disable + +using System; + +namespace SkiaSharp +{ + internal partial class ResourcesApi + { +#if __IOS__ || __TVOS__ + private const string SKIA = "@rpath/libSkiaSharp.framework/libSkiaSharp"; +#else + private const string SKIA = "libSkiaSharp"; +#endif + +#if USE_DELEGATES + private static readonly Lazy libSkiaSharpHandle = + new Lazy (() => LibraryLoader.LoadLocalLibrary (SKIA)); + + private static T GetSymbol (string name) where T : Delegate => + LibraryLoader.GetSymbolDelegate (libSkiaSharpHandle.Value, name); +#endif + } +} diff --git a/binding/SkiaSharp.Resources/ResourcesApi.generated.cs b/binding/SkiaSharp.Resources/ResourcesApi.generated.cs new file mode 100644 index 0000000000..c5442998d7 --- /dev/null +++ b/binding/SkiaSharp.Resources/ResourcesApi.generated.cs @@ -0,0 +1,267 @@ +using System; +using System.Runtime.InteropServices; + +#region Namespaces + +using SkiaSharp.Resources; + +#endregion + +#region Class declarations + +using gr_backendrendertarget_t = System.IntPtr; +using gr_backendtexture_t = System.IntPtr; +using gr_direct_context_t = System.IntPtr; +using gr_glinterface_t = System.IntPtr; +using gr_recording_context_t = System.IntPtr; +using gr_vk_extensions_t = System.IntPtr; +using gr_vk_memory_allocator_t = System.IntPtr; +using gr_vkinterface_t = System.IntPtr; +using sk_bitmap_t = System.IntPtr; +using sk_canvas_t = System.IntPtr; +using sk_codec_t = System.IntPtr; +using sk_colorfilter_t = System.IntPtr; +using sk_colorspace_icc_profile_t = System.IntPtr; +using sk_colorspace_t = System.IntPtr; +using sk_compatpaint_t = System.IntPtr; +using sk_data_t = System.IntPtr; +using sk_document_t = System.IntPtr; +using sk_drawable_t = System.IntPtr; +using sk_flattenable_t = System.IntPtr; +using sk_font_t = System.IntPtr; +using sk_fontmgr_t = System.IntPtr; +using sk_fontstyle_t = System.IntPtr; +using sk_fontstyleset_t = System.IntPtr; +using sk_image_t = System.IntPtr; +using sk_imagefilter_t = System.IntPtr; +using sk_manageddrawable_t = System.IntPtr; +using sk_managedtracememorydump_t = System.IntPtr; +using sk_maskfilter_t = System.IntPtr; +using sk_nodraw_canvas_t = System.IntPtr; +using sk_nvrefcnt_t = System.IntPtr; +using sk_nway_canvas_t = System.IntPtr; +using sk_opbuilder_t = System.IntPtr; +using sk_overdraw_canvas_t = System.IntPtr; +using sk_paint_t = System.IntPtr; +using sk_path_effect_t = System.IntPtr; +using sk_path_iterator_t = System.IntPtr; +using sk_path_rawiterator_t = System.IntPtr; +using sk_path_t = System.IntPtr; +using sk_pathmeasure_t = System.IntPtr; +using sk_picture_recorder_t = System.IntPtr; +using sk_picture_t = System.IntPtr; +using sk_pixelref_factory_t = System.IntPtr; +using sk_pixmap_t = System.IntPtr; +using sk_refcnt_t = System.IntPtr; +using sk_region_cliperator_t = System.IntPtr; +using sk_region_iterator_t = System.IntPtr; +using sk_region_spanerator_t = System.IntPtr; +using sk_region_t = System.IntPtr; +using sk_rrect_t = System.IntPtr; +using sk_runtimeeffect_t = System.IntPtr; +using sk_shader_t = System.IntPtr; +using sk_stream_asset_t = System.IntPtr; +using sk_stream_filestream_t = System.IntPtr; +using sk_stream_managedstream_t = System.IntPtr; +using sk_stream_memorystream_t = System.IntPtr; +using sk_stream_streamrewindable_t = System.IntPtr; +using sk_stream_t = System.IntPtr; +using sk_string_t = System.IntPtr; +using sk_surface_t = System.IntPtr; +using sk_surfaceprops_t = System.IntPtr; +using sk_svgcanvas_t = System.IntPtr; +using sk_textblob_builder_t = System.IntPtr; +using sk_textblob_t = System.IntPtr; +using sk_tracememorydump_t = System.IntPtr; +using sk_typeface_t = System.IntPtr; +using sk_vertices_t = System.IntPtr; +using sk_wstream_dynamicmemorystream_t = System.IntPtr; +using sk_wstream_filestream_t = System.IntPtr; +using sk_wstream_managedstream_t = System.IntPtr; +using sk_wstream_t = System.IntPtr; +using skottie_animation_builder_t = System.IntPtr; +using skottie_animation_t = System.IntPtr; +using skottie_logger_t = System.IntPtr; +using skottie_marker_observer_t = System.IntPtr; +using skottie_property_observer_t = System.IntPtr; +using skottie_resource_provider_t = System.IntPtr; +using skresources_external_track_asset_t = System.IntPtr; +using skresources_image_asset_t = System.IntPtr; +using skresources_multi_frame_image_asset_t = System.IntPtr; +using skresources_resource_provider_t = System.IntPtr; +using sksg_invalidation_controller_t = System.IntPtr; +using vk_device_t = System.IntPtr; +using vk_instance_t = System.IntPtr; +using vk_physical_device_features_2_t = System.IntPtr; +using vk_physical_device_features_t = System.IntPtr; +using vk_physical_device_t = System.IntPtr; +using vk_queue_t = System.IntPtr; + +#endregion + +#region Functions + +namespace SkiaSharp +{ + internal unsafe partial class ResourcesApi + { + #region skresources_resource_provider.h + + // skresources_resource_provider_t* skresources_caching_resource_provider_proxy_make(skresources_resource_provider_t* rp) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern skresources_resource_provider_t skresources_caching_resource_provider_proxy_make (skresources_resource_provider_t rp); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate skresources_resource_provider_t skresources_caching_resource_provider_proxy_make (skresources_resource_provider_t rp); + } + private static Delegates.skresources_caching_resource_provider_proxy_make skresources_caching_resource_provider_proxy_make_delegate; + internal static skresources_resource_provider_t skresources_caching_resource_provider_proxy_make (skresources_resource_provider_t rp) => + (skresources_caching_resource_provider_proxy_make_delegate ??= GetSymbol ("skresources_caching_resource_provider_proxy_make")).Invoke (rp); + #endif + + // skresources_resource_provider_t* skresources_data_uri_resource_provider_proxy_make(skresources_resource_provider_t* rp, bool predecode) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern skresources_resource_provider_t skresources_data_uri_resource_provider_proxy_make (skresources_resource_provider_t rp, [MarshalAs (UnmanagedType.I1)] bool predecode); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate skresources_resource_provider_t skresources_data_uri_resource_provider_proxy_make (skresources_resource_provider_t rp, [MarshalAs (UnmanagedType.I1)] bool predecode); + } + private static Delegates.skresources_data_uri_resource_provider_proxy_make skresources_data_uri_resource_provider_proxy_make_delegate; + internal static skresources_resource_provider_t skresources_data_uri_resource_provider_proxy_make (skresources_resource_provider_t rp, [MarshalAs (UnmanagedType.I1)] bool predecode) => + (skresources_data_uri_resource_provider_proxy_make_delegate ??= GetSymbol ("skresources_data_uri_resource_provider_proxy_make")).Invoke (rp, predecode); + #endif + + // skresources_resource_provider_t* skresources_file_resource_provider_make(sk_string_t* base_dir, bool predecode) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern skresources_resource_provider_t skresources_file_resource_provider_make (sk_string_t base_dir, [MarshalAs (UnmanagedType.I1)] bool predecode); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate skresources_resource_provider_t skresources_file_resource_provider_make (sk_string_t base_dir, [MarshalAs (UnmanagedType.I1)] bool predecode); + } + private static Delegates.skresources_file_resource_provider_make skresources_file_resource_provider_make_delegate; + internal static skresources_resource_provider_t skresources_file_resource_provider_make (sk_string_t base_dir, [MarshalAs (UnmanagedType.I1)] bool predecode) => + (skresources_file_resource_provider_make_delegate ??= GetSymbol ("skresources_file_resource_provider_make")).Invoke (base_dir, predecode); + #endif + + // void skresources_resource_provider_delete(skresources_resource_provider_t* instance) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void skresources_resource_provider_delete (skresources_resource_provider_t instance); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void skresources_resource_provider_delete (skresources_resource_provider_t instance); + } + private static Delegates.skresources_resource_provider_delete skresources_resource_provider_delete_delegate; + internal static void skresources_resource_provider_delete (skresources_resource_provider_t instance) => + (skresources_resource_provider_delete_delegate ??= GetSymbol ("skresources_resource_provider_delete")).Invoke (instance); + #endif + + // sk_data_t* skresources_resource_provider_load(skresources_resource_provider_t* instance, const char* path, const char* name) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern sk_data_t skresources_resource_provider_load (skresources_resource_provider_t instance, [MarshalAs (UnmanagedType.LPStr)] String path, [MarshalAs (UnmanagedType.LPStr)] String name); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate sk_data_t skresources_resource_provider_load (skresources_resource_provider_t instance, [MarshalAs (UnmanagedType.LPStr)] String path, [MarshalAs (UnmanagedType.LPStr)] String name); + } + private static Delegates.skresources_resource_provider_load skresources_resource_provider_load_delegate; + internal static sk_data_t skresources_resource_provider_load (skresources_resource_provider_t instance, [MarshalAs (UnmanagedType.LPStr)] String path, [MarshalAs (UnmanagedType.LPStr)] String name) => + (skresources_resource_provider_load_delegate ??= GetSymbol ("skresources_resource_provider_load")).Invoke (instance, path, name); + #endif + + // skresources_external_track_asset_t* skresources_resource_provider_load_audio_asset(skresources_resource_provider_t* instance, const char* path, const char* name, const char* id) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern skresources_external_track_asset_t skresources_resource_provider_load_audio_asset (skresources_resource_provider_t instance, [MarshalAs (UnmanagedType.LPStr)] String path, [MarshalAs (UnmanagedType.LPStr)] String name, [MarshalAs (UnmanagedType.LPStr)] String id); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate skresources_external_track_asset_t skresources_resource_provider_load_audio_asset (skresources_resource_provider_t instance, [MarshalAs (UnmanagedType.LPStr)] String path, [MarshalAs (UnmanagedType.LPStr)] String name, [MarshalAs (UnmanagedType.LPStr)] String id); + } + private static Delegates.skresources_resource_provider_load_audio_asset skresources_resource_provider_load_audio_asset_delegate; + internal static skresources_external_track_asset_t skresources_resource_provider_load_audio_asset (skresources_resource_provider_t instance, [MarshalAs (UnmanagedType.LPStr)] String path, [MarshalAs (UnmanagedType.LPStr)] String name, [MarshalAs (UnmanagedType.LPStr)] String id) => + (skresources_resource_provider_load_audio_asset_delegate ??= GetSymbol ("skresources_resource_provider_load_audio_asset")).Invoke (instance, path, name, id); + #endif + + // skresources_image_asset_t* skresources_resource_provider_load_image_asset(skresources_resource_provider_t* instance, const char* path, const char* name, const char* id) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern skresources_image_asset_t skresources_resource_provider_load_image_asset (skresources_resource_provider_t instance, [MarshalAs (UnmanagedType.LPStr)] String path, [MarshalAs (UnmanagedType.LPStr)] String name, [MarshalAs (UnmanagedType.LPStr)] String id); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate skresources_image_asset_t skresources_resource_provider_load_image_asset (skresources_resource_provider_t instance, [MarshalAs (UnmanagedType.LPStr)] String path, [MarshalAs (UnmanagedType.LPStr)] String name, [MarshalAs (UnmanagedType.LPStr)] String id); + } + private static Delegates.skresources_resource_provider_load_image_asset skresources_resource_provider_load_image_asset_delegate; + internal static skresources_image_asset_t skresources_resource_provider_load_image_asset (skresources_resource_provider_t instance, [MarshalAs (UnmanagedType.LPStr)] String path, [MarshalAs (UnmanagedType.LPStr)] String name, [MarshalAs (UnmanagedType.LPStr)] String id) => + (skresources_resource_provider_load_image_asset_delegate ??= GetSymbol ("skresources_resource_provider_load_image_asset")).Invoke (instance, path, name, id); + #endif + + // sk_typeface_t* skresources_resource_provider_load_typeface(skresources_resource_provider_t* instance, const char* name, const char* url) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern sk_typeface_t skresources_resource_provider_load_typeface (skresources_resource_provider_t instance, [MarshalAs (UnmanagedType.LPStr)] String name, [MarshalAs (UnmanagedType.LPStr)] String url); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate sk_typeface_t skresources_resource_provider_load_typeface (skresources_resource_provider_t instance, [MarshalAs (UnmanagedType.LPStr)] String name, [MarshalAs (UnmanagedType.LPStr)] String url); + } + private static Delegates.skresources_resource_provider_load_typeface skresources_resource_provider_load_typeface_delegate; + internal static sk_typeface_t skresources_resource_provider_load_typeface (skresources_resource_provider_t instance, [MarshalAs (UnmanagedType.LPStr)] String name, [MarshalAs (UnmanagedType.LPStr)] String url) => + (skresources_resource_provider_load_typeface_delegate ??= GetSymbol ("skresources_resource_provider_load_typeface")).Invoke (instance, name, url); + #endif + + // void skresources_resource_provider_ref(skresources_resource_provider_t* instance) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void skresources_resource_provider_ref (skresources_resource_provider_t instance); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void skresources_resource_provider_ref (skresources_resource_provider_t instance); + } + private static Delegates.skresources_resource_provider_ref skresources_resource_provider_ref_delegate; + internal static void skresources_resource_provider_ref (skresources_resource_provider_t instance) => + (skresources_resource_provider_ref_delegate ??= GetSymbol ("skresources_resource_provider_ref")).Invoke (instance); + #endif + + // void skresources_resource_provider_unref(skresources_resource_provider_t* instance) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void skresources_resource_provider_unref (skresources_resource_provider_t instance); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void skresources_resource_provider_unref (skresources_resource_provider_t instance); + } + private static Delegates.skresources_resource_provider_unref skresources_resource_provider_unref_delegate; + internal static void skresources_resource_provider_unref (skresources_resource_provider_t instance) => + (skresources_resource_provider_unref_delegate ??= GetSymbol ("skresources_resource_provider_unref")).Invoke (instance); + #endif + + #endregion + + } +} + +#endregion Functions + +#region Delegates + +#endregion + +#region Structs + +#endregion + +#region Enums + +#endregion diff --git a/binding/SkiaSharp.Resources/SkiaSharp.Resources.csproj b/binding/SkiaSharp.Resources/SkiaSharp.Resources.csproj new file mode 100644 index 0000000000..87ee248726 --- /dev/null +++ b/binding/SkiaSharp.Resources/SkiaSharp.Resources.csproj @@ -0,0 +1,18 @@ + + + $(AllTargetFrameworks) + SkiaSharp.Resources + SkiaSharp.Resources + SkiaSharp.Resources + SkiaSharp Resource Providers + SkiaSharp Skottie provides a Lottie implementation using the SkiaSharp library. + skottie;lottie + enable + + + $(DefineConstants);USE_DELEGATES + + + + + \ No newline at end of file diff --git a/binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs b/binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs index a3b6ab1f96..29c4929b88 100644 --- a/binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs +++ b/binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs @@ -85,6 +85,10 @@ using skottie_marker_observer_t = System.IntPtr; using skottie_property_observer_t = System.IntPtr; using skottie_resource_provider_t = System.IntPtr; +using skresources_external_track_asset_t = System.IntPtr; +using skresources_image_asset_t = System.IntPtr; +using skresources_multi_frame_image_asset_t = System.IntPtr; +using skresources_resource_provider_t = System.IntPtr; using sksg_invalidation_controller_t = System.IntPtr; using vk_device_t = System.IntPtr; using vk_instance_t = System.IntPtr; diff --git a/binding/SkiaSharp.Skottie/Animation.cs b/binding/SkiaSharp.Skottie/Animation.cs index a6ad5ae5b9..a7360d7328 100644 --- a/binding/SkiaSharp.Skottie/Animation.cs +++ b/binding/SkiaSharp.Skottie/Animation.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using SkiaSharp.Resources; using SkiaSharp.SceneGraph; namespace SkiaSharp.Skottie @@ -20,6 +21,11 @@ void ISKNonVirtualReferenceCounted.UnreferenceNative () protected override void DisposeNative () => SkottieApi.skottie_animation_delete (Handle); + // AnimationBuilder + + public static AnimationBuilder CreateBuilder (AnimationBuilderFlags flags = AnimationBuilderFlags.None) => + new AnimationBuilder (flags); + // Parse public static Animation? Parse (string json) => @@ -77,6 +83,7 @@ public static bool TryCreate (SKData data, [System.Diagnostics.CodeAnalysis.NotN fixed (byte* ptr = span) { animation = GetObject (SkottieApi.skottie_animation_make_from_data (ptr, (IntPtr)span.Length)); + GC.KeepAlive(data); return animation != null; } } diff --git a/binding/SkiaSharp.Skottie/AnimationBuilder.cs b/binding/SkiaSharp.Skottie/AnimationBuilder.cs new file mode 100644 index 0000000000..b84f563a36 --- /dev/null +++ b/binding/SkiaSharp.Skottie/AnimationBuilder.cs @@ -0,0 +1,88 @@ +using System; +using System.IO; +using SkiaSharp.Resources; + +namespace SkiaSharp.Skottie +{ + public sealed unsafe class AnimationBuilder : SKObject, ISKSkipObjectRegistration + { + internal AnimationBuilder (AnimationBuilderFlags flags) + : this (SkottieApi.skottie_animation_builder_new (flags), true) + { + } + + internal AnimationBuilder (IntPtr handle, bool owns) + : base (handle, owns) + { + } + + public AnimationBuilder SetFontManager (SKFontManager fontManager) + { + _ = fontManager ?? throw new ArgumentNullException (nameof (fontManager)); + SkottieApi.skottie_animation_builder_set_font_manager (Handle, fontManager.Handle); + Referenced (this, fontManager); + return this; + } + + public AnimationBuilder SetResourceProvider (ResourceProvider resourceProvider) + { + _ = resourceProvider ?? throw new ArgumentNullException (nameof (resourceProvider)); + SkottieApi.skottie_animation_builder_set_resource_provider (Handle, resourceProvider.Handle); + Referenced (this, resourceProvider); + return this; + } + + public AnimationBuilderStats Stats + { + get + { + AnimationBuilderStats stats; + SkottieApi.skottie_animation_builder_get_stats (Handle, &stats); + return stats; + } + } + + public Animation? Build (Stream stream) + { + _ = stream ?? throw new ArgumentNullException (nameof (stream)); + + using var data = SKData.Create (stream); + return Build (data); + } + + public Animation? Build (SKStream stream) + { + _ = stream ?? throw new ArgumentNullException (nameof (stream)); + + using var data = SKData.Create (stream); + return Build (data); + } + + public Animation? Build (SKData data) + { + _ = data ?? throw new ArgumentNullException (nameof (data)); + + var preamble = Utils.GetPreambleSize (data); + var span = data.AsSpan ().Slice (preamble); + + fixed (byte* ptr = span) { + try { + return Animation.GetObject (SkottieApi.skottie_animation_builder_make_from_data (Handle, ptr, (IntPtr)span.Length)); + } finally { + GC.KeepAlive(data); + } + } + } + + public Animation? Build (string path) + { + _ = path ?? throw new ArgumentNullException (nameof (path)); + + using var data = SKData.Create (path); + return Build (data); + } + + protected override void DisposeNative () + => SkottieApi.skottie_animation_builder_delete (Handle); + } +} diff --git a/binding/SkiaSharp.Skottie/AnimationBuilderStats.cs b/binding/SkiaSharp.Skottie/AnimationBuilderStats.cs new file mode 100644 index 0000000000..42d9e48efd --- /dev/null +++ b/binding/SkiaSharp.Skottie/AnimationBuilderStats.cs @@ -0,0 +1,21 @@ + +using System; + +namespace SkiaSharp.Skottie +{ + public partial struct AnimationBuilderStats + { + public readonly TimeSpan TotalLoadTime => + TimeSpan.FromMilliseconds (fTotalLoadTimeMS); + + public readonly TimeSpan JsonParseTime => + TimeSpan.FromMilliseconds (fJsonParseTimeMS); + + public readonly TimeSpan SceneParseTime => + TimeSpan.FromMilliseconds (fSceneParseTimeMS); + + public readonly int JsonSize => (int)fJsonSize; + + public readonly int AnimatorCount => (int)fAnimatorCount; + } +} diff --git a/binding/SkiaSharp.Skottie/SkiaSharp.Skottie.csproj b/binding/SkiaSharp.Skottie/SkiaSharp.Skottie.csproj index 8947f56b39..4fd4ef3112 100644 --- a/binding/SkiaSharp.Skottie/SkiaSharp.Skottie.csproj +++ b/binding/SkiaSharp.Skottie/SkiaSharp.Skottie.csproj @@ -15,5 +15,6 @@ + \ No newline at end of file diff --git a/binding/SkiaSharp.Skottie/SkottieApi.generated.cs b/binding/SkiaSharp.Skottie/SkottieApi.generated.cs index 8bcc631ec4..9ea5421504 100644 --- a/binding/SkiaSharp.Skottie/SkottieApi.generated.cs +++ b/binding/SkiaSharp.Skottie/SkottieApi.generated.cs @@ -85,6 +85,10 @@ using skottie_marker_observer_t = System.IntPtr; using skottie_property_observer_t = System.IntPtr; using skottie_resource_provider_t = System.IntPtr; +using skresources_external_track_asset_t = System.IntPtr; +using skresources_image_asset_t = System.IntPtr; +using skresources_multi_frame_image_asset_t = System.IntPtr; +using skresources_resource_provider_t = System.IntPtr; using sksg_invalidation_controller_t = System.IntPtr; using vk_device_t = System.IntPtr; using vk_instance_t = System.IntPtr; @@ -103,6 +107,132 @@ internal unsafe partial class SkottieApi { #region skottie_animation.h + // void skottie_animation_builder_delete(skottie_animation_builder_t* instance) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void skottie_animation_builder_delete (skottie_animation_builder_t instance); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void skottie_animation_builder_delete (skottie_animation_builder_t instance); + } + private static Delegates.skottie_animation_builder_delete skottie_animation_builder_delete_delegate; + internal static void skottie_animation_builder_delete (skottie_animation_builder_t instance) => + (skottie_animation_builder_delete_delegate ??= GetSymbol ("skottie_animation_builder_delete")).Invoke (instance); + #endif + + // void skottie_animation_builder_get_stats(skottie_animation_builder_t* instance, skottie_animation_builder_stats_t* stats) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void skottie_animation_builder_get_stats (skottie_animation_builder_t instance, AnimationBuilderStats* stats); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void skottie_animation_builder_get_stats (skottie_animation_builder_t instance, AnimationBuilderStats* stats); + } + private static Delegates.skottie_animation_builder_get_stats skottie_animation_builder_get_stats_delegate; + internal static void skottie_animation_builder_get_stats (skottie_animation_builder_t instance, AnimationBuilderStats* stats) => + (skottie_animation_builder_get_stats_delegate ??= GetSymbol ("skottie_animation_builder_get_stats")).Invoke (instance, stats); + #endif + + // skottie_animation_t* skottie_animation_builder_make_from_data(skottie_animation_builder_t* instance, const char* data, size_t length) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern skottie_animation_t skottie_animation_builder_make_from_data (skottie_animation_builder_t instance, /* char */ void* data, /* size_t */ IntPtr length); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate skottie_animation_t skottie_animation_builder_make_from_data (skottie_animation_builder_t instance, /* char */ void* data, /* size_t */ IntPtr length); + } + private static Delegates.skottie_animation_builder_make_from_data skottie_animation_builder_make_from_data_delegate; + internal static skottie_animation_t skottie_animation_builder_make_from_data (skottie_animation_builder_t instance, /* char */ void* data, /* size_t */ IntPtr length) => + (skottie_animation_builder_make_from_data_delegate ??= GetSymbol ("skottie_animation_builder_make_from_data")).Invoke (instance, data, length); + #endif + + // skottie_animation_t* skottie_animation_builder_make_from_file(skottie_animation_builder_t* instance, const char* path) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern skottie_animation_t skottie_animation_builder_make_from_file (skottie_animation_builder_t instance, /* char */ void* path); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate skottie_animation_t skottie_animation_builder_make_from_file (skottie_animation_builder_t instance, /* char */ void* path); + } + private static Delegates.skottie_animation_builder_make_from_file skottie_animation_builder_make_from_file_delegate; + internal static skottie_animation_t skottie_animation_builder_make_from_file (skottie_animation_builder_t instance, /* char */ void* path) => + (skottie_animation_builder_make_from_file_delegate ??= GetSymbol ("skottie_animation_builder_make_from_file")).Invoke (instance, path); + #endif + + // skottie_animation_t* skottie_animation_builder_make_from_stream(skottie_animation_builder_t* instance, sk_stream_t* stream) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern skottie_animation_t skottie_animation_builder_make_from_stream (skottie_animation_builder_t instance, sk_stream_t stream); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate skottie_animation_t skottie_animation_builder_make_from_stream (skottie_animation_builder_t instance, sk_stream_t stream); + } + private static Delegates.skottie_animation_builder_make_from_stream skottie_animation_builder_make_from_stream_delegate; + internal static skottie_animation_t skottie_animation_builder_make_from_stream (skottie_animation_builder_t instance, sk_stream_t stream) => + (skottie_animation_builder_make_from_stream_delegate ??= GetSymbol ("skottie_animation_builder_make_from_stream")).Invoke (instance, stream); + #endif + + // skottie_animation_t* skottie_animation_builder_make_from_string(skottie_animation_builder_t* instance, const char* data, size_t length) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern skottie_animation_t skottie_animation_builder_make_from_string (skottie_animation_builder_t instance, /* char */ void* data, /* size_t */ IntPtr length); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate skottie_animation_t skottie_animation_builder_make_from_string (skottie_animation_builder_t instance, /* char */ void* data, /* size_t */ IntPtr length); + } + private static Delegates.skottie_animation_builder_make_from_string skottie_animation_builder_make_from_string_delegate; + internal static skottie_animation_t skottie_animation_builder_make_from_string (skottie_animation_builder_t instance, /* char */ void* data, /* size_t */ IntPtr length) => + (skottie_animation_builder_make_from_string_delegate ??= GetSymbol ("skottie_animation_builder_make_from_string")).Invoke (instance, data, length); + #endif + + // skottie_animation_builder_t* skottie_animation_builder_new(skottie_animation_builder_flags_t flags) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern skottie_animation_builder_t skottie_animation_builder_new (AnimationBuilderFlags flags); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate skottie_animation_builder_t skottie_animation_builder_new (AnimationBuilderFlags flags); + } + private static Delegates.skottie_animation_builder_new skottie_animation_builder_new_delegate; + internal static skottie_animation_builder_t skottie_animation_builder_new (AnimationBuilderFlags flags) => + (skottie_animation_builder_new_delegate ??= GetSymbol ("skottie_animation_builder_new")).Invoke (flags); + #endif + + // void skottie_animation_builder_set_font_manager(skottie_animation_builder_t* instance, sk_fontmgr_t* fontManager) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void skottie_animation_builder_set_font_manager (skottie_animation_builder_t instance, sk_fontmgr_t fontManager); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void skottie_animation_builder_set_font_manager (skottie_animation_builder_t instance, sk_fontmgr_t fontManager); + } + private static Delegates.skottie_animation_builder_set_font_manager skottie_animation_builder_set_font_manager_delegate; + internal static void skottie_animation_builder_set_font_manager (skottie_animation_builder_t instance, sk_fontmgr_t fontManager) => + (skottie_animation_builder_set_font_manager_delegate ??= GetSymbol ("skottie_animation_builder_set_font_manager")).Invoke (instance, fontManager); + #endif + + // void skottie_animation_builder_set_resource_provider(skottie_animation_builder_t* instance, skottie_resource_provider_t* resourceProvider) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void skottie_animation_builder_set_resource_provider (skottie_animation_builder_t instance, skottie_resource_provider_t resourceProvider); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void skottie_animation_builder_set_resource_provider (skottie_animation_builder_t instance, skottie_resource_provider_t resourceProvider); + } + private static Delegates.skottie_animation_builder_set_resource_provider skottie_animation_builder_set_resource_provider_delegate; + internal static void skottie_animation_builder_set_resource_provider (skottie_animation_builder_t instance, skottie_resource_provider_t resourceProvider) => + (skottie_animation_builder_set_resource_provider_delegate ??= GetSymbol ("skottie_animation_builder_set_resource_provider")).Invoke (instance, resourceProvider); + #endif + // void skottie_animation_delete(skottie_animation_t* instance) #if !USE_DELEGATES [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] @@ -201,20 +331,6 @@ internal static void skottie_animation_get_version (skottie_animation_t instance (skottie_animation_get_version_delegate ??= GetSymbol ("skottie_animation_get_version")).Invoke (instance, version); #endif - // void skottie_animation_keepalive() - #if !USE_DELEGATES - [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] - internal static extern void skottie_animation_keepalive (); - #else - private partial class Delegates { - [UnmanagedFunctionPointer (CallingConvention.Cdecl)] - internal delegate void skottie_animation_keepalive (); - } - private static Delegates.skottie_animation_keepalive skottie_animation_keepalive_delegate; - internal static void skottie_animation_keepalive () => - (skottie_animation_keepalive_delegate ??= GetSymbol ("skottie_animation_keepalive")).Invoke (); - #endif - // skottie_animation_t* skottie_animation_make_from_data(const char* data, size_t length) #if !USE_DELEGATES [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] @@ -382,12 +498,68 @@ internal static void skottie_animation_unref (skottie_animation_t instance) => #region Structs +namespace SkiaSharp.Skottie { + + // skottie_animation_builder_stats_t + [StructLayout (LayoutKind.Sequential)] + public readonly unsafe partial struct AnimationBuilderStats : IEquatable { + // public float fTotalLoadTimeMS + private readonly Single fTotalLoadTimeMS; + + // public float fJsonParseTimeMS + private readonly Single fJsonParseTimeMS; + + // public float fSceneParseTimeMS + private readonly Single fSceneParseTimeMS; + + // public size_t fJsonSize + private readonly /* size_t */ IntPtr fJsonSize; + + // public size_t fAnimatorCount + private readonly /* size_t */ IntPtr fAnimatorCount; + + public readonly bool Equals (AnimationBuilderStats obj) => + fTotalLoadTimeMS == obj.fTotalLoadTimeMS && fJsonParseTimeMS == obj.fJsonParseTimeMS && fSceneParseTimeMS == obj.fSceneParseTimeMS && fJsonSize == obj.fJsonSize && fAnimatorCount == obj.fAnimatorCount; + + public readonly override bool Equals (object obj) => + obj is AnimationBuilderStats f && Equals (f); + + public static bool operator == (AnimationBuilderStats left, AnimationBuilderStats right) => + left.Equals (right); + + public static bool operator != (AnimationBuilderStats left, AnimationBuilderStats right) => + !left.Equals (right); + + public readonly override int GetHashCode () + { + var hash = new HashCode (); + hash.Add (fTotalLoadTimeMS); + hash.Add (fJsonParseTimeMS); + hash.Add (fSceneParseTimeMS); + hash.Add (fJsonSize); + hash.Add (fAnimatorCount); + return hash.ToHashCode (); + } + + } +} + #endregion #region Enums namespace SkiaSharp.Skottie { + // skottie_animation_builder_flags_t + public enum AnimationBuilderFlags { + // NONE_SKOTTIE_ANIMATION_BUILDER_FLAGS = 0 + None = 0, + // DEFER_IMAGE_LOADING_SKOTTIE_ANIMATION_BUILDER_FLAGS = 0x01 + DeferImageLoading = 1, + // PREFER_EMBEDDED_FONTS_SKOTTIE_ANIMATION_BUILDER_FLAGS = 0x02 + PreferEmbeddedFonts = 2, + } + // skottie_animation_renderflags_t [Flags] public enum AnimationRenderFlags { diff --git a/binding/SkiaSharp/Properties/SkiaSharpAssemblyInfo.cs b/binding/SkiaSharp/Properties/SkiaSharpAssemblyInfo.cs index 5b6906f879..8d994ffb6c 100644 --- a/binding/SkiaSharp/Properties/SkiaSharpAssemblyInfo.cs +++ b/binding/SkiaSharp/Properties/SkiaSharpAssemblyInfo.cs @@ -45,6 +45,13 @@ "dafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef00" + "65d016df")] +[assembly: InternalsVisibleTo("SkiaSharp.Resources, PublicKey=" + + "002400000480000094000000060200000024000052534131000400000100010079159977d2d03a" + + "8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c" + + "3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fd" + + "dafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef00" + + "65d016df")] + [assembly: AssemblyMetadata("IsTrimmable", "True")] #if __IOS__ || __TVOS__ || __MACOS__ diff --git a/binding/SkiaSharp/SKData.cs b/binding/SkiaSharp/SKData.cs index 5bb53d47ca..a86a1bb954 100644 --- a/binding/SkiaSharp/SKData.cs +++ b/binding/SkiaSharp/SKData.cs @@ -156,7 +156,11 @@ public static SKData Create (SKStream stream, int length) if (stream == null) throw new ArgumentNullException (nameof (stream)); - return GetObject (SkiaApi.sk_data_new_from_stream (stream.Handle, (IntPtr)length)); + try { + return GetObject (SkiaApi.sk_data_new_from_stream (stream.Handle, (IntPtr)length)); + } finally { + GC.KeepAlive(stream); + } } public static SKData Create (SKStream stream, ulong length) @@ -164,7 +168,11 @@ public static SKData Create (SKStream stream, ulong length) if (stream == null) throw new ArgumentNullException (nameof (stream)); - return GetObject (SkiaApi.sk_data_new_from_stream (stream.Handle, (IntPtr)length)); + try { + return GetObject (SkiaApi.sk_data_new_from_stream (stream.Handle, (IntPtr)length)); + } finally { + GC.KeepAlive(stream); + } } public static SKData Create (SKStream stream, long length) @@ -172,7 +180,11 @@ public static SKData Create (SKStream stream, long length) if (stream == null) throw new ArgumentNullException (nameof (stream)); - return GetObject (SkiaApi.sk_data_new_from_stream (stream.Handle, (IntPtr)length)); + try { + return GetObject (SkiaApi.sk_data_new_from_stream (stream.Handle, (IntPtr)length)); + } finally { + GC.KeepAlive(stream); + } } public static SKData Create (IntPtr address, int length) diff --git a/binding/SkiaSharp/SKObject.cs b/binding/SkiaSharp/SKObject.cs index aad6bf8cd7..bcd6635178 100644 --- a/binding/SkiaSharp/SKObject.cs +++ b/binding/SkiaSharp/SKObject.cs @@ -195,7 +195,7 @@ internal static T Owned (T owner, SKObject child) return owner; } - // indicate that the chile should not be garbage collected while + // indicate that the child should not be garbage collected while // the owner still lives internal static T Referenced (T owner, SKObject child) where T : SKObject @@ -350,11 +350,19 @@ public static int GetReferenceCount (this ISKReferenceCounted obj) } } + /// + /// This should be implemented on all types that inherit directly or + /// indirectly from SkRefCnt or SkRefCntBase + /// internal interface ISKReferenceCounted { IntPtr Handle { get; } } + /// + /// This should be implemented on all types that inherit directly or + /// indirectly from SkNVRefCnt + /// internal interface ISKNonVirtualReferenceCounted : ISKReferenceCounted { void ReferenceNative (); @@ -362,6 +370,12 @@ internal interface ISKNonVirtualReferenceCounted : ISKReferenceCounted void UnreferenceNative (); } + /// + /// This should be implemented on all types that can skip the expensive + // registration in the global dictionary. Typically this would be the case + /// if the type os _only_ constructed by the user and not provided as a + /// return type for _any_ member. + /// internal interface ISKSkipObjectRegistration { } diff --git a/binding/SkiaSharp/SkiaApi.generated.cs b/binding/SkiaSharp/SkiaApi.generated.cs index 96d4351d7e..88b37249aa 100644 --- a/binding/SkiaSharp/SkiaApi.generated.cs +++ b/binding/SkiaSharp/SkiaApi.generated.cs @@ -84,6 +84,10 @@ using skottie_marker_observer_t = System.IntPtr; using skottie_property_observer_t = System.IntPtr; using skottie_resource_provider_t = System.IntPtr; +using skresources_external_track_asset_t = System.IntPtr; +using skresources_image_asset_t = System.IntPtr; +using skresources_multi_frame_image_asset_t = System.IntPtr; +using skresources_resource_provider_t = System.IntPtr; using sksg_invalidation_controller_t = System.IntPtr; using vk_device_t = System.IntPtr; using vk_instance_t = System.IntPtr; diff --git a/binding/libSkiaSharp.Resources.json b/binding/libSkiaSharp.Resources.json new file mode 100644 index 0000000000..ed53436df7 --- /dev/null +++ b/binding/libSkiaSharp.Resources.json @@ -0,0 +1,86 @@ +// configuration for the libSkiaSharp binary +{ + "dllName": "SKIA", + "namespace": "SkiaSharp", + "namespaces": { + "sk_": { + "prefix": "SK", + "exclude": true + }, + "gr_": { + "exclude": true + }, + "vk_": { + "exclude": true + }, + "sksg_": { + "exclude": true + }, + "skottie_": { + "exclude": true + }, + "skresources_": { + "cs": "Resources", + "prefix": "" + } + }, + "className": "ResourcesApi", + "includeDirs": [ + "." + ], + "headers": { + "include/c": [ "sk_*", "gr_*", "skottie*", "sksg_*", "skresources_*" ], + "include/xamarin": [ "sk_*" ] + }, + "source": { + "src/c": [ "sk_*", "gr_*", "skottie*", "sksg_*" ], + "src/xamarin": [ "sk_*" ] + }, + "mappings": { + "types": { + "skottie_animation_builder_flags_t": { + "flags": true + } + }, + "functions": { + "skottie_animation_builder_make_from_string": { + "parameters": { + "0": "[MarshalAs (UnmanagedType.LPStr)] String", + "1": "int" + + } + }, + "skottie_animation_builder_make_from_file": { + "parameters": { + "0": "[MarshalAs (UnmanagedType.LPStr)] String" + } + }, + "skresources_resource_provider_load": { + "parameters": { + "1": "[MarshalAs (UnmanagedType.LPStr)] String", + "2": "[MarshalAs (UnmanagedType.LPStr)] String" + } + }, + "skresources_resource_provider_load_audio_asset": { + "parameters": { + "1": "[MarshalAs (UnmanagedType.LPStr)] String", + "2": "[MarshalAs (UnmanagedType.LPStr)] String", + "3": "[MarshalAs (UnmanagedType.LPStr)] String" + } + }, + "skresources_resource_provider_load_image_asset": { + "parameters": { + "1": "[MarshalAs (UnmanagedType.LPStr)] String", + "2": "[MarshalAs (UnmanagedType.LPStr)] String", + "3": "[MarshalAs (UnmanagedType.LPStr)] String" + } + }, + "skresources_resource_provider_load_typeface": { + "parameters": { + "1": "[MarshalAs (UnmanagedType.LPStr)] String", + "2": "[MarshalAs (UnmanagedType.LPStr)] String" + } + } + } + } +} \ No newline at end of file diff --git a/binding/libSkiaSharp.SceneGraph.json b/binding/libSkiaSharp.SceneGraph.json index f90dc8e63d..0b432a4d72 100644 --- a/binding/libSkiaSharp.SceneGraph.json +++ b/binding/libSkiaSharp.SceneGraph.json @@ -19,6 +19,9 @@ }, "skottie_": { "exclude": true + }, + "skresources_": { + "exclude": true } }, "className": "SceneGraphApi", diff --git a/binding/libSkiaSharp.Skottie.json b/binding/libSkiaSharp.Skottie.json index e887c28e65..caceca9fb8 100644 --- a/binding/libSkiaSharp.Skottie.json +++ b/binding/libSkiaSharp.Skottie.json @@ -19,6 +19,9 @@ "skottie_": { "cs": "Skottie", "prefix": "" + }, + "skresources_": { + "exclude": true } }, "className": "SkottieApi", @@ -35,6 +38,10 @@ }, "mappings": { "types": { + "skottie_animation_builder_stats_t": { + "readonly": true, + "properties": false + }, "skottie_animation_renderflags_t": { "cs": "AnimationRenderFlags", "flags": true diff --git a/binding/libSkiaSharp.json b/binding/libSkiaSharp.json index 2e872b0b28..a67a69969c 100644 --- a/binding/libSkiaSharp.json +++ b/binding/libSkiaSharp.json @@ -17,6 +17,9 @@ }, "skottie_": { "exclude": true + }, + "skresources_": { + "exclude": true } }, "className": "SkiaApi", diff --git a/build.cake b/build.cake index 6d36c029bf..ba206f5f67 100644 --- a/build.cake +++ b/build.cake @@ -125,6 +125,7 @@ var TRACKED_NUGETS = new Dictionary { { "SkiaSharp.HarfBuzz", new Version (1, 60, 0) }, { "SkiaSharp.Skottie", new Version (1, 60, 0) }, { "SkiaSharp.SceneGraph", new Version (1, 60, 0) }, + { "SkiaSharp.Resources", new Version (1, 60, 0) }, { "SkiaSharp.Vulkan.SharpVk", new Version (1, 60, 0) }, }; diff --git a/externals/skia b/externals/skia index 8990028b2f..53d2065ea8 160000 --- a/externals/skia +++ b/externals/skia @@ -1 +1 @@ -Subproject commit 8990028b2f3a70104c4db924e614f5bccbb2c637 +Subproject commit 53d2065ea8724daeb85e839ba47f54c582809615 diff --git a/native/linux/libSkiaSharp/libSkiaSharp.map b/native/linux/libSkiaSharp/libSkiaSharp.map index efb3ef0c45..c10403496d 100644 --- a/native/linux/libSkiaSharp/libSkiaSharp.map +++ b/native/linux/libSkiaSharp/libSkiaSharp.map @@ -4,6 +4,7 @@ libSkiaSharp { gr_*; skottie_*; sksg_*; + skresources_*; local: *; }; diff --git a/scripts/VERSIONS.txt b/scripts/VERSIONS.txt index 234b8e0f5a..fa0d56e5f1 100644 --- a/scripts/VERSIONS.txt +++ b/scripts/VERSIONS.txt @@ -68,6 +68,7 @@ SkiaSharp.Views.Blazor nuget 3.0.0 SkiaSharp.HarfBuzz nuget 3.0.0 SkiaSharp.Skottie nuget 3.0.0 SkiaSharp.SceneGraph nuget 3.0.0 +SkiaSharp.Resources nuget 3.0.0 SkiaSharp.Vulkan.SharpVk nuget 3.0.0 # HarfBuzzSharp HarfBuzzSharp nuget 8.3.0 diff --git a/source/SkiaSharpSource.Linux.slnf b/source/SkiaSharpSource.Linux.slnf index e3884ef0d3..aa198819f1 100644 --- a/source/SkiaSharpSource.Linux.slnf +++ b/source/SkiaSharpSource.Linux.slnf @@ -13,6 +13,7 @@ "..\\binding\\SkiaSharp.NativeAssets.WebAssembly\\SkiaSharp.NativeAssets.WebAssembly.csproj", "..\\binding\\SkiaSharp.NativeAssets.Win32\\SkiaSharp.NativeAssets.Win32.csproj", "..\\binding\\SkiaSharp.NativeAssets.macOS\\SkiaSharp.NativeAssets.macOS.csproj", + "..\\binding\\SkiaSharp.Resources\\SkiaSharp.Resources.csproj", "..\\binding\\SkiaSharp.SceneGraph\\SkiaSharp.SceneGraph.csproj", "..\\binding\\SkiaSharp.Skottie\\SkiaSharp.Skottie.csproj", "..\\binding\\SkiaSharp\\SkiaSharp.csproj", diff --git a/source/SkiaSharpSource.Mac.slnf b/source/SkiaSharpSource.Mac.slnf index 3a1c5f8fb2..5d046513e3 100644 --- a/source/SkiaSharpSource.Mac.slnf +++ b/source/SkiaSharpSource.Mac.slnf @@ -23,6 +23,7 @@ "..\\binding\\SkiaSharp.NativeAssets.iOS\\SkiaSharp.NativeAssets.iOS.csproj", "..\\binding\\SkiaSharp.NativeAssets.macOS\\SkiaSharp.NativeAssets.macOS.csproj", "..\\binding\\SkiaSharp.NativeAssets.tvOS\\SkiaSharp.NativeAssets.tvOS.csproj", + "..\\binding\\SkiaSharp.Resources\\SkiaSharp.Resources.csproj", "..\\binding\\SkiaSharp.SceneGraph\\SkiaSharp.SceneGraph.csproj", "..\\binding\\SkiaSharp.Skottie\\SkiaSharp.Skottie.csproj", "..\\binding\\SkiaSharp\\SkiaSharp.csproj", diff --git a/source/SkiaSharpSource.Windows.slnf b/source/SkiaSharpSource.Windows.slnf index b90c7f0fcf..4d17afd5e7 100644 --- a/source/SkiaSharpSource.Windows.slnf +++ b/source/SkiaSharpSource.Windows.slnf @@ -24,6 +24,7 @@ "..\\binding\\SkiaSharp.NativeAssets.iOS\\SkiaSharp.NativeAssets.iOS.csproj", "..\\binding\\SkiaSharp.NativeAssets.macOS\\SkiaSharp.NativeAssets.macOS.csproj", "..\\binding\\SkiaSharp.NativeAssets.tvOS\\SkiaSharp.NativeAssets.tvOS.csproj", + "..\\binding\\SkiaSharp.Resources\\SkiaSharp.Resources.csproj", "..\\binding\\SkiaSharp.SceneGraph\\SkiaSharp.SceneGraph.csproj", "..\\binding\\SkiaSharp.Skottie\\SkiaSharp.Skottie.csproj", "..\\binding\\SkiaSharp\\SkiaSharp.csproj", diff --git a/source/SkiaSharpSource.sln b/source/SkiaSharpSource.sln index 20380709a4..55d2de312a 100644 --- a/source/SkiaSharpSource.sln +++ b/source/SkiaSharpSource.sln @@ -109,6 +109,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "binding", "binding", "{937A EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "source", "source", "{21E35524-DFEB-462F-84DD-A81213A38EEA}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SkiaSharp.Resources", "SkiaSharp.Resources", "{1EE838FE-13D6-4837-B7DE-35DD2805F092}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Resources", "..\binding\SkiaSharp.Resources\SkiaSharp.Resources.csproj", "{542CD60D-B619-4555-9A2E-A8C2A85C9CC8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -275,6 +279,10 @@ Global {1DE3BDD6-344B-4927-BC67-DAA80C691F6C}.Debug|Any CPU.Build.0 = Debug|Any CPU {1DE3BDD6-344B-4927-BC67-DAA80C691F6C}.Release|Any CPU.ActiveCfg = Release|Any CPU {1DE3BDD6-344B-4927-BC67-DAA80C691F6C}.Release|Any CPU.Build.0 = Release|Any CPU + {542CD60D-B619-4555-9A2E-A8C2A85C9CC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {542CD60D-B619-4555-9A2E-A8C2A85C9CC8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {542CD60D-B619-4555-9A2E-A8C2A85C9CC8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {542CD60D-B619-4555-9A2E-A8C2A85C9CC8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -331,6 +339,8 @@ Global {DD1EAB2E-29FD-4971-8440-055A1A1E69BA} = {2F28C1EB-D020-4A3A-948F-DF0AD0FDCC53} {2B4DCCF7-8BF3-4027-9A79-344BFBD21B6D} = {2F28C1EB-D020-4A3A-948F-DF0AD0FDCC53} {1DE3BDD6-344B-4927-BC67-DAA80C691F6C} = {2F28C1EB-D020-4A3A-948F-DF0AD0FDCC53} + {1EE838FE-13D6-4837-B7DE-35DD2805F092} = {937A3EE4-3719-452F-AA5C-2942F5C72D7D} + {542CD60D-B619-4555-9A2E-A8C2A85C9CC8} = {1EE838FE-13D6-4837-B7DE-35DD2805F092} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {67EACD19-0CEA-4127-9842-549AA6FB84C9} diff --git a/tests/Content/images/lottie-base64_dotnet-bot.json b/tests/Content/images/lottie-base64_dotnet-bot.json new file mode 100644 index 0000000000..b8c6e506d2 --- /dev/null +++ b/tests/Content/images/lottie-base64_dotnet-bot.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE ","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":239,"w":1200,"h":1200,"nm":"works","ddd":0,"assets":[{"id":"image_0","w":93,"h":51,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_1","w":94,"h":94,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF4AAABeCAYAAACq0qNuAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAQOUlEQVR4nO1dzY4cRRL+oqbN7gHJfgN84IDVRh4OKyHErvsNtuGIkGgQD+B9AoY3ME/AzGXFigX6DXa4rbSrpb14GPAF+8bRvmGZqdhDVWZGREZmVfd0jwe0IfVU5U9lRX7x5ZdZ1dU1hEtqi9mDfZzxdVC7D9A1APuxkEVF7v60AMD8GEwrZn7Me7SaTH5eHR6/9vhCHR9p9LwdCLaYnc4aYIaWZiDclmXsHcAR81SHAY4FADMAxqMWvAJwfMa0/OyfNx7uqAtr2XMDfjH78VqDn+cEmjPw5+hQwSO26LMICEvgoQMQNmn/ETMv0fLhX/81XW23V+PtwoFfzB7sE/gOgedEdNXzxDrFboJTMEQQBMAqAFk+M5jxiFvc/d0vTw8PVxcrSRcG/Iez01kLOiCi2+HM8eQV0IOx2dHpFAS1jUCzSsf9FIAnAJa8RwcXJUU7B/7D2ekMRAcMum3BpoIHVcaLDCsvQAekKz09yF0dF/zQ5tHPz57eWe54BOwM+MXs9HoDOiQSgBuwPeDJEXm2Al/Q965ul4jgwoAspMcFv0s/AfHdz/49PTgHBFXbCfAfzE4PiJqPioDHra8x0ilf30UwavruMTwcm4HPTjDwiNqzxWerV483hKJoWwV+MXuw36A9JKJbAWwiKOAj2HqTp4V54GfyAg/4bicDFMPgp3wGgE/+9p/pnY2BcWxrwH8wO10Q0V2ArkawBcMl4GoUCC9qzljwR+l7voqpgh+AtuAzM7jFvT00889W25l8twL8+7MfDhvi90BUZrkjO+6qZk2NtywP9f1VjAN+m4LFbcozkhNXP4x2/vctSM+5gO8ugp4eE+FWBrpgeRYIcWar89XlpKPx/vJRgIwxWm6B9iVHTNjvf76aHm4IW+jqZraY/Xit4afHINyipgD6CJ1fS+MV8GFb1ncpPWPBdyXHjIT+88kX/91c9zcCfjH78Rpxx3Qi6oFGHXTB8EhyZy0/ZnLVshK2GuQ6+L6OQwI9JhjMR198e3OxCYZrAz8a9PABEstLOm9ob2WeFdK5vof9QfA9bc91vLrKMaxHy3z01QbgN+tUtqCjB3wM6LE66Q+I+nICNUDT5HWogahDWZk8vyy3fkH45fsPdax3x07V6wB87+2b3x7sFHjip8cAbiEAirwjMk+CjghgACyBnQFtPo09NgYrD6YKtAE/AarzSkBnRIm5pgLoo/n0ZLET4Bd/+uEQwK3osPSTjKPQAEimBYZnLKsEwGOkZbg+hweqyTMYKv9lnQxo3d+w0xB/Op+epC9rBmwU8Is/ni4I/J7ypcocB/S+V3V2CzkJH8luZ+RYQBMzXaxSfhwtFdY7QKtqpNsm4Hi+/821MZgOAr9448E+iO4qQG1nCoHQTK3ISpPAha3TIGm8rOcELddrP08SpMp6B2h3GRaDxVfp2QvLrQCPvfYQgP7CwjLb9iEwJLKPEjuyAJECuamOCP+4MTruAZ1ANRKUUdyLDvI8AADffnt6f3B9XwV+8ebpAaKua5Bz76EDEUCX7DGAZOx2mSyYn9X1L9ys7GVuymBYq+WLItlHGx8GHcxfOb1ew7YI/OL10+tM9FHJCRuI0CE3EAVmeqA1FY23+l4kAwb8soAKcihQPWDJNOHhA75KnVIUrQh8O0F+YMXxErPG6z/5zG7kcaRHkUTEGTkl33yJTG2k2rK/ouOS3l4aAMC35ze/nXnYAgXgF2+ezgi4nQ1PD1Rplc52H9L5/Z9RUhMDUZpc7bnL/iosPcaW+jVkpg4xHZaqusC3LQ5ymuRO1AITx6T5RIIa0KuAe/KStWuBdnz3+lPLszamjraXShdWGfDvvnk6Q3igaGyUHYdyfbRgldb0ei2fjYh4ChPoEtAVH+2uVQ8xQDPueVvbRlfGB45HOfDU4iBrLaQLzM/qVY6TjJSBUJOuw3BPkrLohrEWg5TLjZcWRyp3vW0A1garBAcKrFfAv/PGyT6gH58bbdXAWOQpqxb0v6bvEuhsRIni2PbYEVtMU96vwWO8U3C2rlfAN9zc8RqyUfbOOcgcKxUOYiV994AedKiWPieQG9gtex8nAr+YfXMNwNzTLWvxK71iWtR1tnY/DgKRiGt4GKAvB5Brm2V9BP7s59/PIW8NxAP0dsOzjkr7gaBLCWRn6zhCc5mKwLfE87xyMq4Vrmu2Mafx+GBBfEZjV86cx9ZxhK/Ob3wXMU4azzSTTdlttcnwhXNM5/557ck89yu4lvPze0G4tIHRRg3Pwn4DAO++fjqDlBnjePxCOaYT0H6gOJbFOpwDnb64TicsfbcpHq0Qjjm92yQwFxYo1oxv23Z2/jadNJvCGAnW9aCB1d/sF77lZ7jB3cjPMX7XjhlvL4W7lr3UdDJTtU2HuFMvlxb0oLJ4tMIpt00Z9FmOtCBZwoUxIzXLGxj9MjEqHnsdySd98jYYepIOrdg8O5GPOM52gMSBubOs2+R0fDYi4ABQIoQDjjc3WdCzUWW21o9MDo1R/yO6yTt/CAt7BthZulWAjUU929QCntOBRH2aSDUBMIg98FUlFTj7ABJEOmvHC4KXX6pX8clNj7MOeG7pOu3ljTExKDCSASIGQwNLRDIOuSOStQF8kMyGiqw3otLp+m3+QKmSGxMIJTNjAS+NmiEbF4geeOJ9j+lkBgBzuvQvnohMtmR9yTcCKLK1hHpgPSvZScNbgxxPZDJtILR02MAUhpxsSPk4lv58FQAmxHQNBJ9tis65P0Fu9Mkpr07pOEIaOWIQpNoFaZOaq/U+BSOx3puIzcd0x1sl2SUsq2OdRkbafHqyP2HGfup332sJBCie3JWbbKhoX0jMHVG24DCcuynAkkv1LYINBXAmMZn0jBsRWb7MckeNDtg6NgmtMdLcqEaNJzfQ5SXWp3wvr8uP88iAaeA5Y78/4eo8b0RE2VHsHpAVOHlmdNSMgBcnoQ057BW4trERrGcBdGpCNM5SfYSeeXInOwYDeNgKgIdI7AXCdje/UrZ0LwyHkcbAy5M8V/eeyaDhsD4uJQO2ASSp5X1NxXDVNDt5Ojvs5MAL0C2zWedB7LJscEwgZLVN9EXYpDuxWF87q5vMDOvjWl5M0lKeQh0OGWF5FDI9sHNd0leNkZH6905yBLhan8mOxd1D2JgTwDVJj0nL0N8wBe/XYL1ks/BL7InackR4F2z2UJnFcptYLgGUTE+Aa4mxE3EWDJnMyoVjsUKhDxWbpJ6MY70GNZcSO4l2+yJfxDCtblAPQjhOUI3tNgYl/2Wf9FhJjC3LRgTnx8rAZa2Mt4mR9DLr0Q2NSH5GkhyugO9oPmTzMVugVLieYJHOge/PbkEvMFtNoAMgD8nOujIDiOWkBNplfd8rFpNoB3ifF7KcoCkvU2tlk4fb0cbOvjO52hGgpcf9+fx2AjHOVhO0eMwNqqyXzXuX/rm0dDW8NXqSHtmaM5f65NJg92lPdgbf1MHpGLvEXDsQG1jDDVapNa6cOHfcTlxeJyHz7L32NtyDZ7SFb5zc+gU/x/qjwWOdhiSGDM7W2I4rwE8TtPS40+reek0G9W2LFU2S4i7PXp0SKC4p3eWj6IwnZRzrGmO1iYmc6Ynl7gjIQMwDlJEvNph8OC/bPz+Z/jRBc7ZibsR1TNJxSughrttJygX1E2dyi+JfxPpKIyyyNghe2u7KQFjAY54uT5qfQLejuiQx7oja3B4BwOQX/LLa4xdUibyDKPOk3mfLRFVboMfi5lcsQ6b/Cu9Cv9iUDek8YCZR5KC7MgpdP5OYc7Ad6KS96V4BxY/sxOJPNvnQ9DU/1NU/QVd1hF77v7J2PuaYev3CUwoG9DAypK5XJWZjvDsj4hWQlpMrJrwEyJtlPQfZrjj0asVjvndnspSM2czZVKArmE7LtGI69+0hbSN7HeI4+Z4U2TlhU2uBY6B/yoBbHGe3RgNrkDroMl/WLbCsWNbKTuV5tp5bJ+y3zmpH1dsMdCkxCp8NbXn/1QR8e7a39CYS74RDQ1nlZyCOlInWfPr81gXID2oaBXlAspWOAdmXovODDtDXYa8BgOX3Nx4y45EdTiUGVIdjGzoktD+yshCEtjZazPmUztfrewGugS6JgxSHWPfcsIPjj4/F8/G05IJTNfDLk6sAt8TqjOWSwebTMlpzTCuO9SfuNX2SoDtYnNfas70ceEb6eWWItAs+bN5QZ/JyT6utjFSD5IEtRgPMeSybLbgQ/u0KdAD3lt+nF8lF4Jcn0xUQ5KZ30gF/mOF9mQErSBC3jNYJkgpGQeNdX0bJVHniRSEYWwYdBP274cYU3g0nL4HvMRyFMi8AKggKuGF5aEP9kXNCaSKXKxo/qNsFHQDaK8/KwHeF9ESB7y3T1BCts2wYHMtsT+O7cnjzgthXkuKtnFpdXhq12wYdwJF9V7ECvr+KjRNADqTPDheILACcAVUGxs9vnTzY8xjAla/wyeKt6bdpfLZ3YPOy37l6lVyQFQCsO1Rkpi8rmfauofFRfhjZqkeDq4PiTcy7AB3AkZxUi8D3lY488Gv6noZpHoDa1WSabIc/sZ7U+MGr3/oFmx0B2zaPyEDhXQZ85dmdoPUqX3TOG7J6ZKTytiYjfVmNrdloKElJheFDPu7IXLYDBeCXq9ceE7V3vbKi8668hCHMeZkH4EBwMpBbu/73V0fF9XwYkTsxelJiOzDwrfNb0/sPge6uZbEBQnqAKbwbIKZFHdj9/HGOga/A86v2HjUWhRLIuM9QE6uttwsj4o+/vP/qQak8f4RPGBMviOkf1TpsH+0AahAyB/B7NMTDVGOwkCDLNmUFltu+wkUB3tu9GujAwDvJuluY9MnQWXK9NcO9tjJxZKf0aYfqlm7CSdm5AGPQYqjO0OgGALw1vb9CeMPqSIuSImRIndA+TjLkDauNn8cs9mPWhRoBf/ny5KY7P0qrSk0wPtub0167Qv8zklHHCH2NX2uJZ6H0U2ryWZ5Km4WTWPm5aLCFHY0BHRj5ptXl9zceMrXVdx3UzF2ZqHsuw2t5Vd4aCbErpOdj97pl+DgbJTXB5tOTBYE/Xd+nEY6M8OQ5gjpg9ITPmv3Smt2ztd6mvTyZHo6ZbDexMZPr5TR6wsBsHdCBNRkf7K3p/UMA721y7G/LetBP1v9njRsBD/wf/POADqwpNdK+Orm5IOKPNz3+123nAx04B+OD7XLCvaR2j8/25utqurWNGR9seTI9ZNBr3t3M36Ad8ZVna0+knp2b8cHm+99c615az7e31eZlsrFXpGu0t117e3r/DoMO1rnKveR2j0GL8+i5Z1sHHgDmr5xe796f/mtmPz0hau8O3WXcuPVdNBpsfvPbWf8q7+o9/UtoR3y2d7ANLS/ZToEP1q98DnD5A7BzwINdCPDB+gDcwZq3mC/ALgzwYBcKfLD59GS/CwDNn+MkfI+Aw/bKs8Nd/2N0z54L8NLmN76bd28g5Tl2LkX0NYGX7dne8iLZ7XryPE9ubf7K6XXstTPqXpjWfzYeEY8ArIh41QLH4ZcYl8UuFfAlC+9eJ+BFBl4uVFsB3Y93Pz+Z/nRhzm1o/wPG7agWmLPcLwAAAABJRU5ErkJggg==","e":1},{"id":"image_2","w":195,"h":352,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_3","w":41,"h":68,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACkAAABECAYAAAAcChxyAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAFNUlEQVRogdWaz28bRRTHv29217HjqE6jpKiVohpoIWGD6oorEr5wQahs4QBHI3FEpX+Ckei9IMGpEuEfoFsOiBupxBFUR41JpRIloVTQVpQa2iT2eudx8I/YXnu9nh2b8j1Yu+Pdmc/Oe29m3s4SYspZ2swKw3cYyAGUPfyHdwgoSd9w3VvLO3HaIGW4lZt5YlEE+LUIzVxnkkV34+U1lbZGhnSWNrNkyNVocAFdY8sruKWzj0a5aSRIZ/lnhwSvApwZCa27yQoDebdsl6LeIaJe6NjlAgl5NR4gAHCGwDccu1yIekeknnTscoHAXypzDRBLcd7dfMkddt1QyEaA0Pd6sALNRzJ9KGQzSErxTRyqXba8XFgwhfpkM4rHCQgAJ8lLFMMuGAj5tr1xUXGYURB/5KzczA/61+xX6ORuzLJHRYC14xgmIZUWSE0LGOaht5GAiw3MRoZsdL8+MxsmYW7BxNFjFlLpgcbLXDh3+8pn35z+IMDTW9AIFn9bF9zCcQvzJywYxvDRzquhfumrrNVbHngsMuRFHYCZORPLr0zjmcVEJEAAsBIwL5y7faW3vAvSyd2YBVCIC7h4KonsUjIyXKfSGePd3rLunvQSThxfNEzCC2emMXesr6tH0lRSzFx4Z+uNzrIuSALHMvXzdiosMCLLAi51nrdrdJY2swDOqFa8eCqpBRAAkjPGSud5u1Zh+I5qpZk5M5aJe2UlYH745i9t32xDMkgJ0jAJi6endLD11Iv3Wscd9lGbAheORxsDR1VyWrzaOhZAYzmmUpFhEuZPBMZeLUqlxXzrWDR/8ioVZebMsfRiSy2/FADATDmVSo5qDJZ+EoJfBw59Ugly5oihDaifhEmngEPIk6NWMJMZLyAATCWFDQBCNWhS03oG7iEygRFS2l51LljHpVRazAKAUI3sSWoiNoujYmF79qmHfPCgXhCqY6Rf15+kDZIAqG+GNkz7e1I3y0Apm3v/yf8A0q/zxEBjBc5f9z1dHKESAI/01rVTlYe+Tpa+Yl/+KIg48hvXXtWqEg/v13UyBfTFdy/+EHucvHenBt8f73AUG7JWlbj3a00HS0BeDXUAENI3lM3d0oPfPTz+W79/1j35GAAEDF85cDq1c+tA+5BU9/hPABCqG0C98uuMrfK+VlDf59+Atk9SRUulTVBdpveq7AKHgRPbL1vy64ytjX3cu6MhmNi4CjQhieRa/Bq79cedGjZ/2lPuVa+G+uffPrcLNHMI6RslEvrn4VpVYmtjH4kpgYUTFo7MmUhMRUs7Dvb83dZxI3Geqq7BG8+bCKABe3e7irvbVaTSAjNHDBgmId2TcR48kagdSOzvSfxTkZ+0ytuPdd4ur01uS2S42Deebe2Tt2ccAg/d45ug1js38tuQ0jeeGkgCVjvP25BN8vUJ8/SVtLzVzvOuBQaDLk+Upr+u9W6Gdq+CrJqra/ZRFRMHOqoLsvkEq5MCCoqu91tLBNaT7Iv/zORMstivPADp3lreIeKPx04UUP9eBAaszKVZvzxp32Rg4EZXX0i3dPYRSyqMjSgg+jTsO4zQ2f68veECeEs7U7fWr5ZXQt9HhSZibHkFALth18QTVRjDLRYK6ZbOPmrslI3HP5mkE+VLq6EprVu2SwzkdYMy6P2o+VXkF9+OXc4RsBb/2wyqMElnlAQw8ssBt2yX2KplAbqugtbUOvsiN2qGqrSF0Px2rYjI+z9UIXDx6/KK0mwWa5+j8amiLACUD7oBVQBeY5Drlu3VOO1olbNyM6+6eRWmfwEoLsOjMRWeQgAAAABJRU5ErkJggg==","e":1},{"id":"image_4","w":41,"h":68,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACkAAABECAYAAAAcChxyAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAFM0lEQVRogd2azW8bRRiHf++M13ZSNw4GKjhEjWhLP2xIInFBQmAkDohKsCniwKk+IipBkPgDfOAPCAe4gIS5cWoWDogbjsSRqqkSE6pGba2oAiIUOdDEsde7LwevXXvttb27Y1fiOa1nJ7OP3jc7HztDCImeLi0KcBbEs8wiCwBEdhFMFRtUNErpjbDPoBByOQLnAZweUrVMwOr1UmY16LN8S+qZzSwxFTBczk2ZbbFibF8y/D5T+Kl8JbOZJ6af4V8QAE6TsNeW0yXfER05ksvprQKAq34f4PHYddbqurGxVBmp9iiV1Aq2ucWamR1FdGi6nfSoFgSABTK1kVI/UFK/+JsO8MdqnPpy9UpmMz+skme69cWbs2RG7wOcVGnVDyZ+3dh6oeh13zOSZGqFSQgCADEV9MWbs173+0rqmc0sgHfGJdWH06IRWfG62Tfdy+lSEeDXxmUUjQlE44TEjOw0qRHzG1/+dP4Xd/2Iu0DPbGbB6gUTSYknntaQSEpEY31jE/u3YhUAnHXf6Ek3scirlEumInh+YRpn0lNInYp4CQIATs7KMx++efsVd3lXJPUL2/OApSSK0ZjA3LlYd0pH+btp+RmAbGdZlyRJ2/Of1w/JVARz52KQ0v8k6+SsfNVd5ko364HNHFKnNMxfiAcSBAApiT56+87XnWVtST1dWkSw2U2X4NzZWJgmAACxKXG583dbkoBcmIaTqYgSQQA4MSOfufbW3XbAOtLN2aCNyghh7pwawXab0vqgdS2A5jgNYCFog3Nng70kg9Di4r3WdTOStVg2aGOJpEQy1TMmhCY+LbvTLaS1GLSxp57VVDj1oEUR+fTduy8CjmRrKeqXaEyMJYot6nXrfaD94vB8kEaSKX+jiV+ERi8Dj97uQP3jzJPjiyIAaBqdBwDhdOKB8Dsu+yWiURIABMj2nBEPIhrztWQPRGxKTAGAgCWDScbV9ouDEGG6n0lw7fKdlfHnTAH/b0mrwSo9PIlolAgsWT20Vbp4IjXxUqh0T0LUtuzZUJKH/1iqXDwRUlRCSe7vmapcPLFM+1dhWzLwh/fqoY16bbwvUMPkhwLSGulrqxd/7dZV+XgSup/c3zPH/gIRACynt0LlLJGUOJOeUmPkIv/VPDmRpIMwDT08sMaa9la6Q+9a/blbx/5eI2wzXdSqdhVQKAkAuzvHSkUbJh8ArYWYIklArahp8m2gFUlLFJW06rC7c4zdnRosK1wfatbYABxJ4/eL9wGUQ9t1sL9nYvvGUbioslwDuvvJYjitXqwGY3fnGNs3jvD3H6av0alWtatf/PhcGej4iMqgIoHHsfOFes3Gg3s1PLhXw9QJgcSMRDQuED/RO5YcH9qoHtqoHtnftcoeLZy1ugFT+2Yckp1UHYlhsC1+aF13LfmW01sGJrt/4wEdrJXS7VVsV7zZFoWJ+/SFuzbuuySbu/rhhkgVMHGh83fvPg7Zgc9KKKLs3gztkbQjjdXHGU0G5d1lPZLGxlLlMUazbJTSBXdh30nv44pmvygCHpLGxlLFOfMzSfpGERiwfGgeNqL1sSm5YOKc172Baxy2RG4yaafPAx1vAJqzI7Ypp1rJxS3W6vlBFYauFo3tSwYBnyhT6oIO2JJDDzGNtKR1DsN9q8SrDR0wkHXmsgMZed29Vsrk1EXUERzx2KKvjwPXS5lVtsVyuJeJ1lmrz/s5Vxno63zzYJPm93hYmUF5r75wEKG2EPQL2/Mi0sgxkw7vXd7vGWQEkWuhdJ/DOfTUhEVFxVFZAPgPgCmz6jQxijgAAAAASUVORK5CYII=","e":1},{"id":"image_5","w":76,"h":117,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_6","w":504,"h":509,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAfgAAAH9CAYAAAD25W7MAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAgAElEQVR4nOy9f7Adx3XfefriASD4QwAlk5YoawHEW7YYKUswFSfZbGqJOJVs/kiWqGS3nD+S5ZNLlCk5LkGpTaLEkXXlrKN4d1OkLP9aW2uBjp21NnYCRYptySsJTDmSLdshKFsSnTL1APGHZEIiAOIH8R7eu71/vPtjpvuc7tM9PXfm3vv9sC7fTP843XNxZ759TvfMGAIA9J5H371xhGjtyDRhZI4R2UM0qJYyx1XGDNWrMfnupiV7pl7EnDMDe26yv722ffZdw6OXVO0DAOaCiRcBALTFo//guWPb1h4aGHuEjDlCRGQsHR9nHyFDh6unqfE26pjQGW0CJ7wJmhUrC+WfImMvWWMuGUtnxyXPEu1c2l5bO/eu4evOBXoJACgEBB6AFnn05Mah7bW1Y4ORPTIamCMDomNEdIh2/x4kItZj3t3QCbsR0ieZMVGXq/uV2XKRq4hQ57wle87YwTk7sOdotDsA+IH/7Q1nwtYAAFog8AAU4P0nN46sra0doREdp7E3biw9MC3ACW3Hwp4t6oGrRs4AgKlw2dLo7MDQWWsH56zdOYspAADSgcADkMj/fvK5YzQYHSNrjhlDx2jijQdE3DBptc0UYQ8JbEDwBXPkinqKSKeIf7C+rt55InuOyJwxA3PWkDn7doT7ARCBwAMQoCrmtCvkD7AiKoi7TvAbCnuWt54n6rmCnijkCZjLRKOzEH0AfCDwAFR4/8lnjw9odJzIHDdEx8jQwZpn7Z4xpb32EsKuFHW2TEzUFVeMUmIeXDAY7sB5Q3TWkjljaXTm+4ffdrZZTwBYTCDwYGV59OTGoS3ac9ySOW7IHiei+4hcoU0X92LCLqQ3FfbSot5E0PNEPKchesKSPTOgwZm3D193JqdVABYNCDxYKd5/8tnjhugEkT1u7K6ge+LnCrDGqw547anh+GLC7nQyJtpaUc8RdJ2Qp4QHGvMEEZ2Ghw+WGQg8WGp+5ORzx9Z2do5bY44T0YM1MRSFtV2vPXmePUnY07z1JFHXzrdHywkF0pJLcpmIThOZMzfoxmms1gfLAgQeLB3//O999YQZmONEdMKQPUxEgpfO7SeIu8Zr14bjE4U9KQwf8tYLiHpY0GOhgl5ehJ4isqdHZE/DuweLTA/PLQDSGJ7cOLR/Z88JIjpBRMfJ7D5AhhMxjbiX89oV4XjJaxUE3zehF3aNt95c1OVGsy42XV6hLBERnSeiM5bo9DuG95zusDcAJAOBBwvJ8OTGob1jUR8QPTjNYD3omNj3x2tvVdgbiLpK0HPEXDOY0NoqiOWTLxPRaWsh9mAxgMCDhWEm6vaEseZBTnzjwlvZzBD31rx2IUrgV9cJewlvnRd1fvSgupCE+pFDiauXoOSKahB70Hsg8KDXDE9uHNq7tecEGXvCmImnbtTiy4p7LCTPpak8+bDXzgoqJ+xsehlhbyzqWi9daltDH69K4YHAZUt0emDp9PdB7EGP6OOpBAD987/31RMja0+Y3Xn1gzVRThF31mufbTSZb+dC8ileu96TZ6ICzk7TMLzfF994UUFPuPL0KEQfLWyIzu+K/ejU27BAD3QMBB70hvc/snFkNBicJEMniOjwJL0zcQ9FAfzONfPaWxD2eYu6WDZylVFdhOZ5pVKoe7TIboGnjKFT+0abp96CW+9AB0DgQadMQvAjGq0PyDwge74lxL0imApx785rN357zk4rwh4T9QKCnjsI6BWCuodE31p6HCF8MG8W6bQCS8T7H9k4srNnMCQ7DsETBQSyXXHP8+SNu8m0GbDJprUn7NneukbUpTYTympo7OmX8MwTK7tJhuj8yNpTt9itx+DVg7aBwIO58sPv+Oq6saN143jrsuj2TdxNPSvHa2dF3LjZsrhqBhRifxTeeqaoNxX00Bgk0wJDhoTb4G5SU9Uka+hxInPq7e/Bs/FBO0DgQesMT24c2rM1OEmWThLjrXci7iov3U0zYhnuONr22tsUdo3Y5gq6dJzJhuZGPCavEn1Z8J+yZB57+w+97lRixwAI0qezCCwZw3dsHNszGpwkQw9N0roQ99zFdPV9424y7XHHIdisFGpP2OvGkkVdajuYEMhu6OKHjrsINtW/D7voyoV41d3L1trHyA5O4Z32oAQQeFCcf/b2r56wdnTSC8NP/zfe74m4x8U+IO6cZxv15BmvXSHsUnt+ekNhbyDqct/jl5rWBbwp6gEAH9MP1nUyR4Yepx0zhNCDJvT5dAILxg8/srFONBgS0WHWG144cTf1LIWXzulam147K+xctIAvwvZBk+8lJwh674U8lajwJwp+PeOJkTFDzNODHJbpNAMdMFzfODS4hU7QyAxpYA4T+Rd9WYjH+04F9Vz5HMRd9LCTxT7Pay8i7LneepKo84Ubizl37A3MSbBi22RJfVD0/Ti+QuyfIEOPfd97cJsd0AOBB1kM1zcOmX100hhzkogOep73sop7VGw5+wqvXWOXTZt1Xi3sLYp6lqCHBiA9woo7usp8lWSxP2/IDN+GBXlAQZ/PJ9BDJsJOZE6SGa+IJyIyhhd3d7/P4l6147SjtV2vNh+vvS1hV4t6ylVEijKkMDcXPrFqgg0bCxmExB5CD5RA4IGKmrATHax767woyoJOjjAFvH93v5S4s23oxV3rtXPHIbbBpPltFRT2kLdeStS5fkbKFyiSTO5tbsGiyvIasQ949RB6IAKBB0GG6xuHaB+dNBNhJ3KEsiKKlY2guNf2l1fcm3rtJYU93VvPFHWtoIcGFz1FuShOLqIpFxL7sFd/ngydxBw9qNLn8wl0zPDhjXUiMyRTXxWv8rxzxN2137G4a8Se+z58+5E0jdfu2nVsNRL2QKGoqEv9EsoFuqKuOxdSvfWEutqQvi/2Cq/eYtU9mAGBBx5TYR+/0Y0PrSvF3d3vlbjXpDksvIzdehGFuHMiFxxAzAy2K+wmkMegEfVUQU+4ErVx0cp9PawqW1M++KYaLtsG8ojI0hNmNDqJV9auNhB4MGX41o3jZMyQiB6YpInz5op59yLiztprWdxT7FYqiMLOpXGiK3Q2PLAQ2mPa8PviCHsTUU8R9EBm8gWpyRUscWFdyoNqglmxJ9+GbEnG5PD94yM8MGdlgcADGj6ycYR2Bo8R2Qer6Spxr2wEhXJanxHnDHEP2ojanKO4c8LnpgkK7p2cWnFPEHZpsFEtoBF1rfArs8Ijlbmge+ZsjuhrbrdL9+ojQj+y79uHN9itHBD4FWaygI6sea+X6VzYVYviAkIZqi96qC2KOyvIQeF12zGMbecwYvZqaT0S9hZEPV42/VJU4uKVd3dc+Ib1lIfmNBb7NKG/bKw5iRX3qwMEfkUZz7M/RpOV8Q4h7z0q7u6+ZnAQsucU6LO454m9IO6Zwu63KQyMmEpsdkzUtYKuFPOUgUNxUkSbKxF+/0wwMSb2Ma/ecgb4bj01InMSC/GWHwj8isHNs7t0Pu++AOIeFOJUceeENSDukuD77SmEXRJ1qT2hXTZJIeihY+klusg9ScqaLPYZXr0k9Nz8/L6dzZMI2y8vi3BKgQIM1zcO0drgMTL2oWBBRyRjAtmquDuJnYt70fn2WSdTRFzSzGLCzrUVapMtwzdaWsy1A48pWu86FZXo8wobW4DXxKtXCv1lsjT8vh+65zHeClhkIPArQCwcX6XRLXGiABvdojqtuAfbcu1XexHoL7PfSNyD++ninizsTFm2zVDboTa9Hb9mE0EPmJ0f4an2aD25rm9Ys9I+5NWLQh+Yo0fYfvmBwC8xu6vjzSkKhOOrpITmZUF2bfmDA5XnXUTcKzbE/mls6sU9LvbGty8ch7cpinsLwt5U1JVXFrG/fUe6/1woW/kTzVR79U2FnjkGO6IP7LebQ4Ttl4NFPLWAguHbNobs6ngJSYRLhuYFb5S3lSfurA2xfxqbgeN37Tr7dduzimKfFW347VTEvbCw83nGTxIrCKaX8aqj9faD3r2vuKEQfY7Qq8P2ROt47O3is4yn2kozXkR3isZPodNSKjQ/t0V10cHCAoo7J65iG3MSdu7AhP7llFlqYl5+gth3IfTG0kd3RuYkHpKzuKzqqbd0DNc3DtFeGhKZd6bWbRSaD4ha0Xn3pMFCz8SdE9sEsffb4I9PtM3ZZ9qJCbta1HFV8VGKfZLQOwmS0OvC9liEt4zgVFwCcr12IvKEMiTu7r4soCZgt/ZHFucccQ/1uy1xD9nlxD02UODSmAy1184JOzd48BsT+8Q2gSuJngJiX1LoVWF7S0+MRmYd3vxigdNygWnitU/oQ2g+KO5iH536lYLdi/usUpK4c8LrFGbFVCvsXJuC0ZiwQ9QLERL7VK9eGbqPCz28+WUBp+iCMnx44xiROU05XvuY8qH5iPcdtMV7p43FXdVvxkagv2E7srhrxZ61x7SpssvYjwo7RL0bImKv9ui1Qq/05r1ylp7YN9o8gZX2/WfQdQdAOsO3bQyJzJPUQNxdWKGMla1X8TM14p5jy83OFPe6/X6Iu2Hs1dMqNjXiburp0+MxplaSSVLlgYJw/6bBvFli7Z/H+bcKDiKZtPqvgv2dPbA12H/u//pnL5yIHxToEpyyC8TYaz9FRPc1tRXy3qOizG4bx07tT0TsZxcStk+K+qxYqu21JO4RIWfTnEY5r10aqHBi77flSYR4FRCfggfmBudl72bkefSNvHl/Xp7I4HG3fQan8IKQ8jS6KI4IsUKnEPdZ3YhAM7ZKiru+n5y9QuLOtMHZjdsOiLvbBpfGCTtjTBL2kOCDDpHC91x6RZmDQq+Ym1eG7M+b0ejE24bfdpbrIugOnMo9Z3ch3eAUOe9qb0LuwjpZRP26McEM3e9edFFdj8Q9LvbMYCdwHF43xTQj7UbTQc9QC318IV6eNy+usiey9n3f997XD4Wegw7AKd1jSiykc+ksNM+KGiNomoFCpVJQ3IO2A+KutllK3CsC7J6Rrn0uzbXJ2XXKxdJBz8kQ+uLePCfyhAV4fQKL7HrK8K0bJ6nwQjoXV+zqicQLR8iOZ1coqxR3sZ3Gt8MtqLgbIW2WVTFk6unucdSLgUXDEL8gzzi/hUlBcn8jtSpuJf434/7w+N/iA1uD/ed+6p997bj6WEBr4PTuGW2E5Cfkeu+ykDonOSPQfF1G3IP9c20Z367YR8cW0+da1Q7EPX4xdY+BsccY4uyytsHiw87FF/Lm/Tn3+hPweE+eRta+7+0I2XcKTvUe0UZIfoooxL7IhMSyrdB8irjr++jYalHcRbEP2WHa8WzF7DMNQdhXF3bVvUboNfP1ovCLi+9oRPTELQjZdwZC9D1hvEq+tZA8f203gbxQPT6PE8pakuS9i4LsZsfFXd1huZFWxN24dph2WFsJ4m6Ydv22wTKjD9tPt2YboQGvsz9pq1qQey7DgOiBzcH+cz8zfO5Y2pGAEuC075jh+sYhWhs8RsY+1Fojjtc62/YFU+cZ+56w7HFX6/LiLgpmpK+erZBt5Yr5tsTdbVgj7kFhd4xIwo4zfIXRhO25W+oCnrvGk+dC9paILJm3vP2HXndK2XtQAJz+HTJ8ZOMI7ZjTVODBNSHK3hYXEemgTb/uXObdteIu2ish7hUxDg1KYrYde+4xiTbBysKFzit/SBWyj8zLa1bYWyKyhh5/+3vuWdf2HTQDl4GOGM+3n6ESD64JEfCI08V9ZkQn6GFxV9mpVAoJeta8e9/E3T1uLg1eO8ghwZtXz8tnijwRPbV/tHkc8/Ltgzn4DqjMt7cr7lS/1hsuVRAnfjtN3N2EYGhe6rfyYTa83QLi7pj3Oq0Ud+P2WTiGWtNm+sczwIq78dMAIKLd3xLz263/tg3zm5sWdTb437N47tXbuw/z8vMBAj9nhm89f4rIfHgujalEMFwtZCal+WAeI8K72wpxD7UT846DtpkKwsVOI+7e96+1y9hyhZwbPADAwS2E44R5vFXbEEVeO8Cu5x8cDQZP/tQPf20960CAClwW5sTu/e3mNBE9MK822RD2nBbWeSInXQSCdtL6WrdVqautP92fFY5d5LLEncL7fjuCLab/AGjR3N8+3nI2FIvvFPfKV+x+4JH33nMytf8gDi4Pc2Bei+lqiCKaP/ceFWlpYEAkDBrC/Qz3py1xnxnrXtxNPQviDgoTFvlZgbZF3lp6/BaLt9KVBpeIlpnbYjqHvnrvulXzcXF3xVElzqwYJ9RX2Wtf3DmxByCbkHdNNDeRJ0tP7bdYfFcSzMG3yHgx3Rmas7i7wiJlhaq5qa7AVbc5MePEXRQ8yU6gb5w4avunFnfX5DzE3cw6NN2EuIM2MczguXZ+MoNe5blV/60z51fd7n1bZv9ZLL4rBy4VLTEW9/kspnNYRO/d9Vx1fVPWFfpatxW9+FT/yMfr2E+3Kdip9RWAdsidl2/kyfs2Lw/s6DjeL98cePAtMNeV8i6SN+vvKvLKiXvMe5dsqu1UhdEtLtSP3Q4HcQerRvhWOqM4F/j9oCfv2zw4MlhhXwIIfGGGbz1/qtXHzkZgtcy4Z55W+Frul7fvNyyX9TOiFx3tCEcadITKMXklxN3E+g1AYdhb6ZidHJGvN+Rv15wJaz8MkW8GLh2F6OI2OA/R205YOT+t54+ydTbMpMlZtyThq9UVBE5lx6+rF/uoNxGvH+qb11fOvizuOENBZwQX3+WH64NvoeND9x94O26jywKXjwKMxf0MzfM2OAZWZFqae/cEq5KQe897qF+inZBAp4p7tI9+n4P9DNlzbYhtANAh8xD58Mr6yZ/H3/5ePMM+FYToG9IXcXfDXUbIClVzFTQkzNVt4yYktx1XMrGEQpCDnneiraC4a+25Nrg+QtxBHzChAawRftfxAWvGIPuhn3rfC6eyjmGFwWWkAeN73E9R1+JO0klYOXmi3iyleeFevYg3GxTPsPeeHJrPubBExVgh7oFj9+0FxB2AHiKG0lM8eWeVvujJy/Yev2E3T74L98qrwOUkk64eYCMxux2uLoChkbUo1GphDote7m1xpR5okyLubF3lccb67LcFcQeLSdciP95+6obdPA6Rj4MQfQa9Ffd6qrfpCkqOuPA2eO+9uu0KZrWCZ1MwE7OpOz5H3Ll2hPZqwlzNgriDFSEpXE+V/cBvnbPBGpol3XeL2X/m0eHGIWW3VxYIfCJ9E3cXVkhD5dzUiPcet6HM0ww0REGPD17E43PzFAMF7t7g6DabB3EHi49G5Ce79YqK7ZD9+gDivlsIIh8DAp9AL8WdPVF4T7NX3rvUR8FMcr3kQYNQ121Xd/Fh7EHcwfIQE3n9eeHaSxqEQ+QjQOCV9FLcKajvte1I5Iva8t5DJ3ZI7GJCKtl0y8Tm3aV+1+1GxN2tD3EHK0C2yFeTNedq3YybCJEPAIFX0FdxD4a5lPXa9t75Zv1GdQMGf3SvuggIXn9o0DDbZo7RtRW8mEHcwfISFHkSzgtDTinOnomcl7UkiLwABD5Cb8WdpBGtf/Z4XnPMXkveu9Qnt0zuM+yb2IldeKrow/SCuAdsA7BoyINdpcgHTgjdUzCJCCLPAoEP0GdxrxEY7HJlp5vSaFmuUkloyXsXT+jwwMUr4hxbyoDF1P+nfNmNk614sx0AS4F7HoREflZEMTAP1OXrQ+QdIPACvRd33n33NrWCEjOXFAGg4EkYPrlT+6jIE8sG+8aLu9iOJqKQ2lEAFgVG5N1t9vcfHawnD9Ah8hUg8AzD9Y1DROY09VXcSSGmkTrknEAk7IaMFPHeNd5x9tvw/IuD+12lDDZkL8W1xXseEHew1ITOe4WzEDvfWHP8eXzfftr/WLzDyw8E3qHybPnDXfdFRCWm4bIBE7VE424LNbK991g/JLHU1IsMVuQLCnMFUl9gjLM/zoe4gxUga2V91GngrwGR69ZDPznEs+sh8BV68+KYCPwPW/ByQ3VSvXehuXa9d7+Mznt3G9PaNGzf2CiAZw7iDkDTlfXaaJxbnjnNVl7kIfBVFkDca/CRL7HsdFMpOPyJF/be2cSC3rsnrk0uBtJFRdU3YtvwxF2qC8ASo3pBlFQ3You365cZ/3nop4YvrGy4HgI/ZvjW86doEcQ9pqYKMWVrSidLqFk3Q4wAlPPeq9sp4hkcJAQM6x+4w9RN7SQAS4SRdhQD7tD7NUIDcC7PWnrnTwyfWw/3djmBwNNY3I19qOt+aGB/zBER4U80UY1nxQQRY2YDojaKee8ZoTzdgME/ttjAwx0YeMcBcQerjJF2nfNFE1WTrlvK6Jyxgw+vosivvMAP37pxclHEvYZ48oTLhka7UmKy9y4O3SPZGjGO9SkxT+fZB+xI97tD3AEoG6pX5kl2xiJ/LFB06VhpgR8+vLFOxjzadT/UxBSZGcGK3rF04olNZHjvfnUvsw3vnbjd4Eif+bKy7Lj9AQA0ea+EuKo+0c4sfXBmlUR+ZQV++NaN40Tmw133IwXpt66urywbHyD4FfiTbZ7euzMoUJ/0/sDF7Ytr0xsYRPsGwGoTcjTk88uv3Hgwb+mgIXN6VR6Es5ICP3x44xgZc7rrfmRjgrtRgawlSycGV0dhN6U/Zb1336A2wpCXV+mn8nsBYGWRxJg530NVi+RZOryf9q3E0+5WTuAX4Sl1LOyv1VfLuNaY4FkR8nKl7kRHzjFKeO9ZITvee9f2y7WJ0DwAMm29AjrdpiGydN++0b5TKf1fRFZO4Hv/lDqBqKBGKkXFRy2mUmfcXWZQEO1PA+9d30VdXnCwEh7wAAB4VFE7haOQe37Xyhl68Cd+6Lmlvkd+pQR+Ye51DxELQyuURhoA8wV9LzfahDQKF8q27b3z2/GQBz+oqlyMtFcSAMAuosctDO6r+5KXk3D+m/r/iMi88yfes7y3z62MwC/s7XBEgnj4ihvXm7CiqwRZMmecDLeoUgzjAw7GXsCGenTvHEvKgAGheQD0qB5zLTkJSkcjwYsnMmZpb59bCYEfvm3jxELdDucgDVy1laLed8RbzhHn0GAh5BlXEyVH2y2YPXpPvljEvQwAQBz+HPLPr1C9cl48EY0GZ35q+LUjwU4vIEsv8MOHN46RNae67kcRAiFkPiFsK+4tM554rF+Jt8ZFbTOZ2pXz0ZG7UCl0oQh5FAAAJYXOudxIXq2cISKyB+1otHS3zy21wI9XzJ+iRVsxXyWmqIyHK3q7sZMh6C0nmWOMh2yHvXeV6ZxRe7BPbl5aPQBAGFVULqVeqhfvYInu2ztarvfIL7XA097BKVrwRXV8OFtfKSc8X8tOCc+niLN0Mkq2vf74I4z2vPfKRQfeOwBlEM89xYC/hBdfMWqm7diHfvw9L5wMdXuRWFqBH75tY0hkH+y6H8XoWXieF2emTlQQ/RG7VkijA5YS3nvGRQUAoCN5sC0nTSs18eJ3+2QfXZZFd0t5mRq+deM4GfOZrvvRGOfHaiobksfsipIxTh3JriCG0xMwVr9SWLrfnd1mvOOmxyPbMBmPpOW9dwg8AIWwRJbdtrX06R9me1x8aoC3F7Jhx/UnZc3lrT2bR941PHop86h6wdJ58MNHNo4s9GNoK0Q91Fj9WNlIfpKIRUbFIY88Hk1Q9kcYFCR570Ebyn4AAPS04MVrbdRq1urZg2s7exdeR5ZO4GlnAR9Dq0ARsQ5msp6qWDAshvwJw9QxoVwnVRJWro7keYdbkLsr2jBcUQBAYfhzTDj/pIG3YI9tS4hYVhmQeWDRn3S3VAI/fHjjMVrwRXUsgV+rVhA19Yt43woFVI+oq9tKZQ1679EBR8iGoiIAIA/N+Rbz4qVRf8ypqRZ1Clpr3vnBf/rCCWX13rE0Aj9828YJIvPOrvtRjFh8Xv1jT7Ffye4gPB8UVi454eRXee9MIWg7APMh5MV75XK9eKZA7LplDJ1a1IfgLIXADx/ZOLI0D7MZE/1xRvKlkHqfw/Nhi+PU2ADBy4T3DsBCEDjvouest9PgWuGVswe3d3ZOBbrQW5ZC4GlnwR9mEyH+w2xgN8NTz+6LCZ5/oq2kxYKxUXmgP64RaDsA8yXqxVfPb8VJqY321eqw1xPzwAf/6fPDeIv9YuEFfvd+d3qg6360RuDHGP/N6iefVOH1QH52/WqxmOKnDBCqNZUnd3DAAoUHoH0yvfgkh6BaxRswyJWNofd+8J8+e1xnvR8s9GVr+PDGMSLzZNf9KA4rZBWBY0axtW2nsmcrWN+I967z9Y1Tn+L1Sx4L069ZPSP3h/Hea9+B0B8AQMvk3hfv3RO/m1m/v12+l946CdN69f6cv7m2dWxR7o9fWA9+/Jz5hb9PkYPVkpQwNZesGgGH3dugQ6voX1pfAskRz1rMVnnvTEgC4g7A/Aice2ovPlaHKaCMQh7es7PvVKgbfWJhBZ7WBo8R0eGuu9E2+aIaVlHPQ401HsjPrs/0RSwRONH578XvXOMTHQAwd3IG9iFvQn3tEDozsPTgj73nuXW5UH9YSIHffb+7fajrfrSOyuMsK0hpT7/zC5dcPV/0Vj2nLP/9hY8HADAf+PPOVP5fSVGco9pBgtQHt6ixg8ceXYBb5xZO4IfrG4eW7Za4GjE3s8GPUkwUzpKSgwj2BAsWVNRP+C6SohEQdQD6g8m7frT2LA8iIrIH17b7f+vcwgn8+BWwS3tLHEumKFbzG2lWLMSV2L+0+mVCbGzELhaNCHULANAq2ghgfLqxfJh+HEt44Md/sN+vll0ogd99Wt0SvQKWQfrh8T/CgJVYeD95xBrPj+glcSenVKXove/KqQ7JLgCgAwLnYuzyF0wuFKYnIrKGho++u7+h+oUR+KUPzbsoRamkBqWF98MKzfaxZHg+ZqrhAAHaDkD3RK8jTR0FpmKao2APrq31N1S/MAK/kqF5Isqdf4+ZqqdpwlGZ9DU8H+pktF8AgLkQ9zRmKXO4lrDmbH9D9Qsh8KsQmieiPFFReL1FvXx3Wxw05NvNqZgdnofbDsBiYBKuawWjgVGzhshSP0P1vRf4VRxmaAYAACAASURBVArNKwerzdtoef496iW3EYloWB86D0A/iZ6PJdfzcNmqC4I9uKeHofreC/yqhubj4aNAzRwPOukk0Ie0S86/x0fsCM8DsHQEPJ/iU35NnB9rHvixf9KvB+D0WuCHb904vhKheZdYWDleLMlmsTYibTY9GT1bhcLz8b4AAHqBE6aPlQ0mq+or5+GnxQePPTrcOBSxPDd6K/DD9Y1DZFYjNC9TMKwtmleOJkgp0E3D4x2E5xOyAQAdkBOmr2UXvK6Ep1LtwbWb+x+LtDY3eivwtI9O0go8a35KtkAHknOi9Q0FOs9opFbmSBvheQCWhLCq1lOCkT3FRTEWGYxgrX2oL6+V7aXADx/ZOELWvLfrfnROYbFRhbV1VsQkNrzfcPQs2s0kbU0DAKBXBCKLTc3x14bEBg2RHfUj+txLgaedfnw580T6kaX9eHNc9pTwU1pXpN2m8+9Vg+J31bQ+AKBXNHUesuorOiVcQw5/4J88O2xovTG9E/jde97pga770VsKhvIbVSukhklmMk9mPhHheQAWithJHTul256H98yZk13fG98rgR/f896bBQqdoFzzlvTDFY01WGCnqOMl5pxAmfPv1fx4CA4AsFB0ECFM65MhIjo4GGx3qme9EviVW1gXJEEYFdtFiIyQs8L7c55/rxpBeB6AxaKVMLtkV1shmG8efPTd3S24643AY2FdIonCGR/VKvIT6uSfcy3Nv0PBAVh8cq5hTefhVRdPueqgw9u9eyPwq7iwbsqcBalh2Cm5gbTwmc5mKD9uHvPvACwP4ZO35Dy8VCcyDXj4x/7xc528jKYXAr/7xDosrGuGwvPlasVGty1Sa6+NBjH/DsDy0nQePqfJxIV2EyzRsIsn3PVC4Mms9sI69Rz6vAQpcOKI/Wi4wI6t1UboDPPvACw0xebhw2tzSy20m3BwcGPvMMVUCToX+OHDG+tEdF/X/eg72YIkinH+nFIxchbYtRFiAwAsDi1N8SWbTa1g6J3zvm2uU4Efrm8cIlpt771GGz/cUiSsoM8fVevPsqQBT2wSDoMCABYcfbQwy1kqFC2c921z3Xrwu7fFrdyrYJPI+bHOYzSqrFNkmiFzgV0LU3AAgD6RE2bvYqHdBDvf2+Y6E/jxQ206WVnYf8qqT4OIvGulUbG5ampsHQEAYOmY93meFgGY7gyLd0SgOw9+Lw0J3nseDX7FjefvC9F4BT0W2AGwssxtSpCb0Wt40TBED8zLi+9E4IePbBwhMu/sou3eoV6R3kLT8wptZ66gTxbiPq9hAACUYw5TimUWNks15/Pcl248+O3BsJN2l5acSXe15cxCCYsHtDSuAzUHYHnRL7Rja83xmmSIDj/67ufWM2onMXeBHz6ycYSMfWje7faV3i0K62wOvaUV9ACA5SbjIpB13WgwLSgwzOlGCvP34OG9qygiXGL4v7n18rfINe+IOryPUQEAS4t37uespC8Mdz2ahxc/V4GH955H5x5rh+sEIMYAgBjFLxMFwvVKE8OMltTM14OH916WUr/qOczfFwocCNb1xTsfLAEAipCz9IetUPBCkGqqbS9+bgIP7z1Cw3mkdoWr+T3wUrH8W+QAAKAbsl46IxccNulLiPl58PDe01lV8etkhT0AYKFYluuEbc+Ln4vAw3vvDnGRiapiqQ6kFy0SkcAtcgCsGHm3ygkWCt0Lr2KYXEPBfDx4eO8JQIhY8LUAANqmq+uMpcOP/oPyXnzrAg/vvTCFfoCF55ByCybT2LPHQAGA5aPgGqbyKK3vKe/Ft+/Bw3tfKHIWobbfCAAANKfxrF2pW4a5OpYOP/oPXziRYU2kVYEfrm8cImOLdhgsI5m3quQ85AYAsPT06hbdBCyNir5htV0PHu97D7No97EDAABoDVP4TXPtCjze957OXGLkLZvq6WgAAxYAlotWz+mOrod2ZNYLtdyewA8f3lgneO+gCUs+4AAAtMACnO+RgclDj75740iJdlr04M2wPdugS+b3BD0AAFgOUq6PdmetSPS7FYEfvnXjOBEdbsM2AAAAUI5euibrj57cONTUSDsevBlg7h20SC9PSADAqlNuWvHgaG3velMzxQV++MjGESL7YGm7IBHxh5b3FjYAAOgdS7xOxxjb2FEu78HvELx34NO3E7GHJzQAYAWRr0WH/89/+NVGz5EpKvDD9Y1DROWW+AMAAACLRMmFx8Y209OyHvxeOkG4NQ4AAAAowYNNbpkrHKLHg20AAACAUjS5Za6YwA8f3jhGRPeVsgcAAAAsGlbYzrZnaT23bjkP3uLWOBCgxC+9j3YAAKAJ8WvRwX/5D766nmO6iMDjrXE9RPzRJCobhBAA0FdWZcBvTZa+lvHgsbgOzJW+n40AgJWkvQFH1mK7QiF63BoHAABgEVkMh2F7e209tU5jgd99ch090NQOWBykRSSLcZoAAMD8aXp9NJS+2K65Bz/KX+EHQJBVmV8DAJRjAc73TMfo8P/xvz57PKWd5gLf8Ek7wCH5x1nw17zkgopoAwDLRavndA+vh8ba9ZTyjQQer4VtSA9/QJJZCCIAALRL8DpriYjSVtM39OAH683qA0BEZPNGEJbZtBiYALDqeNeAoheC+VxVhFYO/su/r78nvpnA4973paCRIDYUZgAAmBdW3MkxUNiOGr0Xny3ww7dt4N73LigkjrbVH2V7Ct7YO8fgAoDlI+O8nl+kT2k9UKyaNTL04KMnNw5pTOZ78KMBvPdWgAKx4GsBALTNglxnbg72qPQ3X+ARnl8IqvNPSb/dDhYAFr+/vnE8DgCwWHALc7It5F+HWr7cGGWYPkvgEZ6fE6s6vz2v416G7wqAVWUVrhNy26owfZ4Hj/B8eQrOIZX/PTafQ5KKtbsWAAAAymNzAgWFC2rC9HkCj/B8P1i0++i7vFWFmabAOAGAxYU9f3NuA+rhs8I0jWjC9MkCj/D8/OlclErdGlKqbQAAqNCLp9jZ4G65dmZEw/TpHjzC83OhyA9WFObm1qPTAx0MANQPu8GgAYClRYocdrnmNmk6NaFvsTB9usAjPF8UtXfeA4+59XtFc+bwW+kLAGBhaLh+Ka1S3tRgWxhLx0P5SQI/fvY8wvO9o+w8kmM5s1CkZicrYDEcAGB5ybtFrlHUsWCdnKijjczDp3nwhuC9l6bD+W1pJWjxSELmyZbsqWNFPgCrQUvnevl74JvfgST2aXfn4I+e/Kqoy4kh+rQ32YCWaCBK+T/UspS5VQ4r6QFYRcqs+1FEPpn8rOtVixhjjkt5aoEfPrJxhPBq2DlR9hdUZl1d2ZFo6+SsaAUALDTzPs/V7eUU1B9MAQ9+G+H5TkiYypbC2yXaya1TZAV7wii7d4sWAQDtEXMoclbQZ16j5hIZ5Nc7HX7/yY0jXI5e4M3geE5/QAJ9nkPmQlWx7TZCZpG2o4VjBwIAWED0nm+WELcwJciG+jOvRQPib19PmIO3D+Y1DUpQZsFHNS3vl1RUC3MWvbQx+gYALA4tRQHnEvUszm7HDfHz8CqBH98eB1pCvXKzI29d1Q8+dBTJjzSvEnMstANglSgTLQzXEcP7STb10cKm131LxDrgOg8et8ctADlDUMq7Va4Q0XBVgQZ6MWACAJQn4IjEx/6ZEcw8nyViVJcVu16+/+Szx900ZYheXoYPClBwLia3OV3hjAlySj3xdDZD+XHzmIcHYHkIn7ydL7BreW3VpKhhVtNHBX64vnGIiO7TNwfmQuIPtbX5a0XIKdmgsp/iSZUxYIK+A7AA5FzDYlHKNqYCY6ZjU5oZGLLH3bS4B78v/Kxb0BZ6l1Q9h9+UiOOb9ZvNWWjXlJy5NQBA5xSbf9fY1VZQ5rd+rbR0n/t2ubjARx5mDwqTMR+T73krGwu1He1HwkCFK9p0dI15eACWj6bz7xlRwrQ+6acB8x0Y/zi2aM/x6r5iDh7z772i5fkcdbVCwph/AoXz4yNkzMMDsFBkOBAl5987WWCX2JB19Doo8Jh/nx9lwuyKkSlXK0kY9V2RdtsaYeeczK1OaQAAipE/f96gvqJTxSOEsfB++Np5vLoX9uAx/94thRWnKqz5psO/vqYnoaZIgXMyuX0AQE8IOA9NzfHXhsQGY9fYYl5U/Ro77mptHj4s8Jh/nx8FQ+/eP3rJfmRFtpv/eOMF/ULx7wFhegAWAqUoxp2YlubfdSZluwWcoAk3aO3YZDsyB2+OhfNBu+gnfVp55WpOmL3hACF6HE2/h1j9SHUAwPyJnpdtXxeSpjGVjkOj8H5goDIaHZ9sxhbZPRDJB22g1NwkMUooXCwc3uI8vGq6IaU+lB2A/lO9LGSKdtPIINsXrmSDa0qz6/xsoZ0o8Hj+fLe0MrIL1Uo6WfSh7ZInY+ywEaYHYAkJuMxNnQapfo7TUM1Pq182UmsqjrnswQ8w/z5vsuZmctoo9COWkqJCOsdwmrZ+sagFAKAoOeH5uU77RYxFry0tOD8/cvK5Y0QhgbcDzL/Pmxxlaer5NmhOHDHnRBDyulMsTN+sEwCA1rEJ17WmEcUUs00FOr87ot3Bzigi8GQh8L2gZc83cZ4pGWVITNt4fOoCYXoAlgalos7rWiKZ4+uHuxPMSjwWz+b4DjhW4McPuDkc7iFoldgPIF4svcnYWMKKO14S28cCoSgtSYMdJgoAfQege6LXkabheaZi06lLsXuxi2rJYzEU8ODXCN57R0g/jrQRYtjtro4Qm/6YxaS2f8wRgZY7FsmCygPQDwLnYrHwfEJUtKTTo21fcyxCkfuIJIHHArt+0SDcM8nvLszetH6LYfrIyQl9B6A7otNp1YF9cJDfv/B8a1HYisH3/71nj/MCjwV23ZHh+dZK5owYY6IYbzZKK2H6hO8iKbwGZQegP4iDcr7sdLPj8HwOOYMVqbA1o2NrQjMQ+D5gicjEswLF0pu0RCZkrNaY33K1Pt+vSipToHZcsb4wFVXfhSWyhvv+wscDAJgPvDjbyv8rKQpVLRmev/UOolvvmAmtrRSW+sY7G5b35it2b94wdPFC4mClgifwWGDXL4JCHlQzR8U4uzFRjKll0/pMX8QSzrHEvxe/c2wTjKGSA6a2uf3gHrr9VXu67kYr7Ntv6NV3723NvmXdHkWpQIIVy9UrWSK6+/V7BHtM2zY1LdgzTzGsmBboU7Wkk/iqVxPt3csctVfUEcrqVu2Pr7aWKev10Pk3iP378N8j871Eyrjkevabr9BT3/4d/1W2w+178Fhg1zlRIVJXqiSH9T6usqLXq+/ftL6qL4HkoLoHssOHV/fiI22kcPvBPfTaN+yj175hL91591569V1C4AzMF8uJt5smixInSNYpM8sNiNb0DydiroBVaialOb1l1NsybqKfZtg06bv0yhlLpvY97aaR3T3F7CStkrD7Z5ZbqTlLr2QbMrPvrVatluPl1Vqpnvv1Hb8M0e4FbbbjfhPZl49bDthGr2vnrjQQ+K6JKXxEcNLC7OH68cGGX6KLML03PhEGLOyAhxHzEvr+2jfso2N/4Tb61jfsy6gNWscYX4Q8HfGFhTHEl2EEJGylJj/1Wv4Gb1JsxpFPtpzOIPe1SVXrYh4orvmaWTHnv+KwyFM9j6j23Xo2a/k0LUN8VmWnViKbr21sHHnd0aPncur6Am/oSKPegLKovM6AkAZdZUUzMXVjBDGpfrVYsOzusaijANWa1UGC8vv0EhJU/vaDe+gv/rVXQdiXBZX4KKv7GtXYfsiALOZMPaYcK+aCmrPDE0/hhTTXO2a9eD/d609I5KmeR8R582a8a6vFmfZmuXFtly4cmoEj0fba2hEiOhcpzMKsoscrYvuGFbb5hES7KfVtcDduq3peCyN7zlbRe+ID/XGNBL93gVffvUZ/4395DcR9YTHs5di4e8Lg0jBbobbiWYZJi7Udb1+uH7dMJETVhCbZZO/7myV436GXzmVL35NTy9R3TCBv8v/aP4VXxnh7bBF1pl9wQLPXv6bC3SYHge8BrKAkCB0rTipR9UtItkIdi96uJ3U2VicwyOAHHL7ih74D7ytIUPlX371G/8P3vJr27Ve6+qBzit4hUcAWN7wIpiiE1tT/x2UE7fHfEd8w21dOzCUrYRUXxbyoyDOKHtD1SgIv9sm67nx2dsx3UCY1gR+voD+YawwUJKbwMVFM8Xq57AzPXqwSEEkvSyGo7CAj8n2I300hL37ffkN/6cQhiPvCwSmaoozGTiXZ+DsB7zG//RQvXmtFsmU45Te6IQqj+lT9YkLH0Y7Ix7x544t1VL39JnM+OzfpT3rGlNQ9eKyg7ycBZYmH2cNuu+Dkyu03DdOTJKiRZpUDDn6Q0L4Xf+y/u31pb1cDFNNvIa3BwMDJMsyGn6bpmGF2c714Aa2es+kZ3n1lMybyRsiblXDMCwk6XQ/68Wr27ivkwRPC871FHSlWeL19DtNrByza45mHF79vv6F7//StgV6APsP5WnHNFBQrmha/yPOta0jxvzOsMCrPevHsEZgEMZ8V9EpI6V6eLOSeyGu8+YjQB3WdQpnxz2APHXCtaBk4e4dyDYHyZM3DV4suYJg+VE97PEEvXtluyIt3+/Ffvzn7/AN9gA01RxM4Q/pcT6iE6pybHvTs3bqcd57pxTNNiOnqRMm1J+Y7aijyjjcf7ppxq0Td9oKa7n2+9uyzx12zGuoCb02WEdASynn4uHffjzB9NAoQW1dQTZU88Aji8+kTvHiX12LF/GogCFHYY84bGCQvtlO0V8KLl+bdOQvSSvsk776hyHsy7Yh8zJsPCr1S7FnRnxNuiB4efF8pMPddLdtFmD40YAk63IoBQ6iTtv6/uA1FP6rHhVviFh+dxDIipNXYgKuuv/jzJVX99HbzvHixZ41C9bUsvwOsS8xlS0Iu57G91Ap9tawo9mHR135y3/DqCnyjx+KB8sRFNVwp6+1y1Wzl5L8XBVD0UXs8tS4EJt+VXU334qsvkmDqYuX8EtBCmD5N5yUxq6cZeSOSJpuX2NV8pRcv2Q4ouSTmqemTPyEhZ/NC3jxTZib0wiqJoLveRN7zry9TgR/fIgf6Rp/C9HpzjPGQbeF4FA1EQ/0lvHihVErQBCwJnNBwHqms5AlN6etFBxOs0html6vFDX6UaSSE6lmkwZFO5GebMZEPDYA0Ql8vqdbzBmzfNH8tp97Mg8ctcv2nozB9UhSAe2GFWDZQLmAkFFVoz4uv/KmkH7iVe1YUWEQYXzVbmkPJxt+Jjwcq3rnOi5ftScckHqsmuDFJbxyqN/x3kiXynnsve/oNhH5WOiD41foZn50dukUyG2JQ2YIH31O6CNOL5mNRgOq2Yu58djxhLz7k+Wd78dHIgpvntEdE16+NAjXBQtEwTB/WVs1QodwQw5Mxpcee4sWnheq7EHkxUfbmU4Q+4Lq7gt/Qgae1PXRPTr2q+wEPvq90EKbX9osfcDBefMpcviIzdMtcqCkxzzkW7aABrCCcwCg8Zz8t34vn0oKevRJO88OmuEGRUDgg5rki7wm54617Flg9j3vq4sx7VMFnBfj/JKe9/t/aPnOX1EKImcBbePALQYEwPStkYkFlmJ5pQDVg0IhpsF2bLshSaEAT7pcW3IGloJwPHfbdU+IA2oe/RtvSevGMpd1inBcv9EN/j9w0PUfk63m+utdF3B8EzHZZVReFPir26h+NJPFlqHjweItcnykZpo82EDOvEsWwF8/3xw+Be0LaphdPwnfrjQWg7EuLNkwvO6mBBKWQqorzXryUFmjFS5OEn/V2SRJzSfylRXelRJ5PFL35TKEnioh9tV6uhjvlv/a1Z48ratXACqFFoaswveCqRgccwbnzQJda8uJDx1VqwR1YVnLviQ+PAmQxL+TFK0IHkgOvdOxnyerFdeH0VkQ+5M37FeNCHxF7dcyn6QBAQVXgHyhjErROSpheEKDofDNXJ3ceXfLAA7WzvPjY91I0z+8nWA5011a5lMI/1luOePG+mMsVgl68UtF3i0WHFpUkcUQwJ5GPefP+QKCeKyhuRIjlGfc8DBka2D3J0+jw4BeIrDB9tY6yrDRFHarAe7phzz/FWxZtOKmlvPjQAMg6dcGSoQrTEyNErDIF04y/I1bKui9e68VLxRjh54YLRCEtn4fIG/eP12NZzx31F7Q84L6rvW5J+GP/7Va2ydPoAyKi4SMbR1Irgg5ICdMHBdrK4io24Quh1gsOeuCB2ulefOC4goLPfFmZgw+wrKQEyfkyvfLiHeEOirnomHMiL0h2aZGX8vw/lTzem2fFmxHtWVJA0Q3z6ZBdD36bjnTbDZBMQjhaEtTYeCFqWyOCTO32vPj0vFAzKjtJr9wDiwL/UhWuIJPAiU+rXjyfJgk/693WdpVtJHrsRUV+li3mTf7EvPn6btCF95L8G934wyjyyQAh+gUjJ0zPC2rYbdeGs6MiKIXHpf45qblefCjEHjKcsuAO0r5q6OVVKtGOFx9x3lUNyFXD3r0s2nxySZGf5bHeOu+0k5cRFPqwV+8m83e3F8Kk3+k2GPfwSLlegFbJCNOrzIkeeKBZN0McMzBefJNweIbA6jx133Bobh4sN9Kt3F6CUK4zL94wJZVefFjMpXTJj5ZEnk3OEPlZHt+axpuPCT1fM6bhnOiHHmsT+xgytHk9Xach8IuMP+UcLDvdVIpTyIsXTPOJpb346r7Si4/2JRCVCA1uoPPLjCgpkbRwida9eKlIsD4jYKLIcyYYeZUqkHQvPDUT+brTXuldPSNH6A2zx5qIOO25Ep8LQvQLCC+oghcfqsOMELSCFfLAid0t58XrQvVuY1qbfKiejXSApUf0CqNpQk6guvF3Ar3glL3JgjupNd3xyovumOpjG01Env93MfzXV01JFXqV2CsEv4laN6i7K/B4TO1ioRLUcNmo+DNiGhRrbrslL15dLyLGKaF61QAELB9Fb5kzwS2pgYjWK1CE6h2Blpxvo8usJwfum88TecN/vdP82h+ng4lCzxdgNDdByTPd9737zGtlozxjDx6PqV00ooIaqSO6pDEPNTA/zTdUwosXohNRL94P1bvfVXaoHp78CpN2y1y6F8+Va+LFe0UC3eFEnikRTPfJFnnxa42IfNSbTxF64+8y+q8Tfc0ggC+7Z818q1BBBCH6RSXkdlc2Qx5zijnOqVUUbzz/He2jIk8s2yRUD1aGlFvmPIEIqDu35ZWr/fEVK2XBXbBcqGyyyAuyGxT58ABAFHITkspZJl8mLPRBsZcLellhWU/LTQUCvwz4Tniw7HRTObHMh/15AZQqacP7Tbz45AV3QlJM5Nn+gRUjwYsP67yXFvLrNPVlG9pQPWMnKPJMnWSRDw8A2O9wmhfJzxR6ZtdJFUYFCkWODQByBd1lIvCYg19AeK87LIQqLzhREKW8bC8+de67gB1vsEAy2mfyg+WhkRcfqOhtcSoeUfbmoXpO5Lk+8u1LElhe5EMP652JfHOhN7VNJ0e2zZXQKnlLij8R+PvSq4LOUXnM4Xolbpkr7sWLeTbWhGDHr1fbD/afOUaxHbBatODFR7Ikrc8O1Qd3HZGXxjhCZlzk0wcAk3l5UWiD3vykVzGhr5SrbjK7OsEv4ZPn1UeIfsFJ8piZ7Fqq49m24cV70YRoiD3Ql6RoQPlQPUR+tZi3F2+YNG9Hq+u1HcXAhBkQSGKeL/J8nd283AV2lfyiQi+re5qMN3PdL168mBRth8AvOgE19QRIE8qONZXhxfOiKvRRMJNcr3ioHiIPOLRePCdKpiYSwbreH65VTtkV72R3NqT06dacRJ4oJvKR/Mp3nir0Os+cT+KS0wYBso3t7RtJd7xB4JeMkIfKlnNTW/Di2TzNYEMUY1+BZWH2e+WOM6IiH5oHsEQvvbjNtgaWj3wvPlA8rulhGzVh4Y0xWl3fjYo814GCIp+1wn6SHxHwStheK/Rxsa/UCQl+wEjyAEAzKnCAwC8BvAceF8HOvXhbEVyhfcbpF21mheq5doT2pOjB5o0RVxusDIIXzyl5QN29rdofTvENu8mncWUlMefSmX6WFHkSBk+T/OgCu8JCnyz2Tl2uRkzRkxU/zmC4voEV9MuE5IHzRSMGfHs6Gyl5fqnQKnUvZB5rQyPyTHvy4IEZzICVQu3Fy8khnQ+1zPzhhJQXfl7vnfrSbnGRF4Q+usAu9EWNhT5QQi/0k96GxV6nu02VvfpZU7U4YUBrhKfYLQGhkHR1M+jlRu2FbOR68bxN3YK73FC9rn+slw+RByyyF+/JX0DdvS3jpks16zvZ8/HBPgnpWSLP5xFNRD7gY8dEPOrNj9ueCH0DsecEv4HDXRyE6JcFSawoLHJ8CNz3cFXeLueNq9qOK6VYokmo3rWrsAWRB0SyFx8SynDZWUJYWjnFl9x0vuGo864v0Ejkw6voC3nzGqGvqLROnBUKzySV+KQCgV8i+HnkfC8+qa2Ax13dDgloyIuXBzCBUH3UrjOQcZuKRgWg7qCKoCacmHtbUkKgUO0PJ6KS8PPePbMbTfeTBJEXvPLwAruIyI/zw0VShd5U/yhFlZHiNtQ9Q+Eh8MtEwG1vw4vnxdn3bFUPwpEW3DUJ1QtN1av4x8mVl/sCkV9VePFJu21OKudtGTedq+kXypmPb0XkhbxZckTkoyvpY+qnFfpJj3ix12tsPxQeAr9ksNqY/Ta2/LZV/fL24yH+JqH64HFFBiGhKQqwurCXXK2es8VnBcMiz4k5b1Q1Hz8HkTdC3ixZFjFD0oCqUiYath9bGpfTSWZd7PMFvxsg8MtGCS++mprgxbsJbSy4Sw3V6wYyTN2QVy8dO1g9Urx4T+TVqh8uJCs736OORL6ezOeFH3yj8ea1Qj9uTO3VT3tIMcHvk/BD4JeQ4l5844FCSl7zUH1IeOXBgzOY8Wx73Yi2BVYDQeMleWML+v6usMVpupeeIi/yynp+t12RJ5o48hpvXiP0wSIzixOvXi32055M67tKiZYoPwAAIABJREFULwl/k0/aTXIQ+OWktBdPvtBVt0t58VFhlvY14XV3fKMVeUrrJ1hF1Aqf4LTPCoZFXhpG+COB0KI7RqfdGskiXxdyZggTEPLYIIBooqkxOTZ6j37S8kTok8S+Up8V/qaKP66fCAR+SSnrxduoOPNt+yKve4kM74lnPQAnJPJ+k9NOITwPUkhacOcJh1r1vQRZzPkq8xT56V4gLyTkM/3nBwHTckrxSxZ6xrNPl1jBbvInDwj8stJFiD3QZnobhUL1lY3ggCFoz2kaIg8Y2Muw+tosCL9kRkpQiHmrIs+ItQnk1fKFL2uq8SGRp3ShT3OIZ16464z3GQj8EjNvL96y2y2H6rUiLxkJFdCKPABEgrhovfharle2nm64P1xCfUcp8lJ6TOTrSXX58/PqzKrIsqny5kkv9ESz8H2aUM+8+5qHXxH9vog/BH6Z0YhqpFrITErzwbwmoXrGVmibPTZpQBOzAXUHDrzGp4fq4w66JPJcdprIqzz8Wp4k5KE8XwLrTn7Emy8q9FQR6lxZros+K/7CICD6qdRNXWUHgV9yeL1L8+Jrima9XYUd3otXDQCazscr+hgTeXEAwe2DFUcQCDaZ9/gV6s6me2JOQnoBkdcLuZ9nhLxaSsybn2aHBXki9CnCbUyuZx/sxezjKX7kU6u/di6lZQj8shMIh+tC7OP9hBA7bzMzVO8V5OvLgwdHpHNE3h2MRAYnYLXRL7gjXs/ZdCOke9VqZdl0bzNd5GtJiSI/3TPeRi0/5s3PssPe/LTsVOgTZLsq9pHvfh7ceeed51LKQ+BXAF6MAnPUhes1D9VX/vjBh9m+OGBIEHnWHkQepNE4VO9tSek67362KXnEJUWeyWOEPDYImKYkefMaoae08H21pZrgpy7Umz8DMnSp606AlsnyuP0yuQvu3AR1qF4Saclzp4AIC4vuovYg8iAL4covuetcGqvdXLrh/nAJooe/uyuLPK/BkpDX82Kevu/Nu/1qSeip4tU3mHs3nuj3w9snIhoMf/bo2a47AdqnrBfP57EDh2pSaqjey1aIvLbDgTBDqsh/4+s3A42CVUUM1Yf1PJY4zar88RLiIs/thD32mJD79fTeej2ZF+j6GEAp9HMVe8ciK/zNPqkgRL8qRMLX1TIpXrxO1MUijF23f64twUpA8K2zw9oO2aDAcRPR5g348YCHvyan3DrHpfMeeJrIS0KuFPlanonkscWrG0JyQOgjZao5KV79zH5VVPvgi+cBgV8hUp4vL0TXHTsFQ/WhPiimEry6cxZ5AHhSFtdJIs+VN9H0yh8v2+tZY5Gf5fHeunG22I16mbrL7qEZDNRs1oReL9qTOftFFHwI/IrBajzjxbvb8wrVR+tWKgVD9SHb7tQERB60iT4mL6QzXrAmvfaHF+w2RL6WxCt61Jv3yoS8+Ygdr7xJ9+prNhzBNxmDhhyuX7NPpdaBwK8aAUHVed/jzSKhel7kpf7VsksvunPtV6tFRB6AGEnz8SR7936elM7Z60jkazvCoCTJm5eFXhO6r9UZi3Wu2E9tGV7467Zz2xjXazAHfzmjVbCg8JpkA3l8vUaPnw00JIuym68QeVeDtSIfigbU9iHyQIcUaJbEvJnI+wWTRF41ADCBesatybr1TBW/A2yWLJY1oU9aZOeKfRmPvBo1kAYB4c9uvRxvfFIHK+lXCVGMfTc75iFXC6tC9Z7dSKje6yNf321n7iIPQIyAu54j8lxW5Q+XoBD5vAFAyJvnRdzvqZ9cQOinG3rRrgqy/zS57his0XZynTY6AvqPasFdG6F6d18r8pKhQGg9GDEoLvIAxJFC9Tki70uf94dLiIh8KM/pCSPkUp6QRK5wygMB9miThN736pViT3XvuyvR33+L+c3UOhB4QEQBsQuVrVfxMxWh+ixbbrY0H+/uiwaomcgTAHpCIi+lB7LqCf4fLmF+Iu8ocdibN6FktzGhXFh0vWI5q+orVT3RbzzfHmCU/lC6scAbPM1uBVGtYG8aqleIPKuiyj6qRF6y5/U1IvLR4wdAh3h/vKTkUloRkU8dADBz73KuzptnRFwr4IbNDossW6eBV16T9ZreG38AkPvJcMd3q5gR5uBXFEFW2bysUL2i8WCo3u1HjsiHPHC3r7HV9RB5UATpTWWJ982zeakiH8qThNzpqaeLMZH3Zvw5Nff3Ip46r+9h0XbFuabShTxx16/P+RBle/BgZRE9ZF4spaqVKuSpZkiUq8mSyHsiHLLXgchD6EEO4qK7xJX13lZlrw2Rr+16qk9irqDovID7FXhbvAiHBwVhwWbHBm2H3xUMRumL4SHwoIVQvV89bT5eIfIUsjdfkQcgF/H54pKYB9LHW/V0/089QTkACAl5VsieEXFtGU05N0X26vViP9H5sOh3I/4SuwI/ojPddgN0jSpULwhzSqg+xVbdXrgcRB4sKiVX1o+36un+n3opxQBgd9dLcFqSPX1miMAqtVbAPSmNCL1XJ0PsOTu+6FcSgwOAnE868ODBLppQfaiqRuRFtSdRoL22IqF7rlNtiXygmwAkUWZlfY7I6wcAs02lyHv5MW++3gKTzFaKC32C2GeG4YPSXEDrjSG64847z6g7NGa8yA7vhAcNQ/WuLdaQvyvWrQp0kiDz/U4W+dAgJ3DcAOSSvLK+iMjzeSEhZ/Nqu6En3LElRJWWxdtPCGu7Uuy9hDKeNGc65ZPLgIgI74QHE0qF6r1Qu7MTsxUVecmemx+oGH1oDUQezJXAyvo5i/xs04h5SSF7Jp89XkHAdeIdyU4Ue1nfS8twnJtb9kJOPYToQZ3EUH1VmNWhes+2UN/Zyl5ZHxLnVJF324G6g5KwK+iJuhV5J2+u3nw9IezE+0IrlleIvZsb1/e2/HFD21uDFzIq1gQ++VV0YDmRQ/VxtzVJ5EkQZal+qG9eX137hUS+chycLQAaI741LFPkvbx6ou//1hO9PHYz7K2z3nzrQh/w6tlEnRA31veUyXiz++802GuTn0NPRLRW2cY8PJhiqfITr+5YIju5NozTLRGZSplaXdoVTGNmld36bqOuPbfczJ7Tn1D/KhVn+5U+V20y+/V2ZjvQdtAGxhiy7D2ohoyxzO2phshYMt4g2hCRnWTT5qal557Zomef2aKLF7bp2sujWum7X79Gd961Rn/iT+6jO+/aU61ORER2klAxPdkkMvXJvOr5SzORt9UeVmzMSjmDcceO2xs2a5roJTApTiJbt1aaReubs6YjdvffQh/X15hREXhzCZcrMMUVVaqIG/ki6Ym8K5hVc9KAQejDzHalFwVEnmJ9HuexdidufMY7mgHQEBT5ukxO0yWRv/ryDn3hc9fpK1/aDLb54vPb9OLz2/SHZ2/Q3a9foz/15w/Qt37bmqPplRPPE3FnEDBLrPV+two/EBCGCwGhn5XVlufEXiw6zZDO9TTdnOcVYybwZnSWrHlwjm2DniOKqOsJz4rInrczInAFXxbkyr7XQL3xVJHn+hz23Ll9Sxe+dpP9/gBoiijyxpCxcZHf2rT0u2euRoWd48Xnt+lTv3KF7n79Gv23f/U2uu2OyU1XVXnM8+Z3k5xhSrbQ1xMVui4l6gU/mskWzGZgTdZC+NkcfMabasDyk3LrnFfXyctadMfas37fXBsxm5XKbD+l467sT9I2X6mHOQEoify0u/Cc/HPPbNG/+79fyhL3Ki8+v02/+q9fpue+cnOqZYZm8sskTnc98fN2vZl3z84kQUgWEyPZQmK9L25OsBpvIlJQ9xmZvBfCVRfZ4VY5wMLrt5UF1NZK1WvliLxrr6jIV7wDtp2KHXdQ47YFQEuIIk++yG9tWvrsr1+lM//+Zbq5WeYXenPT0n/8+FX6vSeuMyJe33I32dvpGgm9cHtdIDFN14NqPS9Nr33W1rbPeR1RUAnRw4MHAk6ovTYPTRnz8dP9XWPuHHzU3nR/3H5KWN0L11fsMO2Q2PdKZwGYA5qFdy9d2KbP/voVungha9F1lD88u0k3Ny396QdupX37d0+k2aWhcpGobO72cPf/mrD9blIodC+W9C8kTKJ4+roqrYvPi9VDaC4bVXsHDtx5LsH8lKkHj4fdgBCxW+fkcDpTv5YViAS4+6158hU7zMFEb6MDYE6EPPmvfOkGffL/vdSauE/4ype36FO/fGV3BX6CNz/bjXnqWo++XjLoRbOJxtkL1I96+bLHz6Fx3CfkPuSGyH/QzeVcQ2D5kQUzFJNXbCvziou8nf7JEnnoPOgCTuR/5zNX6T/9+pViIfkYF7+xQ7/6r1+mP35uu6ZIflCcPMWqSyu5GU6SXuiF0vU6kVFAVKpVmq6Rb/1n5yZlPeSGyBd4ePFAhhFMNs/1kKvJrFfPCLTQVlGR5+xWIxKWhP5WbEHlQQdMRH5r09LHfv4l+vJ/vj73PtzctPSpX7lCTz85XsSn8ebbEHrRq28i9rzgi/65Vq8zWNtvvpRX0xV4a87lGgIrQijUXt2PCvJ4v28iXzHgHss0CyF70AMuXtihf/uz32g9JB/jP//H6/Rbn7xOW5s27s2Luw2EXihbr6EQe5Un3lC/M5z4tb30XzSmOdZqe4PRObKZwwywMqjvjx9vWCL9k+4ocI98zGYlMf1+9opd51iIaYtc+wDMkS/93nX6nc9c6bobU77y5U26eGGb/vu/cTvd9qrB7rkyPnlml4rKRWOSURkcT+TTGV6TW203aXbysQvynPJcLaFInWiBeuE2LgmWBtmR9boHP6IzTTsDVoPii+6q7nJqWN1ro6Qn74Ts2T4DMB+2Ni395q+93Ctxn1CblydiPXUvQ3TcdR49kcKrD7ju1QV6Kg8/qOCp7nmM3XKD0Sj7Dre6wONWOZCAKJbuPHa1fE9Fnp1acG05bU3tQ+jBHLh6eYc+8Usv0TNffKXrrojU5+V9Ea9LW0OhF8L3uWKvEnzXVnKMXmtoZuzAHXecSbU8oSbwuFUOJCGIbmi7K5FXz+07+1MzocV3BEC7fP3ZLfrYz3+TXup4vl3L7rz8NdqqPkTP8ebzhD7Nq4+KvUrwFaIv2W742RlRo9Ec9z54vDYW6HEFurplfdHk6s1D5L12GNH3+suG7B3hB6Blzn72Kn3iIxd3F7EtEF/58iZ96pdfpmsvW5IEPCr0TNkUr54oIvZuXYXbbogX/mQHXsHWjVH2AjsiVuCxkh6kIXvHvMizl6kuRJ7ZbzovD0AptjYtffr0JXrqs9e67ko2u/Pyl+m5Z7Yo5KmLQs/szpIiXn1E7NWCH1TuekH/v2ZO/IHbzJlQ6zF8gTcjhOlBMkGRJ0HkA6H7us32RV5t27EHkQdt8NKL2/SJX3qJnv2jZi+K6QOT59j//m9Nos2lhV7w6usFWFSC79pJctmbSvzgnKYViTUmDQIPsihy+1xlv25z16D6VjfW7kSJ9bfREdNnmpqaHRcApfjqH23Sf/q1ywsXko/x+7/9Cl28sEN//q/etvsce6pcLCqbRO6ukFlJmiWzb4YP1qsXqas290Je0SZHw39CY/JeEzvB9+AHEHiQj+gJCw+Pmb8nP9tQhefdKYZAyB6Appz97FX6zOlLSyfuE577yhb92i9epksXdiqpcY/eMHtc+XqpYKxe5YlzQfegpx9rJ/Fz48aNsgI//Omj55oYBCtOSIC7EvnKPvfkvODiu5h9AAqwtWnp1z9ycaHn27VcuzKi3/iVl2njS5uOVDJCnxq+D4h9kuBHNFwS/iTxj7CzbW/ceeedjW5d51bRExE90cQoWHH6JvKu7ano23qa0xZn3/XmIfKgKS+9uE0fe/yb9MfPbnXdlblxc9PS537jGv3eE9cZPQ176WqvPqjjCjVPFP1ZtTL/3dyiP9S1KCMIvEWYHjQj5AW3LPKsXdG2LPIqzx0KDxrwR3/wCn3iIy/R1Zd34oWXkKfP3qBf/de76w1Shd5PyhV7peD7lZLFP4UDB5qtoCeSPXgIPGgMJ5huZhsiL9mVbc+GBcnz8kz/ANDw+U9fof/06y8v7Xy7losXduj0hy/RxW/sDnJkoY+H79VirxD85LvcG863ux/bcIEdEQQetIwX+mYyi4i8M4/O2Y3bDs/LB6MFACiZzLd38YrXvnJz09Kv/uJlevrsjZCO+ym5Yu8mq6L0obvbW+FcUwOswOORtaAkuY+JTRJ5pp36tEDYtmZeXuXNAxBgFefbU/i9J67T5z55jba2LOu0z9CF430ZDghzgm77RXMebxPC0IEDB85ECkWRPHgiLLQDBYk97W68VdvIFXnO064b8SLzjv2IyIemHgAQWPX5di1f+dIm/X+/fIUuTm6lC0fn+VSFhvsp0bh94Wi9/N/WDftMvJU4AYHHQjtQllIiH3x2vWeb3+faqrdXn5ePrrIHIMBv/trLmG9P4OKFbfqNX36Znn3mJknqXlLsZQ9fFbsvHrEf7KHPN7cSEniDd8OD8pQQec8OuSJvRZHnbBcL2QPgsLVp6WOPf7PXr3jtKzc3Lf3Hj12hL/zWdRLVneq7SWKvcNj51KwYftJnba8pIvDco2p3GdBZQiQJtID4SNuJYioea+vZ8fZ3DYuPsp3sk2OfZm3M2pxlsI+4hcoDhpde3KZPfOQleO0N+f3feoX++LlteuBv3OE84pYq5yZNz2fn9CQ/VSjsVxIlXLYbLq3F2jIRdNGDHz/R7nyJRgBwCS+8s5Nkqm6w8+bB0DnvyeeF7Gcbbsj+5YsYCYM6f/QHr9DHfv6bEPdCvPjcTfrVX7xEFy9sOznhmL3sawc8cYWjrnXG00rPPiUW2BGFF9kRUfP78ACQyBb52kY1nF6xVS1omTnzgMinhuwvv+RedMAqM5lvB2W59vKIfvUXL9NXvsS9Yc8RSUZpw5odUfXM+facCH2pBXZEMYG3ozOlGgKAI1fkORGOrbDXzsvX7LFtzDK4BXhgNcF8+3z43Cev0uc+eZVujp9+xxNX97hOKxU9Rb11/Ia6ZAR5Dp6ICAvtwBzw5uSJpoNw6VWz083Aft32ROQT5+WZNsmOdyuNXbuyQ7fdsafJ1wAWGMy3z5evfGmTLl7YoQf+xzvo9jtmfir/7TOz8syUfGQ6XrDHEfgNKER+/4HBb8dL6Qh68OMH3lwu1RgAEsEV6oInP93kwumO7Sbz8mx0oPY/SxtP32COCqwCmG/vhosXtuk//MIlevYrW6HIvIPgVgsV85zxnMD87LOzs3NG+RVEiczBExE1f+A9ABpKibxoSzkvX2ujOvfPhOwnc/Of/9QV+cDA0oL59m65uWnpiX9/hb7wuVfIU3jKFWQmKXFaPi0iP2Nn275y4MCBcxlVWeICj3l4MEeiIm8jIl9Nc/br9mduewlv/tOnL9G1K1hNvypgvr1ffOG3rtNv/JvLtLVJJLnzzT3wQFaB6XlDRDdv2GLheSKNwGMeHsyZ8ANlZqLsinqed8+IfKVNrTd//eoOffAHnw8cFVgWXnpxm37lZy7QS94tW6BL/vi5m/QffuFi5Va6gML7uQqPW6HszaLzdMvtg4/mHLtEVOAxDw+6IHxbmxVFnfOy1fPyAc+dS3OF/vOfvkIf/1ffjB0aWGC+9HvXMd/eY669PKL/8AuX6JkvcmtiqmLPu/T5YfaGyj7+mAKviK2imIMnIszDgy6IinzGvHw1zZ2Xj4TsRW++ws/96NfhyS8hW5uWfvPXXqbf+QzWWiwCn/vkVfrsJ65EBmKRGL4iKl+avXv3nilpTynwo9MlGwVATVDkSSfyOSH7RG++ymc+eon+/t96hv7gd655hwMWj6uXd+gTv/QS5tsXjK98aZN+499cpmsv7yjFmJHwghH5GJs3Rr+n6mYCOoHfg3l40CHWEWFXgDmRj4TsOZHXPBgn5M1XOfeHN+iH3nKOPviDz0PoF5ivP7tFH/v5b2K+fUG5eGGbPv4Ll+jZZ7a8qLwOQa65EH/DwcD+WwYfb3CoYu9VDB8+d5aI7ivdAQBSMO4v1lR/xLMdU0mqbTr12TTjlXDaIa+d3/5U+Fapu+7ZS3/uu19Ff/Yv30FH33gLHorTIS8+f5NefGErWu78f9mkp5+8PocedcP1qzt0/eqo627MjW/9tr302jfsrSdaohdfuEkvvnCzm05V+Nr5raevXhn9m61r5udOP33vuRI2EwR+4zEi884SjQLQhLDIzwqIIs+lxQYOXDuVrM9HBN7l1tv30NE33pJUpykbT9+g61dxKx8AfWdtr3nBjujHtwdbP3X67P2Xcu3oBf5tGyfImn+X2xAARWE86qDIOztxz51Lk4X+85/Gw04AAGUxA9ocGPO+X/7Cm96fVT+l8PDhc5eI6GBOQwAUR/CoS4fs/XaMlwaBBwC0xdpe88WbtPUXU7155Sr6CbhdDvQId/HdJI3ZSVllH37M7cyut9IeAABaYPumfdNes+8LJ449eSilXqLA43Y50D/iIp+2yn5qM7rS3jLiDwAA5dnesm/YY/c9mVInTeBvEgQe9JL4i2Msk1YrrvPmvTSoOwBgPoy27ZH/6b/54j/Wlk8S+OGpo5eI6KnkXgEwDwL3rc8KtOXNAwDAHDD0j7RFE0P0RGTtqeQ6AMyL6Lw81UQ+2ZsPCj0AALTLzrY9eOLNv39cUzZd4NcQpgf9hw3Zu0+/iyzAY715Jo2I6OBr1hr2GAAAdOy/Ze1va8olC/zwp4+eI4TpwSKgWmXvePOM567x5tf2tvHqCQAA8BmsWdVTstI9eCKE6cFCIYl81JuPzc3TTOjv/BZ48ACA+bB/7+C1mnJ5Ao8wPVgw2LfDxbx5oqjnPkk/9Jo12ndL3ukEAAAp7OyQ6oE3WVckhOnBQhII2Wu9+Wk6k/aGb99fuMMAAOCzPRrd0JTLdzkQpgcLSjFv3ilw6FvW6DXf6rytCgAACmOs+aymXL7AI0wPFhm1Ny/fN1/bHacdeeMtEHkAQKtcv0yf1JRrtPQX74gHS0H0pTX1hOAb6sYbl76xTef+8AbtbOMmeQBAOfbsMRd/+QtverWmbMNVQfaxZvUB6AGSN68N2zOr7Q+9Zo3+1J+7jV53eB8W3wEAijEY6KPnze7tuUmnaS99uJENAHqCteR77pbIVj33yUjAmKnIm3G5ScVJ+p49hu45vJ/uObKfrl8d0aVv3KSrl3do84alrRujNg8FALCkbN2kH9OWbfx0juHD508T2Qeb2gGgTxjuzMgI29d2GZvu++evXNoJ90EDN20g5ItJkbbjXUvo/CI+Iyhp5iVcOGqKe5qiwoi3kDQD8THM7kJVpx1Vc87DJaSnROJR0DNeubLzoz/xa9/xbm355k/nMKNTZA0EHiwVFUe9kji+/kx1fZZQ9/KpslPZddKneXYm9Hcc2uN3hlsj4IwsRI3MEHs2WSHCoUFOkiGp5hwGAs3ERKjs3mKZaEaskynq/l0h1s8vJezcsUPYc7l8+62Df5FSocgpM3z43CUiOljCFgC9Q1iEV/njFSzl0Xv5IeVtKvaBjBzBZ4tG6/XZnY8oTqqQC4VTBN1LVou6XzgoqCWE3WlEGF+EBxirjDWPDz90eD2lSqHVP7gnHiwxwiI877Y6xUK82q6TPk1i0qf53OI/pzPeff5yUf7CzGR6yW5C4IJcK2ZnH96GlKH5aGhgn0uqfjQ9UZgVywpZoYZrvyemcPXfROov+3ty+u51zO2Sc8up9QrMiqn/KVeO0anUGmUeoL2HHqMdemcRWwD0FClsT0Rkq15+aCHedKey66RP82wl2XVsKxfdWX+qijxrm41A1IvWcBcZcpncNdiwiUyaYFpK1Pv05ZShiCVBcHMaZQU2VNZTXadMqCOcoDumQv2pN239Ytz3AlGPcX74oaNnUisV8eDx6FqwSkgejf+EPMZr8XYqPlXIWwt4NjWv2Lda9zQ5M1qPkikbyvIcxqBhmZCJtj4lOhe1m/BdqspOfgNehXE59ndSNxT01rnfTyWh/huvNyT9hqfpIIzNuyW94A26uCcerBCBi2Gu0NeSAhfDtBB+1djsCi2KvVM8WfAjQhUUrcZqWxhF39TdTvyeYt9BVdT5SpVyGlEPCXvoeNwWU4Ud4q4j88mx5QT+Jp0mosvF7AGwCJQUelurLgr9NDkkguKFOyz2OYKvErOQSEU+6oIFP+53ojwkVUHVMYbMihUrZS3JAuoco5jvVneaquVD2FvEfHQcJU+mmMAPTx29RNbg+fRgNZEumFx6RXm9y7Nz8eMv6oH8UN/q12CqtV5RtKB371RzxSBL/CIX/AY6nf3J7oyiuLZB9t/eMzAuW/33jf0OuCKhf/tKgt+N+o9K+i1Gf6NAxo6yo+Nln6G5NhoWtQfAolG5SErpVihcy5MukkLeNDl2ka+UUXv3luoXdtao/wl5wVobZVS53TaCxXNsVP8NWSPjOpV/n9DxiiH4imm2a4ywz3a8XzKEvR2yFtdNKCrw4zDCEyVtArCQBITev6AqhN56JoIhek8oYv30hMJV68omI94h+6z4y1lJeq1pq4lRlckmAwJXzJWCXkTUOWF3mg0Ju/c7dM1A2JuTubhuQpnb5GrYU0TmgfJ2AVhAJhdZ5hn3RFR/Ah5VrsiVW+ym+ba6UzNDZOUH6NhKwdBDdoh84WBvwZsmzYxMczUP0xHMsUW6fO5NAXHyxDOhERvO9kxEB1qhMpbdHCfUU6xYMKHPQMNl2qZTTQy0cvoMHz53jogOt2EbgIWGfexsKM+ERTP2XHnNM+VTnkqX+yS60L32C44viOqS9dwUYZS8c6E5zdjCH4xA2Dsl48l1Lu28x9LgyXYAsERCp/I8vRMWrWS7cVY3BBwNF7th4lD3rf9hLPofd9cJI3OfPiD1zVvUVut4/Iji3yPfkWDo3S3Htewk+r+n6kHFf0e1PFCWAmva2hH4LcI98QCECF3YHU2cpdev7hqxryVHFNQVL63ScmLlVxOlUlR51m5kUJD1CbQjVghadI6iZ/GWAAASuUlEQVQ6VcwrX5d7vKGvNbZCPvy7qXdsmi/9VqrfD2iDJ3JvjavSisCPb5l7vA3bACwboiiKF25fSfmLNnlGa8kREXcFUCv4XhcZcQ60pvsUU/mcSkzPhWNN+b5Ugu58VWKvkkTd1suEfjv1cQBoC1PmwXHtePBEuGUOgFRCAuhc0P1KzcQ+5t2TUzZL9LkuCwMAnckSCq9sIdDfnOP3voOQGevUkXqfIerVclInar8PMA/OD3/maJFnyrQm8LhlDoBMfM2u5bkX+lDFoNg3FHxyyjcWfu4YO/60chwxkzmCninqKm8dwj5n7LCUpfY8eCIiW66jAKwkktCP8xqJvZjoZ7GR7HC3w8K/DMLhHEtWJIKzQYG6TGYpUSc3H3TB5eHPHj1VylirAj9+Ag+8eACa4uu1l58r9taxofLwKU+wORvRQcA8BUdoOzSVoO5eRMw9G8J3IP/bNRN1CHsPKDT3PqGFB9244ME3ABSlKvKBd73bcX7lj1N5ZsC9rovPt+EeouMkhO7z1yBqzCKIj9BH9QBAm2zlCtbbSKoOuuNy6TvQ5vK8CTz4BoA5EHqIzjif2VQZ0dqNUcpOZ8REsy07GkHX2IWo9xdj3zf8maPDkibbnYOfgrl4AFpHGcYPz/Uyceh6Vb9OQkg9FIGPhuhTP9EG9R8pLB853GhhMav6hTCx8+p3FuqE972C/tLC82PmNmaGFw9AR8Q8+0q5yp+sQuoLyiJ461qUwhkcBEQMacLutSIQ88WiwGNpOebkwRPBiwegI2KefaWc5K3KhWytkNrDTfHCuyKjj9FiVddbuBfPMsVi3wc89QWnpefGzHUcDS8egJ6h9e7HZQO7cgVlA4vg1Ku1U+lyswMfrXkI+XLQkvdONFcPnghePAA9g3HGQ2W9eWknma0gPkmmXknrMHf58TsrHJsc+6hV1UYsWKcfLActPvV17oNmePEALBBpTrhXL5LUpcFdWKFMV89Xro3oua9sNu5Ow25kcfXlnfk0pOS+v3B7112YHy1670RzuQ/exQ6JzIfn3y4AIBlb+7OLJqzPiNM0KWuBXsjg/JCa3L5p6erlfgklWABafmfLnEP0ROPH8J2fd7sAgELEo+3R+twn9qS4Tj5S5F0ZWgdAxn6gxCthQ8xd4HfBXDwAS4Uk0qniz9jsx6Q7AEW5TDdp2HYjnQj82It/qou2AQBzRiH+i6KlQe8eAC3GPjY8dfRS28105METkbUnO2sbANAPQiH60IcKfhLaXbgRCegjxZ85L9GZwONNcwCAbBCGB4vKnLx3oi49eCIivC8eAADA6nC+9AtlQnQq8MMPHT1D1jzeZR8AAACA+TBfp7ZbD56o9fsAAQAAgB7wxHiB+dzoXOCHP330HBn7vq77AQAAALRGB1PSnQs8EU3eg3u5624AAAAAxbHm8fHC8rnSmxc4DR/eWMcjbAEAi8jVyzv0zBdf6bobS8Ff+Z9fPbe2brtjD912x55W2xgMaPPwd97y07fevufSHto5/R3333621QYr9EbgiYiGD587S0T3dd0P0H/ufv2+rrvQGnffs5zHtm+/oUPf0sHrL+bA17+6Rf/Pj/9x191YCt7/C9/edRfa4vJ+unHk6P13zuUWOaJOXjbD8+UnXxlevHDz7AvntuYq8Hd+yxrt3d+rcU4x7vyWvbR333IeGwB9Ai+aATEs0cl5ijtRjwTekD306rv2PvTqu/Z23RUAAACgJE/ce/+BU/NutB+L7IhoP20OCQvtAAAALBkD2unk0ey9Efij9995yRLh+fQAAACWCPuBeS6sq9IbgSciGocw8Hx6AAAAy8DlcXS6E3ol8ERElmi96z4AAAAATTE0Wp/3wroqvRP4e+8/cM4S4cl2AAAAFpknvvP+20532YHeCTwR0b33HxgS0fmu+wEAAGC+fO38ZtddKMHlPkSjeynwRAjVAwDAKvLK9VHXXSiAHd57/4FzXfeitwJ/7/0HzhDZD3TdDwAAACCBJ954/62Pdd0Joh4LPNH03niE6gEAACwEXd3zztGbJ9lxHL3/zktffvKVdUP0ma77AgAA8+J73nE3fc877pruX3jhJv39v/UMXbsSfiTum7/rNvrhDx+Z7n/kJy/QR37yRTYvxt988xe9fqTwN9/8xax6i4wlel9X97xz9NqDJ0KoHgAA7rpnL33P9+cJ7YQXX9gq1BvAY58aLxDvDb0XeCKE6gEA4K//ndfQm7/rtuz6Lz5/s2BvgMuARutd98FlIQR+/Bjb9a77AQAAXfIDP/L6Vt9ffv3qDn3xd6/RF3/3Gpt/4YWbdO4PbwRtXHjhplh/ebHv6lNofkKv5+Cr3Hv/gTNPP3n9A0TmnV33BQAAuuCue/bSX/+7r5nOqzfhi797jd6zfi5Y5iM/+aLXljuXr7Gz5PRm1bzLQnjwE954/60niexTXfcDAADmyYUXZuH173nHXXT0jbd02BtQoRcPtJFYKIEn6uc8BwAAtInrRf/Aj7y+o56AKpboZB8eaCOxcAK/O89h39V1PwAAYF68+PxN+vynr0z3j3znLfQ977i7wx4BIvvR8RtQe8vCCTwR0Xi+A6+VBQCsDB/8wefp+tXZffAI1XfK+f20ud51J2IszCI7l/1048Qm3XKOiA523RcAAGiba1d26Jd+4gJ97z967TTte9/92uwFbm/6M7fRv/2DN4n5q/igGi0D2jnR5WtgtSykB080vXXuRNf9AACAefHxf/XN2i1ob/ozt9Ff/7uv6bBHq0ffnlYXYmEFnghPuQMA9IN7Du+fW1sf/MHna/t/+/vvortfv3du7a84T/TtaXUhFjZEP+GN99968uknrx8nMvd13RcAwGpyy63z85VefP4mfeQnL0yfEX/r7XvoB37k9cmh+utXd2jj6fBDa0CNy/vpxkJFjRde4ImILJkThugsYT4eALACfOQnX6Q/95fvoCPfubvI7k1/5jb67hOHkh5Hu/H0jVV/QE0Slmgh5t2rLHSIfsK99x84h/l4AMAq8XP/4uu1/e9992vptlctxSW9d1ii9+1OCS8WS/NruPf+A2cs0fu67gcAAMyDP/ida/TxX/jmdP/W2/fQ9/6j13XYo2XFfnSR5t2rLI3AExGN/xFwfzwAYCX4yE9cqD3G9q57sNiuMAtxv7vEUgk80e798YRXywIAFoA3f9dt9L3vfi1994lDWfWvXdmhn/vRrxXuFRhzeVHud5dYikV2VY7ef+el//Lk1RMj2nOGsOgOANBT7n793tpb2YiIPn06XUt++1NX6POfvkJ/9rvvSKqHB92EsUQnF+V+d4ml8+CJdp9Xb4lOdt0PAACQ+LPf/argfgruY2xBU+wH+v6ceQ1L58FPuPf+A6eefvL6Mbw/HgDQRz5z+hL97e+/i269fQ8R7T6lLpdrV3bo7/z5p6PlVt0rV/LE7qvJF5+lFXii6UNwjhCZB7vuCwAAVJmI8pu/6zbaePoGXbsy88AvvLBVeyRtNa9rrl3ZqfVtuR6WY5/aT5tLc8u16boDbbPx5MVDm7T/DJ50BwBok3/8d57pugtLwcM/eA/9iXsPdNH05QHtHF/0efcqSzkHX2X3pTTmBBFd7rovAAAA+oklOrFM4k60AgJPtPukuwHtHO+6HwAAAPqHJXrLIj6pLsZKCDzRdGX9W7ruBwAAgP5giB5fhhXzHCsj8ES7K+vxOFsAAAC72I9+5/0H1rvuRVuslMAT7T7O1hA93nU/AAAAdIl9apEfQ6th5QSeiGg8YsMz6wEAYDU5v582jy/yY2g1rKTAE02eWW+f6rofAAAA5srCP2Ney8oK/NH777y0nzaPE15MAwAAq8LS3eseYmUFnmhX5Ae0g3vkAQBgBVjGe91DrLTAE+3ePje+Rx4iDwAAS8qy3useYuUFnggiDwAAy8xY3E913Y95s9Qvm0nhO+6//eyXn3zlpCH6cNd9AQCAVWXj6Rt0/eqokY3BgDZf/yf2n3rVnWtfH9Do7Bvvv+10oe4tFBD4Cvfef+DUl598hZZN5K9d2enV26hKcnPT0sVvbHfdjdZ48YWtrrvQGi8+v7zHBvLZePoVuvC1Rr+Ny0T2+N9867eszFy7xNK/Ta4Jw7eeP0XGPtR1PwAA/eepz17tugtLwbe/6QDdfnBPbvXLRPb48GePrry4E2EOPsjwQ4fXyRo89Q4AABYCexLiPgMCHwEiDwAAi4B9y/Bnj57quhd9AgKvACIPAAB9BuLOAYFXApEHAIA+AnGXgMAnAJEHAIA+AXEPAYFPBCIPAAB9AOIeAwKfAUQeAAA64zJZ+5cg7nEg8Jnsirx9V9f9AACAFWL3PvcPHT3TdUcWAQh8A4YfOvoYkX1L1/0AAIAVAA+xSQQC35DdMBFEHgAAWgTingEEvgAVkcfb6AAAoCxP0R57DOKeDp5FX5DhwxvHiMwZIjrYdV8AAPPlmT94xUvbd4uhvfuX0486cNuA9uwpLyEHbhvQnrWp3afopj0+PHX0UvGGVgAIfGEg8gAAUIQn6KY9AXHPBwLfAsNHNo7QjjlNRPd13RcAAFg4rHl8+KHD6113Y9GBwLfEcH3jEO01ZwgiDwAACdgPDH/26Mmue7EMQOBbBu+UBwAALXg6XUmWc/VHjxh+6PA6Gfu+rvsBAAA9Bk+nawF48HNi+PDGOpH5cNf9AACAnnGeyJ7AbXDlgcDPEaywBwCAGrgNrkUg8HMGK+wBAICwUn4OYA5+zgx/+ug5ummP4210AICVxdp3QdzbBx58hwzftjEka97bdT8AAGBOXCZrT+BtcPMBAt8xw7dtnCBrThHm5QEAy81TtMeeGP700XNdd2RVQIi+Y4Y/c/Q0kT1ORE913RcAAGgFax6nm/9/e3dz28YRxmH8mZWSMzsw2QE7CDsIO8gepEC3MB2MO+DZ9oHpgOqA7ICqYKUOxGvs7OTAjUIjhkyFH/v1/AABFAQIc/vzfeedmTQx3C/LCr4hYl4MuM7mXoojqVNS+j1+Gs3rXkYfGfAN43l5SR3h+faaGfANVJ2XXwLv6l6LJL1duOdzmXu+vV4GfEPtHqvJFpB+rnstknQwW/KNYcA3XLwpZoQQccpeUrPZkm8YA74Fqpb9Am+/k9RItuSbyIBvkXhbzCH8Vvc6JKmyhTTzFbhmMuBbJt4UE0JYYsteUr3WXKXcs+3NZcC3kAN4kmoV0vv4YRTrXoZeZ8C3mNfcSrqwB0i5g3TtYMC3nNW8pIuwam8dA74jrOYlnYlVe0sZ8B1iNS/ppKzaW82A7yCreUlHWlfH36zaW8yA76hdNU/03LykN9iSUvSq2W4w4DuuOjc/x1vwJL0q3HNVzjzX3h0GfE/EX4tICjNs20v62hMp5fHTaFX3QnRaBnyPxLtiyF/Z3CE8ScCWkOYO0XWXAd9Dtu2lvrMd3wcGfI/5FK3UO7bje8SA7zmn7aVecDq+hwx4Ae7PS50V0nv+ZO5b7f1jwOsr1f58BH6qey2SjpDCH1yX0X32/jLg9U3xtsghROBdzUuR9DbeQifAgNd3GPRSa6yrffZV3QtRMxjwOkgV9HOcuJeaxmDXNxnwOljMiwE/MvNGPKkRDHa9yoDXm+0FfY6te+nSDHYdxIDXUdyjly7GYNebGPA6CYNeOhuDXf+LAa+T8hy9dCKeY9eRDHidRbwtxqRsRki/1L0WqUW2hDQnY2Gw61gGvM4q3hVDSnIn76VXPUGKfGbplbI6FQNeF1Pt08/wmVqpEu5J5dz9dZ2DAa+LizfFBLLc9r16yja8LsKAV21iXgy4JieEGU7fq/vWkBbx42hR90LUDwa8GmFvKG+Ke/XqjidCWlitqw4GvBol5sWAH5hCyPGondppSwpLsnIZP4yWdS9G/WXAq7HiXTHkC1NCyHEwT40X7qFcOgmvpjDg1QrxthgDOYQp7terOR5IacE1S1vwahoDXq1j2KtmhrpawYBXq+2F/QTb+DqfNSktDXW1iQGvztjbs5/igJ6Os4Wwck9dbWbAq5OqN+snlNmUkCbYytf3PUBakVh6s5y6wIBXL+zO2TOxutee3XG2UK64YmXrXV1jwKuX4k0xIWNCChMM/L7Ytd1TuSKwih9Hm7oXJJ2TAS9h4HfUE4SNga6+MuClb3hp6ZONCWmME/ptsIa0ATa23CUDXjpI9TDOeFflZ2NIYxzcq9OaFB6h3AAbh+Kk/zLgpSPsnr5lTGAIYQyM8bGcU3oCHglpReIR2Nhqlw5jwEsn9lLtw5iMQbWvP8A2/2vWEJ4Ju4qckmercuk4Brx0QdVlPENC9VNmQ0Ia0v0vAGsAQlpVv28oeeYLGy+Rkc7DgJcaphrwGwCQMXn5w64T8I+6vxCs//34UnlDyTOw+3zNo4NuUn0MeKkj9rYGTvt/bZVLkiRJzfA3oB6MypRiEO8AAAAASUVORK5CYII=","e":1},{"id":"image_7","w":132,"h":390,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_8","w":199,"h":389,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_9","w":245,"h":343,"u":"","p":"data:image/png;base64,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","e":1}],"layers":[{"ddd":0,"ind":1,"ty":2,"nm":"ball head","refId":"image_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[535.095,255.22,0],"ix":2},"a":{"a":0,"k":[46.001,25.171,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":2,"nm":"ball","refId":"image_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[394.924,534.767,0],"ix":2},"a":{"a":0,"k":[46.798,46.798,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":2,"nm":"Hand","refId":"image_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[11]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":178,"s":[11]},{"t":238,"s":[0]}],"ix":10},"p":{"a":0,"k":[389.117,535.861,0],"ix":2},"a":{"a":0,"k":[175.131,18.657,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":2,"nm":"Layer 11","refId":"image_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[753.222,512.085,0],"ix":2},"a":{"a":0,"k":[20.262,33.699,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":60,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":75,"s":[100,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":90,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":179,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":194,"s":[100,0,100]},{"t":209,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":2,"nm":"Layer 8","refId":"image_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[593.544,512.897,0],"ix":2},"a":{"a":0,"k":[20.428,33.795,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":60,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":75,"s":[100,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":90,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":179,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":194,"s":[100,0,100]},{"t":209,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":2,"nm":"Layer 12","refId":"image_5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[-10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":150,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[-10]},{"t":210,"s":[0]}],"ix":10},"p":{"a":0,"k":[532.132,249.678,0],"ix":2},"a":{"a":0,"k":[47.909,118.344,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":2,"nm":"Layer 1","refId":"image_6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[557.993,501.428,0],"ix":2},"a":{"a":0,"k":[251.852,254.048,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":2,"nm":"Layer 10","refId":"image_7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[488.203,863.677,0],"ix":2},"a":{"a":0,"k":[65.677,194.503,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":2,"nm":"Layer 9","refId":"image_8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":42,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":90,"s":[5]},{"t":151,"s":[0]}],"ix":10},"p":{"a":0,"k":[629.371,718.723,0],"ix":2},"a":{"a":0,"k":[74.03,67.009,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":2,"nm":"Layer 2","refId":"image_9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":60,"s":[124]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[124]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[0]},{"t":240,"s":[0]}],"ix":10},"p":{"a":0,"k":[747.941,545.162,0],"ix":2},"a":{"a":0,"k":[14.418,315.027,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":600,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/tests/Content/images/lottie-base64_women-thinking.json b/tests/Content/images/lottie-base64_women-thinking.json new file mode 100644 index 0000000000..6d29326fb5 --- /dev/null +++ b/tests/Content/images/lottie-base64_women-thinking.json @@ -0,0 +1 @@ +{"v":"5.7.3","fr":60,"ip":0,"op":361,"w":1878,"h":1878,"nm":"women-thinking","ddd":0,"assets":[{"id":"image_0","w":174,"h":569,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_1","w":501,"h":1188,"u":"","p":"data:image/png;base64,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YXRvcgAACJlzTMlPSlVwTCtJLVJwTUtLTS4pBgBBegbOanoVxQAAIABJREFUeJzs3V9wXNedJ/bv73YDIERYAGnJElczIjylP5yRRPZaVU5SNWsiL6ps7LHlrZqUFVk26IxSrmw8Ep2k9m3E2Ye87FaGzstOameH8Eoa7dOa2kyqplKVErR5mMlmPAbHdkzLrjXosa1/tgRIIAEC3ffkoQGyAXT3/XfuOb9z7vdTZRkAgb6/7nvu+d1z7vkDEBERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERKSe+AyCKWWd+cQ5H0OkCANpoo4tUkk5qMNf/jRTJrf8CSZICaf9fDJJVg3QVu38LAN+7+ifL7qInotAwqRNV8OipxQVJMWeSpANJ5wTSMQYQ4OzovxIApuqh1wGs9F9NllOkANrL7VZ3beX7SytVX5yIwsSkTpRDp7M4191CJwEWjKAjRjoGOOk7rlEEuGaAVYEsG5GVHdNbuXp1adV3XERULyZ1ohE684tzvSN4EiJPwuBzvuM5qER7fx2CFTFmOUV7ub3VXVlZXVqrJTgi8oJJneiAU6cW5ycgFwB5EjCzvuMppmCqN7giIpdTpMvfu7q0XFdUROQGkzrRrkcfXVyQrlzA2Ofh9bLytL28dQiWYczl1hFcXllhK54oNEzq1HiPnvq9BUHvAjwmc6WuiJilbYPLfB5PFAYmdWqsR08tLgj8tsyDYfAqRC63tu68vLJ6kS14IqWY1KlxOqcW53uQJTCZF2dkXcRcTlrmIqfOEenDpE6N0R/NLhcBfNl3LDEw/UF2F7979U+XfMdCRH1M6tQIpx/+yvMQc8EAgY1m10+A9RRycWPrzour7Jon8opJnaL26KnFBRi5KIIzvmNpgHVjzFJXcJED64j8YFKnKHU6i3Pdm3JBDJ5zd1TPE9J0+WYL5sIKkzuRU0zqFJ1HT/3eAtBbkmHLuBqw1LuzbhJzsX0DF7lyHZEbrN4oGn5a55RFjKxDcPFvr/7pBd+xEMWOSZ2i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","e":1},{"id":"image_2","w":687,"h":773,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_3","w":114,"h":276,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_4","w":91,"h":175,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_5","w":144,"h":160,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_6","w":184,"h":174,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_7","w":77,"h":74,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_8","w":62,"h":57,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_9","w":161,"h":177,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_10","w":134,"h":149,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_11","w":135,"h":186,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_12","w":133,"h":137,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_13","w":131,"h":111,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_14","w":188,"h":139,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_15","w":134,"h":121,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_16","w":67,"h":50,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_17","w":141,"h":116,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_18","w":252,"h":164,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_19","w":164,"h":175,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_20","w":139,"h":141,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_21","w":90,"h":113,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_22","w":37,"h":40,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_23","w":144,"h":134,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_24","w":166,"h":195,"u":"","p":"data:image/png;base64,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","e":1}],"layers":[{"ddd":0,"ind":1,"ty":2,"nm":"Layer 32","refId":"image_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":29,"s":[-10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":59,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":91,"s":[-10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":121,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":150,"s":[-10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":180,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":210,"s":[-10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":240,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":270,"s":[-10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":300,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":330,"s":[-10]},{"t":360,"s":[0]}],"ix":10},"p":{"a":0,"k":[834.039,1285.384,0],"ix":2},"a":{"a":0,"k":[48.541,524.26,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":2425,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":2,"nm":"Layer 6","refId":"image_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[984.285,1080.978,0],"ix":2},"a":{"a":0,"k":[250.402,593.69,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":2425,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":2,"nm":"Layer 33","refId":"image_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":59,"s":[11]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":119,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":180,"s":[11]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":240,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":300,"s":[11]},{"t":360,"s":[0]}],"ix":10},"p":{"a":0,"k":[1002.549,568.705,0],"ix":2},"a":{"a":0,"k":[501.25,56.409,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":2425,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":2,"nm":"Layer 14","refId":"image_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[1],"y":[0]},"t":61,"s":[15]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":109,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[1],"y":[0]},"t":300,"s":[0]},{"t":360,"s":[376]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":61,"s":[1165.74,-495.207,0],"to":[-26,138.667,0],"ti":[26,-138.667,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":109,"s":[1009.74,336.793,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":300,"s":[1009.74,336.793,0],"to":[-271.333,-56,0],"ti":[271.333,56,0]},{"t":360,"s":[-618.26,0.793,0]}],"ix":2},"a":{"a":0,"k":[56.984,137.852,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":61,"op":2486,"st":37,"bm":0},{"ddd":0,"ind":5,"ty":2,"nm":"Layer 15","refId":"image_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[1],"y":[0]},"t":53,"s":[15]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":101,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[1],"y":[0]},"t":300,"s":[0]},{"t":360,"s":[364]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":53,"s":[1267.7,-434.106,0],"to":[-26,138.667,0],"ti":[26,-138.667,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.167,"y":0.167},"t":101,"s":[1111.7,397.894,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":300,"s":[1111.7,397.894,0],"to":[207.333,-76,0],"ti":[-207.333,76,0]},{"t":360,"s":[2355.7,-58.106,0]}],"ix":2},"a":{"a":0,"k":[45.056,87.197,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":53,"op":2478,"st":29,"bm":0},{"ddd":0,"ind":6,"ty":2,"nm":"Layer 19","refId":"image_5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":22,"s":[923.463,980.12,0],"to":[-55.333,-49,0],"ti":[55.333,49,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":82,"s":[591.463,686.12,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":262,"s":[591.463,686.12,0],"to":[55.333,49,0],"ti":[-55.333,-49,0]},{"t":322,"s":[923.463,980.12,0]}],"ix":2},"a":{"a":0,"k":[71.899,79.72,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":22,"op":2447,"st":22,"bm":0},{"ddd":0,"ind":7,"ty":2,"nm":"Layer 2","refId":"image_6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":3,"s":[909.806,970.321,0],"to":[111,-21,0],"ti":[-111,21,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":63,"s":[1575.806,844.321,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":243,"s":[1575.806,844.321,0],"to":[-111,21,0],"ti":[111,-21,0]},{"t":303,"s":[909.806,970.321,0]}],"ix":2},"a":{"a":0,"k":[91.632,86.741,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":3,"op":2428,"st":3,"bm":0},{"ddd":0,"ind":8,"ty":2,"nm":"Layer 3","refId":"image_7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":17,"s":[947.498,934.079,0],"to":[-28,-62,0],"ti":[28,62,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":77,"s":[779.498,562.079,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":257,"s":[779.498,562.079,0],"to":[28,62,0],"ti":[-28,-62,0]},{"t":317,"s":[947.498,934.079,0]}],"ix":2},"a":{"a":0,"k":[38.274,36.981,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":17,"op":2442,"st":17,"bm":0},{"ddd":0,"ind":9,"ty":2,"nm":"Layer 4","refId":"image_8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":2,"s":[915.599,969.942,0],"to":[-38.667,-54.667,0],"ti":[38.667,54.667,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":62,"s":[683.599,641.942,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":242,"s":[683.599,641.942,0],"to":[38.667,54.667,0],"ti":[-38.667,-54.667,0]},{"t":302,"s":[915.599,969.942,0]}],"ix":2},"a":{"a":0,"k":[30.853,28.307,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":2,"op":2427,"st":2,"bm":0},{"ddd":0,"ind":10,"ty":2,"nm":"Layer 5","refId":"image_9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":6,"s":[904.285,955.754,0],"to":[-33.667,-77.667,0],"ti":[33.667,77.667,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":66,"s":[702.285,489.754,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":246,"s":[702.285,489.754,0],"to":[33.667,77.667,0],"ti":[-33.667,-77.667,0]},{"t":306,"s":[904.285,955.754,0]}],"ix":2},"a":{"a":0,"k":[80.336,88.382,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":6,"op":2431,"st":6,"bm":0},{"ddd":0,"ind":11,"ty":2,"nm":"Layer 16","refId":"image_10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":14,"s":[941.34,941.283,0],"to":[52,-4.333,0],"ti":[-52,4.333,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":74,"s":[1253.34,915.283,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":254,"s":[1253.34,915.283,0],"to":[-52,4.333,0],"ti":[52,-4.333,0]},{"t":314,"s":[941.34,941.283,0]}],"ix":2},"a":{"a":0,"k":[66.598,74.152,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":14,"op":2439,"st":14,"bm":0},{"ddd":0,"ind":12,"ty":2,"nm":"Layer 17","refId":"image_11","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[903.727,966.582,0],"to":[56,-47,0],"ti":[-56,47,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":60,"s":[1239.727,684.582,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":240,"s":[1239.727,684.582,0],"to":[-56,47,0],"ti":[56,-47,0]},{"t":300,"s":[903.727,966.582,0]}],"ix":2},"a":{"a":0,"k":[67.313,92.977,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":2425,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":2,"nm":"Layer 18","refId":"image_12","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":22,"s":[902.245,959.29,0],"to":[-91,-2.667,0],"ti":[91,2.667,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":82,"s":[356.245,943.29,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":262,"s":[356.245,943.29,0],"to":[91,2.667,0],"ti":[-91,-2.667,0]},{"t":322,"s":[902.245,959.29,0]}],"ix":2},"a":{"a":0,"k":[66.241,68.049,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":22,"op":2447,"st":22,"bm":0},{"ddd":0,"ind":14,"ty":2,"nm":"Layer 20","refId":"image_13","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":29,"s":[933.839,976.188,0],"to":[-114,-19.333,0],"ti":[114,19.333,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":89,"s":[249.839,860.188,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":269,"s":[249.839,860.188,0],"to":[114,19.333,0],"ti":[-114,-19.333,0]},{"t":329,"s":[933.839,976.188,0]}],"ix":2},"a":{"a":0,"k":[65.371,55.049,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":29,"op":2454,"st":29,"bm":0},{"ddd":0,"ind":15,"ty":2,"nm":"Layer 21","refId":"image_14","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":5,"s":[896.696,968.016,0],"to":[-70,-24.667,0],"ti":[70,24.667,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":65,"s":[476.696,820.016,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":245,"s":[476.696,820.016,0],"to":[70,24.667,0],"ti":[-70,-24.667,0]},{"t":305,"s":[896.696,968.016,0]}],"ix":2},"a":{"a":0,"k":[93.922,69.435,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":5,"op":2430,"st":5,"bm":0},{"ddd":0,"ind":16,"ty":2,"nm":"Layer 22","refId":"image_15","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[929.73,939.986,0],"to":[-95.333,-44.333,0],"ti":[95.333,44.333,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":60,"s":[357.73,673.986,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":240,"s":[357.73,673.986,0],"to":[95.333,44.333,0],"ti":[-95.333,-44.333,0]},{"t":300,"s":[929.73,939.986,0]}],"ix":2},"a":{"a":0,"k":[66.88,60.28,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":2425,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":2,"nm":"Layer 23","refId":"image_16","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":28,"s":[925.782,936.967,0],"to":[-74.333,-51.333,0],"ti":[74.333,51.333,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":88,"s":[479.782,628.967,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":268,"s":[479.782,628.967,0],"to":[74.333,51.333,0],"ti":[-74.333,-51.333,0]},{"t":328,"s":[925.782,936.967,0]}],"ix":2},"a":{"a":0,"k":[33.215,24.757,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":28,"op":2453,"st":28,"bm":0},{"ddd":0,"ind":18,"ty":2,"nm":"Layer 24","refId":"image_17","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":5,"s":[956.3,894.969,0],"to":[54.333,-62,0],"ti":[-54.333,62,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":65,"s":[1282.3,522.969,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":245,"s":[1282.3,522.969,0],"to":[-54.333,62,0],"ti":[54.333,-62,0]},{"t":305,"s":[956.3,894.969,0]}],"ix":2},"a":{"a":0,"k":[70.492,57.92,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":5,"op":2430,"st":5,"bm":0},{"ddd":0,"ind":19,"ty":2,"nm":"Layer 25","refId":"image_18","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":6,"s":[908.046,955.314,0],"to":[120.333,-55,0],"ti":[-120.333,55,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":66,"s":[1630.046,625.314,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":246,"s":[1630.046,625.314,0],"to":[-120.333,55,0],"ti":[120.333,-55,0]},{"t":306,"s":[908.046,955.314,0]}],"ix":2},"a":{"a":0,"k":[125.576,81.636,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":6,"op":2431,"st":6,"bm":0},{"ddd":0,"ind":20,"ty":2,"nm":"Layer 26","refId":"image_19","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":2,"s":[935.79,868.205,0],"to":[83.667,-23.333,0],"ti":[-83.667,23.333,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":62,"s":[1437.79,728.205,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":242,"s":[1437.79,728.205,0],"to":[-83.667,23.333,0],"ti":[83.667,-23.333,0]},{"t":302,"s":[935.79,868.205,0]}],"ix":2},"a":{"a":0,"k":[81.6,87.08,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":2,"op":2427,"st":2,"bm":0},{"ddd":0,"ind":21,"ty":2,"nm":"Layer 27","refId":"image_20","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":4,"s":[963.953,926.261,0],"to":[84.667,-70.333,0],"ti":[-84.667,70.333,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":64,"s":[1471.953,504.261,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":244,"s":[1471.953,504.261,0],"to":[-84.667,70.333,0],"ti":[84.667,-70.333,0]},{"t":304,"s":[963.953,926.261,0]}],"ix":2},"a":{"a":0,"k":[69.384,70.155,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":4,"op":2429,"st":4,"bm":0},{"ddd":0,"ind":22,"ty":2,"nm":"Layer 28","refId":"image_21","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":16,"s":[925.304,981.72,0],"to":[-66.667,-87.333,0],"ti":[66.667,87.333,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":76,"s":[525.304,457.72,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":256,"s":[525.304,457.72,0],"to":[66.667,87.333,0],"ti":[-66.667,-87.333,0]},{"t":316,"s":[925.304,981.72,0]}],"ix":2},"a":{"a":0,"k":[44.801,56.096,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":16,"op":2441,"st":16,"bm":0},{"ddd":0,"ind":23,"ty":2,"nm":"Layer 29","refId":"image_22","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":13,"s":[937.312,948.256,0],"to":[-74.333,0,0],"ti":[74.333,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":73,"s":[491.312,948.256,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":253,"s":[491.312,948.256,0],"to":[74.333,0,0],"ti":[-74.333,0,0]},{"t":313,"s":[937.312,948.256,0]}],"ix":2},"a":{"a":0,"k":[18.395,19.881,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":13,"op":2438,"st":13,"bm":0},{"ddd":0,"ind":24,"ty":2,"nm":"Layer 30","refId":"image_23","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":5,"s":[905.527,924.306,0],"to":[-85.333,-67.333,0],"ti":[85.333,67.333,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":65,"s":[393.527,520.306,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":245,"s":[393.527,520.306,0],"to":[85.333,67.333,0],"ti":[-85.333,-67.333,0]},{"t":305,"s":[905.527,924.306,0]}],"ix":2},"a":{"a":0,"k":[71.97,66.794,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":5,"op":2430,"st":5,"bm":0},{"ddd":0,"ind":25,"ty":2,"nm":"Layer 31","refId":"image_24","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[900.969,954.77,0],"to":[-116,-43.333,0],"ti":[116,43.333,0]},{"i":{"x":0,"y":0},"o":{"x":0.333,"y":0.333},"t":60,"s":[204.969,694.77,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":240,"s":[204.969,694.77,0],"to":[116,43.333,0],"ti":[-116,-43.333,0]},{"t":300,"s":[900.969,954.77,0]}],"ix":2},"a":{"a":0,"k":[82.801,97.357,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":2425,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/tests/SkiaSharp.Tests.Console.sln b/tests/SkiaSharp.Tests.Console.sln index 4ecd3f584e..f2a39ff7c7 100644 --- a/tests/SkiaSharp.Tests.Console.sln +++ b/tests/SkiaSharp.Tests.Console.sln @@ -17,6 +17,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Vulkan.SharpVk", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.SceneGraph", "..\binding\SkiaSharp.SceneGraph\SkiaSharp.SceneGraph.csproj", "{978AD2C6-E592-4F5E-B565-26C357877B2C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Resources", "..\binding\SkiaSharp.Resources\SkiaSharp.Resources.csproj", "{AD2C6978-4F5E-E592-B565-26C357877B2C}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Skottie", "..\binding\SkiaSharp.Skottie\SkiaSharp.Skottie.csproj", "{D35696BA-3038-41F2-9BE9-181439E6EF9E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "source", "source", "{9FAA974B-A671-40BC-82EA-8EF77F463ECB}" @@ -115,6 +117,18 @@ Global {978AD2C6-E592-4F5E-B565-26C357877B2C}.Release|x64.Build.0 = Release|Any CPU {978AD2C6-E592-4F5E-B565-26C357877B2C}.Release|x86.ActiveCfg = Release|Any CPU {978AD2C6-E592-4F5E-B565-26C357877B2C}.Release|x86.Build.0 = Release|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Debug|x64.ActiveCfg = Debug|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Debug|x64.Build.0 = Debug|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Debug|x86.ActiveCfg = Debug|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Debug|x86.Build.0 = Debug|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Release|Any CPU.Build.0 = Release|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Release|x64.ActiveCfg = Release|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Release|x64.Build.0 = Release|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Release|x86.ActiveCfg = Release|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Release|x86.Build.0 = Release|Any CPU {D35696BA-3038-41F2-9BE9-181439E6EF9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D35696BA-3038-41F2-9BE9-181439E6EF9E}.Debug|Any CPU.Build.0 = Debug|Any CPU {D35696BA-3038-41F2-9BE9-181439E6EF9E}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -137,6 +151,7 @@ Global {0DE402FA-A101-438E-8528-6EA82E0FF803} = {9FAA974B-A671-40BC-82EA-8EF77F463ECB} {A53DD2E5-55C4-4F7C-9316-D7FAD9A6F19F} = {9FAA974B-A671-40BC-82EA-8EF77F463ECB} {978AD2C6-E592-4F5E-B565-26C357877B2C} = {9FAA974B-A671-40BC-82EA-8EF77F463ECB} + {AD2C6978-4F5E-E592-B565-26C357877B2C} = {9FAA974B-A671-40BC-82EA-8EF77F463ECB} {D35696BA-3038-41F2-9BE9-181439E6EF9E} = {9FAA974B-A671-40BC-82EA-8EF77F463ECB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/tests/SkiaSharp.Tests.Console/SkiaSharp.Tests.Console.csproj b/tests/SkiaSharp.Tests.Console/SkiaSharp.Tests.Console.csproj index 9344683577..394deb1828 100644 --- a/tests/SkiaSharp.Tests.Console/SkiaSharp.Tests.Console.csproj +++ b/tests/SkiaSharp.Tests.Console/SkiaSharp.Tests.Console.csproj @@ -25,6 +25,7 @@ + diff --git a/tests/SkiaSharp.Tests.Console/SkiaSharp/SKBitmapThreadingTest.cs b/tests/SkiaSharp.Tests.Console/SkiaSharp/SKBitmapThreadingTest.cs index c92dc2526a..5c345c9961 100644 --- a/tests/SkiaSharp.Tests.Console/SkiaSharp/SKBitmapThreadingTest.cs +++ b/tests/SkiaSharp.Tests.Console/SkiaSharp/SKBitmapThreadingTest.cs @@ -12,6 +12,7 @@ namespace SkiaSharp.Tests public class SKBitmapThreadingTest : SKTest { [SkippableTheory] + [InlineData(10, 10)] [InlineData(100, 1000)] public static void ImageScalingMultipleThreadsTest(int numThreads, int numIterationsPerThread) { diff --git a/tests/SkiaSharp.Tests.Devices.sln b/tests/SkiaSharp.Tests.Devices.sln index a27222c5cb..265ff46f70 100644 --- a/tests/SkiaSharp.Tests.Devices.sln +++ b/tests/SkiaSharp.Tests.Devices.sln @@ -13,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HarfBuzzSharp", "..\binding EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.SceneGraph", "..\binding\SkiaSharp.SceneGraph\SkiaSharp.SceneGraph.csproj", "{8CD906F8-B3E4-48E6-8B16-EAFC0C34EAE1}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Resources", "..\binding\SkiaSharp.Resources\SkiaSharp.Resources.csproj", "{AD2C6978-4F5E-E592-B565-26C357877B2C}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Skottie", "..\binding\SkiaSharp.Skottie\SkiaSharp.Skottie.csproj", "{915D1D57-B059-4301-9A35-2E5EB68DED99}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.HarfBuzz", "..\source\SkiaSharp.HarfBuzz\SkiaSharp.HarfBuzz\SkiaSharp.HarfBuzz.csproj", "{6F999CA5-B67F-46A3-9A94-9E99527060F6}" @@ -55,6 +57,10 @@ Global {8CD906F8-B3E4-48E6-8B16-EAFC0C34EAE1}.Debug|Any CPU.Build.0 = Debug|Any CPU {8CD906F8-B3E4-48E6-8B16-EAFC0C34EAE1}.Release|Any CPU.ActiveCfg = Release|Any CPU {8CD906F8-B3E4-48E6-8B16-EAFC0C34EAE1}.Release|Any CPU.Build.0 = Release|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Release|Any CPU.Build.0 = Release|Any CPU {915D1D57-B059-4301-9A35-2E5EB68DED99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {915D1D57-B059-4301-9A35-2E5EB68DED99}.Debug|Any CPU.Build.0 = Debug|Any CPU {915D1D57-B059-4301-9A35-2E5EB68DED99}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -87,6 +93,7 @@ Global {9D753C4C-D7FC-4D1B-ABF0-BF1C089B987A} = {6779122B-72B0-42ED-A1E7-5029C1C0A78D} {D48557C5-795D-4948-84EE-A7531DDD91DC} = {6779122B-72B0-42ED-A1E7-5029C1C0A78D} {8CD906F8-B3E4-48E6-8B16-EAFC0C34EAE1} = {6779122B-72B0-42ED-A1E7-5029C1C0A78D} + {AD2C6978-4F5E-E592-B565-26C357877B2C} = {6779122B-72B0-42ED-A1E7-5029C1C0A78D} {915D1D57-B059-4301-9A35-2E5EB68DED99} = {6779122B-72B0-42ED-A1E7-5029C1C0A78D} {6F999CA5-B67F-46A3-9A94-9E99527060F6} = {6779122B-72B0-42ED-A1E7-5029C1C0A78D} {398936B0-1B68-4F2D-B91C-6880CAC9F168} = {6779122B-72B0-42ED-A1E7-5029C1C0A78D} diff --git a/tests/SkiaSharp.Tests.Devices/SkiaSharp.Tests.Devices.csproj b/tests/SkiaSharp.Tests.Devices/SkiaSharp.Tests.Devices.csproj index d464186f28..9eb1a63ee2 100644 --- a/tests/SkiaSharp.Tests.Devices/SkiaSharp.Tests.Devices.csproj +++ b/tests/SkiaSharp.Tests.Devices/SkiaSharp.Tests.Devices.csproj @@ -46,6 +46,7 @@ + diff --git a/tests/SkiaSharp.Tests.Wasm.sln b/tests/SkiaSharp.Tests.Wasm.sln index ec7f300759..ad2b61529a 100644 --- a/tests/SkiaSharp.Tests.Wasm.sln +++ b/tests/SkiaSharp.Tests.Wasm.sln @@ -13,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.HarfBuzz", "..\so EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.SceneGraph", "..\binding\SkiaSharp.SceneGraph\SkiaSharp.SceneGraph.csproj", "{2A777BD2-9108-4747-BBD2-0240B8D7CCC3}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Resources", "..\binding\SkiaSharp.Resources\SkiaSharp.Resources.csproj", "{AD2C6978-4F5E-E592-B565-26C357877B2C}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Skottie", "..\binding\SkiaSharp.Skottie\SkiaSharp.Skottie.csproj", "{3FCCE93A-727E-4891-8449-468F13E8052A}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "source", "source", "{5C42DB9F-1771-4F1D-8247-E58AEB9D9094}" @@ -43,6 +45,10 @@ Global {2A777BD2-9108-4747-BBD2-0240B8D7CCC3}.Debug|Any CPU.Build.0 = Debug|Any CPU {2A777BD2-9108-4747-BBD2-0240B8D7CCC3}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A777BD2-9108-4747-BBD2-0240B8D7CCC3}.Release|Any CPU.Build.0 = Release|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Release|Any CPU.Build.0 = Release|Any CPU {3FCCE93A-727E-4891-8449-468F13E8052A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3FCCE93A-727E-4891-8449-468F13E8052A}.Debug|Any CPU.Build.0 = Debug|Any CPU {3FCCE93A-727E-4891-8449-468F13E8052A}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -56,6 +62,7 @@ Global {B020BCC5-FC01-4ADC-839E-18E63BC6D4C5} = {5C42DB9F-1771-4F1D-8247-E58AEB9D9094} {6E6DF00F-30EF-479B-92FB-B07DDE6B1259} = {5C42DB9F-1771-4F1D-8247-E58AEB9D9094} {2A777BD2-9108-4747-BBD2-0240B8D7CCC3} = {5C42DB9F-1771-4F1D-8247-E58AEB9D9094} + {AD2C6978-4F5E-E592-B565-26C357877B2C} = {5C42DB9F-1771-4F1D-8247-E58AEB9D9094} {3FCCE93A-727E-4891-8449-468F13E8052A} = {5C42DB9F-1771-4F1D-8247-E58AEB9D9094} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/tests/SkiaSharp.Tests.Wasm/SkiaSharp.Tests.Wasm.csproj b/tests/SkiaSharp.Tests.Wasm/SkiaSharp.Tests.Wasm.csproj index ba495e41e8..dc12070831 100644 --- a/tests/SkiaSharp.Tests.Wasm/SkiaSharp.Tests.Wasm.csproj +++ b/tests/SkiaSharp.Tests.Wasm/SkiaSharp.Tests.Wasm.csproj @@ -28,6 +28,7 @@ + diff --git a/tests/SkiaSharp.Tests/SkiaSharp.Tests.csproj b/tests/SkiaSharp.Tests/SkiaSharp.Tests.csproj index bf617ca98d..a5013ed9fe 100644 --- a/tests/SkiaSharp.Tests/SkiaSharp.Tests.csproj +++ b/tests/SkiaSharp.Tests/SkiaSharp.Tests.csproj @@ -17,6 +17,7 @@ + diff --git a/tests/Tests/Resources/ResourceProviderTest.cs b/tests/Tests/Resources/ResourceProviderTest.cs new file mode 100644 index 0000000000..93bc337b7e --- /dev/null +++ b/tests/Tests/Resources/ResourceProviderTest.cs @@ -0,0 +1,81 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using SkiaSharp.Resources; +using Xunit; + +namespace SkiaSharp.Tests +{ + public class ResourceProviderTest : SKTest + { + [SkippableFact] + public void FileResourceProviderCanReadFiles() + { + var fullPath = Path.Combine(PathToImages, "baboon.png"); + var expectedData = SKData.Create(fullPath); + + using var rp = new FileResourceProvider(PathToImages); + + using var data = rp.Load("baboon.png"); + + Assert.Equal(expectedData.ToArray(), data.ToArray()); + } + + [SkippableFact] + public void ProxyProviderCanReadFiles() + { + var fullPath = Path.Combine(PathToImages, "baboon.png"); + var expectedData = SKData.Create(fullPath); + + using var files = new FileResourceProvider(PathToImages); + using var datauri = new DataUriResourceProvider(files); + using var caching = new CachingResourceProvider(datauri); + + using var data = caching.Load("baboon.png"); + + Assert.Equal(expectedData.ToArray(), data.ToArray()); + } + + [SkippableFact] + public void CanCreateDefaultDataUri() + { + using var datauri = new DataUriResourceProvider(); + + Assert.NotNull(datauri); + } + + [SkippableFact] + public void CanCreateNullDataUri() + { + using var datauri = new DataUriResourceProvider(null); + + Assert.NotNull(datauri); + } + + [SkippableFact] + public void WrappedResourceManagersAreNotCollectedPrematurely() + { + var fullPath = Path.Combine(PathToImages, "baboon.png"); + var expectedData = SKData.Create(fullPath); + + var (caching, weak) = CreateProvider(); + + CollectGarbage(); + + Assert.True(weak.IsAlive); + + using var data = caching.Load("baboon.png"); + + Assert.Equal(expectedData.ToArray(), data.ToArray()); + + static (CachingResourceProvider, WeakReference) CreateProvider() + { + var files = new FileResourceProvider(PathToImages); + var datauri = new DataUriResourceProvider(files); + var caching = new CachingResourceProvider(datauri); + + return (caching, new WeakReference(files)); + } + } + } +} diff --git a/tests/Tests/SkiaSharp/SKDrawableTest.cs b/tests/Tests/SkiaSharp/SKDrawableTest.cs index bc2466ae08..91110e4731 100644 --- a/tests/Tests/SkiaSharp/SKDrawableTest.cs +++ b/tests/Tests/SkiaSharp/SKDrawableTest.cs @@ -6,6 +6,41 @@ public class SKDrawableTest : SKTest { [SkippableFact] public void CanInstantiateDrawable() + { + using (var drawable = new TestDrawable()) + { + } + } + + [SkippableFact] + public void CanAccessBounds() + { + using (var drawable = new TestDrawable()) + { + Assert.Equal(SKRect.Create(100, 100), drawable.Bounds); + Assert.Equal(1, drawable.BoundsFireCount); + } + } + + [Trait(Traits.FailingOn.Key, Traits.FailingOn.Values.macOS)] // Something with sk_sp SkDrawable::onMakePictureSnapshot() is causing issues + [Trait(Traits.FailingOn.Key, Traits.FailingOn.Values.iOS)] // Something with sk_sp SkDrawable::onMakePictureSnapshot() is causing issues + [Trait(Traits.FailingOn.Key, Traits.FailingOn.Values.MacCatalyst)] // Something with sk_sp SkDrawable::onMakePictureSnapshot() is causing issues + [SkippableFact] + public void CanCreateSnapshot() + { + using (var drawable = new TestDrawable()) + { + var picture = drawable.Snapshot(); + Assert.NotNull(picture); + Assert.Equal(1, drawable.SnapshotFireCount); + } + } + + [Trait(Traits.FailingOn.Key, Traits.FailingOn.Values.macOS)] // Something with sk_sp SkDrawable::onMakePictureSnapshot() is causing issues + [Trait(Traits.FailingOn.Key, Traits.FailingOn.Values.iOS)] // Something with sk_sp SkDrawable::onMakePictureSnapshot() is causing issues + [Trait(Traits.FailingOn.Key, Traits.FailingOn.Values.MacCatalyst)] // Something with sk_sp SkDrawable::onMakePictureSnapshot() is causing issues + [SkippableFact] + public void CanUseAllMembers() { using (var drawable = new TestDrawable()) { diff --git a/tests/Tests/Skottie/AnimationBuilderTest.cs b/tests/Tests/Skottie/AnimationBuilderTest.cs new file mode 100644 index 0000000000..a2644e1c2b --- /dev/null +++ b/tests/Tests/Skottie/AnimationBuilderTest.cs @@ -0,0 +1,141 @@ +using System; +using System.IO; +using SkiaSharp.Resources; +using SkiaSharp.SceneGraph; +using SkiaSharp.Skottie; +using Xunit; + +namespace SkiaSharp.Tests +{ + public class AnimationBuilderTest : SKTest + { + public static TheoryData DefaultLottieFiles => + AnimationTest.DefaultLottieFiles; + + public static TheoryData Base64Files => + new TheoryData + { + "lottie-base64_dotnet-bot.json", + "lottie-base64_women-thinking.json", + }; + + [SkippableTheory] + [MemberData(nameof(DefaultLottieFiles))] + public void DefaultBuilderIsTheSameAsDefaultCreate(string filename) + { + var path = Path.Combine(PathToImages, filename); + using var data = SKData.Create(path); + var directAnimation = Animation.Create(data); + + var builderAnimation = Animation.CreateBuilder().Build(data); + Assert.NotNull(builderAnimation); + Assert.NotEqual(IntPtr.Zero, builderAnimation.Handle); + + Assert.Equal(directAnimation.Duration, builderAnimation.Duration); + Assert.Equal(directAnimation.Fps, builderAnimation.Fps); + Assert.Equal(directAnimation.InPoint, builderAnimation.InPoint); + Assert.Equal(directAnimation.OutPoint, builderAnimation.OutPoint); + Assert.Equal(directAnimation.Version, builderAnimation.Version); + Assert.Equal(directAnimation.Size, builderAnimation.Size); + } + + [SkippableTheory] + [MemberData(nameof(DefaultLottieFiles))] + public void DefaultBuilderHasStats(string filename) + { + var path = Path.Combine(PathToImages, filename); + using var data = SKData.Create(path); + + var builder = Animation.CreateBuilder(); + var animation = builder.Build(data); + Assert.NotNull(animation); + + var stats = builder.Stats; + Assert.True(stats.SceneParseTime >= TimeSpan.Zero); + Assert.True(stats.JsonParseTime >= TimeSpan.Zero); + Assert.True(stats.TotalLoadTime >= TimeSpan.Zero); + Assert.True(stats.JsonSize > 0); + Assert.True(stats.AnimatorCount > 0); + } + + [SkippableTheory] + [MemberData(nameof(Base64Files))] + public void CanLoadBase64ImagesFromData(string filename) + { + var path = Path.Combine(PathToImages, filename); + using var data = SKData.Create(path); + + var animation = Animation + .CreateBuilder() + .SetResourceProvider(new DataUriResourceProvider()) + .Build(data); + + Assert.NotNull(animation); + Assert.True(animation.Duration > TimeSpan.Zero); + } + + [SkippableTheory] + [MemberData(nameof(Base64Files))] + public void CanLoadBase64ImagesFromFilename(string filename) + { + var path = Path.Combine(PathToImages, filename); + + var animation = Animation + .CreateBuilder() + .SetResourceProvider(new DataUriResourceProvider()) + .Build(path); + + Assert.NotNull(animation); + Assert.True(animation.Duration > TimeSpan.Zero); + } + + [SkippableTheory] + [MemberData(nameof(Base64Files))] + public void CanRenderWithBase64(string filename) + { + var animation = Animation + .CreateBuilder() + .SetResourceProvider(new DataUriResourceProvider()) + .Build(Path.Combine(PathToImages, filename)); + + using var bmp = new SKBitmap((int)animation.Size.Width, (int)animation.Size.Height); + bmp.Erase(SKColors.Red); + var beforePixels = bmp.Pixels; + + using var canvas = new SKCanvas(bmp); + animation.Seek(0.1); + animation.Render(canvas, bmp.Info.Rect); + var afterPixels = bmp.Pixels; + + Assert.NotEqual(beforePixels, afterPixels); + } + + [SkippableFact] + public void WrappedResourceManagersAreNotCollectedPrematurely() + { + var (builder, weak) = CreateBuilder(); + + CollectGarbage(); + + Assert.True(weak.IsAlive); + + using var animation = builder.Build(Path.Combine(PathToImages, "lottie-base64_dotnet-bot.json")); + + builder.Dispose(); + CollectGarbage(); + + Assert.False(weak.IsAlive); + + static (AnimationBuilder, WeakReference) CreateBuilder() + { + var provider = new DataUriResourceProvider(); + + var builder = Animation + .CreateBuilder() + .SetResourceProvider(provider); + + return (builder, new WeakReference(provider)); + } + } + } +} diff --git a/tests/Tests/Skottie/AnimationTest.cs b/tests/Tests/Skottie/AnimationTest.cs index 02a7b4f0ff..3c115e619b 100644 --- a/tests/Tests/Skottie/AnimationTest.cs +++ b/tests/Tests/Skottie/AnimationTest.cs @@ -177,9 +177,12 @@ public void When_Default_Create_From_File(string filename) Assert.NotEqual(IntPtr.Zero, animation.Handle); } - private Animation BuildDefaultAnimation() + private Animation BuildDefaultAnimation() => + BuildAnimation("LottieLogo1.json"); + + private Animation BuildAnimation(string filename) { - var path = Path.Combine(PathToImages, "LottieLogo1.json"); + var path = Path.Combine(PathToImages, filename); var result = Animation.TryCreate(path, out var animation); Assert.True(result); @@ -307,5 +310,39 @@ public void When_Size() Assert.Equal(new SKSize(375, 667), animation.Size); } + + [SkippableFact] + public void Can_Render() + { + var animation = BuildDefaultAnimation(); + + using var bmp = new SKBitmap((int)animation.Size.Width, (int)animation.Size.Height); + bmp.Erase(SKColors.Red); + var beforePixels = bmp.Pixels; + + using var canvas = new SKCanvas(bmp); + animation.Seek(0.1); + animation.Render(canvas, bmp.Info.Rect); + var afterPixels = bmp.Pixels; + + Assert.NotEqual(beforePixels, afterPixels); + } + + [SkippableFact] + public void Can_Not_Render_With_Base64() + { + var animation = BuildAnimation("lottie-base64_dotnet-bot.json"); + + using var bmp = new SKBitmap((int)animation.Size.Width, (int)animation.Size.Height); + bmp.Erase(SKColors.Red); + var beforePixels = bmp.Pixels; + + using var canvas = new SKCanvas(bmp); + animation.Seek(0.1); + animation.Render(canvas, bmp.Info.Rect); + var afterPixels = bmp.Pixels; + + Assert.Equal(beforePixels, afterPixels); + } } } diff --git a/utils/README.md b/utils/README.md index 665466f169..f40d2a413f 100644 --- a/utils/README.md +++ b/utils/README.md @@ -11,10 +11,7 @@ This is a small set of tools that help with generating the p/invoke layer from t This can be run with: ```pwsh -dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/libSkiaSharp.json --skia externals/skia --output binding/SkiaSharp/SkiaApi.generated.cs -dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/libSkiaSharp.Skottie.json --skia externals/skia --output binding/SkiaSharp.Skottie/SkottieApi.generated.cs -dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/libSkiaSharp.SceneGraph.json --skia externals/skia --output binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs -dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/libHarfBuzzSharp.json --skia externals/skia/third_party/externals/harfbuzz --output binding/HarfBuzzSharp/HarfBuzzApi.generated.cs +.\utils\generate.ps1 ``` * `--config binding/libSkiaSharp.json` diff --git a/utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj b/utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj index 4e74a576f7..7b3c5de990 100644 --- a/utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj +++ b/utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj @@ -4,10 +4,16 @@ Exe net6.0 enable + LatestMajor + + + + + $(NETCoreSdkRuntimeIdentifier) - + diff --git a/utils/generate.ps1 b/utils/generate.ps1 new file mode 100644 index 0000000000..f7fc7a2050 --- /dev/null +++ b/utils/generate.ps1 @@ -0,0 +1,5 @@ +dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/libSkiaSharp.json --skia externals/skia --output binding/SkiaSharp/SkiaApi.generated.cs +dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/libSkiaSharp.Skottie.json --skia externals/skia --output binding/SkiaSharp.Skottie/SkottieApi.generated.cs +dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/libSkiaSharp.SceneGraph.json --skia externals/skia --output binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs +dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/libSkiaSharp.Resources.json --skia externals/skia --output binding/SkiaSharp.Resources/ResourcesApi.generated.cs +dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/libHarfBuzzSharp.json --skia externals/skia/third_party/externals/harfbuzz --output binding/HarfBuzzSharp/HarfBuzzApi.generated.cs From 2ae9b944d2846ac55818655cf22fdc4c07a0c348 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Thu, 22 Feb 2024 01:44:45 +0200 Subject: [PATCH 18/40] Fix comment (#2763) --- binding/SkiaSharp/SKObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binding/SkiaSharp/SKObject.cs b/binding/SkiaSharp/SKObject.cs index bcd6635178..4040ffd8c8 100644 --- a/binding/SkiaSharp/SKObject.cs +++ b/binding/SkiaSharp/SKObject.cs @@ -372,7 +372,7 @@ internal interface ISKNonVirtualReferenceCounted : ISKReferenceCounted /// /// This should be implemented on all types that can skip the expensive - // registration in the global dictionary. Typically this would be the case + /// registration in the global dictionary. Typically this would be the case /// if the type os _only_ constructed by the user and not provided as a /// return type for _any_ member. /// From ac5249061db541016e10a7e2b1c3031b74723d8c Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Tue, 27 Feb 2024 22:16:11 +0200 Subject: [PATCH 19/40] Add a build using MSVC (#2769) --- native/windows/build.cake | 5 +- scripts/azure-templates-stages.yml | 45 ++++++++++++++++ scripts/guardian/APIScanSurrogates.in.xml | 63 +++++++++++++++++++++++ 3 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 scripts/guardian/APIScanSurrogates.in.xml diff --git a/native/windows/build.cake b/native/windows/build.cake index afe61fb8d3..db7dfc7ff7 100644 --- a/native/windows/build.cake +++ b/native/windows/build.cake @@ -1,7 +1,8 @@ DirectoryPath ROOT_PATH = MakeAbsolute(Directory("../..")); DirectoryPath OUTPUT_PATH = MakeAbsolute(ROOT_PATH.Combine("output/native")); -DirectoryPath LLVM_HOME = Argument("llvm", EnvironmentVariable("LLVM_HOME") ?? "C:/Program Files/LLVM"); +var llvmHomeArg = Argument("llvm", EnvironmentVariable("LLVM_HOME") ?? "C:/Program Files/LLVM"); +DirectoryPath LLVM_HOME = string.IsNullOrEmpty(llvmHomeArg) || llvmHomeArg.ToLower() == "msvc" ? "" : llvmHomeArg; string VC_TOOLSET_VERSION = Argument("vcToolsetVersion", "14.2"); string SUPPORT_VULKAN_VAR = Argument ("supportVulkan", EnvironmentVariable ("SUPPORT_VULKAN") ?? "true"); @@ -13,7 +14,7 @@ bool SUPPORT_VULKAN = SUPPORT_VULKAN_VAR == "1" || SUPPORT_VULKAN_VAR.ToLower () string VARIANT = BUILD_VARIANT ?? "windows"; Information("Native Arguments:"); -Information($" {"LLVM_HOME".PadRight(30)} {{0}}", LLVM_HOME); +Information($" {"LLVM_HOME".PadRight(30)} {{0}}", string.IsNullOrEmpty(LLVM_HOME.FullPath) ? "(Using MSVC)" : LLVM_HOME); Information($" {"SUPPORT_VULKAN".PadRight(30)} {{0}}", SUPPORT_VULKAN); Information($" {"VARIANT".PadRight(30)} {{0}}", VARIANT); Information($" {"CONFIGURATION".PadRight(30)} {{0}}", CONFIGURATION); diff --git a/scripts/azure-templates-stages.yml b/scripts/azure-templates-stages.yml index 1fe8102085..ff53526a17 100644 --- a/scripts/azure-templates-stages.yml +++ b/scripts/azure-templates-stages.yml @@ -128,6 +128,39 @@ stages: target: externals-windows additionalArgs: --buildarch=arm64 artifactName: native + - template: azure-templates-bootstrapper.yml # Build Native Win32|x86 (Win + MSVC) + parameters: + name: native_win32_x86_msvc_windows + displayName: Win32 x86 [MSVC] + buildExternals: ${{ parameters.buildExternals }} + buildPipelineType: ${{ parameters.buildPipelineType }} + vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + target: externals-windows + additionalArgs: --buildarch=x86 --llvm="msvc" + artifactName: native_msvc + installLlvm: false + - template: azure-templates-bootstrapper.yml # Build Native Win32|x64 (Win + MSVC) + parameters: + name: native_win32_x64_msvc_windows + displayName: Win32 x64 [MSVC] + buildExternals: ${{ parameters.buildExternals }} + buildPipelineType: ${{ parameters.buildPipelineType }} + vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + target: externals-windows + additionalArgs: --buildarch=x64 --llvm="msvc" + artifactName: native_msvc + installLlvm: false + - template: azure-templates-bootstrapper.yml # Build Native Win32|arm64 (Win + MSVC) + parameters: + name: native_win32_arm64_msvc_windows + displayName: Win32 arm64 [MSVC] + buildExternals: ${{ parameters.buildExternals }} + buildPipelineType: ${{ parameters.buildPipelineType }} + vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + target: externals-windows + additionalArgs: --buildarch=arm64 --llvm="msvc" + artifactName: native_msvc + installLlvm: false - template: azure-templates-bootstrapper.yml # Build Native WinUI|x86 (Win) parameters: name: native_winui_x86_windows @@ -886,6 +919,7 @@ stages: scanArtifacts: - nuget - nuget_symbols + - native_msvc antiMalwareEnabled: true binSkimEnabled: false policheckExclusionFile: $(Build.SourcesDirectory)\scripts\guardian\PoliCheckExclusions.xml @@ -900,7 +934,18 @@ stages: apiScanSoftwareName: 'SkiaSharp' apiScanSoftwareVersionNum: $(SKIASHARP_MAJOR_VERSION) apiScanPreserveLogsFolder: true + apiScanSurrogateConfigurationFolder: $(Build.ArtifactStagingDirectory)\APIScanSurrogates preScanSteps: + - pwsh: | + $softwareFolder = "$(Build.ArtifactStagingDirectory)\binaries-to-scan" + $surrogateFile = "$(Build.SourcesDirectory)\scripts\guardian\APIScanSurrogates.in.xml" + $destFolder = "$(Build.ArtifactStagingDirectory)\APIScanSurrogates" + $destFile = "$destFolder\APIScanSurrogates.xml" + New-Item -ItemType Directory -Force -Path $destFolder | Out-Null + $surrogateContents = (Get-Content $surrogateFile) + $surrogateContents = $surrogateContents.Replace("{SOFTWARE_FOLDER}", $softwareFolder) + $surrogateContents | Set-Content $destFile + displayName: Generate the surrogate files - pwsh: | $nupkgs = (Get-ChildItem "$(Build.ArtifactStagingDirectory)\binaries-to-scan\*\*.*nupkg") foreach ($nupkg in $nupkgs) { diff --git a/scripts/guardian/APIScanSurrogates.in.xml b/scripts/guardian/APIScanSurrogates.in.xml new file mode 100644 index 0000000000..f08a175c43 --- /dev/null +++ b/scripts/guardian/APIScanSurrogates.in.xml @@ -0,0 +1,63 @@ + + + + + + + + + {SOFTWARE_FOLDER} + SRV*https://symweb + + + + + + + + + + + + + {SOFTWARE_FOLDER} + SRV*https://symweb + + + + + + + + + + + + + + {SOFTWARE_FOLDER} + SRV*https://symweb + + + + + + + + + + + + + {SOFTWARE_FOLDER} + SRV*https://symweb + + + + + + + + + + \ No newline at end of file From c4d11725328ca80955403c943829faa8ae215753 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Wed, 28 Feb 2024 22:38:00 +0200 Subject: [PATCH 20/40] Migrate to 1ES PT (#2770) --- scripts/azure-pipelines-complete-internal.yml | 69 ++- scripts/azure-pipelines-complete.yml | 52 +- scripts/azure-pipelines-tests.yml | 44 +- scripts/azure-pipelines.yml | 70 ++- scripts/azure-template.yml | 31 ++ scripts/azure-templates-bootstrapper.yml | 205 +++---- .../azure-templates-download-artifacts.yml | 3 +- scripts/azure-templates-linux-matrix.yml | 12 +- scripts/azure-templates-merger.yml | 49 ++ scripts/azure-templates-stages.yml | 525 +++++++++--------- scripts/azure-templates-wasm-matrix.yml | 20 +- 11 files changed, 619 insertions(+), 461 deletions(-) create mode 100644 scripts/azure-template.yml create mode 100644 scripts/azure-templates-merger.yml diff --git a/scripts/azure-pipelines-complete-internal.yml b/scripts/azure-pipelines-complete-internal.yml index 56a0d9b61b..af2d7e5068 100644 --- a/scripts/azure-pipelines-complete-internal.yml +++ b/scripts/azure-pipelines-complete-internal.yml @@ -4,43 +4,52 @@ pr: none parameters: - name: buildExternals - displayName: 'The specific native artifacts to use for this build.' + displayName: 'The Build ID containing the specific native artifacts to use:' type: string default: 'latest' - - name: VM_IMAGE_HOST + - name: buildAgentHost + displayName: 'The generic host build agent configuration:' type: object default: pool: name: Azure Pipelines vmImage: ubuntu-20.04 - - name: VM_IMAGE_WINDOWS + os: windows + - name: buildAgentWindows + displayName: 'The Windows build agent configuration:' type: object default: pool: name: Azure Pipelines vmImage: windows-2022 - - name: VM_IMAGE_MAC + os: windows + - name: buildAgentMac + displayName: 'The macOS build agent configuration:' type: object default: pool: name: Azure Pipelines vmImage: macos-13 - - name: VM_IMAGE_LINUX + os: macos + - name: buildAgentLinux + displayName: 'The Linux build agent configuration:' type: object default: pool: name: Azure Pipelines vmImage: ubuntu-20.04 + os: linux - name: runCompliance + displayName: 'Run post-build compliance tasks (such as API Scan)' + type: boolean + default: false + - name: use1ESPipelineTemplates + displayName: 'Run the build using the internal 1ES Pipeline Templates' type: boolean default: false - -pool: - name: Azure Pipelines - vmImage: ubuntu-20.04 variables: - - template: azure-pipelines-variables.yml + - template: /scripts/azure-pipelines-variables.yml@self resources: repositories: @@ -49,17 +58,31 @@ resources: name: xamarin/yaml-templates endpoint: xamarin ref: refs/heads/main + - repository: 1ESPipelineTemplates + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release -stages: - - template: azure-templates-stages.yml - parameters: - buildPipelineType: 'both' - buildExternals: ${{ parameters.buildExternals }} - runCompliance: ${{ parameters.runCompliance }} - VM_IMAGE_HOST: ${{ parameters.VM_IMAGE_HOST }} - VM_IMAGE_WINDOWS: ${{ parameters.VM_IMAGE_WINDOWS }} - VM_IMAGE_WINDOWS_NATIVE: ${{ parameters.VM_IMAGE_WINDOWS }} - VM_IMAGE_MAC: ${{ parameters.VM_IMAGE_MAC }} - VM_IMAGE_MAC_NATIVE: ${{ parameters.VM_IMAGE_MAC }} - VM_IMAGE_LINUX: ${{ parameters.VM_IMAGE_LINUX }} - VM_IMAGE_LINUX_NATIVE: ${{ parameters.VM_IMAGE_LINUX }} +extends: + ${{ if eq('${{ parameters.use1ESPipelineTemplates }}', 'true') }}: + template: v1/1ES.Unofficial.PipelineTemplate.yml@1ESPipelineTemplates + ${{ if ne('${{ parameters.use1ESPipelineTemplates }}', 'true') }}: + template: /scripts/azure-template.yml@self + parameters: + pool: ${{ parameters.buildAgentHost.pool }} + customBuildTags: + - ES365AIMigrationTooling + stages: + - template: /scripts/azure-templates-stages.yml@self + parameters: + buildPipelineType: 'both' + buildExternals: ${{ parameters.buildExternals }} + runCompliance: ${{ parameters.runCompliance }} + use1ESPipelineTemplates: ${{ parameters.use1ESPipelineTemplates }} + buildAgentHost: ${{ parameters.buildAgentHost }} + buildAgentWindows: ${{ parameters.buildAgentWindows }} + buildAgentWindowsNative: ${{ parameters.buildAgentWindows }} + buildAgentMac: ${{ parameters.buildAgentMac }} + buildAgentMacNative: ${{ parameters.buildAgentMac }} + buildAgentLinux: ${{ parameters.buildAgentLinux }} + buildAgentLinuxNative: ${{ parameters.buildAgentLinux }} \ No newline at end of file diff --git a/scripts/azure-pipelines-complete.yml b/scripts/azure-pipelines-complete.yml index f0c44874d6..f3deca19b0 100644 --- a/scripts/azure-pipelines-complete.yml +++ b/scripts/azure-pipelines-complete.yml @@ -10,50 +10,58 @@ pr: parameters: - name: buildExternals - displayName: 'The specific native artifacts to use for this build.' + displayName: 'The Build ID containing the specific native artifacts to use:' type: string default: 'latest' - - name: VM_IMAGE_HOST + - name: buildAgentHost + displayName: 'The generic host build agent configuration:' type: object default: pool: name: Azure Pipelines vmImage: ubuntu-20.04 - - name: VM_IMAGE_WINDOWS + os: windows + - name: buildAgentWindows + displayName: 'The Windows build agent configuration:' type: object default: pool: name: Azure Pipelines vmImage: windows-2022 - - name: VM_IMAGE_MAC + os: windows + - name: buildAgentMac + displayName: 'The macOS build agent configuration:' type: object default: pool: name: Azure Pipelines vmImage: macos-13 - - name: VM_IMAGE_LINUX + os: macos + - name: buildAgentLinux + displayName: 'The Linux build agent configuration:' type: object default: pool: name: Azure Pipelines vmImage: ubuntu-20.04 - -pool: - name: Azure Pipelines - vmImage: ubuntu-20.04 + os: linux variables: - - template: azure-pipelines-variables.yml + - template: /scripts/azure-pipelines-variables.yml@self -stages: - - template: azure-templates-stages.yml - parameters: - buildPipelineType: 'both' - buildExternals: ${{ parameters.buildExternals }} - VM_IMAGE_HOST: ${{ parameters.VM_IMAGE_HOST }} - VM_IMAGE_WINDOWS: ${{ parameters.VM_IMAGE_WINDOWS }} - VM_IMAGE_WINDOWS_NATIVE: ${{ parameters.VM_IMAGE_WINDOWS }} - VM_IMAGE_MAC: ${{ parameters.VM_IMAGE_MAC }} - VM_IMAGE_MAC_NATIVE: ${{ parameters.VM_IMAGE_MAC }} - VM_IMAGE_LINUX: ${{ parameters.VM_IMAGE_LINUX }} - VM_IMAGE_LINUX_NATIVE: ${{ parameters.VM_IMAGE_LINUX }} +extends: + template: /scripts/azure-template.yml@self + parameters: + pool: ${{ parameters.buildAgentHost.pool }} + stages: + - template: /scripts/azure-templates-stages.yml@self + parameters: + buildPipelineType: 'both' + buildExternals: ${{ parameters.buildExternals }} + buildAgentHost: ${{ parameters.buildAgentHost }} + buildAgentWindows: ${{ parameters.buildAgentWindows }} + buildAgentWindowsNative: ${{ parameters.buildAgentWindows }} + buildAgentMac: ${{ parameters.buildAgentMac }} + buildAgentMacNative: ${{ parameters.buildAgentMac }} + buildAgentLinux: ${{ parameters.buildAgentLinux }} + buildAgentLinuxNative: ${{ parameters.buildAgentLinux }} diff --git a/scripts/azure-pipelines-tests.yml b/scripts/azure-pipelines-tests.yml index 1127a2e8cb..f7dc37e227 100644 --- a/scripts/azure-pipelines-tests.yml +++ b/scripts/azure-pipelines-tests.yml @@ -3,33 +3,41 @@ trigger: none pr: none parameters: - - name: VM_IMAGE_HOST + - name: buildAgentHost + displayName: 'The generic host build agent configuration:' type: object default: pool: name: Azure Pipelines vmImage: ubuntu-20.04 - - name: VM_IMAGE_WINDOWS + os: windows + - name: buildAgentWindows + displayName: 'The Windows build agent configuration:' type: object default: pool: name: Azure Pipelines vmImage: windows-2022 - - name: VM_IMAGE_MAC + os: windows + - name: buildAgentMac + displayName: 'The macOS build agent configuration:' type: object default: pool: name: Azure Pipelines vmImage: macos-13 - - name: VM_IMAGE_LINUX + os: macos + - name: buildAgentLinux + displayName: 'The Linux build agent configuration:' type: object default: pool: name: Azure Pipelines vmImage: ubuntu-20.04 + os: linux variables: - - template: azure-pipelines-variables.yml + - template: /scripts/azure-pipelines-variables.yml@self resources: repositories: @@ -43,14 +51,18 @@ resources: source: SkiaSharp trigger: true -stages: - - template: azure-templates-stages.yml - parameters: - buildPipelineType: 'tests' - VM_IMAGE_HOST: ${{ parameters.VM_IMAGE_HOST }} - VM_IMAGE_WINDOWS: ${{ parameters.VM_IMAGE_WINDOWS }} - VM_IMAGE_WINDOWS_NATIVE: ${{ parameters.VM_IMAGE_WINDOWS }} - VM_IMAGE_MAC: ${{ parameters.VM_IMAGE_MAC }} - VM_IMAGE_MAC_NATIVE: ${{ parameters.VM_IMAGE_MAC }} - VM_IMAGE_LINUX: ${{ parameters.VM_IMAGE_LINUX }} - VM_IMAGE_LINUX_NATIVE: ${{ parameters.VM_IMAGE_LINUX }} +extends: + template: /scripts/azure-template.yml@self + parameters: + pool: ${{ parameters.buildAgentHost.pool }} + stages: + - template: /scripts/azure-templates-stages.yml@self + parameters: + buildPipelineType: 'tests' + buildAgentHost: ${{ parameters.buildAgentHost }} + buildAgentWindows: ${{ parameters.buildAgentWindows }} + buildAgentWindowsNative: ${{ parameters.buildAgentWindows }} + buildAgentMac: ${{ parameters.buildAgentMac }} + buildAgentMacNative: ${{ parameters.buildAgentMac }} + buildAgentLinux: ${{ parameters.buildAgentLinux }} + buildAgentLinuxNative: ${{ parameters.buildAgentLinux }} \ No newline at end of file diff --git a/scripts/azure-pipelines.yml b/scripts/azure-pipelines.yml index 0575203ec3..cb554e1e60 100644 --- a/scripts/azure-pipelines.yml +++ b/scripts/azure-pipelines.yml @@ -10,39 +10,48 @@ pr: parameters: - name: buildExternals - displayName: 'The specific native artifacts to use for this build.' + displayName: 'The Build ID containing the specific native artifacts to use:' type: string default: 'latest' - - name: VM_IMAGE_HOST + - name: buildAgentHost + displayName: 'The generic host build agent configuration:' type: object default: pool: - name: Azure Pipelines - vmImage: ubuntu-20.04 - - name: VM_IMAGE_WINDOWS + name: AzurePipelines-EO + image: 1ESPT-Windows2022 + os: windows + - name: buildAgentWindows + displayName: 'The Windows build agent configuration:' type: object default: pool: - name: Azure Pipelines - vmImage: windows-2022 - - name: VM_IMAGE_MAC + name: AzurePipelines-EO + image: 1ESPT-Windows2022 + os: windows + - name: buildAgentMac + displayName: 'The macOS build agent configuration:' type: object default: pool: name: Azure Pipelines vmImage: macos-13 - - name: VM_IMAGE_LINUX + os: macos + - name: buildAgentLinux + displayName: 'The Linuk build agent configuration:' type: object default: pool: - name: Azure Pipelines - vmImage: ubuntu-20.04 + name: AzurePipelines-EO + image: 1ESPT-Ubuntu20.04 + os: linux - name: runCompliance + displayName: 'Run post-build compliance tasks (such as API Scan)' type: boolean default: false variables: - - template: azure-pipelines-variables.yml + - template: /scripts/azure-pipelines-variables.yml@self resources: repositories: @@ -51,17 +60,28 @@ resources: name: xamarin/yaml-templates endpoint: xamarin ref: refs/heads/main + - repository: 1ESPipelineTemplates + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release -stages: - - template: azure-templates-stages.yml - parameters: - buildPipelineType: 'build' - buildExternals: ${{ parameters.buildExternals }} - runCompliance: ${{ parameters.runCompliance }} - VM_IMAGE_HOST: ${{ parameters.VM_IMAGE_HOST }} - VM_IMAGE_WINDOWS: ${{ parameters.VM_IMAGE_WINDOWS }} - VM_IMAGE_WINDOWS_NATIVE: ${{ parameters.VM_IMAGE_WINDOWS }} - VM_IMAGE_MAC: ${{ parameters.VM_IMAGE_MAC }} - VM_IMAGE_MAC_NATIVE: ${{ parameters.VM_IMAGE_MAC }} - VM_IMAGE_LINUX: ${{ parameters.VM_IMAGE_LINUX }} - VM_IMAGE_LINUX_NATIVE: ${{ parameters.VM_IMAGE_LINUX }} +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates + parameters: + pool: ${{ parameters.buildAgentHost.pool }} + customBuildTags: + - ES365AIMigrationTooling + stages: + - template: /scripts/azure-templates-stages.yml@self + parameters: + buildPipelineType: 'build' + buildExternals: ${{ parameters.buildExternals }} + runCompliance: ${{ parameters.runCompliance }} + use1ESPipelineTemplates: true + buildAgentHost: ${{ parameters.buildAgentHost }} + buildAgentWindows: ${{ parameters.buildAgentWindows }} + buildAgentWindowsNative: ${{ parameters.buildAgentWindows }} + buildAgentMac: ${{ parameters.buildAgentMac }} + buildAgentMacNative: ${{ parameters.buildAgentMac }} + buildAgentLinux: ${{ parameters.buildAgentLinux }} + buildAgentLinuxNative: ${{ parameters.buildAgentLinux }} \ No newline at end of file diff --git a/scripts/azure-template.yml b/scripts/azure-template.yml new file mode 100644 index 0000000000..e7c203aa64 --- /dev/null +++ b/scripts/azure-template.yml @@ -0,0 +1,31 @@ +parameters: + - name: stages + type: stageList + default: [] + - name: pool + type: object + default: {} + - name: customBuildTags + type: object + default: null + +stages: + - ${{ each stage in parameters.stages }}: + - ${{ each stageProperty in stage }}: + ${{ if notIn(stageProperty.key, 'jobs', 'pool') }}: + ${{ stageProperty.key }}: ${{ stageProperty.value }} + pool: ${{ parameters.pool }} + jobs: + - ${{ each job in stage.jobs }}: + - ${{ each jobProperty in job }}: + ${{ if notIn(jobProperty.key, 'steps', 'templateContext') }}: + ${{ jobProperty.key }}: ${{ jobProperty.value }} + steps: + - ${{ job.steps }} + - ${{ each output in job.templateContext.outputs }}: + - task: PublishPipelineArtifact@1 + displayName: ${{ output.displayName }} + condition: ${{ coalesce(output.condition, 'succeeded()') }} + inputs: + artifactName: ${{ output.artifactName }} + targetPath: ${{ output.targetPath }} \ No newline at end of file diff --git a/scripts/azure-templates-bootstrapper.yml b/scripts/azure-templates-bootstrapper.yml index 8e43dce46a..a1ef372135 100644 --- a/scripts/azure-templates-bootstrapper.yml +++ b/scripts/azure-templates-bootstrapper.yml @@ -1,7 +1,7 @@ parameters: name: '' # in the form type_platform_host displayName: '' # the human name - vmImage: '' # the VM image + buildAgent: '' # the configuration for the build agent packages: '' # any additional packages target: '' # the bootstrapper target dependsOn: [] # the dependiencies @@ -31,25 +31,55 @@ parameters: installEmsdk: false # whether or not to install the Emscripten SDK installNinja: false # whether or not to install the ninja build system artifactName: '' # the name of the artifact to merge this run into + publishArtifacts: [] # the additional artifacts to publish tools: [] # any additional .net global tools + skipInstall: false # whether or not to install any tools + skipSteps: false # whether or not to run any steps + use1ESPipelineTemplates: false # whether or not we are building using the internal 1ES Pipeline Templates jobs: - job: ${{ parameters.name }} displayName: ${{ parameters.displayName }} timeoutInMinutes: 180 - pool: ${{ parameters.vmImage.pool }} + pool: ${{ parameters.buildAgent.pool }} dependsOn: ${{ parameters.dependsOn }} condition: ${{ parameters.condition }} variables: - ${{ if ne(parameters.vmImage.variables, '') }}: - ${{ parameters.vmImage.variables }} + ${{ if ne(parameters.buildAgent.variables, '') }}: + ${{ parameters.buildAgent.variables }} ${{ if ne(length(parameters.variables), 0) }}: ${{ parameters.variables }} + templateContext: + sdl: + spotBugs: + enabled: false + binskim: + break: false + outputParentDirectory: 'output' + outputs: + - output: pipelineArtifact + displayName: 'Publish the ${{ parameters.name }} artifacts' + condition: or(${{ parameters.shouldPublish }}, failed()) + artifactName: ${{ parameters.name }} + targetPath: 'output' + - ${{ if ne(parameters.artifactName, '') }}: + - output: pipelineArtifact + displayName: 'Publish the combined ${{ parameters.artifactName }} artifacts' + artifactName: ${{ parameters.artifactName }} + targetPath: 'output' + - ${{ each additionalArtifact in parameters.publishArtifacts }}: + - output: pipelineArtifact + displayName: 'Publish the ${{ additionalArtifact.name }} artifacts' + ${{ if eq(additionalArtifact.always, 'true') }}: + condition: always() + artifactName: ${{ additionalArtifact.name }} + targetPath: ${{ additionalArtifact.path }} + steps: # prepare - checkout: self submodules: recursive - - template: azure-templates-variables.yml + - template: /scripts/azure-templates-variables.yml@self # checkout required skia PR - pwsh: .\scripts\checkout-skia.ps1 -GitHubToken $(GitHub.Token.PublicAccess) @@ -57,7 +87,7 @@ jobs: condition: eq(variables['Build.Reason'], 'PullRequest') - ${{ if eq(parameters.buildPipelineType, 'tests') }}: - - template: azure-templates-github-status.yml + - template: /scripts/azure-templates-github-status.yml@self parameters: state: 'pending' @@ -66,13 +96,13 @@ jobs: displayName: Determine build type # provisioning steps - - ${{ if ne(parameters.vmImage.provisioningSteps, '') }}: - - ${{ parameters.vmImage.provisioningSteps }} + - ${{ if ne(parameters.buildAgent.provisioningSteps, '') }}: + - ${{ parameters.buildAgent.provisioningSteps }} - ${{ if ne(length(parameters.provisioningSteps), 0) }}: - ${{ parameters.provisioningSteps }} # install any packages on linux - - ${{ if and(eq(parameters.docker, ''), endsWith(parameters.name, '_linux')) }}: + - ${{ if and(eq(parameters.docker, ''), endsWith(parameters.name, '_linux'), ne(parameters.skipInstall, 'true')) }}: - bash: | sudo apt update sudo apt install -y ${{ parameters.packages }} @@ -81,7 +111,7 @@ jobs: condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], ''), ne('${{ parameters.packages }}', '')) # install extra bits for the native builds - - ${{ if startsWith(parameters.name, 'native_') }}: + - ${{ if and(startsWith(parameters.name, 'native_'), ne(parameters.skipInstall, 'true')) }}: # switch to the correct Python version - task: UsePythonVersion@0 displayName: Switch to the correct Python version @@ -120,7 +150,7 @@ jobs: condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) # install extra bits for the managed builds - - ${{ if not(startsWith(parameters.name, 'native_')) }}: + - ${{ if and(not(startsWith(parameters.name, 'native_')), ne(parameters.skipInstall, 'true')) }}: # install ninja - ${{ if eq(parameters.installNinja, 'true') }}: - pwsh: .\scripts\install-ninja.ps1 @@ -201,7 +231,7 @@ jobs: displayName: Install the .NET workloads # install the mac tools - - ${{ if endsWith(parameters.name, '_macos') }}: + - ${{ if and(endsWith(parameters.name, '_macos'), ne(parameters.skipInstall, 'true')) }}: - ${{ if not(startsWith(parameters.name, 'native_')) }}: - bash: sudo ./scripts/select-xcode.sh $(XCODE_VERSION) displayName: Switch to the latest Xcode @@ -212,14 +242,14 @@ jobs: condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) # install the linux tools - - ${{ if and(eq(parameters.installEmsdk, 'true'), endsWith(parameters.name, '_linux')) }}: + - ${{ if and(eq(parameters.installEmsdk, 'true'), endsWith(parameters.name, '_linux'), ne(parameters.skipInstall, 'true')) }}: - bash: ./scripts/install-emsdk.sh $(EMSCRIPTEN_VERSION) displayName: Install the Emscripten SDK retryCountOnTaskFailure: 3 condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) # install the Windows tools - - ${{ if endsWith(parameters.name, '_windows') }}: + - ${{ if and(endsWith(parameters.name, '_windows'), ne(parameters.skipInstall, 'true')) }}: # select the correct/latest version of Visual Studio - pwsh: .\scripts\select-vs.ps1 displayName: Select Visual Studio @@ -245,18 +275,19 @@ jobs: condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) # install any .NET global tools - - ${{ each tool in parameters.tools }}: - - pwsh: dotnet tool install -g ${{ tool }} - displayName: Install ${{ tool }} - retryCountOnTaskFailure: 3 - condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) + - ${{ if ne(parameters.skipInstall, 'true') }}: + - ${{ each tool in parameters.tools }}: + - pwsh: dotnet tool install -g ${{ tool }} + displayName: Install ${{ tool }} + retryCountOnTaskFailure: 3 + condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) # download artifacts - - template: azure-templates-download-artifacts.yml + - template: /scripts/azure-templates-download-artifacts.yml@self parameters: condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) artifacts: ${{ parameters.requiredArtifacts }} - - template: azure-templates-download-artifacts.yml + - template: /scripts/azure-templates-download-artifacts.yml@self parameters: condition: and(succeeded(), ne(variables['DOWNLOAD_EXTERNALS'], '')) sourceBuildId: $(DOWNLOAD_EXTERNALS) @@ -264,88 +295,76 @@ jobs: - name: ${{ parameters.name }} # pre-build steps - - ${{ if ne(parameters.vmImage.preBuildSteps, '') }}: - - ${{ parameters.vmImage.preBuildSteps }} + - ${{ if ne(parameters.buildAgent.preBuildSteps, '') }}: + - ${{ parameters.buildAgent.preBuildSteps }} - ${{ if ne(length(parameters.preBuildSteps), 0) }}: - ${{ parameters.preBuildSteps }} - # build - - ${{ if eq(parameters.docker, '') }}: - - ${{ if endsWith(parameters.name, '_windows') }}: - - pwsh: | - Get-Content $PSCommandPath - dotnet tool restore - ${{ parameters.initScript }} - dotnet cake --target=${{ parameters.target }} --verbosity=${{ parameters.verbosity }} --configuration=${{ coalesce(parameters.configuration, 'Release') }} ${{ parameters.additionalArgs }} + # actual build + - ${{ if ne(parameters.skipSteps, 'true') }}: + - ${{ if eq(parameters.docker, '') }}: + - ${{ if endsWith(parameters.name, '_windows') }}: + - pwsh: | + Get-Content $PSCommandPath + dotnet tool restore + ${{ parameters.initScript }} + dotnet cake --target=${{ parameters.target }} --verbosity=${{ parameters.verbosity }} --configuration=${{ coalesce(parameters.configuration, 'Release') }} ${{ parameters.additionalArgs }} - env: - JavaSdkDirectory: $(JAVA_HOME) - LLVM_HOME: $(LLVM_HOME) - # There seems to be a bug in some verions of mspdbcmf.exe. This looks to be fixed in a VS preview. - AppxSymbolPackageEnabled: false - displayName: Run the bootstrapper for ${{ parameters.target }} - retryCountOnTaskFailure: ${{ parameters.retryCount }} + env: + JavaSdkDirectory: $(JAVA_HOME) + LLVM_HOME: $(LLVM_HOME) + # There seems to be a bug in some verions of mspdbcmf.exe. This looks to be fixed in a VS preview. + AppxSymbolPackageEnabled: false + displayName: Run the bootstrapper for ${{ parameters.target }} + retryCountOnTaskFailure: ${{ parameters.retryCount }} + condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) + - ${{ if not(endsWith(parameters.name, '_windows')) }}: + - bash: | + cat ${BASH_SOURCE[0]} + dotnet tool restore + ${{ parameters.initScript }} + dotnet cake --target=${{ parameters.target }} --verbosity=${{ parameters.verbosity }} --configuration=${{ coalesce(parameters.configuration, 'Release') }} ${{ parameters.additionalArgs }} + + env: + JavaSdkDirectory: $(JAVA_HOME) + displayName: Run the bootstrapper for ${{ parameters.target }} + retryCountOnTaskFailure: ${{ parameters.retryCount }} + condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) + - ${{ if ne(parameters.docker, '') }}: + - ${{ if eq(parameters.use1ESPipelineTemplates, 'true') }}: + - task: 1ES.BuildContainerImage@1 + displayName: Build the Docker image for ${{ parameters.docker }} + condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) + inputs: + dockerfile: ${{ parameters.docker }}/Dockerfile + context: ${{ parameters.docker }} + image: skiasharp:skiasharp + buildArguments: --tag skiasharp ${{ parameters.dockerArgs }} + enableNetwork: true + - ${{ if ne(parameters.use1ESPipelineTemplates, 'true') }}: + - task: Docker@2 + displayName: Build the Docker image for ${{ parameters.docker }} + condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) + inputs: + command: build + buildContext: ${{ parameters.docker }} + dockerfile: ${{ parameters.docker }}/Dockerfile + arguments: --tag skiasharp ${{ parameters.dockerArgs }} + - bash: | + echo dotnet tool restore > cmd.sh + echo dotnet cake --target=${{ parameters.target }} --verbosity=${{ parameters.verbosity }} --configuration=${{ coalesce(parameters.configuration, 'Release') }} ${{ parameters.additionalArgs }} >> cmd.sh + sed -i 's/--gnArgs=\" \"//' cmd.sh + cat cmd.sh + displayName: Generate the script for the Docker image condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) - - ${{ if not(endsWith(parameters.name, '_windows')) }}: - bash: | - cat ${BASH_SOURCE[0]} - dotnet tool restore - ${{ parameters.initScript }} - dotnet cake --target=${{ parameters.target }} --verbosity=${{ parameters.verbosity }} --configuration=${{ coalesce(parameters.configuration, 'Release') }} ${{ parameters.additionalArgs }} - - env: - JavaSdkDirectory: $(JAVA_HOME) - displayName: Run the bootstrapper for ${{ parameters.target }} + docker run --rm --name skiasharp --volume $(pwd):/work skiasharp /bin/bash /work/cmd.sh + displayName: Run the bootstrapper for ${{ parameters.target }} using the Docker image retryCountOnTaskFailure: ${{ parameters.retryCount }} condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) - - ${{ if ne(parameters.docker, '') }}: - - task: Docker@2 - displayName: Build the Docker image for ${{ parameters.docker }} - condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) - inputs: - command: build - buildContext: ${{ parameters.docker }} - dockerfile: ${{ parameters.docker }}/Dockerfile - arguments: --tag skiasharp ${{ parameters.dockerArgs }} - - bash: | - echo dotnet tool restore > cmd.sh - echo dotnet cake --target=${{ parameters.target }} --verbosity=${{ parameters.verbosity }} --configuration=${{ coalesce(parameters.configuration, 'Release') }} ${{ parameters.additionalArgs }} >> cmd.sh - sed -i 's/--gnArgs=\" \"//' cmd.sh - cat cmd.sh - displayName: Generate the script for the Docker image - condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) - - bash: | - docker run --rm --name skiasharp --volume $(pwd):/work skiasharp /bin/bash /work/cmd.sh - displayName: Run the bootstrapper for ${{ parameters.target }} using the Docker image - retryCountOnTaskFailure: ${{ parameters.retryCount }} - condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) # post-build steps - ${{ parameters.postBuildSteps }} - # publish artifacts - - task: PublishBuildArtifacts@1 - displayName: Publish the ${{ parameters.name }} artifacts - condition: or(${{ parameters.shouldPublish }}, failed()) - retryCountOnTaskFailure: 3 - inputs: - artifactName: ${{ parameters.name }} - pathToPublish: 'output' - - ${{ if ne(parameters.artifactName, '') }}: - - task: PublishBuildArtifacts@1 - displayName: Publish the combined ${{ parameters.artifactName }} artifacts - retryCountOnTaskFailure: 3 - inputs: - artifactName: ${{ parameters.artifactName }} - pathToPublish: 'output' - - ${{ if and(eq(variables['System.TeamProject'], 'devdiv'), ne(parameters.buildPipelineType, 'tests'), ne(variables['System.PullRequest.IsFork'], 'true'), or(and(eq(variables['Build.Reason'], 'Schedule'), or(eq(variables['Build.SourceBranch'], 'refs/heads/main'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'))), parameters.runCompliance)) }}: - - task: ComponentGovernanceComponentDetection@0 - displayName: Run component detection - condition: always() - inputs: - scanType: 'Register' - verbosity: 'Verbose' - alertWarningLevel: 'High' - - ${{ if eq(parameters.buildPipelineType, 'tests') }}: - - template: azure-templates-github-status.yml + - template: /scripts/azure-templates-github-status.yml@self diff --git a/scripts/azure-templates-download-artifacts.yml b/scripts/azure-templates-download-artifacts.yml index db94dadcbe..2300409591 100644 --- a/scripts/azure-templates-download-artifacts.yml +++ b/scripts/azure-templates-download-artifacts.yml @@ -54,9 +54,10 @@ steps: downloadType: 'single' allowPartiallySucceededBuilds: true artifactName: ${{ artifact.name }} - downloadPath: 'download-temp' + downloadPath: 'download-temp/${{ artifact.name }}' - pwsh: | + Get-ChildItem '.\download-temp\' New-Item '.\output\${{ artifact.dir }}\' -Type Directory -Force | Out-Null Get-ChildItem '.\download-temp\${{ artifact.name }}\' | Copy-Item -Destination '.\output\${{ artifact.dir }}\' -Recurse -Force Remove-Item '.\download-temp\${{ artifact.name }}\' -Recurse -Force diff --git a/scripts/azure-templates-linux-matrix.yml b/scripts/azure-templates-linux-matrix.yml index 6bad3fbbd1..980d3e4be5 100644 --- a/scripts/azure-templates-linux-matrix.yml +++ b/scripts/azure-templates-linux-matrix.yml @@ -1,8 +1,8 @@ parameters: - artifactName: '' # the name of the artifact to merge this run into buildExternals: '' # the build number to download externals from buildPipelineType: 'both' # the type of build pipeline setup - vmImage: '' # the VM image + buildAgent: '' # the configuration for the build agent + use1ESPipelineTemplates: false # whether or not we are building using the internal 1ES Pipeline Templates builds: - name: '' desc: '' @@ -20,15 +20,15 @@ parameters: jobs: - ${{ each build in parameters.builds }}: - ${{ each item in parameters.matrix }}: - - template: azure-templates-bootstrapper.yml + - template: /scripts/azure-templates-bootstrapper.yml@self parameters: name: ${{ replace(replace(format('native_linux_{0}_{1}_{2}_{3}_linux', item.arch, item.variant, build.name, item.alt), '__', '_'), '__', '_') }} displayName: Linux ${{ replace(replace(replace(replace(replace(format('({0}|{1}|{2}|{3})', item.arch, item.variant, build.name, item.alt), '||', '|'), '||', '|'), '(|', '('), '|)', ')'), '|', ', ') }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.vmImage }} + buildAgent: ${{ parameters.buildAgent }} + use1ESPipelineTemplates: ${{ parameters.use1ESPipelineTemplates }} docker: ${{ item.docker }} dockerArgs: ${{ item.dockerArgs }} target: ${{ coalesce(item.target, 'externals-linux') }} - additionalArgs: --buildarch=${{ item.arch }} --variant=${{ coalesce(item.variant, 'linux') }}${{ build.name }} --gnArgs="\"${{ build.gnArgs }} ${{ item.gnArgs }}\"" ${{ build.additionalArgs }} ${{ item.additionalArgs }} - artifactName: ${{ parameters.artifactName }} + additionalArgs: --buildarch=${{ item.arch }} --variant=${{ coalesce(item.variant, 'linux') }}${{ build.name }} --gnArgs="\"${{ build.gnArgs }} ${{ item.gnArgs }}\"" ${{ build.additionalArgs }} ${{ item.additionalArgs }} \ No newline at end of file diff --git a/scripts/azure-templates-merger.yml b/scripts/azure-templates-merger.yml new file mode 100644 index 0000000000..0e2858571d --- /dev/null +++ b/scripts/azure-templates-merger.yml @@ -0,0 +1,49 @@ +parameters: + name: '' # in the form type_platform_host + displayName: '' # the human name + buildAgent: '' # the configuration for the build agent + buildPipelineType: 'both' # the type of build pipeline setup + requiredArtifacts: [] # the artifacts that this build needs to download + matrixArtifacts: [] # the artifacts that this build needs to download + +jobs: + - template: /scripts/azure-templates-bootstrapper.yml@self + parameters: + name: ${{ parameters.name }} + displayName: ${{ parameters.displayName }} + buildPipelineType: ${{ parameters.buildPipelineType }} + buildAgent: ${{ parameters.buildAgent }} + skipInstall: true + skipSteps: true + requiredArtifacts: ${{ parameters.requiredArtifacts }} + preBuildSteps: + - pwsh: az devops configure --defaults organization=$(System.TeamFoundationCollectionUri) project=$(System.TeamProject) --use-git-aliases true + displayName: Configure the az CLI tool + - ${{ each artifact in parameters.matrixArtifacts }}: + - pwsh: | + $artifactJson=@' + ${{ artifact.jobs }} + '@ + + echo $artifactJson + + $json = ConvertFrom-Json $artifactJson + $objects = $json | Get-Member -MemberType NoteProperty + $names = $objects | ForEach-Object { $json."$($_.Name)".name } + + Write-Host "Found $($names.Length) items:" + $names | ForEach-Object { Write-Host " - $_" } + + $dir = "$(Build.SourcesDirectory)/output" + New-Item "$dir" -Type Directory -Force | Out-Null + + $id = "$(Build.BuildId)" + foreach ($name in $names) { + Write-Host "Downloading '$name'..." + az pipelines runs artifact download --artifact-name "$name" --path "$dir" --run-id "$id" --verbose + } + Write-Host "Downloads complete." + Get-ChildItem "$dir" + env: + AZURE_DEVOPS_EXT_PAT: $(System.AccessToken) + displayName: Download the pre-built ${{ artifact.name }} artifacts diff --git a/scripts/azure-templates-stages.yml b/scripts/azure-templates-stages.yml index ff53526a17..d782a44af0 100644 --- a/scripts/azure-templates-stages.yml +++ b/scripts/azure-templates-stages.yml @@ -5,23 +5,26 @@ parameters: - name: buildExternals type: string default: 'latest' - - name: VM_IMAGE_HOST + - name: buildAgentHost type: object - - name: VM_IMAGE_WINDOWS + - name: buildAgentWindows type: object - - name: VM_IMAGE_WINDOWS_NATIVE + - name: buildAgentWindowsNative type: object - - name: VM_IMAGE_MAC + - name: buildAgentMac type: object - - name: VM_IMAGE_MAC_NATIVE + - name: buildAgentMacNative type: object - - name: VM_IMAGE_LINUX + - name: buildAgentLinux type: object - - name: VM_IMAGE_LINUX_NATIVE + - name: buildAgentLinuxNative type: object - name: runCompliance type: boolean default: false + - name: use1ESPipelineTemplates + type: boolean + default: false stages: - stage: prepare @@ -29,263 +32,244 @@ stages: jobs: - job: prepare # Prepare Build displayName: Prepare Build - pool: ${{ parameters.VM_IMAGE_HOST.pool }} + pool: ${{ parameters.buildAgentHost.pool }} steps: - checkout: none - - template: azure-templates-variables.yml + - template: /scripts/azure-templates-variables.yml@self parameters: updateBuild: true - ${{ if eq(parameters.buildPipelineType, 'build') }}: - - template: azure-templates-github-status.yml + - template: /scripts/azure-templates-github-status.yml@self parameters: context: 'SkiaSharp-Tests' state: 'pending' displayName: Queue up the status for the tests pipeline - ${{ if eq(parameters.buildPipelineType, 'tests') }}: - - template: azure-templates-github-status.yml + - template: /scripts/azure-templates-github-status.yml@self - ${{ if ne(parameters.buildPipelineType, 'tests') }}: - stage: native_windows displayName: Native Windows dependsOn: prepare jobs: - - template: azure-templates-bootstrapper.yml # Build Native Android|x86 (Win) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Android|x86 (Win) parameters: name: native_android_x86_windows displayName: Android x86 buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-android additionalArgs: --buildarch=x86 - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native Android|x64 (Win) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Android|x64 (Win) parameters: name: native_android_x64_windows displayName: Android x64 buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-android additionalArgs: --buildarch=x64 - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native Android|arm (Win) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Android|arm (Win) parameters: name: native_android_arm_windows displayName: Android arm buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-android additionalArgs: --buildarch=arm - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native Android|arm64 (Win) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Android|arm64 (Win) parameters: name: native_android_arm64_windows displayName: Android arm64 buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-android additionalArgs: --buildarch=arm64 - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native Tizen (Win) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Tizen (Win) parameters: name: native_tizen_windows displayName: Tizen buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-tizen - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native Win32|x86 (Win) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Win32|x86 (Win) parameters: name: native_win32_x86_windows displayName: Win32 x86 buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-windows additionalArgs: --buildarch=x86 - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native Win32|x64 (Win) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Win32|x64 (Win) parameters: name: native_win32_x64_windows displayName: Win32 x64 buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-windows additionalArgs: --buildarch=x64 - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native Win32|arm64 (Win) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Win32|arm64 (Win) parameters: name: native_win32_arm64_windows displayName: Win32 arm64 buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-windows additionalArgs: --buildarch=arm64 - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native Win32|x86 (Win + MSVC) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Win32|x86 (Win + MSVC) parameters: name: native_win32_x86_msvc_windows displayName: Win32 x86 [MSVC] buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-windows additionalArgs: --buildarch=x86 --llvm="msvc" - artifactName: native_msvc installLlvm: false - - template: azure-templates-bootstrapper.yml # Build Native Win32|x64 (Win + MSVC) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Win32|x64 (Win + MSVC) parameters: name: native_win32_x64_msvc_windows displayName: Win32 x64 [MSVC] buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-windows additionalArgs: --buildarch=x64 --llvm="msvc" - artifactName: native_msvc installLlvm: false - - template: azure-templates-bootstrapper.yml # Build Native Win32|arm64 (Win + MSVC) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Win32|arm64 (Win + MSVC) parameters: name: native_win32_arm64_msvc_windows displayName: Win32 arm64 [MSVC] buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-windows additionalArgs: --buildarch=arm64 --llvm="msvc" - artifactName: native_msvc installLlvm: false - - template: azure-templates-bootstrapper.yml # Build Native WinUI|x86 (Win) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native WinUI|x86 (Win) parameters: name: native_winui_x86_windows displayName: WinUI x86 buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-winui additionalArgs: --buildarch=x86 - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native WinUI|x64 (Win) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native WinUI|x64 (Win) parameters: name: native_winui_x64_windows displayName: WinUI x64 buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-winui additionalArgs: --buildarch=x64 - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native WinUI|arm64 (Win) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native WinUI|arm64 (Win) parameters: name: native_winui_arm64_windows displayName: WinUI arm64 buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-winui additionalArgs: --buildarch=arm64 - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native NanoServer|x64 (Win) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native NanoServer|x64 (Win) parameters: name: native_win32_x64_nanoserver_windows displayName: Nano Server x64 buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS_NATIVE }} + buildAgent: ${{ parameters.buildAgentWindowsNative }} target: externals-nanoserver additionalArgs: --buildarch=x64 - artifactName: native - ${{ if ne(parameters.buildPipelineType, 'tests') }}: - stage: native_macos displayName: Native macOS dependsOn: prepare jobs: - - template: azure-templates-bootstrapper.yml # Build Native Android|x86 (macOS) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Android|x86 (macOS) parameters: name: native_android_x86_macos displayName: Android x86 buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC_NATIVE }} + buildAgent: ${{ parameters.buildAgentMacNative }} target: externals-android additionalArgs: --buildarch=x86 - - template: azure-templates-bootstrapper.yml # Build Native Android|x64 (macOS) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Android|x64 (macOS) parameters: name: native_android_x64_macos displayName: Android x64 buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC_NATIVE }} + buildAgent: ${{ parameters.buildAgentMacNative }} target: externals-android additionalArgs: --buildarch=x64 - - template: azure-templates-bootstrapper.yml # Build Native Android|arm (macOS) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Android|arm (macOS) parameters: name: native_android_arm_macos displayName: Android arm buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC_NATIVE }} + buildAgent: ${{ parameters.buildAgentMacNative }} target: externals-android additionalArgs: --buildarch=arm - - template: azure-templates-bootstrapper.yml # Build Native Android|arm64 (macOS) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Android|arm64 (macOS) parameters: name: native_android_arm64_macos displayName: Android arm64 buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC_NATIVE }} + buildAgent: ${{ parameters.buildAgentMacNative }} target: externals-android additionalArgs: --buildarch=arm64 - - template: azure-templates-bootstrapper.yml # Build Native iOS (macOS) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native iOS (macOS) parameters: name: native_ios_macos displayName: iOS buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC_NATIVE }} + buildAgent: ${{ parameters.buildAgentMacNative }} target: externals-ios - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native Mac Catalyst (macOS) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Mac Catalyst (macOS) parameters: name: native_maccatalyst_macos displayName: Mac Catalyst buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC_NATIVE }} + buildAgent: ${{ parameters.buildAgentMacNative }} target: externals-maccatalyst - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native macOS (macOS) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native macOS (macOS) parameters: name: native_macos_macos displayName: macOS buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC_NATIVE }} + buildAgent: ${{ parameters.buildAgentMacNative }} target: externals-macos - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native tvOS (macOS) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native tvOS (macOS) parameters: name: native_tvos_macos displayName: tvOS buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC_NATIVE }} + buildAgent: ${{ parameters.buildAgentMacNative }} target: externals-tvos - artifactName: native - - template: azure-templates-bootstrapper.yml # Build Native Tizen (macOS) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Tizen (macOS) parameters: name: native_tizen_macos displayName: Tizen buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC_NATIVE }} + buildAgent: ${{ parameters.buildAgentMacNative }} target: externals-tizen - ${{ if ne(parameters.buildPipelineType, 'tests') }}: @@ -293,12 +277,12 @@ stages: displayName: Native Linux dependsOn: prepare jobs: - - template: azure-templates-linux-matrix.yml # Build Native Linux (Linux) + - template: /scripts/azure-templates-linux-matrix.yml@self # Build Native Linux (Linux) parameters: - artifactName: native buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_LINUX_NATIVE }} + buildAgent: ${{ parameters.buildAgentLinuxNative }} + use1ESPipelineTemplates: ${{ parameters.use1ESPipelineTemplates }} builds: - name: '' - name: nodeps @@ -318,13 +302,13 @@ stages: docker: scripts/Docker/debian9/clang-cross dockerArgs: --build-arg TOOLCHAIN_ARCH=aarch64-linux-gnu --build-arg TOOLCHAIN_ARCH_SHORT=arm64 target: externals-linux-clang-cross - - template: azure-templates-bootstrapper.yml # Build Native Tizen (Linux) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Native Tizen (Linux) parameters: name: native_tizen_linux displayName: Tizen buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_LINUX_NATIVE }} + buildAgent: ${{ parameters.buildAgentLinuxNative }} packages: $(TIZEN_LINUX_PACKAGES) target: externals-tizen @@ -333,12 +317,12 @@ stages: displayName: Native WASM dependsOn: prepare jobs: - - template: azure-templates-wasm-matrix.yml # Build Native WASM (Linux) + - template: /scripts/azure-templates-wasm-matrix.yml@self # Build Native WASM (Linux) parameters: buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_LINUX_NATIVE }} - artifactName: native + buildAgent: ${{ parameters.buildAgentLinuxNative }} + use1ESPipelineTemplates: ${{ parameters.use1ESPipelineTemplates }} emscripten: - 2.0.6: displayName: 2.0.6 @@ -392,54 +376,119 @@ stages: features: _wasmeh,simd,mt - ${{ if ne(parameters.buildPipelineType, 'tests') }}: - - stage: managed - displayName: Build Managed + - stage: native + displayName: Native + variables: + nativeLinuxJobs: $[ convertToJson(stageDependencies.native_linux) ] + nativeWasmJobs: $[ convertToJson(stageDependencies.native_wasm) ] dependsOn: - native_windows - native_macos - native_linux - native_wasm jobs: - - template: azure-templates-bootstrapper.yml # Build Managed (Windows) + - template: /scripts/azure-templates-merger.yml@self # Merge Native Artifacts + parameters: + name: native + displayName: Merge Native Artifacts + buildPipelineType: ${{ parameters.buildPipelineType }} + buildAgent: ${{ parameters.buildAgentHost }} + requiredArtifacts: + # Android + - name: native_android_x86_windows + - name: native_android_x64_windows + - name: native_android_arm_windows + - name: native_android_arm64_windows + # Tizen + - name: native_tizen_windows + # Win32 + - name: native_win32_x86_windows + - name: native_win32_x64_windows + - name: native_win32_arm64_windows + # WinUI + - name: native_winui_x86_windows + - name: native_winui_x64_windows + - name: native_winui_arm64_windows + # Nano Server + - name: native_win32_x64_nanoserver_windows + # iOS + - name: native_ios_macos + # Mac Catalyst + - name: native_maccatalyst_macos + # macOS + - name: native_macos_macos + # tvOS + - name: native_tvos_macos + matrixArtifacts: + - name: native_linux + jobs: $(nativeLinuxJobs) + - name: native_wasm + jobs: $(nativeWasmJobs) + - template: /scripts/azure-templates-merger.yml@self # Merge Native WASM Artifacts + parameters: + name: native_wasm + displayName: Merge Native WASM Artifacts + buildPipelineType: ${{ parameters.buildPipelineType }} + buildAgent: ${{ parameters.buildAgentHost }} + matrixArtifacts: + - name: native_wasm + jobs: $(nativeWasmJobs) + - template: /scripts/azure-templates-merger.yml@self # Merge Native MSVC Artifacts + parameters: + name: native_msvc + displayName: Merge Native MSVC Artifacts + buildPipelineType: ${{ parameters.buildPipelineType }} + buildAgent: ${{ parameters.buildAgentHost }} + requiredArtifacts: + - name: native_win32_x86_msvc_windows + - name: native_win32_x64_msvc_windows + - name: native_win32_arm64_msvc_windows + + - ${{ if ne(parameters.buildPipelineType, 'build') }}: + - stage: managed + displayName: Build Managed + ${{ if eq(parameters.buildPipelineType, 'tests') }}: + dependsOn: prepare + ${{ if eq(parameters.buildPipelineType, 'both') }}: + dependsOn: native + jobs: + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Managed (Windows) parameters: name: managed_windows displayName: Managed (Windows) buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS}} + buildAgent: ${{ parameters.buildAgentWindows}} target: libs additionalArgs: --skipExternals="all" requiredArtifacts: - name: native - artifactName: managed postBuildSteps: - pwsh: Remove-Item ./output/native/ -Recurse -Force -ErrorAction Continue displayName: Delete the native folder - - template: azure-templates-bootstrapper.yml # Build Managed (macOS) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Managed (macOS) parameters: name: managed_macos displayName: Managed (macOS) buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC }} + buildAgent: ${{ parameters.buildAgentMac }} target: libs additionalArgs: --skipExternals="all" requiredArtifacts: - name: native - artifactName: managed postBuildSteps: - pwsh: Remove-Item ./output/native/ -Recurse -Force -ErrorAction Continue displayName: Delete the native folder - - template: azure-templates-bootstrapper.yml # Build Managed (Linux) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Managed (Linux) parameters: name: managed_linux displayName: Managed (Linux) buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_LINUX }} + buildAgent: ${{ parameters.buildAgentLinux }} packages: $(MANAGED_LINUX_PACKAGES) target: libs additionalArgs: --skipExternals="all" requiredArtifacts: - name: native - artifactName: managed postBuildSteps: - pwsh: Remove-Item ./output/native/ -Recurse -Force -ErrorAction Continue displayName: Delete the native folder @@ -447,51 +496,44 @@ stages: - ${{ if ne(parameters.buildPipelineType, 'tests') }}: - stage: package displayName: Package NuGets - dependsOn: - - native_windows - - native_macos - - native_linux - - native_wasm + dependsOn: native jobs: - - template: azure-templates-bootstrapper.yml # Package NuGets + - template: /scripts/azure-templates-bootstrapper.yml@self # Package NuGets parameters: name: package_normal_windows displayName: Package NuGets buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS}} + buildAgent: ${{ parameters.buildAgentWindows}} target: nuget-normal additionalArgs: --skipExternals="all" requiredArtifacts: - name: native postBuildSteps: - - task: PublishBuildArtifacts@1 - displayName: Publish the nuget artifacts - inputs: - artifactName: nuget - pathToPublish: 'output/nugets' - - task: PublishBuildArtifacts@1 - displayName: Publish the SignList.xml into nuget artifacts - inputs: - artifactName: nuget - pathToPublish: 'scripts\SignList.xml' - - task: PublishBuildArtifacts@1 - displayName: Publish the symbols nuget artifacts - inputs: - artifactName: nuget_symbols - pathToPublish: 'output/nugets-symbols' + - pwsh: Remove-Item ./output/native/ -Recurse -Force -ErrorAction Continue + displayName: Delete the native folder - pwsh: | - Remove-Item ./output/native/ -Recurse -Force - Remove-Item ./output/nugets/ -Recurse -Force - Remove-Item ./output/nugets-symbols/ -Recurse -Force - displayName: Delete the pre-published folders - - template: azure-templates-bootstrapper.yml # Package Special NuGets + New-Item '$(Build.ArtifactStagingDirectory)\nugets\' -Type Directory -Force | Out-Null + Get-ChildItem '.\output\nugets\' | Copy-Item -Destination '$(Build.ArtifactStagingDirectory)\nugets\' -Recurse -Force + Copy-Item -Path '.\scripts\SignList.xml' -Destination '$(Build.ArtifactStagingDirectory)\nugets\' + Remove-Item '.\output\nugets\' -Recurse -Force + displayName: Move the nugets artifact to the staging directory + - pwsh: | + New-Item '$(Build.ArtifactStagingDirectory)\nugets-symbols\' -Type Directory -Force | Out-Null + Get-ChildItem '.\output\nugets-symbols\' | Copy-Item -Destination '$(Build.ArtifactStagingDirectory)\nugets-symbols\' -Recurse -Force + Remove-Item '.\output\nugets-symbols\' -Recurse -Force + displayName: Move the nugets-symbols artifact to the staging directory + publishArtifacts: + - name: nuget + path: '$(Build.ArtifactStagingDirectory)\nugets' + - name: nuget_symbols + path: '$(Build.ArtifactStagingDirectory)\nugets-symbols' + - template: /scripts/azure-templates-bootstrapper.yml@self # Package Special NuGets parameters: name: package_special_windows displayName: Package Special NuGets buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS}} - dependsOn: - - package_normal_windows + buildAgent: ${{ parameters.buildAgentWindows}} + dependsOn: package_normal_windows target: nuget-special additionalArgs: --skipExternals="all" --exclusive requiredArtifacts: @@ -500,16 +542,18 @@ stages: - name: nuget_symbols dir: nugets-symbols postBuildSteps: - - task: PublishBuildArtifacts@1 - displayName: Publish the special nuget artifacts - inputs: - artifactName: nuget_special - pathToPublish: 'output/nugets-special' + - pwsh: | + New-Item '$(Build.ArtifactStagingDirectory)\nugets-special\' -Type Directory -Force | Out-Null + Get-ChildItem '.\output\nugets-special\' | Copy-Item -Destination '$(Build.ArtifactStagingDirectory)\nugets-special\' -Recurse -Force + Remove-Item '.\output\nugets-special\' -Recurse -Force + displayName: Move the nugets-special artifact to the staging directory - pwsh: | Remove-Item ./output/nugets/ -Recurse -Force - Remove-Item ./output/nugets-special/ -Recurse -Force Remove-Item ./output/nugets-symbols/ -Recurse -Force - displayName: Delete the pre-published folders + displayName: Delete the downloaded artifacts + publishArtifacts: + - name: nuget_special + path: '$(Build.ArtifactStagingDirectory)\nugets-special' - ${{ if ne(parameters.buildPipelineType, 'build') }}: - stage: api_diff @@ -519,12 +563,12 @@ stages: ${{ if eq(parameters.buildPipelineType, 'both') }}: dependsOn: package jobs: - - template: azure-templates-bootstrapper.yml # API Diff + - template: /scripts/azure-templates-bootstrapper.yml@self # API Diff parameters: name: api_diff_windows displayName: API Diff buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS}} + buildAgent: ${{ parameters.buildAgentWindows}} target: docs-api-diff additionalArgs: --nugetDiffPrerelease=$(NUGET_DIFF_PRERELEASE) shouldPublish: false @@ -534,19 +578,13 @@ stages: preBuildSteps: - pwsh: .\scripts\install-gtk.ps1 displayName: Install GTK# 2.12 - postBuildSteps: - - task: PublishBuildArtifacts@1 - displayName: Publish the API diffs - condition: always() - inputs: - artifactName: api-diff - pathToPublish: '$(Build.SourcesDirectory)\output\api-diff' - - task: PublishBuildArtifacts@1 - displayName: Publish the changelogs - condition: always() - inputs: - artifactName: changelogs - pathToPublish: '$(Build.SourcesDirectory)\changelogs' + publishArtifacts: + - name: api-diff + always: true + path: '$(Build.SourcesDirectory)\output\api-diff' + - name: changelogs + always: true + path: '$(Build.SourcesDirectory)\changelogs' - ${{ if and(eq(variables['System.TeamProject'], 'devdiv'), ne(parameters.buildPipelineType, 'tests'), ne(variables['System.PullRequest.IsFork'], 'true')) }}: - stage: signing @@ -559,17 +597,8 @@ stages: signType: 'Real' ${{ if not(or(eq(variables['Build.SourceBranch'], 'refs/heads/main'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'))) }}: signType: 'Test' - - - ${{ if and(eq(variables['System.TeamProject'], 'devdiv'), ne(parameters.buildPipelineType, 'tests'), ne(variables['System.PullRequest.IsFork'], 'true')) }}: - - stage: sbom - displayName: 'Software Bill of Materials' - dependsOn: signing - jobs: - - template: compliance/sbom/job.v1.yml@xamarin-templates # Software Bill of Materials (SBOM): https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-docs/secure-supply-chain/ado-sbom-generator - parameters: - artifactNames: ['nuget'] - packageName: 'SkiaSharp' - packageFilter: '*.nupkg' + use1ESTemplate: ${{ parameters.use1ESPipelineTemplates }} + usePipelineArtifactTasks: true - ${{ if ne(parameters.buildPipelineType, 'build') }}: - stage: tests @@ -577,18 +606,14 @@ stages: ${{ if eq(parameters.buildPipelineType, 'tests') }}: dependsOn: prepare ${{ if eq(parameters.buildPipelineType, 'both') }}: - dependsOn: - - native_windows - - native_macos - - native_linux - - native_wasm + dependsOn: native jobs: - - template: azure-templates-bootstrapper.yml # Tests|netfx (Windows) + - template: /scripts/azure-templates-bootstrapper.yml@self # Tests|netfx (Windows) parameters: name: tests_netfx_windows displayName: Windows (.NET Framework) buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS}} + buildAgent: ${{ parameters.buildAgentWindows}} target: tests-netfx additionalArgs: --skipExternals="all" --coverage=$(ENABLE_CODE_COVERAGE) shouldPublish: false @@ -604,18 +629,16 @@ stages: testResultsFormat: xUnit testResultsFiles: 'output/logs/testlogs/**/TestResults.xml' testRunTitle: 'Windows .NET Framework Tests' - - task: PublishBuildArtifacts@1 - displayName: Publish the test logs - condition: always() - inputs: - artifactName: testlogs_netfx_windows - pathToPublish: 'output/logs/testlogs' - - template: azure-templates-bootstrapper.yml # Tests|netcore (Windows) + publishArtifacts: + - name: testlogs_netfx_windows + always: true + path: 'output/logs/testlogs' + - template: /scripts/azure-templates-bootstrapper.yml@self # Tests|netcore (Windows) parameters: name: tests_netcore_windows displayName: Windows (.NET Core) buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS}} + buildAgent: ${{ parameters.buildAgentWindows}} target: tests-netcore additionalArgs: --skipExternals="all" --coverage=$(ENABLE_CODE_COVERAGE) shouldPublish: false @@ -631,23 +654,18 @@ stages: testResultsFormat: xUnit testResultsFiles: 'output/logs/testlogs/**/TestResults.xml' testRunTitle: 'Windows .NET Core Tests' - - task: PublishBuildArtifacts@1 - displayName: Publish the test logs - condition: always() - inputs: - artifactName: testlogs_netcore_windows - pathToPublish: 'output/logs/testlogs' - - task: PublishBuildArtifacts@1 - displayName: 'Publish the code coverage results' - inputs: - artifactName: coverage_netcore_windows - pathToPublish: 'output/coverage' - - template: azure-templates-bootstrapper.yml # Tests|netcore (macOS) + publishArtifacts: + - name: testlogs_netcore_windows + always: true + path: 'output/logs/testlogs' + - name: coverage_netcore_windows + path: 'output/coverage' + - template: /scripts/azure-templates-bootstrapper.yml@self # Tests|netcore (macOS) parameters: name: tests_netcore_macos displayName: macOS (.NET Core) buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC }} + buildAgent: ${{ parameters.buildAgentMac }} target: tests-netcore additionalArgs: --skipExternals="all" --coverage=$(ENABLE_CODE_COVERAGE) shouldPublish: false @@ -661,23 +679,18 @@ stages: testResultsFormat: xUnit testResultsFiles: 'output/logs/testlogs/**/TestResults.xml' testRunTitle: 'macOS .NET Core Tests' - - task: PublishBuildArtifacts@1 - displayName: Publish the test logs - condition: always() - inputs: - artifactName: testlogs_netcore_macos - pathToPublish: 'output/logs/testlogs' - - task: PublishBuildArtifacts@1 - displayName: 'Publish the code coverage results' - inputs: - artifactName: coverage_netcore_macos - pathToPublish: 'output/coverage' - - template: azure-templates-bootstrapper.yml # Tests|netcore (Linux) + publishArtifacts: + - name: testlogs_netcore_macos + always: true + path: 'output/logs/testlogs' + - name: coverage_netcore_macos + path: 'output/coverage' + - template: /scripts/azure-templates-bootstrapper.yml@self # Tests|netcore (Linux) parameters: name: tests_netcore_linux displayName: Linux (.NET Core) buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_LINUX }} + buildAgent: ${{ parameters.buildAgentLinux }} packages: $(MANAGED_LINUX_PACKAGES) target: tests-netcore additionalArgs: --skipExternals="all" --coverage=$(ENABLE_CODE_COVERAGE) @@ -693,23 +706,18 @@ stages: testResultsFormat: xUnit testResultsFiles: 'output/logs/testlogs/**/TestResults.xml' testRunTitle: 'Linux .NET Core Tests' - - task: PublishBuildArtifacts@1 - displayName: Publish the test logs - condition: always() - inputs: - artifactName: testlogs_netcore_linux - pathToPublish: 'output/logs/testlogs' - - task: PublishBuildArtifacts@1 - displayName: 'Publish the code coverage results' - inputs: - artifactName: coverage_netcore_linux - pathToPublish: 'output/coverage' - - template: azure-templates-bootstrapper.yml # Tests|android (macOS) + publishArtifacts: + - name: testlogs_netcore_linux + always: true + path: 'output/logs/testlogs' + - name: coverage_netcore_linux + path: 'output/coverage' + - template: /scripts/azure-templates-bootstrapper.yml@self # Tests|android (macOS) parameters: name: tests_android_macos displayName: Android (macOS) buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC }} + buildAgent: ${{ parameters.buildAgentMac }} target: tests-android additionalArgs: --device=android-emulator-64 --deviceVersion=$(ANDROID_TEST_DEVICE_VERSION) --skipExternals="all" --coverage=$(ENABLE_CODE_COVERAGE) shouldPublish: false @@ -731,25 +739,23 @@ stages: testResultsFormat: xUnit testResultsFiles: 'output/logs/testlogs/**/TestResults.xml' testRunTitle: 'Android Tests (API $(ANDROID_TEST_DEVICE_VERSION))' - - task: PublishBuildArtifacts@1 - displayName: Publish the test logs - condition: always() - inputs: - artifactName: testlogs_android_$(ANDROID_TEST_DEVICE_VERSION) - pathToPublish: 'output/logs/testlogs' - - template: azure-templates-bootstrapper.yml # Tests|ios (macOS) + publishArtifacts: + - name: testlogs_android_$(ANDROID_TEST_DEVICE_VERSION) + always: true + path: 'output/logs/testlogs' + - template: /scripts/azure-templates-bootstrapper.yml@self # Tests|ios (macOS) parameters: name: tests_ios_macos displayName: iOS (macOS) buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC }} + buildAgent: ${{ parameters.buildAgentMac }} target: tests-ios additionalArgs: --device=ios-simulator-64 --deviceVersion=$(IOS_TEST_DEVICE_VERSION) --skipExternals="all" --coverage=$(ENABLE_CODE_COVERAGE) shouldPublish: false requiredArtifacts: - name: native_ios_macos preBuildSteps: - - template: azure-templates-provisioning-profiles.yml + - template: /scripts/azure-templates-provisioning-profiles.yml@self postBuildSteps: - task: PublishTestResults@2 displayName: Publish the iOS test results @@ -758,51 +764,47 @@ stages: testResultsFormat: xUnit testResultsFiles: 'output/logs/testlogs/**/TestResults.xml' testRunTitle: 'iOS Tests (v$(IOS_TEST_DEVICE_VERSION))' - - task: PublishBuildArtifacts@1 - displayName: Publish the test logs - condition: always() - inputs: - artifactName: testlogs_ios_$(IOS_TEST_DEVICE_VERSION) - pathToPublish: 'output/logs/testlogs' - - template: azure-templates-bootstrapper.yml # Tests|maccatalyst (macOS) + publishArtifacts: + - name: testlogs_ios_$(IOS_TEST_DEVICE_VERSION) + always: true + path: 'output/logs/testlogs' + - template: /scripts/azure-templates-bootstrapper.yml@self # Tests|maccatalyst (macOS) parameters: name: tests_maccatalyst_macos displayName: Mac Catalyst (macOS) buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC }} + buildAgent: ${{ parameters.buildAgentMac }} target: tests-maccatalyst additionalArgs: --device=maccatalyst --skipExternals="all" --coverage=$(ENABLE_CODE_COVERAGE) shouldPublish: false requiredArtifacts: - name: native_maccatalyst_macos preBuildSteps: - - template: azure-templates-provisioning-profiles.yml + - template: /scripts/azure-templates-provisioning-profiles.yml@self postBuildSteps: - task: PublishTestResults@2 - displayName: Publish the iOMac CatalystS test results + displayName: Publish the Mac Catalyst test results condition: always() inputs: testResultsFormat: xUnit testResultsFiles: 'output/logs/testlogs/**/TestResults.xml' testRunTitle: 'Mac Catalyst Tests' - - task: PublishBuildArtifacts@1 - displayName: Publish the test logs - condition: always() - inputs: - artifactName: testlogs_maccatalyst - pathToPublish: 'output/logs/testlogs' - - template: azure-templates-bootstrapper.yml # Tests [WASM] (Linux) + publishArtifacts: + - name: testlogs_maccatalyst + always: true + path: 'output/logs/testlogs' + - template: /scripts/azure-templates-bootstrapper.yml@self # Tests [WASM] (Linux) parameters: name: tests_wasm_linux displayName: WASM (Linux) buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_LINUX }} + buildAgent: ${{ parameters.buildAgentLinux }} packages: $(MANAGED_LINUX_PACKAGES) ninja-build target: tests-wasm additionalArgs: --skipExternals="all" --coverage=false --chromedriver=$(CHROMEWEBDRIVER) shouldPublish: false requiredArtifacts: - - name: native_wasm_linux + - name: native_wasm installEmsdk: true initScript: source ~/emsdk/emsdk_env.sh postBuildSteps: @@ -813,27 +815,25 @@ stages: testResultsFormat: xUnit testResultsFiles: 'output/logs/testlogs/**/*.xml' testRunTitle: 'Linux WASM Tests' - - task: PublishBuildArtifacts@1 - displayName: Publish the test logs - condition: always() - inputs: - artifactName: testlogs_wasm - pathToPublish: 'output/logs/testlogs' + publishArtifacts: + - name: testlogs_wasm + always: true + path: 'output/logs/testlogs' # TODO: add tests for linux alpine # TODO: add tests for linux no dependencies # TODO: add tests for windows nano server - job: coverage_reports # Coverage Reports displayName: Coverage Reports - pool: ${{ parameters.VM_IMAGE_HOST.pool }} + pool: ${{ parameters.buildAgentHost.pool }} dependsOn: - tests_netcore_windows - tests_netcore_macos - tests_netcore_linux steps: - checkout: self - - template: azure-templates-variables.yml + - template: /scripts/azure-templates-variables.yml@self - ${{ if ne(parameters.buildPipelineType, 'both') }}: - - template: azure-templates-github-status.yml + - template: /scripts/azure-templates-github-status.yml@self parameters: state: 'pending' - task: DownloadBuildArtifacts@1 @@ -857,7 +857,7 @@ stages: codeCoverageTool: Cobertura summaryFileLocation: 'output/**/Cobertura.xml' - ${{ if ne(parameters.buildPipelineType, 'both') }}: - - template: azure-templates-github-status.yml + - template: /scripts/azure-templates-github-status.yml@self - ${{ if ne(parameters.buildPipelineType, 'build') }}: - stage: samples @@ -867,12 +867,12 @@ stages: ${{ if eq(parameters.buildPipelineType, 'both') }}: dependsOn: package jobs: - - template: azure-templates-bootstrapper.yml # Build Samples (Windows) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Samples (Windows) parameters: name: samples_windows displayName: Windows buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_WINDOWS}} + buildAgent: ${{ parameters.buildAgentWindows}} target: samples requiredArtifacts: - name: nuget @@ -880,12 +880,12 @@ stages: postBuildSteps: - pwsh: Remove-Item ./output/nugets/ -Recurse -Force -ErrorAction Continue displayName: Delete the nugets folder - - template: azure-templates-bootstrapper.yml # Build Samples (macOS) + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Samples (macOS) parameters: name: samples_macos displayName: macOS buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_MAC }} + buildAgent: ${{ parameters.buildAgentMac }} target: samples installNinja: true shouldPublish: false @@ -893,13 +893,13 @@ stages: - name: nuget dir: nugets preBuildSteps: - - template: azure-templates-provisioning-profiles.yml - - template: azure-templates-bootstrapper.yml # Build Samples (Linux) + - template: /scripts/azure-templates-provisioning-profiles.yml@self + - template: /scripts/azure-templates-bootstrapper.yml@self # Build Samples (Linux) parameters: name: samples_linux displayName: Linux buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.VM_IMAGE_LINUX }} + buildAgent: ${{ parameters.buildAgentLinux }} packages: $(MANAGED_LINUX_PACKAGES) target: samples shouldPublish: false @@ -962,16 +962,17 @@ stages: displayName: Finalize Build dependsOn: - api_diff + - managed - samples - tests jobs: - job: finalize # Finalize Build displayName: Finalize Build - pool: ${{ parameters.VM_IMAGE_HOST.pool }} + pool: ${{ parameters.buildAgentHost.pool }} steps: - checkout: none - - template: azure-templates-variables.yml - - template: azure-templates-github-status.yml + - template: /scripts/azure-templates-variables.yml@self + - template: /scripts/azure-templates-github-status.yml@self parameters: context: 'SkiaSharp-Tests' displayName: Update the final status for the tests pipeline diff --git a/scripts/azure-templates-wasm-matrix.yml b/scripts/azure-templates-wasm-matrix.yml index 52730c71e4..bbceb72be2 100644 --- a/scripts/azure-templates-wasm-matrix.yml +++ b/scripts/azure-templates-wasm-matrix.yml @@ -1,27 +1,21 @@ parameters: - artifactName: '' # the name of the artifact to merge this run into buildExternals: '' # the build number to download externals from - buildPipelineType: false - vmImage: '' # the VM image + buildPipelineType: 'both' # the type of build pipeline setup + buildAgent: '' # the configuration for the build agent + use1ESPipelineTemplates: false # whether or not we are building using the internal 1ES Pipeline Templates emscripten: [ ] jobs: - ${{ each version in parameters.emscripten }}: - - template: azure-templates-bootstrapper.yml + - template: /scripts/azure-templates-bootstrapper.yml@self parameters: name: native_wasm_${{ replace(version.displayName, '.', '_') }}_linux displayName: WASM (${{ version.displayName }}) buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} - vmImage: ${{ parameters.vmImage }} + buildAgent: ${{ parameters.buildAgent }} + use1ESPipelineTemplates: ${{ parameters.use1ESPipelineTemplates }} docker: scripts/Docker/wasm target: externals-wasm dockerArgs: --build-arg EMSCRIPTEN_VERSION=${{ version.version }} - additionalArgs: --emscriptenVersion=${{ version.version }} --emscriptenFeatures="${{ version.features }}" - artifactName: ${{ parameters.artifactName }} - postBuildSteps: - - task: PublishBuildArtifacts@1 - displayName: Publish the native_wasm_linux artifacts - inputs: - artifactName: native_wasm_linux - pathToPublish: 'output' \ No newline at end of file + additionalArgs: --emscriptenVersion=${{ version.version }} --emscriptenFeatures="${{ version.features }}" \ No newline at end of file From d98115c53394d6b6fa3a2a0e4d6c189c84f581e0 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Thu, 29 Feb 2024 17:35:10 +0200 Subject: [PATCH 21/40] Improve compliance jobs (#2772) --- scripts/azure-templates-bootstrapper.yml | 25 +++++++++++++----------- scripts/azure-templates-stages.yml | 2 ++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/scripts/azure-templates-bootstrapper.yml b/scripts/azure-templates-bootstrapper.yml index a1ef372135..f476be899c 100644 --- a/scripts/azure-templates-bootstrapper.yml +++ b/scripts/azure-templates-bootstrapper.yml @@ -30,7 +30,6 @@ parameters: installLlvm: true # whether or not to install the LLVM compiler installEmsdk: false # whether or not to install the Emscripten SDK installNinja: false # whether or not to install the ninja build system - artifactName: '' # the name of the artifact to merge this run into publishArtifacts: [] # the additional artifacts to publish tools: [] # any additional .net global tools skipInstall: false # whether or not to install any tools @@ -57,23 +56,27 @@ jobs: break: false outputParentDirectory: 'output' outputs: - - output: pipelineArtifact - displayName: 'Publish the ${{ parameters.name }} artifacts' - condition: or(${{ parameters.shouldPublish }}, failed()) - artifactName: ${{ parameters.name }} - targetPath: 'output' - - ${{ if ne(parameters.artifactName, '') }}: + - ${{ if eq(parameters.shouldPublish, 'true') }}: - output: pipelineArtifact - displayName: 'Publish the combined ${{ parameters.artifactName }} artifacts' - artifactName: ${{ parameters.artifactName }} + displayName: 'Publish the ${{ parameters.name }} artifacts' + artifactName: ${{ parameters.name }} + targetPath: 'output' + - output: pipelineArtifact + displayName: 'Publish the failed ${{ parameters.name }} artifacts' + condition: failed() + artifactName: ${{ parameters.name }}_failed_$(System.JobAttempt) targetPath: 'output' - ${{ each additionalArtifact in parameters.publishArtifacts }}: - output: pipelineArtifact displayName: 'Publish the ${{ additionalArtifact.name }} artifacts' - ${{ if eq(additionalArtifact.always, 'true') }}: - condition: always() artifactName: ${{ additionalArtifact.name }} targetPath: ${{ additionalArtifact.path }} + - ${{ if eq(additionalArtifact.always, 'true') }}: + - output: pipelineArtifact + displayName: 'Publish the failed ${{ additionalArtifact.name }} artifacts' + condition: failed() + artifactName: ${{ additionalArtifact.name }}_failed_$(System.JobAttempt) + targetPath: ${{ additionalArtifact.path }} steps: # prepare diff --git a/scripts/azure-templates-stages.yml b/scripts/azure-templates-stages.yml index d782a44af0..da6fcea289 100644 --- a/scripts/azure-templates-stages.yml +++ b/scripts/azure-templates-stages.yml @@ -916,6 +916,8 @@ stages: - package complianceEnabled: true complianceTimeoutInMinutes: 480 + windowsPoolName: ${{ parameters.buildAgentHost.pool.name }} + windowsImageOverride: ${{ parameters.buildAgentHost.pool.image }} scanArtifacts: - nuget - nuget_symbols From ca295d0066958cca646a0e24de6d7c99ef806737 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Sun, 3 Mar 2024 20:43:13 +0200 Subject: [PATCH 22/40] Fix benchmarks project (#2781) --- benchmarks/SkiaSharp.Benchmarks.sln | 4 ++++ source/SkiaSharp.Build.targets | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/benchmarks/SkiaSharp.Benchmarks.sln b/benchmarks/SkiaSharp.Benchmarks.sln index 12dcd8fba7..2cbfe66ee3 100644 --- a/benchmarks/SkiaSharp.Benchmarks.sln +++ b/benchmarks/SkiaSharp.Benchmarks.sln @@ -43,6 +43,10 @@ Global {42B5D998-A676-4B50-B558-1D3ACA7D3FC4}.Debug|Any CPU.Build.0 = Debug|Any CPU {42B5D998-A676-4B50-B558-1D3ACA7D3FC4}.Release|Any CPU.ActiveCfg = Release|Any CPU {42B5D998-A676-4B50-B558-1D3ACA7D3FC4}.Release|Any CPU.Build.0 = Release|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD2C6978-4F5E-E592-B565-26C357877B2C}.Release|Any CPU.Build.0 = Release|Any CPU {DD03EAA1-A85D-4588-8B84-8285EC1979C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DD03EAA1-A85D-4588-8B84-8285EC1979C8}.Debug|Any CPU.Build.0 = Debug|Any CPU {DD03EAA1-A85D-4588-8B84-8285EC1979C8}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/source/SkiaSharp.Build.targets b/source/SkiaSharp.Build.targets index 7336df8e1f..0a152064b7 100644 --- a/source/SkiaSharp.Build.targets +++ b/source/SkiaSharp.Build.targets @@ -166,14 +166,14 @@ internal partial class VersionConstants { Verify that the output assembly is signed correctly for release. =================================================================================================================== --> - + <_SignAssemblyVerifyAfterTargets> Build + Condition=" $(IsWindows) and '$(SignAssembly)' == 'true' and '$(Configuration)' == 'Release' and '$(TargetPath)' != '' and '$(BuildingInsideVisualStudio)' != 'true' "> From 7ebc1f0719e68210523355fadd8dec4a9ef5f34c Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Mon, 4 Mar 2024 21:42:00 +0200 Subject: [PATCH 23/40] Use Unsafe.As for better perf (#2780) --- binding/Directory.Build.targets | 4 + binding/SkiaSharp/SKMatrix44.cs | 65 +++---- externals/skia | 2 +- tests/Tests/SkiaSharp/SKMatrix44Tests.cs | 237 +++++++++++++++-------- 4 files changed, 189 insertions(+), 119 deletions(-) diff --git a/binding/Directory.Build.targets b/binding/Directory.Build.targets index f6e780a0ff..813aac0552 100644 --- a/binding/Directory.Build.targets +++ b/binding/Directory.Build.targets @@ -4,6 +4,10 @@ + + + + SkiaSharp is a cross-platform 2D graphics API for .NET platforms based on Google's Skia Graphics Library. It provides a comprehensive 2D API that can be used across mobile, server and desktop models to render images. diff --git a/binding/SkiaSharp/SKMatrix44.cs b/binding/SkiaSharp/SKMatrix44.cs index dfbe3754df..8c44538d4a 100644 --- a/binding/SkiaSharp/SKMatrix44.cs +++ b/binding/SkiaSharp/SKMatrix44.cs @@ -2,6 +2,7 @@ using System; using System.Numerics; +using System.Runtime.CompilerServices; namespace SkiaSharp { @@ -348,46 +349,46 @@ public static SKMatrix44 Multiply (SKMatrix44 value1, float value2) => public SKMatrix Matrix => new SKMatrix ( - m00, m01, m03, - m10, m11, m13, - m30, m31, m33); + m00, m10, m30, + m01, m11, m31, + m03, m13, m33); public float this[int row, int column] { - get => column switch { - 0 => row switch { + get => row switch { + 0 => column switch { 0 => m00, 1 => m01, 2 => m02, 3 => m03, - _ => throw new ArgumentOutOfRangeException (nameof (row)) + _ => throw new ArgumentOutOfRangeException (nameof (column)) }, - 1 => row switch { + 1 => column switch { 0 => m10, 1 => m11, 2 => m12, 3 => m13, - _ => throw new ArgumentOutOfRangeException (nameof (row)) + _ => throw new ArgumentOutOfRangeException (nameof (column)) }, - 2 => row switch { + 2 => column switch { 0 => m20, 1 => m21, 2 => m22, 3 => m23, - _ => throw new ArgumentOutOfRangeException (nameof (row)) + _ => throw new ArgumentOutOfRangeException (nameof (column)) }, - 3 => row switch { + 3 => column switch { 0 => m30, 1 => m31, 2 => m32, 3 => m33, - _ => throw new ArgumentOutOfRangeException (nameof (row)) + _ => throw new ArgumentOutOfRangeException (nameof (column)) }, - _ => throw new ArgumentOutOfRangeException (nameof (column)) + _ => throw new ArgumentOutOfRangeException (nameof (row)) }; set { - switch (column) { + switch (row) { case 0: - switch (row) { + switch (column) { case 0: m00 = value; break; @@ -401,11 +402,11 @@ public static SKMatrix44 Multiply (SKMatrix44 value1, float value2) => m03 = value; break; default: - throw new ArgumentOutOfRangeException (nameof (row)); + throw new ArgumentOutOfRangeException (nameof (column)); }; break; case 1: - switch (row) { + switch (column) { case 0: m10 = value; break; @@ -419,11 +420,11 @@ public static SKMatrix44 Multiply (SKMatrix44 value1, float value2) => m13 = value; break; default: - throw new ArgumentOutOfRangeException (nameof (row)); + throw new ArgumentOutOfRangeException (nameof (column)); }; break; case 2: - switch (row) { + switch (column) { case 0: m20 = value; break; @@ -437,11 +438,11 @@ public static SKMatrix44 Multiply (SKMatrix44 value1, float value2) => m23 = value; break; default: - throw new ArgumentOutOfRangeException (nameof (row)); + throw new ArgumentOutOfRangeException (nameof (column)); }; break; case 3: - switch (row) { + switch (column) { case 0: m30 = value; break; @@ -455,11 +456,11 @@ public static SKMatrix44 Multiply (SKMatrix44 value1, float value2) => m33 = value; break; default: - throw new ArgumentOutOfRangeException (nameof (row)); + throw new ArgumentOutOfRangeException (nameof (column)); }; break; default: - throw new ArgumentOutOfRangeException (nameof (column)); + throw new ArgumentOutOfRangeException (nameof (row)); }; } } @@ -468,23 +469,15 @@ public static SKMatrix44 Multiply (SKMatrix44 value1, float value2) => public static implicit operator SKMatrix44 (SKMatrix matrix) => new SKMatrix44 ( - matrix.ScaleX, matrix.SkewX, 0, matrix.TransX, - matrix.SkewY, matrix.ScaleY, 0, matrix.TransY, + matrix.ScaleX, matrix.SkewY, 0, matrix.Persp0, + matrix.SkewX, matrix.ScaleY, 0, matrix.Persp1, 0, 0, 1, 0, - matrix.Persp0, matrix.Persp1, 0, matrix.Persp2); + matrix.TransX, matrix.TransY, 0, matrix.Persp2); public static implicit operator Matrix4x4 (SKMatrix44 matrix) => - new Matrix4x4 ( - matrix.m00, matrix.m10, matrix.m20, matrix.m30, - matrix.m01, matrix.m11, matrix.m21, matrix.m31, - matrix.m02, matrix.m12, matrix.m22, matrix.m32, - matrix.m03, matrix.m13, matrix.m23, matrix.m33); + Unsafe.As (ref matrix); public static implicit operator SKMatrix44 (Matrix4x4 matrix) => - new SKMatrix44 ( - matrix.M11, matrix.M21, matrix.M31, matrix.M41, - matrix.M12, matrix.M22, matrix.M32, matrix.M42, - matrix.M13, matrix.M23, matrix.M33, matrix.M43, - matrix.M14, matrix.M24, matrix.M34, matrix.M44); + Unsafe.As (ref matrix); } } diff --git a/externals/skia b/externals/skia index 53d2065ea8..a0008792c8 160000 --- a/externals/skia +++ b/externals/skia @@ -1 +1 @@ -Subproject commit 53d2065ea8724daeb85e839ba47f54c582809615 +Subproject commit a0008792c861228872a0a21f5f3422c4c8824720 diff --git a/tests/Tests/SkiaSharp/SKMatrix44Tests.cs b/tests/Tests/SkiaSharp/SKMatrix44Tests.cs index f8dc0ac381..371b81f759 100644 --- a/tests/Tests/SkiaSharp/SKMatrix44Tests.cs +++ b/tests/Tests/SkiaSharp/SKMatrix44Tests.cs @@ -60,6 +60,74 @@ public void MatrixGoesFullCircle() Assert.Equal(rowMajor, result); } + [SkippableFact] + public void TranslationFieldsAreCorrectForMatrix() + { + var skm44 = SKMatrix44.CreateTranslation(10, 20, 30); + + var matrix = skm44.Matrix; + + Assert.Equal(10, matrix.TransX); + Assert.Equal(20, matrix.TransY); + } + + [SkippableFact] + public void ScaleFieldsAreCorrectForMatrix() + { + var skm44 = SKMatrix44.CreateScale(10, 20, 30); + + var matrix = skm44.Matrix; + + Assert.Equal(10, matrix.ScaleX); + Assert.Equal(20, matrix.ScaleY); + } + + [SkippableFact] + public void TranslateConvertsToMatrix() + { + var matrix44 = SKMatrix44.CreateTranslation(10, 20, 30); + var matrix = SKMatrix.CreateTranslation(10, 20); + + AssertSimilar(matrix.Values, matrix44.Matrix.Values, 6); + } + + [SkippableFact] + public void ScaleConvertsToMatrix() + { + var matrix44 = SKMatrix44.CreateScale(10, 20, 30); + var matrix = SKMatrix.CreateScale(10, 20); + + AssertSimilar(matrix.Values, matrix44.Matrix.Values, 6); + } + + [SkippableFact] + public void RotationConvertsToMatrix() + { + var matrix44 = SKMatrix44.CreateRotationDegrees(0, 0, 1, 45); + var matrix = SKMatrix.CreateRotationDegrees(45); + + AssertSimilar(matrix.Values, matrix44.Matrix.Values, 6); + } + + [SkippableFact] + public void ImplicitFromMatrix() + { + var matrix = SKMatrix.CreateRotationDegrees(45); + var matrix44 = (SKMatrix44)matrix; + + Assert.Equal(matrix.Values, matrix44.Matrix.Values); + } + + [SkippableFact] + public void ImplicitFromRotationScale() + { + var rs = SKRotationScaleMatrix.CreateRotationDegrees(45, 0, 0); + var matrix = SKMatrix.CreateRotationDegrees(45); + var matrix44 = (SKMatrix44)rs.ToMatrix(); + + Assert.Equal(matrix.Values, matrix44.Matrix.Values); + } + [SkippableFact] public void TransposeWorks() { @@ -136,108 +204,32 @@ public void Matrix44Inverts() } [SkippableFact] - public void Matrix44ConvertsToMatrix() - { - var rowMajor44 = new float[] { - 2, 3, 4, 5, - 4, 6, 8, 10, - 6, 9, 12, 15, - 8, 12, 16, 20, - }; - var rowMajor = new float[] { - rowMajor44[0], rowMajor44[1], rowMajor44[3], - rowMajor44[4], rowMajor44[5], rowMajor44[7], - rowMajor44[12], rowMajor44[13], rowMajor44[15], - }; - - var matrix44 = SKMatrix44.FromRowMajor(rowMajor44); - - Assert.Equal(rowMajor, matrix44.Matrix.Values); - } - - [SkippableFact] - public void TransformConvertsToMatrix() - { - var matrix44 = SKMatrix44.CreateRotationDegrees(0, 0, 1, 45); - var matrix = SKMatrix.CreateRotationDegrees(45); - - AssertSimilar(matrix.Values, matrix44.Matrix.Values, 6); - } - - [SkippableFact] - public void ImplicitFromMatrix() - { - var matrix = SKMatrix.CreateRotationDegrees(45); - var matrix44 = (SKMatrix44)matrix; - - Assert.Equal(matrix.Values, matrix44.Matrix.Values); - } - - [SkippableFact] - public void ImplicitFromRotationScale() - { - var rs = SKRotationScaleMatrix.CreateRotationDegrees(45, 0, 0); - var matrix = SKMatrix.CreateRotationDegrees(45); - var matrix44 = (SKMatrix44)rs.ToMatrix(); - - Assert.Equal(matrix.Values, matrix44.Matrix.Values); - } - -#if NET5_0_OR_GREATER - - [SkippableFact] - public void IndicesAreCorrectOnIdentity() + public void IndicesAreCorrectOnIdentityUsingFields() { var skm = SKMatrix44.CreateIdentity(); var m4x4 = Matrix4x4.Identity; - for (var row = 0; row < 4; row++) - { - for (var col = 0; col < 4; col++) - { - var sk = skm[row, col]; - var m = m4x4[row, col]; - Assert.Equal(m, sk); - } - } + AssertEqualFields(skm, m4x4); } [SkippableFact] - public void IndicesAreCorrectOnTranslate() + public void IndicesAreCorrectOnTranslateUsingFields() { var skm = SKMatrix44.CreateTranslation(10, 20, 30); var m4x4 = Matrix4x4.CreateTranslation(10, 20, 30); - for (var row = 0; row < 4; row++) - { - for (var col = 0; col < 4; col++) - { - var sk = skm[row, col]; - var m = m4x4[row, col]; - Assert.Equal(m, sk); - } - } + AssertEqualFields(skm, m4x4); } [SkippableFact] - public void IndicesAreCorrectOnScale() + public void IndicesAreCorrectOnScaleUsingFields() { var skm = SKMatrix44.CreateScale(10, 20, 30); var m4x4 = Matrix4x4.CreateScale(10, 20, 30); - for (var row = 0; row < 4; row++) - { - for (var col = 0; col < 4; col++) - { - var sk = skm[row, col]; - var m = m4x4[row, col]; - Assert.Equal(m, sk); - } - } + AssertEqualFields(skm, m4x4); } -#endif - [SkippableFact] public void TranslationMapsScalars() { @@ -350,6 +342,87 @@ public void ScaleIsCorrectLayoutWithOriginTopLeft(int x, int y, int z) AssertMatrixBitmap(bmp, SKRectI.Create(30 * x, 30 * y, 10 * x, 10 * y)); } + [SkippableTheory] + [InlineData(1, 0, 0, 30)] + [InlineData(0, 1, 0, 30)] + [InlineData(0, 0, 1, 30)] + [InlineData(1, 0, 0, -30)] + [InlineData(0, 1, 0, -30)] + [InlineData(0, 0, 1, -30)] + public void RotationIsCorrectLayoutWithOriginTopLeft(int x, int y, int z, int angle) + { + var matrix = SKMatrix44.CreateRotationDegrees(x, y, z, angle); + + using var bmp = DrawMatrixBitmap(SKRectI.Create(25, 25, 50, 50), matrix); + } + +#if NET5_0_OR_GREATER + + [SkippableFact] + public void IndicesAreCorrectOnIdentity() + { + var skm = SKMatrix44.CreateIdentity(); + var m4x4 = Matrix4x4.Identity; + + AssertEqualIndices(skm, m4x4); + } + + [SkippableFact] + public void IndicesAreCorrectOnTranslate() + { + var skm = SKMatrix44.CreateTranslation(10, 20, 30); + var m4x4 = Matrix4x4.CreateTranslation(10, 20, 30); + + AssertEqualIndices(skm, m4x4); + } + + [SkippableFact] + public void IndicesAreCorrectOnScale() + { + var skm = SKMatrix44.CreateScale(10, 20, 30); + var m4x4 = Matrix4x4.CreateScale(10, 20, 30); + + AssertEqualIndices(skm, m4x4); + } + + private static void AssertEqualIndices(SKMatrix44 skm, Matrix4x4 m4x4) + { + for (var row = 0; row < 4; row++) + { + for (var col = 0; col < 4; col++) + { + var sk = skm[row, col]; + var m = m4x4[row, col]; + Assert.Equal(m, sk); + } + } + } + +#endif + + private static void AssertEqualFields(SKMatrix44 skm, Matrix4x4 m4x4) + { + Assert.Equal(skm.M00, m4x4.M11); + Assert.Equal(skm.M01, m4x4.M12); + Assert.Equal(skm.M02, m4x4.M13); + Assert.Equal(skm.M03, m4x4.M14); + + Assert.Equal(skm.M10, m4x4.M21); + Assert.Equal(skm.M11, m4x4.M22); + Assert.Equal(skm.M12, m4x4.M23); + Assert.Equal(skm.M13, m4x4.M24); + + Assert.Equal(skm.M20, m4x4.M31); + Assert.Equal(skm.M21, m4x4.M32); + Assert.Equal(skm.M22, m4x4.M33); + Assert.Equal(skm.M23, m4x4.M34); + + Assert.Equal(skm.M30, m4x4.M41); + Assert.Equal(skm.M31, m4x4.M42); + Assert.Equal(skm.M32, m4x4.M43); + Assert.Equal(skm.M33, m4x4.M44); + } + private static SKBitmap DrawMatrixBitmap(SKRect rect, SKMatrix44 matrix) { var bmp = new SKBitmap(100, 100); From cf2907f313f18b71434ad5bc7c6860b1585d2a99 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Wed, 6 Mar 2024 21:44:34 +0200 Subject: [PATCH 24/40] Fix 1ES Builds (#2785) --- scripts/azure-pipelines.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/azure-pipelines.yml b/scripts/azure-pipelines.yml index cb554e1e60..c62f4cb874 100644 --- a/scripts/azure-pipelines.yml +++ b/scripts/azure-pipelines.yml @@ -18,7 +18,7 @@ parameters: type: object default: pool: - name: AzurePipelines-EO + name: Maui-1ESPT image: 1ESPT-Windows2022 os: windows - name: buildAgentWindows @@ -26,7 +26,7 @@ parameters: type: object default: pool: - name: AzurePipelines-EO + name: Maui-1ESPT image: 1ESPT-Windows2022 os: windows - name: buildAgentMac @@ -42,7 +42,7 @@ parameters: type: object default: pool: - name: AzurePipelines-EO + name: Maui-1ESPT image: 1ESPT-Ubuntu20.04 os: linux - name: runCompliance From a81a5ab5209913ec16bfb2a1e79d8f33bae21f30 Mon Sep 17 00:00:00 2001 From: "dotnet-policy-service[bot]" <123482357+dotnet-policy-service[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 17:25:15 +0200 Subject: [PATCH 25/40] FabricBot: Onboarding to GitOps.ResourceManagement because of FabricBot decommissioning (#2799) * Add prIssueManagement.yml to onboard repo to GitOps.ResourceManagement as FabricBot replacement Details on the replacement service and the syntax of the new yaml configuration file is available publicly at: https://microsoft.github.io/GitOps/policies/resource-management.html Please review and merge this PR to complete the process of onboarding to the new service. * Deleting fabricbot.json --------- Co-authored-by: dotnet-policy-service[bot] <123482357+dotnet-policy-service[bot]@users.noreply.github.com> --- .github/fabricbot.json | 2834 ----------------------- .github/policies/resourceManagement.yml | 562 +++++ 2 files changed, 562 insertions(+), 2834 deletions(-) delete mode 100644 .github/fabricbot.json create mode 100644 .github/policies/resourceManagement.yml diff --git a/.github/fabricbot.json b/.github/fabricbot.json deleted file mode 100644 index a42cda55ad..0000000000 --- a/.github/fabricbot.json +++ /dev/null @@ -1,2834 +0,0 @@ -{ - "version": "1.0", - "tasks": [ - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssueCommentResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "operator": "not", - "operands": [ - { - "name": "isOpen", - "parameters": {} - } - ] - }, - { - "name": "isAction", - "parameters": { - "action": "created" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/no-recent-activity" - } - }, - { - "operator": "or", - "operands": [ - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-info" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-repro" - } - } - ] - }, - { - "operator": "not", - "operands": [ - { - "name": "noActivitySince", - "parameters": { - "days": 7 - } - } - ] - }, - { - "operator": "not", - "operands": [ - { - "name": "isCloseAndComment", - "parameters": {} - } - ] - }, - { - "name": "isActivitySender", - "parameters": { - "user": { - "type": "author" - } - } - }, - { - "name": "activitySenderHasPermissions", - "parameters": { - "permissions": "none" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issue_comment" - ], - "taskName": "[Idle Issue Management] For issues closed due to inactivity, re-open an issue if issue author posts a reply within 7 days.", - "actions": [ - { - "name": "reopenIssue", - "parameters": {} - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/no-recent-activity" - } - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/needs-info" - } - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/needs-repro" - } - }, - { - "name": "addLabel", - "parameters": { - "label": "status/needs-attention" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssueCommentResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isAction", - "parameters": { - "action": "created" - } - }, - { - "operator": "not", - "operands": [ - { - "name": "isOpen", - "parameters": {} - } - ] - }, - { - "name": "activitySenderHasPermissions", - "parameters": { - "permissions": "read" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 7 - } - }, - { - "operator": "not", - "operands": [ - { - "name": "isCloseAndComment", - "parameters": {} - } - ] - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issue_comment" - ], - "taskName": "[Closed Issue Management] For issues closed with no activity over 7 days, ask non-contributor to consider opening a new issue instead.", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hello lovely human, thank you for your comment on this issue. Because this issue has been closed for a period of time, please strongly consider opening a new issue linking to this issue instead to ensure better visibility of your comment. Thank you!" - } - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "frequency": [ - { - "weekDay": 0, - "hours": [ - 1, - 4, - 7, - 10, - 13, - 16, - 19, - 22 - ], - "timezoneOffset": -8 - }, - { - "weekDay": 1, - "hours": [ - 1, - 4, - 7, - 10, - 13, - 16, - 19, - 22 - ], - "timezoneOffset": -8 - }, - { - "weekDay": 2, - "hours": [ - 1, - 4, - 7, - 10, - 13, - 16, - 19, - 22 - ], - "timezoneOffset": -8 - }, - { - "weekDay": 3, - "hours": [ - 1, - 4, - 7, - 10, - 13, - 16, - 19, - 22 - ], - "timezoneOffset": -8 - }, - { - "weekDay": 4, - "hours": [ - 1, - 4, - 7, - 10, - 13, - 16, - 19, - 22 - ], - "timezoneOffset": -8 - }, - { - "weekDay": 5, - "hours": [ - 1, - 4, - 7, - 10, - 13, - 16, - 19, - 22 - ], - "timezoneOffset": -8 - }, - { - "weekDay": 6, - "hours": [ - 1, - 4, - 7, - 10, - 13, - 16, - 19, - 22 - ], - "timezoneOffset": -8 - } - ], - "searchTerms": [ - { - "name": "isClosed", - "parameters": {} - }, - { - "name": "noActivitySince", - "parameters": { - "days": 30 - } - }, - { - "name": "isUnlocked", - "parameters": {} - }, - { - "name": "isIssue", - "parameters": {} - } - ], - "taskName": "[Closed Issue Management] Lock issues closed without activity for over 30 days", - "actions": [ - { - "name": "lockIssue", - "parameters": { - "reason": "resolved" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssueCommentResponder", - "version": "1.0", - "config": { - "taskName": "[Idle Issue Management] Replace needs author feedback label with needs attention label when the author comments on an issue", - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isAction", - "parameters": { - "action": "created" - } - }, - { - "operator": "or", - "operands": [ - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-info" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-repro" - } - } - ] - }, - { - "name": "isOpen", - "parameters": {} - }, - { - "operator": "or", - "operands": [ - { - "operator": "and", - "operands": [ - { - "operator": "not", - "operands": [ - { - "name": "activitySenderHasPermissions", - "parameters": { - "permissions": "write" - } - } - ] - }, - { - "operator": "not", - "operands": [ - { - "name": "activitySenderHasPermissions", - "parameters": { - "permissions": "admin" - } - } - ] - } - ] - }, - { - "name": "isActivitySender", - "parameters": { - "user": { - "type": "author" - } - } - } - ] - } - ] - }, - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "status/needs-attention" - } - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/needs-info" - } - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/needs-repro" - } - } - ], - "eventType": "issue", - "eventNames": [ - "issue_comment" - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "taskName": "[Closed Issue Management] Remove no recent activity label from issues", - "conditions": { - "operator": "and", - "operands": [ - { - "operator": "not", - "operands": [ - { - "name": "isAction", - "parameters": { - "action": "closed" - } - } - ] - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/no-recent-activity" - } - } - ] - }, - "actions": [ - { - "name": "removeLabel", - "parameters": { - "label": "status/no-recent-activity" - } - } - ], - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssueCommentResponder", - "version": "1.0", - "config": { - "taskName": "[Idle Issue Management] Remove no recent activity label when an issue is commented on", - "conditions": { - "operator": "and", - "operands": [ - { - "name": "hasLabel", - "parameters": { - "label": "status/no-recent-activity" - } - } - ] - }, - "actions": [ - { - "name": "removeLabel", - "parameters": { - "label": "status/no-recent-activity" - } - } - ], - "eventType": "issue", - "eventNames": [ - "issue_comment" - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "taskName": "[Idle Issue Management] Close stale `status/needs-info` issues", - "frequency": [ - { - "weekDay": 1, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 2, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 3, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 4, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 5, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - } - ], - "searchTerms": [ - { - "name": "isIssue", - "parameters": {} - }, - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-info" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/no-recent-activity" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 3 - } - } - ], - "actions": [ - { - "name": "closeIssue", - "parameters": {} - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "taskName": "[Idle Issue Management] Close stale `status/needs-repro` issues", - "frequency": [ - { - "weekDay": 1, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 2, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 3, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 4, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 5, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - } - ], - "searchTerms": [ - { - "name": "isIssue", - "parameters": {} - }, - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-repro" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/no-recent-activity" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 3 - } - } - ], - "actions": [ - { - "name": "closeIssue", - "parameters": {} - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "taskName": "[Idle Issue Management] Add no recent activity label to `status/needs-info` issues", - "frequency": [ - { - "weekDay": 1, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 2, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 3, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 4, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 5, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - } - ], - "searchTerms": [ - { - "name": "isIssue", - "parameters": {} - }, - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-info" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 4 - } - }, - { - "name": "noLabel", - "parameters": { - "label": "status/no-recent-activity" - } - } - ], - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "status/no-recent-activity" - } - }, - { - "name": "addReply", - "parameters": { - "comment": "This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**. If it *is* closed, feel free to comment when you are able to provide the additional information and we will re-investigate." - } - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "taskName": "[Idle Issue Management] Add no recent activity label to `status/needs-repro` issues", - "frequency": [ - { - "weekDay": 1, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 2, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 3, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 4, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 5, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - } - ], - "searchTerms": [ - { - "name": "isIssue", - "parameters": {} - }, - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-repro" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 4 - } - }, - { - "name": "noLabel", - "parameters": { - "label": "status/no-recent-activity" - } - } - ], - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "status/no-recent-activity" - } - }, - { - "name": "addReply", - "parameters": { - "comment": "This issue has been automatically marked as stale because it has been marked as requiring author feedback to reproduce the issue but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**. If it *is* closed, feel free to comment when you are able to provide the additional information and we will re-investigate." - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isAction", - "parameters": { - "action": "opened" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "dotnet-maestro[bot]", - "association": "CONTRIBUTOR" - } - }, - { - "name": "titleContains", - "parameters": { - "titlePattern": "Update dependencies" - } - } - ] - }, - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ], - "taskName": "[Infrastructure PRs] Add area-infrastructure label to dependency update Pull Requests", - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "area/infrastructure 🏗️" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "addedToMilestone", - "parameters": { - "milestoneName": "Backlog" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Comment: Issue moved to Backlog", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time." - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "status/needs-info" - } - } - ] - }, - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ], - "taskName": "Replace `status/needs-info` with `status/pr-needs-author-input` for PRs", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hello. I see that you've just added `status/needs-info` label to this PR.\nThat label is for Issues and not for PRs. Don't worry, I'm going to replace it with the correct one." - } - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/needs-info" - } - }, - { - "name": "addLabel", - "parameters": { - "label": "status/pr-needs-author-input" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "status/needs-repro" - } - } - ] - }, - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ], - "taskName": "Remove `status/needs-repro` from PRs", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hello. I see that you've just added `status/needs-repro` label to this PR.\nThat label is for Issues and not for PRs, so I removed it." - } - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/needs-repro" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "status/needs-info" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Add comment when `status/needs-info` is applied to issue", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hi @${issueAuthor}. We have added the `status/needs-info` label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time." - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "status/needs-repro" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Add comment when `status/needs-repro` is applied to issue", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hi @${issueAuthor}. We have added the `status/needs-repro` label to this issue, which indicates that we require steps and sample code to reproduce the issue before we can take further action. Please try to create a minimal sample project/solution or code samples which reproduce the issue, ideally as a GitHub repo that we can clone.\n\nThis issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time." - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "or", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "control-newcontrol" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-general" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-webview" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-datetimepicker" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-picker" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-switch" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-dualscreen" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-checkbox" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-border" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-label" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-button" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-dialogalert" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-entry" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-frame" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-stepper" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-refreshview" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-image" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-activityindicator" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-radiobutton" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-slider" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-progressbar" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-pages" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-map" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Add area/controls label when any 'control-X' label is applied to the issue", - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "area/controls 🎮" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "or", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "control-newcontrol" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-general" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-webview" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-datetimepicker" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-picker" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-switch" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-dualscreen" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-checkbox" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-border" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-label" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-button" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-dialogalert" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-entry" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-frame" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-stepper" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-refreshview" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-image" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-activityindicator" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-radiobutton" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-slider" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-progressbar" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-pages" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-map" - } - } - ] - }, - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ], - "taskName": "Add area/controls label when any 'control-X' label is applied to the PR", - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "area/controls 🎮" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isAction", - "parameters": { - "action": "opened" - } - }, - { - "operator": "or", - "operands": [ - { - "name": "isActivitySender", - "parameters": { - "user": "alexeystrakh" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "alexkblount" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "BenBtg" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "DeanFaizal" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "jgold6" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "jmongaras" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "jonlipsky" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "JoonghyunCho" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "juanlao" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "migueBarrera" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "mikeparker104" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "myroot" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "rookiejava" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "shyunMin" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "sung-su" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "Sweekriti91" - } - } - ] - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Add 'partner' label when issue is opened by a partner", - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "partner" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "labelAdded", - "parameters": { - "label": "status/move-to-vs-feedback" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Ask user to use VS Feedback for VS issues", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Thanks for the issue report @${issueAuthor}! This issue appears to be a problem with Visual Studio, so we ask that you use the VS feedback tool to report the issue. That way it will get to the routed to the team that owns this experience in VS.\n\nIf you encounter a problem with Visual Studio, we want to know about it so that we can diagnose and fix it. By using the Report a Problem tool, you can collect detailed information about the problem, and send it to Microsoft with just a few button clicks.\n\n1. Go to the [VS feedback tool](https://docs.microsoft.com/visualstudio/ide/how-to-report-a-problem-with-visual-studio?view=vs-2022) to report the issue\n2. Close this bug, and consider adding a link to the VS Feedback issue so that others can follow its activity there.\n\nThis issue will be automatically closed in 3 days if there are no further comments." - } - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "frequency": [ - { - "weekDay": 0, - "hours": [ - 0, - 6, - 12, - 18 - ] - }, - { - "weekDay": 1, - "hours": [ - 0, - 6, - 12, - 18 - ] - }, - { - "weekDay": 2, - "hours": [ - 0, - 6, - 12, - 18 - ] - }, - { - "weekDay": 3, - "hours": [ - 0, - 6, - 12, - 18 - ] - }, - { - "weekDay": 4, - "hours": [ - 0, - 6, - 12, - 18 - ] - }, - { - "weekDay": 5, - "hours": [ - 0, - 6, - 12, - 18 - ] - }, - { - "weekDay": 6, - "hours": [ - 0, - 6, - 12, - 18 - ] - } - ], - "searchTerms": [ - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/move-to-vs-feedback" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 3 - } - } - ], - "taskName": "Close `status/move-to-vs-feedback` after 3 days of no activity", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "This issue is being closed due to inactivity. If this issue is still affecting you, please follow the steps above to use the VS Feedback Tool to report the issue." - } - }, - { - "name": "closeIssue", - "parameters": {} - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssueCommentResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "isAction", - "parameters": { - "action": "created" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/move-to-vs-feedback" - } - }, - { - "operator": "not", - "operands": [ - { - "name": "noActivitySince", - "parameters": { - "days": 3 - } - } - ] - }, - { - "operator": "not", - "operands": [ - { - "name": "isCloseAndComment", - "parameters": {} - } - ] - }, - { - "name": "isActivitySender", - "parameters": { - "user": { - "type": "author" - } - } - }, - { - "name": "activitySenderHasPermissions", - "parameters": { - "permissions": "none" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issue_comment" - ], - "taskName": "For issues labeled with `status/move-to-vs-feedback` mark as `status/needs-attention` if there is activity", - "actions": [ - { - "name": "removeLabel", - "parameters": { - "label": "status/move-to-vs-feedback" - } - }, - { - "name": "addLabel", - "parameters": { - "label": "status/needs-attention" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isAction", - "parameters": { - "user": "roubachof", - "action": "opened" - } - }, - { - "operator": "or", - "operands": [ - { - "name": "isActivitySender", - "parameters": { - "user": "roubachof" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "davidbritch" - } - } - ] - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Add 'i/great-reporter' when issue is opened by an author we know opens high quality issues", - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "i/great-reporter" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "status/try-latest-version" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Add comment when `status/try-latest-version` is applied to the issue", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hi @${issueAuthor}. We have added the `status/try-latest-version` label to this issue, which indicates that we'd like you to try and reproduce this issue on the latest available public version. This can happen because we think that this issue was fixed in a version that has just been released, or the information provided by you indicates that you might be working with an older version.\n\nIf the issue still persists, please let us know with any additional details and ideally a reproduction project provided through a GitHub repository.\n\nThis issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time." - } - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "frequency": [ - { - "weekDay": 0, - "hours": [ - 3, - 15 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 1, - "hours": [ - 3, - 15 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 2, - "hours": [ - 3, - 15 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 3, - "hours": [ - 3, - 15 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 4, - "hours": [ - 3, - 15 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 5, - "hours": [ - 3, - 15 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 6, - "hours": [ - 3, - 15 - ], - "timezoneOffset": 2 - } - ], - "searchTerms": [ - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/try-latest-version" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 7 - } - } - ], - "taskName": "[Idle Issue Management] Close stale `status/try-latest-version` issues", - "actions": [ - { - "name": "closeIssue", - "parameters": {} - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "activitySenderHasPermissions", - "parameters": { - "permissions": "read" - } - }, - { - "operator": "not", - "operands": [ - { - "name": "isActivitySender", - "parameters": { - "user": "dotnet-maestro" - } - } - ] - }, - { - "operator": "not", - "operands": [ - { - "name": "isActivitySender", - "parameters": { - "user": "dotnet-maestro-bot" - } - } - ] - }, - { - "name": "isAction", - "parameters": { - "action": "opened" - } - } - ] - }, - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ], - "taskName": "Add 'community ✨' label to community contributions", - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "community ✨" - } - }, - { - "name": "addReactionToIssue", - "parameters": { - "reaction": "heart" - } - }, - { - "name": "addReply", - "parameters": { - "comment": "Hey there @${issueAuthor}! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed." - } - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "frequency": [ - { - "weekDay": 0, - "hours": [ - 2, - 5, - 8, - 11, - 14, - 17, - 20, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 1, - "hours": [ - 2, - 5, - 8, - 11, - 14, - 17, - 20, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 2, - "hours": [ - 2, - 5, - 8, - 11, - 14, - 17, - 20, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 3, - "hours": [ - 2, - 5, - 8, - 11, - 14, - 17, - 20, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 4, - "hours": [ - 2, - 5, - 8, - 11, - 14, - 17, - 20, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 5, - "hours": [ - 2, - 5, - 8, - 11, - 14, - 17, - 20, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 6, - "hours": [ - 2, - 5, - 8, - 11, - 14, - 17, - 20, - 23 - ], - "timezoneOffset": 2 - } - ], - "searchTerms": [ - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "isPr", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/pr-needs-author-input" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 10 - } - }, - { - "name": "noLabel", - "parameters": { - "label": "stale" - } - } - ], - "taskName": "Stale PR reminder", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hi @${issueAuthor}.\nIt seems you haven't touched this PR for the last two weeks. To avoid accumulating old PRs, we're marking it as `stale`. As a result, it will be closed if no further activity occurs **within 4 days of this comment**." - } - }, - { - "name": "addLabel", - "parameters": { - "label": "stale" - } - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "frequency": [ - { - "weekDay": 0, - "hours": [ - 3, - 7, - 11, - 15, - 19, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 1, - "hours": [ - 3, - 7, - 11, - 15, - 19, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 2, - "hours": [ - 3, - 7, - 11, - 15, - 19, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 3, - "hours": [ - 3, - 7, - 11, - 15, - 19, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 4, - "hours": [ - 3, - 7, - 11, - 15, - 19, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 5, - "hours": [ - 3, - 7, - 11, - 15, - 19, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 6, - "hours": [ - 3, - 7, - 11, - 15, - 19, - 23 - ], - "timezoneOffset": 2 - } - ], - "searchTerms": [ - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "isPr", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/pr-needs-author-input" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "stale" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 4 - } - } - ], - "taskName": "Close stale PRs", - "actions": [ - { - "name": "closeIssue", - "parameters": {} - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "hasLabel", - "parameters": { - "label": "stale" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/pr-needs-author-input" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": { - "type": "author" - } - } - }, - { - "operator": "not", - "operands": [ - { - "name": "activitySenderHasPermissions", - "parameters": { - "permissions": "write" - } - } - ] - } - ] - }, - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ], - "taskName": "Revitalize stale PR and reopen", - "actions": [ - { - "name": "reopenIssue", - "parameters": {} - }, - { - "name": "removeLabel", - "parameters": { - "label": "stale" - } - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/pr-needs-author-input" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "status/pr-needs-author-input" - } - } - ] - }, - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ], - "taskName": "Add comment when `status/pr-needs-author-input` is applied to PR", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hi @${issueAuthor}. We have added the `status/pr-needs-author-input` label to this issue, which indicates that we have an open question/action for you before we can take further action. This PRwill be closed automatically in 14 days if we do not hear back from you by then - please feel free to re-open it if you come back to this PR after that time." - } - } - ] - } - } - ], - "userGroups": [] -} \ No newline at end of file diff --git a/.github/policies/resourceManagement.yml b/.github/policies/resourceManagement.yml new file mode 100644 index 0000000000..5dc7e5b351 --- /dev/null +++ b/.github/policies/resourceManagement.yml @@ -0,0 +1,562 @@ +id: +name: GitOps.PullRequestIssueManagement +description: GitOps.PullRequestIssueManagement primitive +owner: +resource: repository +disabled: false +where: +configuration: + resourceManagementConfiguration: + scheduledSearches: + - description: '[Idle Issue Management] Close stale `status/needs-info` issues' + frequencies: + - weekday: + day: Monday + time: 0:0 + - weekday: + day: Tuesday + time: 0:0 + - weekday: + day: Wednesday + time: 0:0 + - weekday: + day: Thursday + time: 0:0 + - weekday: + day: Friday + time: 0:0 + filters: + - isIssue + - isOpen + - hasLabel: + label: status/needs-info + - hasLabel: + label: status/no-recent-activity + - noActivitySince: + days: 3 + actions: + - closeIssue + - description: '[Idle Issue Management] Close stale `status/needs-repro` issues' + frequencies: + - weekday: + day: Monday + time: 0:0 + - weekday: + day: Tuesday + time: 0:0 + - weekday: + day: Wednesday + time: 0:0 + - weekday: + day: Thursday + time: 0:0 + - weekday: + day: Friday + time: 0:0 + filters: + - isIssue + - isOpen + - hasLabel: + label: status/needs-repro + - hasLabel: + label: status/no-recent-activity + - noActivitySince: + days: 3 + actions: + - closeIssue + - description: '[Idle Issue Management] Add no recent activity label to `status/needs-info` issues' + frequencies: + - weekday: + day: Monday + time: 0:0 + - weekday: + day: Tuesday + time: 0:0 + - weekday: + day: Wednesday + time: 0:0 + - weekday: + day: Thursday + time: 0:0 + - weekday: + day: Friday + time: 0:0 + filters: + - isIssue + - isOpen + - hasLabel: + label: status/needs-info + - noActivitySince: + days: 4 + - isNotLabeledWith: + label: status/no-recent-activity + actions: + - addLabel: + label: status/no-recent-activity + - addReply: + reply: This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**. If it *is* closed, feel free to comment when you are able to provide the additional information and we will re-investigate. + - description: '[Idle Issue Management] Add no recent activity label to `status/needs-repro` issues' + frequencies: + - weekday: + day: Monday + time: 0:0 + - weekday: + day: Tuesday + time: 0:0 + - weekday: + day: Wednesday + time: 0:0 + - weekday: + day: Thursday + time: 0:0 + - weekday: + day: Friday + time: 0:0 + filters: + - isIssue + - isOpen + - hasLabel: + label: status/needs-repro + - noActivitySince: + days: 4 + - isNotLabeledWith: + label: status/no-recent-activity + actions: + - addLabel: + label: status/no-recent-activity + - addReply: + reply: This issue has been automatically marked as stale because it has been marked as requiring author feedback to reproduce the issue but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**. If it *is* closed, feel free to comment when you are able to provide the additional information and we will re-investigate. + - description: Close `status/move-to-vs-feedback` after 3 days of no activity + frequencies: + - hourly: + hour: 6 + filters: + - isOpen + - hasLabel: + label: status/move-to-vs-feedback + - noActivitySince: + days: 3 + actions: + - addReply: + reply: This issue is being closed due to inactivity. If this issue is still affecting you, please follow the steps above to use the VS Feedback Tool to report the issue. + - closeIssue + - description: '[Idle Issue Management] Close stale `status/try-latest-version` issues' + frequencies: + - hourly: + hour: 12 + filters: + - isOpen + - hasLabel: + label: status/try-latest-version + - noActivitySince: + days: 7 + actions: + - closeIssue + - description: Stale PR reminder + frequencies: + - hourly: + hour: 3 + filters: + - isOpen + - isPullRequest + - hasLabel: + label: status/pr-needs-author-input + - noActivitySince: + days: 10 + - isNotLabeledWith: + label: stale + actions: + - addReply: + reply: >- + Hi @${issueAuthor}. + + It seems you haven't touched this PR for the last two weeks. To avoid accumulating old PRs, we're marking it as `stale`. As a result, it will be closed if no further activity occurs **within 4 days of this comment**. + - addLabel: + label: stale + - description: Close stale PRs + frequencies: + - hourly: + hour: 4 + filters: + - isOpen + - isPullRequest + - hasLabel: + label: status/pr-needs-author-input + - hasLabel: + label: stale + - noActivitySince: + days: 4 + actions: + - closeIssue + eventResponderTasks: + - if: + - payloadType: Issue_Comment + - isAction: + action: Created + - or: + - hasLabel: + label: status/needs-info + - hasLabel: + label: status/needs-repro + - isOpen + - or: + - and: + - not: + activitySenderHasPermission: + permission: Write + - not: + activitySenderHasPermission: + permission: Admin + - isActivitySender: + issueAuthor: True + then: + - addLabel: + label: status/needs-attention + - removeLabel: + label: status/needs-info + - removeLabel: + label: status/needs-repro + description: '[Idle Issue Management] Replace needs author feedback label with needs attention label when the author comments on an issue' + - if: + - payloadType: Issues + - not: + isAction: + action: Closed + - hasLabel: + label: status/no-recent-activity + then: + - removeLabel: + label: status/no-recent-activity + description: '[Closed Issue Management] Remove no recent activity label from issues' + - if: + - payloadType: Issue_Comment + - hasLabel: + label: status/no-recent-activity + then: + - removeLabel: + label: status/no-recent-activity + description: '[Idle Issue Management] Remove no recent activity label when an issue is commented on' + - if: + - payloadType: Pull_Request + - isAction: + action: Opened + - isActivitySender: + user: dotnet-maestro[bot] + issueAuthor: False + - titleContains: + pattern: Update dependencies + isRegex: False + then: + - addLabel: + label: "area/infrastructure \U0001F3D7️" + description: '[Infrastructure PRs] Add area-infrastructure label to dependency update Pull Requests' + - if: + - payloadType: Pull_Request + - labelAdded: + label: status/needs-info + then: + - addReply: + reply: >- + Hello. I see that you've just added `status/needs-info` label to this PR. + + That label is for Issues and not for PRs. Don't worry, I'm going to replace it with the correct one. + - removeLabel: + label: status/needs-info + - addLabel: + label: status/pr-needs-author-input + description: Replace `status/needs-info` with `status/pr-needs-author-input` for PRs + - if: + - payloadType: Pull_Request + - labelAdded: + label: status/needs-repro + then: + - addReply: + reply: >- + Hello. I see that you've just added `status/needs-repro` label to this PR. + + That label is for Issues and not for PRs, so I removed it. + - removeLabel: + label: status/needs-repro + description: Remove `status/needs-repro` from PRs + - if: + - payloadType: Issues + - labelAdded: + label: status/needs-info + then: + - addReply: + reply: Hi @${issueAuthor}. We have added the `status/needs-info` label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time. + description: Add comment when `status/needs-info` is applied to issue + - if: + - payloadType: Issues + - labelAdded: + label: status/needs-repro + then: + - addReply: + reply: >- + Hi @${issueAuthor}. We have added the `status/needs-repro` label to this issue, which indicates that we require steps and sample code to reproduce the issue before we can take further action. Please try to create a minimal sample project/solution or code samples which reproduce the issue, ideally as a GitHub repo that we can clone. + + + This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time. + description: Add comment when `status/needs-repro` is applied to issue + - if: + - payloadType: Issues + - or: + - labelAdded: + label: control-newcontrol + - labelAdded: + label: control-general + - labelAdded: + label: control-webview + - labelAdded: + label: control-datetimepicker + - labelAdded: + label: control-picker + - labelAdded: + label: control-switch + - labelAdded: + label: control-dualscreen + - labelAdded: + label: control-checkbox + - labelAdded: + label: control-border + - labelAdded: + label: control-label + - labelAdded: + label: control-button + - labelAdded: + label: control-dialogalert + - labelAdded: + label: control-entry + - labelAdded: + label: control-frame + - labelAdded: + label: control-stepper + - labelAdded: + label: control-refreshview + - labelAdded: + label: control-image + - labelAdded: + label: control-activityindicator + - labelAdded: + label: control-radiobutton + - labelAdded: + label: control-slider + - labelAdded: + label: control-progressbar + - labelAdded: + label: control-pages + - labelAdded: + label: control-map + then: + - addLabel: + label: "area/controls \U0001F3AE" + description: Add area/controls label when any 'control-X' label is applied to the issue + - if: + - payloadType: Pull_Request + - or: + - labelAdded: + label: control-newcontrol + - labelAdded: + label: control-general + - labelAdded: + label: control-webview + - labelAdded: + label: control-datetimepicker + - labelAdded: + label: control-picker + - labelAdded: + label: control-switch + - labelAdded: + label: control-dualscreen + - labelAdded: + label: control-checkbox + - labelAdded: + label: control-border + - labelAdded: + label: control-label + - labelAdded: + label: control-button + - labelAdded: + label: control-dialogalert + - labelAdded: + label: control-entry + - labelAdded: + label: control-frame + - labelAdded: + label: control-stepper + - labelAdded: + label: control-refreshview + - labelAdded: + label: control-image + - labelAdded: + label: control-activityindicator + - labelAdded: + label: control-radiobutton + - labelAdded: + label: control-slider + - labelAdded: + label: control-progressbar + - labelAdded: + label: control-pages + - labelAdded: + label: control-map + then: + - addLabel: + label: "area/controls \U0001F3AE" + description: Add area/controls label when any 'control-X' label is applied to the PR + - if: + - payloadType: Issues + - isAction: + action: Opened + - or: + - isActivitySender: + user: alexeystrakh + issueAuthor: False + - isActivitySender: + user: alexkblount + issueAuthor: False + - isActivitySender: + user: BenBtg + issueAuthor: False + - isActivitySender: + user: DeanFaizal + issueAuthor: False + - isActivitySender: + user: jgold6 + issueAuthor: False + - isActivitySender: + user: jmongaras + issueAuthor: False + - isActivitySender: + user: jonlipsky + issueAuthor: False + - isActivitySender: + user: JoonghyunCho + issueAuthor: False + - isActivitySender: + user: juanlao + issueAuthor: False + - isActivitySender: + user: migueBarrera + issueAuthor: False + - isActivitySender: + user: mikeparker104 + issueAuthor: False + - isActivitySender: + user: myroot + issueAuthor: False + - isActivitySender: + user: rookiejava + issueAuthor: False + - isActivitySender: + user: shyunMin + issueAuthor: False + - isActivitySender: + user: sung-su + issueAuthor: False + - isActivitySender: + user: Sweekriti91 + issueAuthor: False + then: + - addLabel: + label: partner + description: Add 'partner' label when issue is opened by a partner + - if: + - payloadType: Issues + - isOpen + - labelAdded: + label: status/move-to-vs-feedback + then: + - addReply: + reply: >- + Thanks for the issue report @${issueAuthor}! This issue appears to be a problem with Visual Studio, so we ask that you use the VS feedback tool to report the issue. That way it will get to the routed to the team that owns this experience in VS. + + + If you encounter a problem with Visual Studio, we want to know about it so that we can diagnose and fix it. By using the Report a Problem tool, you can collect detailed information about the problem, and send it to Microsoft with just a few button clicks. + + + 1. Go to the [VS feedback tool](https://docs.microsoft.com/visualstudio/ide/how-to-report-a-problem-with-visual-studio?view=vs-2022) to report the issue + + 2. Close this bug, and consider adding a link to the VS Feedback issue so that others can follow its activity there. + + + This issue will be automatically closed in 3 days if there are no further comments. + description: Ask user to use VS Feedback for VS issues + - if: + - payloadType: Issues + - isAction: + action: Opened + - or: + - isActivitySender: + user: roubachof + issueAuthor: False + - isActivitySender: + user: davidbritch + issueAuthor: False + then: + - addLabel: + label: i/great-reporter + description: Add 'i/great-reporter' when issue is opened by an author we know opens high quality issues + - if: + - payloadType: Issues + - labelAdded: + label: status/try-latest-version + then: + - addReply: + reply: >- + Hi @${issueAuthor}. We have added the `status/try-latest-version` label to this issue, which indicates that we'd like you to try and reproduce this issue on the latest available public version. This can happen because we think that this issue was fixed in a version that has just been released, or the information provided by you indicates that you might be working with an older version. + + + If the issue still persists, please let us know with any additional details and ideally a reproduction project provided through a GitHub repository. + + + This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time. + description: Add comment when `status/try-latest-version` is applied to the issue + - if: + - payloadType: Pull_Request + - activitySenderHasPermission: + permission: Read + - not: + isActivitySender: + user: dotnet-maestro + issueAuthor: False + - not: + isActivitySender: + user: dotnet-maestro-bot + issueAuthor: False + - isAction: + action: Opened + then: + - addLabel: + label: community ✨ + - addReply: + reply: Hey there @${issueAuthor}! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. + description: Add 'community ✨' label to community contributions + - if: + - payloadType: Pull_Request + - hasLabel: + label: stale + - hasLabel: + label: status/pr-needs-author-input + - isActivitySender: + issueAuthor: True + - not: + activitySenderHasPermission: + permission: Write + then: + - reopenIssue + - removeLabel: + label: stale + - removeLabel: + label: status/pr-needs-author-input + description: Revitalize stale PR and reopen + - if: + - payloadType: Pull_Request + - labelAdded: + label: status/pr-needs-author-input + then: + - addReply: + reply: Hi @${issueAuthor}. We have added the `status/pr-needs-author-input` label to this issue, which indicates that we have an open question/action for you before we can take further action. This PRwill be closed automatically in 14 days if we do not hear back from you by then - please feel free to re-open it if you come back to this PR after that time. + description: Add comment when `status/pr-needs-author-input` is applied to PR +onFailure: +onSuccess: From 7f2774e55c95e82a7cdbcfb08488fd1f2baed7ac Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Mon, 25 Mar 2024 19:59:30 +0200 Subject: [PATCH 26/40] Use the new connection string (#2802) --- scripts/azure-pipelines-complete-internal.yml | 28 +++++++- scripts/azure-pipelines.yml | 27 +++++++- scripts/azure-templates-bootstrapper.yml | 7 +- scripts/azure-templates-linux-matrix.yml | 2 + scripts/azure-templates-merger.yml | 2 + scripts/azure-templates-stages.yml | 69 +++++++++++++------ scripts/azure-templates-wasm-matrix.yml | 2 + scripts/install-python.ps1 | 9 +-- 8 files changed, 111 insertions(+), 35 deletions(-) diff --git a/scripts/azure-pipelines-complete-internal.yml b/scripts/azure-pipelines-complete-internal.yml index af2d7e5068..394a5de69d 100644 --- a/scripts/azure-pipelines-complete-internal.yml +++ b/scripts/azure-pipelines-complete-internal.yml @@ -39,8 +39,12 @@ parameters: name: Azure Pipelines vmImage: ubuntu-20.04 os: linux + - name: enableSigning + displayName: 'Enable package signing (Test signing)' + type: boolean + default: false - name: runCompliance - displayName: 'Run post-build compliance tasks (such as API Scan)' + displayName: 'Run post-build compliance tasks (such as API Scan and PoliCheck)' type: boolean default: false - name: use1ESPipelineTemplates @@ -77,7 +81,27 @@ extends: parameters: buildPipelineType: 'both' buildExternals: ${{ parameters.buildExternals }} - runCompliance: ${{ parameters.runCompliance }} + enableSigning: ${{ parameters.enableSigning }} + ${{ if eq(parameters.runCompliance, 'true') }}: + sdl: + apiscan: + enabled: true + binskim: + break: false + codeInspector: + enabled: true + credscan: + suppressionsFile: $(Build.SourcesDirectory)\scripts\guardian\CredScanSuppressions.json + policheck: + enabled: true + exclusionsFile: $(Build.SourcesDirectory)\scripts\guardian\PoliCheckExclusions.xml + spotBugs: + enabled: false + suppression: + suppressionFile: $(Build.SourcesDirectory)\scripts\guardian\source.gdnsuppress + tsa: + enabled: true + configFile: $(Build.SourcesDirectory)\scripts\guardian\tsaoptions-v2.json use1ESPipelineTemplates: ${{ parameters.use1ESPipelineTemplates }} buildAgentHost: ${{ parameters.buildAgentHost }} buildAgentWindows: ${{ parameters.buildAgentWindows }} diff --git a/scripts/azure-pipelines.yml b/scripts/azure-pipelines.yml index c62f4cb874..30e6bcb5e8 100644 --- a/scripts/azure-pipelines.yml +++ b/scripts/azure-pipelines.yml @@ -46,7 +46,7 @@ parameters: image: 1ESPT-Ubuntu20.04 os: linux - name: runCompliance - displayName: 'Run post-build compliance tasks (such as API Scan)' + displayName: 'Run post-build compliance tasks (such as API Scan and PoliCheck)' type: boolean default: false @@ -76,7 +76,30 @@ extends: parameters: buildPipelineType: 'build' buildExternals: ${{ parameters.buildExternals }} - runCompliance: ${{ parameters.runCompliance }} + ${{ if and(eq(variables['System.TeamProject'], 'devdiv'), ne(variables['System.PullRequest.IsFork'], 'true')) }}: + enableSigning: true + ${{ if or(parameters.runCompliance, and(eq(variables['Build.Reason'], 'Schedule'), or(eq(variables['Build.SourceBranch'], 'refs/heads/main'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')))) }}: + sdl: + apiscan: + enabled: true + binskim: + enabled: true + break: false + codeInspector: + enabled: true + credscan: + enabled: true + # suppressionsFile: $(Build.SourcesDirectory)\scripts\guardian\CredScanSuppressions.json + policheck: + enabled: true + exclusionsFile: $(Build.SourcesDirectory)\scripts\guardian\PoliCheckExclusions.xml + spotBugs: + enabled: false + suppression: + suppressionFile: $(Build.SourcesDirectory)\scripts\guardian\source.gdnsuppress + tsa: + enabled: true + configFile: $(Build.SourcesDirectory)\scripts\guardian\tsaoptions-v2.json use1ESPipelineTemplates: true buildAgentHost: ${{ parameters.buildAgentHost }} buildAgentWindows: ${{ parameters.buildAgentWindows }} diff --git a/scripts/azure-templates-bootstrapper.yml b/scripts/azure-templates-bootstrapper.yml index f476be899c..4e9736538e 100644 --- a/scripts/azure-templates-bootstrapper.yml +++ b/scripts/azure-templates-bootstrapper.yml @@ -35,6 +35,7 @@ parameters: skipInstall: false # whether or not to install any tools skipSteps: false # whether or not to run any steps use1ESPipelineTemplates: false # whether or not we are building using the internal 1ES Pipeline Templates + sdl: [] # the SDL properties to use for this job jobs: - job: ${{ parameters.name }} @@ -49,11 +50,7 @@ jobs: ${{ if ne(length(parameters.variables), 0) }}: ${{ parameters.variables }} templateContext: - sdl: - spotBugs: - enabled: false - binskim: - break: false + sdl: ${{ parameters.sdl }} outputParentDirectory: 'output' outputs: - ${{ if eq(parameters.shouldPublish, 'true') }}: diff --git a/scripts/azure-templates-linux-matrix.yml b/scripts/azure-templates-linux-matrix.yml index 980d3e4be5..26681ce2d0 100644 --- a/scripts/azure-templates-linux-matrix.yml +++ b/scripts/azure-templates-linux-matrix.yml @@ -3,6 +3,7 @@ parameters: buildPipelineType: 'both' # the type of build pipeline setup buildAgent: '' # the configuration for the build agent use1ESPipelineTemplates: false # whether or not we are building using the internal 1ES Pipeline Templates + sdl: [] # the SDL properties to use for this job builds: - name: '' desc: '' @@ -24,6 +25,7 @@ jobs: parameters: name: ${{ replace(replace(format('native_linux_{0}_{1}_{2}_{3}_linux', item.arch, item.variant, build.name, item.alt), '__', '_'), '__', '_') }} displayName: Linux ${{ replace(replace(replace(replace(replace(format('({0}|{1}|{2}|{3})', item.arch, item.variant, build.name, item.alt), '||', '|'), '||', '|'), '(|', '('), '|)', ')'), '|', ', ') }} + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgent }} diff --git a/scripts/azure-templates-merger.yml b/scripts/azure-templates-merger.yml index 0e2858571d..23b9eb65c2 100644 --- a/scripts/azure-templates-merger.yml +++ b/scripts/azure-templates-merger.yml @@ -5,12 +5,14 @@ parameters: buildPipelineType: 'both' # the type of build pipeline setup requiredArtifacts: [] # the artifacts that this build needs to download matrixArtifacts: [] # the artifacts that this build needs to download + sdl: [] # the SDL properties to use for this job jobs: - template: /scripts/azure-templates-bootstrapper.yml@self parameters: name: ${{ parameters.name }} displayName: ${{ parameters.displayName }} + sdl: ${{ parameters.sdl }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgent }} skipInstall: true diff --git a/scripts/azure-templates-stages.yml b/scripts/azure-templates-stages.yml index da6fcea289..92863de974 100644 --- a/scripts/azure-templates-stages.yml +++ b/scripts/azure-templates-stages.yml @@ -19,10 +19,19 @@ parameters: type: object - name: buildAgentLinuxNative type: object - - name: runCompliance + - name: sdl + type: object + default: + apiscan: + enabled: false + binskim: + break: false + spotBugs: + enabled: false + - name: use1ESPipelineTemplates type: boolean default: false - - name: use1ESPipelineTemplates + - name: enableSigning type: boolean default: false @@ -56,6 +65,7 @@ stages: parameters: name: native_android_x86_windows displayName: Android x86 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -65,6 +75,7 @@ stages: parameters: name: native_android_x64_windows displayName: Android x64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -74,6 +85,7 @@ stages: parameters: name: native_android_arm_windows displayName: Android arm + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -83,6 +95,7 @@ stages: parameters: name: native_android_arm64_windows displayName: Android arm64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -92,6 +105,7 @@ stages: parameters: name: native_tizen_windows displayName: Tizen + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -100,6 +114,7 @@ stages: parameters: name: native_win32_x86_windows displayName: Win32 x86 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -109,6 +124,7 @@ stages: parameters: name: native_win32_x64_windows displayName: Win32 x64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -118,6 +134,7 @@ stages: parameters: name: native_win32_arm64_windows displayName: Win32 arm64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -127,6 +144,7 @@ stages: parameters: name: native_win32_x86_msvc_windows displayName: Win32 x86 [MSVC] + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -137,6 +155,7 @@ stages: parameters: name: native_win32_x64_msvc_windows displayName: Win32 x64 [MSVC] + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -147,6 +166,7 @@ stages: parameters: name: native_win32_arm64_msvc_windows displayName: Win32 arm64 [MSVC] + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -157,6 +177,7 @@ stages: parameters: name: native_winui_x86_windows displayName: WinUI x86 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -166,6 +187,7 @@ stages: parameters: name: native_winui_x64_windows displayName: WinUI x64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -175,6 +197,7 @@ stages: parameters: name: native_winui_arm64_windows displayName: WinUI arm64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -184,6 +207,7 @@ stages: parameters: name: native_win32_x64_nanoserver_windows displayName: Nano Server x64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -199,6 +223,7 @@ stages: parameters: name: native_android_x86_macos displayName: Android x86 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -208,6 +233,7 @@ stages: parameters: name: native_android_x64_macos displayName: Android x64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -217,6 +243,7 @@ stages: parameters: name: native_android_arm_macos displayName: Android arm + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -226,6 +253,7 @@ stages: parameters: name: native_android_arm64_macos displayName: Android arm64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -235,6 +263,7 @@ stages: parameters: name: native_ios_macos displayName: iOS + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -243,6 +272,7 @@ stages: parameters: name: native_maccatalyst_macos displayName: Mac Catalyst + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -251,6 +281,7 @@ stages: parameters: name: native_macos_macos displayName: macOS + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -259,6 +290,7 @@ stages: parameters: name: native_tvos_macos displayName: tvOS + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -267,6 +299,7 @@ stages: parameters: name: native_tizen_macos displayName: Tizen + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -279,6 +312,7 @@ stages: jobs: - template: /scripts/azure-templates-linux-matrix.yml@self # Build Native Linux (Linux) parameters: + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentLinuxNative }} @@ -319,6 +353,7 @@ stages: jobs: - template: /scripts/azure-templates-wasm-matrix.yml@self # Build Native WASM (Linux) parameters: + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentLinuxNative }} @@ -391,6 +426,7 @@ stages: parameters: name: native displayName: Merge Native Artifacts + sdl: ${{ parameters.sdl }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentHost }} requiredArtifacts: @@ -428,6 +464,7 @@ stages: parameters: name: native_wasm displayName: Merge Native WASM Artifacts + sdl: ${{ parameters.sdl }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentHost }} matrixArtifacts: @@ -437,6 +474,7 @@ stages: parameters: name: native_msvc displayName: Merge Native MSVC Artifacts + sdl: ${{ parameters.sdl }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentHost }} requiredArtifacts: @@ -502,6 +540,7 @@ stages: parameters: name: package_normal_windows displayName: Package NuGets + sdl: ${{ parameters.sdl }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindows}} target: nuget-normal @@ -531,6 +570,7 @@ stages: parameters: name: package_special_windows displayName: Package Special NuGets + sdl: ${{ parameters.sdl }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindows}} dependsOn: package_normal_windows @@ -586,7 +626,7 @@ stages: always: true path: '$(Build.SourcesDirectory)\changelogs' - - ${{ if and(eq(variables['System.TeamProject'], 'devdiv'), ne(parameters.buildPipelineType, 'tests'), ne(variables['System.PullRequest.IsFork'], 'true')) }}: + - ${{ if eq(parameters.enableSigning, 'true') }}: - stage: signing displayName: Sign NuGets dependsOn: package @@ -909,33 +949,22 @@ stages: installEmsdk: true initScript: source ~/emsdk/emsdk_env.sh - - ${{ if and(eq(variables['System.TeamProject'], 'devdiv'), ne(parameters.buildPipelineType, 'tests'), ne(variables['System.PullRequest.IsFork'], 'true'), or(and(eq(variables['Build.Reason'], 'Schedule'), or(eq(variables['Build.SourceBranch'], 'refs/heads/main'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'))), parameters.runCompliance)) }}: - - template: security/full/v1.yml@xamarin-templates + - ${{ if eq(parameters.sdl.apiscan.enabled, 'true') }}: + - template: security/apiscan/v0.yml@xamarin-templates parameters: - stageDependsOn: - - package - complianceEnabled: true - complianceTimeoutInMinutes: 480 windowsPoolName: ${{ parameters.buildAgentHost.pool.name }} windowsImageOverride: ${{ parameters.buildAgentHost.pool.image }} + timeoutInMinutes: 480 + stageDependsOn: + - package scanArtifacts: - nuget - nuget_symbols - native_msvc - antiMalwareEnabled: true - binSkimEnabled: false - policheckExclusionFile: $(Build.SourcesDirectory)\scripts\guardian\PoliCheckExclusions.xml - policheckGdnSuppressionFilesFolder: $(Build.SourcesDirectory)\scripts\guardian - credScanEnabled: true - credScanSuppressionFile: $(Build.SourcesDirectory)\scripts\guardian\CredScanSuppressions.json - sourceGdnSuppressionFile: $(Build.SourcesDirectory)\scripts\guardian\source.gdnsuppress - tsaConfigFile: $(Build.SourcesDirectory)\scripts\guardian\tsaoptions-v2.json - tsaReportBranch: $(Build.SourceBranch) - enableCodeInspector: true - apiScanEnabled: true apiScanSoftwareName: 'SkiaSharp' apiScanSoftwareVersionNum: $(SKIASHARP_MAJOR_VERSION) apiScanPreserveLogsFolder: true + apiScanAuthConnectionString: 'runAs=App;AppId=$(ApiScanClientId)' apiScanSurrogateConfigurationFolder: $(Build.ArtifactStagingDirectory)\APIScanSurrogates preScanSteps: - pwsh: | diff --git a/scripts/azure-templates-wasm-matrix.yml b/scripts/azure-templates-wasm-matrix.yml index bbceb72be2..9a383a54b5 100644 --- a/scripts/azure-templates-wasm-matrix.yml +++ b/scripts/azure-templates-wasm-matrix.yml @@ -3,6 +3,7 @@ parameters: buildPipelineType: 'both' # the type of build pipeline setup buildAgent: '' # the configuration for the build agent use1ESPipelineTemplates: false # whether or not we are building using the internal 1ES Pipeline Templates + sdl: [] # the SDL properties to use for this job emscripten: [ ] jobs: @@ -11,6 +12,7 @@ jobs: parameters: name: native_wasm_${{ replace(version.displayName, '.', '_') }}_linux displayName: WASM (${{ version.displayName }}) + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgent }} diff --git a/scripts/install-python.ps1 b/scripts/install-python.ps1 index 029a0869c7..6002b96e5e 100644 --- a/scripts/install-python.ps1 +++ b/scripts/install-python.ps1 @@ -31,12 +31,9 @@ if ($IsMacOS) { } else { $platform = "win32" } - -$downloadUrl = (($pythonManifest - | Where-Object { $_.version -eq $Version } - | Select-Object -First 1).files - | Where-Object { $_.platform -eq $platform -and $_.arch -eq $Arch } - | Select-Object -First 1).download_url +$manifestFileVersion = $pythonManifest | Where-Object { $_.version -eq $Version } | Select-Object -First 1 +$manifestFileItem = $manifestFileVersion.files | Where-Object { $_.platform -eq $platform -and $_.arch -eq $Arch } | Select-Object -First 1 +$downloadUrl = $manifestFileItem.download_url # download $tempDir = Join-Path "$HOME_DIR" "python-temp" From 7fe63492371a5eeb5871a04ac0663d5e25cbc8d6 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Wed, 27 Mar 2024 16:31:22 +0200 Subject: [PATCH 27/40] Scan the correct things correctly (#2808) --- scripts/azure-templates-stages.yml | 62 ++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/scripts/azure-templates-stages.yml b/scripts/azure-templates-stages.yml index 92863de974..b39f34db49 100644 --- a/scripts/azure-templates-stages.yml +++ b/scripts/azure-templates-stages.yml @@ -545,27 +545,41 @@ stages: buildAgent: ${{ parameters.buildAgentWindows}} target: nuget-normal additionalArgs: --skipExternals="all" + shouldPublish: false requiredArtifacts: - name: native postBuildSteps: - - pwsh: Remove-Item ./output/native/ -Recurse -Force -ErrorAction Continue - displayName: Delete the native folder - pwsh: | - New-Item '$(Build.ArtifactStagingDirectory)\nugets\' -Type Directory -Force | Out-Null - Get-ChildItem '.\output\nugets\' | Copy-Item -Destination '$(Build.ArtifactStagingDirectory)\nugets\' -Recurse -Force - Copy-Item -Path '.\scripts\SignList.xml' -Destination '$(Build.ArtifactStagingDirectory)\nugets\' - Remove-Item '.\output\nugets\' -Recurse -Force - displayName: Move the nugets artifact to the staging directory + Remove-Item ./output/native/ -Recurse -Force -ErrorAction Continue + Move-Item -Path '.\output\' -Destination '$(Build.ArtifactStagingDirectory)\output\' + New-Item '.\output\' -Type Directory -Force | Out-Null + displayName: Re-organize the output folder for publishing + - pwsh: | + Move-Item -Path '$(Build.ArtifactStagingDirectory)\output\nugets\' -Destination '.\output\' + Copy-Item -Path '.\scripts\SignList.xml' -Destination '.\output\nugets\' + displayName: Prepare the nugets artifact for publishing - pwsh: | - New-Item '$(Build.ArtifactStagingDirectory)\nugets-symbols\' -Type Directory -Force | Out-Null - Get-ChildItem '.\output\nugets-symbols\' | Copy-Item -Destination '$(Build.ArtifactStagingDirectory)\nugets-symbols\' -Recurse -Force - Remove-Item '.\output\nugets-symbols\' -Recurse -Force - displayName: Move the nugets-symbols artifact to the staging directory + Move-Item -Path '$(Build.ArtifactStagingDirectory)\output\nugets-symbols\' -Destination '.\output\' + displayName: Prepare the nugets-symbols artifact for publishing + - pwsh: | + Move-Item -Path '$(Build.ArtifactStagingDirectory)\output\' -Destination '.\output\' + displayName: Prepare the build artifact for publishing + - pwsh: | + $nupkgs = (Get-ChildItem ".\output\nugets*\*.*nupkg") + foreach ($nupkg in $nupkgs) { + $filename = $nupkg.Name.TrimEnd('.nupkg') + $dest = ".\output\extracted_nugets\$filename" + Write-Host "Extracting '$nupkg' to '$dest'..." + Expand-Archive $nupkg $dest + } + displayName: Extract all the .nupkg files for scanning publishArtifacts: + - name: package_normal_windows + path: '.\output\output\' - name: nuget - path: '$(Build.ArtifactStagingDirectory)\nugets' + path: '.\output\nugets' - name: nuget_symbols - path: '$(Build.ArtifactStagingDirectory)\nugets-symbols' + path: '.\output\nugets-symbols' - template: /scripts/azure-templates-bootstrapper.yml@self # Package Special NuGets parameters: name: package_special_windows @@ -576,6 +590,7 @@ stages: dependsOn: package_normal_windows target: nuget-special additionalArgs: --skipExternals="all" --exclusive + shouldPublish: false requiredArtifacts: - name: nuget dir: nugets @@ -583,17 +598,22 @@ stages: dir: nugets-symbols postBuildSteps: - pwsh: | - New-Item '$(Build.ArtifactStagingDirectory)\nugets-special\' -Type Directory -Force | Out-Null - Get-ChildItem '.\output\nugets-special\' | Copy-Item -Destination '$(Build.ArtifactStagingDirectory)\nugets-special\' -Recurse -Force - Remove-Item '.\output\nugets-special\' -Recurse -Force - displayName: Move the nugets-special artifact to the staging directory + Remove-Item ./output/nugets/ -Recurse -Force -ErrorAction Continue + Remove-Item ./output/nugets-symbols/ -Recurse -Force -ErrorAction Continue + Move-Item -Path '.\output\' -Destination '$(Build.ArtifactStagingDirectory)\output\' + New-Item '.\output\' -Type Directory -Force | Out-Null + displayName: Re-organize the output folder for publishing + - pwsh: | + Move-Item -Path '$(Build.ArtifactStagingDirectory)\output\nugets-special\' -Destination '.\output\' + displayName: Prepare the nugets-special artifact for publishing - pwsh: | - Remove-Item ./output/nugets/ -Recurse -Force - Remove-Item ./output/nugets-symbols/ -Recurse -Force - displayName: Delete the downloaded artifacts + Move-Item -Path '$(Build.ArtifactStagingDirectory)\output\' -Destination '.\output\' + displayName: Prepare the build artifact for publishing publishArtifacts: + - name: package_special_windows + path: '.\output\output\' - name: nuget_special - path: '$(Build.ArtifactStagingDirectory)\nugets-special' + path: '.\output\nugets-special' - ${{ if ne(parameters.buildPipelineType, 'build') }}: - stage: api_diff From ba0135c12a9ef08f846c0508959c131e70f1621b Mon Sep 17 00:00:00 2001 From: gmurray81 Date: Thu, 28 Mar 2024 10:11:22 -0400 Subject: [PATCH 28/40] Add SKGLElement to SkiaSharp.Views.WPF (#2317) * add SKGLElement * revert unintentional change to build props * fix bad merge * remove whitespace diff * update package conditional, remove obselete member * update to newer glwpfcontrol version * prevent opentk from automatically registering events * simplify releasing the managed resources * remove unecessary duplicate clear * block signing for OpenTK 4+ --- .../SkiaSharp.Views.WPF/SKGLElement.cs | 221 ++++++++++++++++++ .../SkiaSharp.Views.WPF.csproj | 9 + 2 files changed, 230 insertions(+) create mode 100644 source/SkiaSharp.Views/SkiaSharp.Views.WPF/SKGLElement.cs diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SKGLElement.cs b/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SKGLElement.cs new file mode 100644 index 0000000000..00993eab5d --- /dev/null +++ b/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SKGLElement.cs @@ -0,0 +1,221 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using OpenTK.Graphics; +using System.Windows.Media.Media3D; +using SkiaSharp.Views.Desktop; +using OpenTK.Wpf; +using SkiaSharp; +using OpenTK.Graphics.OpenGL; +using OpenTK.Platform.Windows; +using OpenTK; +using System.Windows.Interop; +using OpenTK.Platform; +#if NETCOREAPP || NET +using OpenTK.Mathematics; +#endif + +namespace SkiaSharp.Views.WPF +{ + [DefaultEvent("PaintSurface")] + [DefaultProperty("Name")] + public class SKGLElement : GLWpfControl, IDisposable + { + private const SKColorType colorType = SKColorType.Rgba8888; + private const GRSurfaceOrigin surfaceOrigin = GRSurfaceOrigin.BottomLeft; + + private bool designMode; + + private GRContext grContext; + private GRGlFramebufferInfo glInfo; + private GRBackendRenderTarget renderTarget; + private SKSurface surface; + private SKCanvas canvas; + + private SKSizeI lastSize; + + public SKGLElement() + : base() + { + Initialize(); + } + + private void Initialize() + { + designMode = DesignerProperties.GetIsInDesignMode(this); + var settings = new GLWpfControlSettings() { MajorVersion = 2, MinorVersion = 1, RenderContinuously = false }; + + this.Render += OnPaint; + + this.Loaded += SKGLElement_Loaded; + this.Unloaded += SKGLElement_Unloaded; + +#if NETCOREAPP + this.RegisterToEventsDirectly = false; +#endif + + Start(settings); + } + + private void SKGLElement_Unloaded(object sender, RoutedEventArgs e) + { + Release(); + } + private void SKGLElement_Loaded(object sender, RoutedEventArgs e) + { + InvalidateVisual(); + } + + public SKSize CanvasSize => lastSize; + + public GRContext GRContext => grContext; + + [Category("Appearance")] + public event EventHandler PaintSurface; + + private SKSizeI GetSize() + { + var currentWidth = ActualWidth; + var currentHeight = ActualHeight; + + if (currentWidth < 0 || + currentHeight < 0) + { + currentWidth = 0; + currentHeight = 0; + } + + PresentationSource source = PresentationSource.FromVisual(this); + + double dpiX = 1.0; + double dpiY = 1.0; + if (source != null) + { + dpiX = source.CompositionTarget.TransformToDevice.M11; + dpiY = source.CompositionTarget.TransformToDevice.M22; + } + + return new SKSizeI((int)(currentWidth * dpiX), (int)(currentHeight * dpiY)); + } + + protected override void OnRender(DrawingContext drawingContext) + { + if (grContext != null) + { + grContext.ResetContext(); + } + base.OnRender(drawingContext); + } + + protected virtual void OnPaint(TimeSpan e) + { + if (disposed) + { + return; + } + if (designMode) + { + return; + } + + // create the contexts if not done already + if (grContext == null) + { + var glInterface = GRGlInterface.Create(); + grContext = GRContext.CreateGl(glInterface); + } + + // get the new surface size + var newSize = GetSize(); + + GL.ClearColor(Color4.Transparent); + GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit); + + // manage the drawing surface + if (renderTarget == null || lastSize != newSize || !renderTarget.IsValid) + { + + // create or update the dimensions + lastSize = newSize; + + GL.GetInteger(GetPName.FramebufferBinding, out var framebuffer); + GL.GetInteger(GetPName.StencilBits, out var stencil); + GL.GetInteger(GetPName.Samples, out var samples); + var maxSamples = grContext.GetMaxSurfaceSampleCount(colorType); + if (samples > maxSamples) + samples = maxSamples; + glInfo = new GRGlFramebufferInfo((uint)framebuffer, colorType.ToGlSizedFormat()); + + // destroy the old surface + surface?.Dispose(); + surface = null; + canvas = null; + + // re-create the render target + renderTarget?.Dispose(); + renderTarget = new GRBackendRenderTarget(newSize.Width, newSize.Height, samples, stencil, glInfo); + } + + // create the surface + if (surface == null) + { + surface = SKSurface.Create(grContext, renderTarget, surfaceOrigin, colorType); + canvas = surface.Canvas; + } + + using (new SKAutoCanvasRestore(canvas, true)) + { + // start drawing + OnPaintSurface(new SKPaintGLSurfaceEventArgs(surface, renderTarget, surfaceOrigin, colorType)); + } + + // update the control + canvas.Flush(); + } + + protected virtual void OnPaintSurface(SKPaintGLSurfaceEventArgs e) + { + // invoke the event + PaintSurface?.Invoke(this, e); + } + + private bool disposed = false; + + + protected virtual void Dispose(bool disposing) + { + if (disposed) + { + return; + } + + Release(); + + disposed = true; + } + + private void Release() + { + canvas = null; + surface?.Dispose(); + surface = null; + renderTarget?.Dispose(); + renderTarget = null; + grContext?.Dispose(); + grContext = null; + } + + public void Dispose() + { + Dispose(true); + } + } + +} diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SkiaSharp.Views.WPF.csproj b/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SkiaSharp.Views.WPF.csproj index 8108387533..cc8ba3e40c 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SkiaSharp.Views.WPF.csproj +++ b/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SkiaSharp.Views.WPF.csproj @@ -7,8 +7,17 @@ SkiaSharp.Views.WPF $(DefineConstants);__DESKTOP__;__WPF__ SkiaSharp Views & Layers for Windows Presentation Foundation (WPF) + false wpf + + + + + + + + From 99a2607fd3c1b563a2c0663d8349d26d4f26373d Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Fri, 29 Mar 2024 00:34:20 +0200 Subject: [PATCH 29/40] Clean up SKTextBlobBuilder and SKRunBuffer APIs (#2775) --- binding/SkiaSharp/SKRunBuffer.cs | 130 ++++++++---- binding/SkiaSharp/SKTextBlob.cs | 196 +++++++++++------- .../SkiaSharp.HarfBuzz/CanvasExtensions.cs | 6 +- tests/Tests/SkiaSharp/SKTextBlobTest.cs | 51 ++++- 4 files changed, 252 insertions(+), 131 deletions(-) diff --git a/binding/SkiaSharp/SKRunBuffer.cs b/binding/SkiaSharp/SKRunBuffer.cs index 8f4916104e..65831136ef 100644 --- a/binding/SkiaSharp/SKRunBuffer.cs +++ b/binding/SkiaSharp/SKRunBuffer.cs @@ -1,10 +1,11 @@ #nullable disable using System; -using System.ComponentModel; namespace SkiaSharp { + // Base + public unsafe class SKRunBuffer { internal readonly SKRunBufferInternal internalBuffer; @@ -17,103 +18,142 @@ internal SKRunBuffer (SKRunBufferInternal buffer, int size) public int Size { get; } - public Span GetGlyphSpan () => - new Span (internalBuffer.glyphs, internalBuffer.glyphs == null ? 0 : Size); + public Span Glyphs => new (internalBuffer.glyphs, Size); + + public void SetGlyphs (ReadOnlySpan glyphs) => glyphs.CopyTo (Glyphs); - public void SetGlyphs (ReadOnlySpan glyphs) => - glyphs.CopyTo (GetGlyphSpan ()); + [Obsolete ("Use Glyphs instead.")] + public Span GetGlyphSpan () => Glyphs; } public sealed unsafe class SKHorizontalRunBuffer : SKRunBuffer { - internal SKHorizontalRunBuffer (SKRunBufferInternal buffer, int count) - : base (buffer, count) + internal SKHorizontalRunBuffer (SKRunBufferInternal buffer, int size) + : base (buffer, size) { } - public Span GetPositionSpan () => - new Span (internalBuffer.pos, internalBuffer.pos == null ? 0 : Size); + public Span Positions => new (internalBuffer.pos, Size); - public void SetPositions (ReadOnlySpan positions) => - positions.CopyTo (GetPositionSpan ()); + public void SetPositions (ReadOnlySpan positions) => positions.CopyTo (Positions); + + [Obsolete ("Use Positions instead.")] + public Span GetPositionSpan () => Positions; } public sealed unsafe class SKPositionedRunBuffer : SKRunBuffer { - internal SKPositionedRunBuffer (SKRunBufferInternal buffer, int count) - : base (buffer, count) + internal SKPositionedRunBuffer (SKRunBufferInternal buffer, int size) + : base (buffer, size) { } - public Span GetPositionSpan () => - new Span (internalBuffer.pos, internalBuffer.pos == null ? 0 : Size); + public Span Positions => new (internalBuffer.pos, Size); + + public void SetPositions (ReadOnlySpan positions) => positions.CopyTo (Positions); - public void SetPositions (ReadOnlySpan positions) => - positions.CopyTo (GetPositionSpan ()); + [Obsolete ("Use Positions instead.")] + public Span GetPositionSpan () => Positions; } public sealed unsafe class SKRotationScaleRunBuffer : SKRunBuffer { - internal SKRotationScaleRunBuffer (SKRunBufferInternal buffer, int count) - : base (buffer, count) + internal SKRotationScaleRunBuffer (SKRunBufferInternal buffer, int size) + : base (buffer, size) { } - public Span GetRotationScaleSpan () => - new Span (internalBuffer.pos, Size); + public Span Positions => new (internalBuffer.pos, Size); - public void SetRotationScale (ReadOnlySpan positions) => - positions.CopyTo (GetRotationScaleSpan ()); + public void SetPositions (ReadOnlySpan positions) => positions.CopyTo (Positions); + + [Obsolete ("Use Positions instead.")] + public Span GetRotationScaleSpan () => Positions; + + [Obsolete ("Use SetPositions instead.")] + public void SetRotationScale (ReadOnlySpan positions) => SetPositions (positions); } + // Text + public unsafe class SKTextRunBuffer : SKRunBuffer { - internal SKTextRunBuffer (SKRunBufferInternal buffer, int count, int textSize) - : base (buffer, count) + internal SKTextRunBuffer (SKRunBufferInternal buffer, int size, int textSize) + : base (buffer, size) { TextSize = textSize; } public int TextSize { get; } - public Span GetTextSpan () => - new Span (internalBuffer.utf8text, internalBuffer.utf8text == null ? 0 : TextSize); + public Span Text => new (internalBuffer.utf8text, TextSize); - public Span GetClusterSpan () => - new Span (internalBuffer.clusters, internalBuffer.clusters == null ? 0 : Size); + public Span Clusters => new (internalBuffer.clusters, Size); - public void SetText (ReadOnlySpan text) => - text.CopyTo (GetTextSpan ()); + public void SetText (ReadOnlySpan text) => text.CopyTo (Text); - public void SetClusters (ReadOnlySpan clusters) => - clusters.CopyTo (GetClusterSpan ()); + public void SetClusters (ReadOnlySpan clusters) => clusters.CopyTo (Clusters); } public sealed unsafe class SKHorizontalTextRunBuffer : SKTextRunBuffer { - internal SKHorizontalTextRunBuffer (SKRunBufferInternal buffer, int count, int textSize) - : base (buffer, count, textSize) + internal SKHorizontalTextRunBuffer (SKRunBufferInternal buffer, int size, int textSize) + : base (buffer, size, textSize) { } - public Span GetPositionSpan () => - new Span (internalBuffer.pos, internalBuffer.pos == null ? 0 : Size); + public Span Positions => new (internalBuffer.pos, Size); - public void SetPositions (ReadOnlySpan positions) => - positions.CopyTo (GetPositionSpan ()); + public void SetPositions (ReadOnlySpan positions) => positions.CopyTo (Positions); } public sealed unsafe class SKPositionedTextRunBuffer : SKTextRunBuffer { - internal SKPositionedTextRunBuffer (SKRunBufferInternal buffer, int count, int textSize) - : base (buffer, count, textSize) + internal SKPositionedTextRunBuffer (SKRunBufferInternal buffer, int size, int textSize) + : base (buffer, size, textSize) { } - public Span GetPositionSpan () => - new Span (internalBuffer.pos, internalBuffer.pos == null ? 0 : Size); + public Span Positions => new (internalBuffer.pos, Size); + + public void SetPositions (ReadOnlySpan positions) => positions.CopyTo (Positions); + } + + public sealed unsafe class SKRotationScaleTextRunBuffer : SKTextRunBuffer + { + internal SKRotationScaleTextRunBuffer (SKRunBufferInternal buffer, int size, int textSize) + : base (buffer, size, textSize) + { + } + + public Span Positions => new (internalBuffer.pos, Size); + + public void SetPositions (ReadOnlySpan positions) => positions.CopyTo (Positions); + } + + // Raw / Struct + + public unsafe readonly struct SKRawRunBuffer + { + internal readonly SKRunBufferInternal buffer; + private readonly int size; + private readonly int posSize; + private readonly int textSize; + + internal SKRawRunBuffer (SKRunBufferInternal buffer, int size, int posSize, int textSize) + { + this.buffer = buffer; + this.size = size; + this.posSize = posSize; + this.textSize = textSize; + } + + public Span Glyphs => new (buffer.glyphs, size); + + public Span Positions => new (buffer.pos, posSize); + + public Span Text => new (buffer.utf8text, textSize); - public void SetPositions (ReadOnlySpan positions) => - positions.CopyTo (GetPositionSpan ()); + public Span Clusters => new (buffer.clusters, size); } } diff --git a/binding/SkiaSharp/SKTextBlob.cs b/binding/SkiaSharp/SKTextBlob.cs index 704b3e95b8..10193d25a0 100644 --- a/binding/SkiaSharp/SKTextBlob.cs +++ b/binding/SkiaSharp/SKTextBlob.cs @@ -1,7 +1,4 @@ -#nullable disable - -using System; -using System.ComponentModel; +using System; namespace SkiaSharp { @@ -31,27 +28,27 @@ public SKRect Bounds { // Create - public static SKTextBlob Create (string text, SKFont font, SKPoint origin = default) => + public static SKTextBlob? Create (string text, SKFont font, SKPoint origin = default) => Create (text.AsSpan (), font, origin); - public static SKTextBlob Create (ReadOnlySpan text, SKFont font, SKPoint origin = default) + public static SKTextBlob? Create (ReadOnlySpan text, SKFont font, SKPoint origin = default) { fixed (void* t = text) { return Create (t, text.Length * 2, SKTextEncoding.Utf16, font, origin); } } - public static SKTextBlob Create (IntPtr text, int length, SKTextEncoding encoding, SKFont font, SKPoint origin = default) => + public static SKTextBlob? Create (IntPtr text, int length, SKTextEncoding encoding, SKFont font, SKPoint origin = default) => Create (text.AsReadOnlySpan (length), encoding, font, origin); - public static SKTextBlob Create (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, SKPoint origin = default) + public static SKTextBlob? Create (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, SKPoint origin = default) { fixed (void* t = text) { return Create (t, text.Length, encoding, font, origin); } } - internal static SKTextBlob Create (void* text, int length, SKTextEncoding encoding, SKFont font, SKPoint origin) + internal static SKTextBlob? Create (void* text, int length, SKTextEncoding encoding, SKFont font, SKPoint origin) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -61,35 +58,35 @@ internal static SKTextBlob Create (void* text, int length, SKTextEncoding encodi return null; using var builder = new SKTextBlobBuilder (); - var buffer = builder.AllocatePositionedRun (font, count); - font.GetGlyphs (text, length, encoding, buffer.GetGlyphSpan ()); - font.GetGlyphPositions (buffer.GetGlyphSpan (), buffer.GetPositionSpan (), origin); + var buffer = builder.AllocateRawPositionedRun (font, count); + font.GetGlyphs (text, length, encoding, buffer.Glyphs); + font.GetGlyphPositions (buffer.Glyphs, buffer.Positions, origin); return builder.Build (); } // CreateHorizontal - public static SKTextBlob CreateHorizontal (string text, SKFont font, ReadOnlySpan positions, float y) => + public static SKTextBlob? CreateHorizontal (string text, SKFont font, ReadOnlySpan positions, float y) => CreateHorizontal (text.AsSpan (), font, positions, y); - public static SKTextBlob CreateHorizontal (ReadOnlySpan text, SKFont font, ReadOnlySpan positions, float y) + public static SKTextBlob? CreateHorizontal (ReadOnlySpan text, SKFont font, ReadOnlySpan positions, float y) { fixed (void* t = text) { return CreateHorizontal (t, text.Length * 2, SKTextEncoding.Utf16, font, positions, y); } } - public static SKTextBlob CreateHorizontal (IntPtr text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions, float y) => + public static SKTextBlob? CreateHorizontal (IntPtr text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions, float y) => CreateHorizontal (text.AsReadOnlySpan (length), encoding, font, positions, y); - public static SKTextBlob CreateHorizontal (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions, float y) + public static SKTextBlob? CreateHorizontal (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions, float y) { fixed (void* t = text) { return CreateHorizontal (t, text.Length, encoding, font, positions, y); } } - internal static SKTextBlob CreateHorizontal (void* text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions, float y) + internal static SKTextBlob? CreateHorizontal (void* text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions, float y) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -99,35 +96,35 @@ internal static SKTextBlob CreateHorizontal (void* text, int length, SKTextEncod return null; using var builder = new SKTextBlobBuilder (); - var buffer = builder.AllocateHorizontalRun (font, count, y); - font.GetGlyphs (text, length, encoding, buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetPositionSpan ()); + var buffer = builder.AllocateRawHorizontalRun (font, count, y); + font.GetGlyphs (text, length, encoding, buffer.Glyphs); + positions.CopyTo (buffer.Positions); return builder.Build (); } // CreatePositioned - public static SKTextBlob CreatePositioned (string text, SKFont font, ReadOnlySpan positions) => + public static SKTextBlob? CreatePositioned (string text, SKFont font, ReadOnlySpan positions) => CreatePositioned (text.AsSpan (), font, positions); - public static SKTextBlob CreatePositioned (ReadOnlySpan text, SKFont font, ReadOnlySpan positions) + public static SKTextBlob? CreatePositioned (ReadOnlySpan text, SKFont font, ReadOnlySpan positions) { fixed (void* t = text) { return CreatePositioned (t, text.Length * 2, SKTextEncoding.Utf16, font, positions); } } - public static SKTextBlob CreatePositioned (IntPtr text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) => + public static SKTextBlob? CreatePositioned (IntPtr text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) => CreatePositioned (text.AsReadOnlySpan (length), encoding, font, positions); - public static SKTextBlob CreatePositioned (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) + public static SKTextBlob? CreatePositioned (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) { fixed (void* t = text) { return CreatePositioned (t, text.Length, encoding, font, positions); } } - internal static SKTextBlob CreatePositioned (void* text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) + internal static SKTextBlob? CreatePositioned (void* text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -137,35 +134,35 @@ internal static SKTextBlob CreatePositioned (void* text, int length, SKTextEncod return null; using var builder = new SKTextBlobBuilder (); - var buffer = builder.AllocatePositionedRun (font, count); - font.GetGlyphs (text, length, encoding, buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetPositionSpan ()); + var buffer = builder.AllocateRawPositionedRun (font, count); + font.GetGlyphs (text, length, encoding, buffer.Glyphs); + positions.CopyTo (buffer.Positions); return builder.Build (); } // CreateRotationScale - public static SKTextBlob CreateRotationScale (string text, SKFont font, ReadOnlySpan positions) => + public static SKTextBlob? CreateRotationScale (string text, SKFont font, ReadOnlySpan positions) => CreateRotationScale (text.AsSpan (), font, positions); - public static SKTextBlob CreateRotationScale (ReadOnlySpan text, SKFont font, ReadOnlySpan positions) + public static SKTextBlob? CreateRotationScale (ReadOnlySpan text, SKFont font, ReadOnlySpan positions) { fixed (void* t = text) { return CreateRotationScale (t, text.Length * 2, SKTextEncoding.Utf16, font, positions); } } - public static SKTextBlob CreateRotationScale (IntPtr text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) => + public static SKTextBlob? CreateRotationScale (IntPtr text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) => CreateRotationScale (text.AsReadOnlySpan (length), encoding, font, positions); - public static SKTextBlob CreateRotationScale (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) + public static SKTextBlob? CreateRotationScale (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) { fixed (void* t = text) { return CreateRotationScale (t, text.Length, encoding, font, positions); } } - internal static SKTextBlob CreateRotationScale (void* text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) + internal static SKTextBlob? CreateRotationScale (void* text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -176,34 +173,34 @@ internal static SKTextBlob CreateRotationScale (void* text, int length, SKTextEn using var builder = new SKTextBlobBuilder (); var buffer = builder.AllocateRotationScaleRun (font, count); - font.GetGlyphs (text, length, encoding, buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetRotationScaleSpan ()); + font.GetGlyphs (text, length, encoding, buffer.Glyphs); + positions.CopyTo (buffer.Positions); return builder.Build (); } // CreatePathPositioned - public static SKTextBlob CreatePathPositioned (string text, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) => + public static SKTextBlob? CreatePathPositioned (string text, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) => CreatePathPositioned (text.AsSpan (), font, path, textAlign, origin); - public static SKTextBlob CreatePathPositioned (ReadOnlySpan text, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) + public static SKTextBlob? CreatePathPositioned (ReadOnlySpan text, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) { fixed (void* t = text) { return CreatePathPositioned (t, text.Length * 2, SKTextEncoding.Utf16, font, path, textAlign, origin); } } - public static SKTextBlob CreatePathPositioned (IntPtr text, int length, SKTextEncoding encoding, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) => + public static SKTextBlob? CreatePathPositioned (IntPtr text, int length, SKTextEncoding encoding, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) => CreatePathPositioned (text.AsReadOnlySpan (length), encoding, font, path, textAlign, origin); - public static SKTextBlob CreatePathPositioned (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) + public static SKTextBlob? CreatePathPositioned (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) { fixed (void* t = text) { return CreatePathPositioned (t, text.Length, encoding, font, path, textAlign, origin); } } - internal static SKTextBlob CreatePathPositioned (void* text, int length, SKTextEncoding encoding, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) + internal static SKTextBlob? CreatePathPositioned (void* text, int length, SKTextEncoding encoding, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -228,7 +225,7 @@ internal static SKTextBlob CreatePathPositioned (void* text, int length, SKTextE // GetIntercepts - public float[] GetIntercepts (float upperBounds, float lowerBounds, SKPaint paint = null) + public float[] GetIntercepts (float upperBounds, float lowerBounds, SKPaint? paint = null) { var n = CountIntercepts (upperBounds, lowerBounds, paint); var intervals = new float[n]; @@ -236,7 +233,7 @@ public float[] GetIntercepts (float upperBounds, float lowerBounds, SKPaint pain return intervals; } - public void GetIntercepts (float upperBounds, float lowerBounds, Span intervals, SKPaint paint = null) + public void GetIntercepts (float upperBounds, float lowerBounds, Span intervals, SKPaint? paint = null) { var bounds = stackalloc float[2]; bounds[0] = upperBounds; @@ -248,7 +245,7 @@ public void GetIntercepts (float upperBounds, float lowerBounds, Span int // CountIntercepts - public int CountIntercepts (float upperBounds, float lowerBounds, SKPaint paint = null) + public int CountIntercepts (float upperBounds, float lowerBounds, SKPaint? paint = null) { var bounds = stackalloc float[2]; bounds[0] = upperBounds; @@ -258,7 +255,7 @@ public int CountIntercepts (float upperBounds, float lowerBounds, SKPaint paint // - internal static SKTextBlob GetObject (IntPtr handle) => + internal static SKTextBlob? GetObject (IntPtr handle) => handle == IntPtr.Zero ? null : new SKTextBlob (handle, true); } @@ -282,7 +279,7 @@ protected override void DisposeNative () => // Build - public SKTextBlob Build () + public SKTextBlob? Build () { var blob = SKTextBlob.GetObject (SkiaApi.sk_textblob_builder_make (Handle)); GC.KeepAlive (this); @@ -293,48 +290,36 @@ public SKTextBlob Build () public void AddRun (ReadOnlySpan glyphs, SKFont font, SKPoint origin = default) { - if (font == null) - throw new ArgumentNullException (nameof (font)); - - var buffer = AllocatePositionedRun (font, glyphs.Length); - glyphs.CopyTo (buffer.GetGlyphSpan ()); - font.GetGlyphPositions (buffer.GetGlyphSpan (), buffer.GetPositionSpan (), origin); + var buffer = AllocateRawPositionedRun (font, glyphs.Length); + glyphs.CopyTo (buffer.Glyphs); + font.GetGlyphPositions (buffer.Glyphs, buffer.Positions, origin); } // AddHorizontalRun public void AddHorizontalRun (ReadOnlySpan glyphs, SKFont font, ReadOnlySpan positions, float y) { - if (font == null) - throw new ArgumentNullException (nameof (font)); - - var buffer = AllocateHorizontalRun (font, glyphs.Length, y); - glyphs.CopyTo (buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetPositionSpan ()); + var buffer = AllocateRawHorizontalRun (font, glyphs.Length, y); + glyphs.CopyTo (buffer.Glyphs); + positions.CopyTo (buffer.Positions); } // AddPositionedRun public void AddPositionedRun (ReadOnlySpan glyphs, SKFont font, ReadOnlySpan positions) { - if (font == null) - throw new ArgumentNullException (nameof (font)); - - var buffer = AllocatePositionedRun (font, glyphs.Length); - glyphs.CopyTo (buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetPositionSpan ()); + var buffer = AllocateRawPositionedRun (font, glyphs.Length); + glyphs.CopyTo (buffer.Glyphs); + positions.CopyTo (buffer.Positions); } // AddRotationScaleRun public void AddRotationScaleRun (ReadOnlySpan glyphs, SKFont font, ReadOnlySpan positions) { - if (font == null) - throw new ArgumentNullException (nameof (font)); - - var buffer = AllocateRotationScaleRun (font, glyphs.Length); - glyphs.CopyTo (buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetRotationScaleSpan ()); + var buffer = AllocateRawRotationScaleRun (font, glyphs.Length); + glyphs.CopyTo (buffer.Glyphs); + positions.CopyTo (buffer.Positions); } // AddPathPositionedRun @@ -390,9 +375,17 @@ public void AddPathPositionedRun (ReadOnlySpan glyphs, SKFont font, Read AddRotationScaleRun (glyphSubset, font, positions); } - // AllocateRun + // Allocate* + + // Allocate*Run public SKRunBuffer AllocateRun (SKFont font, int count, float x, float y, SKRect? bounds = null) + { + var buffer = AllocateRawRun (font, count, x, y, bounds); + return new SKRunBuffer (buffer.buffer, count); + } + + public SKRawRunBuffer AllocateRawRun (SKFont font, int count, float x, float y, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -403,10 +396,16 @@ public SKRunBuffer AllocateRun (SKFont font, int count, float x, float y, SKRect else SkiaApi.sk_textblob_builder_alloc_run (Handle, font.Handle, count, x, y, null, &runbuffer); - return new SKRunBuffer (runbuffer, count); + return new SKRawRunBuffer (runbuffer, count, 0, 0); } public SKTextRunBuffer AllocateTextRun (SKFont font, int count, float x, float y, int textByteCount, SKRect? bounds = null) + { + var buffer = AllocateRawTextRun (font, count, x, y, textByteCount, bounds); + return new SKTextRunBuffer (buffer.buffer, count, textByteCount); + } + + public SKRawRunBuffer AllocateRawTextRun (SKFont font, int count, float x, float y, int textByteCount, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -417,12 +416,18 @@ public SKTextRunBuffer AllocateTextRun (SKFont font, int count, float x, float y else SkiaApi.sk_textblob_builder_alloc_run_text (Handle, font.Handle, count, x, y, textByteCount, null, &runbuffer); - return new SKTextRunBuffer (runbuffer, count, textByteCount); + return new SKRawRunBuffer (runbuffer, count, 0, textByteCount); } - // AllocateHorizontalRun + // Allocate*HorizontalRun public SKHorizontalRunBuffer AllocateHorizontalRun (SKFont font, int count, float y, SKRect? bounds = null) + { + var buffer = AllocateRawHorizontalRun (font, count, y, bounds); + return new SKHorizontalRunBuffer (buffer.buffer, count); + } + + public SKRawRunBuffer AllocateRawHorizontalRun (SKFont font, int count, float y, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -433,10 +438,16 @@ public SKHorizontalRunBuffer AllocateHorizontalRun (SKFont font, int count, floa else SkiaApi.sk_textblob_builder_alloc_run_pos_h (Handle, font.Handle, count, y, null, &runbuffer); - return new SKHorizontalRunBuffer (runbuffer, count); + return new SKRawRunBuffer (runbuffer, count, count, 0); } public SKHorizontalTextRunBuffer AllocateHorizontalTextRun (SKFont font, int count, float y, int textByteCount, SKRect? bounds = null) + { + var buffer = AllocateRawHorizontalTextRun (font, count, y, textByteCount, bounds); + return new SKHorizontalTextRunBuffer (buffer.buffer, count, textByteCount); + } + + public SKRawRunBuffer AllocateRawHorizontalTextRun (SKFont font, int count, float y, int textByteCount, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -447,12 +458,19 @@ public SKHorizontalTextRunBuffer AllocateHorizontalTextRun (SKFont font, int cou else SkiaApi.sk_textblob_builder_alloc_run_text_pos_h (Handle, font.Handle, count, y, textByteCount, null, &runbuffer); - return new SKHorizontalTextRunBuffer (runbuffer, count, textByteCount); + return new SKRawRunBuffer (runbuffer, count, count, textByteCount); + } // AllocatePositionedRun public SKPositionedRunBuffer AllocatePositionedRun (SKFont font, int count, SKRect? bounds = null) + { + var buffer = AllocateRawPositionedRun (font, count, bounds); + return new SKPositionedRunBuffer (buffer.buffer, count); + } + + public SKRawRunBuffer AllocateRawPositionedRun (SKFont font, int count, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -463,10 +481,16 @@ public SKPositionedRunBuffer AllocatePositionedRun (SKFont font, int count, SKRe else SkiaApi.sk_textblob_builder_alloc_run_pos (Handle, font.Handle, count, null, &runbuffer); - return new SKPositionedRunBuffer (runbuffer, count); + return new SKRawRunBuffer (runbuffer, count, count, 0); } public SKPositionedTextRunBuffer AllocatePositionedTextRun (SKFont font, int count, int textByteCount, SKRect? bounds = null) + { + var buffer = AllocateRawPositionedTextRun (font, count, textByteCount, bounds); + return new SKPositionedTextRunBuffer (buffer.buffer, count, textByteCount); + } + + public SKRawRunBuffer AllocateRawPositionedTextRun (SKFont font, int count, int textByteCount, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -477,12 +501,18 @@ public SKPositionedTextRunBuffer AllocatePositionedTextRun (SKFont font, int cou else SkiaApi.sk_textblob_builder_alloc_run_text_pos (Handle, font.Handle, count, textByteCount, null, &runbuffer); - return new SKPositionedTextRunBuffer (runbuffer, count, textByteCount); + return new SKRawRunBuffer (runbuffer, count, count, textByteCount); } // AllocateRotationScaleRun public SKRotationScaleRunBuffer AllocateRotationScaleRun (SKFont font, int count, SKRect? bounds = null) + { + var buffer = AllocateRawRotationScaleRun (font, count, bounds); + return new SKRotationScaleRunBuffer (buffer.buffer, count); + } + + public SKRawRunBuffer AllocateRawRotationScaleRun (SKFont font, int count, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -493,10 +523,16 @@ public SKRotationScaleRunBuffer AllocateRotationScaleRun (SKFont font, int count else SkiaApi.sk_textblob_builder_alloc_run_rsxform (Handle, font.Handle, count, null, &runbuffer); - return new SKRotationScaleRunBuffer (runbuffer, count); + return new SKRawRunBuffer (runbuffer, count, count, 0); + } + + public SKRotationScaleTextRunBuffer AllocateRotationScaleTextRun (SKFont font, int count, int textByteCount, SKRect? bounds = null) + { + var buffer = AllocateRawRotationScaleTextRun (font, count, textByteCount, bounds); + return new SKRotationScaleTextRunBuffer (buffer.buffer, count, textByteCount); } - public SKRotationScaleRunBuffer AllocateRotationScaleTextRun (SKFont font, int count, int textByteCount, SKRect? bounds = null) + public SKRawRunBuffer AllocateRawRotationScaleTextRun (SKFont font, int count, int textByteCount, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -507,7 +543,7 @@ public SKRotationScaleRunBuffer AllocateRotationScaleTextRun (SKFont font, int c else SkiaApi.sk_textblob_builder_alloc_run_text_rsxform (Handle, font.Handle, count, textByteCount, null, &runbuffer); - return new SKRotationScaleRunBuffer (runbuffer, count); + return new SKRawRunBuffer (runbuffer, count, count, textByteCount); } } } diff --git a/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz/CanvasExtensions.cs b/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz/CanvasExtensions.cs index d03462caf8..8b39ae75d9 100644 --- a/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz/CanvasExtensions.cs +++ b/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz/CanvasExtensions.cs @@ -74,11 +74,11 @@ public static void DrawShapedText(this SKCanvas canvas, SKShaper shaper, string // create the text blob using var builder = new SKTextBlobBuilder(); - var run = builder.AllocatePositionedRun(font, result.Codepoints.Length); + var run = builder.AllocateRawPositionedRun(font, result.Codepoints.Length, null); // copy the glyphs - var g = run.GetGlyphSpan(); - var p = run.GetPositionSpan(); + var g = run.Glyphs; + var p = run.Positions; for (var i = 0; i < result.Codepoints.Length; i++) { g[i] = (ushort)result.Codepoints[i]; diff --git a/tests/Tests/SkiaSharp/SKTextBlobTest.cs b/tests/Tests/SkiaSharp/SKTextBlobTest.cs index 32cb3e35cd..58785b35c7 100644 --- a/tests/Tests/SkiaSharp/SKTextBlobTest.cs +++ b/tests/Tests/SkiaSharp/SKTextBlobTest.cs @@ -16,6 +16,36 @@ public void TestEmptyBuilderReturnsNull() Assert.Null(blob); } + [SkippableFact] + public void RunsAllocateNoPositions() + { + var font = new SKFont(); + + using var builder = new SKTextBlobBuilder(); + + var run = builder.AllocateRun(font, 100, 0, 0); + Assert.Equal(100, run.Glyphs.Length); + + using var blob = builder.Build(); + Assert.NotNull(blob); + } + + [SkippableFact] + public void RawRunsAllocateNoPositions() + { + var font = new SKFont(); + + using var builder = new SKTextBlobBuilder(); + + var run = builder.AllocateRawRun(font, 100, 0, 0); + Assert.Equal(100, run.Glyphs.Length); + Assert.Equal(0, run.Positions.Length); + Assert.Equal(0, run.Text.Length); + + using var blob = builder.Build(); + Assert.NotNull(blob); + } + [SkippableFact] public void TextRunsAllocateTextSpan() { @@ -24,8 +54,23 @@ public void TextRunsAllocateTextSpan() using var builder = new SKTextBlobBuilder(); var run = builder.AllocateTextRun(font, 100, 0, 0, 50); - Assert.Equal(100, run.GetGlyphSpan().Length); - Assert.Equal(50, run.GetTextSpan().Length); + Assert.Equal(100, run.Glyphs.Length); + Assert.Equal(50, run.Text.Length); + + using var blob = builder.Build(); + Assert.NotNull(blob); + } + + [SkippableFact] + public void RawTextRunsAllocateTextSpan() + { + var font = new SKFont(); + + using var builder = new SKTextBlobBuilder(); + + var run = builder.AllocateRawTextRun(font, 100, 0, 0, 50); + Assert.Equal(100, run.Glyphs.Length); + Assert.Equal(50, run.Text.Length); using var blob = builder.Build(); Assert.NotNull(blob); @@ -112,7 +157,7 @@ public unsafe void TestPositionedRunIsBothPointsAndFloats() run.SetPositions(positions); - var span = run.GetPositionSpan(); + var span = run.Positions; Assert.Equal(positions, span.ToArray()); var floats = new float[6]; From 4f87c3a1b7ad3f4a5fb8bbef58076110d34ea6e5 Mon Sep 17 00:00:00 2001 From: Nick Kovalsky Date: Fri, 29 Mar 2024 01:34:59 +0300 Subject: [PATCH 30/40] Fix Snapshot returning magenta color Apple Metal (#2804) --- .../SkiaSharp.Views/Platform/Apple/SKMetalView.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKMetalView.cs b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKMetalView.cs index f9c1dc97ff..fe0dabc5b9 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKMetalView.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKMetalView.cs @@ -83,6 +83,7 @@ private void Initialize() ColorPixelFormat = MTLPixelFormat.BGRA8Unorm; DepthStencilPixelFormat = MTLPixelFormat.Depth32Float_Stencil8; SampleCount = 1; + FramebufferOnly = false; Device = device; backendContext = new GRMtlBackendContext { From 510e73801510ea165411e4d128403f5fb63c5e36 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Fri, 29 Mar 2024 20:26:47 +0200 Subject: [PATCH 31/40] Installing Java is troublesome, so avoid it (#2815) There are some sort of weird corruption issues on macOS --- scripts/install-openjdk.ps1 | 78 ++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/scripts/install-openjdk.ps1 b/scripts/install-openjdk.ps1 index 9291f86cb8..3feb68f36f 100644 --- a/scripts/install-openjdk.ps1 +++ b/scripts/install-openjdk.ps1 @@ -6,50 +6,56 @@ Param( $ErrorActionPreference = 'Stop' -Add-Type -AssemblyName System.IO.Compression.FileSystem +if (Test-Path (Join-Path "$env:JAVA_HOME_17_X64" "bin")) { + Write-Host "Java is already installed to '$env:JAVA_HOME_17_X64'..." + $java_home = $env:JAVA_HOME_17_X64 +} else { + Add-Type -AssemblyName System.IO.Compression.FileSystem -$HOME_DIR = if ($env:HOME) { $env:HOME } else { $env:USERPROFILE } + $HOME_DIR = if ($env:HOME) { $env:HOME } else { $env:USERPROFILE } -if ($IsMacOS) { - $ext = "tar.gz" - $url = "https://aka.ms/download-jdk/microsoft-jdk-$Version-macOS-x64.tar.gz" -} elseif ($IsLinux) { - $ext = "tar.gz" - $url = "https://aka.ms/download-jdk/microsoft-jdk-$Version-linux-x64.tar.gz" -} else { - $ext = "zip" - $url = "https://aka.ms/download-jdk/microsoft-jdk-$Version-windows-x64.zip" -} + if ($IsMacOS) { + $ext = "tar.gz" + $url = "https://aka.ms/download-jdk/microsoft-jdk-$Version-macOS-x64.tar.gz" + } elseif ($IsLinux) { + $ext = "tar.gz" + $url = "https://aka.ms/download-jdk/microsoft-jdk-$Version-linux-x64.tar.gz" + } else { + $ext = "zip" + $url = "https://aka.ms/download-jdk/microsoft-jdk-$Version-windows-x64.zip" + } -$jdk = Join-Path "$HOME_DIR" "openjdk" -if ($InstallDestination) { - $jdk = $InstallDestination -} -Write-Host "Install destination is '$jdk'..." + $jdk = Join-Path "$HOME_DIR" "openjdk" + if ($InstallDestination) { + $jdk = $InstallDestination + } + Write-Host "Install destination is '$jdk'..." -$jdkTemp = Join-Path "$HOME_DIR" "openjdk-temp" -$archive = Join-Path "$jdkTemp" "openjdk.$ext" + $jdkTemp = Join-Path "$HOME_DIR" "openjdk-temp" + $archive = Join-Path "$jdkTemp" "openjdk.$ext" -# download -Write-Host "Downloading OpenJDK to '$archive'..." -New-Item -ItemType Directory -Force -Path "$jdkTemp" | Out-Null -(New-Object System.Net.WebClient).DownloadFile("$url", "$archive") + # download + Write-Host "Downloading OpenJDK to '$archive'..." + New-Item -ItemType Directory -Force -Path "$jdkTemp" | Out-Null + (New-Object System.Net.WebClient).DownloadFile("$url", "$archive") -# install -Write-Host "Extracting OpenJDK to '$jdk'..." -New-Item -ItemType Directory -Force -Path "$jdk" | Out-Null -if ($IsMacOS -or $IsLinux) { - tar -vxzf "$archive" -C "$jdk" -} else { - [System.IO.Compression.ZipFile]::ExtractToDirectory("$archive", "$jdk") -} + # install + Write-Host "Extracting OpenJDK to '$jdk'..." + New-Item -ItemType Directory -Force -Path "$jdk" | Out-Null + if ($IsMacOS -or $IsLinux) { + tar -vxzf "$archive" -C "$jdk" + } else { + [System.IO.Compression.ZipFile]::ExtractToDirectory("$archive", "$jdk") + } -# set the JAVA_HOME -if ($IsMacOS) { - $java_home = Join-Path "$jdk" "jdk-$FolderVersion/Contents/Home" -} else { - $java_home = Join-Path "$jdk" "jdk-$FolderVersion" + # set the JAVA_HOME + if ($IsMacOS) { + $java_home = Join-Path "$jdk" "jdk-$FolderVersion/Contents/Home" + } else { + $java_home = Join-Path "$jdk" "jdk-$FolderVersion" + } } + Write-Host "##vso[task.setvariable variable=JAVA_HOME;]$java_home" $env:JAVA_HOME = "$java_home" From a290ccffc74bc95a45569e8b74e77be851d4a688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Tue, 2 Apr 2024 08:16:14 -0600 Subject: [PATCH 32/40] Expose Blazor components dpi (#1832) --- .../SkiaSharp.Views.Blazor/SKCanvasView.razor.cs | 2 ++ source/SkiaSharp.Views/SkiaSharp.Views.Blazor/SKGLView.razor.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.Blazor/SKCanvasView.razor.cs b/source/SkiaSharp.Views/SkiaSharp.Views.Blazor/SKCanvasView.razor.cs index b1c7afa6a4..7d803f3496 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.Blazor/SKCanvasView.razor.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.Blazor/SKCanvasView.razor.cs @@ -60,6 +60,8 @@ public bool IgnorePixelScaling [Parameter(CaptureUnmatchedValues = true)] public IReadOnlyDictionary? AdditionalAttributes { get; set; } + public double Dpi => dpi; + protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.Blazor/SKGLView.razor.cs b/source/SkiaSharp.Views/SkiaSharp.Views.Blazor/SKGLView.razor.cs index 6864aff219..6473fb1e8e 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.Blazor/SKGLView.razor.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.Blazor/SKGLView.razor.cs @@ -67,6 +67,8 @@ public bool IgnorePixelScaling [Parameter(CaptureUnmatchedValues = true)] public IReadOnlyDictionary? AdditionalAttributes { get; set; } + public double Dpi => dpi; + protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) From 647403d6dcc8347202daa521ad8ff745868ece1e Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Mon, 8 Apr 2024 21:08:57 +0200 Subject: [PATCH 33/40] Add and remove the compatibility APIs (#2789) --- binding/SkiaSharp/SKCanvas.cs | 4 + binding/SkiaSharp/SKImageFilter.cs | 36 ++++++++ binding/SkiaSharp/SKPath.cs | 15 ++- binding/SkiaSharp/SkiaSharp.csproj | 1 + .../3.0.0/SkiaSharp.humanreadable.md | 91 +++++++++++++++---- source/SkiaSharp.Build.props | 4 + source/SkiaSharp.Build.targets | 18 ++++ source/SkiaSharp.NuGet.targets | 67 +++++++++++++- 8 files changed, 211 insertions(+), 25 deletions(-) diff --git a/binding/SkiaSharp/SKCanvas.cs b/binding/SkiaSharp/SKCanvas.cs index b4124c5b96..e5a0dbfc68 100644 --- a/binding/SkiaSharp/SKCanvas.cs +++ b/binding/SkiaSharp/SKCanvas.cs @@ -856,6 +856,10 @@ public void ResetMatrix () public void SetMatrix (in SKMatrix matrix) => SetMatrix ((SKMatrix44)matrix); + [Obsolete("Use SetMatrix(in SKMatrix) instead.", true)] + public void SetMatrix (SKMatrix matrix) => + SetMatrix (in matrix); + public void SetMatrix (in SKMatrix44 matrix) { fixed (SKMatrix44* ptr = &matrix) { diff --git a/binding/SkiaSharp/SKImageFilter.cs b/binding/SkiaSharp/SKImageFilter.cs index 91f106f923..bcc384a1b4 100644 --- a/binding/SkiaSharp/SKImageFilter.cs +++ b/binding/SkiaSharp/SKImageFilter.cs @@ -14,6 +14,14 @@ protected override void Dispose (bool disposing) => // CreateMatrix + [Obsolete("Use SetMatrix(in SKMatrix) instead.", true)] + public static SKImageFilter CreateMatrix (SKMatrix matrix) => + CreateMatrix (in matrix); + + [Obsolete("Use SetMatrix(in SKMatrix, SKSamplingOptions, SKImageFilter) instead.", true)] + public static SKImageFilter CreateMatrix (SKMatrix matrix, SKFilterQuality quality, SKImageFilter? input) => + CreateMatrix (in matrix, quality.ToSamplingOptions (), input); + public static SKImageFilter CreateMatrix (in SKMatrix matrix) => CreateMatrix (matrix, SKSamplingOptions.Default, null); @@ -29,6 +37,14 @@ public static SKImageFilter CreateMatrix (in SKMatrix matrix, SKSamplingOptions // CreateAlphaThreshold + [Obsolete("Use CreateAlphaThreshold(SKRegion, float, float, SKImageFilter) instead.", true)] + public static SKImageFilter CreateAlphaThreshold(SKRectI region, float innerThreshold, float outerThreshold, SKImageFilter? input) + { + var reg = new SKRegion (); + reg.SetRect (region); + return CreateAlphaThreshold (reg, innerThreshold, outerThreshold, input); + } + public static SKImageFilter CreateAlphaThreshold (SKRegion region, float innerThreshold, float outerThreshold) => CreateAlphaThreshold (region, innerThreshold, outerThreshold, null); @@ -376,6 +392,10 @@ public static SKImageFilter CreateImage (SKImage image, SKRect src, SKRect dst, return GetObject (SkiaApi.sk_imagefilter_new_image (image.Handle, &src, &dst, &sampling)); } + [Obsolete("Use CreateImage(SKImage, SKRect, SKRect, SKSamplingOptions) instead.", true)] + public static SKImageFilter CreateImage (SKImage image, SKRect src, SKRect dst, SKFilterQuality filterQuality) => + CreateImage (image, src, dst, filterQuality.ToSamplingOptions ()); + // CreateMagnifier public static SKImageFilter CreateMagnifier (SKRect lensBounds, float zoomAmount, float inset, SKSamplingOptions sampling) => @@ -390,6 +410,22 @@ public static SKImageFilter CreateMagnifier (SKRect lensBounds, float zoomAmount private static SKImageFilter CreateMagnifier (SKRect lensBounds, float zoomAmount, float inset, SKSamplingOptions sampling, SKImageFilter? input, SKRect* cropRect) => GetObject (SkiaApi.sk_imagefilter_new_magnifier (&lensBounds, zoomAmount, inset, &sampling, input?.Handle ?? IntPtr.Zero, cropRect)); + // CreatePaint + + [Obsolete("Use CreateShader(SKShader) instead.", true)] + public static SKImageFilter CreatePaint (SKPaint paint) + { + _ = paint ?? throw new ArgumentNullException (nameof (paint)); + return CreateShader(paint.Shader, paint.IsDither, null); + } + + [Obsolete("Use CreateShader(SKShader, bool, SKRect) instead.", true)] + public static SKImageFilter CreatePaint (SKPaint paint, SKRect cropRect) + { + _ = paint ?? throw new ArgumentNullException (nameof (paint)); + return CreateShader(paint.Shader, paint.IsDither, &cropRect); + } + // CreateShader public static SKImageFilter CreateShader (SKShader? shader) => diff --git a/binding/SkiaSharp/SKPath.cs b/binding/SkiaSharp/SKPath.cs index d1a0d7f0e1..d4b36fbe8c 100644 --- a/binding/SkiaSharp/SKPath.cs +++ b/binding/SkiaSharp/SKPath.cs @@ -181,8 +181,11 @@ public bool Contains (float x, float y) => public void Offset (SKPoint offset) => Offset (offset.X, offset.Y); - public void Offset (float dx, float dy) => - Transform (SKMatrix.CreateTranslation (dx, dy)); + public void Offset (float dx, float dy) + { + var matrix = SKMatrix.CreateTranslation (dx, dy); + Transform (in matrix); + } public void MoveTo (SKPoint point) => SkiaApi.sk_path_move_to (Handle, point.X, point.Y); @@ -340,6 +343,14 @@ public void Transform (in SKMatrix matrix, SKPath destination) SkiaApi.sk_path_transform_to_dest (Handle, m, destination.Handle); } + [Obsolete("Use Transform(in SKMatrix) instead.", true)] + public void Transform (SKMatrix matrix) => + Transform (in matrix); + + [Obsolete("Use Transform(in SKMatrix matrix, SKPath destination) instead.", true)] + public void Transform (SKMatrix matrix, SKPath destination) => + Transform (in matrix, destination); + public void AddPath (SKPath other, float dx, float dy, SKPathAddMode mode = SKPathAddMode.Append) { if (other == null) diff --git a/binding/SkiaSharp/SkiaSharp.csproj b/binding/SkiaSharp/SkiaSharp.csproj index 4f0937b0b8..eb53cfa375 100644 --- a/binding/SkiaSharp/SkiaSharp.csproj +++ b/binding/SkiaSharp/SkiaSharp.csproj @@ -5,6 +5,7 @@ SkiaSharp SkiaSharp enable + true $(DefineConstants);USE_DELEGATES diff --git a/changelogs/SkiaSharp/3.0.0/SkiaSharp.humanreadable.md b/changelogs/SkiaSharp/3.0.0/SkiaSharp.humanreadable.md index 70e2d245d2..0ba58ee800 100644 --- a/changelogs/SkiaSharp/3.0.0/SkiaSharp.humanreadable.md +++ b/changelogs/SkiaSharp/3.0.0/SkiaSharp.humanreadable.md @@ -1,22 +1,28 @@ -# API diff: SkiaSharp.dll - -## SkiaSharp.dll - -> Assembly Version Changed: 3.0.0.0 vs 2.88.0.0 - -### Major Changes +# SkiaSharp 3.x Changes The diff below contains all the changes that are in addition to the removal of obsolete types and members. The 3.x release is a major upgrade and many of the obsolete types and members needed to go away. -#### Platform Reduction +**Contents** -SkiaSharp supports many platforms, however in 3.x we reduce the platforms to just the more modern ones: +* [Improvements](#improvements) + There are many new APIs and improvements to exisitng features. +* [Breaking Changes](#breaking-changes) + In order to update to the latest skia builds and to keep the library maintainable, we unfortunately had to make some hard choices and remove some old APIs. + * [Platform Reduction](#platform-reduction) + In order to move forward, we had to reduce our supported platforms. However, all the modern and supported .NET platforms are still there. + * [ABI Breaking Changes](#abi-breaking-changes) + Unfortunately several APIs had to be dropped. This could be that the new skia engine does not support a feature or it was not working previously. + * [Removed `[Obsolete]` Types and Members](#removed-obsolete-types-and-members) + Several obsolete APIs were removed as they have been marked for removal for several years now. In most cases, there are already alternatives that you can use instead. + * [Analysis and Tooling](#analysis-and-tooling) + Because some breaking changes are hard to detect and since SkiaSharp is so widely used, we have put together some tooling to help you detect those breaking APIs before you even update. +* [Newly Obsoleted Types and Members](#newly-obsoleted-types-and-members) + The new version of skia does things a bit differently in some places, so some existing APIs are no longer relevant or there are better APIs to use. +* [API diff: SkiaSharp.dll](#api-diff-skiasharpdll) + This is a more readable diff of SkiaSharp as the full diff is really long and has many changes that are not really relevant. -* .NET Standard 2.0+ -* .NET Framework 4.6.2+ -* .NET 7+ (All the platforms: Android, iOS, Mac Catalyst, macOS, Tizen, tvOS, Windows) -#### Improvements +## Improvements There are some small improvements in the initial release of 3.x, and many more will be added with later builds. @@ -30,9 +36,19 @@ There are some small improvements in the initial release of 3.x, and many more w * CPU is NOT accelerated and may be very slow. * `SKMatrix44` is now a high-performance struct that can be used on any `SKCanvas`. -#### Breaking Changes +## Breaking Changes -With the major update from 2x to 3x, some APIs were broken to make maintainance easier as well as to simplify things for consumers. +With the major update from 2.x to 3.x, some APIs were broken to make maintainance easier as well as to simplify things for consumers. + +### Platform Reduction + +SkiaSharp supports many platforms, however in 3.x we reduce the platforms to just the more modern ones: + +* .NET Standard 2.0+ +* .NET Framework 4.6.2+ +* .NET 7+ (All the platforms: Android, iOS, Mac Catalyst, macOS, Tizen, tvOS, Windows) + +### ABI Breaking Changes Below is a list of notable breaking changes. @@ -45,7 +61,7 @@ Below is a list of notable breaking changes. * `SK3dView` was removed because it was expensive to use The new `SKMatrix44` can do all the same things as well as just using `System.Numerics.Matrix4x4` and related `System.Numerics` types. -##### Removed [Obsolete] Types and Members +### Removed `[Obsolete]` Types and Members Many types and members were obsoleted at trhe start of the 2.x version (and some before). The 3.x release will be removing all the members that were previously marked `[Obsolete]`. @@ -63,9 +79,44 @@ Some of the notable removals are: * `SKMask` - All types and members relating to `SKMask` have been removed. * `SKXmlWriter` - All types and members relating to `SKXmlWriter` and `SKXmlStreamWriter` have been removed. -#### Obsoleted Types and Members +### Analysis and Tooling + +If you are upgrading to SkiaSharp 3.x, you may be interested in using the [`api-tools` .NET CLI tool](https://nuget.org/packages/api-tools) to help identify any usages of removed types. + +There is [full documentation available](https://github.com/mattleibow/Mono.ApiTools.NuGetDiff/blob/5c14bf43a6a587c2fd2878c7884ff1db6a9beca1/docs/api-tools.md#compat-command), but the `api-tools` CLI tool can be used to find all usages of missing types and members: + +```sh +dotnet api-tools compat Svg.Skia/Svg.Skia.dll SkiaSharp/v3/SkiaSharp.dll +``` + +This will produce an output similar to: + +```xml + + + + + + + + + + + + + + + + + +``` + +This output indicates that there are several usages of missing types and members. However, in many cases, there are overloads or alternate APIs that can be used that are present in both 2.x and 3.x versions of SkiaSharp. + + +## Newly Obsoleted Types and Members -With the major update from 2x to 3x, several APIs are no longer the recommeneded way to do something. There might be a better or cleaner way of doing something. For all of these types and members, they will be marked `[Obsolete]` and removed in the next major release. +With the major update from 2.x to 3.x, several APIs are no longer the recommeneded way to do something. There might be a better or cleaner way of doing something. For all of these types and members, they will be marked `[Obsolete]` and removed in the next major release. Some of the notable obsolete items are: @@ -74,6 +125,10 @@ Some of the notable obsolete items are: * `SKFont` & `SKPaint` - All the "font-related" members on `SKPaint` have been marked obsolete and now exist on `SKFont`. In previous skia versions, the `SKPaint` functionality was split into 2 objects: `SKPaint` and `SKFont`. SkiaSharp tried to maintain 100% backwards compatibility by re-merginf the types. However, this is getting hard to maintain. As a result, `SKFont` is now the correct replacement to work with typefaces and character styles. All APIs tha accepted just a `SKPaint` now also have an overload that accepts `SKFont` and `SKTextAlign`. +## API diff: SkiaSharp.dll + +> Assembly Version Changed: 3.0.0.0 vs 2.88.0.0 + ### Namespace SkiaSharp #### Type Changed: SkiaSharp.GRGlFramebufferInfo diff --git a/source/SkiaSharp.Build.props b/source/SkiaSharp.Build.props index 0cb92531a1..7d20b27460 100644 --- a/source/SkiaSharp.Build.props +++ b/source/SkiaSharp.Build.props @@ -160,9 +160,13 @@ + portable true + True + + false diff --git a/source/SkiaSharp.Build.targets b/source/SkiaSharp.Build.targets index 0a152064b7..3f83ca44cf 100644 --- a/source/SkiaSharp.Build.targets +++ b/source/SkiaSharp.Build.targets @@ -138,6 +138,22 @@ internal partial class VersionConstants { + + + + + + + + - + @@ -34,23 +40,74 @@ $(PackageNotes) - + + + + + + + + + + + + + + + <_IncludeAdditionalTfmSpecificPackageFilesDependsOn> + _IncludeAdditionalTfmSpecificPackageFilesPrepare; + IncludeMDocTfmSpecificPackageFiles; + IncludeReferenceAssemblyTfmSpecificPackageFiles; + IncludeAdditionalTfmSpecificPackageFiles; + + + DependsOnTargets="$(_IncludeAdditionalTfmSpecificPackageFilesDependsOn)" /> + + + Set the package version properties. + =================================================================================================================== + --> $(Version) From 63141bfff418f9b99d5ec83e6a999e74e420704d Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 8 Apr 2024 12:09:21 -0700 Subject: [PATCH 34/40] Bring Metal APIs to a common .NET TFM (#2788) Co-authored-by: Matthew Leibowitz --- binding/SkiaSharp/GRBackendTexture.cs | 4 -- binding/SkiaSharp/GRContext.cs | 12 ++---- binding/SkiaSharp/GRDefinitions.cs | 38 +++++++++++++++---- binding/SkiaSharp/GRMtlBackendContext.cs | 47 ++++++++++++++++++++++-- 4 files changed, 77 insertions(+), 24 deletions(-) diff --git a/binding/SkiaSharp/GRBackendTexture.cs b/binding/SkiaSharp/GRBackendTexture.cs index 603731f457..254cc3c708 100644 --- a/binding/SkiaSharp/GRBackendTexture.cs +++ b/binding/SkiaSharp/GRBackendTexture.cs @@ -25,8 +25,6 @@ public GRBackendTexture (int width, int height, GRVkImageInfo vkInfo) CreateVulkan (width, height, vkInfo); } -#if __IOS__ || __MACOS__ - public GRBackendTexture (int width, int height, bool mipmapped, GRMtlTextureInfo mtlInfo) : this (IntPtr.Zero, true) { @@ -38,8 +36,6 @@ public GRBackendTexture (int width, int height, bool mipmapped, GRMtlTextureInfo } } -#endif - private void CreateGl (int width, int height, bool mipmapped, GRGlTextureInfo glInfo) { Handle = SkiaApi.gr_backendtexture_new_gl (width, height, mipmapped, &glInfo); diff --git a/binding/SkiaSharp/GRContext.cs b/binding/SkiaSharp/GRContext.cs index 70a50e67a4..55071e4187 100644 --- a/binding/SkiaSharp/GRContext.cs +++ b/binding/SkiaSharp/GRContext.cs @@ -63,8 +63,6 @@ public static GRContext CreateVulkan (GRVkBackendContext backendContext, GRConte } } -#if __IOS__ || __MACOS__ - // CreateMetal public static GRContext CreateMetal (GRMtlBackendContext backendContext) => @@ -75,19 +73,17 @@ public static GRContext CreateMetal (GRMtlBackendContext backendContext, GRConte if (backendContext == null) throw new ArgumentNullException (nameof (backendContext)); - var device = backendContext.Device; - var queue = backendContext.Queue; + var device = backendContext.DeviceHandle; + var queue = backendContext.QueueHandle; if (options == null) { - return GetObject (SkiaApi.gr_direct_context_make_metal ((void*)(IntPtr)device.Handle, (void*)(IntPtr)queue.Handle)); + return GetObject (SkiaApi.gr_direct_context_make_metal ((void*)device, (void*)queue)); } else { var opts = options.ToNative (); - return GetObject (SkiaApi.gr_direct_context_make_metal_with_options ((void*)(IntPtr)device.Handle, (void*)(IntPtr)queue.Handle, &opts)); + return GetObject (SkiaApi.gr_direct_context_make_metal_with_options ((void*)device, (void*)queue, &opts)); } } -#endif - // public override GRBackend Backend => base.Backend; diff --git a/binding/SkiaSharp/GRDefinitions.cs b/binding/SkiaSharp/GRDefinitions.cs index 54c9a46ad9..304f479386 100644 --- a/binding/SkiaSharp/GRDefinitions.cs +++ b/binding/SkiaSharp/GRDefinitions.cs @@ -74,24 +74,48 @@ public GRGlTextureInfo (uint target, uint id, uint format) } } -#if __IOS__ || __MACOS__ - public unsafe partial struct GRMtlTextureInfo { + private IntPtr _textureHandle; + + public GRMtlTextureInfo (IntPtr textureHandle) + { + TextureHandle = textureHandle; + } + + public IntPtr TextureHandle { + get => _textureHandle; + set { + _textureHandle = value; +#if __IOS__ || __MACOS__ + _texture = null; +#endif + } + } + +#if __IOS__ || __MACOS__ + private Metal.IMTLTexture _texture; public GRMtlTextureInfo (Metal.IMTLTexture texture) { Texture = texture; } - public Metal.IMTLTexture Texture { get; set; } + public Metal.IMTLTexture Texture { + get => _texture; + set { + _texture = value; + _textureHandle = _texture.Handle; + } + } +#endif internal GRMtlTextureInfoNative ToNative () => new GRMtlTextureInfoNative { - fTexture = (void*)(IntPtr)Texture.Handle + fTexture = (void*)TextureHandle }; public readonly bool Equals (GRMtlTextureInfo obj) => - Texture == obj.Texture; + TextureHandle == obj.TextureHandle; public readonly override bool Equals (object obj) => obj is GRMtlTextureInfo f && Equals (f); @@ -105,13 +129,11 @@ public readonly override bool Equals (object obj) => public readonly override int GetHashCode () { var hash = new HashCode (); - hash.Add (Texture); + hash.Add (TextureHandle); return hash.ToHashCode (); } } -#endif - public static partial class SkiaExtensions { public static uint ToGlSizedFormat (this SKColorType colorType) => diff --git a/binding/SkiaSharp/GRMtlBackendContext.cs b/binding/SkiaSharp/GRMtlBackendContext.cs index aba9670b9a..9c2aa28112 100644 --- a/binding/SkiaSharp/GRMtlBackendContext.cs +++ b/binding/SkiaSharp/GRMtlBackendContext.cs @@ -1,16 +1,56 @@ #nullable disable -#if __IOS__ || __MACOS__ using System; +#if __IOS__ || __MACOS__ using Metal; +#endif namespace SkiaSharp { public class GRMtlBackendContext : IDisposable { - public IMTLDevice Device { get; set; } + private IntPtr _deviceHandle, _queueHandle; + + public IntPtr DeviceHandle { + get => _deviceHandle; + set { + _deviceHandle = value; +#if __IOS__ || __MACOS__ + _device = null; +#endif + } + } + + public IntPtr QueueHandle { + get => _queueHandle; + set { + _queueHandle = value; +#if __IOS__ || __MACOS__ + _queue = null; +#endif + } + } - public IMTLCommandQueue Queue { get; set; } +#if __IOS__ || __MACOS__ + private IMTLDevice _device; + private IMTLCommandQueue _queue; + + public IMTLDevice Device { + get => _device; + set { + _device = value; + _deviceHandle = _device.Handle; + } + } + + public IMTLCommandQueue Queue { + get => _queue; + set { + _queue = value; + _queueHandle = _queue.Handle; + } + } +#endif protected virtual void Dispose (bool disposing) { @@ -23,4 +63,3 @@ public void Dispose () } } } -#endif From 0a5739a5284fabb650d4f6093e455edcda46596a Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Sat, 13 Apr 2024 08:49:41 +0200 Subject: [PATCH 35/40] Validate the generated interop files (#2831) --- scripts/azure-templates-bootstrapper.yml | 7 ----- scripts/azure-templates-stages.yml | 9 ++++++ scripts/cake/externals.cake | 27 +++++++++++++++++ .../docker/NativeLibraryMiniTest.csproj | 2 +- .../Generate/GenerateCommand.cs | 4 +-- .../SkiaSharpGenerator.csproj | 2 +- utils/generate.ps1 | 30 +++++++++++++++---- 7 files changed, 65 insertions(+), 16 deletions(-) diff --git a/scripts/azure-templates-bootstrapper.yml b/scripts/azure-templates-bootstrapper.yml index 4e9736538e..5fe77fc96b 100644 --- a/scripts/azure-templates-bootstrapper.yml +++ b/scripts/azure-templates-bootstrapper.yml @@ -188,13 +188,6 @@ jobs: - pwsh: Remove-Item "$env:AGENT_TOOLSDIRECTORY/dotnet" -Recurse -Force -ErrorAction SilentlyContinue displayName: Cleanup existing versions of .NET condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) - - task: UseDotNet@2 - condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) - inputs: - packageType: 'sdk' - version: 3.1.x - retryCountOnTaskFailure: 3 - displayName: Install .NET 3.1.x - task: UseDotNet@2 condition: and(succeeded(), eq(variables['DOWNLOAD_EXTERNALS'], '')) inputs: diff --git a/scripts/azure-templates-stages.yml b/scripts/azure-templates-stages.yml index b39f34db49..ebf702e81c 100644 --- a/scripts/azure-templates-stages.yml +++ b/scripts/azure-templates-stages.yml @@ -490,6 +490,15 @@ stages: ${{ if eq(parameters.buildPipelineType, 'both') }}: dependsOn: native jobs: + - template: /scripts/azure-templates-bootstrapper.yml@self # Validate Interop + parameters: + name: managed_interop_windows + displayName: Validate Interop + buildPipelineType: ${{ parameters.buildPipelineType }} + buildAgent: ${{ parameters.buildAgentWindows}} + target: externals-interop + additionalArgs: --skipExternals="all" + installAndroidSdk: false - template: /scripts/azure-templates-bootstrapper.yml@self # Build Managed (Windows) parameters: name: managed_windows diff --git a/scripts/cake/externals.cake b/scripts/cake/externals.cake index d5b4df53ed..0ee5c74526 100644 --- a/scripts/cake/externals.cake +++ b/scripts/cake/externals.cake @@ -40,6 +40,33 @@ Task("externals-download") await DownloadPackageAsync("_nativeassets", "./output/native"); }); +//////////////////////////////////////////////////////////////////////////////////////////////////// +// EXTERNALS INTEROP - re-generate the interop files +//////////////////////////////////////////////////////////////////////////////////////////////////// + +Task("externals-interop") + .IsDependentOn("git-sync-deps") + .Does(() => +{ + RunProcess("pwsh", "./utils/generate.ps1"); + + RunProcess("git", "diff --name-only binding/*/*.generated.cs", out var files); + + if (files.Any()) { + Information("Generated files have changed:"); + foreach (var file in files) { + Information($" - {file}"); + } + + if (Argument("validateInterop", false)) { + throw new Exception("Generated interop files are out of date. Please run `pwsh ./utils/generate.ps1`."); + } else { + Warning("Generated interop files are out of date. Please run `pwsh ./utils/generate.ps1`."); + Warning("##vso[task.logissue type=warning]Generated interop files are out of date. Please run `pwsh ./utils/generate.ps1`."); + } + } +}); + //////////////////////////////////////////////////////////////////////////////////////////////////// // CLEAN - remove all the build artefacts //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/utils/NativeLibraryMiniTest/docker/NativeLibraryMiniTest.csproj b/utils/NativeLibraryMiniTest/docker/NativeLibraryMiniTest.csproj index 21aa313d61..f40c99436d 100644 --- a/utils/NativeLibraryMiniTest/docker/NativeLibraryMiniTest.csproj +++ b/utils/NativeLibraryMiniTest/docker/NativeLibraryMiniTest.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + net7.0 True diff --git a/utils/SkiaSharpGenerator/Generate/GenerateCommand.cs b/utils/SkiaSharpGenerator/Generate/GenerateCommand.cs index 105da78e10..bc7404e7f6 100644 --- a/utils/SkiaSharpGenerator/Generate/GenerateCommand.cs +++ b/utils/SkiaSharpGenerator/Generate/GenerateCommand.cs @@ -20,7 +20,7 @@ public GenerateCommand() protected override OptionSet OnCreateOptions() => new OptionSet { - { "s|skia=", "The root of the skia source", v => SourceRoot = v }, + { "r|root=", "The root of the source", v => SourceRoot = v }, { "c|config=", "The config file path", v => ConfigPath = v }, { "o|output=", "The output path", v => OutputPath = v }, }; @@ -31,7 +31,7 @@ protected override bool OnValidateArguments(IEnumerable extras) if (string.IsNullOrEmpty(SourceRoot)) { - Program.Log.LogError($"{Program.Name}: Path to the skia source was not provided: `--skia=`."); + Program.Log.LogError($"{Program.Name}: Path to the skia source was not provided: `--root=`."); hasError = true; } else if (!Directory.Exists(SourceRoot)) diff --git a/utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj b/utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj index 7b3c5de990..25df0ee165 100644 --- a/utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj +++ b/utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net7.0 enable LatestMajor diff --git a/utils/generate.ps1 b/utils/generate.ps1 index f7fc7a2050..12d937313b 100644 --- a/utils/generate.ps1 +++ b/utils/generate.ps1 @@ -1,5 +1,25 @@ -dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/libSkiaSharp.json --skia externals/skia --output binding/SkiaSharp/SkiaApi.generated.cs -dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/libSkiaSharp.Skottie.json --skia externals/skia --output binding/SkiaSharp.Skottie/SkottieApi.generated.cs -dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/libSkiaSharp.SceneGraph.json --skia externals/skia --output binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs -dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/libSkiaSharp.Resources.json --skia externals/skia --output binding/SkiaSharp.Resources/ResourcesApi.generated.cs -dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/libHarfBuzzSharp.json --skia externals/skia/third_party/externals/harfbuzz --output binding/HarfBuzzSharp/HarfBuzzApi.generated.cs +$ErrorActionPreference = "Stop" + +$projects = @( + @{ Json="libSkiaSharp.json"; Root="externals/skia"; Output="SkiaSharp/SkiaApi.generated.cs" }, + @{ Json="libSkiaSharp.Skottie.json"; Root="externals/skia"; Output="SkiaSharp.Skottie/SkottieApi.generated.cs" }, + @{ Json="libSkiaSharp.SceneGraph.json"; Root="externals/skia"; Output="SkiaSharp.SceneGraph/SceneGraphApi.generated.cs" }, + @{ Json="libSkiaSharp.Resources.json"; Root="externals/skia"; Output="SkiaSharp.Resources/ResourcesApi.generated.cs" }, + @{ Json="libHarfBuzzSharp.json"; Root="externals/skia/third_party/externals/harfbuzz"; Output="HarfBuzzSharp/HarfBuzzApi.generated.cs" } +) + +New-Item -ItemType Directory -Force -Path "output/generated/" | Out-Null + +foreach ($proj in $projects) { + $json = $proj.Json; + $output = $proj.Output; + $root = $proj.Root; + $filename = Split-Path $output -Leaf + + dotnet run --project=utils/SkiaSharpGenerator/SkiaSharpGenerator.csproj -- generate --config binding/$json --root $root --output binding/$output + if (!$?) { + exit $LASTEXITCODE + } + + Copy-Item -Path binding/$output -Destination output/generated/$filename -Force +} From bef2eab4ef394b9250aac1bd5daf31d17a935b3e Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Sun, 14 Apr 2024 23:49:35 +0200 Subject: [PATCH 36/40] GRMtlTextureInfo should have readonly getters (#2833) --- binding/SkiaSharp/GRDefinitions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/binding/SkiaSharp/GRDefinitions.cs b/binding/SkiaSharp/GRDefinitions.cs index 304f479386..ed6c3facb0 100644 --- a/binding/SkiaSharp/GRDefinitions.cs +++ b/binding/SkiaSharp/GRDefinitions.cs @@ -84,7 +84,7 @@ public GRMtlTextureInfo (IntPtr textureHandle) } public IntPtr TextureHandle { - get => _textureHandle; + readonly get => _textureHandle; set { _textureHandle = value; #if __IOS__ || __MACOS__ @@ -101,7 +101,7 @@ public GRMtlTextureInfo (Metal.IMTLTexture texture) } public Metal.IMTLTexture Texture { - get => _texture; + readonly get => _texture; set { _texture = value; _textureHandle = _texture.Handle; From a0f3767c9698416fec904a04efeef8f71117f67e Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Mon, 15 Apr 2024 12:28:32 +0200 Subject: [PATCH 37/40] Update skia to m116 (#2829) --- README.md | 6 +++--- binding/SkiaSharp/SKImageFilter.cs | 20 -------------------- externals/skia | 2 +- scripts/VERSIONS.txt | 6 +++--- 4 files changed, 7 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 81a4dc0f4f..e20162e2ec 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,6 @@ However, these are easy to install as they are found on the various websites. If Here are some links to show the differences in our code as compared to Google's code. -What version are we on? [**m115**](https://github.com/google/skia/tree/chrome/m115) -Are we up-to-date with Google? [Compare](https://github.com/mono/skia/compare/skiasharp...google:chrome/m115) -What have we added? [Compare](https://github.com/google/skia/compare/chrome/m115...mono:skiasharp) +What version are we on? [**m116**](https://github.com/google/skia/tree/chrome/m116) +Are we up-to-date with Google? [Compare](https://github.com/mono/skia/compare/skiasharp...google:chrome/m116) +What have we added? [Compare](https://github.com/google/skia/compare/chrome/m116...mono:skiasharp) diff --git a/binding/SkiaSharp/SKImageFilter.cs b/binding/SkiaSharp/SKImageFilter.cs index bcc384a1b4..a1fceca6c8 100644 --- a/binding/SkiaSharp/SKImageFilter.cs +++ b/binding/SkiaSharp/SKImageFilter.cs @@ -34,26 +34,6 @@ public static SKImageFilter CreateMatrix (in SKMatrix matrix, SKSamplingOptions return GetObject (SkiaApi.sk_imagefilter_new_matrix_transform (m, &sampling, input?.Handle ?? IntPtr.Zero)); } - - // CreateAlphaThreshold - - [Obsolete("Use CreateAlphaThreshold(SKRegion, float, float, SKImageFilter) instead.", true)] - public static SKImageFilter CreateAlphaThreshold(SKRectI region, float innerThreshold, float outerThreshold, SKImageFilter? input) - { - var reg = new SKRegion (); - reg.SetRect (region); - return CreateAlphaThreshold (reg, innerThreshold, outerThreshold, input); - } - - public static SKImageFilter CreateAlphaThreshold (SKRegion region, float innerThreshold, float outerThreshold) => - CreateAlphaThreshold (region, innerThreshold, outerThreshold, null); - - public static SKImageFilter CreateAlphaThreshold (SKRegion region, float innerThreshold, float outerThreshold, SKImageFilter? input) - { - _ = region ?? throw new ArgumentNullException (nameof (region)); - return GetObject (SkiaApi.sk_imagefilter_new_alpha_threshold (region.Handle, innerThreshold, outerThreshold, input?.Handle ?? IntPtr.Zero)); - } - // CreateBlur public static SKImageFilter CreateBlur (float sigmaX, float sigmaY) => diff --git a/externals/skia b/externals/skia index a0008792c8..8684edb4e6 160000 --- a/externals/skia +++ b/externals/skia @@ -1 +1 @@ -Subproject commit a0008792c861228872a0a21f5f3422c4c8824720 +Subproject commit 8684edb4e68d2bbf0d56a600633f5d4c44a16a36 diff --git a/scripts/VERSIONS.txt b/scripts/VERSIONS.txt index fa0d56e5f1..536f5bafc3 100644 --- a/scripts/VERSIONS.txt +++ b/scripts/VERSIONS.txt @@ -1,7 +1,7 @@ # dependencies mdoc release 5.8.9 harfbuzz release 8.3.0 -skia release m115 +skia release m116 xunit release 2.4.2 xunit.runner.console release 2.4.2 OpenTK release 3.1.0 @@ -23,12 +23,12 @@ ANGLE release chromium/6275 # this is related to the API versions, not the library versions # - milestone: the skia milestone determined by Google/Chromium # - increment: the C API version increment caused by new APIs (externals\skia\include\c\sk_types.h) -libSkiaSharp milestone 115 +libSkiaSharp milestone 116 libSkiaSharp increment 0 # native sonames # ..0 -libSkiaSharp soname 115.0.0 +libSkiaSharp soname 116.0.0 # 0.<60000 + major*100 + minor*10 + micro>.0 HarfBuzz soname 0.60830.0 From aa4f2ffedbcf0eb1988c61e123a0436d6cad338b Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Mon, 15 Apr 2024 23:50:36 +0200 Subject: [PATCH 38/40] Expose SKBlender (#2830) --- .../ResourcesApi.generated.cs | 1 + .../SceneGraphApi.generated.cs | 1 + .../SkiaSharp.Skottie/SkottieApi.generated.cs | 1 + binding/SkiaSharp/SKBlender.cs | 63 ++++++ binding/SkiaSharp/SKColorSpace.cs | 5 + binding/SkiaSharp/SKData.cs | 5 + binding/SkiaSharp/SKFontManager.cs | 5 + binding/SkiaSharp/SKImageFilter.cs | 17 ++ binding/SkiaSharp/SKObject.cs | 1 + binding/SkiaSharp/SKPaint.cs | 5 + binding/SkiaSharp/SKRuntimeEffect.cs | 62 +++++ binding/SkiaSharp/SKShader.cs | 17 ++ binding/SkiaSharp/SKTypeface.cs | 5 + binding/SkiaSharp/SkiaApi.generated.cs | 163 ++++++++++++++ .../3.0.0/SkiaSharp.humanreadable.md | 2 +- externals/skia | 2 +- tests/Tests/GarbageCleanupFixture.cs | 1 + tests/Tests/SkiaSharp/SKBlenderTest.cs | 213 ++++++++++++++++++ 18 files changed, 567 insertions(+), 2 deletions(-) create mode 100644 binding/SkiaSharp/SKBlender.cs create mode 100644 tests/Tests/SkiaSharp/SKBlenderTest.cs diff --git a/binding/SkiaSharp.Resources/ResourcesApi.generated.cs b/binding/SkiaSharp.Resources/ResourcesApi.generated.cs index c5442998d7..71eb442fcc 100644 --- a/binding/SkiaSharp.Resources/ResourcesApi.generated.cs +++ b/binding/SkiaSharp.Resources/ResourcesApi.generated.cs @@ -18,6 +18,7 @@ using gr_vk_memory_allocator_t = System.IntPtr; using gr_vkinterface_t = System.IntPtr; using sk_bitmap_t = System.IntPtr; +using sk_blender_t = System.IntPtr; using sk_canvas_t = System.IntPtr; using sk_codec_t = System.IntPtr; using sk_colorfilter_t = System.IntPtr; diff --git a/binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs b/binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs index 29c4929b88..36d57c6fbc 100644 --- a/binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs +++ b/binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs @@ -18,6 +18,7 @@ using gr_vk_memory_allocator_t = System.IntPtr; using gr_vkinterface_t = System.IntPtr; using sk_bitmap_t = System.IntPtr; +using sk_blender_t = System.IntPtr; using sk_canvas_t = System.IntPtr; using sk_codec_t = System.IntPtr; using sk_colorfilter_t = System.IntPtr; diff --git a/binding/SkiaSharp.Skottie/SkottieApi.generated.cs b/binding/SkiaSharp.Skottie/SkottieApi.generated.cs index 9ea5421504..38f281ace3 100644 --- a/binding/SkiaSharp.Skottie/SkottieApi.generated.cs +++ b/binding/SkiaSharp.Skottie/SkottieApi.generated.cs @@ -18,6 +18,7 @@ using gr_vk_memory_allocator_t = System.IntPtr; using gr_vkinterface_t = System.IntPtr; using sk_bitmap_t = System.IntPtr; +using sk_blender_t = System.IntPtr; using sk_canvas_t = System.IntPtr; using sk_codec_t = System.IntPtr; using sk_colorfilter_t = System.IntPtr; diff --git a/binding/SkiaSharp/SKBlender.cs b/binding/SkiaSharp/SKBlender.cs new file mode 100644 index 0000000000..e4a82adede --- /dev/null +++ b/binding/SkiaSharp/SKBlender.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; + +namespace SkiaSharp; + +public unsafe class SKBlender : SKObject, ISKReferenceCounted +{ + private static readonly Dictionary blendModeBlenders; + + static SKBlender () + { + // TODO: This is not the best way to do this as it will create a lot of objects that + // might not be needed, but it is the only way to ensure that the static + // instances are created before any access is made to them. + // See more info: SKObject.EnsureStaticInstanceAreInitialized() + + var modes = Enum.GetValues (typeof (SKBlendMode)); + blendModeBlenders = new Dictionary (modes.Length); + foreach (SKBlendMode mode in modes) + { + blendModeBlenders [mode] = new SKBlenderStatic (SkiaApi.sk_blender_new_mode (mode)); + } + } + + internal static void EnsureStaticInstanceAreInitialized () + { + // IMPORTANT: do not remove to ensure that the static instances + // are initialized before any access is made to them + } + + internal SKBlender(IntPtr handle, bool owns) + : base (handle, owns) + { + } + + protected override void Dispose (bool disposing) => + base.Dispose (disposing); + + public static SKBlender CreateBlendMode (SKBlendMode mode) + { + if (!blendModeBlenders.TryGetValue (mode, out var value)) + throw new ArgumentOutOfRangeException (nameof (mode)); + return value; + } + + public static SKBlender CreateArithmetic (float k1, float k2, float k3, float k4, bool enforcePMColor) => + GetObject (SkiaApi.sk_blender_new_arithmetic (k1, k2, k3, k4, enforcePMColor)); + + internal static SKBlender GetObject (IntPtr handle) => + GetOrAddObject (handle, (h, o) => new SKBlender (h, o)); + + // + + private sealed class SKBlenderStatic : SKBlender + { + internal SKBlenderStatic (IntPtr x) + : base (x, false) + { + } + + protected override void Dispose (bool disposing) { } + } +} diff --git a/binding/SkiaSharp/SKColorSpace.cs b/binding/SkiaSharp/SKColorSpace.cs index 1b5680df8f..a639dac46f 100644 --- a/binding/SkiaSharp/SKColorSpace.cs +++ b/binding/SkiaSharp/SKColorSpace.cs @@ -12,6 +12,11 @@ public unsafe class SKColorSpace : SKObject, ISKNonVirtualReferenceCounted static SKColorSpace () { + // TODO: This is not the best way to do this as it will create a lot of objects that + // might not be needed, but it is the only way to ensure that the static + // instances are created before any access is made to them. + // See more info: SKObject.EnsureStaticInstanceAreInitialized() + srgb = new SKColorSpaceStatic (SkiaApi.sk_colorspace_new_srgb ()); srgbLinear = new SKColorSpaceStatic (SkiaApi.sk_colorspace_new_srgb_linear ()); } diff --git a/binding/SkiaSharp/SKData.cs b/binding/SkiaSharp/SKData.cs index a86a1bb954..af8f1f857f 100644 --- a/binding/SkiaSharp/SKData.cs +++ b/binding/SkiaSharp/SKData.cs @@ -19,6 +19,11 @@ public unsafe class SKData : SKObject, ISKNonVirtualReferenceCounted static SKData () { + // TODO: This is not the best way to do this as it will create a lot of objects that + // might not be needed, but it is the only way to ensure that the static + // instances are created before any access is made to them. + // See more info: SKObject.EnsureStaticInstanceAreInitialized() + empty = new SKDataStatic (SkiaApi.sk_data_new_empty ()); } diff --git a/binding/SkiaSharp/SKFontManager.cs b/binding/SkiaSharp/SKFontManager.cs index 4fa74bac7f..737b875155 100644 --- a/binding/SkiaSharp/SKFontManager.cs +++ b/binding/SkiaSharp/SKFontManager.cs @@ -14,6 +14,11 @@ public unsafe class SKFontManager : SKObject, ISKReferenceCounted static SKFontManager () { + // TODO: This is not the best way to do this as it will create a lot of objects that + // might not be needed, but it is the only way to ensure that the static + // instances are created before any access is made to them. + // See more info: SKObject.EnsureStaticInstanceAreInitialized() + defaultManager = new SKFontManagerStatic (SkiaApi.sk_fontmgr_ref_default ()); } diff --git a/binding/SkiaSharp/SKImageFilter.cs b/binding/SkiaSharp/SKImageFilter.cs index a1fceca6c8..45eea572e3 100644 --- a/binding/SkiaSharp/SKImageFilter.cs +++ b/binding/SkiaSharp/SKImageFilter.cs @@ -341,6 +341,23 @@ public static SKImageFilter CreateBlendMode (SKBlendMode mode, SKImageFilter? ba private static SKImageFilter CreateBlendMode (SKBlendMode mode, SKImageFilter? background, SKImageFilter? foreground, SKRect* cropRect) => GetObject (SkiaApi.sk_imagefilter_new_blend (mode, background?.Handle ?? IntPtr.Zero, foreground?.Handle ?? IntPtr.Zero, cropRect)); + // CreateBlendMode (Blender) + + public static SKImageFilter CreateBlendMode (SKBlender blender, SKImageFilter? background) => + CreateBlendMode (blender, background, null, null); + + public static SKImageFilter CreateBlendMode (SKBlender blender, SKImageFilter? background, SKImageFilter? foreground) => + CreateBlendMode (blender, background, foreground, null); + + public static SKImageFilter CreateBlendMode (SKBlender blender, SKImageFilter? background, SKImageFilter? foreground, SKRect cropRect) => + CreateBlendMode (blender, background, foreground, &cropRect); + + private static SKImageFilter CreateBlendMode (SKBlender blender, SKImageFilter? background, SKImageFilter? foreground, SKRect* cropRect) + { + _ = blender ?? throw new ArgumentNullException (nameof (blender)); + return GetObject (SkiaApi.sk_imagefilter_new_blender (blender.Handle, background?.Handle ?? IntPtr.Zero, foreground?.Handle ?? IntPtr.Zero, cropRect)); + } + // CreateArithmetic public static SKImageFilter CreateArithmetic (float k1, float k2, float k3, float k4, bool enforcePMColor, SKImageFilter? background) => diff --git a/binding/SkiaSharp/SKObject.cs b/binding/SkiaSharp/SKObject.cs index 4040ffd8c8..ddaae8b879 100644 --- a/binding/SkiaSharp/SKObject.cs +++ b/binding/SkiaSharp/SKObject.cs @@ -44,6 +44,7 @@ static SKObject () SKData.EnsureStaticInstanceAreInitialized (); SKFontManager.EnsureStaticInstanceAreInitialized (); SKTypeface.EnsureStaticInstanceAreInitialized (); + SKBlender.EnsureStaticInstanceAreInitialized (); } internal SKObject (IntPtr handle, bool owns) diff --git a/binding/SkiaSharp/SKPaint.cs b/binding/SkiaSharp/SKPaint.cs index 09dde1ff23..1e8d1be424 100644 --- a/binding/SkiaSharp/SKPaint.cs +++ b/binding/SkiaSharp/SKPaint.cs @@ -203,6 +203,11 @@ public SKBlendMode BlendMode { set => SkiaApi.sk_paint_set_blendmode (Handle, value); } + public SKBlender Blender { + get => SKBlender.GetObject (SkiaApi.sk_paint_get_blender (Handle)); + set => SkiaApi.sk_paint_set_blender (Handle, value == null ? IntPtr.Zero : value.Handle); + } + [Obsolete ($"Use {nameof (SKSamplingOptions)} instead.")] public SKFilterQuality FilterQuality { get => (SKFilterQuality)SkiaApi.sk_compatpaint_get_filter_quality (Handle); diff --git a/binding/SkiaSharp/SKRuntimeEffect.cs b/binding/SkiaSharp/SKRuntimeEffect.cs index 8487aa8f86..9a26537938 100644 --- a/binding/SkiaSharp/SKRuntimeEffect.cs +++ b/binding/SkiaSharp/SKRuntimeEffect.cs @@ -41,6 +41,17 @@ public static SKRuntimeEffect CreateColorFilter (string sksl, out string errors) return effect; } + public static SKRuntimeEffect CreateBlender (string sksl, out string errors) + { + using var s = new SKString (sksl); + using var errorString = new SKString (); + var effect = GetObject (SkiaApi.sk_runtimeeffect_make_for_blender (s.Handle, errorString.Handle)); + errors = errorString?.ToString (); + if (errors?.Length == 0) + errors = null; + return effect; + } + // Build* public static SKRuntimeShaderBuilder BuildShader (string sksl) @@ -57,6 +68,13 @@ public static SKRuntimeColorFilterBuilder BuildColorFilter (string sksl) return new SKRuntimeColorFilterBuilder (effect); } + public static SKRuntimeBlenderBuilder BuildBlender (string sksl) + { + var effect = CreateBlender (sksl, out var errors); + ValidateResult (effect, errors); + return new SKRuntimeBlenderBuilder (effect); + } + private static void ValidateResult (SKRuntimeEffect effect, string errors) { if (effect is null) { @@ -148,6 +166,30 @@ private SKColorFilter ToColorFilter (SKData uniforms, SKObject[] children) } } + // ToBlender + + public SKBlender ToBlender () => + ToBlender ((SKData)null, null); + + public SKBlender ToBlender (SKRuntimeEffectUniforms uniforms) => + ToBlender (uniforms.ToData (), null); + + private SKBlender ToBlender (SKData uniforms) => + ToBlender (uniforms, null); + + public SKBlender ToBlender (SKRuntimeEffectUniforms uniforms, SKRuntimeEffectChildren children) => + ToBlender (uniforms.ToData (), children.ToArray ()); + + private SKBlender ToBlender (SKData uniforms, SKObject[] children) + { + var uniformsHandle = uniforms?.Handle ?? IntPtr.Zero; + using var childrenHandles = Utils.RentHandlesArray (children, true); + + fixed (IntPtr* ch = childrenHandles) { + return SKBlender.GetObject (SkiaApi.sk_runtimeeffect_make_blender (Handle, uniformsHandle, ch, (IntPtr)childrenHandles.Length)); + } + } + // internal static SKRuntimeEffect GetObject (IntPtr handle) => @@ -560,15 +602,24 @@ public SKRuntimeEffectChild (SKColorFilter colorFilter) value = colorFilter; } + public SKRuntimeEffectChild (SKBlender blender) + { + value = blender; + } + public SKObject Value => value; public SKShader Shader => value as SKShader; public SKColorFilter ColorFilter => value as SKColorFilter; + public SKBlender Blender => value as SKBlender; + public static implicit operator SKRuntimeEffectChild (SKShader shader) => new (shader); public static implicit operator SKRuntimeEffectChild (SKColorFilter colorFilter) => new (colorFilter); + + public static implicit operator SKRuntimeEffectChild (SKBlender blender) => new (blender); } public class SKRuntimeEffectBuilderException : ApplicationException @@ -627,4 +678,15 @@ public SKRuntimeColorFilterBuilder (SKRuntimeEffect effect) public SKColorFilter Build () => Effect.ToColorFilter (Uniforms, Children); } + + public class SKRuntimeBlenderBuilder : SKRuntimeEffectBuilder + { + public SKRuntimeBlenderBuilder (SKRuntimeEffect effect) + : base (effect) + { + } + + public SKBlender Build () => + Effect.ToBlender (Uniforms, Children); + } } diff --git a/binding/SkiaSharp/SKShader.cs b/binding/SkiaSharp/SKShader.cs index 9216985672..6069b57776 100644 --- a/binding/SkiaSharp/SKShader.cs +++ b/binding/SkiaSharp/SKShader.cs @@ -408,6 +408,23 @@ public static SKShader CreateCompose (SKShader shaderA, SKShader shaderB, SKBlen return GetObject (SkiaApi.sk_shader_new_blend (mode, shaderA.Handle, shaderB.Handle)); } + // CreateBlend + + public static SKShader CreateBlend (SKBlendMode mode, SKShader shaderA, SKShader shaderB) + { + _ = shaderA ?? throw new ArgumentNullException (nameof (shaderA)); + _ = shaderB ?? throw new ArgumentNullException (nameof (shaderB)); + return GetObject (SkiaApi.sk_shader_new_blend (mode, shaderA.Handle, shaderB.Handle)); + } + + public static SKShader CreateBlend (SKBlender blender, SKShader shaderA, SKShader shaderB) + { + _ = shaderA ?? throw new ArgumentNullException (nameof (shaderA)); + _ = shaderB ?? throw new ArgumentNullException (nameof (shaderB)); + _ = blender ?? throw new ArgumentNullException (nameof (blender)); + return GetObject (SkiaApi.sk_shader_new_blender (blender.Handle, shaderA.Handle, shaderB.Handle)); + } + // CreateColorFilter public static SKShader CreateColorFilter (SKShader shader, SKColorFilter filter) diff --git a/binding/SkiaSharp/SKTypeface.cs b/binding/SkiaSharp/SKTypeface.cs index 3455c8ec29..f9ea664166 100644 --- a/binding/SkiaSharp/SKTypeface.cs +++ b/binding/SkiaSharp/SKTypeface.cs @@ -14,6 +14,11 @@ public unsafe class SKTypeface : SKObject, ISKReferenceCounted static SKTypeface () { + // TODO: This is not the best way to do this as it will create a lot of objects that + // might not be needed, but it is the only way to ensure that the static + // instances are created before any access is made to them. + // See more info: SKObject.EnsureStaticInstanceAreInitialized() + defaultTypeface = new SKTypefaceStatic (SkiaApi.sk_typeface_ref_default ()); } diff --git a/binding/SkiaSharp/SkiaApi.generated.cs b/binding/SkiaSharp/SkiaApi.generated.cs index 88b37249aa..3dd311d4dc 100644 --- a/binding/SkiaSharp/SkiaApi.generated.cs +++ b/binding/SkiaSharp/SkiaApi.generated.cs @@ -17,6 +17,7 @@ using gr_vk_memory_allocator_t = System.IntPtr; using gr_vkinterface_t = System.IntPtr; using sk_bitmap_t = System.IntPtr; +using sk_blender_t = System.IntPtr; using sk_canvas_t = System.IntPtr; using sk_codec_t = System.IntPtr; using sk_colorfilter_t = System.IntPtr; @@ -1414,6 +1415,66 @@ internal static bool sk_bitmap_try_alloc_pixels_with_flags (sk_bitmap_t cbitmap, #endregion + #region sk_blender.h + + // sk_blender_t* sk_blender_new_arithmetic(float k1, float k2, float k3, float k4, bool enforcePremul) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern sk_blender_t sk_blender_new_arithmetic (Single k1, Single k2, Single k3, Single k4, [MarshalAs (UnmanagedType.I1)] bool enforcePremul); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate sk_blender_t sk_blender_new_arithmetic (Single k1, Single k2, Single k3, Single k4, [MarshalAs (UnmanagedType.I1)] bool enforcePremul); + } + private static Delegates.sk_blender_new_arithmetic sk_blender_new_arithmetic_delegate; + internal static sk_blender_t sk_blender_new_arithmetic (Single k1, Single k2, Single k3, Single k4, [MarshalAs (UnmanagedType.I1)] bool enforcePremul) => + (sk_blender_new_arithmetic_delegate ??= GetSymbol ("sk_blender_new_arithmetic")).Invoke (k1, k2, k3, k4, enforcePremul); + #endif + + // sk_blender_t* sk_blender_new_mode(sk_blendmode_t mode) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern sk_blender_t sk_blender_new_mode (SKBlendMode mode); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate sk_blender_t sk_blender_new_mode (SKBlendMode mode); + } + private static Delegates.sk_blender_new_mode sk_blender_new_mode_delegate; + internal static sk_blender_t sk_blender_new_mode (SKBlendMode mode) => + (sk_blender_new_mode_delegate ??= GetSymbol ("sk_blender_new_mode")).Invoke (mode); + #endif + + // void sk_blender_ref(sk_blender_t* blender) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_blender_ref (sk_blender_t blender); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_blender_ref (sk_blender_t blender); + } + private static Delegates.sk_blender_ref sk_blender_ref_delegate; + internal static void sk_blender_ref (sk_blender_t blender) => + (sk_blender_ref_delegate ??= GetSymbol ("sk_blender_ref")).Invoke (blender); + #endif + + // void sk_blender_unref(sk_blender_t* blender) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_blender_unref (sk_blender_t blender); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_blender_unref (sk_blender_t blender); + } + private static Delegates.sk_blender_unref sk_blender_unref_delegate; + internal static void sk_blender_unref (sk_blender_t blender) => + (sk_blender_unref_delegate ??= GetSymbol ("sk_blender_unref")).Invoke (blender); + #endif + + #endregion + #region sk_canvas.h // void sk_canvas_clear(sk_canvas_t* ccanvas, sk_color_t color) @@ -5326,6 +5387,20 @@ internal static sk_imagefilter_t sk_imagefilter_new_blend (SKBlendMode mode, sk_ (sk_imagefilter_new_blend_delegate ??= GetSymbol ("sk_imagefilter_new_blend")).Invoke (mode, background, foreground, cropRect); #endif + // sk_imagefilter_t* sk_imagefilter_new_blender(sk_blender_t* blender, const sk_imagefilter_t* background, const sk_imagefilter_t* foreground, const sk_rect_t* cropRect) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern sk_imagefilter_t sk_imagefilter_new_blender (sk_blender_t blender, sk_imagefilter_t background, sk_imagefilter_t foreground, SKRect* cropRect); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate sk_imagefilter_t sk_imagefilter_new_blender (sk_blender_t blender, sk_imagefilter_t background, sk_imagefilter_t foreground, SKRect* cropRect); + } + private static Delegates.sk_imagefilter_new_blender sk_imagefilter_new_blender_delegate; + internal static sk_imagefilter_t sk_imagefilter_new_blender (sk_blender_t blender, sk_imagefilter_t background, sk_imagefilter_t foreground, SKRect* cropRect) => + (sk_imagefilter_new_blender_delegate ??= GetSymbol ("sk_imagefilter_new_blender")).Invoke (blender, background, foreground, cropRect); + #endif + // sk_imagefilter_t* sk_imagefilter_new_blur(float sigmaX, float sigmaY, sk_shader_tilemode_t tileMode, const sk_imagefilter_t* input, const sk_rect_t* cropRect) #if !USE_DELEGATES [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] @@ -5706,6 +5781,24 @@ internal static void sk_imagefilter_unref (sk_imagefilter_t cfilter) => #endregion + #region sk_linker.h + + // void sk_linker_keep_alive() + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_linker_keep_alive (); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_linker_keep_alive (); + } + private static Delegates.sk_linker_keep_alive sk_linker_keep_alive_delegate; + internal static void sk_linker_keep_alive () => + (sk_linker_keep_alive_delegate ??= GetSymbol ("sk_linker_keep_alive")).Invoke (); + #endif + + #endregion + #region sk_maskfilter.h // sk_maskfilter_t* sk_maskfilter_new_blur(sk_blurstyle_t, float sigma) @@ -5998,6 +6091,20 @@ internal static void sk_paint_delete (sk_paint_t param0) => (sk_paint_delete_delegate ??= GetSymbol ("sk_paint_delete")).Invoke (param0); #endif + // sk_blender_t* sk_paint_get_blender(sk_paint_t* cpaint) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern sk_blender_t sk_paint_get_blender (sk_paint_t cpaint); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate sk_blender_t sk_paint_get_blender (sk_paint_t cpaint); + } + private static Delegates.sk_paint_get_blender sk_paint_get_blender_delegate; + internal static sk_blender_t sk_paint_get_blender (sk_paint_t cpaint) => + (sk_paint_get_blender_delegate ??= GetSymbol ("sk_paint_get_blender")).Invoke (cpaint); + #endif + // sk_blendmode_t sk_paint_get_blendmode(sk_paint_t*) #if !USE_DELEGATES [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] @@ -6270,6 +6377,20 @@ internal static void sk_paint_set_antialias (sk_paint_t param0, [MarshalAs (Unma (sk_paint_set_antialias_delegate ??= GetSymbol ("sk_paint_set_antialias")).Invoke (param0, param1); #endif + // void sk_paint_set_blender(sk_paint_t* paint, sk_blender_t* blender) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_paint_set_blender (sk_paint_t paint, sk_blender_t blender); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_paint_set_blender (sk_paint_t paint, sk_blender_t blender); + } + private static Delegates.sk_paint_set_blender sk_paint_set_blender_delegate; + internal static void sk_paint_set_blender (sk_paint_t paint, sk_blender_t blender) => + (sk_paint_set_blender_delegate ??= GetSymbol ("sk_paint_set_blender")).Invoke (paint, blender); + #endif + // void sk_paint_set_blendmode(sk_paint_t*, sk_blendmode_t) #if !USE_DELEGATES [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] @@ -9456,6 +9577,20 @@ private partial class Delegates { (sk_runtimeeffect_get_uniforms_size_delegate ??= GetSymbol ("sk_runtimeeffect_get_uniforms_size")).Invoke (effect); #endif + // sk_blender_t* sk_runtimeeffect_make_blender(sk_runtimeeffect_t* effect, sk_data_t* uniforms, sk_flattenable_t** children, size_t childCount) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern sk_blender_t sk_runtimeeffect_make_blender (sk_runtimeeffect_t effect, sk_data_t uniforms, sk_flattenable_t* children, /* size_t */ IntPtr childCount); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate sk_blender_t sk_runtimeeffect_make_blender (sk_runtimeeffect_t effect, sk_data_t uniforms, sk_flattenable_t* children, /* size_t */ IntPtr childCount); + } + private static Delegates.sk_runtimeeffect_make_blender sk_runtimeeffect_make_blender_delegate; + internal static sk_blender_t sk_runtimeeffect_make_blender (sk_runtimeeffect_t effect, sk_data_t uniforms, sk_flattenable_t* children, /* size_t */ IntPtr childCount) => + (sk_runtimeeffect_make_blender_delegate ??= GetSymbol ("sk_runtimeeffect_make_blender")).Invoke (effect, uniforms, children, childCount); + #endif + // sk_colorfilter_t* sk_runtimeeffect_make_color_filter(sk_runtimeeffect_t* effect, sk_data_t* uniforms, sk_flattenable_t** children, size_t childCount) #if !USE_DELEGATES [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] @@ -9470,6 +9605,20 @@ internal static sk_colorfilter_t sk_runtimeeffect_make_color_filter (sk_runtimee (sk_runtimeeffect_make_color_filter_delegate ??= GetSymbol ("sk_runtimeeffect_make_color_filter")).Invoke (effect, uniforms, children, childCount); #endif + // sk_runtimeeffect_t* sk_runtimeeffect_make_for_blender(sk_string_t* sksl, sk_string_t* error) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern sk_runtimeeffect_t sk_runtimeeffect_make_for_blender (sk_string_t sksl, sk_string_t error); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate sk_runtimeeffect_t sk_runtimeeffect_make_for_blender (sk_string_t sksl, sk_string_t error); + } + private static Delegates.sk_runtimeeffect_make_for_blender sk_runtimeeffect_make_for_blender_delegate; + internal static sk_runtimeeffect_t sk_runtimeeffect_make_for_blender (sk_string_t sksl, sk_string_t error) => + (sk_runtimeeffect_make_for_blender_delegate ??= GetSymbol ("sk_runtimeeffect_make_for_blender")).Invoke (sksl, error); + #endif + // sk_runtimeeffect_t* sk_runtimeeffect_make_for_color_filter(sk_string_t* sksl, sk_string_t* error) #if !USE_DELEGATES [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] @@ -9544,6 +9693,20 @@ internal static sk_shader_t sk_shader_new_blend (SKBlendMode mode, sk_shader_t d (sk_shader_new_blend_delegate ??= GetSymbol ("sk_shader_new_blend")).Invoke (mode, dst, src); #endif + // sk_shader_t* sk_shader_new_blender(sk_blender_t* blender, const sk_shader_t* dst, const sk_shader_t* src) + #if !USE_DELEGATES + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern sk_shader_t sk_shader_new_blender (sk_blender_t blender, sk_shader_t dst, sk_shader_t src); + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate sk_shader_t sk_shader_new_blender (sk_blender_t blender, sk_shader_t dst, sk_shader_t src); + } + private static Delegates.sk_shader_new_blender sk_shader_new_blender_delegate; + internal static sk_shader_t sk_shader_new_blender (sk_blender_t blender, sk_shader_t dst, sk_shader_t src) => + (sk_shader_new_blender_delegate ??= GetSymbol ("sk_shader_new_blender")).Invoke (blender, dst, src); + #endif + // sk_shader_t* sk_shader_new_color(sk_color_t color) #if !USE_DELEGATES [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] diff --git a/changelogs/SkiaSharp/3.0.0/SkiaSharp.humanreadable.md b/changelogs/SkiaSharp/3.0.0/SkiaSharp.humanreadable.md index 0ba58ee800..111da80d82 100644 --- a/changelogs/SkiaSharp/3.0.0/SkiaSharp.humanreadable.md +++ b/changelogs/SkiaSharp/3.0.0/SkiaSharp.humanreadable.md @@ -32,7 +32,7 @@ There are some small improvements in the initial release of 3.x, and many more w * `SKPoint3` is now implicitly compatible with `System.Numerics.Vector3` in both directions. * `SKPointI` is now implicitly cast to `System.Numerics.Vector3`. * `SKRuntimeEffect` now works on both CPU and GPU: - * GPU is accelerated and support more targets: `SKColorFilter` and `SKShader` (there is also a new `SKBlender` that is not yet exposed in SkiaSharp). + * GPU is accelerated and support more targets: `SKColorFilter`, `SKShader` and the new `SKBlender`. * CPU is NOT accelerated and may be very slow. * `SKMatrix44` is now a high-performance struct that can be used on any `SKCanvas`. diff --git a/externals/skia b/externals/skia index 8684edb4e6..f1c2f7b424 160000 --- a/externals/skia +++ b/externals/skia @@ -1 +1 @@ -Subproject commit 8684edb4e68d2bbf0d56a600633f5d4c44a16a36 +Subproject commit f1c2f7b4246141c6037820dc75d89496ac4aa8b3 diff --git a/tests/Tests/GarbageCleanupFixture.cs b/tests/Tests/GarbageCleanupFixture.cs index a3518a83ee..4f1cfaa582 100644 --- a/tests/Tests/GarbageCleanupFixture.cs +++ b/tests/Tests/GarbageCleanupFixture.cs @@ -16,6 +16,7 @@ public class GarbageCleanupFixture : IDisposable "SkiaSharp.SKFontStyle+SKFontStyleStatic", "SkiaSharp.SKTypeface+SKTypefaceStatic", "SkiaSharp.SKColorSpace+SKColorSpaceStatic", + "SkiaSharp.SKBlender+SKBlenderStatic", }; public GarbageCleanupFixture() diff --git a/tests/Tests/SkiaSharp/SKBlenderTest.cs b/tests/Tests/SkiaSharp/SKBlenderTest.cs new file mode 100644 index 0000000000..b7a01ad8b5 --- /dev/null +++ b/tests/Tests/SkiaSharp/SKBlenderTest.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; +using Xunit; + +namespace SkiaSharp.Tests; + +public class SKBlenderTest +{ + [SkippableFact] + public void SameBlendModeReturnsSameBlenderInstance() + { + var blender1 = SKBlender.CreateBlendMode(SKBlendMode.Src); + var blender2 = SKBlender.CreateBlendMode(SKBlendMode.Src); + + Assert.Same(blender1, blender2); + } + + [SkippableFact] + public void BlendModeBlenderIsNotDisposed() + { + var blender = SKBlender.CreateBlendMode(SKBlendMode.Src); + Assert.True(SKObject.GetInstance(blender.Handle, out _)); + + blender.Dispose(); + Assert.True(SKObject.GetInstance(blender.Handle, out _)); + } + + [SkippableFact] + public void ArithmeticBlendModeBlenderIsBlendModeBlender() + { + var blendmode = SKBlender.CreateBlendMode(SKBlendMode.Src); + + var arithmetic = SKBlender.CreateArithmetic(0, 1, 0, 0, false); + + Assert.Same(blendmode, arithmetic); + } + + [SkippableFact] + public void InvalidBlendModeThrowsArgumentException() + { + Assert.Throws(() => SKBlender.CreateBlendMode((SKBlendMode)100)); + } + + public abstract class SurfaceTestBase : SKTest + { + protected SKSurface Surface { get; set; } + + protected SKImageInfo Info { get; set; } + + protected abstract void CreateSurface(int width, int height); + + [SkippableTheory] + [MemberData(nameof(GetAllBlendModes))] + public void BlenderMatchesBlendModeWhenUsingOpaqueColor(SKBlendMode mode) + { + var blendModeColor = GetColor(p => ApplyColor(p, false), p => ApplyBlendMode(p, mode)); + var blenderColor = GetColor(p => ApplyColor(p, false), p => ApplyBlender(p, mode)); + Assert.Equal(blendModeColor, blenderColor); + } + + [SkippableTheory] + [MemberData(nameof(GetAllBlendModes))] + public void BlenderMatchesBlendModeWhenUsingransparentColor(SKBlendMode mode) + { + var blendModeColor = GetColor(p => ApplyColor(p, true), p => ApplyBlendMode(p, mode)); + var blenderColor = GetColor(p => ApplyColor(p, true), p => ApplyBlender(p, mode)); + Assert.Equal(blendModeColor, blenderColor); + } + + [SkippableTheory] + [MemberData(nameof(GetAllBlendModes))] + public void BlenderMatchesBlendModeWhenUsingOpaqueShader(SKBlendMode mode) + { + var blendModeColor = GetColor(p => ApplyColorShader(p, false), p => ApplyBlendMode(p, mode)); + var blenderColor = GetColor(p => ApplyColorShader(p, false), p => ApplyBlender(p, mode)); + Assert.Equal(blendModeColor, blenderColor); + } + + [SkippableTheory] + [MemberData(nameof(GetAllBlendModes))] + public void BlenderMatchesBlendModeWhenUsingransparentShader(SKBlendMode mode) + { + var blendModeColor = GetColor(p => ApplyColorShader(p, true), p => ApplyBlendMode(p, mode)); + var blenderColor = GetColor(p => ApplyColorShader(p, true), p => ApplyBlender(p, mode)); + Assert.Equal(blendModeColor, blenderColor); + } + + private SKColor GetColor(Action applyColor, Action applyBlend) + { + // Draw a solid red pixel. + using var paint = new SKPaint + { + Shader = null, + Color = SKColors.Red, + Blender = null, + BlendMode = SKBlendMode.Src, + }; + Surface.Canvas.DrawRect(SKRect.Create(1, 1), paint); + + // Draw a blue pixel on top of it, using the passed-in blend mode. + applyColor(paint); + applyBlend(paint); + Surface.Canvas.DrawRect(SKRect.Create(1, 1), paint); + + // Read the pixels out of the surface and into the bitmap. + using var bmp = new SKBitmap(new SKImageInfo(1, 1)); + Surface.ReadPixels(bmp.Info, bmp.GetPixels(), bmp.RowBytes, 0, 0); + + // Get the pixel color. + return bmp.GetPixel(0, 0); + } + + private static void ApplyBlendMode(SKPaint paint, SKBlendMode mode) => + paint.BlendMode = mode; + + private static void ApplyBlender(SKPaint paint, SKBlendMode mode) => + paint.Blender = GetRuntimeBlenderForBlendMode(mode); + + private static void ApplyColor(SKPaint paint, bool useTransparent) + { + var alpha = GetAlpha(useTransparent); + paint.Color = new SKColor(0x00, 0x00, 0xFF, alpha); + } + + private static void ApplyColorShader(SKPaint paint, bool useTransparent) + { + // Install a different color in the paint, to ensure we're using the shader + paint.Color = SKColors.Green; + + var alpha = GetAlpha(useTransparent); + paint.Shader = SKShader.CreateColor(new SKColor(0x00, 0x00, 0xFF, alpha)); + } + + private static byte GetAlpha(bool useTransparent) => + useTransparent ? (byte)0x80 : (byte)0xFF; + + public static IEnumerable GetAllBlendModes() + { + foreach (SKBlendMode mode in Enum.GetValues(typeof(SKBlendMode))) + yield return new object[] { mode }; + } + + private static SKBlender GetRuntimeBlenderForBlendMode(SKBlendMode mode) + { + using var builder = SKRuntimeEffect.BuildBlender( + """ + uniform blender b; + half4 main(half4 src, half4 dst) { + return b.eval(src, dst); + } + """); + + Assert.NotNull(builder.Effect); + + builder.Children["b"] = SKBlender.CreateBlendMode(mode); + + return builder.Build(); + } + } + + [Trait(Traits.Category.Key, Traits.Category.Values.Gpu)] + public unsafe class Gpu : SurfaceTestBase, IDisposable + { + GlContext glContext; + GRContext grContext; + + public Gpu() + { + glContext = CreateGlContext(); + glContext.MakeCurrent(); + + grContext = GRContext.CreateGl(); + + CreateSurface(1, 1); + } + + protected override void CreateSurface(int width, int height) + { + Surface?.Dispose(); + + Info = new SKImageInfo(width, height, SKColorType.Rgba8888); + Surface = SKSurface.Create(grContext, false, Info); + } + + public void Dispose() + { + Surface.Dispose(); + grContext.Dispose(); + glContext.Destroy(); + } + } + + public unsafe class Raster : SurfaceTestBase, IDisposable + { + public Raster() + { + CreateSurface(1, 1); + } + + protected override void CreateSurface(int width, int height) + { + Surface?.Dispose(); + + Info = new SKImageInfo(width, height, SKColorType.Rgba8888); + Surface = SKSurface.Create(Info); + } + + public void Dispose() + { + Surface.Dispose(); + } + } +} From 8a59d53c7aa3c492cff9befcda7954e6b83e4595 Mon Sep 17 00:00:00 2001 From: Fxplorer <154011238+Fxplorer@users.noreply.github.com> Date: Sun, 28 Apr 2024 05:56:01 -0400 Subject: [PATCH 39/40] fix typo in README.dib (#2839) --- interactive/README.dib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactive/README.dib b/interactive/README.dib index 75a567c83c..bbe466d809 100644 --- a/interactive/README.dib +++ b/interactive/README.dib @@ -4,7 +4,7 @@ Welcome to SkiaSharp, the most awesome, cross-platform 2D-graphics engine. It is powered by the same engine that powers Android and Chrome. -The first thing we need to do is intsall the package: +The first thing we need to do is install the package: #!csharp From bfd166e463f622a831956c93e2b35167e7c011b4 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Fri, 3 May 2024 22:19:50 +0800 Subject: [PATCH 40/40] Create similarissues.yml (#2851) --- .github/workflows/similarissues.yml | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/similarissues.yml diff --git a/.github/workflows/similarissues.yml b/.github/workflows/similarissues.yml new file mode 100644 index 0000000000..73a49f265b --- /dev/null +++ b/.github/workflows/similarissues.yml @@ -0,0 +1,38 @@ +name: Find Similar Issues + +on: + issues: + types: [opened] + issue_comment: + types: [created] + +jobs: + getSimilarIssues: + runs-on: ubuntu-latest + if: >- + (github.event_name == 'issues' && github.event.action == 'opened') || + (github.event_name == 'issue_comment' && github.event.action == 'created' && startsWith(github.event.comment.body, '/similarissues')) + outputs: + message: ${{ steps.getBody.outputs.message }} + steps: + - id: getBody + uses: craigloewen-msft/GitGudSimilarIssues@main + with: + issueTitle: ${{ github.event.issue.title }} + issueBody: ${{ github.event.issue.body }} + repo: ${{ github.repository }} + similaritytolerance: "0.70" + add-comment: + needs: getSimilarIssues + runs-on: ubuntu-latest + permissions: + issues: write + if: needs.getSimilarIssues.outputs.message != '' + steps: + - name: Add comment + run: gh issue comment "$NUMBER" --repo "$REPO" --body "$BODY" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NUMBER: ${{ github.event.issue.number }} + REPO: ${{ github.repository }} + BODY: ${{ needs.getSimilarIssues.outputs.message }}