mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-31 21:03:43 +01:00
Merge branch 'apiX' into feature/itextureprovider-updates
This commit is contained in:
commit
8c7771bf7d
2213 changed files with 10372 additions and 1088868 deletions
|
|
@ -132,14 +132,6 @@ internal sealed class DelegateFontHandle : FontHandle
|
|||
/// <inheritdoc/>
|
||||
public IFontHandleManager Manager { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
|
||||
public IFontAtlasBuildToolkitPreBuild? PreBuildToolkitForApi9Compat { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
|
||||
public bool CreateFontOnAccess { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
using System.Buffers;
|
||||
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;
|
||||
|
|
@ -34,7 +34,7 @@ internal sealed partial class FontAtlasFactory
|
|||
/// Implementations for <see cref="IFontAtlasBuildToolkitPreBuild"/> and
|
||||
/// <see cref="IFontAtlasBuildToolkitPostBuild"/>.
|
||||
/// </summary>
|
||||
private class BuildToolkit : IFontAtlasBuildToolkit.IApi9Compat, IFontAtlasBuildToolkitPreBuild, IFontAtlasBuildToolkitPostBuild, IDisposable
|
||||
private class BuildToolkit : IFontAtlasBuildToolkitPreBuild, IFontAtlasBuildToolkitPostBuild, IDisposable
|
||||
{
|
||||
private static readonly ushort FontAwesomeIconMin =
|
||||
(ushort)Enum.GetValues<FontAwesomeIcon>().Where(x => x > 0).Min();
|
||||
|
|
@ -112,34 +112,6 @@ internal sealed partial class FontAtlasFactory
|
|||
/// <inheritdoc/>
|
||||
public void DisposeWithAtlas(Action action) => this.data.Garbage.Add(action);
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
|
||||
public void FromUiBuilderObsoleteEventHandlers(Action action)
|
||||
{
|
||||
var previousSubstances = new IFontHandleSubstance[this.data.Substances.Count];
|
||||
for (var i = 0; i < previousSubstances.Length; i++)
|
||||
{
|
||||
previousSubstances[i] = this.data.Substances[i].Manager.Substance;
|
||||
this.data.Substances[i].Manager.Substance = this.data.Substances[i];
|
||||
this.data.Substances[i].CreateFontOnAccess = true;
|
||||
this.data.Substances[i].PreBuildToolkitForApi9Compat = this;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
finally
|
||||
{
|
||||
for (var i = 0; i < previousSubstances.Length; i++)
|
||||
{
|
||||
this.data.Substances[i].Manager.Substance = previousSubstances[i];
|
||||
this.data.Substances[i].CreateFontOnAccess = false;
|
||||
this.data.Substances[i].PreBuildToolkitForApi9Compat = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ImFontPtr GetFont(IFontHandle fontHandle)
|
||||
{
|
||||
|
|
@ -167,7 +139,7 @@ internal sealed partial class FontAtlasFactory
|
|||
/// <inheritdoc/>
|
||||
public int StoreTexture(IDalamudTextureWrap textureWrap, bool disposeOnError) =>
|
||||
this.data.AddNewTexture(textureWrap, disposeOnError);
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RegisterPostBuild(Action action) => this.registeredPostBuildActions.Add(action);
|
||||
|
||||
|
|
@ -392,12 +364,10 @@ internal sealed partial class FontAtlasFactory
|
|||
});
|
||||
|
||||
case DalamudAsset.LodestoneGameSymbol when !this.factory.HasGameSymbolsFontFile:
|
||||
{
|
||||
return this.AddGameGlyphs(
|
||||
new(GameFontFamily.Axis, fontConfig.SizePx),
|
||||
fontConfig.GlyphRanges,
|
||||
fontConfig.MergeFont);
|
||||
}
|
||||
|
||||
default:
|
||||
return this.factory.AddFont(
|
||||
|
|
@ -436,9 +406,163 @@ internal sealed partial class FontAtlasFactory
|
|||
public ImFontPtr AddGameGlyphs(GameFontStyle gameFontStyle, ushort[]? glyphRanges, ImFontPtr mergeFont) =>
|
||||
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/>
|
||||
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();
|
||||
if (dalamudConfiguration.EffectiveLanguage == "ko"
|
||||
|| Service<DalamudIme>.GetNullable()?.EncounteredHangul is true)
|
||||
|
|
@ -447,41 +571,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<DalamudConfiguration>.Get().EffectiveLanguage == "tw")
|
||||
if (Service<DalamudConfiguration>.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<DalamudConfiguration>.Get().EffectiveLanguage == "zh"
|
||||
|| Service<DalamudIme>.GetNullable()?.EncounteredHan is true))
|
||||
else if (Service<DalamudConfiguration>.Get().EffectiveLanguage == "zh"
|
||||
|| Service<DalamudIme>.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(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -728,5 +835,30 @@ internal sealed partial class FontAtlasFactory
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void FitRatio(ImFontPtr font, bool rebuildLookupTable = true)
|
||||
{
|
||||
var nsize = font.FontSize;
|
||||
var glyphs = font.GlyphsWrapped();
|
||||
foreach (ref var glyph in glyphs.DataSpan)
|
||||
{
|
||||
var ratio = 1f;
|
||||
if (glyph.X1 - glyph.X0 > nsize)
|
||||
ratio = Math.Max(ratio, (glyph.X1 - glyph.X0) / nsize);
|
||||
if (glyph.Y1 - glyph.Y0 > nsize)
|
||||
ratio = Math.Max(ratio, (glyph.Y1 - glyph.Y0) / nsize);
|
||||
var w = MathF.Round((glyph.X1 - glyph.X0) / ratio, MidpointRounding.ToZero);
|
||||
var h = MathF.Round((glyph.Y1 - glyph.Y0) / ratio, MidpointRounding.AwayFromZero);
|
||||
glyph.X0 = MathF.Round((nsize - w) / 2f, MidpointRounding.ToZero);
|
||||
glyph.Y0 = MathF.Round((nsize - h) / 2f, MidpointRounding.AwayFromZero);
|
||||
glyph.X1 = glyph.X0 + w;
|
||||
glyph.Y1 = glyph.Y0 + h;
|
||||
glyph.AdvanceX = nsize;
|
||||
}
|
||||
|
||||
if (rebuildLookupTable)
|
||||
this.BuildLookupTable(font);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ internal sealed partial class FontAtlasFactory
|
|||
/// </summary>
|
||||
public const string EllipsisCodepoints = "\u2026\u0085";
|
||||
|
||||
/// <summary>Marker for tasks on whether it's being called inside a font build cycle.</summary>
|
||||
public static readonly AsyncLocal<bool> IsBuildInProgressForTask = new();
|
||||
|
||||
/// <summary>
|
||||
/// If set, disables concurrent font build operation.
|
||||
/// </summary>
|
||||
|
|
@ -205,12 +208,12 @@ internal sealed partial class FontAtlasFactory
|
|||
{
|
||||
while (this.IsBuildInProgress)
|
||||
await Task.Delay(100);
|
||||
this.Garbage.Dispose();
|
||||
this.Clear();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Garbage.Dispose();
|
||||
this.Clear();
|
||||
}
|
||||
|
||||
return newRefCount;
|
||||
|
|
@ -228,6 +231,20 @@ internal sealed partial class FontAtlasFactory
|
|||
var axisSubstance = this.Substances.OfType<GamePrebakedFontHandle.HandleSubstance>().Single();
|
||||
return new(factory, this, axisSubstance, isAsync) { BuildStep = FontAtlasBuildStep.PreBuild };
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.Garbage.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(
|
||||
e,
|
||||
$"Disposing {nameof(FontAtlasBuiltData)} of {this.Owner?.Name ?? "???"}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DalamudFontAtlas : IFontAtlas, DisposeSafety.IDisposeCallback
|
||||
|
|
@ -420,11 +437,28 @@ internal sealed partial class FontAtlasFactory
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IFontHandle NewGameFontHandle(GameFontStyle style) => this.gameFontHandleManager.NewFontHandle(style);
|
||||
public IFontHandle NewGameFontHandle(GameFontStyle style)
|
||||
{
|
||||
if (IsBuildInProgressForTask.Value)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"{nameof(this.NewGameFontHandle)} may not be called during {nameof(this.BuildStepChange)} or the callback of {nameof(this.NewDelegateFontHandle)}.");
|
||||
}
|
||||
|
||||
return this.gameFontHandleManager.NewFontHandle(style);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IFontHandle NewDelegateFontHandle(FontAtlasBuildStepDelegate buildStepDelegate) =>
|
||||
this.delegateFontHandleManager.NewFontHandle(buildStepDelegate);
|
||||
public IFontHandle NewDelegateFontHandle(FontAtlasBuildStepDelegate buildStepDelegate)
|
||||
{
|
||||
if (IsBuildInProgressForTask.Value)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"{nameof(this.NewDelegateFontHandle)} may not be called during {nameof(this.BuildStepChange)} or the callback of {nameof(this.NewDelegateFontHandle)}.");
|
||||
}
|
||||
|
||||
return this.delegateFontHandleManager.NewFontHandle(buildStepDelegate);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void BuildFontsOnNextFrame()
|
||||
|
|
@ -554,13 +588,13 @@ internal sealed partial class FontAtlasFactory
|
|||
{
|
||||
if (this.buildIndex != rebuildIndex)
|
||||
{
|
||||
data.ExplicitDisposeIgnoreExceptions();
|
||||
data.Release();
|
||||
return;
|
||||
}
|
||||
|
||||
var prevBuiltData = this.builtData;
|
||||
this.builtData = data;
|
||||
prevBuiltData.ExplicitDisposeIgnoreExceptions();
|
||||
prevBuiltData?.Release();
|
||||
|
||||
this.buildTask = EmptyTask;
|
||||
fontsAndLocks.EnsureCapacity(data.Substances.Sum(x => x.RelevantHandles.Count));
|
||||
|
|
@ -623,6 +657,8 @@ internal sealed partial class FontAtlasFactory
|
|||
FontAtlasBuiltData? res = null;
|
||||
nint atlasPtr = 0;
|
||||
BuildToolkit? toolkit = null;
|
||||
|
||||
IsBuildInProgressForTask.Value = true;
|
||||
try
|
||||
{
|
||||
res = new(this, scale);
|
||||
|
|
@ -747,6 +783,7 @@ internal sealed partial class FontAtlasFactory
|
|||
// ReSharper disable once ConstantConditionalAccessQualifier
|
||||
toolkit?.Dispose();
|
||||
this.buildQueued = false;
|
||||
IsBuildInProgressForTask.Value = false;
|
||||
}
|
||||
|
||||
unsafe bool ValidateMergeFontReferences(ImFontPtr replacementDstFont)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace Dalamud.Interface.ManagedFontAtlas.Internals;
|
|||
/// </summary>
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal sealed partial class FontAtlasFactory
|
||||
: IServiceType, GamePrebakedFontHandle.IGameFontTextureProvider, IDisposable
|
||||
: IInternalDisposableService, GamePrebakedFontHandle.IGameFontTextureProvider
|
||||
{
|
||||
private readonly DisposeSafety.ScopedFinalizer scopedFinalizer = new();
|
||||
private readonly CancellationTokenSource cancellationTokenSource = new();
|
||||
|
|
@ -166,7 +166,7 @@ internal sealed partial class FontAtlasFactory
|
|||
this.dalamudAssetManager.IsStreamImmediatelyAvailable(DalamudAsset.LodestoneGameSymbol);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.cancellationTokenSource.Cancel();
|
||||
this.scopedFinalizer.Dispose();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Interface.Internal;
|
||||
|
|
@ -24,7 +25,6 @@ internal abstract class FontHandle : IFontHandle
|
|||
private static readonly ConditionalWeakTable<LocalPlugin, object> NonMainThreadFontAccessWarning = new();
|
||||
private static long nextNonMainThreadFontAccessWarningCheck;
|
||||
|
||||
private readonly InterfaceManager interfaceManager;
|
||||
private readonly List<IDisposable> pushedFonts = new(8);
|
||||
|
||||
private IFontHandleManager? manager;
|
||||
|
|
@ -36,7 +36,6 @@ internal abstract class FontHandle : IFontHandle
|
|||
/// <param name="manager">An instance of <see cref="IFontHandleManager"/>.</param>
|
||||
protected FontHandle(IFontHandleManager manager)
|
||||
{
|
||||
this.interfaceManager = Service<InterfaceManager>.Get();
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
|
|
@ -58,7 +57,11 @@ internal abstract class FontHandle : IFontHandle
|
|||
/// Gets the associated <see cref="IFontHandleManager"/>.
|
||||
/// </summary>
|
||||
/// <exception cref="ObjectDisposedException">When the object has already been disposed.</exception>
|
||||
protected IFontHandleManager Manager => this.manager ?? throw new ObjectDisposedException(this.GetType().Name);
|
||||
protected IFontHandleManager Manager =>
|
||||
this.manager
|
||||
?? throw new ObjectDisposedException(
|
||||
this.GetType().Name,
|
||||
"Did you write `using (fontHandle)` instead of `using (fontHandle.Push())`?");
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
|
|
@ -122,7 +125,7 @@ internal abstract class FontHandle : IFontHandle
|
|||
}
|
||||
}
|
||||
|
||||
this.interfaceManager.EnqueueDeferredDispose(locked);
|
||||
Service<InterfaceManager>.Get().EnqueueDeferredDispose(locked);
|
||||
return locked.ImFont;
|
||||
}
|
||||
|
||||
|
|
@ -136,13 +139,18 @@ internal abstract class FontHandle : IFontHandle
|
|||
/// An instance of <see cref="ILockedImFont"/> that <b>must</b> be disposed after use on success;
|
||||
/// <c>null</c> with <paramref name="errorMessage"/> populated on failure.
|
||||
/// </returns>
|
||||
/// <exception cref="ObjectDisposedException">Still may be thrown.</exception>
|
||||
public ILockedImFont? TryLock(out string? errorMessage)
|
||||
{
|
||||
IFontHandleSubstance? prevSubstance = default;
|
||||
while (true)
|
||||
{
|
||||
var substance = this.Manager.Substance;
|
||||
if (this.manager is not { } nonDisposedManager)
|
||||
{
|
||||
errorMessage = "The font handle has been disposed.";
|
||||
return null;
|
||||
}
|
||||
|
||||
var substance = nonDisposedManager.Substance;
|
||||
|
||||
// Does the associated IFontAtlas have a built substance?
|
||||
if (substance is null)
|
||||
|
|
@ -196,7 +204,7 @@ internal abstract class FontHandle : IFontHandle
|
|||
ThreadSafety.AssertMainThread();
|
||||
|
||||
// Warn if the client is not properly managing the pushed font stack.
|
||||
var cumulativePresentCalls = this.interfaceManager.CumulativePresentCalls;
|
||||
var cumulativePresentCalls = Service<InterfaceManager>.Get().CumulativePresentCalls;
|
||||
if (this.lastCumulativePresentCalls != cumulativePresentCalls)
|
||||
{
|
||||
this.lastCumulativePresentCalls = cumulativePresentCalls;
|
||||
|
|
@ -213,7 +221,7 @@ internal abstract class FontHandle : IFontHandle
|
|||
if (this.TryLock(out _) is { } locked)
|
||||
{
|
||||
font = locked.ImFont;
|
||||
this.interfaceManager.EnqueueDeferredDispose(locked);
|
||||
Service<InterfaceManager>.Get().EnqueueDeferredDispose(locked);
|
||||
}
|
||||
|
||||
var rented = SimplePushedFont.Rent(this.pushedFonts, font);
|
||||
|
|
@ -284,11 +292,15 @@ internal abstract class FontHandle : IFontHandle
|
|||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (Interlocked.Exchange(ref this.manager, null) is not { } managerToDisassociate)
|
||||
return;
|
||||
|
||||
if (this.pushedFonts.Count > 0)
|
||||
Log.Warning($"{nameof(IFontHandle)}.{nameof(IDisposable.Dispose)}: fonts were still in a stack.");
|
||||
this.Manager.FreeFontHandle(this);
|
||||
this.manager = null;
|
||||
|
||||
managerToDisassociate.FreeFontHandle(this);
|
||||
this.Disposed?.InvokeSafely();
|
||||
this.Disposed = null;
|
||||
this.ImFontChanged = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -231,14 +231,6 @@ internal class GamePrebakedFontHandle : FontHandle
|
|||
/// <inheritdoc/>
|
||||
public IFontHandleManager Manager => this.handleManager;
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
|
||||
public IFontAtlasBuildToolkitPreBuild? PreBuildToolkitForApi9Compat { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
|
||||
public bool CreateFontOnAccess { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
@ -295,27 +287,11 @@ internal class GamePrebakedFontHandle : FontHandle
|
|||
}
|
||||
}
|
||||
|
||||
// Use this on API 10.
|
||||
// /// <inheritdoc/>
|
||||
// public ImFontPtr GetFontPtr(IFontHandle handle) =>
|
||||
// handle is GamePrebakedFontHandle ggfh
|
||||
// ? this.fonts.GetValueOrDefault(ggfh.FontStyle)?.FullRangeFont ?? default
|
||||
// : default;
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
|
||||
public ImFontPtr GetFontPtr(IFontHandle handle)
|
||||
{
|
||||
if (handle is not GamePrebakedFontHandle ggfh)
|
||||
return default;
|
||||
if (this.fonts.GetValueOrDefault(ggfh.FontStyle)?.FullRangeFont is { } font)
|
||||
return font;
|
||||
if (!this.CreateFontOnAccess)
|
||||
return default;
|
||||
if (this.PreBuildToolkitForApi9Compat is not { } tk)
|
||||
return default;
|
||||
return this.GetOrCreateFont(ggfh.FontStyle, tk);
|
||||
}
|
||||
public ImFontPtr GetFontPtr(IFontHandle handle) =>
|
||||
handle is GamePrebakedFontHandle ggfh
|
||||
? this.fonts.GetValueOrDefault(ggfh.FontStyle)?.FullRangeFont ?? default
|
||||
: default;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Exception? GetBuildException(IFontHandle handle) =>
|
||||
|
|
|
|||
|
|
@ -21,19 +21,6 @@ internal interface IFontHandleSubstance : IDisposable
|
|||
/// </summary>
|
||||
IFontHandleManager Manager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the relevant <see cref="IFontAtlasBuildToolkitPreBuild"/> for this.
|
||||
/// </summary>
|
||||
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
|
||||
IFontAtlasBuildToolkitPreBuild? PreBuildToolkitForApi9Compat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to create a new instance of <see cref="ImGuiNET.ImFontPtr"/> on first
|
||||
/// access, for compatibility with API 9.
|
||||
/// </summary>
|
||||
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
|
||||
bool CreateFontOnAccess { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the relevant handles.
|
||||
/// </summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue