git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commite2e55e8d6c9ece81185ea142ae88165566924ec4
parentc80504eacd
authorLucas Galante <[email protected]>
date2026-07-21 21:08
fix: fall back to system fonts when the bundled fonts dir yields nothing

An empty fontdb is a guaranteed panic on the first shaped glyph
(cosmic-text: "no default font found"). The greeter runs as root with no
$HOME/Dropbox/Fonts, so the $HOME-based fonts_dir() left it with zero
faces and crash-looped the display manager. Load system fonts whenever
the db comes up empty; regression test included.

Co-Authored-By: Claude Fable 5 <[email protected]>

 src/lib.rs             |  7 +++++++
 tests/font_fallback.rs | 15 +++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/src/lib.rs b/src/lib.rs
index faf9e02..894d2a5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -62,6 +62,13 @@ fn build_font_system(load_system_fonts: bool) -> glyphon::FontSystem {
     if load_system_fonts || std::env::var("CCE_LOAD_SYSTEM_FONTS").is_ok() {
         db.load_system_fonts();
     }
+    // An empty database guarantees a panic on the first shaped glyph
+    // (cosmic-text: "no default font found"), so if the bundled dir yielded
+    // nothing (missing $HOME/Dropbox/Fonts — e.g. the greeter running as
+    // root), fall back to system fonts rather than crash.
+    if db.faces().next().is_none() {
+        db.load_system_fonts();
+    }
 
     // Validate configured custom fonts
     let font_getters = vec![
diff --git a/tests/font_fallback.rs b/tests/font_fallback.rs
new file mode 100644
index 0000000..811b56d
--- /dev/null
+++ b/tests/font_fallback.rs
@@ -0,0 +1,15 @@
+//! Regression test: a missing bundled-fonts dir must not produce an empty font
+//! database — cosmic-text panics with "no default font found" on the first
+//! shaped glyph (this is what crash-looped the cce-display-manager greeter,
+//! which runs as root with no $HOME/Dropbox/Fonts).
+
+#[test]
+fn empty_bundled_dir_falls_back_to_system_fonts() {
+    std::env::set_var("CCE_FONTS_DIR", "/nonexistent-cce-fonts");
+    std::env::remove_var("CCE_LOAD_SYSTEM_FONTS");
+    let fs = cce_ui::create_font_system();
+    assert!(
+        fs.db().faces().next().is_some(),
+        "font database is empty — system-font fallback did not kick in"
+    );
+}