Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
font_resolver.hpp
Go to the documentation of this file.
1// font_resolver.hpp
2//
3// `FontResolver` is the canonical resolution path: one parser, one
4// cascade, one set of fallback semantics. Every text-rendering or text-
5// measurement caller in the SDK (SkiaCanvas, TextShaper, bundled_fonts,
6// sdf_atlas, examples/ui-preview, the JS web-compat layer) talks to
7// this resolver. Legacy split parsers/cascades are kept out of the
8// public paint and measurement paths.
9//
10// The resolver returns a `ResolvedFont` describing not just the chosen
11// typeface but also *how* it was chosen: which scope owned it, which
12// step of the cascade matched, whether faux-synthesis was applied. That
13// trace data feeds the `FontFlightRecorder` and missing-font advice.
14//
15// This header forward-declares `SkTypeface`; the implementation pulls
16// in Skia. Non-GPU translation units can include this header to obtain
17// a `ResolvedFont` value without dragging Skia in — the typeface field
18// is opaque via `ResolvedFont::has_typeface()`.
19
20#pragma once
21
23
24#include <cstdint>
25#include <memory>
26#include <optional>
27#include <string>
28#include <string_view>
29#include <vector>
30
31#ifdef PULP_HAS_SKIA
32#include "include/core/SkFont.h"
33#include "include/core/SkFontTypes.h"
34#include "include/core/SkRefCnt.h"
35class SkTypeface;
36#endif
37
38namespace pulp::canvas {
39
50std::string platform_family_for_css_generic(const std::string& css_family);
51
56void set_css_generic_family_override(const std::string& keyword, const std::string& family);
57
60 std::string name;
61 bool quoted = false;
63};
64
67CssFontFamily parse_css_font_family(std::string_view entry);
68
74std::vector<std::string> split_css_font_family_list(std::string_view list);
75
85bool paragraph_fakes_missing_font_styles(std::string_view css_font_family, int weight, int slant);
86
90std::string platform_family_for_css_family(std::string_view entry);
91
98bool platform_face_is_family(std::string_view platform_family, std::string_view actual_family);
99
100#ifdef PULP_HAS_SKIA
101
102// ── AA / hinting policy ─────────────────────────────────────────────────
103//
104// Pure enum-to-enum translation from the platform-neutral FontOptions modes
105// (HintingMode, AntiAliasMode) to Skia's paint flags (SkFont::Edging,
106// SkFontHinting). Centralised here so every Skia-backed paint path —
107// SkiaCanvas, TextShaper, SDF glyph atlas — pulls the same policy out of
108// the resolver instead of inventing its own mapping. Stateless and
109// branch-free; safe to call from the audio thread (no allocations, no
110// locks, no Skia globals touched).
111//
112// Mapping rules (locked by test_font_aa_hinting):
113// * AntiAliasMode::Default → nullopt (caller keeps the
114// opacity-layer text edging heuristic).
115// * AntiAliasMode::LCD → kSubpixelAntiAlias
116// * AntiAliasMode::Grayscale → kAntiAlias
117// * AntiAliasMode::NoAA → kAlias
118//
119// * HintingMode::PlatformDefault → nullopt (caller preserves the
120// backend/platform default).
121// * HintingMode::None → kNone
122// * HintingMode::Slight → kSlight
123// * HintingMode::Normal → kNormal
124// * HintingMode::Full → kFull
125
126// `AntiAliasMode::Default` follows the caller's opacity-layer text edging
127// heuristic, and `HintingMode::PlatformDefault` preserves the backend's own
128// default. Hard-coding either to a single Skia value erases the per-caller
129// branch.
130//
131// Both helpers now return `std::optional`: `Default` / `PlatformDefault`
132// resolve to `nullopt` ("caller decides"); explicit modes resolve to the
133// fixed Skia enum. The convenience `ResolvedFont::sk_edging()` /
134// `sk_hinting()` accessors below preserve that optional result so
135// callers can keep their own opacity / backend-default branches intact.
136
137constexpr std::optional<SkFont::Edging> sk_edging_for(AntiAliasMode mode) noexcept {
138 switch (mode) {
139 case AntiAliasMode::LCD: return SkFont::Edging::kSubpixelAntiAlias;
140 case AntiAliasMode::Grayscale: return SkFont::Edging::kAntiAlias;
141 case AntiAliasMode::NoAA: return SkFont::Edging::kAlias;
142 case AntiAliasMode::Default: return std::nullopt;
143 }
144 return std::nullopt;
145}
146
147constexpr std::optional<SkFontHinting> sk_hinting_for(HintingMode mode) noexcept {
148 switch (mode) {
149 case HintingMode::None: return SkFontHinting::kNone;
150 case HintingMode::Slight: return SkFontHinting::kSlight;
151 case HintingMode::Normal: return SkFontHinting::kNormal;
152 case HintingMode::Full: return SkFontHinting::kFull;
153 case HintingMode::PlatformDefault: return std::nullopt;
154 }
155 return std::nullopt;
156}
157
158#endif // PULP_HAS_SKIA
159
160// ── Trace types ──────────────────────────────────────────────────────────
161
176
177const char* to_string(FallbackOrigin) noexcept;
178
186
188 bool faux_bold = false;
189 bool faux_italic = false;
190 bool faux_width = false;
191 std::string source_family;
192};
193
194// ── ResolvedFont ─────────────────────────────────────────────────────────
195
212std::string resolved_face_identity(const std::string& css_font_family,
213 float weight,
215
217#ifdef PULP_HAS_SKIA
218 sk_sp<SkTypeface> typeface;
219#endif
220
221 std::string actual_family;
224 std::uint64_t generation = 0;
225
226 std::vector<FallbackTraceStep> trace;
228
234
239
240 bool has_typeface() const noexcept {
241#ifdef PULP_HAS_SKIA
242 return static_cast<bool>(typeface);
243#else
244 return false;
245#endif
246 }
247
248 bool resolved() const noexcept {
250 }
251
252#ifdef PULP_HAS_SKIA
257 std::optional<SkFont::Edging> sk_edging() const noexcept {
258 return sk_edging_for(aa_mode);
259 }
260
264 std::optional<SkFontHinting> sk_hinting() const noexcept {
265 return sk_hinting_for(hinting_mode);
266 }
267#endif
268
280 bool supports_color_font() const noexcept;
281
289 bool color_font_active() const noexcept;
290};
291
292// ── FontResolver ─────────────────────────────────────────────────────────
293
294class FontResolver {
295public:
297 static FontResolver& instance();
298
306
315 const ResolvedFont& primary,
316 std::uint32_t codepoint);
317
322
331 void set_cache_capacity(std::size_t entries);
332 std::size_t cache_capacity() const noexcept;
333
336 std::size_t cache_size() const noexcept;
337
341 struct Impl;
342
343private:
344 FontResolver();
345 ~FontResolver();
346 FontResolver(const FontResolver&) = delete;
347 FontResolver& operator=(const FontResolver&) = delete;
348
349 std::unique_ptr<Impl> impl_;
350};
351
352} // namespace pulp::canvas
void set_cache_capacity(std::size_t entries)
Cap the resolver cache so per-frame axis-instance variation (60fps animation across wght 100→900 = 60...
ResolvedFont resolve_character_fallback(const FontOptions &options, const ResolvedFont &primary, std::uint32_t codepoint)
Character-level fallback.
std::size_t cache_capacity() const noexcept
ResolvedFont resolve_family_list(const FontOptions &options)
Resolve the primary face for a FontOptions blob.
std::size_t cache_size() const noexcept
Current number of cached entries.
void clear_cache()
Test-only: discard the internal cache.
static FontResolver & instance()
Process-wide singleton. Thread-safe.
Definition affine_transform.hpp:24
std::string platform_family_for_css_family(std::string_view entry)
The family name to ask a font matcher for, for one list entry (quotes allowed): the platform family a...
bool platform_face_is_family(std::string_view platform_family, std::string_view actual_family)
Whether a face that reports actual_family is the family a matcher was asked for as platform_family,...
FontSlant
CSS-style slant.
Definition font_options.hpp:37
@ Normal
Definition font_options.hpp:38
std::string resolved_face_identity(const std::string &css_font_family, float weight, FontSlant slant=FontSlant::Normal)
The output of a resolver call.
std::vector< std::string > split_css_font_family_list(std::string_view list)
Split a font-family list on commas into trimmed entries, each KEPT with its quotes,...
ColorFontMode
Color-font policy.
Definition font_options.hpp:95
@ Auto
Definition font_options.hpp:96
std::string platform_family_for_css_generic(const std::string &css_family)
The platform family a CSS generic family keyword stands for, matching the browser's defaults on this ...
bool paragraph_fakes_missing_font_styles(std::string_view css_font_family, int weight, int slant)
Whether SkParagraph may fake the bold or oblique the matched face lacks, for text in css_font_family ...
const char * to_string(FallbackOrigin) noexcept
void set_css_generic_family_override(const std::string &keyword, const std::string &family)
Map the generic keyword to family instead of the platform default, or restore the built-in mapping wh...
FallbackOrigin
Which step of the cascade produced the resolved typeface.
Definition font_resolver.hpp:164
@ NotFound
Nothing matched and synthesis was disabled.
Definition font_resolver.hpp:174
@ Platform
Resolved by SkFontMgr::matchFamilyStyle.
Definition font_resolver.hpp:169
@ ScopePlugin
Resolved inside a Plugin-scoped registration.
Definition font_resolver.hpp:166
@ Bundled
Resolved by match_bundled_typeface (external/fonts).
Definition font_resolver.hpp:168
@ PlatformChar
Resolved by SkFontMgr::matchFamilyStyleCharacter (character-fallback path; only emitted by resolve_ch...
Definition font_resolver.hpp:170
@ ScopeView
Resolved inside a View-scoped registration.
Definition font_resolver.hpp:165
@ ScopeGlobal
Resolved inside the Global scope.
Definition font_resolver.hpp:167
@ Synthetic
No matching face; resolver applied faux-synthesis.
Definition font_resolver.hpp:173
CssFontFamily parse_css_font_family(std::string_view entry)
Parse one font-family list entry: trim whitespace, then strip one matching pair of single or double q...
HintingMode
CSS font-smoothing analogue.
Definition font_options.hpp:72
@ None
Definition font_options.hpp:73
@ PlatformDefault
Definition font_options.hpp:77
@ Slight
Definition font_options.hpp:74
@ Normal
Definition font_options.hpp:75
@ Full
Definition font_options.hpp:76
AntiAliasMode
Default follows the existing inside_non_opaque_layer() heuristic for opacity-layer text edging.
Definition font_options.hpp:84
@ NoAA
Definition font_options.hpp:88
@ Default
Definition font_options.hpp:85
@ Grayscale
Definition font_options.hpp:87
@ LCD
Definition font_options.hpp:86
STL namespace.
One entry of a CSS font-family list, as written.
Definition font_resolver.hpp:59
std::string name
without surrounding whitespace or quotes
Definition font_resolver.hpp:60
bool quoted
written as a string: a family literally named name, never a generic keyword
Definition font_resolver.hpp:61
Definition font_resolver.hpp:179
bool succeeded
Whether this step produced a usable face.
Definition font_resolver.hpp:182
FallbackOrigin origin
Cascade step attempted at this position.
Definition font_resolver.hpp:181
std::string selected_family
Actual family name on the chosen face.
Definition font_resolver.hpp:183
std::string requested_family
Family name as listed in the cascade.
Definition font_resolver.hpp:180
std::string note
Free-text annotation (e.g. "platform default fallback rejected").
Definition font_resolver.hpp:184
The typed, hashable contract that replaces (family_string, size) throughout the font subsystem.
Definition font_options.hpp:190
Opaque identifier for a FontScope (defined in font_scope.hpp).
Definition font_options.hpp:168
Definition font_resolver.hpp:216
bool supports_color_font() const noexcept
Does the resolved typeface carry color-glyph tables?
SynthesisTrace synthesis
Definition font_resolver.hpp:227
bool color_font_active() const noexcept
Composite of color_font_mode + supports_color_font().
HintingMode hinting_mode
Definition font_resolver.hpp:233
ColorFontMode color_font_mode
Color-font mode carried from FontOptions.
Definition font_resolver.hpp:238
bool has_typeface() const noexcept
Definition font_resolver.hpp:240
FontScopeId scope
Definition font_resolver.hpp:223
std::vector< FallbackTraceStep > trace
Definition font_resolver.hpp:226
std::string actual_family
Family name reported by the chosen face.
Definition font_resolver.hpp:221
std::uint64_t generation
merged_generation_for(options.scope) at resolve time.
Definition font_resolver.hpp:224
AntiAliasMode aa_mode
AA/hinting policy carried over from the originating FontOptions.
Definition font_resolver.hpp:232
FallbackOrigin origin
Definition font_resolver.hpp:222
bool resolved() const noexcept
Definition font_resolver.hpp:248
Definition font_resolver.hpp:187
std::string source_family
Family the synthesis was applied to.
Definition font_resolver.hpp:191
bool faux_italic
Definition font_resolver.hpp:189
bool faux_width
Definition font_resolver.hpp:190
bool faux_bold
Definition font_resolver.hpp:188