mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-08 19:42:12 +00:00
69 lines
3.2 KiB
Rust
69 lines
3.2 KiB
Rust
//! Deterministic app-supplied fonts for dialog tests, including their first layout pass.
|
|
|
|
use std::path::PathBuf;
|
|
use std::sync::{Arc, OnceLock};
|
|
|
|
use egui::{FontData, FontDefinitions, FontId};
|
|
use sha2::{Digest, Sha256};
|
|
|
|
// Assets from craft-fonts b076417b5880bd4154bd22f00695b1d28c6bea83. Keep the
|
|
// input outside this repository; do not fall back to machine-installed fonts.
|
|
const INPUTS: [(&str, &str, &str); 2] = [
|
|
("keymap-symbols", "fonts/noto-sans-symbols/NotoSansSymbols.ttf", "f7e7e04b4a24b6c78893d50cbfd2b2f6cae49617ab047bfef668d252adb128f7"),
|
|
(
|
|
"keymap-symbols-2",
|
|
"fonts/noto-sans-symbols-2/NotoSansSymbols2-Regular.ttf",
|
|
"7d5fb73b7ca67a6798101741f5d280a3d016a56a197afcd4199dbb57b4b82a21",
|
|
),
|
|
];
|
|
|
|
/// Load the pinned craft-fonts inputs once for all dialog tests.
|
|
///
|
|
/// Requires an absolute `CRAFT_FONTS_DIR`, verifies the SHA-256 of both symbol faces, refuses any
|
|
/// installed-font fallback, and appends the two pinned faces plus egui's Hack to every family.
|
|
fn definitions() -> FontDefinitions {
|
|
static FONTS: OnceLock<FontDefinitions> = OnceLock::new();
|
|
FONTS
|
|
.get_or_init(|| {
|
|
let root = PathBuf::from(std::env::var_os("CRAFT_FONTS_DIR").unwrap_or_else(|| {
|
|
panic!("UI tests require absolute CRAFT_FONTS_DIR at craft-fonts b076417b5880bd4154bd22f00695b1d28c6bea83; see README.md")
|
|
}));
|
|
assert!(root.is_absolute(), "CRAFT_FONTS_DIR must be absolute: {}", root.display());
|
|
let mut fonts = FontDefinitions::default();
|
|
assert!(fonts.font_data.contains_key("Hack"), "UI tests require egui default_fonts");
|
|
for (name, relative, expected) in INPUTS {
|
|
let path = root.join(relative);
|
|
let bytes = std::fs::read(&path).unwrap_or_else(|e| panic!("required font {}: {e}", path.display()));
|
|
assert_eq!(format!("{:x}", Sha256::digest(&bytes)), expected, "unreviewed font input: {}", path.display());
|
|
fonts.font_data.insert(name.into(), Arc::new(FontData::from_owned(bytes)));
|
|
}
|
|
for family in fonts.families.values_mut() {
|
|
for name in ["keymap-symbols", "keymap-symbols-2", "Hack"] {
|
|
if !family.iter().any(|existing| existing == name) {
|
|
family.push(name.into());
|
|
}
|
|
}
|
|
}
|
|
fonts
|
|
})
|
|
.clone()
|
|
}
|
|
|
|
/// Install the deterministic fonts on `ctx` before its first layout pass.
|
|
pub fn configure(ctx: &egui::Context) {
|
|
ctx.set_fonts(definitions());
|
|
}
|
|
|
|
/// All printable ASCII plus the key symbols, dialog icons and accented pseudolocale
|
|
/// repertoire. Direction marks are intentionally invisible, rather than drawn glyphs.
|
|
pub fn assert_coverage(ctx: &egui::Context) {
|
|
const SYMBOLS: &str = "×·—“”…‹›←↑→↓↩↺⇥⇧⌃⌘⌥⌦⌫⎋⏎⌨▾⚠✕⟦⟧ÅÉØáëïöüÜ";
|
|
ctx.fonts_mut(|fonts| {
|
|
for font in [FontId::proportional(16.0), FontId::monospace(16.0)] {
|
|
for c in (' '..='~').chain(SYMBOLS.chars()) {
|
|
assert!(fonts.has_glyph(&font, c), "test font {:?} lacks {c} (U+{:04X})", font.family, u32::from(c));
|
|
}
|
|
}
|
|
});
|
|
}
|