IFontAtlas API9 compat: support reading GameFontHandle.ImFont during UiBuilder.After/BuildFonts

This commit is contained in:
Soreepeong 2024-01-21 00:15:12 +09:00
parent 11c1b4658b
commit dd5cbdfd5d
8 changed files with 148 additions and 22 deletions

View file

@ -1,6 +1,8 @@
using System.Runtime.InteropServices;
using Dalamud.Interface.ManagedFontAtlas.Internals;
using Dalamud.Interface.Utility;
using Dalamud.Utility;
using ImGuiNET;
@ -11,6 +13,20 @@ namespace Dalamud.Interface.ManagedFontAtlas;
/// </summary>
public interface IFontAtlasBuildToolkit
{
/// <summary>
/// Functionalities for compatibility behavior.<br />
/// </summary>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
internal interface IApi9Compat : IFontAtlasBuildToolkit
{
/// <summary>
/// Invokes <paramref name="action"/>, temporarily applying <see cref="IFontHandleSubstance"/>s.<br />
/// </summary>
/// <param name="action">The action to invoke.</param>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public void FromUiBuilderObsoleteEventHandlers(Action action);
}
/// <summary>
/// Gets or sets the font relevant to the call.
/// </summary>

View file

@ -4,6 +4,7 @@ using System.Linq;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Logging.Internal;
using Dalamud.Utility;
using ImGuiNET;
@ -144,6 +145,14 @@ internal class DelegateFontHandle : IFontHandle.IInternal
/// <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()
{

View file

@ -30,7 +30,7 @@ internal sealed partial class FontAtlasFactory
/// Implementations for <see cref="IFontAtlasBuildToolkitPreBuild"/> and
/// <see cref="IFontAtlasBuildToolkitPostBuild"/>.
/// </summary>
private class BuildToolkit : IFontAtlasBuildToolkitPreBuild, IFontAtlasBuildToolkitPostBuild, IDisposable
private class BuildToolkit : IFontAtlasBuildToolkit.IApi9Compat, IFontAtlasBuildToolkitPreBuild, IFontAtlasBuildToolkitPostBuild, IDisposable
{
private static readonly ushort FontAwesomeIconMin =
(ushort)Enum.GetValues<FontAwesomeIcon>().Where(x => x > 0).Min();
@ -107,6 +107,34 @@ 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 IgnoreGlobalScale(ImFontPtr fontPtr)
{

View file

@ -230,6 +230,14 @@ internal class GamePrebakedFontHandle : IFontHandle.IInternal
/// <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()
{
@ -285,11 +293,27 @@ internal class GamePrebakedFontHandle : IFontHandle.IInternal
}
}
// Use this on API 10.
// /// <inheritdoc/>
// public ImFontPtr GetFontPtr(IFontHandle handle) =>
// handle is GamePrebakedFontHandle ggfh
// ? this.fonts.GetValueOrDefault(ggfh.FontStyle)?.FullRangeFont ?? default
// : default;
/// <inheritdoc/>
public ImFontPtr GetFontPtr(IFontHandle handle) =>
handle is GamePrebakedFontHandle ggfh
? this.fonts.GetValueOrDefault(ggfh.FontStyle)?.FullRangeFont ?? default
: default;
[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);
}
/// <inheritdoc/>
public Exception? GetBuildException(IFontHandle handle) =>

View file

@ -1,4 +1,6 @@
using ImGuiNET;
using Dalamud.Utility;
using ImGuiNET;
namespace Dalamud.Interface.ManagedFontAtlas.Internals;
@ -12,6 +14,19 @@ 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 font.
/// </summary>

View file

@ -104,6 +104,7 @@ public sealed class UiBuilder : IDisposable
/// pointers inside this handler.
/// </summary>
[Obsolete($"Use {nameof(this.FontAtlas)} instead.", false)]
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public event Action? BuildFonts;
/// <summary>
@ -113,6 +114,7 @@ public sealed class UiBuilder : IDisposable
/// pointers inside this handler.
/// </summary>
[Obsolete($"Use {nameof(this.FontAtlas)} instead.", false)]
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public event Action? AfterBuildFonts;
/// <summary>
@ -423,6 +425,7 @@ public sealed class UiBuilder : IDisposable
/// <param name="style">Font to get.</param>
/// <returns>Handle to the game font which may or may not be available for use yet.</returns>
[Obsolete($"Use {nameof(this.FontAtlas)}.{nameof(IFontAtlas.NewGameFontHandle)} instead.", false)]
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public GameFontHandle GetGameFontHandle(GameFontStyle style) => new(
(IFontHandle.IInternal)this.FontAtlas.NewGameFontHandle(style),
Service<FontAtlasFactory>.Get());
@ -620,29 +623,38 @@ public sealed class UiBuilder : IDisposable
this.hitchDetector.Stop();
}
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
private unsafe void PrivateAtlasOnBuildStepChange(IFontAtlasBuildToolkit e)
{
if (e.IsAsyncBuildOperation)
return;
if (this.BuildFonts is not null)
{
e.OnPreBuild(
_ =>
{
var prev = ImGui.GetIO().NativePtr->Fonts;
ImGui.GetIO().NativePtr->Fonts = e.NewImAtlas.NativePtr;
this.BuildFonts?.InvokeSafely();
((IFontAtlasBuildToolkit.IApi9Compat)e)
.FromUiBuilderObsoleteEventHandlers(() => this.BuildFonts?.InvokeSafely());
ImGui.GetIO().NativePtr->Fonts = prev;
});
}
if (this.AfterBuildFonts is not null)
{
e.OnPostBuild(
_ =>
{
var prev = ImGui.GetIO().NativePtr->Fonts;
ImGui.GetIO().NativePtr->Fonts = e.NewImAtlas.NativePtr;
this.AfterBuildFonts?.InvokeSafely();
((IFontAtlasBuildToolkit.IApi9Compat)e)
.FromUiBuilderObsoleteEventHandlers(() => this.AfterBuildFonts?.InvokeSafely());
ImGui.GetIO().NativePtr->Fonts = prev;
});
}
}
private void OnResizeBuffers()
{

View file

@ -1,6 +1,8 @@
using System.Reflection;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using Serilog;
using Serilog.Events;
@ -14,6 +16,7 @@ namespace Dalamud.Logging;
/// move over as soon as reasonably possible for performance reasons.
/// </remarks>
[Obsolete("Static PluginLog will be removed in API 10. Developers should use IPluginLog.")]
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public static class PluginLog
{
#region "Log" prefixed Serilog style methods

View file

@ -0,0 +1,19 @@
namespace Dalamud.Utility;
/// <summary>
/// Utility class for marking something to be changed for API 10, for ease of lookup.
/// </summary>
[AttributeUsage(AttributeTargets.All, Inherited = false)]
internal sealed class Api10ToDoAttribute : Attribute
{
/// <summary>
/// Marks that this exists purely for making API 9 plugins work.
/// </summary>
public const string DeleteCompatBehavior = "Delete. This is for making API 9 plugins work.";
/// <summary>
/// Initializes a new instance of the <see cref="Api10ToDoAttribute"/> class.
/// </summary>
/// <param name="what">The explanation.</param>
public Api10ToDoAttribute(string what) => _ = what;
}