From 27ce92b6765aefbdfcf46e7d1ec64ff3a2fd7d9c Mon Sep 17 00:00:00 2001 From: "blu@blu.cx" <38222767+thebrandonlucas@users.noreply.github.com> Date: Thu, 29 Oct 2026 08:40:42 -0500 Subject: [PATCH] fix(gpui): register bundled fonts on macOS Core Graphics cannot load the bitmap-only (CBDT) Buzz Color Emoji font, and GPUI rejects a whole add_fonts batch when one font fails. On macOS that dropped Inter and JetBrains Mono too: every text style missed its font and fell through GPUI's fallback stack on each layout, which kept the main thread busy and made scrolling and typing choppy. Register each font on its own so one failure cannot drop the rest, and on macOS skip the bundled emoji font and fall back to Apple Color Emoji. Linux and Windows keep the bundled emoji font. --- apps/buzz-gpui/crates/ui/src/fonts.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/apps/buzz-gpui/crates/ui/src/fonts.rs b/apps/buzz-gpui/crates/ui/src/fonts.rs index 619427760af..fd444e4cb35 100644 --- a/apps/buzz-gpui/crates/ui/src/fonts.rs +++ b/apps/buzz-gpui/crates/ui/src/fonts.rs @@ -11,7 +11,8 @@ //! (swash has no COLRv1). Left to cosmic-text's own fallback, emoji Inter //! lacks land in whichever system font covers them first, often DejaVu //! Sans in monochrome, so Noto Color Emoji 2.051 is bundled and named as -//! every text style's fallback ([`fallbacks`]). Two edits make that work, +//! every text style's fallback ([`fallbacks`]). macOS cannot load it, so +//! there the fallback is the system's Apple Color Emoji. Two edits make that work, //! both done with fontTools: //! //! - GPUI drops any family without a glyph for `m` when it loads it by @@ -45,19 +46,31 @@ const FONTS: &[&[u8]] = &[ include_bytes!("../../../assets/fonts/jetbrains-mono/JetBrainsMono-Regular.ttf"), // The terminal's bold, as buzz-app's terminal loads 600 too. include_bytes!("../../../assets/fonts/jetbrains-mono/JetBrainsMono-SemiBold.ttf"), + // Core Graphics cannot load a bitmap-only (CBDT) font, so macOS draws + // emoji with the system's Apple Color Emoji instead. + #[cfg(not(target_os = "macos"))] EMOJI_FONT, ]; -/// Registers the bundled fonts with GPUI's text system. +/// The colour emoji family that text styles fall back to. +#[cfg(target_os = "macos")] +const FALLBACK_EMOJI: &str = "Apple Color Emoji"; +#[cfg(not(target_os = "macos"))] +const FALLBACK_EMOJI: &str = EMOJI; + +/// Registers the bundled fonts with GPUI's text system. Each font is added +/// on its own: GPUI rejects a whole batch when one font in it fails to load, +/// and then every text style falls through to the system fallbacks. pub fn register(cx: &mut App) { - let fonts = FONTS.iter().map(|bytes| Cow::Borrowed(*bytes)).collect(); - if let Err(err) = cx.text_system().add_fonts(fonts) { - eprintln!("buzz-ui: failed to register bundled fonts: {err:#}"); + for bytes in FONTS { + if let Err(err) = cx.text_system().add_fonts(vec![Cow::Borrowed(*bytes)]) { + eprintln!("buzz-ui: failed to register a bundled font: {err:#}"); + } } } /// The fallback chain for every text style: colour emoji before any /// system font. pub fn fallbacks() -> FontFallbacks { - FontFallbacks::from_fonts(vec![EMOJI.to_string()]) + FontFallbacks::from_fonts(vec![FALLBACK_EMOJI.to_string()]) }