Agent I-4c: embedded @font-face glyph mode (a second self-contained renderer)

A render mode that references each glyph by its SMuFL codepoint via `<text>`,
drawn from an `@font-face`-embedded Bravura subset, alongside the default inline
`<path>` outlines. The SVG stays self-contained (the font travels in it) and the
text is selectable, at a larger file size.

  - GlyphMode::EmbeddedFont: the SVG declares the font once via
    <defs><style>@font-face{...}</style></defs>, then emits one
    <text transform="translate(x y) scale(1 -1)" font-size="4" ...>&#xNNNN;</text>
    per glyph. Geometry is consistent with PathOutline by construction: same
    origin, a per-glyph counter-flip cancels the outer y-flip, and the SMuFL em is
    four staff spaces. A new `text_count` stat; unbundled glyphs still fall through
    to the visible bbox rect + diagnostic. The metadata comment declares which mode
    produced the SVG (and, on the empty canvas too, via a shared `glyph_note`).
    Path mode stays the byte-golden-locked, pixel-verified reference; the embedded
    mode is structurally tested (well-formed XML — also under `xmllint`; one
    @font-face; one <text>/codepoint per glyph; provenance preserved; determinism).

  - The subset is a GENERATED artifact, not a vendored binary: a deterministic
    base64 OTF emitted into src/font_subset_generated.rs by
    `tools/extract_bravura_outlines.py --font-out` (the same SHA-pinned 1.392 font
    the outlines come from). `recalcTimestamp=False` keeps the source font's fixed
    head.modified so the bytes are reproducible across runs, not just within one.

  - OFL compliance: the subset is a Modified Version, so its PRIMARY font name is
    renamed off the Reserved Font Name "Bravura" to "EpiphanyBravuraSubset" in BOTH
    naming structures an OTF carries — the SFNT `name` table AND the CFF (Name INDEX
    + top-dict FullName/FamilyName). The copyright/trademark/license records, which
    name Bravura as attribution, are kept; the renderer references the renamed
    family in @font-face and <text>. The generator reparses the saved bytes and
    fails if the reserved name leaks into a primary record, and validates the cmap
    covers every glyph.

  - Machine-locked payload: the generator emits the decoded length and a BLAKE3-256
    (the workspace's sole hash) of the font bytes; a render-svg test base64-decodes
    the payload (no new runtime dep) and asserts the length, the OTTO signature, the
    BLAKE3, and — parsing the SFNT name table and CFF Name INDEX — that neither
    primary name is the reserved name. Adds an epiphany-determinism dev-dep.

The demo example gains `--glyph-mode=path|embedded`; lib/README/DECISIONS document
the two modes, the subset's OFL rename, and the regeneration command (--font-out +
the blake3 dependency). PathOutline goldens are byte-unchanged; the outlines stay
byte-identical. Full gate green: build, fmt, clippy, 585 tests, conformance scale 1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Levi Neuwirth 2026-06-27 11:09:34 -04:00
parent 41cd8bf58b
commit 6293734fa0
14 changed files with 603 additions and 104 deletions

1
Cargo.lock generated
View File

