mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Add FluentGlyphRangeBuilder and AttachWindowsDefaultFont (#1745)
`FluentGlyphRangeBuilder` can build glyph ranges without having to allocate native ImGui objects, and supports adding `ReadOnlySpan` and `IEnumerable` of `char`s and `byte`s, `UnicodeRange`s, and known glyph ranges for select cultures (CJK for now.) Added `IFontAtlasBuildToolkitPreBuild.AttachWindowsDefaultFont` which has a predefined list of default Windows fonts per language.
This commit is contained in:
parent
2ea89e216a
commit
05c943df69
4 changed files with 594 additions and 44 deletions
361
Dalamud/Interface/ManagedFontAtlas/FluentGlyphRangeBuilder.cs
Normal file
361
Dalamud/Interface/ManagedFontAtlas/FluentGlyphRangeBuilder.cs
Normal file
|
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>A fluent ImGui glyph range builder.</summary>
|
||||||
|
[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;
|
||||||
|
|
||||||
|
/// <summary>Clears the builder.</summary>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>A builder is in cleared state on first use.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public FluentGlyphRangeBuilder Clear()
|
||||||
|
{
|
||||||
|
this.characters?.SetAll(false);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Adds a single codepoint to the builder.</summary>
|
||||||
|
/// <param name="codepoint">The codepoint to add.</param>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>Unsupported codepoints will be ignored.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public FluentGlyphRangeBuilder With(char codepoint) => this.With((int)codepoint);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="With(char)"/>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public FluentGlyphRangeBuilder With(uint codepoint) =>
|
||||||
|
codepoint <= char.MaxValue ? this.With((int)codepoint) : this;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="With(char)"/>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public FluentGlyphRangeBuilder With(int codepoint)
|
||||||
|
{
|
||||||
|
if (codepoint <= ImUnicodeCodepointMax)
|
||||||
|
this.EnsureCharacters().Set(codepoint, true);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Adds a unicode range to the builder.</summary>
|
||||||
|
/// <param name="range">The unicode range to add.</param>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>Unsupported codepoints will be ignored.</remarks>
|
||||||
|
public FluentGlyphRangeBuilder With(UnicodeRange range) =>
|
||||||
|
this.With(range.FirstCodePoint, (range.FirstCodePoint + range.Length) - 1);
|
||||||
|
|
||||||
|
/// <summary>Adds unicode ranges to the builder.</summary>
|
||||||
|
/// <param name="range1">The 1st unicode range to add.</param>
|
||||||
|
/// <param name="range2">The 2st unicode range to add.</param>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>Unsupported codepoints will be ignored.</remarks>
|
||||||
|
public FluentGlyphRangeBuilder With(UnicodeRange range1, UnicodeRange range2) =>
|
||||||
|
this.With(range1.FirstCodePoint, (range1.FirstCodePoint + range1.Length) - 1)
|
||||||
|
.With(range2.FirstCodePoint, (range2.FirstCodePoint + range2.Length) - 1);
|
||||||
|
|
||||||
|
/// <summary>Adds unicode ranges to the builder.</summary>
|
||||||
|
/// <param name="range1">The 1st unicode range to add.</param>
|
||||||
|
/// <param name="range2">The 2st unicode range to add.</param>
|
||||||
|
/// <param name="range3">The 3rd unicode range to add.</param>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>Unsupported codepoints will be ignored.</remarks>
|
||||||
|
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);
|
||||||
|
|
||||||
|
/// <summary>Adds unicode ranges to the builder.</summary>
|
||||||
|
/// <param name="range1">The 1st unicode range to add.</param>
|
||||||
|
/// <param name="range2">The 2st unicode range to add.</param>
|
||||||
|
/// <param name="range3">The 3rd unicode range to add.</param>
|
||||||
|
/// <param name="range4">The 4th unicode range to add.</param>
|
||||||
|
/// <param name="evenMoreRanges">Even more unicode ranges to add.</param>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>Unsupported codepoints will be ignored.</remarks>
|
||||||
|
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);
|
||||||
|
|
||||||
|
/// <summary>Adds unicode ranges to the builder.</summary>
|
||||||
|
/// <param name="ranges">Unicode ranges to add.</param>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>Unsupported codepoints will be ignored.</remarks>
|
||||||
|
public FluentGlyphRangeBuilder With(IEnumerable<UnicodeRange> ranges)
|
||||||
|
{
|
||||||
|
foreach (var range in ranges)
|
||||||
|
this.With(range);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Adds a range of characters to the builder.</summary>
|
||||||
|
/// <param name="from">The first codepoint, inclusive.</param>
|
||||||
|
/// <param name="to">The last codepoint, inclusive.</param>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>Unsupported codepoints will be ignored.</para>
|
||||||
|
/// <para>If <paramref name="from"/> is more than <paramref name="to"/>, then they will be swapped.</para>
|
||||||
|
/// </remarks>
|
||||||
|
public FluentGlyphRangeBuilder With(char from, char to) =>
|
||||||
|
this.With(Math.Clamp(from, int.MinValue, int.MaxValue), Math.Clamp(to, int.MinValue, int.MaxValue));
|
||||||
|
|
||||||
|
/// <inheritdoc cref="With(char,char)"/>
|
||||||
|
public FluentGlyphRangeBuilder With(uint from, uint to) =>
|
||||||
|
this.With((int)Math.Min(from, int.MaxValue), (int)Math.Min(to, int.MaxValue));
|
||||||
|
|
||||||
|
/// <inheritdoc cref="With(char,char)"/>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Adds characters from a UTF-8 character sequence.</summary>
|
||||||
|
/// <param name="utf8Sequence">The sequence.</param>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>Unsupported codepoints will be ignored.</remarks>
|
||||||
|
public FluentGlyphRangeBuilder With(ReadOnlySpan<byte> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Adds characters from a UTF-8 character sequence.</summary>
|
||||||
|
/// <param name="utf8Sequence">The sequence.</param>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>Unsupported codepoints will be ignored.</remarks>
|
||||||
|
public FluentGlyphRangeBuilder With(IEnumerable<byte> utf8Sequence)
|
||||||
|
{
|
||||||
|
Span<byte> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Adds characters from a UTF-16 character sequence.</summary>
|
||||||
|
/// <param name="utf16Sequence">The sequence.</param>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>Unsupported codepoints will be ignored.</remarks>
|
||||||
|
public FluentGlyphRangeBuilder With(ReadOnlySpan<char> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Adds characters from a UTF-16 character sequence.</summary>
|
||||||
|
/// <param name="utf16Sequence">The sequence.</param>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>Unsupported codepoints will be ignored.</remarks>
|
||||||
|
public FluentGlyphRangeBuilder With(IEnumerable<char> utf16Sequence)
|
||||||
|
{
|
||||||
|
var bits = this.EnsureCharacters();
|
||||||
|
foreach (var c in utf16Sequence)
|
||||||
|
{
|
||||||
|
if (!char.IsSurrogate(c))
|
||||||
|
bits.Set(c, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Adds characters from a string.</summary>
|
||||||
|
/// <param name="string">The string.</param>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>Unsupported codepoints will be ignored.</remarks>
|
||||||
|
public FluentGlyphRangeBuilder With(string @string) => this.With(@string.AsSpan());
|
||||||
|
|
||||||
|
/// <summary>Adds glyphs that are likely to be used in the given culture to the builder.</summary>
|
||||||
|
/// <param name="cultureInfo">A culture info.</param>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>Unsupported codepoints will be ignored. Unsupported culture will do nothing.
|
||||||
|
/// Do make a PR if you need more.</remarks>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Adds glyphs that are likely to be used in the given culture to the builder.</summary>
|
||||||
|
/// <param name="languageTag">A language tag that will be used to locate the culture info.</param>
|
||||||
|
/// <returns><c>this</c> for method chaining.</returns>
|
||||||
|
/// <remarks>See <see cref="CultureInfo.GetCultureInfo(string)"/> documentation for supported language tags.
|
||||||
|
/// </remarks>
|
||||||
|
public FluentGlyphRangeBuilder WithLanguage(string languageTag) =>
|
||||||
|
this.WithLanguage(CultureInfo.GetCultureInfo(languageTag));
|
||||||
|
|
||||||
|
/// <summary>Builds the accumulated data into an ImGui glyph range.</summary>
|
||||||
|
/// <param name="addFallbackCodepoints">Whether to add the default fallback codepoints to the range.</param>
|
||||||
|
/// <param name="addEllipsisCodepoints">Whether to add the default ellipsis codepoints to the range.</param>
|
||||||
|
/// <returns>The built ImGui glyph ranges.</returns>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Builds the accumulated data into an ImGui glyph range, exactly as specified.</summary>
|
||||||
|
/// <returns>The built ImGui glyph ranges.</returns>
|
||||||
|
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<ushort>((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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Ensures that <see cref="characters"/> is not null, by creating one as necessary.</summary>
|
||||||
|
/// <returns>An instance of <see cref="BitArray"/>.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private BitArray EnsureCharacters() => this.characters ??= new(ImUnicodeCodepointMax + 1);
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text.Unicode;
|
||||||
|
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
|
|
||||||
|
|
@ -12,6 +13,34 @@ namespace Dalamud.Interface.ManagedFontAtlas;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class FontAtlasBuildToolkitUtilities
|
public static class FontAtlasBuildToolkitUtilities
|
||||||
{
|
{
|
||||||
|
/// <summary>Begins building a new array of <see cref="ushort"/> containing ImGui glyph ranges.</summary>
|
||||||
|
/// <param name="chars">The chars.</param>
|
||||||
|
/// <returns>A new range builder.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static FluentGlyphRangeBuilder BeginGlyphRange(this IEnumerable<char> chars) =>
|
||||||
|
default(FluentGlyphRangeBuilder).With(chars);
|
||||||
|
|
||||||
|
/// <summary>Begins building a new array of <see cref="ushort"/> containing ImGui glyph ranges.</summary>
|
||||||
|
/// <param name="chars">The chars.</param>
|
||||||
|
/// <returns>A new range builder.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static FluentGlyphRangeBuilder BeginGlyphRange(this ReadOnlySpan<char> chars) =>
|
||||||
|
default(FluentGlyphRangeBuilder).With(chars);
|
||||||
|
|
||||||
|
/// <summary>Begins building a new array of <see cref="ushort"/> containing ImGui glyph ranges.</summary>
|
||||||
|
/// <param name="chars">The chars.</param>
|
||||||
|
/// <returns>A new range builder.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static FluentGlyphRangeBuilder BeginGlyphRange(this string chars) =>
|
||||||
|
default(FluentGlyphRangeBuilder).With(chars);
|
||||||
|
|
||||||
|
/// <summary>Begins building a new array of <see cref="ushort"/> containing ImGui glyph ranges.</summary>
|
||||||
|
/// <param name="range">The unicode range.</param>
|
||||||
|
/// <returns>A new range builder.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static FluentGlyphRangeBuilder BeginGlyphRange(this UnicodeRange range) =>
|
||||||
|
default(FluentGlyphRangeBuilder).With(range);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compiles given <see cref="char"/>s into an array of <see cref="ushort"/> containing ImGui glyph ranges.
|
/// Compiles given <see cref="char"/>s into an array of <see cref="ushort"/> containing ImGui glyph ranges.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -19,16 +48,12 @@ public static class FontAtlasBuildToolkitUtilities
|
||||||
/// <param name="addFallbackCodepoints">Add fallback codepoints to the range.</param>
|
/// <param name="addFallbackCodepoints">Add fallback codepoints to the range.</param>
|
||||||
/// <param name="addEllipsisCodepoints">Add ellipsis codepoints to the range.</param>
|
/// <param name="addEllipsisCodepoints">Add ellipsis codepoints to the range.</param>
|
||||||
/// <returns>The compiled range.</returns>
|
/// <returns>The compiled range.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ushort[] ToGlyphRange(
|
public static ushort[] ToGlyphRange(
|
||||||
this IEnumerable<char> enumerable,
|
this IEnumerable<char> enumerable,
|
||||||
bool addFallbackCodepoints = true,
|
bool addFallbackCodepoints = true,
|
||||||
bool addEllipsisCodepoints = true)
|
bool addEllipsisCodepoints = true) =>
|
||||||
{
|
enumerable.BeginGlyphRange().Build(addFallbackCodepoints, addEllipsisCodepoints);
|
||||||
using var builderScoped = ImGuiHelpers.NewFontGlyphRangeBuilderPtrScoped(out var builder);
|
|
||||||
foreach (var c in enumerable)
|
|
||||||
builder.AddChar(c);
|
|
||||||
return builder.BuildRangesToArray(addFallbackCodepoints, addEllipsisCodepoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compiles given <see cref="char"/>s into an array of <see cref="ushort"/> containing ImGui glyph ranges.
|
/// Compiles given <see cref="char"/>s into an array of <see cref="ushort"/> containing ImGui glyph ranges.
|
||||||
|
|
@ -37,16 +62,12 @@ public static class FontAtlasBuildToolkitUtilities
|
||||||
/// <param name="addFallbackCodepoints">Add fallback codepoints to the range.</param>
|
/// <param name="addFallbackCodepoints">Add fallback codepoints to the range.</param>
|
||||||
/// <param name="addEllipsisCodepoints">Add ellipsis codepoints to the range.</param>
|
/// <param name="addEllipsisCodepoints">Add ellipsis codepoints to the range.</param>
|
||||||
/// <returns>The compiled range.</returns>
|
/// <returns>The compiled range.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ushort[] ToGlyphRange(
|
public static ushort[] ToGlyphRange(
|
||||||
this ReadOnlySpan<char> span,
|
this ReadOnlySpan<char> span,
|
||||||
bool addFallbackCodepoints = true,
|
bool addFallbackCodepoints = true,
|
||||||
bool addEllipsisCodepoints = true)
|
bool addEllipsisCodepoints = true) =>
|
||||||
{
|
span.BeginGlyphRange().Build(addFallbackCodepoints, addEllipsisCodepoints);
|
||||||
using var builderScoped = ImGuiHelpers.NewFontGlyphRangeBuilderPtrScoped(out var builder);
|
|
||||||
foreach (var c in span)
|
|
||||||
builder.AddChar(c);
|
|
||||||
return builder.BuildRangesToArray(addFallbackCodepoints, addEllipsisCodepoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compiles given string into an array of <see cref="ushort"/> containing ImGui glyph ranges.
|
/// Compiles given string into an array of <see cref="ushort"/> containing ImGui glyph ranges.
|
||||||
|
|
@ -55,11 +76,12 @@ public static class FontAtlasBuildToolkitUtilities
|
||||||
/// <param name="addFallbackCodepoints">Add fallback codepoints to the range.</param>
|
/// <param name="addFallbackCodepoints">Add fallback codepoints to the range.</param>
|
||||||
/// <param name="addEllipsisCodepoints">Add ellipsis codepoints to the range.</param>
|
/// <param name="addEllipsisCodepoints">Add ellipsis codepoints to the range.</param>
|
||||||
/// <returns>The compiled range.</returns>
|
/// <returns>The compiled range.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ushort[] ToGlyphRange(
|
public static ushort[] ToGlyphRange(
|
||||||
this string @string,
|
this string @string,
|
||||||
bool addFallbackCodepoints = true,
|
bool addFallbackCodepoints = true,
|
||||||
bool addEllipsisCodepoints = true) =>
|
bool addEllipsisCodepoints = true) =>
|
||||||
@string.AsSpan().ToGlyphRange(addFallbackCodepoints, addEllipsisCodepoints);
|
@string.BeginGlyphRange().Build(addFallbackCodepoints, addEllipsisCodepoints);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds the corresponding <see cref="ImFontConfigPtr"/> in
|
/// Finds the corresponding <see cref="ImFontConfigPtr"/> in
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System.IO;
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
using Dalamud.Interface.FontIdentifier;
|
using Dalamud.Interface.FontIdentifier;
|
||||||
|
|
@ -8,6 +9,8 @@ using Dalamud.Utility;
|
||||||
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
|
||||||
namespace Dalamud.Interface.ManagedFontAtlas;
|
namespace Dalamud.Interface.ManagedFontAtlas;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -216,10 +219,35 @@ public interface IFontAtlasBuildToolkitPreBuild : IFontAtlasBuildToolkit
|
||||||
/// <returns>The added font.</returns>
|
/// <returns>The added font.</returns>
|
||||||
ImFontPtr AddGameGlyphs(GameFontStyle gameFontStyle, ushort[]? glyphRanges, ImFontPtr mergeFont);
|
ImFontPtr AddGameGlyphs(GameFontStyle gameFontStyle, ushort[]? glyphRanges, ImFontPtr mergeFont);
|
||||||
|
|
||||||
|
/// <summary>Adds glyphs from the Windows default font for the given culture info into the provided font.</summary>
|
||||||
|
/// <param name="cultureInfo">The culture info.</param>
|
||||||
|
/// <param name="fontConfig">The font config. If <see cref="SafeFontConfig.MergeFont"/> is not set, then
|
||||||
|
/// <see cref="IFontAtlasBuildToolkit.Font"/> will be used as the target. If that is empty too, then it will do
|
||||||
|
/// nothing.</param>
|
||||||
|
/// <param name="weight">The font weight, in range from <c>1</c> to <c>1000</c>. <c>400</c> is regular(normal).
|
||||||
|
/// </param>
|
||||||
|
/// <param name="stretch">The font stretch, in range from <c>1</c> to <c>9</c>. <c>5</c> is medium(normal).
|
||||||
|
/// </param>
|
||||||
|
/// <param name="style">The font style, in range from <c>0</c> to <c>2</c>. <c>0</c> is normal.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>May do nothing at all if <paramref name="cultureInfo"/> is unsupported by Dalamud font handler.</para>
|
||||||
|
/// <para>See
|
||||||
|
/// <a href="https://learn.microsoft.com/en-us/windows/apps/design/globalizing/loc-international-fonts">Microsoft
|
||||||
|
/// Learn</a> for the fonts.</para>
|
||||||
|
/// </remarks>
|
||||||
|
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);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds glyphs of extra languages into the provided font, depending on Dalamud Configuration.<br />
|
/// Adds glyphs of extra languages into the provided font, depending on Dalamud Configuration.<br />
|
||||||
/// <see cref="SafeFontConfig.GlyphRanges"/> will be ignored.
|
/// <see cref="SafeFontConfig.GlyphRanges"/> will be ignored.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fontConfig">The font config.</param>
|
/// <param name="fontConfig">The font config. If <see cref="SafeFontConfig.MergeFont"/> is not set, then
|
||||||
|
/// <see cref="IFontAtlasBuildToolkit.Font"/> will be used as the target. If that is empty too, then it will do
|
||||||
|
/// nothing.</param>
|
||||||
void AttachExtraGlyphsForDalamudLanguage(in SafeFontConfig fontConfig);
|
void AttachExtraGlyphsForDalamudLanguage(in SafeFontConfig fontConfig);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text.Unicode;
|
|
||||||
|
|
||||||
using Dalamud.Configuration.Internal;
|
using Dalamud.Configuration.Internal;
|
||||||
using Dalamud.Interface.FontIdentifier;
|
using Dalamud.Interface.FontIdentifier;
|
||||||
|
|
@ -17,6 +17,8 @@ using ImGuiNET;
|
||||||
|
|
||||||
using SharpDX.DXGI;
|
using SharpDX.DXGI;
|
||||||
|
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
|
||||||
namespace Dalamud.Interface.ManagedFontAtlas.Internals;
|
namespace Dalamud.Interface.ManagedFontAtlas.Internals;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -433,9 +435,163 @@ internal sealed partial class FontAtlasFactory
|
||||||
public ImFontPtr AddGameGlyphs(GameFontStyle gameFontStyle, ushort[]? glyphRanges, ImFontPtr mergeFont) =>
|
public ImFontPtr AddGameGlyphs(GameFontStyle gameFontStyle, ushort[]? glyphRanges, ImFontPtr mergeFont) =>
|
||||||
this.gameFontHandleSubstance.AttachGameGlyphs(this, mergeFont, gameFontStyle, glyphRanges);
|
this.gameFontHandleSubstance.AttachGameGlyphs(this, mergeFont, gameFontStyle, glyphRanges);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void AttachExtraGlyphsForDalamudLanguage(in SafeFontConfig fontConfig)
|
public void AttachExtraGlyphsForDalamudLanguage(in SafeFontConfig fontConfig)
|
||||||
{
|
{
|
||||||
|
var targetFont = fontConfig.MergeFont;
|
||||||
|
if (targetFont.IsNull())
|
||||||
|
targetFont = this.Font;
|
||||||
|
if (targetFont.IsNull())
|
||||||
|
return;
|
||||||
|
|
||||||
var dalamudConfiguration = Service<DalamudConfiguration>.Get();
|
var dalamudConfiguration = Service<DalamudConfiguration>.Get();
|
||||||
if (dalamudConfiguration.EffectiveLanguage == "ko"
|
if (dalamudConfiguration.EffectiveLanguage == "ko"
|
||||||
|| Service<DalamudIme>.GetNullable()?.EncounteredHangul is true)
|
|| Service<DalamudIme>.GetNullable()?.EncounteredHangul is true)
|
||||||
|
|
@ -444,41 +600,24 @@ internal sealed partial class FontAtlasFactory
|
||||||
DalamudAsset.NotoSansKrRegular,
|
DalamudAsset.NotoSansKrRegular,
|
||||||
fontConfig with
|
fontConfig with
|
||||||
{
|
{
|
||||||
GlyphRanges = ImGuiHelpers.CreateImGuiRangesFrom(
|
MergeFont = targetFont,
|
||||||
UnicodeRanges.HangulJamo,
|
GlyphRanges = default(FluentGlyphRangeBuilder).WithLanguage("ko-kr").BuildExact(),
|
||||||
UnicodeRanges.HangulCompatibilityJamo,
|
|
||||||
UnicodeRanges.HangulSyllables,
|
|
||||||
UnicodeRanges.HangulJamoExtendedA,
|
|
||||||
UnicodeRanges.HangulJamoExtendedB),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var windowsDir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
|
if (Service<DalamudConfiguration>.Get().EffectiveLanguage == "tw")
|
||||||
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<DalamudConfiguration>.Get().EffectiveLanguage == "tw")
|
|
||||||
{
|
{
|
||||||
this.AddFontFromFile(fontPathCht, fontConfig with
|
this.AttachWindowsDefaultFont(CultureInfo.GetCultureInfo("zh-hant"), fontConfig with
|
||||||
{
|
{
|
||||||
GlyphRanges = ImGuiHelpers.CreateImGuiRangesFrom(
|
GlyphRanges = default(FluentGlyphRangeBuilder).WithLanguage("zh-hant").BuildExact(),
|
||||||
UnicodeRanges.CjkUnifiedIdeographs,
|
|
||||||
UnicodeRanges.CjkUnifiedIdeographsExtensionA),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (fontPathChs != null && (Service<DalamudConfiguration>.Get().EffectiveLanguage == "zh"
|
else if (Service<DalamudConfiguration>.Get().EffectiveLanguage == "zh"
|
||||||
|| Service<DalamudIme>.GetNullable()?.EncounteredHan is true))
|
|| Service<DalamudIme>.GetNullable()?.EncounteredHan is true)
|
||||||
{
|
{
|
||||||
this.AddFontFromFile(fontPathChs, fontConfig with
|
this.AttachWindowsDefaultFont(CultureInfo.GetCultureInfo("zh-hans"), fontConfig with
|
||||||
{
|
{
|
||||||
GlyphRanges = ImGuiHelpers.CreateImGuiRangesFrom(
|
GlyphRanges = default(FluentGlyphRangeBuilder).WithLanguage("zh-hans").BuildExact(),
|
||||||
UnicodeRanges.CjkUnifiedIdeographs,
|
|
||||||
UnicodeRanges.CjkUnifiedIdeographsExtensionA),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue