1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
//! Built-in MOCK FONTS with fully controlled metrics.
//!
//! # Why these exist
//!
//! Every text assertion made against a *system* font is a guess: the engine
//! has no control over Arial's advances, and on a CI box Arial may not even
//! exist (see `register_named_font` — a family that fontconfig cannot find
//! silently falls back, which is exactly how the "8 families → 2 `FontIds`"
//! bug hid for so long). So text tests degenerate into "roughly this wide".
//!
//! The mock fonts fix that by making text layout ARITHMETIC:
//!
//! | family | advance | ascent | descent | glyphs |
//! |-------------------|---------|--------|---------|---------------|
//! | `Azul Mock Mono` | 0.5 em | 0.8 em | 0.2 em | ASCII 0x20-7E |
//! | `Azul Mock Wide` | 1.0 em | 0.8 em | 0.2 em | ASCII 0x20-7E |
//!
//! At `font-size: 20px`, `Azul Mock Mono` advances exactly 10 px per glyph:
//! a 5-character string is exactly 50 px wide and its line box is exactly
//! 20 px tall. Caret offsets, selection rectangles, line-break positions and
//! bidi run widths become exact integers a test can write down.
//!
//! # Registration path
//!
//! These are registered as ordinary rust-fontconfig **memory fonts** in the
//! shared [`rust_fontconfig::FcFontCache`] (see
//! [`crate::text3::cache::FontManager::register_named_font`]) — the same
//! mechanism an embedder uses for a bundled font. They therefore travel the
//! *real* resolution path: CSS `font-family` → font-stack collection →
//! chain resolution → `FontId` → `load_missing_for_chains` → shaping. There
//! is no test-only bypass, which is the point: a test using them exercises
//! font resolution rather than skipping it.
//!
//! # Adding more mock fonts
//!
//! `scripts/gen_mock_fonts.py` builds the `.ttf`s (no third-party deps). Add
//! an entry to its `FONTS` list — family name, upem, advance, ascent,
//! descent, codepoint range — re-run it, commit the `.ttf`, and add it to
//! [`BUILTIN_MOCK_FONTS`] below. An RTL mock is the same call with a
//! Hebrew/Arabic range; a missing-glyph mock is the same call with a
//! truncated range (uncovered chars then take the real fallback path); a
//! proportional mock is the same call with a wider advance.
use UnicodeRange;
/// `Azul Mock Mono`: every ASCII glyph advances 0.5 em (10 px at 20 px).
pub const MOCK_MONO_TTF: & = include_bytes!;
/// `Azul Mock Wide`: every ASCII glyph advances 1.0 em (20 px at 20 px).
pub const MOCK_WIDE_TTF: & = include_bytes!;
/// Codepoints the mock fonts cover (printable ASCII). Anything outside this
/// range is deliberately *not* covered, so it exercises real fallback.
/// The mock fonts registered into every `FontManager`: `(family, bytes)`.
///
/// Registering them unconditionally (rather than behind a test-only flag)
/// is intentional: it keeps the production and test font paths identical,
/// costs ~10 KiB, and the families are only reachable if a stylesheet asks
/// for them by name.
pub const BUILTIN_MOCK_FONTS: & = &;
/// Advance of one glyph of `family` at `font_size_px`, or `None` if the
/// family is not a mock font.
///
/// Test helper: lets a test compute the expected width of a string without
/// hardcoding the em fraction twice.