use crate::atlas::allocator::GlyphAtlas;
use crate::atlas::cache::GlyphCache;
use crate::font::registry::FontRegistry;
use crate::types::FontFaceId;
#[derive(Debug)]
pub struct AtlasSnapshot<'a> {
pub dirty: bool,
pub width: u32,
pub height: u32,
pub pixels: &'a [u8],
pub glyphs_evicted: bool,
}
pub struct TextFontService {
pub(crate) font_registry: FontRegistry,
pub(crate) atlas: GlyphAtlas,
pub(crate) glyph_cache: GlyphCache,
pub(crate) scale_context: swash::scale::ScaleContext,
pub(crate) scale_factor: f32,
pub(crate) scale_generation: u64,
}
impl TextFontService {
pub fn new() -> Self {
Self {
font_registry: FontRegistry::new(),
atlas: GlyphAtlas::new(),
glyph_cache: GlyphCache::new(),
scale_context: swash::scale::ScaleContext::new(),
scale_factor: 1.0,
scale_generation: 0,
}
}
pub fn register_font(&mut self, data: &[u8]) -> FontFaceId {
let ids = self.font_registry.register_font(data);
ids.into_iter()
.next()
.expect("font data contained no faces")
}
pub fn register_font_as(
&mut self,
data: &[u8],
family: &str,
weight: u16,
italic: bool,
) -> FontFaceId {
let ids = self
.font_registry
.register_font_as(data, family, weight, italic);
ids.into_iter()
.next()
.expect("font data contained no faces")
}
pub fn set_default_font(&mut self, face: FontFaceId, size_px: f32) {
self.font_registry.set_default_font(face, size_px);
}
pub fn set_generic_family(&mut self, generic: &str, family: &str) {
self.font_registry.set_generic_family(generic, family);
}
pub fn font_family_name(&self, face_id: FontFaceId) -> Option<String> {
self.font_registry.font_family_name(face_id)
}
pub fn font_registry(&self) -> &FontRegistry {
&self.font_registry
}
pub fn set_scale_factor(&mut self, scale_factor: f32) {
let sf = scale_factor.clamp(0.25, 8.0);
if (self.scale_factor - sf).abs() <= f32::EPSILON {
return;
}
self.scale_factor = sf;
self.glyph_cache.entries.clear();
self.atlas = GlyphAtlas::new();
self.scale_generation = self.scale_generation.wrapping_add(1);
}
pub fn scale_factor(&self) -> f32 {
self.scale_factor
}
pub fn scale_generation(&self) -> u64 {
self.scale_generation
}
pub fn atlas_snapshot(&mut self, advance_generation: bool) -> AtlasSnapshot<'_> {
let mut glyphs_evicted = false;
if advance_generation {
self.glyph_cache.advance_generation();
let evicted = self.glyph_cache.evict_unused();
glyphs_evicted = !evicted.is_empty();
for alloc_id in evicted {
self.atlas.deallocate(alloc_id);
}
}
let dirty = self.atlas.dirty;
let width = self.atlas.width;
let height = self.atlas.height;
if dirty {
self.atlas.dirty = false;
}
AtlasSnapshot {
dirty,
width,
height,
pixels: &self.atlas.pixels[..],
glyphs_evicted,
}
}
pub fn touch_glyphs(&mut self, keys: &[crate::atlas::cache::GlyphCacheKey]) {
self.glyph_cache.touch(keys);
}
pub fn atlas_dirty(&self) -> bool {
self.atlas.dirty
}
pub fn atlas_width(&self) -> u32 {
self.atlas.width
}
pub fn atlas_height(&self) -> u32 {
self.atlas.height
}
pub fn atlas_pixels(&self) -> &[u8] {
&self.atlas.pixels
}
pub fn mark_atlas_clean(&mut self) {
self.atlas.dirty = false;
}
}
impl Default for TextFontService {
fn default() -> Self {
Self::new()
}
}