use std::cell::RefCell;
pub struct TextSystem {
pub(crate) fonts: parley::FontContext,
pub(crate) layouts: parley::LayoutContext<()>,
}
impl TextSystem {
pub fn bundled_only() -> TextSystem {
let collection = fontique::Collection::new(fontique::CollectionOptions {
shared: false,
system_fonts: false,
});
let source_cache =
fontique::SourceCache::new(fontique::SourceCacheOptions { shared: false });
let mut system = TextSystem {
fonts: parley::FontContext {
collection,
source_cache,
},
layouts: parley::LayoutContext::new(),
};
system.register_bundled_fonts();
system
}
pub fn with_system_fonts() -> TextSystem {
let mut system = TextSystem {
fonts: parley::FontContext::default(),
layouts: parley::LayoutContext::new(),
};
system.register_bundled_fonts();
system
}
pub fn install(self) {
CURRENT.with(|slot| {
let mut slot = slot.try_borrow_mut().expect(
"the thread's text system cannot be replaced while it is in \
use",
);
*slot = Some(self);
});
}
pub fn with<R>(f: impl FnOnce(&mut TextSystem) -> R) -> R {
CURRENT.with(|slot| {
let mut slot = slot.try_borrow_mut().expect(
"TextSystem::with cannot run inside another with call on the \
same thread",
);
let system = slot.get_or_insert_with(default_for_platform);
f(system)
})
}
#[cfg(feature = "bundled-fonts")]
fn register_bundled_fonts(&mut self) {
use std::sync::Arc;
let register = |system: &mut TextSystem, data: &'static [u8]| {
let blob = fontique::Blob::new(Arc::new(data));
system.fonts.collection.register_fonts(blob, None)
};
let sans = register(self, crate::fonts::SANS_REGULAR);
let sans_bold = register(self, crate::fonts::SANS_BOLD);
let mono = register(self, crate::fonts::MONO_REGULAR);
let sans_family = sans
.first()
.map(|(family, _)| *family)
.expect("a font file yields at least one family");
let sans_bold_family = sans_bold
.first()
.map(|(family, _)| *family)
.expect("a font file yields at least one family");
debug_assert_eq!(
sans_family, sans_bold_family,
"the bundled sans faces share a family name"
);
let mono_family = mono
.first()
.map(|(family, _)| *family)
.expect("a font file yields at least one family");
self.fall_back_to(fontique::GenericFamily::SansSerif, sans_family);
self.fall_back_to(fontique::GenericFamily::Monospace, mono_family);
}
#[cfg(feature = "bundled-fonts")]
fn fall_back_to(&mut self, generic: fontique::GenericFamily, family: fontique::FamilyId) {
let collection = &mut self.fonts.collection;
let mut families: Vec<_> = collection.generic_families(generic).collect();
if !families.contains(&family) {
families.push(family);
}
collection.set_generic_families(generic, families.into_iter());
}
#[cfg(not(feature = "bundled-fonts"))]
fn register_bundled_fonts(&mut self) {}
}
thread_local! {
static CURRENT: RefCell<Option<TextSystem>> = const { RefCell::new(None) };
}
fn default_for_platform() -> TextSystem {
#[cfg(target_arch = "wasm32")]
{
TextSystem::bundled_only()
}
#[cfg(not(target_arch = "wasm32"))]
{
TextSystem::with_system_fonts()
}
}
#[cfg(test)]
#[path = "system_tests.rs"]
mod tests;