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

commita8eb442031730dd948f134b9ef213e1c36e77286
parent3028e10b03
authorLucas Galante <[email protected]>
date2026-07-09 12:48
feat(engine): Application::load_system_fonts — system fonts in the render FontSystem

The engine's render FontSystem (WgpuAdapter) is bundled-fonts-only, so
text asking for a family that exists only among installed system fonts
is silently invisible — buffers shaped app-side against a system-fonts
FontSystem carry fontdb face IDs the engine's database doesn't have (the
cce-colors Phase 6e bug, and cce-fonts' entire reason to exist). The new
hook lets an app opt the render FontSystem into system fonts (additive —
bundled fonts still load first, keeping face IDs aligned with
create_font_system databases); consulted once at GPU init.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016MjP3pGQEDLkJbV5WEmYBe

 src/backend/wgpu_adapter.rs  | 11 +++++++++--
 src/backend/window_runner.rs | 16 +++++++++++++++-
 2 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/src/backend/wgpu_adapter.rs b/src/backend/wgpu_adapter.rs
index 260e5b3..b8c2b8b 100644
--- a/src/backend/wgpu_adapter.rs
+++ b/src/backend/wgpu_adapter.rs
@@ -21,6 +21,7 @@ impl WgpuAdapter {
         surface_ptr: *mut std::ffi::c_void,
         width: u32,
         height: u32,
+        load_system_fonts: bool,
     ) -> Self {
         let wayland_handle = Box::leak(Box::new(WaylandSurfaceHandle {
             display_ptr,
@@ -86,8 +87,14 @@ impl WgpuAdapter {
 
         surface.configure(&device, &config);
 
-        // Initialize text rendering
-        let font_system = crate::create_font_system();
+        // Initialize text rendering. The render FontSystem is bundled-fonts-only unless the
+        // app opts into system fonts (Application::load_system_fonts — the font picker must
+        // shape and rasterize every installed family).
+        let font_system = if load_system_fonts {
+            crate::create_font_system_with_system_fonts()
+        } else {
+            crate::create_font_system()
+        };
         let swash_cache = SwashCache::new();
         let cache = Cache::new(&device);
         let mut text_atlas = TextAtlas::new(&device, &queue, &cache, config.format);
diff --git a/src/backend/window_runner.rs b/src/backend/window_runner.rs
index 189c48b..cfb2ce6 100644
--- a/src/backend/window_runner.rs
+++ b/src/backend/window_runner.rs
@@ -1634,6 +1634,19 @@ pub trait Application: Sized + 'static {
     fn display_list_text(&self) -> bool {
         false
     }
+
+    /// Opt into system fonts in the ENGINE's render `FontSystem` (the one that shapes
+    /// display-list text and rasterizes every glyph at prepare time). Default `false`: the
+    /// render FontSystem loads only the bundled CCE fonts, and text asking for a family that
+    /// exists only among installed system fonts is silently invisible — buffers shaped
+    /// app-side against a system-fonts `FontSystem` carry fontdb face IDs the engine's
+    /// database doesn't have (the cce-colors Phase 6e bug). An app whose UI must render
+    /// arbitrary installed families (the font picker) returns `true`; its own `FontSystem`,
+    /// if it keeps one for measurement, should be `create_font_system_with_system_fonts()`
+    /// so both databases load identically. Consulted once, at GPU init.
+    fn load_system_fonts(&self) -> bool {
+        false
+    }
 }
 
 pub struct PressedKey {
@@ -1722,7 +1735,8 @@ impl<A: Application> EngineState<A> {
         let display_ptr = conn.backend().display_id().as_ptr() as *mut std::ffi::c_void;
         let surface_ptr = surface.id().as_ptr() as *mut std::ffi::c_void;
         
-        let adapter = WgpuAdapter::new(display_ptr, surface_ptr, pw, ph).await;
+        let load_system_fonts = self.inner.as_ref().map_or(false, |a| a.load_system_fonts());
+        let adapter = WgpuAdapter::new(display_ptr, surface_ptr, pw, ph, load_system_fonts).await;
         
         let shader = adapter.device.create_shader_module(wgpu::ShaderModuleDescriptor {
             label: Some("Shader"),