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

View File

@ -48,8 +48,7 @@
<ItemGroup>
<PackageReference Include="DalamudPackager" Version="2.1.5"/>
<PackageReference Include="System.Drawing.Common" Version="6.0.0"/>
<PackageReference Include="Vanara.PInvoke.Gdi32" Version="3.3.15"/>
<PackageReference Include="SharpDX.Direct2D1" Version="4.2.0"/>
<PackageReference Include="XivCommon" Version="5.0.0"/>
</ItemGroup>
@ -80,4 +79,4 @@
</EmbeddedResource>
</ItemGroup>
</Project>
</Project>

View File

@ -32,9 +32,9 @@ internal sealed class PluginUi : IDisposable {
private List<IUiComponent> 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<byte>());
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<byte>());
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
);
}

View File

@ -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<string> GetJpFonts() {
internal static List<string> GetFonts() {
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("@")) {
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<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;
}
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<byte>();
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;
}

View File

@ -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<FontFamily> Fonts { get; } = new();
private List<string> Fonts { get; set; } = new();
private List<string> 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);
}
}