feat: use newer way of getting fonts
This commit is contained in:
@@ -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>
|
||||||
|
|
||||||
|
|||||||
+32
-13
@@ -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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+103
-43
@@ -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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
anyItalic = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!anyItalic) {
|
||||||
|
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));
|
using var normal = family.GetFirstMatchingFont(FontWeight.Normal, FontStretch.Normal, FontStyle.Normal);
|
||||||
var hdc = g.GetHdc();
|
if (normal == null) {
|
||||||
|
|
||||||
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 null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FaceData? GetFontData(SharpDX.DirectWrite.Font font) {
|
||||||
|
using var face = new FontFace(font);
|
||||||
|
var files = face.GetFiles();
|
||||||
|
if (files.Length == 0) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
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 regular = GetFontData(regularFont);
|
var normalData = GetFontData(normal);
|
||||||
var italic = Array.Empty<byte>();
|
if (normalData == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
FaceData? italicData = null;
|
||||||
if (withItalic) {
|
if (withItalic) {
|
||||||
var italicFont = Gdi32.CreateFontIndirect(new LOGFONT {
|
using var italic = family.GetFirstMatchingFont(FontWeight.Normal, FontStretch.Normal, FontStyle.Italic)
|
||||||
lfFaceName = name,
|
?? family.GetFirstMatchingFont(FontWeight.Normal, FontStretch.Normal, FontStyle.Oblique);
|
||||||
lfItalic = true,
|
if (italic == null) {
|
||||||
lfCharSet = charset,
|
|
||||||
lfOutPrecision = LogFontOutputPrecision.OUT_TT_ONLY_PRECIS,
|
|
||||||
});
|
|
||||||
|
|
||||||
italic = GetFontData(italicFont);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (regular == null || italic == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FontData(regular, italic);
|
italicData = GetFontData(italic);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (italicData == null && withItalic) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FontData(normalData, italicData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class FaceData {
|
||||||
|
internal byte[] Data { get; }
|
||||||
|
internal float Ratio { get; }
|
||||||
|
|
||||||
|
internal FaceData(byte[] data, float ratio) {
|
||||||
|
this.Data = data;
|
||||||
|
this.Ratio = ratio;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user