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 ^ ^ ^