fdsm-ttf-parser 0.2.0

Import glyphs from ttf-parser for fdsm
Documentation
// ttf-parser import for msdfgen-rs for testing, adapted from
// <https://github.com/katyo/msdfgen-rs/blob/master/src/interop/ttf_parser.rs>
// Vendored so that we can update our ttf-parser dependency without
// waiting for msdfgen-rs to release a new version.
mod msdf_import_from_ttf_parser {
    use msdfgen::{Contour, EdgeColor, EdgeHolder, Point2, Shape};

    #[derive(Default)]
    struct ContourBuilder {
        contour: Contour,
        point: Point2<f64>,
        start_point: Point2<f64>,
    }

    impl ContourBuilder {
        pub fn open_at(x: f64, y: f64) -> Self {
            Self {
                contour: Contour::default(),
                point: Point2::new(x, y),
                start_point: Point2::new(x, y),
            }
        }

        pub fn line_to(&mut self, x: f64, y: f64) {
            let point = Point2::new(x, y);
            self.contour.add_edge(&EdgeHolder::new_linear(
                self.point,
                point,
                EdgeColor::default(),
            ));
            self.point = point;
        }

        pub fn quad_to(&mut self, cx: f64, cy: f64, x: f64, y: f64) {
            let cpoint = Point2::new(cx, cy);
            let point = Point2::new(x, y);
            self.contour.add_edge(&EdgeHolder::new_quadratic(
                self.point,
                cpoint,
                point,
                EdgeColor::default(),
            ));
            self.point = point;
        }

        pub fn curve_to(&mut self, c1x: f64, c1y: f64, c2x: f64, c2y: f64, x: f64, y: f64) {
            let c1point = Point2::new(c1x, c1y);
            let c2point = Point2::new(c2x, c2y);
            let point = Point2::new(x, y);
            self.contour.add_edge(&EdgeHolder::new_cubic(
                self.point,
                c1point,
                c2point,
                point,
                EdgeColor::default(),
            ));
            self.point = point;
        }

        pub fn close(self) -> Contour {
            self.contour
        }
    }

    #[derive(Default)]
    struct ShapeBuilder {
        shape: Shape,
        contour: Option<ContourBuilder>,
    }

    impl ShapeBuilder {
        pub fn build(self) -> Shape {
            self.shape
        }
    }

    impl ttf_parser::OutlineBuilder for ShapeBuilder {
        fn move_to(&mut self, x: f32, y: f32) {
            if self.contour.is_some() {
                panic!("Unexpected move_to");
            }

            self.contour = ContourBuilder::open_at(x as _, y as _).into();
        }

        fn line_to(&mut self, x: f32, y: f32) {
            self.contour
                .as_mut()
                .expect("Opened contour")
                .line_to(x as _, y as _);
        }

        fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
            self.contour
                .as_mut()
                .expect("Opened contour")
                .quad_to(x1 as _, y1 as _, x as _, y as _);
        }

        fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
            self.contour
                .as_mut()
                .expect("Opened contour")
                .curve_to(x1 as _, y1 as _, x2 as _, y2 as _, x as _, y as _);
        }

        fn close(&mut self) {
            let mut contour = self.contour.take().expect("Opened contour");
            if contour.point != contour.start_point {
                contour.line_to(contour.start_point.x as _, contour.start_point.y as _);
            }
            self.shape.add_contour(&contour.close());
        }
    }

    pub fn glyph_shape_vendored(
        this: &ttf_parser::Face<'_>,
        glyph: ttf_parser::GlyphId,
    ) -> Option<Shape> {
        let mut builder = ShapeBuilder::default();

        this.outline_glyph(glyph, &mut builder)?;

        Some(builder.build())
    }

    #[cfg(test)]
    mod test {
        use super::*;
        use notosans::REGULAR_TTF;
        use ttf_parser::{Face, GlyphId};

        #[test]
        fn glyph_shape() {
            let font = Face::parse(REGULAR_TTF, 0).unwrap();

            let mut shapes = 0;

            for glyph in 0..font.number_of_glyphs() {
                let glyph = GlyphId(glyph);
                if let Some(_shape) = glyph_shape_vendored(&font, glyph) {
                    shapes += 1;
                }
            }

            assert_eq!(shapes, 2392);
        }
    }
}