Manages font loading, caching, and lookup for text rendering. More...
#include "donner/svg/resources/FontManager.h"
Classes | |
| struct | GlyphOutlineComplexity |
| Validation-time allocation/work bound for one font outline. More... | |
| class | DependencyCapture |
| Record every catalog face consulted in a layout, including memoized and pending faces. The output survives this manager and can be attached to a stable preview/document task. More... | |
Public Member Functions | |
| FontManager (Registry ®istry, size_t maximumLoadedFontBytes=kDefaultMaximumLoadedFontBytes, size_t maximumLoadedFonts=kDefaultMaximumLoadedFonts, size_t maximumFontValidationWork=kDefaultMaximumFontValidationWork) | |
Construct a FontManager tied to the provided ECS registry. | |
| ~FontManager () | |
| Destructor. | |
| FontManager (const FontManager &)=delete | |
| FontManager & | operator= (const FontManager &)=delete |
| FontManager (FontManager &&)=delete | |
| FontManager & | operator= (FontManager &&)=delete |
| DependencyCapture | captureDependencies (std::vector< FontFaceDependency > &output) |
| Begin a scoped capture of font faces consulted during layout preparation. | |
| void | recordDependencies (std::span< const FontFaceDependency > dependencies) |
| Attribute an already-prepared resource to the enclosing dependency capture. | |
| std::vector< FontFaceDependency > | faceDependencies () const |
| Latest bounded consumer states. No provider/store callbacks access the registry. | |
| bool | refreshPendingFonts () |
| Retry pending faces from the normal serialized text/frame preparation path. Returns true when a successful resolution changed fontResourceRevision(), even if asset identity did not. | |
| bool | needsResourceRefresh () const |
| Whether provider state changes need another normal preparation pass. | |
| bool | hasUnresolvedDependencies () const |
| Whether current face dependencies still have unresolved states. | |
| uint64_t | fontResourceRevision () const |
| Revision advanced when a resolved font change invalidates prepared text geometry. | |
| bool | fontDependenciesOverflowed () const |
| Whether bounded dependency collection exceeded its resource limit. | |
| void | addFontFace (const css::FontFace &face) |
| Register a @font-face declaration. | |
| void | setGenericFamilyMapping (std::string_view genericName, std::string_view realFamily) |
| Register a mapping from a CSS generic family name (serif, sans-serif, monospace, cursive, fantasy) to a real font family name registered via addFontFace(). | |
| bool | hasFamily (std::string_view family) const |
Returns whether any registered @font-face rule or the attached provider claims family, after resolving CSS generic names. | |
| FontHandle | findFont (std::string_view family) |
| Find or load a font matching the given family name. | |
| FontHandle | findFont (std::string_view family, int weight) |
| Find or load a font matching the given family name and weight. | |
| FontHandle | findFont (std::string_view family, int weight, int style, int stretch) |
| Find or load a font matching the given family name, weight, style, and stretch. | |
| FontHandle | loadFontData (std::span< const uint8_t > data, FontDataTrust trust=FontDataTrust::Untrusted) |
| Load encoded TTF/OTF/WOFF data (including WOFF2 in full-text builds). | |
| std::span< const uint8_t > | fontData (FontHandle handle) const |
| Get the raw font data bytes for a handle. | |
| std::optional< FontFaceRequest > | providerFaceRequest (FontHandle handle) const |
| Requested catalog face attributes for a loaded provider font, if any. | |
| bool | isGenericSansProviderFont (FontHandle handle) const |
| Whether a loaded provider face is the editor's generic sans-serif family. | |
| bool | isImmutableCatalogFont (FontHandle handle) const |
| Whether a loaded provider face is backed by an immutable catalog asset. | |
| bool | isTrustedFont (FontHandle handle) const |
Returns whether handle was loaded from an explicitly trusted source. | |
| std::optional< GlyphOutlineComplexity > | glyphOutlineComplexity (FontHandle handle, int glyphIndex) const |
| Return a lifetime-safe O(1) pre-decode bound for a validated glyph. | |
| std::optional< std::span< const uint8_t > > | sfntTable (FontHandle handle, std::string_view tag) const |
| Get a table from the cached, validated sfnt directory for a handle. | |
| bool | isValidatedFont (FontHandle handle) const |
Return true when handle has a cached validated sfnt directory. | |
| bool | fontsShareFamily (FontHandle first, FontHandle second) const |
| Compare the actual family names cached from two loaded fonts, independently of CSS aliases. | |
| size_t | loadedFontBytes () const |
| Font-data, cached-index, and family-name storage bytes charged to this registry's budget. | |
| size_t | numLoadedFonts () const |
| Number of loaded font components currently charged to this registry's budget. | |
| size_t | fontValidationWork () const |
| CFF validation work permanently consumed by load attempts in this registry. | |
| size_t | compressedFontDecompressionAttempts () const |
| Compressed-font decompression attempts performed for this registry. | |
| size_t | numFaces () const |
| Get the number of registered @font-face rules. | |
| std::string_view | faceFamilyName (size_t index) const |
| Get the family name of a registered @font-face rule by index. | |
| FontHandle | fallbackFont () |
| Get the handle for the embedded fallback font (Public Sans). | |
| void | setFontProvider (const FontFamilyProvider *provider) |
| Attach an external font provider (typically a FontCatalog) consulted during findFont() for family names not satisfied by a registered @font-face rule, before falling back to the embedded Public Sans font. | |
Static Public Member Functions | |
| static void | SetDefaultFontProvider (const FontFamilyProvider *provider) |
| Set the process-wide default font provider. | |
| static const FontFamilyProvider * | DefaultFontProvider () |
| Returns the current process-wide default font provider (may be nullptr). | |
Static Public Attributes | |
| static constexpr size_t | kDefaultMaximumLoadedFontBytes = 64 * 1024 * 1024 |
| Default aggregate byte budget for font data loaded into one registry. | |
| static constexpr size_t | kDefaultMaximumLoadedFonts = 1024 |
| Default maximum number of font byte streams retained in one registry. | |
| static constexpr size_t | kDefaultMaximumFontValidationWork |
| Default aggregate CFF validation work admitted for one registry. | |
Friends | |
| struct | FontManagerTestAccess |
Manages font loading, caching, and lookup for text rendering.
FontManager is the shared font infrastructure used by both the Skia and TinySkia backends. It handles:
FontManager uses entt entities to store font data, with one entity per registered @font-face rule or directly-loaded font. Text backends can cache parsed backend objects directly on the same entity.
FontManager follows the registry's access discipline rather than providing internal locking. Const queries may run in parallel while the registry is held for reading; loads and other mutations require serialized write access. The registry must outlive every stack-local manager.
| struct donner::svg::FontManager::GlyphOutlineComplexity |
|
explicit |
Construct a FontManager tied to the provided ECS registry.
The first manager to perform a serialized font load for a registry establishes its aggregate byte, item, and untrusted CFF-validation limits. Read-only queries never establish or replace that state. Later manager instances for the same registry share it so loaded components and validation attempts remain accounted across manager lifetimes.
Construction does not access the registry context, so a FontManager can itself be safely constructed by registry.ctx().emplace<FontManager>(registry).
| void donner::svg::FontManager::addFontFace | ( | const css::FontFace & | face | ) |
Register a @font-face declaration.
Sources are resolved lazily on first findFont() call for the corresponding family name.
Registration is idempotent: re-registering a declaration that is byte-for-byte the same rule (same family, weight, style, stretch, and the same ordered source list pointing at the same payloads) reuses the entity minted the first time and leaves the resolution cache intact. Callers that re-announce a document's whole @font-face set on every style recompute therefore keep stable font entities, which keeps every downstream per-font cache (rendered glyph outlines, backend face objects) valid across unrelated document mutations. A rule that differs in any of those fields is a different declaration and mints a new entity, so newly loaded font data is never served from a stale entity.
Family names are compared case-insensitively, matching how findFont() selects a face, so two declarations differing only in the casing of their family name are one declaration here and numFaces() counts them once.
| face | The parsed @font-face rule. |
|
inline |
Begin a scoped capture of font faces consulted during layout preparation.
| output | Caller-owned dependency destination. |
| std::string_view donner::svg::FontManager::faceFamilyName | ( | size_t | index | ) | const |
Get the family name of a registered @font-face rule by index.
| index | Index into the registered faces (0 to numFaces()-1). |
| FontHandle donner::svg::FontManager::findFont | ( | std::string_view | family | ) |
Find or load a font matching the given family name.
Resolution order:
| family | Font family name to look up. |
| FontHandle donner::svg::FontManager::findFont | ( | std::string_view | family, |
| int | weight ) |
Find or load a font matching the given family name and weight.
| family | Font family name to look up. |
| weight | CSS font-weight value (100-900, 400=normal, 700=bold). |
| FontHandle donner::svg::FontManager::findFont | ( | std::string_view | family, |
| int | weight, | ||
| int | style, | ||
| int | stretch ) |
Find or load a font matching the given family name, weight, style, and stretch.
| family | Font family name to look up. |
| weight | CSS font-weight value (100-900, 400=normal, 700=bold). |
| style | CSS font-style value (0=normal, 1=italic, 2=oblique). |
| stretch | CSS font-stretch value (1-9, 5=normal, matching FontStretch enum). |
| std::span< const uint8_t > donner::svg::FontManager::fontData | ( | FontHandle | handle | ) | const |
Get the raw font data bytes for a handle.
This is useful for backends (like Skia) that need to create their own font objects from the raw data.
| handle | A valid FontHandle. |
| bool donner::svg::FontManager::fontsShareFamily | ( | FontHandle | first, |
| FontHandle | second ) const |
Compare the actual family names cached from two loaded fonts, independently of CSS aliases.
Equal valid handles match even without a name; different handles with missing or lossy names do not. This performs no decoding or allocation.
| first | First loaded font. |
| second | Second loaded font. |
| bool donner::svg::FontManager::hasFamily | ( | std::string_view | family | ) | const |
Returns whether any registered @font-face rule or the attached provider claims family, after resolving CSS generic names.
A font-family list must skip entries nothing provides so a later entry can match. findFont() cannot express that, because an unmatched family is answered with the embedded fallback rather than an invalid handle, so callers walking a list test availability here first. This performs no loading and leaves the resolution cache untouched.
Text layout asks this once per family per span, and neither the family-list length nor the registered-rule count is bounded by anything but the document, so registered families are answered from a lowercased index maintained by addFontFace rather than by rescanning the rules. That index is per FontManager instance and covers the rules this instance has seen: it is seeded from the registry at construction and extended on each registration, so a second manager over the same registry that registers its own rules does not update this one's.
Like every other query here this writes nothing, so it is safe to run in parallel under the registry read lock. A family the provider already resolved through findFont is answered from a second index that resolution fills, and anything still unknown falls through to the provider, which is why FontFamilyProvider::hasFamily must answer in constant or logarithmic time.
| family | Font family name to test, before generic-name resolution. |
| FontHandle donner::svg::FontManager::loadFontData | ( | std::span< const uint8_t > | data, |
| FontDataTrust | trust = FontDataTrust::Untrusted ) |
Load encoded TTF/OTF/WOFF data (including WOFF2 in full-text builds).
The data is copied internally. The font is not associated with any family name; callers should use findFont() for name-based lookup.
The default treats the bytes as untrusted. The simple text backend refuses to pass untrusted bytes to stb_truetype because that parser does not accept a buffer length. Use FontDataTrust::Trusted only for application-controlled embedded or local-system fonts.
| data | Encoded font-file bytes supported by this build's text feature tier. |
| trust | Whether the source is trusted enough for length-unaware font backends. |
|
static |
Set the process-wide default font provider.
Every FontManager constructed afterwards adopts it (existing instances are unaffected). The editor installs its FontCatalog here so document render paths that create their own FontManager resolve embedded and system fonts without threading the catalog through every call site.
The provider is borrowed, not owned, and must outlive all FontManagers that adopt it.
|
inline |
Attach an external font provider (typically a FontCatalog) consulted during findFont() for family names not satisfied by a registered @font-face rule, before falling back to the embedded Public Sans font.
The provider is borrowed, not owned, and must outlive this FontManager. Pass nullptr to detach.
Attaching a different provider abandons every font resolved through the previous one, since another provider may answer the same family with different bytes. Those fonts keep their entities and their share of the aggregate budget: handles to them may still be held by text runs and by backend caches keyed on the handle, so their bytes have to stay valid. The budget is released when the entities are destroyed, normally with the registry.
Resolution order for findFont(family):
| void donner::svg::FontManager::setGenericFamilyMapping | ( | std::string_view | genericName, |
| std::string_view | realFamily ) |
Register a mapping from a CSS generic family name (serif, sans-serif, monospace, cursive, fantasy) to a real font family name registered via addFontFace().
This allows findFont("sans-serif") to resolve to the specified family.
| genericName | The CSS generic family name (case-insensitive). |
| realFamily | The real family name to resolve to. |
| std::optional< std::span< const uint8_t > > donner::svg::FontManager::sfntTable | ( | FontHandle | handle, |
| std::string_view | tag ) const |
Get a table from the cached, validated sfnt directory for a handle.
| handle | A valid FontHandle. |
| tag | Four-byte sfnt table tag. |
|
staticconstexpr |
Default aggregate CFF validation work admitted for one registry.