1#![doc = include_str!("../README.md")]
2
3use fdsm::{
4 bezier::{Point, Segment},
5 shape::{Contour, Shape},
6};
7use skrifa::{
8 FontRef, GlyphId, MetadataProvider, OutlineGlyph,
9 outline::{AdjustedMetrics, DrawError, DrawSettings, OutlinePen},
10 prelude::{LocationRef, Size},
11};
12
13extern crate nalgebra as na;
14
15#[cfg(test)]
16mod tests;
17
18pub fn load_shape_from_face<'a>(
20 face: &FontRef<'_>,
21 glyph_id: GlyphId,
22 location_ref: impl Into<LocationRef<'a>>,
23) -> Result<(Shape<Contour>, AdjustedMetrics), DrawError> {
24 let glyph = face
25 .outline_glyphs()
26 .get(glyph_id)
27 .ok_or(DrawError::GlyphNotFound(glyph_id))?;
28 load_shape_from_glyph(glyph, location_ref)
29}
30
31pub fn load_shape_from_glyph<'a>(
33 glyph: OutlineGlyph<'_>,
34 location_ref: impl Into<LocationRef<'a>>,
35) -> Result<(Shape<Contour>, AdjustedMetrics), DrawError> {
36 let mut builder = ShapeBuilder {
38 shape: Shape::default(),
39 start_point: None,
40 last_point: None,
41 };
42 let am = glyph.draw(
43 DrawSettings::unhinted(Size::unscaled(), location_ref),
44 &mut builder,
45 )?;
46 Ok((builder.shape, am))
47}
48
49#[derive(Debug)]
50struct ShapeBuilder {
51 shape: Shape<Contour>,
52 start_point: Option<Point>,
53 last_point: Option<Point>,
54}
55
56impl OutlinePen for ShapeBuilder {
57 fn move_to(&mut self, x: f32, y: f32) {
58 if let Some(contour) = self.shape.contours.last_mut()
60 && self.start_point != self.last_point
61 {
62 contour.segments.push(Segment::line(
63 self.last_point.unwrap(),
64 self.start_point.unwrap(),
65 ));
66 }
67 self.start_point = Some(Point::new(x.into(), y.into()));
68 self.last_point = self.start_point;
69 self.shape.contours.push(Contour::default());
70 }
71
72 fn line_to(&mut self, x: f32, y: f32) {
73 let next_point = Point::new(x.into(), y.into());
75 self.shape
76 .contours
77 .last_mut()
78 .unwrap()
79 .segments
80 .push(Segment::line(self.last_point.unwrap(), next_point));
81 self.last_point = Some(next_point);
82 }
83
84 fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
85 let next_point = Point::new(x.into(), y.into());
87 self.shape
88 .contours
89 .last_mut()
90 .unwrap()
91 .segments
92 .push(Segment::quad(
93 self.last_point.unwrap(),
94 Point::new(x1.into(), y1.into()),
95 next_point,
96 ));
97 self.last_point = Some(next_point);
98 }
99
100 fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
101 let next_point = Point::new(x.into(), y.into());
103 self.shape
104 .contours
105 .last_mut()
106 .unwrap()
107 .segments
108 .push(Segment::cubic(
109 self.last_point.unwrap(),
110 Point::new(x1.into(), y1.into()),
111 Point::new(x2.into(), y2.into()),
112 next_point,
113 ));
114 self.last_point = Some(next_point);
115 }
116
117 fn close(&mut self) {
118 if let Some(contour) = self.shape.contours.last_mut()
120 && self.start_point != self.last_point
121 {
122 contour.segments.push(Segment::line(
123 self.last_point.take().unwrap(),
124 self.start_point.take().unwrap(),
125 ));
126 }
127 }
128}