use crate::face::Face;
use crate::shaper::{shape_run_with_font, PositionedGlyph};
use crate::style::{synthetic_italic_shear, Style};
use crate::Error;
#[derive(Debug)]
pub struct FaceChain {
faces: Vec<Face>,
}
impl FaceChain {
pub fn new(primary: Face) -> Self {
Self {
faces: vec![primary],
}
}
#[must_use]
pub fn push_fallback(mut self, face: Face) -> Self {
self.faces.push(face);
self
}
pub fn len(&self) -> usize {
self.faces.len()
}
pub fn is_empty(&self) -> bool {
self.faces.is_empty()
}
pub fn face(&self, idx: u16) -> &Face {
&self.faces[idx as usize]
}
pub fn primary(&self) -> &Face {
&self.faces[0]
}
pub fn shape(&self, text: &str, size_px: f32) -> Result<Vec<PositionedGlyph>, Error> {
self.shape_styled(text, size_px, Style::REGULAR)
}
pub fn shape_styled(
&self,
text: &str,
size_px: f32,
_style: Style,
) -> Result<Vec<PositionedGlyph>, Error> {
if text.is_empty() || size_px <= 0.0 {
return Ok(Vec::new());
}
let assigned = self.assign_codepoints(text)?;
if assigned.is_empty() {
return Ok(Vec::new());
}
let mut out: Vec<PositionedGlyph> = Vec::with_capacity(assigned.len());
let mut run_start = 0usize;
while run_start < assigned.len() {
let face_idx = assigned[run_start].0;
let mut run_end = run_start + 1;
while run_end < assigned.len() && assigned[run_end].0 == face_idx {
run_end += 1;
}
let gids: Vec<u16> = assigned[run_start..run_end].iter().map(|p| p.1).collect();
let face = &self.faces[face_idx as usize];
let mut run_glyphs =
face.with_font(|font| shape_run_with_font(font, &gids, size_px, face_idx))?;
out.append(&mut run_glyphs);
run_start = run_end;
}
Ok(out)
}
fn assign_codepoints(&self, text: &str) -> Result<Vec<(u16, u16)>, Error> {
let mut out: Vec<(u16, u16)> = Vec::with_capacity(text.len());
for ch in text.chars() {
let mut found: Option<(u16, u16)> = None;
for (idx, face) in self.faces.iter().enumerate() {
let g = face.with_font(|font| font.glyph_index(ch))?;
match g {
Some(gid) if gid != 0 => {
found = Some((idx as u16, gid));
break;
}
_ => continue,
}
}
out.push(found.unwrap_or((0, 0)));
}
Ok(out)
}
}
pub fn shear_for(face: &Face, style: Style) -> f32 {
synthetic_italic_shear(style, face.italic_angle())
}
#[cfg(test)]
mod tests {
}