From 872f036d6486c4943b5f1d287165eb1338a19edf Mon Sep 17 00:00:00 2001
From: Mary-nyan <mary@mary.zone>
Date: Fri, 9 Dec 2022 18:00:53 +0100
Subject: [PATCH] misc: Remove dependency on System.Drawing.Common (#4082)

We only used it in one spot for DPI scaling factor.

This implements the same behaviour using gdiplus.

This remove 700KB of dependency to download and around 170KB unpacked.
---
 Ryujinx.Common/Ryujinx.Common.csproj   |  1 -
 Ryujinx.Common/System/ForceDpiAware.cs |  3 +-
 Ryujinx.Common/System/GdiPlusHelper.cs | 76 ++++++++++++++++++++++++++
 3 files changed, 77 insertions(+), 3 deletions(-)
 create mode 100644 Ryujinx.Common/System/GdiPlusHelper.cs

diff --git a/Ryujinx.Common/Ryujinx.Common.csproj b/Ryujinx.Common/Ryujinx.Common.csproj
index ef5bbae7..9a83c2b4 100644
--- a/Ryujinx.Common/Ryujinx.Common.csproj
+++ b/Ryujinx.Common/Ryujinx.Common.csproj
@@ -7,7 +7,6 @@
 
   <ItemGroup>
     <PackageReference Include="MsgPack.Cli" Version="1.0.1" />
-    <PackageReference Include="System.Drawing.Common" Version="7.0.0" />
     <PackageReference Include="System.Management" Version="7.0.0" />
   </ItemGroup>
 
diff --git a/Ryujinx.Common/System/ForceDpiAware.cs b/Ryujinx.Common/System/ForceDpiAware.cs
index d40d5f5e..8d19876e 100644
--- a/Ryujinx.Common/System/ForceDpiAware.cs
+++ b/Ryujinx.Common/System/ForceDpiAware.cs
@@ -1,6 +1,5 @@
 using Ryujinx.Common.Logging;
 using System;
-using System.Drawing;
 using System.Globalization;
 using System.Runtime.InteropServices;
 
@@ -51,7 +50,7 @@ namespace Ryujinx.Common.System
             {
                 if (OperatingSystem.IsWindows())
                 {
-                    userDpiScale = Graphics.FromHwnd(IntPtr.Zero).DpiX;
+                    userDpiScale = GdiPlusHelper.GetDpiX(IntPtr.Zero);
                 }
                 else if (OperatingSystem.IsLinux())
                 {
diff --git a/Ryujinx.Common/System/GdiPlusHelper.cs b/Ryujinx.Common/System/GdiPlusHelper.cs
new file mode 100644
index 00000000..c084c651
--- /dev/null
+++ b/Ryujinx.Common/System/GdiPlusHelper.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+
+namespace Ryujinx.Common.System
+{
+    [SupportedOSPlatform("windows")]
+    public static class GdiPlusHelper
+    {
+        private const string LibraryName = "gdiplus.dll";
+
+        private static readonly IntPtr _initToken;
+
+        static GdiPlusHelper()
+        {
+            CheckStatus(GdiplusStartup(out _initToken, StartupInputEx.Default, out _));
+        }
+
+        private static void CheckStatus(int gdiStatus)
+        {
+            if (gdiStatus != 0)
+            {
+                throw new Exception($"GDI Status Error: {gdiStatus}");
+            }
+        }
+
+        private struct StartupInputEx
+        {
+            public int GdiplusVersion;
+
+#pragma warning disable CS0649
+            public IntPtr DebugEventCallback;
+            public int SuppressBackgroundThread;
+            public int SuppressExternalCodecs;
+            public int StartupParameters;
+#pragma warning restore CS0649
+
+            public static StartupInputEx Default => new StartupInputEx
+            {
+                // We assume Windows 8 and upper
+                GdiplusVersion = 2,
+                DebugEventCallback = IntPtr.Zero,
+                SuppressBackgroundThread = 0,
+                SuppressExternalCodecs = 0,
+                StartupParameters = 0,
+            };
+        }
+
+        private struct StartupOutput
+        {
+            public IntPtr NotificationHook;
+            public IntPtr NotificationUnhook;
+        }
+
+        [DllImport(LibraryName)]
+        private static extern int GdiplusStartup(out IntPtr token, in StartupInputEx input, out StartupOutput output);
+
+        [DllImport(LibraryName)]
+        private static extern int GdipCreateFromHWND(IntPtr hwnd, out IntPtr graphics);
+
+        [DllImport(LibraryName)]
+        private static extern int GdipDeleteGraphics(IntPtr graphics);
+
+        [DllImport(LibraryName)]
+        private static extern int GdipGetDpiX(IntPtr graphics, out float dpi);
+
+        public static float GetDpiX(IntPtr hwnd)
+        {
+            CheckStatus(GdipCreateFromHWND(hwnd, out IntPtr graphicsHandle));
+            CheckStatus(GdipGetDpiX(graphicsHandle, out float result));
+            CheckStatus(GdipDeleteGraphics(graphicsHandle));
+
+            return result;
+        }
+    }
+}