use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use cosmic_text::{FontSystem, fontdb};
static EXTRA_FONTS: Mutex<Vec<Arc<Vec<u8>>>> = Mutex::new(Vec::new());
static REGISTERED: AtomicUsize = AtomicUsize::new(0);
pub fn register_font(bytes: Vec<u8>) {
let mut fonts = EXTRA_FONTS.lock().expect("font registry poisoned");
fonts.push(Arc::new(bytes));
REGISTERED.store(fonts.len(), Ordering::Release);
}
pub(crate) fn registered_count() -> usize {
REGISTERED.load(Ordering::Acquire)
}
pub(crate) fn sync_font_system(font_system: &mut FontSystem, loaded: &mut usize) -> bool {
if *loaded >= registered_count() {
return false;
}
let fonts = EXTRA_FONTS.lock().expect("font registry poisoned");
let mut added = false;
for font in fonts.iter().skip(*loaded) {
let source: Arc<dyn AsRef<[u8]> + Send + Sync> = font.clone();
font_system
.db_mut()
.load_font_source(fontdb::Source::Binary(source));
added = true;
}
*loaded = fonts.len();
added
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(feature = "jetbrains-mono")]
fn sync_loads_only_new_entries_and_reports_change() {
let mut fs =
FontSystem::new_with_locale_and_db("en-US".to_string(), fontdb::Database::new());
let mut loaded = registered_count();
assert!(!sync_font_system(&mut fs, &mut loaded), "nothing new yet");
let before = fs.db().len();
register_font(damascene_fonts::JETBRAINS_MONO_VARIABLE.to_vec());
assert!(sync_font_system(&mut fs, &mut loaded));
assert!(fs.db().len() > before, "registered face should be loaded");
assert_eq!(loaded, registered_count());
assert!(!sync_font_system(&mut fs, &mut loaded));
}
#[test]
#[cfg(feature = "jetbrains-mono")]
fn atlas_registration_reaches_the_measurement_side() {
let before = crate::text::metrics::font_system_face_count_for_tests();
let mut atlas = crate::text::atlas::GlyphAtlas::new();
atlas.register_font(damascene_fonts::JETBRAINS_MONO_VARIABLE.to_vec());
let after = crate::text::metrics::font_system_face_count_for_tests();
assert!(
after > before,
"atlas-registered font must reach measurement ({before} -> {after})"
);
}
}