From 6414cd77e83bf1f2ad2c0972e8c97d52581a3d81 Mon Sep 17 00:00:00 2001 From: Anna Clemens Date: Sat, 5 Feb 2022 03:12:37 -0500 Subject: [PATCH] feat: use newer way of getting fonts --- ChatTwo/ChatTwo.csproj | 5 +- ChatTwo/PluginUi.cs | 45 ++++++--- ChatTwo/Ui/Fonts.cs | 156 ++++++++++++++++++++--------- ChatTwo/Ui/SettingsTabs/Display.cs | 24 ++--- 4 files changed, 148 insertions(+), 82 deletions(-) diff --git a/ChatTwo/ChatTwo.csproj b/ChatTwo/ChatTwo.csproj index 8f6244d..ebe4f5f 100755 --- a/ChatTwo/ChatTwo.csproj +++ b/ChatTwo/ChatTwo.csproj @@ -48,8 +48,7 @@ - - + @@ -80,4 +79,4 @@ - + \ No newline at end of file diff --git a/ChatTwo/PluginUi.cs b/ChatTwo/PluginUi.cs index 2f0ffa1..c5ab658 100755 --- a/ChatTwo/PluginUi.cs +++ b/ChatTwo/PluginUi.cs @@ -32,9 +32,9 @@ internal sealed class PluginUi : IDisposable { private List Components { get; } private ImFontConfigPtr _fontCfg; private ImFontConfigPtr _fontCfgMerge; - private (GCHandle, int) _regularFont; - private (GCHandle, int) _italicFont; - private (GCHandle, int) _jpFont; + private (GCHandle, int, float) _regularFont; + private (GCHandle, int, float) _italicFont; + private (GCHandle, int, float) _jpFont; private (GCHandle, int) _gameSymFont; private readonly ImVector _ranges; @@ -121,10 +121,18 @@ internal sealed class PluginUi : IDisposable { if (this.Plugin.Config.GlobalFont.StartsWith(Fonts.IncludedIndicator)) { var globalFont = Fonts.GlobalFonts.FirstOrDefault(font => font.Name == this.Plugin.Config.GlobalFont); if (globalFont != null) { - fontData = new FontData(this.GetResource(globalFont.ResourcePath), this.GetResource(globalFont.ResourcePathItalic)); + var regular = new FaceData(this.GetResource(globalFont.ResourcePath), 1f); + var italic = new FaceData(this.GetResource(globalFont.ResourcePathItalic), 1f); + fontData = new FontData(regular, italic); } } else { fontData = Fonts.GetFont(this.Plugin.Config.GlobalFont, true); + if (fontData != null) { + File.WriteAllBytes(@"D:\font.ttf", fontData.Regular.Data); + if (fontData.Italic != null) { + File.WriteAllBytes(@"D:\font_italic.ttf", fontData.Italic.Data); + } + } } if (fontData == null) { @@ -132,7 +140,9 @@ internal sealed class PluginUi : IDisposable { this.Plugin.SaveConfig(); var globalFont = Fonts.GlobalFonts[0]; - fontData = new FontData(this.GetResource(globalFont.ResourcePath), this.GetResource(globalFont.ResourcePathItalic)); + var regular = new FaceData(this.GetResource(globalFont.ResourcePath), 1f); + var italic = new FaceData(this.GetResource(globalFont.ResourcePathItalic), 1f); + fontData = new FontData(regular, italic); } if (this._regularFont.Item1.IsAllocated) { @@ -144,20 +154,25 @@ internal sealed class PluginUi : IDisposable { } this._regularFont = ( - GCHandle.Alloc(fontData.Regular, GCHandleType.Pinned), - fontData.Regular.Length + GCHandle.Alloc(fontData.Regular.Data, GCHandleType.Pinned), + fontData.Regular.Data.Length, + fontData.Regular.Ratio ); this._italicFont = ( - GCHandle.Alloc(fontData.Italic, GCHandleType.Pinned), - fontData.Italic.Length + GCHandle.Alloc(fontData.Italic!.Data, GCHandleType.Pinned), + fontData.Italic.Data.Length, + fontData.Italic.Ratio ); FontData? jpFontData = null; if (this.Plugin.Config.JapaneseFont.StartsWith(Fonts.IncludedIndicator)) { var jpFont = Fonts.JapaneseFonts.FirstOrDefault(item => item.Item1 == this.Plugin.Config.JapaneseFont); if (jpFont != default) { - jpFontData = new FontData(this.GetResource(jpFont.Item2), Array.Empty()); + jpFontData = new FontData( + new FaceData(this.GetResource(jpFont.Item2), 1f), + null + ); } } // else { @@ -170,7 +185,10 @@ internal sealed class PluginUi : IDisposable { this.Plugin.SaveConfig(); var jpFont = Fonts.JapaneseFonts[0]; - jpFontData = new FontData(this.GetResource(jpFont.Item2), Array.Empty()); + jpFontData = new FontData( + new FaceData(this.GetResource(jpFont.Item2), 1f), + null + ); } if (this._jpFont.Item1.IsAllocated) { @@ -178,8 +196,9 @@ internal sealed class PluginUi : IDisposable { } this._jpFont = ( - GCHandle.Alloc(jpFontData.Regular, GCHandleType.Pinned), - jpFontData.Regular.Length + GCHandle.Alloc(jpFontData.Regular.Data, GCHandleType.Pinned), + jpFontData.Regular.Data.Length, + jpFontData.Regular.Ratio ); } diff --git a/ChatTwo/Ui/Fonts.cs b/ChatTwo/Ui/Fonts.cs index a4b83bc..36ddcfd 100755 --- a/ChatTwo/Ui/Fonts.cs +++ b/ChatTwo/Ui/Fonts.cs @@ -1,5 +1,7 @@ -using System.Drawing; -using Vanara.PInvoke; +using System.Runtime.InteropServices; +using Dalamud.Logging; +using SharpDX.DirectWrite; +using FontStyle = SharpDX.DirectWrite.FontStyle; namespace ChatTwo.Ui; @@ -34,73 +36,131 @@ internal static class Fonts { // ($"{IncludedIndicator}Noto Serif JP", "ChatTwo.fonts.NotoSerifJP-Regular.otf"), }; - internal static List GetJpFonts() { + internal static List GetFonts() { var fonts = new List(); - using var g = Graphics.FromImage(new Bitmap(1, 1)); - foreach (var (lpelfe, _, fontType) in Gdi32.EnumFontFamiliesEx(g.GetHdc(), CharacterSet.SHIFTJIS_CHARSET)) { - var name = lpelfe.elfEnumLogfontEx.elfLogFont.lfFaceName; - if (name.StartsWith("@")) { + + using var factory = new Factory(); + using var collection = factory.GetSystemFontCollection(false); + for (var i = 0; i < collection.FontFamilyCount; i++) { + using var family = collection.GetFontFamily(i); + PluginLog.Log(family.FamilyNames.GetString(0)); + var anyItalic = false; + for (var j = 0; j < family.FontCount; j++) { + using var font = family.GetFont(j); + if (font.Style is not (FontStyle.Italic or FontStyle.Oblique)) { + continue; + } + + anyItalic = true; + break; + } + + if (!anyItalic) { continue; } + var name = family.FamilyNames.GetString(0); fonts.Add(name); } + fonts.Sort(); + return fonts; + } + + internal static List GetJpFonts() { + var fonts = new List(); + // using var g = Graphics.FromImage(new Bitmap(1, 1)); + // foreach (var (lpelfe, _, fontType) in Gdi32.EnumFontFamiliesEx(g.GetHdc(), CharacterSet.SHIFTJIS_CHARSET)) { + // var name = lpelfe.elfEnumLogfontEx.elfLogFont.lfFaceName; + // if (name.StartsWith("@")) { + // continue; + // } + // + // fonts.Add(name); + // } + return fonts; } - internal static unsafe FontData? GetFont(string name, bool withItalic, CharacterSet charset = CharacterSet.ANSI_CHARSET) { - var regularFont = Gdi32.CreateFontIndirect(new LOGFONT { - lfFaceName = name, - lfItalic = false, - lfCharSet = charset, - lfOutPrecision = LogFontOutputPrecision.OUT_TT_ONLY_PRECIS, - }); - - using var g = Graphics.FromImage(new Bitmap(1, 1)); - var hdc = g.GetHdc(); - - byte[]? GetFontData(HGDIOBJ obj) { - Gdi32.SelectObject(hdc, obj); - var size = Gdi32.GetFontData(hdc, pvBuffer: IntPtr.Zero); - var data = new byte[size]; - fixed (byte* p = data) { - var res = Gdi32.GetFontData(hdc, pvBuffer: (IntPtr) p, cjBuffer: size); - Gdi32.DeleteObject(obj); - if (res == Gdi32.GDI_ERROR) { - return null; - } + internal static FontData? GetFont(string name, bool withItalic) { + using var factory = new Factory(); + using var collection = factory.GetSystemFontCollection(false); + for (var i = 0; i < collection.FontFamilyCount; i++) { + using var family = collection.GetFontFamily(i); + if (family.FamilyNames.GetString(0) != name) { + continue; } - return data; + using var normal = family.GetFirstMatchingFont(FontWeight.Normal, FontStretch.Normal, FontStyle.Normal); + if (normal == null) { + return null; + } + + FaceData? GetFontData(SharpDX.DirectWrite.Font font) { + using var face = new FontFace(font); + var files = face.GetFiles(); + if (files.Length == 0) { + return null; + } + + var key = files[0].GetReferenceKey(); + using var stream = files[0].Loader.CreateStreamFromKey(key); + + stream.ReadFileFragment(out var start, 0, stream.GetFileSize(), out var release); + + var data = new byte[stream.GetFileSize()]; + Marshal.Copy(start, data, 0, data.Length); + + stream.ReleaseFileFragment(release); + + var metrics = font.Metrics; + var ratio = (metrics.Ascent + metrics.Descent + metrics.LineGap) / (float) metrics.DesignUnitsPerEm; + + return new FaceData(data, ratio); + } + + var normalData = GetFontData(normal); + if (normalData == null) { + return null; + } + + FaceData? italicData = null; + if (withItalic) { + using var italic = family.GetFirstMatchingFont(FontWeight.Normal, FontStretch.Normal, FontStyle.Italic) + ?? family.GetFirstMatchingFont(FontWeight.Normal, FontStretch.Normal, FontStyle.Oblique); + if (italic == null) { + return null; + } + + italicData = GetFontData(italic); + } + + if (italicData == null && withItalic) { + return null; + } + + return new FontData(normalData, italicData); } - var regular = GetFontData(regularFont); - var italic = Array.Empty(); - if (withItalic) { - var italicFont = Gdi32.CreateFontIndirect(new LOGFONT { - lfFaceName = name, - lfItalic = true, - lfCharSet = charset, - lfOutPrecision = LogFontOutputPrecision.OUT_TT_ONLY_PRECIS, - }); + return null; + } +} - italic = GetFontData(italicFont); - } +internal sealed class FaceData { + internal byte[] Data { get; } + internal float Ratio { get; } - if (regular == null || italic == null) { - return null; - } - - return new FontData(regular, italic); + internal FaceData(byte[] data, float ratio) { + this.Data = data; + this.Ratio = ratio; } } internal sealed class FontData { - internal byte[] Regular { get; } - internal byte[] Italic { get; } + internal FaceData Regular { get; } + internal FaceData? Italic { get; } - internal FontData(byte[] regular, byte[] italic) { + internal FontData(FaceData regular, FaceData? italic) { this.Regular = regular; this.Italic = italic; } diff --git a/ChatTwo/Ui/SettingsTabs/Display.cs b/ChatTwo/Ui/SettingsTabs/Display.cs index 5120597..bd9e49d 100755 --- a/ChatTwo/Ui/SettingsTabs/Display.cs +++ b/ChatTwo/Ui/SettingsTabs/Display.cs @@ -1,5 +1,3 @@ -using System.Drawing; -using System.Drawing.Text; using ChatTwo.Resources; using ChatTwo.Util; using ImGuiNET; @@ -8,7 +6,7 @@ namespace ChatTwo.Ui.SettingsTabs; internal sealed class Display : ISettingsTab { private Configuration Mutable { get; } - private List Fonts { get; } = new(); + private List Fonts { get; set; } = new(); private List JpFonts { get; set; } = new(); public string Name => Language.Options_Display_Tab + "###tabs-display"; @@ -19,13 +17,7 @@ internal sealed class Display : ISettingsTab { } private void UpdateFonts() { - this.Fonts.Clear(); - - var fonts = new InstalledFontCollection(); - foreach (var font in fonts.Families) { - this.Fonts.Add(font); - } - + this.Fonts = Ui.Fonts.GetFonts(); this.JpFonts = Ui.Fonts.GetJpFonts(); } @@ -74,16 +66,12 @@ internal sealed class Display : ISettingsTab { ImGui.Separator(); - foreach (var family in this.Fonts) { - if (!family.IsStyleAvailable(FontStyle.Italic)) { - continue; + foreach (var name in this.Fonts) { + if (ImGui.Selectable(name, this.Mutable.GlobalFont == name)) { + this.Mutable.GlobalFont = name; } - if (ImGui.Selectable(family.Name, this.Mutable.GlobalFont == family.Name)) { - this.Mutable.GlobalFont = family.Name; - } - - if (ImGui.IsWindowAppearing() && this.Mutable.GlobalFont == family.Name) { + if (ImGui.IsWindowAppearing() && this.Mutable.GlobalFont == name) { ImGui.SetScrollHereY(0.5f); } }