fdsm-skrifa 0.2.0

Import glyphs from Skrifa for fdsm
Documentation
#![doc = include_str!("../README.md")]

use fdsm::{
    bezier::{Point, Segment},
    shape::{Contour, Shape},
};
use skrifa::{
    FontRef, GlyphId, MetadataProvider, OutlineGlyph,
    outline::{AdjustedMetrics, DrawError, DrawSettings, OutlinePen},
    prelude::{LocationRef, Size},
};

extern crate nalgebra as na;

#[cfg(test)]
mod tests;

/// Loads a glyph from a [`skrifa::FontRef`] as a [`Shape`].
pub fn load_shape_from_face<'a>(
    face: &FontRef<'_>,
    glyph_id: GlyphId,
    location_ref: impl Into<LocationRef<'a>>,
) -> Result<(Shape<Contour>, AdjustedMetrics), DrawError> {
    let glyph = face
        .outline_glyphs()
        .get(glyph_id)
        .ok_or(DrawError::GlyphNotFound(glyph_id))?;
    load_shape_from_glyph(glyph, location_ref)
}

/// Loads a glyph from a [`skrifa::OutlineGlyph`] as a [`Shape`].
pub fn load_shape_from_glyph<'a>(
    glyph: OutlineGlyph<'_>,
    location_ref: impl Into<LocationRef<'a>>,
) -> Result<(Shape<Contour>, AdjustedMetrics), DrawError> {
    //
    let mut builder = ShapeBuilder {
        shape: Shape::default(),
        start_point: None,
        last_point: None,
    };
    let am = glyph.draw(
        DrawSettings::unhinted(Size::unscaled(), location_ref),
        &mut builder,
    )?;
    Ok((builder.shape, am))
}

#[derive(Debug)]
struct ShapeBuilder {
    shape: Shape<Contour>,
    start_point: Option<Point>,
    last_point: Option<Point>,
}

impl OutlinePen for ShapeBuilder {
    fn move_to(&mut self, x: f32, y: f32) {
        // eprintln!("move_to {x} {y}");
        if let Some(contour) = self.shape.contours.last_mut()
            && self.start_point != self.last_point
        {
            contour.segments.push(Segment::line(
                self.last_point.unwrap(),
                self.start_point.unwrap(),
            ));
        }
        self.start_point = Some(Point::new(x.into(), y.into()));
        self.last_point = self.start_point;
        self.shape.contours.push(Contour::default());
    }

    fn line_to(&mut self, x: f32, y: f32) {
        // eprintln!("line_to {x} {y}");
        let next_point = Point::new(x.into(), y.into());
        self.shape
            .contours
            .last_mut()
            .unwrap()
            .segments
            .push(Segment::line(self.last_point.unwrap(), next_point));
        self.last_point = Some(next_point);
    }

    fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
        // eprintln!("quad_to {x1} {y1} {x} {y}");
        let next_point = Point::new(x.into(), y.into());
        self.shape
            .contours
            .last_mut()
            .unwrap()
            .segments
            .push(Segment::quad(
                self.last_point.unwrap(),
                Point::new(x1.into(), y1.into()),
                next_point,
            ));
        self.last_point = Some(next_point);
    }

    fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
        // eprintln!("curve_to {x1} {y1} {x2} {y2} {x} {y}");
        let next_point = Point::new(x.into(), y.into());
        self.shape
            .contours
            .last_mut()
            .unwrap()
            .segments
            .push(Segment::cubic(
                self.last_point.unwrap(),
                Point::new(x1.into(), y1.into()),
                Point::new(x2.into(), y2.into()),
                next_point,
            ));
        self.last_point = Some(next_point);
    }

    fn close(&mut self) {
        // eprintln!("close");
        if let Some(contour) = self.shape.contours.last_mut()
            && self.start_point != self.last_point
        {
            contour.segments.push(Segment::line(
                self.last_point.take().unwrap(),
                self.start_point.take().unwrap(),
            ));
        }
    }
}