#![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;
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)
}
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) {
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) {
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) {
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) {
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) {
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(),
));
}
}
}