Files
RobustToolbox/Robust.Client/Graphics/SystemFontManager.cs
Pieter-Jan Briers f3a3f564e1 System font API (#5393)
* System font API

This is a new API that allows operating system fonts to be loaded by the engine and used by content.

Fonts are provided in a flat list exposing all the relevant metadata. They are loaded from disk with a Load call.

Initial implementation is only for Windows DirectWrite.

* Load system fonts as memory mapped files if possible.

This allows sharing the font file memory with other processes which is always good.

* Use ArrayPool to reduce char array allocations

* Disable verbose logging

* Implement system font support on Linux via Fontconfig

* Implement macOS support

* Add "FREEDESKTOP" define constant

This is basically LINUX || FREEBSD. Though FreeBSD currently gets detected as LINUX too. Oh well.

* Compile out Fontconfig and CoreText system font backends when not on those platforms

* Don't add Fontconfig package dep on Mac/Windows

* Allow disabling system font support via CVar

Cuz why not.
2025-10-28 22:07:55 +01:00

90 lines
2.8 KiB
C#

using System;
using System.Collections.Generic;
using Robust.Client.Graphics.FontManagement;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Timing;
namespace Robust.Client.Graphics;
/// <summary>
/// Implementation of <see cref="ISystemFontManager"/> that proxies to platform-specific implementations,
/// and adds additional logging.
/// </summary>
internal sealed class SystemFontManager : ISystemFontManagerInternal, IPostInjectInit
{
[Dependency] private readonly IFontManagerInternal _fontManager = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
private ISawmill _sawmill = default!;
private ISystemFontManagerInternal _implementation = default!;
public bool IsSupported => _implementation.IsSupported;
public IEnumerable<ISystemFontFace> SystemFontFaces => _implementation.SystemFontFaces;
public void Initialize()
{
_implementation = GetImplementation();
_sawmill.Verbose($"Using {_implementation.GetType()}");
_sawmill.Debug("Initializing system font manager implementation");
try
{
var sw = RStopwatch.StartNew();
_implementation.Initialize();
_sawmill.Debug($"Done initializing system font manager in {sw.Elapsed}");
}
catch (Exception e)
{
// This is a non-critical engine system that has to parse significant amounts of external data.
// Best to fail gracefully to avoid full startup failures.
_sawmill.Error($"Error while initializing system font manager, resorting to fallback: {e}");
_implementation = new SystemFontManagerFallback();
}
}
public void Shutdown()
{
_sawmill.Verbose("Shutting down system font manager");
try
{
_implementation.Shutdown();
}
catch (Exception e)
{
_sawmill.Error($"Exception shutting down system font manager: {e}");
return;
}
_sawmill.Verbose("Successfully shut down system font manager");
}
private ISystemFontManagerInternal GetImplementation()
{
if (!_cfg.GetCVar(CVars.FontSystem))
return new SystemFontManagerFallback();
#if WINDOWS
return new SystemFontManagerDirectWrite(_logManager, _cfg, _fontManager);
#elif FREEDESKTOP
return new SystemFontManagerFontconfig(_logManager, _fontManager);
#elif MACOS
return new SystemFontManagerCoreText(_logManager, _fontManager);
#else
return new SystemFontManagerFallback();
#endif
}
void IPostInjectInit.PostInject()
{
_sawmill = _logManager.GetSawmill("font.system");
// _sawmill.Level = LogLevel.Verbose;
}
}