diff --git a/Dalamud/Interface/ManagedFontAtlas/FluentGlyphRangeBuilder.cs b/Dalamud/Interface/ManagedFontAtlas/FluentGlyphRangeBuilder.cs
new file mode 100644
index 000000000..ec395a61f
--- /dev/null
+++ b/Dalamud/Interface/ManagedFontAtlas/FluentGlyphRangeBuilder.cs
@@ -0,0 +1,361 @@
+using System.Buffers;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Text.Unicode;
+
+using Dalamud.Interface.ManagedFontAtlas.Internals;
+
+namespace Dalamud.Interface.ManagedFontAtlas;
+
+/// A fluent ImGui glyph range builder.
+[SuppressMessage(
+ "StyleCop.CSharp.SpacingRules",
+ "SA1010:Opening square brackets should be spaced correctly",
+ Justification = "No")]
+public struct FluentGlyphRangeBuilder
+{
+ private const int ImUnicodeCodepointMax = char.MaxValue;
+
+ private BitArray? characters;
+
+ /// Clears the builder.
+ /// this for method chaining.
+ /// A builder is in cleared state on first use.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public FluentGlyphRangeBuilder Clear()
+ {
+ this.characters?.SetAll(false);
+ return this;
+ }
+
+ /// Adds a single codepoint to the builder.
+ /// The codepoint to add.
+ /// this for method chaining.
+ /// Unsupported codepoints will be ignored.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public FluentGlyphRangeBuilder With(char codepoint) => this.With((int)codepoint);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public FluentGlyphRangeBuilder With(uint codepoint) =>
+ codepoint <= char.MaxValue ? this.With((int)codepoint) : this;
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public FluentGlyphRangeBuilder With(int codepoint)
+ {
+ if (codepoint <= ImUnicodeCodepointMax)
+ this.EnsureCharacters().Set(codepoint, true);
+ return this;
+ }
+
+ /// Adds a unicode range to the builder.
+ /// The unicode range to add.
+ /// this for method chaining.
+ /// Unsupported codepoints will be ignored.
+ public FluentGlyphRangeBuilder With(UnicodeRange range) =>
+ this.With(range.FirstCodePoint, (range.FirstCodePoint + range.Length) - 1);
+
+ /// Adds unicode ranges to the builder.
+ /// The 1st unicode range to add.
+ /// The 2st unicode range to add.
+ /// this for method chaining.
+ /// Unsupported codepoints will be ignored.
+ public FluentGlyphRangeBuilder With(UnicodeRange range1, UnicodeRange range2) =>
+ this.With(range1.FirstCodePoint, (range1.FirstCodePoint + range1.Length) - 1)
+ .With(range2.FirstCodePoint, (range2.FirstCodePoint + range2.Length) - 1);
+
+ /// Adds unicode ranges to the builder.
+ /// The 1st unicode range to add.
+ /// The 2st unicode range to add.
+ /// The 3rd unicode range to add.
+ /// this for method chaining.
+ /// Unsupported codepoints will be ignored.
+ public FluentGlyphRangeBuilder With(UnicodeRange range1, UnicodeRange range2, UnicodeRange range3) =>
+ this.With(range1.FirstCodePoint, (range1.FirstCodePoint + range1.Length) - 1)
+ .With(range2.FirstCodePoint, (range2.FirstCodePoint + range2.Length) - 1)
+ .With(range3.FirstCodePoint, (range3.FirstCodePoint + range3.Length) - 1);
+
+ /// Adds unicode ranges to the builder.
+ /// The 1st unicode range to add.
+ /// The 2st unicode range to add.
+ /// The 3rd unicode range to add.
+ /// The 4th unicode range to add.
+ /// Even more unicode ranges to add.
+ /// this for method chaining.
+ /// Unsupported codepoints will be ignored.
+ public FluentGlyphRangeBuilder With(
+ UnicodeRange range1,
+ UnicodeRange range2,
+ UnicodeRange range3,
+ UnicodeRange range4,
+ params UnicodeRange[] evenMoreRanges) =>
+ this.With(range1.FirstCodePoint, (range1.FirstCodePoint + range1.Length) - 1)
+ .With(range2.FirstCodePoint, (range2.FirstCodePoint + range2.Length) - 1)
+ .With(range3.FirstCodePoint, (range3.FirstCodePoint + range3.Length) - 1)
+ .With(range4.FirstCodePoint, (range4.FirstCodePoint + range4.Length) - 1)
+ .With(evenMoreRanges);
+
+ /// Adds unicode ranges to the builder.
+ /// Unicode ranges to add.
+ /// this for method chaining.
+ /// Unsupported codepoints will be ignored.
+ public FluentGlyphRangeBuilder With(IEnumerable ranges)
+ {
+ foreach (var range in ranges)
+ this.With(range);
+ return this;
+ }
+
+ /// Adds a range of characters to the builder.
+ /// The first codepoint, inclusive.
+ /// The last codepoint, inclusive.
+ /// this for method chaining.
+ ///
+ /// Unsupported codepoints will be ignored.
+ /// If is more than , then they will be swapped.
+ ///
+ public FluentGlyphRangeBuilder With(char from, char to) =>
+ this.With(Math.Clamp(from, int.MinValue, int.MaxValue), Math.Clamp(to, int.MinValue, int.MaxValue));
+
+ ///
+ public FluentGlyphRangeBuilder With(uint from, uint to) =>
+ this.With((int)Math.Min(from, int.MaxValue), (int)Math.Min(to, int.MaxValue));
+
+ ///
+ public FluentGlyphRangeBuilder With(int from, int to)
+ {
+ from = Math.Clamp(from, 1, ImUnicodeCodepointMax);
+ to = Math.Clamp(to, 1, ImUnicodeCodepointMax);
+ if (from > to)
+ (from, to) = (to, from);
+
+ var bits = this.EnsureCharacters();
+ for (; from <= to; from++)
+ bits.Set(from, true);
+ return this;
+ }
+
+ /// Adds characters from a UTF-8 character sequence.
+ /// The sequence.
+ /// this for method chaining.
+ /// Unsupported codepoints will be ignored.
+ public FluentGlyphRangeBuilder With(ReadOnlySpan utf8Sequence)
+ {
+ var bits = this.EnsureCharacters();
+ while (!utf8Sequence.IsEmpty)
+ {
+ if (Rune.DecodeFromUtf8(utf8Sequence, out var rune, out var len) == OperationStatus.Done
+ && rune.Value < ImUnicodeCodepointMax)
+ bits.Set(rune.Value, true);
+ utf8Sequence = utf8Sequence[len..];
+ }
+
+ return this;
+ }
+
+ /// Adds characters from a UTF-8 character sequence.
+ /// The sequence.
+ /// this for method chaining.
+ /// Unsupported codepoints will be ignored.
+ public FluentGlyphRangeBuilder With(IEnumerable utf8Sequence)
+ {
+ Span buf = stackalloc byte[4];
+ var bufp = 0;
+ var bits = this.EnsureCharacters();
+ foreach (var b in utf8Sequence)
+ {
+ buf[bufp++] = b;
+
+ while (Rune.DecodeFromUtf8(buf[..bufp], out var rune, out var len) is var state
+ && state != OperationStatus.NeedMoreData)
+ {
+ switch (state)
+ {
+ case OperationStatus.Done when rune.Value <= ImUnicodeCodepointMax:
+ bits.Set(rune.Value, true);
+ goto case OperationStatus.InvalidData;
+
+ case OperationStatus.InvalidData:
+ bufp -= len;
+ break;
+
+ case OperationStatus.NeedMoreData:
+ case OperationStatus.DestinationTooSmall:
+ default:
+ throw new InvalidOperationException($"Unexpected return from {Rune.DecodeFromUtf8}.");
+ }
+ }
+ }
+
+ return this;
+ }
+
+ /// Adds characters from a UTF-16 character sequence.
+ /// The sequence.
+ /// this for method chaining.
+ /// Unsupported codepoints will be ignored.
+ public FluentGlyphRangeBuilder With(ReadOnlySpan utf16Sequence)
+ {
+ var bits = this.EnsureCharacters();
+ while (!utf16Sequence.IsEmpty)
+ {
+ if (Rune.DecodeFromUtf16(utf16Sequence, out var rune, out var len) == OperationStatus.Done
+ && rune.Value <= ImUnicodeCodepointMax)
+ bits.Set(rune.Value, true);
+ utf16Sequence = utf16Sequence[len..];
+ }
+
+ return this;
+ }
+
+ /// Adds characters from a UTF-16 character sequence.
+ /// The sequence.
+ /// this for method chaining.
+ /// Unsupported codepoints will be ignored.
+ public FluentGlyphRangeBuilder With(IEnumerable utf16Sequence)
+ {
+ var bits = this.EnsureCharacters();
+ foreach (var c in utf16Sequence)
+ {
+ if (!char.IsSurrogate(c))
+ bits.Set(c, true);
+ }
+
+ return this;
+ }
+
+ /// Adds characters from a string.
+ /// The string.
+ /// this for method chaining.
+ /// Unsupported codepoints will be ignored.
+ public FluentGlyphRangeBuilder With(string @string) => this.With(@string.AsSpan());
+
+ /// Adds glyphs that are likely to be used in the given culture to the builder.
+ /// A culture info.
+ /// this for method chaining.
+ /// Unsupported codepoints will be ignored. Unsupported culture will do nothing.
+ /// Do make a PR if you need more.
+ public FluentGlyphRangeBuilder WithLanguage(CultureInfo cultureInfo)
+ {
+ // Call in chunks of three to avoid allocating arrays.
+ // Avoid adding ranges that goes over BMP; that is, ranges that goes over ImUnicodeCodepointMax.
+ switch (cultureInfo.TwoLetterISOLanguageName)
+ {
+ case "ja":
+ // http://www.rikai.com/library/kanjitables/kanji_codes.unicode.shtml
+ return
+ this
+ .With(
+ UnicodeRanges.CjkSymbolsandPunctuation,
+ UnicodeRanges.Hiragana,
+ UnicodeRanges.Katakana)
+ .With(
+ UnicodeRanges.HalfwidthandFullwidthForms,
+ UnicodeRanges.CjkUnifiedIdeographs,
+ UnicodeRanges.CjkUnifiedIdeographsExtensionA)
+ // Blame Japanese cell carriers for the below.
+ .With(
+ UnicodeRanges.EnclosedCjkLettersandMonths);
+ case "zh":
+ return
+ this
+ .With(
+ UnicodeRanges.CjkUnifiedIdeographs,
+ UnicodeRanges.CjkUnifiedIdeographsExtensionA);
+ case "ko":
+ return
+ this
+ .With(
+ UnicodeRanges.HangulJamo,
+ UnicodeRanges.HangulCompatibilityJamo,
+ UnicodeRanges.HangulSyllables)
+ .With(
+ UnicodeRanges.HangulJamoExtendedA,
+ UnicodeRanges.HangulJamoExtendedB);
+ default:
+ return this;
+ }
+ }
+
+ /// Adds glyphs that are likely to be used in the given culture to the builder.
+ /// A language tag that will be used to locate the culture info.
+ /// this for method chaining.
+ /// See documentation for supported language tags.
+ ///
+ public FluentGlyphRangeBuilder WithLanguage(string languageTag) =>
+ this.WithLanguage(CultureInfo.GetCultureInfo(languageTag));
+
+ /// Builds the accumulated data into an ImGui glyph range.
+ /// Whether to add the default fallback codepoints to the range.
+ /// Whether to add the default ellipsis codepoints to the range.
+ /// The built ImGui glyph ranges.
+ public ushort[] Build(bool addFallbackCodepoints = true, bool addEllipsisCodepoints = true)
+ {
+ if (addFallbackCodepoints)
+ this.With(FontAtlasFactory.FallbackCodepoints);
+ if (addEllipsisCodepoints)
+ this.With(FontAtlasFactory.EllipsisCodepoints).With('.');
+ return this.BuildExact();
+ }
+
+ /// Builds the accumulated data into an ImGui glyph range, exactly as specified.
+ /// The built ImGui glyph ranges.
+ public ushort[] BuildExact()
+ {
+ if (this.characters is null)
+ return [0];
+ var bits = this.characters;
+
+ // Count the number of ranges first.
+ var numRanges = 0;
+ var lastCodepoint = -1;
+ for (var i = 1; i <= ImUnicodeCodepointMax; i++)
+ {
+ if (bits.Get(i))
+ {
+ if (lastCodepoint == -1)
+ lastCodepoint = i;
+ }
+ else
+ {
+ if (lastCodepoint != -1)
+ {
+ numRanges++;
+ lastCodepoint = -1;
+ }
+ }
+ }
+
+ // Handle the final range that terminates on the ending boundary.
+ if (lastCodepoint != -1)
+ numRanges++;
+
+ // Allocate the array and build the range.
+ var res = GC.AllocateUninitializedArray((numRanges * 2) + 1);
+ var resp = 0;
+ for (var i = 1; i <= ImUnicodeCodepointMax; i++)
+ {
+ if (bits.Get(i) == ((resp & 1) == 0))
+ res[resp++] = unchecked((ushort)i);
+ }
+
+ // Handle the final range that terminates on the ending boundary.
+ if ((resp & 1) == 1)
+ res[resp++] = ImUnicodeCodepointMax;
+
+ // Add the zero terminator.
+ res[resp] = 0;
+
+ return res;
+ }
+
+ /// Ensures that is not null, by creating one as necessary.
+ /// An instance of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private BitArray EnsureCharacters() => this.characters ??= new(ImUnicodeCodepointMax + 1);
+}
diff --git a/Dalamud/Interface/ManagedFontAtlas/FontAtlasBuildToolkitUtilities.cs b/Dalamud/Interface/ManagedFontAtlas/FontAtlasBuildToolkitUtilities.cs
index 4c3e9023a..3b8bfd965 100644
--- a/Dalamud/Interface/ManagedFontAtlas/FontAtlasBuildToolkitUtilities.cs
+++ b/Dalamud/Interface/ManagedFontAtlas/FontAtlasBuildToolkitUtilities.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
+using System.Text.Unicode;
using Dalamud.Interface.Utility;
@@ -12,6 +13,34 @@ namespace Dalamud.Interface.ManagedFontAtlas;
///
public static class FontAtlasBuildToolkitUtilities
{
+ /// Begins building a new array of containing ImGui glyph ranges.
+ /// The chars.
+ /// A new range builder.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static FluentGlyphRangeBuilder BeginGlyphRange(this IEnumerable chars) =>
+ default(FluentGlyphRangeBuilder).With(chars);
+
+ /// Begins building a new array of containing ImGui glyph ranges.
+ /// The chars.
+ /// A new range builder.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static FluentGlyphRangeBuilder BeginGlyphRange(this ReadOnlySpan chars) =>
+ default(FluentGlyphRangeBuilder).With(chars);
+
+ /// Begins building a new array of containing ImGui glyph ranges.
+ /// The chars.
+ /// A new range builder.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static FluentGlyphRangeBuilder BeginGlyphRange(this string chars) =>
+ default(FluentGlyphRangeBuilder).With(chars);
+
+ /// Begins building a new array of containing ImGui glyph ranges.
+ /// The unicode range.
+ /// A new range builder.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static FluentGlyphRangeBuilder BeginGlyphRange(this UnicodeRange range) =>
+ default(FluentGlyphRangeBuilder).With(range);
+
///
/// Compiles given s into an array of containing ImGui glyph ranges.
///
@@ -19,16 +48,12 @@ public static class FontAtlasBuildToolkitUtilities
/// Add fallback codepoints to the range.
/// Add ellipsis codepoints to the range.
/// The compiled range.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort[] ToGlyphRange(
this IEnumerable enumerable,
bool addFallbackCodepoints = true,
- bool addEllipsisCodepoints = true)
- {
- using var builderScoped = ImGuiHelpers.NewFontGlyphRangeBuilderPtrScoped(out var builder);
- foreach (var c in enumerable)
- builder.AddChar(c);
- return builder.BuildRangesToArray(addFallbackCodepoints, addEllipsisCodepoints);
- }
+ bool addEllipsisCodepoints = true) =>
+ enumerable.BeginGlyphRange().Build(addFallbackCodepoints, addEllipsisCodepoints);
///
/// Compiles given s into an array of containing ImGui glyph ranges.
@@ -37,16 +62,12 @@ public static class FontAtlasBuildToolkitUtilities
/// Add fallback codepoints to the range.
/// Add ellipsis codepoints to the range.
/// The compiled range.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort[] ToGlyphRange(
this ReadOnlySpan span,
bool addFallbackCodepoints = true,
- bool addEllipsisCodepoints = true)
- {
- using var builderScoped = ImGuiHelpers.NewFontGlyphRangeBuilderPtrScoped(out var builder);
- foreach (var c in span)
- builder.AddChar(c);
- return builder.BuildRangesToArray(addFallbackCodepoints, addEllipsisCodepoints);
- }
+ bool addEllipsisCodepoints = true) =>
+ span.BeginGlyphRange().Build(addFallbackCodepoints, addEllipsisCodepoints);
///
/// Compiles given string into an array of containing ImGui glyph ranges.
@@ -55,11 +76,12 @@ public static class FontAtlasBuildToolkitUtilities
/// Add fallback codepoints to the range.
/// Add ellipsis codepoints to the range.
/// The compiled range.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort[] ToGlyphRange(
this string @string,
bool addFallbackCodepoints = true,
bool addEllipsisCodepoints = true) =>
- @string.AsSpan().ToGlyphRange(addFallbackCodepoints, addEllipsisCodepoints);
+ @string.BeginGlyphRange().Build(addFallbackCodepoints, addEllipsisCodepoints);
///
/// Finds the corresponding in
diff --git a/Dalamud/Interface/ManagedFontAtlas/IFontAtlasBuildToolkitPreBuild.cs b/Dalamud/Interface/ManagedFontAtlas/IFontAtlasBuildToolkitPreBuild.cs
index 9b80d27ff..b32e3db18 100644
--- a/Dalamud/Interface/ManagedFontAtlas/IFontAtlasBuildToolkitPreBuild.cs
+++ b/Dalamud/Interface/ManagedFontAtlas/IFontAtlasBuildToolkitPreBuild.cs
@@ -1,4 +1,5 @@
-using System.IO;
+using System.Globalization;
+using System.IO;
using System.Runtime.InteropServices;
using Dalamud.Interface.FontIdentifier;
@@ -8,6 +9,8 @@ using Dalamud.Utility;
using ImGuiNET;
+using TerraFX.Interop.DirectX;
+
namespace Dalamud.Interface.ManagedFontAtlas;
///
@@ -216,10 +219,35 @@ public interface IFontAtlasBuildToolkitPreBuild : IFontAtlasBuildToolkit
/// The added font.
ImFontPtr AddGameGlyphs(GameFontStyle gameFontStyle, ushort[]? glyphRanges, ImFontPtr mergeFont);
+ /// Adds glyphs from the Windows default font for the given culture info into the provided font.
+ /// The culture info.
+ /// The font config. If is not set, then
+ /// will be used as the target. If that is empty too, then it will do
+ /// nothing.
+ /// The font weight, in range from 1 to 1000. 400 is regular(normal).
+ ///
+ /// The font stretch, in range from 1 to 9. 5 is medium(normal).
+ ///
+ /// The font style, in range from 0 to 2. 0 is normal.
+ ///
+ /// May do nothing at all if is unsupported by Dalamud font handler.
+ /// See
+ /// Microsoft
+ /// Learn for the fonts.
+ ///
+ void AttachWindowsDefaultFont(
+ CultureInfo cultureInfo,
+ in SafeFontConfig fontConfig,
+ int weight = (int)DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_NORMAL,
+ int stretch = (int)DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_NORMAL,
+ int style = (int)DWRITE_FONT_STYLE.DWRITE_FONT_STYLE_NORMAL);
+
///
/// Adds glyphs of extra languages into the provided font, depending on Dalamud Configuration.
/// will be ignored.
///
- /// The font config.
+ /// The font config. If is not set, then
+ /// will be used as the target. If that is empty too, then it will do
+ /// nothing.
void AttachExtraGlyphsForDalamudLanguage(in SafeFontConfig fontConfig);
}
diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.BuildToolkit.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.BuildToolkit.cs
index 55af20329..34d28ccbd 100644
--- a/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.BuildToolkit.cs
+++ b/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.BuildToolkit.cs
@@ -1,9 +1,9 @@
using System.Buffers;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
-using System.Text.Unicode;
using Dalamud.Configuration.Internal;
using Dalamud.Interface.FontIdentifier;
@@ -17,6 +17,8 @@ using ImGuiNET;
using SharpDX.DXGI;
+using TerraFX.Interop.DirectX;
+
namespace Dalamud.Interface.ManagedFontAtlas.Internals;
///
@@ -433,9 +435,163 @@ internal sealed partial class FontAtlasFactory
public ImFontPtr AddGameGlyphs(GameFontStyle gameFontStyle, ushort[]? glyphRanges, ImFontPtr mergeFont) =>
this.gameFontHandleSubstance.AttachGameGlyphs(this, mergeFont, gameFontStyle, glyphRanges);
+ ///
+ public void AttachWindowsDefaultFont(
+ CultureInfo cultureInfo,
+ in SafeFontConfig fontConfig,
+ int weight = (int)DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_NORMAL,
+ int stretch = (int)DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_NORMAL,
+ int style = (int)DWRITE_FONT_STYLE.DWRITE_FONT_STYLE_NORMAL)
+ {
+ var targetFont = fontConfig.MergeFont;
+ if (targetFont.IsNull())
+ targetFont = this.Font;
+ if (targetFont.IsNull())
+ return;
+
+ // https://learn.microsoft.com/en-us/windows/apps/design/globalizing/loc-international-fonts
+ var splitTag = cultureInfo.IetfLanguageTag.Split("-");
+ foreach (var test in new[]
+ {
+ cultureInfo.IetfLanguageTag,
+ $"{splitTag[0]}-{splitTag[^1]}",
+ })
+ {
+ var familyName = test switch
+ {
+ "af-ZA" => "Segoe UI",
+ "am-ET" => "Ebrima",
+ "ar-SA" => "Segoe UI",
+ "as-IN" => "Nirmala UI",
+ "az-Latn-AZ" => "Segoe UI",
+ "be-BY" => "Segoe UI",
+ "bg-BG" => "Segoe UI",
+ "bn-BD" => "Nirmala UI",
+ "bn-IN" => "Nirmala UI",
+ "bs-Latn-BA" => "Segoe UI",
+ "ca-ES" => "Segoe UI",
+ "ca-ES-valencia" => "Segoe UI",
+ "chr-CHER-US" => "Gadugi",
+ "cs-CZ" => "Segoe UI",
+ "cy-GB" => "Segoe UI",
+ "da-DK" => "Segoe UI",
+ "de-DE" => "Segoe UI",
+ "el-GR" => "Segoe UI",
+ "en-GB" => "Segoe UI",
+ "es-ES" => "Segoe UI",
+ "et-EE" => "Segoe UI",
+ "eu-ES" => "Segoe UI",
+ "fa-IR" => "Segoe UI",
+ "fi-FI" => "Segoe UI",
+ "fil-PH" => "Segoe UI",
+ "fr-FR" => "Segoe UI",
+ "ga-IE" => "Segoe UI",
+ "gd-GB" => "Segoe UI",
+ "gl-ES" => "Segoe UI",
+ "gu-IN" => "Nirmala UI",
+ "ha-Latn-NG" => "Segoe UI",
+ "he-IL" => "Segoe UI",
+ "hi-IN" => "Nirmala UI",
+ "hr-HR" => "Segoe UI",
+ "hu-HU" => "Segoe UI",
+ "hy-AM" => "Segoe UI",
+ "id-ID" => "Segoe UI",
+ "ig-NG" => "Segoe UI",
+ "is-IS" => "Segoe UI",
+ "it-IT" => "Segoe UI",
+ "ja-JP" => "Yu Gothic UI",
+ "ka-GE" => "Segoe UI",
+ "kk-KZ" => "Segoe UI",
+ "km-KH" => "Leelawadee UI",
+ "kn-IN" => "Nirmala UI",
+ "ko-KR" => "Malgun Gothic",
+ "kok-IN" => "Nirmala UI",
+ "ku-ARAB-IQ" => "Segoe UI",
+ "ky-KG" => "Segoe UI",
+ "lb-LU" => "Segoe UI",
+ "lt-LT" => "Segoe UI",
+ "lv-LV" => "Segoe UI",
+ "mi-NZ" => "Segoe UI",
+ "mk-MK" => "Segoe UI",
+ "ml-IN" => "Nirmala UI",
+ "mn-MN" => "Segoe UI",
+ "mr-IN" => "Nirmala UI",
+ "ms-MY" => "Segoe UI",
+ "mt-MT" => "Segoe UI",
+ "nb-NO" => "Segoe UI",
+ "ne-NP" => "Nirmala UI",
+ "nl-NL" => "Segoe UI",
+ "nn-NO" => "Segoe UI",
+ "nso-ZA" => "Segoe UI",
+ "or-IN" => "Nirmala UI",
+ "pa-Arab-PK" => "Segoe UI",
+ "pa-IN" => "Nirmala UI",
+ "pl-PL" => "Segoe UI",
+ "prs-AF" => "Segoe UI",
+ "pt-BR" => "Segoe UI",
+ "pt-PT" => "Segoe UI",
+ "qut-GT" => "Segoe UI",
+ "quz-PE" => "Segoe UI",
+ "ro-RO" => "Segoe UI",
+ "ru-RU" => "Segoe UI",
+ "rw-RW" => "Segoe UI",
+ "sd-Arab-PK" => "Segoe UI",
+ "si-LK" => "Nirmala UI",
+ "sk-SK" => "Segoe UI",
+ "sl-SI" => "Segoe UI",
+ "sq-AL" => "Segoe UI",
+ "sr-Cyrl-BA" => "Segoe UI",
+ "sr-Cyrl-CS" => "Segoe UI",
+ "sr-Latn-CS" => "Segoe UI",
+ "sv-SE" => "Segoe UI",
+ "sw-KE" => "Segoe UI",
+ "ta-IN" => "Nirmala UI",
+ "te-IN" => "Nirmala UI",
+ "tg-Cyrl-TJ" => "Segoe UI",
+ "th-TH" => "Leelawadee UI",
+ "ti-ET" => "Ebrima",
+ "tk-TM" => "Segoe UI",
+ "tn-ZA" => "Segoe UI",
+ "tr-TR" => "Segoe UI",
+ "tt-RU" => "Segoe UI",
+ "ug-CN" => "Segoe UI",
+ "uk-UA" => "Segoe UI",
+ "ur-PK" => "Segoe UI",
+ "uz-Latn-UZ" => "Segoe UI",
+ "vi-VN" => "Segoe UI",
+ "wo-SN" => "Segoe UI",
+ "xh-ZA" => "Segoe UI",
+ "yo-NG" => "Segoe UI",
+ "zh-CN" => "Microsoft YaHei UI",
+ "zh-HK" => "Microsoft JhengHei UI",
+ "zh-TW" => "Microsoft JhengHei UI",
+ "zh-Hans" => "Microsoft YaHei UI",
+ "zh-Hant" => "Microsoft YaHei UI",
+ "zu-ZA" => "Segoe UI",
+ _ => null,
+ };
+ if (familyName is null)
+ continue;
+ var family = IFontFamilyId
+ .ListSystemFonts(false)
+ .FirstOrDefault(
+ x => x.EnglishName.Equals(familyName, StringComparison.InvariantCultureIgnoreCase));
+ if (family?.Fonts[family.FindBestMatch(weight, stretch, style)] is not { } font)
+ return;
+ font.AddToBuildToolkit(this, fontConfig with { MergeFont = targetFont });
+ return;
+ }
+ }
+
///
public void AttachExtraGlyphsForDalamudLanguage(in SafeFontConfig fontConfig)
{
+ var targetFont = fontConfig.MergeFont;
+ if (targetFont.IsNull())
+ targetFont = this.Font;
+ if (targetFont.IsNull())
+ return;
+
var dalamudConfiguration = Service.Get();
if (dalamudConfiguration.EffectiveLanguage == "ko"
|| Service.GetNullable()?.EncounteredHangul is true)
@@ -444,41 +600,24 @@ internal sealed partial class FontAtlasFactory
DalamudAsset.NotoSansKrRegular,
fontConfig with
{
- GlyphRanges = ImGuiHelpers.CreateImGuiRangesFrom(
- UnicodeRanges.HangulJamo,
- UnicodeRanges.HangulCompatibilityJamo,
- UnicodeRanges.HangulSyllables,
- UnicodeRanges.HangulJamoExtendedA,
- UnicodeRanges.HangulJamoExtendedB),
+ MergeFont = targetFont,
+ GlyphRanges = default(FluentGlyphRangeBuilder).WithLanguage("ko-kr").BuildExact(),
});
}
- var windowsDir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
- var fontPathChs = Path.Combine(windowsDir, "Fonts", "msyh.ttc");
- if (!File.Exists(fontPathChs))
- fontPathChs = null;
-
- var fontPathCht = Path.Combine(windowsDir, "Fonts", "msjh.ttc");
- if (!File.Exists(fontPathCht))
- fontPathCht = null;
-
- if (fontPathCht != null && Service.Get().EffectiveLanguage == "tw")
+ if (Service.Get().EffectiveLanguage == "tw")
{
- this.AddFontFromFile(fontPathCht, fontConfig with
+ this.AttachWindowsDefaultFont(CultureInfo.GetCultureInfo("zh-hant"), fontConfig with
{
- GlyphRanges = ImGuiHelpers.CreateImGuiRangesFrom(
- UnicodeRanges.CjkUnifiedIdeographs,
- UnicodeRanges.CjkUnifiedIdeographsExtensionA),
+ GlyphRanges = default(FluentGlyphRangeBuilder).WithLanguage("zh-hant").BuildExact(),
});
}
- else if (fontPathChs != null && (Service.Get().EffectiveLanguage == "zh"
- || Service.GetNullable()?.EncounteredHan is true))
+ else if (Service.Get().EffectiveLanguage == "zh"
+ || Service.GetNullable()?.EncounteredHan is true)
{
- this.AddFontFromFile(fontPathChs, fontConfig with
+ this.AttachWindowsDefaultFont(CultureInfo.GetCultureInfo("zh-hans"), fontConfig with
{
- GlyphRanges = ImGuiHelpers.CreateImGuiRangesFrom(
- UnicodeRanges.CjkUnifiedIdeographs,
- UnicodeRanges.CjkUnifiedIdeographsExtensionA),
+ GlyphRanges = default(FluentGlyphRangeBuilder).WithLanguage("zh-hans").BuildExact(),
});
}
}