use std::rc::Rc;
use cranpose_render_common::software_text_raster::{
SoftwareGlyphAtlasKey, SoftwareGlyphAtlasPlacement,
};
use cranpose_ui_graphics::Color;
#[derive(Clone, Copy, PartialEq)]
struct RunFace {
key: SoftwareGlyphAtlasKey,
color: Color,
}
impl RunFace {
fn of(glyph: &SoftwareGlyphAtlasPlacement) -> Self {
Self {
key: SoftwareGlyphAtlasKey {
glyph_id: 0,
..glyph.key
},
color: glyph.color,
}
}
}
#[derive(Clone, Copy)]
struct RunGlyph {
x: i32,
y: i32,
width: u16,
height: u16,
glyph_id: u16,
face: u16,
}
impl RunGlyph {
fn of(glyph: &SoftwareGlyphAtlasPlacement, face: usize) -> Option<Self> {
Some(Self {
x: glyph.x,
y: glyph.y,
width: u16::try_from(glyph.width).ok()?,
height: u16::try_from(glyph.height).ok()?,
glyph_id: u16::try_from(glyph.key.glyph_id).ok()?,
face: u16::try_from(face).ok()?,
})
}
}
#[derive(Clone)]
pub(crate) struct RunGlyphs {
faces: Rc<[RunFace]>,
glyphs: Rc<[RunGlyph]>,
}
#[derive(Default)]
pub(crate) struct RunGlyphScratch {
faces: Vec<RunFace>,
glyphs: Vec<RunGlyph>,
last_faces: Rc<[RunFace]>,
}
impl RunGlyphs {
pub(crate) fn of(
placements: impl Iterator<Item = SoftwareGlyphAtlasPlacement>,
scratch: &mut RunGlyphScratch,
) -> Option<Self> {
scratch.faces.clear();
scratch.glyphs.clear();
for placement in placements {
let face = RunFace::of(&placement);
if scratch.faces.last() != Some(&face) {
scratch.faces.push(face);
}
let glyph = RunGlyph::of(&placement, scratch.faces.len() - 1)?;
scratch.glyphs.push(glyph);
}
if *scratch.last_faces != *scratch.faces {
scratch.last_faces = Rc::from(scratch.faces.as_slice());
}
Some(Self {
faces: Rc::clone(&scratch.last_faces),
glyphs: Rc::from(scratch.glyphs.as_slice()),
})
}
pub(crate) fn iter(&self) -> impl ExactSizeIterator<Item = SoftwareGlyphAtlasPlacement> + '_ {
self.glyphs.iter().map(|glyph| {
let face = self.faces[usize::from(glyph.face)];
SoftwareGlyphAtlasPlacement {
key: SoftwareGlyphAtlasKey {
glyph_id: u32::from(glyph.glyph_id),
..face.key
},
x: glyph.x,
y: glyph.y,
width: usize::from(glyph.width),
height: usize::from(glyph.height),
color: face.color,
}
})
}
}
#[cfg(test)]
#[path = "tests/glyph_run_tests.rs"]
mod tests;