Lines
100 %
Functions
62.5 %
Branches
//! Font registration for the plotters backends.
//!
//! The charts are drawn by binaries that ship as *static musl* executables in a
//! `FROM scratch` image, where fontconfig cannot be reached at all: a static
//! binary has no dynamic loader, so plotters' `ttf` backend panicked inside
//! `yeslogic-fontconfig-sys` ("Dynamic loading not supported") before it could
//! even look for a face. That panic escaped [`crate::svg::render_svg`]'s
//! fallback, which only catches `Err`.
//! So the face is compiled in and registered with plotters' pure-Rust
//! `ab_glyph` backend instead. No host fonts, no fontconfig, no `dlopen`.
use std::sync::OnceLock;
use plotters::style::{FontStyle, register_font};
/// The family name every chart asks for (see `draw.rs`).
const FAMILY: &str = "sans-serif";
/// DejaVu Sans covers Latin, Greek, Cyrillic and common symbols — not CJK. Chart
/// labels are user text (account, category and tag names), so a label outside
/// that coverage rasterises as missing-glyph boxes in the native PNG/kitty
/// output. The browser still falls back for SVG, since it shapes the `<text>`
/// nodes itself. Vendoring a CJK face would add tens of megabytes to every
/// binary; revisit if such labels are actually in use.
static DEJAVU_SANS: &[u8] = include_bytes!("../fonts/DejaVuSans.ttf");
static REGISTERED: OnceLock<bool> = OnceLock::new();
/// Register the embedded face, once per process. Returns whether every style
/// was accepted; a `false` here means text drawing will fail and callers fall
/// back to their degraded rendering.
///
/// Every style maps to the same regular face: only the regular one is vendored,
/// and a missing style is a drawing error rather than a heavier stroke, so bold
/// text renders as regular by design.
pub(crate) fn ensure_registered() -> bool {
*REGISTERED.get_or_init(|| {
[
FontStyle::Normal,
FontStyle::Bold,
FontStyle::Italic,
FontStyle::Oblique,
]
.into_iter()
.all(|style| register_font(FAMILY, style, DEJAVU_SANS).is_ok())
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn embedded_face_registers_for_every_style() {
assert!(
ensure_registered(),
"embedded font rejected by plotters — charts would degrade to title-only"
);
fn registration_is_idempotent() {
assert!(ensure_registered());