use std::{
path::Path,
sync::{
Mutex, PoisonError,
atomic::{AtomicUsize, Ordering},
},
};
use cranpose_ui::text::{FontFamily, FontStyle, FontWeight};
use crate::{
font_source::{FontLoadError, read_font_file},
software_text_raster::{SoftwareTextFont, SoftwareTextFontError},
};
static INSTALLED: Mutex<Vec<SoftwareTextFont>> = Mutex::new(Vec::new());
static INSTALLED_COUNT: AtomicUsize = AtomicUsize::new(0);
pub fn install_font_file(
family: &FontFamily,
path: &Path,
weights: &[FontWeight],
) -> Result<(), FontLoadError> {
let bytes = read_font_file(path)?;
install(family, bytes, weights).map_err(|source| FontLoadError::Parse {
path: path.to_path_buf(),
source,
})
}
pub fn install_font_bytes(
family: &FontFamily,
bytes: &'static [u8],
weights: &[FontWeight],
) -> Result<(), FontLoadError> {
install(family, bytes, weights).map_err(|source| FontLoadError::ParseBytes { source })
}
fn install(
family: &FontFamily,
bytes: &'static [u8],
weights: &[FontWeight],
) -> Result<(), SoftwareTextFontError> {
let faces = weights
.iter()
.map(|&weight| {
SoftwareTextFont::from_registered_bytes(family, weight, FontStyle::Normal, bytes)
})
.collect::<Result<Vec<_>, _>>()?;
let mut installed = INSTALLED.lock().unwrap_or_else(PoisonError::into_inner);
for face in faces {
let known = installed.iter().any(|known| {
known.content_hash() == face.content_hash()
&& known.weight() == face.weight()
&& known.registered_family() == face.registered_family()
});
if !known {
installed.push(face);
}
}
INSTALLED_COUNT.store(installed.len(), Ordering::Release);
Ok(())
}
pub fn installed_font_generation() -> usize {
INSTALLED_COUNT.load(Ordering::Acquire)
}
pub(crate) fn installed_faces() -> Vec<SoftwareTextFont> {
INSTALLED
.lock()
.unwrap_or_else(PoisonError::into_inner)
.clone()
}