1use crate::{
4 from_obj::{FromObjRef, FromTableRef, ToOwnedTable},
5 util::{self, MultiZip, WrappingGet},
6 FontWrite, OtRound,
7};
8
9use kurbo::BezPath;
10use read_fonts::{tables::glyf::SimpleGlyphFlags, FontRead};
11
12pub use read_fonts::tables::glyf::CurvePoint;
13
14use super::Bbox;
15
16#[derive(Clone, Debug, Default, PartialEq, Eq)]
18pub struct SimpleGlyph {
19 pub bbox: Bbox,
20 pub contours: Vec<Contour>,
21 pub instructions: Vec<u8>,
22}
23
24#[derive(Clone, Debug, Default, PartialEq, Eq)]
26pub struct Contour(Vec<CurvePoint>);
27
28#[derive(Clone, Debug)]
30#[non_exhaustive]
31pub enum MalformedPath {
32 HasCubic,
33 TooSmall,
34 MissingMove,
35 UnequalNumberOfElements(Vec<usize>),
36 InconsistentPathElements(usize, Vec<&'static str>),
37}
38
39impl SimpleGlyph {
40 pub fn from_bezpath(path: &BezPath) -> Result<Self, MalformedPath> {
60 Self::interpolatable_glyphs_from_bezpaths(std::slice::from_ref(path))
61 .map(|mut x| x.pop().unwrap())
62 }
63
64 pub fn interpolatable_glyphs_from_bezpaths(
77 paths: &[BezPath],
78 ) -> Result<Vec<Self>, MalformedPath> {
79 simple_glyphs_from_kurbo(paths)
80 }
81
82 fn compute_point_deltas(
90 &self,
91 ) -> impl Iterator<Item = (SimpleGlyphFlags, CoordDelta, CoordDelta)> + '_ {
92 fn flag_and_delta(
94 value: i16,
95 short_flag: SimpleGlyphFlags,
96 same_or_pos: SimpleGlyphFlags,
97 ) -> (SimpleGlyphFlags, CoordDelta) {
98 const SHORT_MAX: i16 = u8::MAX as i16;
99 const SHORT_MIN: i16 = -SHORT_MAX;
100 match value {
101 0 => (same_or_pos, CoordDelta::Skip),
102 SHORT_MIN..=-1 => (short_flag, CoordDelta::Short(value.unsigned_abs() as u8)),
103 1..=SHORT_MAX => (short_flag | same_or_pos, CoordDelta::Short(value as _)),
104 _other => (SimpleGlyphFlags::empty(), CoordDelta::Long(value)),
105 }
106 }
107
108 let (mut last_x, mut last_y) = (0, 0);
109 let mut iter = self.contours.iter().flat_map(|c| c.iter());
110 std::iter::from_fn(move || {
111 let point = iter.next()?;
112 let mut flag = SimpleGlyphFlags::empty();
113 let d_x = point.x - last_x;
114 let d_y = point.y - last_y;
115 last_x = point.x;
116 last_y = point.y;
117
118 if point.on_curve {
119 flag |= SimpleGlyphFlags::ON_CURVE_POINT;
120 }
121 let (x_flag, x_data) = flag_and_delta(
122 d_x,
123 SimpleGlyphFlags::X_SHORT_VECTOR,
124 SimpleGlyphFlags::X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR,
125 );
126 let (y_flag, y_data) = flag_and_delta(
127 d_y,
128 SimpleGlyphFlags::Y_SHORT_VECTOR,
129 SimpleGlyphFlags::Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR,
130 );
131
132 flag |= x_flag | y_flag;
133 Some((flag, x_data, y_data))
134 })
135 }
136
137 pub fn recompute_bounding_box(&mut self) {
139 let mut points = self
140 .contours
141 .iter()
142 .flat_map(|c| c.iter())
143 .map(|p| (p.x, p.y));
144
145 if let Some((mut x_min, mut y_min)) = points.next() {
146 let mut x_max = x_min;
147 let mut y_max = y_min;
148 for (x, y) in points {
149 x_min = x_min.min(x);
150 y_min = y_min.min(y);
151 x_max = x_max.max(x);
152 y_max = y_max.max(y);
153 }
154 self.bbox = Bbox {
155 x_min,
156 y_min,
157 x_max,
158 y_max,
159 };
160 }
161 }
162}
163
164impl Contour {
165 pub fn len(&self) -> usize {
167 self.0.len()
168 }
169
170 pub fn is_empty(&self) -> bool {
172 self.0.is_empty()
173 }
174
175 pub fn iter(&self) -> impl Iterator<Item = &CurvePoint> {
176 self.0.iter()
177 }
178}
179
180impl From<Vec<CurvePoint>> for Contour {
181 fn from(points: Vec<CurvePoint>) -> Self {
182 Self(points)
183 }
184}
185
186impl From<Contour> for Vec<CurvePoint> {
187 fn from(contour: Contour) -> Self {
188 contour.0
189 }
190}
191
192impl MalformedPath {
193 fn inconsistent_path_els(idx: usize, elements: &[kurbo::PathEl]) -> Self {
194 fn el_types(elements: &[kurbo::PathEl]) -> Vec<&'static str> {
195 elements
196 .iter()
197 .map(|el| match el {
198 kurbo::PathEl::MoveTo(_) => "M",
199 kurbo::PathEl::LineTo(_) => "L",
200 kurbo::PathEl::QuadTo(_, _) => "Q",
201 kurbo::PathEl::CurveTo(_, _, _) => "C",
202 kurbo::PathEl::ClosePath => "Z",
203 })
204 .collect()
205 }
206
207 MalformedPath::InconsistentPathElements(idx, el_types(elements))
208 }
209}
210
211#[derive(Clone, Copy, Debug)]
213enum CoordDelta {
214 Skip,
216 Short(u8),
217 Long(i16),
218}
219
220impl FontWrite for CoordDelta {
221 fn write_into(&self, writer: &mut crate::TableWriter) {
222 match self {
223 CoordDelta::Skip => (),
224 CoordDelta::Short(val) => val.write_into(writer),
225 CoordDelta::Long(val) => val.write_into(writer),
226 }
227 }
228}
229
230impl FromObjRef<read_fonts::tables::glyf::SimpleGlyph<'_>> for SimpleGlyph {
231 fn from_obj_ref(
232 from: &read_fonts::tables::glyf::SimpleGlyph,
233 _data: read_fonts::FontData,
234 ) -> Self {
235 let bbox = Bbox {
236 x_min: from.x_min(),
237 y_min: from.y_min(),
238 x_max: from.x_max(),
239 y_max: from.y_max(),
240 };
241 let mut points = from.points();
242 let mut last_end = 0;
243 let mut contours = vec![];
244 for end_pt in from.end_pts_of_contours() {
245 let end = end_pt.get() as usize + 1;
246 let count = end - last_end;
247 last_end = end;
248 contours.push(Contour(points.by_ref().take(count).collect()));
249 }
250 Self {
251 bbox,
252 contours,
253 instructions: from.instructions().to_owned(),
254 }
255 }
256}
257
258impl FromTableRef<read_fonts::tables::glyf::SimpleGlyph<'_>> for SimpleGlyph {}
259
260impl<'a> FontRead<'a> for SimpleGlyph {
261 fn read(data: read_fonts::FontData<'a>) -> Result<Self, read_fonts::ReadError> {
262 read_fonts::tables::glyf::SimpleGlyph::read(data).map(|g| g.to_owned_table())
263 }
264}
265
266impl FontWrite for SimpleGlyph {
267 fn write_into(&self, writer: &mut crate::TableWriter) {
268 assert!(self.contours.len() < i16::MAX as usize);
269 assert!(self.instructions.len() < u16::MAX as usize);
270 let n_contours = self.contours.len() as i16;
271 if n_contours == 0 {
272 return;
274 }
275 n_contours.write_into(writer);
276 self.bbox.write_into(writer);
277 let mut cur = 0;
279 for contour in &self.contours {
280 cur += contour.len();
281 (cur as u16 - 1).write_into(writer);
282 }
283 (self.instructions.len() as u16).write_into(writer);
284 self.instructions.write_into(writer);
285
286 let deltas = self.compute_point_deltas().collect::<Vec<_>>();
287 RepeatableFlag::iter_from_flags(deltas.iter().map(|(flag, _, _)| *flag))
288 .for_each(|flag| flag.write_into(writer));
289 deltas.iter().for_each(|(_, x, _)| x.write_into(writer));
290 deltas.iter().for_each(|(_, _, y)| y.write_into(writer));
291 writer.pad_to_2byte_aligned();
292 }
293}
294
295#[derive(Clone, Copy, Debug, PartialEq, Eq)]
297struct RepeatableFlag {
298 flag: SimpleGlyphFlags,
299 repeat: u8,
300}
301
302impl FontWrite for RepeatableFlag {
303 fn write_into(&self, writer: &mut crate::TableWriter) {
304 debug_assert_eq!(
305 self.flag.contains(SimpleGlyphFlags::REPEAT_FLAG),
306 self.repeat > 0
307 );
308
309 self.flag.bits().write_into(writer);
310 if self.flag.contains(SimpleGlyphFlags::REPEAT_FLAG) {
311 self.repeat.write_into(writer);
312 }
313 }
314}
315
316impl RepeatableFlag {
317 fn iter_from_flags(
321 flags: impl IntoIterator<Item = SimpleGlyphFlags>,
322 ) -> impl Iterator<Item = RepeatableFlag> {
323 let mut iter = flags.into_iter();
324 let mut prev = None;
325 let mut decompose_single_repeat = None;
333
334 std::iter::from_fn(move || loop {
335 if let Some(repeat) = decompose_single_repeat.take() {
336 return Some(repeat);
337 }
338
339 match (iter.next(), prev.take()) {
340 (None, Some(RepeatableFlag { flag, repeat: 1 })) => {
341 let flag = flag & !SimpleGlyphFlags::REPEAT_FLAG;
342 decompose_single_repeat = Some(RepeatableFlag { flag, repeat: 0 });
343 return decompose_single_repeat;
344 }
345 (None, prev) => return prev,
346 (Some(flag), None) => prev = Some(RepeatableFlag { flag, repeat: 0 }),
347 (Some(flag), Some(mut last)) => {
348 if (last.flag & !SimpleGlyphFlags::REPEAT_FLAG) == flag && last.repeat < u8::MAX
349 {
350 last.repeat += 1;
351 last.flag |= SimpleGlyphFlags::REPEAT_FLAG;
352 prev = Some(last);
353 } else {
354 if last.repeat == 1 {
356 last.flag &= !SimpleGlyphFlags::REPEAT_FLAG;
357 last.repeat = 0;
358 decompose_single_repeat = Some(last);
361 }
362 prev = Some(RepeatableFlag { flag, repeat: 0 });
363 return Some(last);
364 }
365 }
366 }
367 })
368 }
369}
370
371impl crate::validate::Validate for SimpleGlyph {
372 fn validate_impl(&self, ctx: &mut crate::codegen_prelude::ValidationCtx) {
373 if self.instructions.len() > u16::MAX as usize {
374 ctx.report("instructions len overflows");
375 }
376 }
377}
378
379#[derive(Clone, Copy, Debug, PartialEq)]
384struct ContourPoint {
385 point: kurbo::Point,
386 on_curve: bool,
387}
388
389impl ContourPoint {
390 fn new(point: kurbo::Point, on_curve: bool) -> Self {
391 Self { point, on_curve }
392 }
393
394 fn on_curve(point: kurbo::Point) -> Self {
395 Self::new(point, true)
396 }
397
398 fn off_curve(point: kurbo::Point) -> Self {
399 Self::new(point, false)
400 }
401}
402
403impl From<ContourPoint> for CurvePoint {
404 fn from(pt: ContourPoint) -> Self {
405 let (x, y) = pt.point.ot_round();
406 CurvePoint::new(x, y, pt.on_curve)
407 }
408}
409#[derive(Clone, Debug, PartialEq)]
413struct InterpolatableContourBuilder(Vec<Vec<ContourPoint>>);
414
415impl InterpolatableContourBuilder {
416 fn new(move_pts: &[kurbo::Point]) -> Self {
418 assert!(!move_pts.is_empty());
419 Self(
420 move_pts
421 .iter()
422 .map(|pt| vec![ContourPoint::on_curve(*pt)])
423 .collect(),
424 )
425 }
426
427 fn len(&self) -> usize {
429 self.0.len()
430 }
431
432 fn line_to(&mut self, pts: &[kurbo::Point]) {
434 assert_eq!(pts.len(), self.len());
435 for (i, pt) in pts.iter().enumerate() {
436 self.0[i].push(ContourPoint::on_curve(*pt));
437 }
438 }
439
440 fn quad_to(&mut self, pts: &[(kurbo::Point, kurbo::Point)]) {
442 for (i, (p0, p1)) in pts.iter().enumerate() {
443 self.0[i].push(ContourPoint::off_curve(*p0));
444 self.0[i].push(ContourPoint::on_curve(*p1));
445 }
446 }
447
448 fn num_points(&self) -> usize {
450 let n = self.0[0].len();
451 assert!(self.0.iter().all(|c| c.len() == n));
452 n
453 }
454
455 fn first(&self) -> impl Iterator<Item = &ContourPoint> {
457 self.0.iter().map(|v| v.first().unwrap())
458 }
459
460 fn last(&self) -> impl Iterator<Item = &ContourPoint> {
462 self.0.iter().map(|v| v.last().unwrap())
463 }
464
465 fn remove_last(&mut self) {
467 self.0.iter_mut().for_each(|c| {
468 c.pop().unwrap();
469 });
470 }
471
472 fn is_implicit_on_curve(&self, idx: usize) -> bool {
473 self.0
474 .iter()
475 .all(|points| is_implicit_on_curve(points, idx))
476 }
477
478 fn build(self) -> Vec<Contour> {
480 let num_contours = self.len();
481 let num_points = self.num_points();
482 let mut contours = vec![Contour::default(); num_contours];
483 contours.iter_mut().for_each(|c| c.0.reserve(num_points));
484 for point_idx in (0..num_points).filter(|point_idx| !self.is_implicit_on_curve(*point_idx))
485 {
486 for (contour_idx, contour) in contours.iter_mut().enumerate() {
487 contour
488 .0
489 .push(CurvePoint::from(self.0[contour_idx][point_idx]));
490 }
491 }
492 contours
493 }
494}
495
496#[inline]
501fn is_mid_point(p0: kurbo::Point, p1: kurbo::Point, p2: kurbo::Point) -> bool {
502 let mid = p0.midpoint(p2);
503 (util::isclose(mid.x, p1.x) && util::isclose(mid.y, p1.y))
504 || p0.to_vec2().ot_round() + p2.to_vec2().ot_round() == p1.to_vec2().ot_round() * 2.0
505}
506
507fn is_implicit_on_curve(points: &[ContourPoint], idx: usize) -> bool {
508 let p1 = &points[idx]; if !p1.on_curve {
510 return false;
511 }
512 let p0 = points.wrapping_prev(idx);
513 let p2 = points.wrapping_next(idx);
514 if p0.on_curve || p0.on_curve != p2.on_curve {
515 return false;
516 }
517 is_mid_point(p0.point, p1.point, p2.point)
519}
520
521fn simple_glyphs_from_kurbo(paths: &[BezPath]) -> Result<Vec<SimpleGlyph>, MalformedPath> {
523 let num_elements: Vec<usize> = paths.iter().map(|path| path.elements().len()).collect();
525 if num_elements.iter().any(|n| *n != num_elements[0]) {
526 return Err(MalformedPath::UnequalNumberOfElements(num_elements));
527 }
528 let path_iters = MultiZip::new(paths.iter().map(|path| path.iter()).collect());
529 let mut contours: Vec<InterpolatableContourBuilder> = Vec::new();
530 let mut current: Option<InterpolatableContourBuilder> = None;
531 let num_glyphs = paths.len();
532 let mut pts = Vec::with_capacity(num_glyphs);
533 let mut quad_pts = Vec::with_capacity(num_glyphs);
534 for (i, elements) in path_iters.enumerate() {
535 let first_el = elements.first().unwrap();
538 match first_el {
539 kurbo::PathEl::MoveTo(_) => {
540 if let Some(prev) = current.take() {
542 contours.push(prev);
543 }
544 pts.clear();
545 for el in &elements {
546 match el {
547 &kurbo::PathEl::MoveTo(pt) => {
548 pts.push(pt);
549 }
550 _ => return Err(MalformedPath::inconsistent_path_els(i, &elements)),
551 }
552 }
553 current = Some(InterpolatableContourBuilder::new(&pts));
554 }
555 kurbo::PathEl::LineTo(_) => {
556 pts.clear();
557 for el in &elements {
558 match el {
559 &kurbo::PathEl::LineTo(pt) => {
560 pts.push(pt);
561 }
562 _ => return Err(MalformedPath::inconsistent_path_els(i, &elements)),
563 }
564 }
565 current
566 .as_mut()
567 .ok_or(MalformedPath::MissingMove)?
568 .line_to(&pts)
569 }
570 kurbo::PathEl::QuadTo(_, _) => {
571 quad_pts.clear();
572 for el in &elements {
573 match el {
574 &kurbo::PathEl::QuadTo(p0, p1) => {
575 quad_pts.push((p0, p1));
576 }
577 _ => return Err(MalformedPath::inconsistent_path_els(i, &elements)),
578 }
579 }
580 current
581 .as_mut()
582 .ok_or(MalformedPath::MissingMove)?
583 .quad_to(&quad_pts)
584 }
585 kurbo::PathEl::CurveTo(_, _, _) => return Err(MalformedPath::HasCubic),
586 kurbo::PathEl::ClosePath => {
587 let contour = current.as_mut().ok_or(MalformedPath::MissingMove)?;
588 if contour.num_points() > 1 && contour.last().eq(contour.first()) {
592 contour.remove_last();
593 }
594 }
595 }
596 }
597 contours.extend(current);
598
599 let mut glyph_contours = vec![Vec::new(); num_glyphs];
600 for builder in contours {
601 assert_eq!(builder.len(), num_glyphs);
602 for (i, contour) in builder.build().into_iter().enumerate() {
603 glyph_contours[i].push(contour);
604 }
605 }
606
607 let mut glyphs = Vec::new();
608 for (contours, path) in glyph_contours.into_iter().zip(paths.iter()) {
609 glyphs.push(SimpleGlyph {
612 bbox: path.control_box().into(),
613 contours,
614 instructions: Default::default(),
615 })
616 }
617
618 Ok(glyphs)
619}
620
621#[cfg(test)]
622mod tests {
623 use font_types::GlyphId;
624 use kurbo::Affine;
625 use read_fonts::{tables::glyf as read_glyf, FontRef, TableProvider};
626
627 use super::*;
628
629 fn pad_for_loca_format(loca: &read_fonts::tables::loca::Loca, mut bytes: Vec<u8>) -> Vec<u8> {
632 if matches!(loca, read_fonts::tables::loca::Loca::Short(_)) && bytes.len() & 1 != 0 {
633 bytes.push(0);
634 }
635 bytes
636 }
637
638 #[test]
639 fn bad_path_input() {
640 let mut path = BezPath::new();
641 path.move_to((0., 0.));
642 path.curve_to((10., 10.), (20., 20.), (30., 30.));
643 path.line_to((50., 50.));
644 path.line_to((10., 10.));
645 let err = SimpleGlyph::from_bezpath(&path).unwrap_err();
646 assert!(matches!(err, MalformedPath::HasCubic));
647 }
648
649 #[test]
650 fn read_write_simple() {
651 let font = FontRef::new(font_test_data::SIMPLE_GLYF).unwrap();
652 let loca = font.loca(None).unwrap();
653 let glyf = font.glyf().unwrap();
654 let read_glyf::Glyph::Simple(orig) =
655 loca.get_glyf(GlyphId::new(0), &glyf).unwrap().unwrap()
656 else {
657 panic!("not a simple glyph")
658 };
659 let orig_bytes = orig.offset_data();
660
661 let ours = SimpleGlyph::from_table_ref(&orig);
662 let bytes = pad_for_loca_format(&loca, crate::dump_table(&ours).unwrap());
663 let ours = read_glyf::SimpleGlyph::read(bytes.as_slice().into()).unwrap();
664
665 let our_points = ours.points().collect::<Vec<_>>();
666 let their_points = orig.points().collect::<Vec<_>>();
667 assert_eq!(our_points, their_points);
668 assert_eq!(orig_bytes.as_ref(), bytes);
669 assert_eq!(orig.glyph_data(), ours.glyph_data());
670 assert_eq!(orig_bytes.len(), bytes.len());
671 }
672
673 #[test]
674 fn round_trip_simple() {
675 let font = FontRef::new(font_test_data::SIMPLE_GLYF).unwrap();
676 let loca = font.loca(None).unwrap();
677 let glyf = font.glyf().unwrap();
678 let read_glyf::Glyph::Simple(orig) =
679 loca.get_glyf(GlyphId::new(2), &glyf).unwrap().unwrap()
680 else {
681 panic!("not a simple glyph")
682 };
683 let orig_bytes = orig.offset_data();
684
685 let bezpath = BezPath::from_svg("M278,710 L278,470 L998,470 L998,710 Z").unwrap();
686
687 let ours = SimpleGlyph::from_bezpath(&bezpath).unwrap();
688 let bytes = pad_for_loca_format(&loca, crate::dump_table(&ours).unwrap());
689 let ours = read_glyf::SimpleGlyph::read(bytes.as_slice().into()).unwrap();
690
691 let our_points = ours.points().collect::<Vec<_>>();
692 let their_points = orig.points().collect::<Vec<_>>();
693 assert_eq!(our_points, their_points);
694 assert_eq!(orig_bytes.as_ref(), bytes);
695 assert_eq!(orig.glyph_data(), ours.glyph_data());
696 assert_eq!(orig_bytes.len(), bytes.len());
697 }
698
699 #[test]
700 fn round_trip_multi_contour() {
701 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
702 let loca = font.loca(None).unwrap();
703 let glyf = font.glyf().unwrap();
704 let read_glyf::Glyph::Simple(orig) =
705 loca.get_glyf(GlyphId::new(1), &glyf).unwrap().unwrap()
706 else {
707 panic!("not a simple glyph")
708 };
709 let orig_bytes = orig.offset_data();
710
711 let bezpath = BezPath::from_svg("M708,1327 L226,0 L29,0 L584,1456 L711,1456 Z M1112,0 L629,1327 L626,1456 L753,1456 L1310,0 Z M1087,539 L1087,381 L269,381 L269,539 Z").unwrap();
712
713 let ours = SimpleGlyph::from_bezpath(&bezpath).unwrap();
714 let bytes = pad_for_loca_format(&loca, crate::dump_table(&ours).unwrap());
715 let ours = read_glyf::SimpleGlyph::read(bytes.as_slice().into()).unwrap();
716
717 let our_points = ours.points().collect::<Vec<_>>();
718 let their_points = orig.points().collect::<Vec<_>>();
719 dbg!(
720 SimpleGlyphFlags::from_bits(1),
721 SimpleGlyphFlags::from_bits(9)
722 );
723 assert_eq!(our_points, their_points);
724 assert_eq!(orig.glyph_data(), ours.glyph_data());
725 assert_eq!(orig_bytes.len(), bytes.len());
726 assert_eq!(orig_bytes.as_ref(), bytes);
727 }
728
729 #[test]
730 fn simple_glyph_open_path() {
731 let mut path = BezPath::new();
732 path.move_to((20., -100.));
733 path.quad_to((1337., 1338.), (-50., -69.0));
734 path.quad_to((13., 255.), (-255., 256.));
735 path.line_to((20., -100.));
738
739 let glyph = SimpleGlyph::from_bezpath(&path).unwrap();
740 let bytes = crate::dump_table(&glyph).unwrap();
741 let read = read_fonts::tables::glyf::SimpleGlyph::read(bytes.as_slice().into()).unwrap();
742 assert_eq!(read.number_of_contours(), 1);
743 assert_eq!(read.num_points(), 6);
744 assert_eq!(read.end_pts_of_contours(), &[5]);
745 let points = read.points().collect::<Vec<_>>();
746 assert_eq!(points[0].x, 20);
747 assert_eq!(points[0].y, -100);
748 assert!(points[0].on_curve);
749 assert_eq!(points[1].x, 1337);
750 assert_eq!(points[1].y, 1338);
751 assert!(!points[1].on_curve);
752 assert_eq!(points[4].x, -255);
753 assert_eq!(points[4].y, 256);
754 assert!(points[4].on_curve);
755 assert_eq!(points[5].x, 20);
756 assert_eq!(points[5].y, -100);
757 assert!(points[5].on_curve);
758 }
759
760 #[test]
761 fn simple_glyph_closed_path_implicit_vs_explicit_closing_line() {
762 let mut path1 = BezPath::new();
763 path1.move_to((20., -100.));
764 path1.quad_to((1337., 1338.), (-50., -69.0));
765 path1.quad_to((13., 255.), (-255., 256.));
766 path1.close_path();
767
768 let mut path2 = BezPath::new();
769 path2.move_to((20., -100.));
770 path2.quad_to((1337., 1338.), (-50., -69.0));
771 path2.quad_to((13., 255.), (-255., 256.));
772 path2.line_to((20., -100.));
775 path2.close_path();
776
777 for path in &[path1, path2] {
778 let glyph = SimpleGlyph::from_bezpath(path).unwrap();
779 let bytes = crate::dump_table(&glyph).unwrap();
780 let read =
781 read_fonts::tables::glyf::SimpleGlyph::read(bytes.as_slice().into()).unwrap();
782 assert_eq!(read.number_of_contours(), 1);
783 assert_eq!(read.num_points(), 5);
784 assert_eq!(read.end_pts_of_contours(), &[4]);
785 let points = read.points().collect::<Vec<_>>();
786 assert_eq!(points[0].x, 20);
787 assert_eq!(points[0].y, -100);
788 assert!(points[0].on_curve);
789 assert_eq!(points[1].x, 1337);
790 assert_eq!(points[1].y, 1338);
791 assert!(!points[1].on_curve);
792 assert_eq!(points[4].x, -255);
793 assert_eq!(points[4].y, 256);
794 assert!(points[4].on_curve);
795 }
796 }
797
798 #[test]
799 fn keep_single_point_contours() {
800 let mut path = BezPath::new();
802 path.move_to((0.0, 0.0));
803 path.move_to((1.0, 2.0));
805 path.close_path();
806
807 let glyph = SimpleGlyph::from_bezpath(&path).unwrap();
808 let bytes = crate::dump_table(&glyph).unwrap();
809 let read = read_fonts::tables::glyf::SimpleGlyph::read(bytes.as_slice().into()).unwrap();
810 assert_eq!(read.number_of_contours(), 2);
811 assert_eq!(read.num_points(), 2);
812 assert_eq!(read.end_pts_of_contours(), &[0, 1]);
813 let points = read.points().collect::<Vec<_>>();
814 assert_eq!(points[0].x, 0);
815 assert_eq!(points[0].y, 0);
816 assert!(points[0].on_curve);
817 assert_eq!(points[1].x, 1);
818 assert_eq!(points[1].y, 2);
819 assert!(points[0].on_curve);
820 }
821
822 #[test]
823 fn compile_repeatable_flags() {
824 let mut path = BezPath::new();
825 path.move_to((20., -100.));
826 path.line_to((25., -90.));
827 path.line_to((50., -69.));
828 path.line_to((80., -20.));
829
830 let glyph = SimpleGlyph::from_bezpath(&path).unwrap();
831 let flags = glyph
832 .compute_point_deltas()
833 .map(|x| x.0)
834 .collect::<Vec<_>>();
835 let r_flags = RepeatableFlag::iter_from_flags(flags.iter().copied()).collect::<Vec<_>>();
836
837 assert_eq!(r_flags.len(), 2, "{r_flags:?}");
838 let bytes = crate::dump_table(&glyph).unwrap();
839 let read = read_fonts::tables::glyf::SimpleGlyph::read(bytes.as_slice().into()).unwrap();
840 assert_eq!(read.number_of_contours(), 1);
841 assert_eq!(read.num_points(), 4);
842 assert_eq!(read.end_pts_of_contours(), &[3]);
843 let points = read.points().collect::<Vec<_>>();
844 assert_eq!(points[0].x, 20);
845 assert_eq!(points[0].y, -100);
846 assert_eq!(points[1].x, 25);
847 assert_eq!(points[1].y, -90);
848 assert_eq!(points[2].x, 50);
849 assert_eq!(points[2].y, -69);
850 assert_eq!(points[3].x, 80);
851 assert_eq!(points[3].y, -20);
852 }
853
854 #[test]
855 fn simple_glyphs_from_kurbo_unequal_number_of_elements() {
856 let mut path1 = BezPath::new();
857 path1.move_to((0., 0.));
858 path1.line_to((1., 1.));
859 path1.line_to((2., 2.));
860 path1.line_to((0., 0.));
861 path1.close_path();
862 assert_eq!(path1.elements().len(), 5);
863
864 let mut path2 = BezPath::new();
865 path2.move_to((3., 3.));
866 path2.line_to((4., 4.));
867 path2.line_to((5., 5.));
868 path2.line_to((6., 6.));
869 path2.line_to((3., 3.));
870 path2.close_path();
871 assert_eq!(path2.elements().len(), 6);
872
873 let err = simple_glyphs_from_kurbo(&[path1, path2]).unwrap_err();
874 assert!(matches!(err, MalformedPath::UnequalNumberOfElements(_)));
875 assert_eq!(format!("{:?}", err), "UnequalNumberOfElements([5, 6])");
876 }
877
878 #[test]
879 fn simple_glyphs_from_kurbo_inconsistent_path_elements() {
880 let mut path1 = BezPath::new();
881 path1.move_to((0., 0.));
882 path1.line_to((1., 1.));
883 path1.quad_to((2., 2.), (0., 0.));
884 path1.close_path();
885 let mut path2 = BezPath::new();
886 path2.move_to((3., 3.));
887 path2.quad_to((4., 4.), (5., 5.)); path2.line_to((3., 3.));
889 path2.close_path();
890
891 let err = simple_glyphs_from_kurbo(&[path1, path2]).unwrap_err();
892 assert!(matches!(err, MalformedPath::InconsistentPathElements(1, _)));
893 assert_eq!(
894 format!("{:?}", err),
895 "InconsistentPathElements(1, [\"L\", \"Q\"])"
896 );
897 }
898
899 fn make_interpolatable_paths(
920 num_paths: usize,
921 el_types: &str,
922 last_pt_equal_move: bool,
923 ) -> Vec<BezPath> {
924 let mut paths = Vec::new();
925 let mut start = 0.0;
928 let mut points = std::iter::from_fn(move || {
929 let value = start;
930 start += 1.0;
931 Some((value, value))
932 });
933 let el_types = el_types.chars().collect::<Vec<_>>();
934 assert!(!el_types.is_empty());
935 for _ in 0..num_paths {
936 let mut path = BezPath::new();
937 let mut start_pt = None;
938 let mut el_types_iter = el_types.iter().peekable();
940 while let Some(&el_type) = el_types_iter.next() {
941 let next_el_type = el_types_iter.peek().map(|x| **x).unwrap_or('M');
942 match el_type {
943 'M' => {
944 start_pt = points.next();
945 path.move_to(start_pt.unwrap());
946 }
947 'L' => {
948 if matches!(next_el_type, 'Z' | 'M') && last_pt_equal_move {
949 path.line_to(start_pt.unwrap());
950 } else {
951 path.line_to(points.next().unwrap());
952 }
953 }
954 'Q' => {
955 let p1 = points.next().unwrap();
956 let p2 = if matches!(next_el_type, 'Z' | 'M') && last_pt_equal_move {
957 start_pt.unwrap()
958 } else {
959 points.next().unwrap()
960 };
961 path.quad_to(p1, p2);
962 }
963 'Z' => {
964 path.close_path();
965 start_pt = None;
966 }
967 _ => panic!("Unsupported element type {:?}", el_type),
968 }
969 }
970 paths.push(path);
971 }
972 assert_eq!(paths.len(), num_paths);
973 paths
974 }
975
976 fn assert_contour_points(glyph: &SimpleGlyph, all_points: Vec<Vec<CurvePoint>>) {
977 let expected_num_contours = all_points.len();
978 assert_eq!(glyph.contours.len(), expected_num_contours);
979 for (contour, expected_points) in glyph.contours.iter().zip(all_points.iter()) {
980 let points = contour.iter().copied().collect::<Vec<_>>();
981 assert_eq!(points, *expected_points);
982 }
983 }
984
985 #[test]
986 fn simple_glyphs_from_kurbo_3_lines_closed() {
987 let paths = make_interpolatable_paths(2, "MLLLZ", true);
989 let glyphs = simple_glyphs_from_kurbo(&paths).unwrap();
990
991 assert_contour_points(
992 &glyphs[0],
993 vec![vec![
994 CurvePoint::on_curve(0, 0),
995 CurvePoint::on_curve(1, 1),
996 CurvePoint::on_curve(2, 2),
997 ]],
998 );
999 assert_contour_points(
1000 &glyphs[1],
1001 vec![vec![
1002 CurvePoint::on_curve(3, 3),
1003 CurvePoint::on_curve(4, 4),
1004 CurvePoint::on_curve(5, 5),
1005 ]],
1006 );
1007 }
1008
1009 #[test]
1010 fn simple_glyphs_from_kurbo_3_lines_implicitly_closed() {
1011 let paths = make_interpolatable_paths(2, "MLLZ", false);
1013 let glyphs = simple_glyphs_from_kurbo(&paths).unwrap();
1014
1015 assert_contour_points(
1016 &glyphs[0],
1017 vec![vec![
1018 CurvePoint::on_curve(0, 0),
1019 CurvePoint::on_curve(1, 1),
1020 CurvePoint::on_curve(2, 2),
1021 ]],
1022 );
1023 assert_contour_points(
1024 &glyphs[1],
1025 vec![vec![
1026 CurvePoint::on_curve(3, 3),
1027 CurvePoint::on_curve(4, 4),
1028 CurvePoint::on_curve(5, 5),
1029 ]],
1030 );
1031 }
1032
1033 #[test]
1034 fn simple_glyphs_from_kurbo_2_quads_closed() {
1035 let paths = make_interpolatable_paths(2, "MQQZ", true);
1040 let glyphs = simple_glyphs_from_kurbo(&paths).unwrap();
1041
1042 assert_contour_points(
1043 &glyphs[0],
1044 vec![vec![
1045 CurvePoint::on_curve(0, 0),
1046 CurvePoint::off_curve(1, 1),
1047 CurvePoint::off_curve(3, 3),
1049 ]],
1050 );
1051 assert_contour_points(
1052 &glyphs[1],
1053 vec![vec![
1054 CurvePoint::on_curve(4, 4),
1055 CurvePoint::off_curve(5, 5),
1056 CurvePoint::off_curve(7, 7),
1058 ]],
1059 );
1060 }
1061
1062 #[test]
1063 fn simple_glyphs_from_kurbo_2_quads_1_line_implicitly_closed() {
1064 let paths = make_interpolatable_paths(2, "MQQZ", false);
1068 let glyphs = simple_glyphs_from_kurbo(&paths).unwrap();
1069
1070 assert_contour_points(
1071 &glyphs[0],
1072 vec![vec![
1073 CurvePoint::on_curve(0, 0),
1074 CurvePoint::off_curve(1, 1),
1075 CurvePoint::off_curve(3, 3),
1077 CurvePoint::on_curve(4, 4),
1078 ]],
1079 );
1080 assert_contour_points(
1081 &glyphs[1],
1082 vec![vec![
1083 CurvePoint::on_curve(5, 5),
1084 CurvePoint::off_curve(6, 6),
1085 CurvePoint::off_curve(8, 8),
1087 CurvePoint::on_curve(9, 9),
1088 ]],
1089 );
1090 }
1091
1092 #[test]
1093 fn simple_glyphs_from_kurbo_multiple_contours_mixed_segments() {
1094 let paths = make_interpolatable_paths(4, "MLQQZMQLQLZ", true);
1096 let glyphs = simple_glyphs_from_kurbo(&paths).unwrap();
1097
1098 assert_contour_points(
1099 &glyphs[0],
1100 vec![
1101 vec![
1102 CurvePoint::on_curve(0, 0),
1103 CurvePoint::on_curve(1, 1),
1104 CurvePoint::off_curve(2, 2),
1105 CurvePoint::off_curve(4, 4),
1107 ],
1108 vec![
1109 CurvePoint::on_curve(5, 5),
1110 CurvePoint::off_curve(6, 6),
1111 CurvePoint::on_curve(7, 7),
1112 CurvePoint::on_curve(8, 8),
1113 CurvePoint::off_curve(9, 9),
1114 CurvePoint::on_curve(10, 10),
1115 ],
1116 ],
1117 );
1118 }
1119
1120 #[test]
1121 fn simple_glyphs_from_kurbo_all_quad_off_curves() {
1122 let mut path1 = BezPath::new();
1125 path1.move_to((0.0, 1.0));
1126 path1.quad_to((1.0, 1.0), (1.0, 0.0));
1127 path1.quad_to((1.0, -1.0), (0.0, -1.0));
1128 path1.quad_to((-1.0, -1.0), (-1.0, 0.0));
1129 path1.quad_to((-1.0, 1.0), (0.0, 1.0));
1130 path1.close_path();
1131
1132 let mut path2 = path1.clone();
1133 path2.apply_affine(Affine::scale(2.0));
1134
1135 let glyphs = simple_glyphs_from_kurbo(&[path1, path2]).unwrap();
1136
1137 assert_contour_points(
1138 &glyphs[0],
1139 vec![vec![
1140 CurvePoint::off_curve(1, 1),
1141 CurvePoint::off_curve(1, -1),
1142 CurvePoint::off_curve(-1, -1),
1143 CurvePoint::off_curve(-1, 1),
1144 ]],
1145 );
1146 assert_contour_points(
1147 &glyphs[1],
1148 vec![vec![
1149 CurvePoint::off_curve(2, 2),
1150 CurvePoint::off_curve(2, -2),
1151 CurvePoint::off_curve(-2, -2),
1152 CurvePoint::off_curve(-2, 2),
1153 ]],
1154 );
1155 }
1156
1157 #[test]
1158 fn simple_glyphs_from_kurbo_keep_on_curve_unless_impliable_for_all() {
1159 let mut path1 = BezPath::new();
1160 path1.move_to((0.0, 0.0));
1161 path1.quad_to((0.0, 1.0), (1.0, 1.0)); path1.quad_to((2.0, 1.0), (2.0, 0.0));
1163 path1.line_to((0.0, 0.0));
1164 path1.close_path();
1165
1166 assert_contour_points(
1169 &SimpleGlyph::from_bezpath(&path1).unwrap(),
1170 vec![vec![
1171 CurvePoint::on_curve(0, 0),
1172 CurvePoint::off_curve(0, 1),
1173 CurvePoint::off_curve(2, 1),
1175 CurvePoint::on_curve(2, 0),
1176 ]],
1177 );
1178
1179 let mut path2 = BezPath::new();
1180 path2.move_to((0.0, 0.0));
1181 path2.quad_to((0.0, 2.0), (2.0, 2.0)); path2.quad_to((3.0, 2.0), (3.0, 0.0));
1183 path2.line_to((0.0, 0.0));
1184 path2.close_path();
1185
1186 let glyphs = simple_glyphs_from_kurbo(&[path1, path2]).unwrap();
1187
1188 assert_contour_points(
1191 &glyphs[0],
1192 vec![vec![
1193 CurvePoint::on_curve(0, 0),
1194 CurvePoint::off_curve(0, 1),
1195 CurvePoint::on_curve(1, 1), CurvePoint::off_curve(2, 1),
1197 CurvePoint::on_curve(2, 0),
1198 ]],
1199 );
1200 assert_contour_points(
1201 &glyphs[1],
1202 vec![vec![
1203 CurvePoint::on_curve(0, 0),
1204 CurvePoint::off_curve(0, 2),
1205 CurvePoint::on_curve(2, 2), CurvePoint::off_curve(3, 2),
1207 CurvePoint::on_curve(3, 0),
1208 ]],
1209 );
1210 }
1211
1212 #[test]
1213 fn simple_glyphs_from_kurbo_2_lines_open() {
1214 let paths = make_interpolatable_paths(2, "MLL", false);
1217 let glyphs = simple_glyphs_from_kurbo(&paths).unwrap();
1218
1219 assert_contour_points(
1220 &glyphs[0],
1221 vec![vec![
1222 CurvePoint::on_curve(0, 0),
1223 CurvePoint::on_curve(1, 1),
1224 CurvePoint::on_curve(2, 2),
1225 ]],
1226 );
1227 assert_contour_points(
1228 &glyphs[1],
1229 vec![vec![
1230 CurvePoint::on_curve(3, 3),
1231 CurvePoint::on_curve(4, 4),
1232 CurvePoint::on_curve(5, 5),
1233 ]],
1234 );
1235 }
1236
1237 #[test]
1238 fn simple_glyphs_from_kurbo_3_lines_open_duplicate_last_pt() {
1239 let paths = make_interpolatable_paths(2, "MLLL", true);
1244 let glyphs = simple_glyphs_from_kurbo(&paths).unwrap();
1245
1246 assert_contour_points(
1247 &glyphs[0],
1248 vec![vec![
1249 CurvePoint::on_curve(0, 0),
1250 CurvePoint::on_curve(1, 1),
1251 CurvePoint::on_curve(2, 2),
1252 CurvePoint::on_curve(0, 0),
1253 ]],
1254 );
1255 assert_contour_points(
1256 &glyphs[1],
1257 vec![vec![
1258 CurvePoint::on_curve(3, 3),
1259 CurvePoint::on_curve(4, 4),
1260 CurvePoint::on_curve(5, 5),
1261 CurvePoint::on_curve(3, 3),
1262 ]],
1263 );
1264 }
1265
1266 #[test]
1267 fn simple_glyphs_from_kurbo_4_lines_closed_duplicate_last_pt() {
1268 for implicit_closing_line in &[true, false] {
1269 let mut path1 = BezPath::new();
1273 path1.move_to((0.0, 0.0));
1274 path1.line_to((0.0, 1.0));
1275 path1.line_to((1.0, 1.0));
1276 path1.line_to((0.0, 0.0));
1277 if !*implicit_closing_line {
1278 path1.line_to((0.0, 0.0));
1279 }
1280 path1.close_path();
1281
1282 let mut path2 = BezPath::new();
1283 path2.move_to((0.0, 0.0));
1284 path2.line_to((0.0, 2.0));
1285 path2.line_to((2.0, 2.0));
1286 path2.line_to((2.0, 0.0));
1287 if !*implicit_closing_line {
1288 path2.line_to((0.0, 0.0));
1289 }
1290 path2.close_path();
1291
1292 let glyphs = simple_glyphs_from_kurbo(&[path1, path2]).unwrap();
1293
1294 assert_contour_points(
1295 &glyphs[0],
1296 vec![vec![
1297 CurvePoint::on_curve(0, 0),
1298 CurvePoint::on_curve(0, 1),
1299 CurvePoint::on_curve(1, 1),
1300 CurvePoint::on_curve(0, 0), ]],
1302 );
1303 assert_contour_points(
1304 &glyphs[1],
1305 vec![vec![
1306 CurvePoint::on_curve(0, 0),
1307 CurvePoint::on_curve(0, 2),
1308 CurvePoint::on_curve(2, 2),
1309 CurvePoint::on_curve(2, 0),
1310 ]],
1311 );
1312 }
1313 }
1314
1315 #[test]
1316 fn simple_glyphs_from_kurbo_2_quads_1_line_closed_duplicate_last_pt() {
1317 for implicit_closing_line in &[true, false] {
1318 let mut path1 = BezPath::new();
1321 path1.move_to((0.0, 0.0));
1322 path1.quad_to((0.0, 1.0), (1.0, 1.0));
1323 path1.quad_to((1.0, 0.0), (0.0, 0.0));
1324 if !*implicit_closing_line {
1325 path1.line_to((0.0, 0.0));
1326 }
1327 path1.close_path();
1328
1329 let mut path2 = BezPath::new();
1330 path2.move_to((0.0, 0.0));
1331 path2.quad_to((0.0, 2.0), (2.0, 2.0));
1332 path2.quad_to((2.0, 1.0), (1.0, 0.0));
1333 if !*implicit_closing_line {
1334 path2.line_to((0.0, 0.0));
1335 }
1336 path2.close_path();
1337
1338 let glyphs = simple_glyphs_from_kurbo(&[path1, path2]).unwrap();
1339
1340 assert_contour_points(
1341 &glyphs[0],
1342 vec![vec![
1343 CurvePoint::on_curve(0, 0),
1344 CurvePoint::off_curve(0, 1),
1345 CurvePoint::on_curve(1, 1),
1346 CurvePoint::off_curve(1, 0),
1347 CurvePoint::on_curve(0, 0), ]],
1349 );
1350 assert_contour_points(
1351 &glyphs[1],
1352 vec![vec![
1353 CurvePoint::on_curve(0, 0),
1354 CurvePoint::off_curve(0, 2),
1355 CurvePoint::on_curve(2, 2),
1356 CurvePoint::off_curve(2, 1),
1357 CurvePoint::on_curve(1, 0),
1358 ]],
1359 );
1360 }
1361 }
1362
1363 #[test]
1364 fn simple_glyph_from_kurbo_equidistant_but_not_collinear_points() {
1365 let mut path = BezPath::new();
1366 path.move_to((0.0, 0.0));
1367 path.quad_to((2.0, 2.0), (4.0, 3.0));
1368 path.quad_to((6.0, 2.0), (8.0, 0.0));
1369 path.close_path();
1370
1371 let glyph = SimpleGlyph::from_bezpath(&path).unwrap();
1372
1373 assert_contour_points(
1374 &glyph,
1375 vec![vec![
1376 CurvePoint::on_curve(0, 0),
1377 CurvePoint::off_curve(2, 2),
1378 CurvePoint::on_curve(4, 3),
1382 CurvePoint::off_curve(6, 2),
1383 CurvePoint::on_curve(8, 0),
1384 ]],
1385 );
1386 }
1387
1388 #[test]
1389 fn repeatable_flags_basic() {
1390 let flags = [
1391 SimpleGlyphFlags::ON_CURVE_POINT,
1392 SimpleGlyphFlags::X_SHORT_VECTOR,
1393 SimpleGlyphFlags::X_SHORT_VECTOR,
1394 ];
1395 let repeatable = RepeatableFlag::iter_from_flags(flags).collect::<Vec<_>>();
1396 let expected = flags
1397 .into_iter()
1398 .map(|flag| RepeatableFlag { flag, repeat: 0 })
1399 .collect::<Vec<_>>();
1400
1401 assert_eq!(repeatable, expected);
1404 }
1405
1406 #[test]
1407 fn repeatable_flags_repeats() {
1408 let some_dupes = std::iter::repeat(SimpleGlyphFlags::ON_CURVE_POINT).take(4);
1409 let many_dupes = std::iter::repeat(SimpleGlyphFlags::Y_SHORT_VECTOR).take(257);
1410 let repeatable =
1411 RepeatableFlag::iter_from_flags(some_dupes.chain(many_dupes)).collect::<Vec<_>>();
1412 assert_eq!(repeatable.len(), 3);
1413 assert_eq!(
1414 repeatable[0],
1415 RepeatableFlag {
1416 flag: SimpleGlyphFlags::ON_CURVE_POINT | SimpleGlyphFlags::REPEAT_FLAG,
1417 repeat: 3
1418 }
1419 );
1420 assert_eq!(
1421 repeatable[1],
1422 RepeatableFlag {
1423 flag: SimpleGlyphFlags::Y_SHORT_VECTOR | SimpleGlyphFlags::REPEAT_FLAG,
1424 repeat: u8::MAX,
1425 }
1426 );
1427
1428 assert_eq!(
1429 repeatable[2],
1430 RepeatableFlag {
1431 flag: SimpleGlyphFlags::Y_SHORT_VECTOR,
1432 repeat: 0,
1433 }
1434 )
1435 }
1436
1437 #[test]
1438 fn mid_points() {
1439 assert!(is_mid_point(
1441 kurbo::Point::new(0.0, 0.0),
1442 kurbo::Point::new(1.0, 1.0),
1443 kurbo::Point::new(2.0, 2.0)
1444 ));
1445 assert!(is_mid_point(
1447 kurbo::Point::new(0.5, 0.5),
1448 kurbo::Point::new(3.0, 3.0),
1449 kurbo::Point::new(5.5, 5.5)
1450 ));
1451 assert!(is_mid_point(
1453 kurbo::Point::new(0.0, 0.0),
1454 kurbo::Point::new(1.00001, 0.99999),
1455 kurbo::Point::new(2.0, 2.0)
1456 ));
1457 assert!(is_mid_point(
1459 kurbo::Point::new(0.0, 0.0),
1460 kurbo::Point::new(-1.499999, 0.500001),
1461 kurbo::Point::new(-2.0, 2.0)
1462 ));
1463 assert!(!is_mid_point(
1465 kurbo::Point::new(0.0, 0.0),
1466 kurbo::Point::new(1.0, 1.5),
1467 kurbo::Point::new(2.0, 2.0)
1468 ));
1469 }
1470}