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
+108 -48
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;
}