feat: use newer way of getting fonts

This commit is contained in:
Anna
2022-02-05 03:12:37 -05:00
parent 04735444f4
commit e957b9ec76
4 changed files with 148 additions and 82 deletions
+2 -3
View File
@@ -48,8 +48,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="DalamudPackager" Version="2.1.5"/> <PackageReference Include="DalamudPackager" Version="2.1.5"/>
<PackageReference Include="System.Drawing.Common" Version="6.0.0"/> <PackageReference Include="SharpDX.Direct2D1" Version="4.2.0"/>
<PackageReference Include="Vanara.PInvoke.Gdi32" Version="3.3.15"/>
<PackageReference Include="XivCommon" Version="5.0.0"/> <PackageReference Include="XivCommon" Version="5.0.0"/>
</ItemGroup> </ItemGroup>
@@ -80,4 +79,4 @@
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
</Project> </Project>
+32 -13
View File
@@ -32,9 +32,9 @@ internal sealed class PluginUi : IDisposable {
private List<IUiComponent> Components { get; } private List<IUiComponent> Components { get; }
private ImFontConfigPtr _fontCfg; private ImFontConfigPtr _fontCfg;
private ImFontConfigPtr _fontCfgMerge; private ImFontConfigPtr _fontCfgMerge;
private (GCHandle, int) _regularFont; private (GCHandle, int, float) _regularFont;
private (GCHandle, int) _italicFont; private (GCHandle, int, float) _italicFont;
private (GCHandle, int) _jpFont; private (GCHandle, int, float) _jpFont;
private (GCHandle, int) _gameSymFont; private (GCHandle, int) _gameSymFont;
private readonly ImVector _ranges; private readonly ImVector _ranges;
@@ -121,10 +121,18 @@ internal sealed class PluginUi : IDisposable {
if (this.Plugin.Config.GlobalFont.StartsWith(Fonts.IncludedIndicator)) { if (this.Plugin.Config.GlobalFont.StartsWith(Fonts.IncludedIndicator)) {
var globalFont = Fonts.GlobalFonts.FirstOrDefault(font => font.Name == this.Plugin.Config.GlobalFont); var globalFont = Fonts.GlobalFonts.FirstOrDefault(font => font.Name == this.Plugin.Config.GlobalFont);
if (globalFont != null) { 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 { } else {
fontData = Fonts.GetFont(this.Plugin.Config.GlobalFont, true); 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) { if (fontData == null) {
@@ -132,7 +140,9 @@ internal sealed class PluginUi : IDisposable {
this.Plugin.SaveConfig(); this.Plugin.SaveConfig();
var globalFont = Fonts.GlobalFonts[0]; 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) { if (this._regularFont.Item1.IsAllocated) {
@@ -144,20 +154,25 @@ internal sealed class PluginUi : IDisposable {
} }
this._regularFont = ( this._regularFont = (
GCHandle.Alloc(fontData.Regular, GCHandleType.Pinned), GCHandle.Alloc(fontData.Regular.Data, GCHandleType.Pinned),
fontData.Regular.Length fontData.Regular.Data.Length,
fontData.Regular.Ratio
); );
this._italicFont = ( this._italicFont = (
GCHandle.Alloc(fontData.Italic, GCHandleType.Pinned), GCHandle.Alloc(fontData.Italic!.Data, GCHandleType.Pinned),
fontData.Italic.Length fontData.Italic.Data.Length,
fontData.Italic.Ratio
); );
FontData? jpFontData = null; FontData? jpFontData = null;
if (this.Plugin.Config.JapaneseFont.StartsWith(Fonts.IncludedIndicator)) { if (this.Plugin.Config.JapaneseFont.StartsWith(Fonts.IncludedIndicator)) {
var jpFont = Fonts.JapaneseFonts.FirstOrDefault(item => item.Item1 == this.Plugin.Config.JapaneseFont); var jpFont = Fonts.JapaneseFonts.FirstOrDefault(item => item.Item1 == this.Plugin.Config.JapaneseFont);
if (jpFont != default) { if (jpFont != default) {
jpFontData = new FontData(this.GetResource(jpFont.Item2), Array.Empty<byte>()); jpFontData = new FontData(
new FaceData(this.GetResource(jpFont.Item2), 1f),
null
);
} }
} }
// else { // else {
@@ -170,7 +185,10 @@ internal sealed class PluginUi : IDisposable {
this.Plugin.SaveConfig(); this.Plugin.SaveConfig();
var jpFont = Fonts.JapaneseFonts[0]; var jpFont = Fonts.JapaneseFonts[0];
jpFontData = new FontData(this.GetResource(jpFont.Item2), Array.Empty<byte>()); jpFontData = new FontData(
new FaceData(this.GetResource(jpFont.Item2), 1f),
null
);
} }
if (this._jpFont.Item1.IsAllocated) { if (this._jpFont.Item1.IsAllocated) {
@@ -178,8 +196,9 @@ internal sealed class PluginUi : IDisposable {
} }
this._jpFont = ( this._jpFont = (
GCHandle.Alloc(jpFontData.Regular, GCHandleType.Pinned), GCHandle.Alloc(jpFontData.Regular.Data, GCHandleType.Pinned),
jpFontData.Regular.Length jpFontData.Regular.Data.Length,
jpFontData.Regular.Ratio
); );
} }
+108 -48
View File
@@ -1,5 +1,7 @@
using System.Drawing; using System.Runtime.InteropServices;
using Vanara.PInvoke; using Dalamud.Logging;
using SharpDX.DirectWrite;
using FontStyle = SharpDX.DirectWrite.FontStyle;
namespace ChatTwo.Ui; namespace ChatTwo.Ui;
@@ -34,73 +36,131 @@ internal static class Fonts {
// ($"{IncludedIndicator}Noto Serif JP", "ChatTwo.fonts.NotoSerifJP-Regular.otf"), // ($"{IncludedIndicator}Noto Serif JP", "ChatTwo.fonts.NotoSerifJP-Regular.otf"),
}; };
internal static List<string> GetJpFonts() { internal static List<string> GetFonts() {
var fonts = new List<string>(); var fonts = new List<string>();
using var g = Graphics.FromImage(new Bitmap(1, 1));
foreach (var (lpelfe, _, fontType) in Gdi32.EnumFontFamiliesEx(g.GetHdc(), CharacterSet.SHIFTJIS_CHARSET)) { using var factory = new Factory();
var name = lpelfe.elfEnumLogfontEx.elfLogFont.lfFaceName; using var collection = factory.GetSystemFontCollection(false);
if (name.StartsWith("@")) { 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; continue;
} }
var name = family.FamilyNames.GetString(0);
fonts.Add(name); fonts.Add(name);
} }
fonts.Sort();
return fonts;
}
internal static List<string> GetJpFonts() {
var fonts = new List<string>();
// 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; return fonts;
} }
internal static unsafe FontData? GetFont(string name, bool withItalic, CharacterSet charset = CharacterSet.ANSI_CHARSET) { internal static FontData? GetFont(string name, bool withItalic) {
var regularFont = Gdi32.CreateFontIndirect(new LOGFONT { using var factory = new Factory();
lfFaceName = name, using var collection = factory.GetSystemFontCollection(false);
lfItalic = false, for (var i = 0; i < collection.FontFamilyCount; i++) {
lfCharSet = charset, using var family = collection.GetFontFamily(i);
lfOutPrecision = LogFontOutputPrecision.OUT_TT_ONLY_PRECIS, if (family.FamilyNames.GetString(0) != name) {
}); continue;
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;
}
} }
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); return null;
var italic = Array.Empty<byte>(); }
if (withItalic) { }
var italicFont = Gdi32.CreateFontIndirect(new LOGFONT {
lfFaceName = name,
lfItalic = true,
lfCharSet = charset,
lfOutPrecision = LogFontOutputPrecision.OUT_TT_ONLY_PRECIS,
});
italic = GetFontData(italicFont); internal sealed class FaceData {
} internal byte[] Data { get; }
internal float Ratio { get; }
if (regular == null || italic == null) { internal FaceData(byte[] data, float ratio) {
return null; this.Data = data;
} this.Ratio = ratio;
return new FontData(regular, italic);
} }
} }
internal sealed class FontData { internal sealed class FontData {
internal byte[] Regular { get; } internal FaceData Regular { get; }
internal byte[] Italic { get; } internal FaceData? Italic { get; }
internal FontData(byte[] regular, byte[] italic) { internal FontData(FaceData regular, FaceData? italic) {
this.Regular = regular; this.Regular = regular;
this.Italic = italic; this.Italic = italic;
} }
+6 -18
View File
@@ -1,5 +1,3 @@
using System.Drawing;
using System.Drawing.Text;
using ChatTwo.Resources; using ChatTwo.Resources;
using ChatTwo.Util; using ChatTwo.Util;
using ImGuiNET; using ImGuiNET;
@@ -8,7 +6,7 @@ namespace ChatTwo.Ui.SettingsTabs;
internal sealed class Display : ISettingsTab { internal sealed class Display : ISettingsTab {
private Configuration Mutable { get; } private Configuration Mutable { get; }
private List<FontFamily> Fonts { get; } = new(); private List<string> Fonts { get; set; } = new();
private List<string> JpFonts { get; set; } = new(); private List<string> JpFonts { get; set; } = new();
public string Name => Language.Options_Display_Tab + "###tabs-display"; public string Name => Language.Options_Display_Tab + "###tabs-display";
@@ -19,13 +17,7 @@ internal sealed class Display : ISettingsTab {
} }
private void UpdateFonts() { private void UpdateFonts() {
this.Fonts.Clear(); this.Fonts = Ui.Fonts.GetFonts();
var fonts = new InstalledFontCollection();
foreach (var font in fonts.Families) {
this.Fonts.Add(font);
}
this.JpFonts = Ui.Fonts.GetJpFonts(); this.JpFonts = Ui.Fonts.GetJpFonts();
} }
@@ -74,16 +66,12 @@ internal sealed class Display : ISettingsTab {
ImGui.Separator(); ImGui.Separator();
foreach (var family in this.Fonts) { foreach (var name in this.Fonts) {
if (!family.IsStyleAvailable(FontStyle.Italic)) { if (ImGui.Selectable(name, this.Mutable.GlobalFont == name)) {
continue; this.Mutable.GlobalFont = name;
} }
if (ImGui.Selectable(family.Name, this.Mutable.GlobalFont == family.Name)) { if (ImGui.IsWindowAppearing() && this.Mutable.GlobalFont == name) {
this.Mutable.GlobalFont = family.Name;
}
if (ImGui.IsWindowAppearing() && this.Mutable.GlobalFont == family.Name) {
ImGui.SetScrollHereY(0.5f); ImGui.SetScrollHereY(0.5f);
} }
} }