@ -125,6 +125,7 @@ name = "epiphany-render-svg"
version = "0.0.0"
dependencies = [
"epiphany-core",
"epiphany-determinism",
"epiphany-engrave",
"epiphany-layout-ir",
"epiphany-testkit",

View File

@ -5,7 +5,7 @@ edition.workspace = true
rust-version.workspace = true
authors.workspace = true
repository.workspace = true
description = "Agent I's SVG renderer behind the Epiphany RenderIR interface (spec Chapter 7): turns a ResolvedLayoutIR into well-formed SVG 1.1, drawing each glyph as a genuine Bravura SMuFL outline <path>. A renderer, not an engraver — it makes SVG-encoding choices only, never engraving-semantic ones."
description = "Agent I's SVG renderer behind the Epiphany RenderIR interface (spec Chapter 7): turns a ResolvedLayoutIR into well-formed SVG 1.1 using genuine Bravura SMuFL path outlines or an embedded-font text mode. A renderer, not an engraver — it makes SVG-encoding choices only, never engraving-semantic ones."
[dependencies]
# The renderer consumes the Chapter 7 ResolvedLayoutIR / RenderIR and the glyph
@ -21,3 +21,5 @@ epiphany-engrave.workspace = true
# their input from.
epiphany-testkit.workspace = true
epiphany-core.workspace = true
# BLAKE3 (the workspace's sole hash) for the embedded-font content-integrity test.
epiphany-determinism.workspace = true

View File

@ -1,23 +1,21 @@
# epiphany-render-svg — decisions and Pass 12 candidates
This file records (a) the Phase-2 QUICKSTART decisions Agent I made for the
renderer, and (b) ambiguities batched as **Pass 12 candidates**
(`spec/PASS12_BATCH.md`) rather than improvised in code.
This file records (a) the QUICKSTART decisions Agent I made for the renderer,
and (b) ambiguities batched as **Pass 12 candidates** (`spec/PASS12_BATCH.md`)
rather than improvised in code.
## Scope and phase status
## Scope and status
`epiphany-render-svg` is one renderer behind the Chapter 7 `RenderIR` interface:
it turns a `ResolvedLayoutIR` into well-formed **SVG 1.1**, drawing each glyph as
a genuine Bravura SMuFL outline `<path>`. Per the QUICKSTART development pattern
it is built and **golden-locked against the stub solver's output first**, before
the real engraving solver and the score→real-notation engraving pass land. The
stub returns the constrained IR's geometry verbatim — a structural projection,
not yet real notation (each layout object becomes one arbitrary glyph in a row) —
so this phase proves the renderer is *correct and faithful* (genuine outlines,
provenance preserved, output XML-valid and deterministic), independent of
engraving quality. The renderer already consumes any solver's `ResolvedLayoutIR`,
so when the real `epiphany-engrave` solver lands, the visible result improves with
no renderer change (the demo binary's `--solver=stub|real` flag exercises both).
`epiphany-render-svg` is the SVG renderer behind the Chapter 7 `RenderIR`
interface: it turns a `ResolvedLayoutIR` into well-formed **SVG 1.1**, drawing
glyphs from genuine Bravura SMuFL data either as inline outline `<path>`s
(`GlyphMode::PathOutline`) or as `<text>` set in an embedded subset font
(`GlyphMode::EmbeddedFont`). Per the QUICKSTART development pattern it was
golden-locked against the stub solver's output first, then against the real
`epiphany-engrave` solver once the score→real-notation pass and re-spacing
landed. The renderer consumes any solver's `ResolvedLayoutIR`; it proves
renderer faithfulness — resolved geometry preserved, provenance traced,
output XML-valid and deterministic — independent of engraving quality.
## The non-overreach rule (Chapter 7 / QUICKSTART, Agent I)
@ -46,13 +44,25 @@ glyph and one provenance trace per drawn element.
### Local decisions
- **Glyph rendering — inline genuine Bravura outline `<path>`s
(`GlyphMode::PathOutline`), the default and only mode this phase.** The
QUICKSTART's recommendation: path outlines make the SVG self-contained (it
renders in any browser, image tool, or print pipeline with no font installed),
at the cost of file size. An embedded-`@font-face` mode is a documented future
option, intentionally **not stubbed** so the interface does not lie about a
capability that is absent.
- **Glyph rendering — two self-contained modes; inline outlines
(`GlyphMode::PathOutline`) is the default and the verified reference.** Path
outlines make the SVG self-contained (it renders in any browser, image tool, or
print pipeline with no font installed) and are byte-golden-locked, at the cost of
file size — the QUICKSTART's recommendation. `GlyphMode::EmbeddedFont` instead
references each glyph by SMuFL codepoint with a `<text>` element drawn from an
`@font-face`-embedded Bravura *subset* (only the ~33 named glyphs), so the SVG is
still self-contained (the font travels in it) and the text is selectable, at a
larger file size. The two modes anchor glyphs at the same origin (em = 4 staff
spaces), so placement is consistent by construction; the embedded mode is
structurally tested rather than byte-golden-locked, and exact rasterisation is
the consumer's font renderer's, so path mode remains the pixel-verified one.
- **Embedded-font subset — generated, not a vendored binary.** The subset is a
deterministic base64 OTF emitted into `src/font_subset_generated.rs` by
`tools/extract_bravura_outlines.py --font-out`, keeping the "only generated
artifacts committed" rule (no font binary is vendored). It retains the font's
OFL copyright/license name records (belt-and-suspenders with `tools/OFL.txt`).
Caveat: unlike the geometry-only outlines, the binary subset's exact bytes
depend on the fontTools version, which the generated header records.
- **Outline source — the official OFL `Bravura.otf`, extracted reproducibly.**
`tools/extract_bravura_outlines.py` fetches the font + SMuFL `glyphnames.json`
and emits `src/outlines_generated.rs`. The font is **not vendored**; only the
@ -82,12 +92,12 @@ glyph and one provenance trace per drawn element.
See `spec/PASS12_BATCH.md` (rows P12-I1, P12-I2, P12-I3). Most relevant here:
- **P12-I1** — the constrained IR is a structural placeholder, so the rendered
stub output is *not yet recognizable notation*. The QUICKSTART's human-review
visual-acceptance gate ("the SVG visually parses as standard music notation")
is therefore a **next-phase** gate, met once real engraving lands; this phase's
gate is renderer correctness/faithfulness. Recorded so the visual gate is not
mistaken for already-met.
- **P12-I1 (resolved by I-1/I-3)** — the original stub-only renderer output was
a structural placeholder, so the human-review visual-acceptance gate ("the SVG
visually parses as standard music notation") was deferred until real engraving
landed. The real notation pass and real-Engraver goldens now close that gate;
the stub path remains locked as an interface/reference mode, not the visual
deliverable.
- **P12-I2** — stable layout-object id derivation (`MUSCLOID`, Pass-11 item 2.6,
deferred to Agent I) is still unwired: the determinism crate exposes no
`MUSCLOID` tag and is frozen. The renderer traces provenance by the existing

View File

@ -2,19 +2,22 @@
Agent I's **SVG renderer** behind the Epiphany `RenderIR` interface (spec
Chapter 7): turns a `ResolvedLayoutIR` into well-formed **SVG 1.1**, drawing each
glyph as a **genuine Bravura SMuFL outline** `<path>`. It is the visible end of
the v0 `Score → layout IR` pipeline.
glyph from **genuine Bravura SMuFL** data — inline outline `<path>`s by default
(`GlyphMode::PathOutline`), or `<text>` set in an `@font-face`-embedded Bravura
subset (`GlyphMode::EmbeddedFont`). It is the visible end of the v0
`Score → layout IR` pipeline.
## Status: renderer against the stub solver
## Status
This phase builds and golden-locks the renderer against the **stub solver's**
output (the QUICKSTART development pattern), before the real engraving solver and
the score→real-notation engraving pass land. The stub returns the IR geometry
verbatim — a structural projection (each object becomes one arbitrary glyph in a
row), not yet recognizable notation — so what is proven here is **renderer
correctness and faithfulness**: real outlines, provenance preserved, output
XML-valid and deterministic. The renderer consumes any solver's output, so the
picture improves with no renderer change once `epiphany-engrave` lands.
The `Score → layout IR → SVG` pipeline renders **recognizable notation** — clefs,
noteheads at clef-relative staff positions, accidentals, key/time signatures,
rests, barlines, and the staff lines and stems that connect them. Output is
golden-locked against **both** the interface-only stub solver and Agent I's real
`epiphany-engrave` solver (whose horizontal spacing pass re-spaces the glyphs),
and the layout round-trip (criterion 6) runs through both. What the renderer
itself guarantees, independent of engraving quality: real Bravura glyphs,
provenance preserved to the score graph, output XML-valid and deterministic. The
renderer consumes any solver's `ResolvedLayoutIR`.
## Demo
@ -26,6 +29,10 @@ cargo run -p epiphany-render-svg --example render_fixture -- \
# Drive Agent I's engrave solver instead, to bisect renderer-vs-solver:
cargo run -p epiphany-render-svg --example render_fixture -- \
ten_measure_single_staff --solver=real > out.svg
# Use the embedded-font glyph mode (<text> + @font-face) instead of inline paths:
cargo run -p epiphany-render-svg --example render_fixture -- \
ten_measure_single_staff --glyph-mode=embedded > out.svg
```
Fixtures: `ten_measure_single_staff`, `valid_score_rich`, `valid_score`. Stats and
@ -42,19 +49,29 @@ println!("{}", out.svg);
```
`render` is pure and deterministic. `RenderOptions` controls SVG-encoding choices
only (display scale, margin, provenance attributes) — nothing that changes
engraving.
only (display scale, margin, provenance attributes, and `glyph_mode` — inline
`PathOutline` vs `EmbeddedFont`) — nothing that changes engraving.
## Bundled outlines
## Bundled Bravura data
The glyph outlines in `src/outlines_generated.rs` are extracted from the official
OFL `Bravura.otf` by `tools/extract_bravura_outlines.py`. The font is not
vendored; only the generated Rust is committed. Bravura is © Steinberg Media
Technologies GmbH under the SIL Open Font License 1.1 (`tools/OFL.txt`); the
extracted outlines are redistributed under the same license. To regenerate:
Two generated artifacts come from the official OFL `Bravura.otf` via
`tools/extract_bravura_outlines.py` — the font is **not vendored**, only the
generated Rust is committed:
- `src/outlines_generated.rs` — the inline glyph outlines (geometry-only, so
byte-stable across fontTools versions);
- `src/font_subset_generated.rs` — a base64 OTF **subset** (just the pipeline's
glyphs) for `GlyphMode::EmbeddedFont`. As a Modified Version, its primary font
name is renamed off the Reserved Font Name "Bravura" per the OFL; a content
BLAKE3 + decoded length are committed alongside as an integrity lock.
Bravura is © Steinberg Media Technologies GmbH under the SIL Open Font License 1.1
(`tools/OFL.txt`); both artifacts are redistributed under the same license. To
regenerate both (the subset step also needs the `blake3` package):
```sh
cd crates/epiphany-render-svg/tools
python3 -m venv .venv && . .venv/bin/activate && pip install fonttools
python3 extract_bravura_outlines.py > ../src/outlines_generated.rs
python3 -m venv .venv && . .venv/bin/activate && pip install fonttools blake3
python3 extract_bravura_outlines.py --font-out ../src/font_subset_generated.rs \
> ../src/outlines_generated.rs
```

View File

@ -10,20 +10,22 @@
//!
//! ```text
//! cargo run -p epiphany-render-svg --example render_fixture -- \
//! ten_measure_single_staff [--solver=stub|real] [--seed=N] [--no-provenance] \
//! > out.svg
//! ten_measure_single_staff [--solver=stub|real] [--seed=N] \
//! [--glyph-mode=path|embedded] [--no-provenance] > out.svg
//! ```
//!
//! The `--solver` flag selects the interface-only stub (`stub`, the default this
//! phase) or Agent I's engrave solver (`real`); keeping the renderer working
//! against both is how a renderer-vs-solver bug is bisected with a one-flag
//! change (QUICKSTART, Agent I, "Development pattern").
//! change (QUICKSTART, Agent I, "Development pattern"). The `--glyph-mode` flag
//! selects inline outline `<path>`s (`path`, default) or the embedded-font
//! `<text>` mode (`embedded`).
use std::process::ExitCode;
use epiphany_engrave::Engraver;
use epiphany_layout_ir::{to_constrained, to_logical, ConstraintSolver, SolverConfig, StubSolver};
use epiphany_render_svg::{render, RenderOptions};
use epiphany_render_svg::{render, GlyphMode, RenderOptions};
const FIXTURES: &str = "ten_measure_single_staff, valid_score_rich, valid_score";
const SOLVERS: &str = "stub, real";
@ -33,6 +35,7 @@ fn main() -> ExitCode {
let mut solver = String::from("stub");
let mut seed: u64 = 0x000A_11CE;
let mut emit_provenance = true;
let mut glyph_mode = GlyphMode::PathOutline;
for arg in std::env::args().skip(1) {
if let Some(v) = arg.strip_prefix("--solver=") {
@ -42,6 +45,16 @@ fn main() -> ExitCode {
Ok(n) => seed = n,
Err(_) => return fail(&format!("invalid --seed value: {v}")),
}
} else if let Some(v) = arg.strip_prefix("--glyph-mode=") {
glyph_mode = match v {
"path" => GlyphMode::PathOutline,
"embedded" => GlyphMode::EmbeddedFont,
other => {
return fail(&format!(
"unknown --glyph-mode {other:?}; known: path, embedded"
))
}
};
} else if arg == "--no-provenance" {
emit_provenance = false;
} else if arg == "--help" || arg == "-h" {
@ -80,6 +93,7 @@ fn main() -> ExitCode {
&report.layout,
&RenderOptions {
emit_provenance,
glyph_mode,
..RenderOptions::default()
},
);
@ -89,9 +103,10 @@ fn main() -> ExitCode {
report.status
);
eprintln!(
"glyphs={} paths={} fallback_rects={} provenance={} layers={} hard_constraints={} well_formed={}",
"glyphs={} paths={} texts={} fallback_rects={} provenance={} layers={} hard_constraints={} well_formed={}",
out.stats.glyph_count,
out.stats.path_count,
out.stats.text_count,
out.stats.fallback_rect_count,
out.stats.provenance_count,
out.stats.layer_count,
@ -108,9 +123,11 @@ fn main() -> ExitCode {
fn usage() {
eprintln!(
"usage: render_fixture <fixture> [--solver=stub|real] [--seed=N] [--no-provenance]\n\
"usage: render_fixture <fixture> [--solver=stub|real] [--seed=N] \
[--glyph-mode=path|embedded] [--no-provenance]\n\
fixtures: {FIXTURES}\n\
solvers: {SOLVERS} (default: stub)"
solvers: {SOLVERS} (default: stub)\n\
glyph-mode: path, embedded (default: path)"
);
}

File diff suppressed because one or more lines are too long

View File

@ -4,22 +4,20 @@
//! Agent I's **SVG renderer** behind the Epiphany `RenderIR` interface (spec
//! **Chapter 7** §"RenderIR"): it turns a
//! [`ResolvedLayoutIR`](epiphany_layout_ir::ResolvedLayoutIR) into well-formed
//! **SVG 1.1**, drawing each glyph as a **genuine Bravura SMuFL outline**
//! `<path>`. It is the visible end of the v0 `Score → layout IR` pipeline: from a
//! **SVG 1.1**, drawing each glyph from **genuine Bravura SMuFL** data: inline
//! outline `<path>`s by default, or `<text>` set in an `@font-face`-embedded
//! subset. It is the visible end of the v0 `Score → layout IR` pipeline: from a
//! resolved layout, produce an image a musician would recognise.
//!
//! ## Scope of this phase (renderer-against-stub)
//! ## Scope and status
//!
//! Per the QUICKSTART development pattern (`spec/PHASE2_QUICKSTART.md`, Agent I),
//! the renderer is built and golden-locked against the **stub solver's** output
//! first, before the real engraving solver lands. The stub returns the
//! constrained IR's geometry verbatim — a structural projection, not yet real
//! notation — so this phase proves the renderer is *correct and faithful* (every
//! glyph drawn from its real Bravura outline, provenance preserved, output
//! XML-valid and deterministic), independently of engraving quality. The real
//! [`epiphany_engrave`](../epiphany_engrave/index.html) solver and the
//! score→real-notation engraving pass are the next phase; the renderer already
//! consumes any solver's `ResolvedLayoutIR`.
//! the renderer was golden-locked against the **stub solver's** output first, then
//! against the real [`epiphany_engrave`](../epiphany_engrave/index.html) solver
//! once real notation and re-spacing landed. The renderer consumes any solver's
//! [`ResolvedLayoutIR`](epiphany_layout_ir::ResolvedLayoutIR): it preserves the
//! resolved geometry, provenance traces, XML validity, deterministic output, and
//! glyph-mode choice without making engraving-semantic decisions.
//!
//! ## What it draws, and the non-overreach rule
//!
@ -31,12 +29,20 @@
//!
//! ## Font availability
//!
//! The default and only mode this phase is [`GlyphMode::PathOutline`] — inline
//! outlines, so the SVG is self-contained and needs no font installed
//! (QUICKSTART, Agent I, recommendation). An embedded-`@font-face` mode is a
//! future option; it is intentionally not implemented yet rather than stubbed
//! dishonestly.
//! Two self-contained modes ([`GlyphMode`]):
//!
//! * [`GlyphMode::PathOutline`] (default) inlines genuine Bravura outlines as
//! `<path>`s — no font dependency, byte-golden-locked, the pixel-verified
//! reference (QUICKSTART, Agent I, recommendation).
//! * [`GlyphMode::EmbeddedFont`] references glyphs by SMuFL codepoint via a
//! `<text>` element and an `@font-face`-embedded Bravura *subset* (the same
//! SHA-pinned font the outlines come from, base64 in `font_subset_generated`,
//! regenerated by `tools/extract_bravura_outlines.py --font-out`). Still
//! self-contained — the font travels in the SVG — and text-selectable, at the
//! cost of a larger file; glyph placement is consistent with the path mode by
//! construction, while exact rasterisation is the consumer's font renderer's.
mod font_subset_generated;
mod outline;
mod outlines_generated;
mod svg;

View File

@ -16,8 +16,8 @@ pub fn bundled_glyph_count() -> usize {
BRAVURA_OUTLINES.len()
}
/// The SMuFL codepoint of a bundled glyph name, if bundled. Useful for a future
/// embedded-font rendering mode (which references glyphs by codepoint) and for
/// The SMuFL codepoint of a bundled glyph name, if bundled. Used by the
/// embedded-font render mode (which references glyphs by codepoint) and for
/// debugging glyph identity.
pub fn smufl_codepoint(name: &str) -> Option<u32> {
outline(name).map(|o| o.codepoint)
@ -74,6 +74,151 @@ mod tests {
}
}
/// A minimal RFC-4648 base64 decoder for the integrity test (the crate has no
/// base64 dependency); skips non-alphabet bytes, stops at padding.
fn decode_base64(s: &str) -> Vec<u8> {
fn val(c: u8) -> Option<u8> {
match c {
b'A'..=b'Z' => Some(c - b'A'),
b'a'..=b'z' => Some(c - b'a' + 26),
b'0'..=b'9' => Some(c - b'0' + 52),
b'+' => Some(62),
b'/' => Some(63),
_ => None,
}
}
let mut out = Vec::new();
let (mut buf, mut bits) = (0u32, 0u32);
for &c in s.as_bytes() {
if c == b'=' {
break;
}
let Some(v) = val(c) else { continue };
buf = (buf << 6) | u32::from(v);
bits += 6;
if bits >= 8 {
bits -= 8;
out.push((buf >> bits) as u8);
}
}
out
}
#[test]
fn embedded_font_payload_is_a_locked_valid_otf() {
use crate::font_subset_generated::{
BRAVURA_SUBSET_BLAKE3, BRAVURA_SUBSET_LEN, BRAVURA_SUBSET_OTF_BASE64,
};
let bytes = decode_base64(BRAVURA_SUBSET_OTF_BASE64);
// Length + signature: a truncated or non-OTF payload fails here, not later
// in a consumer's font engine.
assert_eq!(
bytes.len(),
BRAVURA_SUBSET_LEN,
"embedded font length changed; regenerate font_subset_generated.rs"
);
assert_eq!(
&bytes[..4],
b"OTTO",
"embedded font is not a CFF OpenType (OTTO) font"
);
// Content lock: any byte-level corruption flips the BLAKE3 (the workspace's
// sole hash), even one that preserves the length.
let digest = epiphany_determinism::blake3_256(&bytes);
let hex: String = digest.iter().map(|b| format!("{b:02x}")).collect();
assert_eq!(
hex, BRAVURA_SUBSET_BLAKE3,
"embedded font content hash changed; regenerate font_subset_generated.rs"
);
}
/// Reads an sfnt table slice by 4-byte tag from a decoded OTF.
fn sfnt_table<'a>(font: &'a [u8], tag: &[u8; 4]) -> Option<&'a [u8]> {
let num_tables = u16::from_be_bytes(font.get(4..6)?.try_into().ok()?) as usize;
for i in 0..num_tables {
let rec = 12 + i * 16; // after the 12-byte sfnt header
if font.get(rec..rec + 4)? == tag {
let off =
u32::from_be_bytes(font.get(rec + 8..rec + 12)?.try_into().ok()?) as usize;
let len =
u32::from_be_bytes(font.get(rec + 12..rec + 16)?.try_into().ok()?) as usize;
return font.get(off..off + len);
}
}
None
}
/// The SFNT `name` table's family record (nameID 1), decoded from the first
/// record carrying it (UTF-16BE for Windows/Unicode platforms, Latin-1 for Mac).
fn sfnt_family_name(name_table: &[u8]) -> Option<String> {
let count = u16::from_be_bytes(name_table.get(2..4)?.try_into().ok()?) as usize;
let storage = u16::from_be_bytes(name_table.get(4..6)?.try_into().ok()?) as usize;
for i in 0..count {
let r = 6 + i * 12;
let platform = u16::from_be_bytes(name_table.get(r..r + 2)?.try_into().ok()?);
let name_id = u16::from_be_bytes(name_table.get(r + 6..r + 8)?.try_into().ok()?);
if name_id != 1 {
continue;
}
let len = u16::from_be_bytes(name_table.get(r + 8..r + 10)?.try_into().ok()?) as usize;
let off = u16::from_be_bytes(name_table.get(r + 10..r + 12)?.try_into().ok()?) as usize;
let raw = name_table.get(storage + off..storage + off + len)?;
return Some(if platform == 1 {
raw.iter().map(|&b| b as char).collect()
} else {
raw.chunks_exact(2)
.filter_map(|p| char::from_u32(u32::from(u16::from_be_bytes([p[0], p[1]]))))
.collect()
});
}
None
}
/// The CFF table's font name — the first entry of its Name INDEX (whose offsets
/// are 1-based from the byte preceding the object data).
fn cff_font_name(cff: &[u8]) -> Option<String> {
let hdr_size = *cff.get(2)? as usize; // CFF header: major, minor, hdrSize, offSize
let count = u16::from_be_bytes(cff.get(hdr_size..hdr_size + 2)?.try_into().ok()?) as usize;
if count == 0 {
return None;
}
let off_size = usize::from(*cff.get(hdr_size + 2)?);
let off_base = hdr_size + 3;
let read = |i: usize| -> Option<usize> {
let s = off_base + i * off_size;
let mut v = 0usize;
for k in 0..off_size {
v = (v << 8) | usize::from(*cff.get(s + k)?);
}
Some(v)
};
let data_base = off_base + (count + 1) * off_size - 1;
let s = cff.get(data_base + read(0)?..data_base + read(1)?)?;
Some(String::from_utf8_lossy(s).into_owned())
}
#[test]
fn embedded_font_presents_no_reserved_primary_name() {
use crate::font_subset_generated::BRAVURA_SUBSET_OTF_BASE64;
let bytes = decode_base64(BRAVURA_SUBSET_OTF_BASE64);
// An OTF carries two naming structures; the OFL restricts the *primary name*
// of a Modified Version, so both must be the non-reserved subset family, never
// the bare Reserved Font Name "Bravura". (Attribution records may, and do,
// still name Bravura — those are not the primary name.)
let name_tbl = sfnt_table(&bytes, b"name").expect("name table present");
assert_eq!(
sfnt_family_name(name_tbl).as_deref(),
Some("EpiphanyBravuraSubset"),
"SFNT family name (nameID 1) must be the non-reserved subset family"
);
let cff = sfnt_table(&bytes, b"CFF ").expect("CFF table present");
assert_eq!(
cff_font_name(cff).as_deref(),
Some("EpiphanyBravuraSubset"),
"CFF Name INDEX must be the non-reserved subset family"
);
}
#[test]
fn outlines_have_finite_bounds_and_nonempty_paths() {
for o in BRAVURA_OUTLINES {

View File

@ -41,7 +41,10 @@ use std::fmt::Write as _;
use epiphany_layout_ir::{BoundingBox, Provenance, ResolvedGlyph, ResolvedLayoutIR, Transform2D};
use crate::outline::outline;
use crate::font_subset_generated::{
BRAVURA_SUBSET_FAMILY, BRAVURA_SUBSET_MIME, BRAVURA_SUBSET_OTF_BASE64,
};
use crate::outline::{outline, smufl_codepoint};
use crate::xml::{check_well_formed, escape_attr};
/// How glyphs are drawn.
@ -50,9 +53,18 @@ pub enum GlyphMode {
/// Inline genuine Bravura outline `<path>`s (default). Self-contained: the
/// SVG renders in any viewer with no font dependency (QUICKSTART, Agent I:
/// "inline path outlines for golden fixtures and the demonstrable
/// deliverable").
/// deliverable"). This is the byte-golden-locked, pixel-verified reference
/// mode.
#[default]
PathOutline,
/// Reference each glyph by its SMuFL codepoint with a `<text>` element, drawn
/// from an `@font-face`-embedded subset of Bravura (the same SHA-pinned font
/// the outlines come from, base64 in `font_subset_generated`). The result is
/// self-contained — the font travels in the SVG — and text-selectable, at the
/// cost of a larger file. Glyph placement is consistent with
/// [`GlyphMode::PathOutline`] by construction (same origin, em = 4 staff
/// spaces); exact glyph rasterisation is then the consumer's font renderer's.
EmbeddedFont,
}
/// Renderer configuration. SVG-encoding choices only — nothing here changes
@ -157,8 +169,12 @@ pub struct Diagnostic {
pub struct RenderStats {
/// Glyphs in the resolved layout (the renderer's input objects).
pub glyph_count: usize,
/// `<path>` elements emitted (glyphs drawn from a bundled outline).
/// `<path>` elements emitted (glyphs drawn from a bundled outline, the
/// default [`GlyphMode::PathOutline`]).
pub path_count: usize,
/// `<text>` elements emitted (glyphs set in the embedded font, the
/// [`GlyphMode::EmbeddedFont`] mode). Zero in the default path mode.
pub text_count: usize,
/// Fallback `<rect>` elements emitted (glyphs with no bundled outline).
pub fallback_rect_count: usize,
/// `<line>` elements emitted (one per resolved stroke: staff line, stem, …).
@ -209,13 +225,14 @@ pub fn render(resolved: &ResolvedLayoutIR, options: &RenderOptions) -> RenderOut
Some(b) => b,
// Empty layout: a minimal, valid, honest empty canvas.
None => {
let svg = empty_svg(options.emit_provenance);
let svg = empty_svg(options.glyph_mode, options.emit_provenance);
let well_formed = check_well_formed(&svg).is_ok();
debug_assert!(well_formed);
return RenderOutput {
stats: RenderStats {
glyph_count: 0,
path_count: 0,
text_count: 0,
fallback_rect_count: 0,
stroke_count: 0,
provenance_count: 0,
@ -248,6 +265,7 @@ pub fn render(resolved: &ResolvedLayoutIR, options: &RenderOptions) -> RenderOut
.collect();
let mut path_count = 0;
let mut text_count = 0;
let mut fallback_rect_count = 0;
let mut stroke_count = 0;
let mut provenance_count = 0;
@ -263,15 +281,26 @@ pub fn render(resolved: &ResolvedLayoutIR, options: &RenderOptions) -> RenderOut
num(height),
);
// Declared metadata wrapper (a comment — honest about what this is, including
// whether provenance traces are present: suppressing them is an explicit
// display-only choice the output announces rather than dropping silently).
// how glyphs are drawn and whether provenance traces are present: suppressing
// them is an explicit display-only choice the output announces, not drops).
let _ = writeln!(
s,
" <!-- epiphany-render-svg: glyphs are genuine Bravura SMuFL outlines; \
geometry is the resolved layout verbatim, no engraving performed here; \
{} -->",
" <!-- epiphany-render-svg: {}; geometry is the resolved layout \
verbatim, no engraving performed here; {} -->",
glyph_note(options.glyph_mode),
provenance_note(options.emit_provenance),
);
// In embedded-font mode, declare the Bravura subset once via `@font-face`; the
// `<text>` glyphs below reference it by its (non-reserved) family name (see the
// font subset's own header for its provenance and the OFL terms it carries).
if options.glyph_mode == GlyphMode::EmbeddedFont {
let _ = writeln!(
s,
" <defs><style>@font-face {{ font-family: \"{}\"; \
src: url(\"data:{};base64,{}\") format(\"opentype\"); }}</style></defs>",
BRAVURA_SUBSET_FAMILY, BRAVURA_SUBSET_MIME, BRAVURA_SUBSET_OTF_BASE64,
);
}
// The single y-flip wrapper: staff-space/y-up world -> SVG y-down.
let _ = writeln!(
s,
@ -338,21 +367,42 @@ pub fn render(resolved: &ResolvedLayoutIR, options: &RenderOptions) -> RenderOut
} else {
String::new()
};
match outline(name) {
Some(o) => {
// The drawn element depends on the mode: an inline outline `<path>`
// (the self-contained default) or a `<text>` referencing the embedded
// Bravura by SMuFL codepoint. Both anchor at the same `(x, y)` origin,
// so the two modes are geometrically consistent. `None` (no bundled
// outline / no codepoint) falls through to the visible bbox rect.
let element = match options.glyph_mode {
GlyphMode::PathOutline => outline(name).map(|o| {
path_count += 1;
let _ = writeln!(
s,
" <path d=\"{}\" transform=\"{}\" fill=\"{}\"{}{}/>",
format!(
"<path d=\"{}\" transform=\"{}\" fill=\"{}\"{}{}/>",
o.path, placement, fill, opacity, prov,
);
)
}),
GlyphMode::EmbeddedFont => smufl_codepoint(name).map(|cp| {
text_count += 1;
// The font glyph is drawn upright by a per-glyph counter-flip
// (`scale(1 -1)`, innermost) cancelling the outer y-flip; the
// em is four staff spaces (SMuFL), so `font-size="4"`.
format!(
"<text transform=\"{placement} scale(1 -1)\" \
font-family=\"{BRAVURA_SUBSET_FAMILY}\" font-size=\"4\" \
fill=\"{fill}\"{opacity}{prov}>&#x{cp:X};</text>",
)
}),
};
match element {
Some(el) => {
let _ = writeln!(s, " {el}");
}
None => {
// No outline: surface it and draw the IR bounding box so the
// missing glyph is visible, not silently absent.
// Unrenderable in this mode: surface it and draw the IR
// bounding box so the missing glyph is visible, not silent.
fallback_rect_count += 1;
diagnostics.push(Diagnostic {
message: "no bundled Bravura outline; drew bounding-box fallback"
message: "no bundled Bravura glyph for this name; drew \
bounding-box fallback"
.to_owned(),
glyph: Some(name.to_owned()),
});
@ -383,6 +433,7 @@ pub fn render(resolved: &ResolvedLayoutIR, options: &RenderOptions) -> RenderOut
stats: RenderStats {
glyph_count: resolved.glyphs.len(),
path_count,
text_count,
fallback_rect_count,
stroke_count,
provenance_count,
@ -572,6 +623,16 @@ fn colour(rgba: u32) -> (String, String) {
(fill, opacity)
}
/// The glyph-mode clause of the metadata comment: which drawing strategy produced
/// the SVG. Shared by the main render and [`empty_svg`] so the declared mode
/// boundary is the same on the empty path.
fn glyph_note(mode: GlyphMode) -> &'static str {
match mode {
GlyphMode::PathOutline => "glyphs are genuine Bravura SMuFL outlines inlined as paths",
GlyphMode::EmbeddedFont => "glyphs are Bravura SMuFL codepoints set in the embedded font",
}
}
/// The provenance-state clause of the metadata comment. Archival mode declares
/// traces present; display-only mode declares them suppressed — so a trace-free
/// SVG (including the empty canvas) announces itself rather than passing as
@ -585,13 +646,15 @@ fn provenance_note(emit_provenance: bool) -> &'static str {
}
/// A minimal, valid empty SVG for a layout with nothing to draw — still declaring
/// its provenance state, so an empty trace-free render is honest like a full one.
fn empty_svg(emit_provenance: bool) -> String {
/// its glyph mode and provenance state, so an empty render is honest like a full
/// one (the metadata is the same declared boundary on both paths).
fn empty_svg(glyph_mode: GlyphMode, emit_provenance: bool) -> String {
format!(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1\" height=\"1\" viewBox=\"0 0 1 1\">\n\
\x20\x20<!-- epiphany-render-svg: empty resolved layout (no glyphs); {} -->\n\
\x20\x20<!-- epiphany-render-svg: empty resolved layout (no glyphs); {}; {} -->\n\
</svg>\n",
glyph_note(glyph_mode),
provenance_note(emit_provenance),
)
}
@ -780,6 +843,77 @@ mod tests {
);
}
#[test]
fn embedded_font_mode_sets_text_from_the_embedded_subset() {
let layout = stub_layout(11);
let out = render(
&layout,
&RenderOptions {
glyph_mode: GlyphMode::EmbeddedFont,
..RenderOptions::default()
},
);
assert!(
out.is_well_formed(),
"embedded-font SVG must be well-formed"
);
// The font is declared exactly once via @font-face with the base64 subset,
// under its non-reserved family name (OFL: not the Reserved Font Name).
assert_eq!(out.svg.matches("@font-face").count(), 1);
assert!(out.svg.contains("font-family: \"EpiphanyBravuraSubset\""));
assert!(!out.svg.contains("font-family: \"Bravura\""));
assert!(out.svg.contains("data:font/otf;base64,"));
// Every glyph is a `<text>` (the stub names only bundled glyphs), none a
// path or a fallback rect, and each carries a SMuFL codepoint reference.
assert_eq!(out.stats.text_count, layout.glyphs.len());
assert_eq!(out.stats.path_count, 0);
assert_eq!(out.stats.fallback_rect_count, 0);
assert!(out.diagnostics.is_empty());
assert_eq!(out.svg.matches("<text ").count(), layout.glyphs.len());
assert_eq!(out.svg.matches("&#x").count(), layout.glyphs.len());
// The metadata comment declares the embedded-font mode, and provenance is
// preserved exactly as in path mode.
assert!(out.svg.contains("set in the embedded font"));
assert_eq!(
out.stats.provenance_count,
layout.glyphs.len() + layout.strokes.len()
);
assert!(out.svg.contains("data-prov="));
}
#[test]
fn embedded_font_mode_is_deterministic_and_draws_every_glyph() {
let layout = stub_layout(7);
let a = render(
&layout,
&RenderOptions {
glyph_mode: GlyphMode::EmbeddedFont,
..RenderOptions::default()
},
);
let b = render(
&layout,
&RenderOptions {
glyph_mode: GlyphMode::EmbeddedFont,
..RenderOptions::default()
},
);
assert_eq!(a.svg, b.svg, "embedded-font render must be deterministic");
// Every glyph is accounted for (text or fallback rect), none dropped — the
// same no-silent-drop contract as path mode.
assert_eq!(
a.stats.text_count + a.stats.fallback_rect_count,
a.stats.glyph_count
);
// The default path mode draws no `<text>`; the modes do not bleed.
let path = render(&layout, &RenderOptions::default());
assert_eq!(path.stats.text_count, 0);
assert!(!path.svg.contains("@font-face"));
}
#[test]
fn empty_layout_renders_a_valid_empty_canvas() {
let layout = ResolvedLayoutIR {
@ -806,6 +940,17 @@ mod tests {
);
assert!(suppressed.is_well_formed());
assert!(suppressed.svg.contains("provenance traces suppressed"));
// The empty canvas also declares its glyph mode (the same boundary as a
// full render), so an empty embedded render is not mistaken for a path one.
let empty_embedded = render(
&layout,
&RenderOptions {
glyph_mode: GlyphMode::EmbeddedFont,
..RenderOptions::default()
},
);
assert!(empty_embedded.svg.contains("set in the embedded font"));
}
#[test]

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="824.5643" height="110.24" viewBox="0 0 82.4564 11.024">
<!-- epiphany-render-svg: glyphs are genuine Bravura SMuFL outlines; geometry is the resolved layout verbatim, no engraving performed here; every glyph and stroke carries a data-prov trace to its score-graph source -->
<!-- epiphany-render-svg: glyphs are genuine Bravura SMuFL outlines inlined as paths; geometry is the resolved layout verbatim, no engraving performed here; every glyph and stroke carries a data-prov trace to its score-graph source -->
<g transform="translate(3.0599 7.392) scale(1 -1)">
<g data-layer="0">
<line x1="0" y1="0" x2="0" y2="0" stroke="#000000" stroke-width="0" data-prov="2ef8d2dba955aee38147023b72bdabb7" data-source-kind="6" data-kind="stroke"/>

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="888.7701" height="110.24" viewBox="0 0 88.877 11.024">
<!-- epiphany-render-svg: glyphs are genuine Bravura SMuFL outlines; geometry is the resolved layout verbatim, no engraving performed here; every glyph and stroke carries a data-prov trace to its score-graph source -->
<!-- epiphany-render-svg: glyphs are genuine Bravura SMuFL outlines inlined as paths; geometry is the resolved layout verbatim, no engraving performed here; every glyph and stroke carries a data-prov trace to its score-graph source -->
<g transform="translate(3.065 7.392) scale(1 -1)">
<g data-layer="0">
<line x1="0" y1="0" x2="0" y2="0" stroke="#000000" stroke-width="0" data-prov="2ef8d2dba955aee38147023b72bdabb7" data-source-kind="6" data-kind="stroke"/>

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="279.5357" height="110.24" viewBox="0 0 27.9536 11.024">
<!-- epiphany-render-svg: glyphs are genuine Bravura SMuFL outlines; geometry is the resolved layout verbatim, no engraving performed here; every glyph and stroke carries a data-prov trace to its score-graph source -->
<!-- epiphany-render-svg: glyphs are genuine Bravura SMuFL outlines inlined as paths; geometry is the resolved layout verbatim, no engraving performed here; every glyph and stroke carries a data-prov trace to its score-graph source -->
<g transform="translate(3.0599 7.392) scale(1 -1)">
<g data-layer="0">
<line x1="0" y1="0" x2="0" y2="0" stroke="#000000" stroke-width="0" data-prov="bd56ad529a36a7bbf2b4c343886b55e5" data-source-kind="6" data-kind="stroke"/>

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="393.3" height="110.24" viewBox="0 0 39.33 11.024">
<!-- epiphany-render-svg: glyphs are genuine Bravura SMuFL outlines; geometry is the resolved layout verbatim, no engraving performed here; every glyph and stroke carries a data-prov trace to its score-graph source -->
<!-- epiphany-render-svg: glyphs are genuine Bravura SMuFL outlines inlined as paths; geometry is the resolved layout verbatim, no engraving performed here; every glyph and stroke carries a data-prov trace to its score-graph source -->
<g transform="translate(3.065 7.392) scale(1 -1)">
<g data-layer="0">
<line x1="0" y1="0" x2="0" y2="0" stroke="#000000" stroke-width="0" data-prov="bd56ad529a36a7bbf2b4c343886b55e5" data-source-kind="6" data-kind="stroke"/>

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -60,7 +60,85 @@ def load():
verify(names_bytes, NAMES_SHA256, "glyphnames.json")
font = TTFont(io.BytesIO(font_bytes))
names = json.loads(names_bytes)
return font, names
return font, names, font_bytes
# The subset is a Modified Version under the OFL, so its primary user-facing name
# must NOT be the Reserved Font Name "Bravura" (OFL §"Reserved Font Name"). The
# copyright/trademark/license records (which name Bravura as attribution) are kept.
SUBSET_FAMILY = "EpiphanyBravuraSubset"
RESERVED_FONT_NAME = "Bravura"
def subset_font_b64(font_bytes, codepoints):
"""A deterministic, OFL-renamed base64 OTF subset of `font_bytes`.
For the renderer's `GlyphMode::EmbeddedFont` `@font-face` data-URI. SMuFL is
accessed by codepoint (no shaping), so layout features are dropped; the result
is small and byte-stable for a given fontTools version. Returns
`(family, b64, decoded_len, blake3_hex)`.
"""
import io, base64, blake3
from fontTools.ttLib import TTFont
from fontTools.subset import Subsetter, Options
# `recalcTimestamp=False` keeps the source font's fixed `head.modified` instead
# of stamping "now" on save, so the subset bytes are reproducible across runs
# (not just within one process), making the BLAKE3 lock stable per fontTools
# version.
sub = TTFont(io.BytesIO(font_bytes), recalcTimestamp=False)
opts = Options()
opts.layout_features = [] # codepoint access only; no GSUB/GPOS shaping
opts.name_IDs = ["*"] # keep name records incl. the OFL copyright/license
opts.notdef_outline = True
opts.recalc_bounds = True
ss = Subsetter(options=opts)
cps = sorted(set(codepoints))
ss.populate(unicodes=cps)
ss.subset(sub)
# OFL reserved-name compliance: rename the primary user-facing name off the
# Reserved Font Name in BOTH naming structures an OTF carries — the SFNT `name`
# table AND the CFF table's own name (the CFF Name INDEX and the top dict's
# FullName/FamilyName). Copyright/trademark/license records (which name Bravura
# as attribution) are left intact.
name = sub["name"]
for rec in list(name.names):
if rec.nameID in (1, 4, 6, 16):
name.setName(SUBSET_FAMILY, rec.nameID, rec.platformID, rec.platEncID, rec.langID)
elif rec.nameID == 3:
name.setName(rec.toUnicode().replace(RESERVED_FONT_NAME, SUBSET_FAMILY),
3, rec.platformID, rec.platEncID, rec.langID)
cff = sub["CFF "].cff
cff.fontNames[0] = SUBSET_FAMILY # the CFF Name INDEX
topdict = cff.topDictIndex[0]
for key in ("FullName", "FamilyName"): # CFF top-dict display names
if key in topdict.rawDict:
setattr(topdict, key, SUBSET_FAMILY)
# Coverage guard: the subset cmap MUST map every requested codepoint, or the
# embedded font would render tofu for a glyph the pipeline names.
cmap = sub.getBestCmap()
missing = [f"U+{cp:04X}" for cp in cps if cp not in cmap]
if missing:
sys.exit(f"subset cmap is missing codepoints: {missing}")
buf = io.BytesIO()
sub.save(buf)
raw = buf.getvalue()
# Compliance guard: reparse the *saved* bytes and confirm no primary name in
# either structure is still the Reserved Font Name (the copyright/trademark
# attribution may, and should, still mention Bravura).
check = TTFont(io.BytesIO(raw))
primary = [check["name"].getDebugName(i) for i in (1, 4, 6, 16)]
primary.append(check["CFF "].cff.fontNames[0])
ctop = check["CFF "].cff.topDictIndex[0]
primary += [getattr(ctop, k, None) for k in ("FullName", "FamilyName")]
if any(p == RESERVED_FONT_NAME for p in primary):
sys.exit(f"reserved font name leaked into a primary name record: {primary}")
return (SUBSET_FAMILY, base64.b64encode(raw).decode("ascii"),
len(raw), blake3.blake3(raw).hexdigest())
def round_d(d, nd=4):
def r(m):
@ -73,7 +151,7 @@ def main():
from fontTools.pens.svgPathPen import SVGPathPen
from fontTools.pens.transformPen import TransformPen
from fontTools.pens.boundsPen import BoundsPen
font, glyphnames = load()
font, glyphnames, font_bytes = load()
upm = font["head"].unitsPerEm
sp = upm / 4.0 # font units per staff space (SMuFL em = 4 staff spaces)
scale = 1.0 / sp
@ -151,5 +229,50 @@ def main():
sys.stdout.write("\n".join(o) + "\n")
print(f"// extracted {len(rows)}/{len(NAMES)} glyphs", file=sys.stderr)
# Optionally emit the embedded-font subset (renderer GlyphMode::EmbeddedFont).
if "--font-out" in sys.argv:
import fontTools
out_path = sys.argv[sys.argv.index("--font-out") + 1]
family, b64, raw_len, digest = subset_font_b64(font_bytes, [cp for _, cp, _, _ in rows])
f = []
f.append("//! GENERATED by `tools/extract_bravura_outlines.py --font-out` — "
"do not edit by hand.")
f.append("//!")
f.append("//! A subset of the OFL `Bravura.otf` holding exactly the glyphs the v0")
f.append("//! layout pipeline can name (the `BRAVURA_METRICS` / `NAMES` set), base64")
f.append("//! OTF for the renderer's `GlyphMode::EmbeddedFont` `@font-face` data-URI.")
f.append("//!")
f.append("//! As a Modified Version under the OFL, the subset's primary font name is")
f.append(f"//! `{family}`, NOT the Reserved Font Name; the copyright/trademark/license")
f.append("//! name records are retained as attribution (and `tools/OFL.txt` ships the")
f.append("//! full license). The cmap is verified at generation to cover every glyph.")
f.append("//!")
f.append(f"//! Source (pinned + SHA-256 verified): Bravura {FONT_TAG}, "
f"steinbergmedia/bravura @ {FONT_REF}.")
f.append(f"//! Subsetted with fontTools {fontTools.version}. Unlike the geometry-only")
f.append("//! outlines, the binary subset's exact bytes depend on the fontTools")
f.append("//! version recorded here, so regeneration is reproducible per version.")
f.append("")
f.append("/// The subset's font-family name (non-reserved; see the module note).")
f.append(f'pub(crate) const BRAVURA_SUBSET_FAMILY: &str = "{family}";')
f.append("")
f.append("/// MIME type for the embedded-font data-URI.")
f.append('pub(crate) const BRAVURA_SUBSET_MIME: &str = "font/otf";')
f.append("")
f.append("/// Decoded length, in bytes, of the embedded OTF (integrity lock).")
f.append("#[allow(dead_code)] // consumed only by the integrity test")
f.append(f"pub(crate) const BRAVURA_SUBSET_LEN: usize = {raw_len};")
f.append("")
f.append("/// BLAKE3-256 (hex) of the decoded OTF bytes (content-integrity lock).")
f.append("#[allow(dead_code)] // consumed only by the integrity test")
f.append(f'pub(crate) const BRAVURA_SUBSET_BLAKE3: &str = "{digest}";')
f.append("")
f.append("/// The Bravura subset (OTF/CFF outlines), base64-encoded.")
f.append(f'pub(crate) const BRAVURA_SUBSET_OTF_BASE64: &str = "{b64}";')
with open(out_path, "w") as fh:
fh.write("\n".join(f) + "\n")
print(f"// wrote {out_path} ({len(b64)} b64 chars, {raw_len} bytes, "
f"blake3 {digest[:16]}…)", file=sys.stderr)
if __name__ == "__main__":
main()