read_fonts/tables/
glyf.rs

1//! The [glyf (Glyph Data)](https://docs.microsoft.com/en-us/typography/opentype/spec/glyf) table
2
3pub mod bytecode;
4
5use bytemuck::AnyBitPattern;
6use core::ops::{Add, AddAssign, Div, Mul, MulAssign, Sub};
7use types::{F26Dot6, Point};
8
9include!("../../generated/generated_glyf.rs");
10
11/// Marker bits for point flags that are set during variation delta
12/// processing and hinting.
13#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
14pub struct PointMarker(u8);
15
16impl PointMarker {
17    /// Marker for points that have an explicit delta in a glyph variation
18    /// tuple.
19    pub const HAS_DELTA: Self = Self(0x4);
20
21    /// Marker that signifies that the x coordinate of a point has been touched
22    /// by an IUP hinting instruction.
23    pub const TOUCHED_X: Self = Self(0x10);
24
25    /// Marker that signifies that the y coordinate of a point has been touched
26    /// by an IUP hinting instruction.
27    pub const TOUCHED_Y: Self = Self(0x20);
28
29    /// Marker that signifies that the both coordinates of a point has been touched
30    /// by an IUP hinting instruction.
31    pub const TOUCHED: Self = Self(Self::TOUCHED_X.0 | Self::TOUCHED_Y.0);
32
33    /// Marks this point as a candidate for weak interpolation.
34    ///
35    /// Used by the automatic hinter.
36    pub const WEAK_INTERPOLATION: Self = Self(0x2);
37
38    /// Marker for points where the distance to next point is very small.
39    ///
40    /// Used by the automatic hinter.
41    pub const NEAR: PointMarker = Self(0x8);
42}
43
44impl core::ops::BitOr for PointMarker {
45    type Output = Self;
46
47    fn bitor(self, rhs: Self) -> Self::Output {
48        Self(self.0 | rhs.0)
49    }
50}
51
52/// Flags describing the properties of a point.
53///
54/// Some properties, such as on- and off-curve flags are intrinsic to the point
55/// itself. Others, designated as markers are set and cleared while an outline
56/// is being transformed during variation application and hinting.
57#[derive(
58    Copy, Clone, PartialEq, Eq, Default, Debug, bytemuck::AnyBitPattern, bytemuck::NoUninit,
59)]
60#[repr(transparent)]
61pub struct PointFlags(u8);
62
63impl PointFlags {
64    // Note: OFF_CURVE_QUAD is signified by the absence of both ON_CURVE
65    // and OFF_CURVE_CUBIC bits, per FreeType and TrueType convention.
66    const ON_CURVE: u8 = SimpleGlyphFlags::ON_CURVE_POINT.bits;
67    const OFF_CURVE_CUBIC: u8 = SimpleGlyphFlags::CUBIC.bits;
68    const CURVE_MASK: u8 = Self::ON_CURVE | Self::OFF_CURVE_CUBIC;
69
70    /// Creates a new on curve point flag.
71    pub const fn on_curve() -> Self {
72        Self(Self::ON_CURVE)
73    }
74
75    /// Creates a new off curve quadratic point flag.
76    pub const fn off_curve_quad() -> Self {
77        Self(0)
78    }
79
80    /// Creates a new off curve cubic point flag.
81    pub const fn off_curve_cubic() -> Self {
82        Self(Self::OFF_CURVE_CUBIC)
83    }
84
85    /// Creates a point flag from the given bits. These are truncated
86    /// to ignore markers.
87    pub const fn from_bits(bits: u8) -> Self {
88        Self(bits & Self::CURVE_MASK)
89    }
90
91    /// Returns true if this is an on curve point.
92    #[inline]
93    pub const fn is_on_curve(self) -> bool {
94        self.0 & Self::ON_CURVE != 0
95    }
96
97    /// Returns true if this is an off curve quadratic point.
98    #[inline]
99    pub const fn is_off_curve_quad(self) -> bool {
100        self.0 & Self::CURVE_MASK == 0
101    }
102
103    /// Returns true if this is an off curve cubic point.
104    #[inline]
105    pub const fn is_off_curve_cubic(self) -> bool {
106        self.0 & Self::OFF_CURVE_CUBIC != 0
107    }
108
109    pub const fn is_off_curve(self) -> bool {
110        self.is_off_curve_quad() || self.is_off_curve_cubic()
111    }
112
113    /// Flips the state of the on curve flag.
114    ///
115    /// This is used for the TrueType `FLIPPT` instruction.
116    pub fn flip_on_curve(&mut self) {
117        self.0 ^= 1;
118    }
119
120    /// Enables the on curve flag.
121    ///
122    /// This is used for the TrueType `FLIPRGON` instruction.
123    pub fn set_on_curve(&mut self) {
124        self.0 |= Self::ON_CURVE;
125    }
126
127    /// Disables the on curve flag.
128    ///
129    /// This is used for the TrueType `FLIPRGOFF` instruction.
130    pub fn clear_on_curve(&mut self) {
131        self.0 &= !Self::ON_CURVE;
132    }
133
134    /// Returns true if the given marker is set for this point.
135    pub fn has_marker(self, marker: PointMarker) -> bool {
136        self.0 & marker.0 != 0
137    }
138
139    /// Applies the given marker to this point.
140    pub fn set_marker(&mut self, marker: PointMarker) {
141        self.0 |= marker.0;
142    }
143
144    /// Clears the given marker for this point.
145    pub fn clear_marker(&mut self, marker: PointMarker) {
146        self.0 &= !marker.0
147    }
148
149    /// Returns a copy with all markers cleared.
150    pub const fn without_markers(self) -> Self {
151        Self(self.0 & Self::CURVE_MASK)
152    }
153
154    /// Returns the underlying bits.
155    pub const fn to_bits(self) -> u8 {
156        self.0
157    }
158}
159
160/// Trait for types that are usable for TrueType point coordinates.
161pub trait PointCoord:
162    Copy
163    + Default
164    // You could bytemuck with me
165    + AnyBitPattern
166    // You could compare me
167    + PartialEq
168    + PartialOrd
169    // You could do math with me
170    + Add<Output = Self>
171    + AddAssign
172    + Sub<Output = Self>
173    + Div<Output = Self>
174    + Mul<Output = Self>
175    + MulAssign {
176    fn from_fixed(x: Fixed) -> Self;
177    fn from_i32(x: i32) -> Self;
178    fn to_f32(self) -> f32;
179    fn midpoint(self, other: Self) -> Self;
180}
181
182impl<'a> SimpleGlyph<'a> {
183    /// Returns the total number of points.
184    pub fn num_points(&self) -> usize {
185        self.end_pts_of_contours()
186            .last()
187            .map(|last| last.get() as usize + 1)
188            .unwrap_or(0)
189    }
190
191    /// Returns true if the contours in the simple glyph may overlap.
192    pub fn has_overlapping_contours(&self) -> bool {
193        // Checks the first flag for the OVERLAP_SIMPLE bit.
194        // Spec says: "When used, it must be set on the first flag byte for
195        // the glyph."
196        FontData::new(self.glyph_data())
197            .read_at::<SimpleGlyphFlags>(0)
198            .map(|flag| flag.contains(SimpleGlyphFlags::OVERLAP_SIMPLE))
199            .unwrap_or_default()
200    }
201
202    /// Reads points and flags into the provided buffers.
203    ///
204    /// Drops all flag bits except on-curve. The lengths of the buffers must be
205    /// equal to the value returned by [num_points](Self::num_points).
206    ///
207    /// ## Performance
208    ///
209    /// As the name implies, this is faster than using the iterator returned by
210    /// [points](Self::points) so should be used when it is possible to
211    /// preallocate buffers.
212    pub fn read_points_fast<C: PointCoord>(
213        &self,
214        points: &mut [Point<C>],
215        flags: &mut [PointFlags],
216    ) -> Result<(), ReadError> {
217        let n_points = self.num_points();
218        if points.len() != n_points || flags.len() != n_points {
219            return Err(ReadError::InvalidArrayLen);
220        }
221        let mut cursor = FontData::new(self.glyph_data()).cursor();
222        let mut i = 0;
223        while i < n_points {
224            let flag = cursor.read::<SimpleGlyphFlags>()?;
225            let flag_bits = flag.bits();
226            if flag.contains(SimpleGlyphFlags::REPEAT_FLAG) {
227                let count = (cursor.read::<u8>()? as usize + 1).min(n_points - i);
228                for f in &mut flags[i..i + count] {
229                    f.0 = flag_bits;
230                }
231                i += count;
232            } else {
233                flags[i].0 = flag_bits;
234                i += 1;
235            }
236        }
237        let mut x = 0i32;
238        for (&point_flags, point) in flags.iter().zip(points.as_mut()) {
239            let mut delta = 0i32;
240            let flag = SimpleGlyphFlags::from_bits_truncate(point_flags.0);
241            if flag.contains(SimpleGlyphFlags::X_SHORT_VECTOR) {
242                delta = cursor.read::<u8>()? as i32;
243                if !flag.contains(SimpleGlyphFlags::X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) {
244                    delta = -delta;
245                }
246            } else if !flag.contains(SimpleGlyphFlags::X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) {
247                delta = cursor.read::<i16>()? as i32;
248            }
249            x = x.wrapping_add(delta);
250            point.x = C::from_i32(x);
251        }
252        let mut y = 0i32;
253        for (point_flags, point) in flags.iter_mut().zip(points.as_mut()) {
254            let mut delta = 0i32;
255            let flag = SimpleGlyphFlags::from_bits_truncate(point_flags.0);
256            if flag.contains(SimpleGlyphFlags::Y_SHORT_VECTOR) {
257                delta = cursor.read::<u8>()? as i32;
258                if !flag.contains(SimpleGlyphFlags::Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) {
259                    delta = -delta;
260                }
261            } else if !flag.contains(SimpleGlyphFlags::Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) {
262                delta = cursor.read::<i16>()? as i32;
263            }
264            y = y.wrapping_add(delta);
265            point.y = C::from_i32(y);
266            let flags_mask = if cfg!(feature = "spec_next") {
267                PointFlags::CURVE_MASK
268            } else {
269                // Drop the cubic bit if the spec_next feature is not enabled
270                PointFlags::ON_CURVE
271            };
272            point_flags.0 &= flags_mask;
273        }
274        Ok(())
275    }
276
277    /// Returns an iterator over the points in the glyph.
278    ///
279    /// ## Performance
280    ///
281    /// This is slower than [read_points_fast](Self::read_points_fast) but
282    /// provides access to the points without requiring a preallocated buffer.
283    pub fn points(&self) -> impl Iterator<Item = CurvePoint> + 'a + Clone {
284        self.points_impl()
285            .unwrap_or_else(|| PointIter::new(&[], &[], &[]))
286    }
287
288    fn points_impl(&self) -> Option<PointIter<'a>> {
289        let end_points = self.end_pts_of_contours();
290        let n_points = end_points.last()?.get().checked_add(1)?;
291        let data = self.glyph_data();
292        let lens = resolve_coords_len(data, n_points).ok()?;
293        let total_len = lens.flags + lens.x_coords + lens.y_coords;
294        if data.len() < total_len as usize {
295            return None;
296        }
297
298        let (flags, data) = data.split_at(lens.flags as usize);
299        let (x_coords, y_coords) = data.split_at(lens.x_coords as usize);
300
301        Some(PointIter::new(flags, x_coords, y_coords))
302    }
303}
304
305/// Point with an associated on-curve flag in a simple glyph.
306///
307/// This type is a simpler representation of the data in the blob.
308#[derive(Clone, Copy, Debug, PartialEq, Eq)]
309pub struct CurvePoint {
310    /// X coordinate.
311    pub x: i16,
312    /// Y coordinate.
313    pub y: i16,
314    /// True if this is an on-curve point.
315    pub on_curve: bool,
316}
317
318impl CurvePoint {
319    /// Construct a new `CurvePoint`
320    pub fn new(x: i16, y: i16, on_curve: bool) -> Self {
321        Self { x, y, on_curve }
322    }
323
324    /// Convenience method to construct an on-curve point
325    pub fn on_curve(x: i16, y: i16) -> Self {
326        Self::new(x, y, true)
327    }
328
329    /// Convenience method to construct an off-curve point
330    pub fn off_curve(x: i16, y: i16) -> Self {
331        Self::new(x, y, false)
332    }
333}
334
335#[derive(Clone)]
336struct PointIter<'a> {
337    flags: Cursor<'a>,
338    x_coords: Cursor<'a>,
339    y_coords: Cursor<'a>,
340    flag_repeats: u8,
341    cur_flags: SimpleGlyphFlags,
342    cur_x: i16,
343    cur_y: i16,
344}
345
346impl Iterator for PointIter<'_> {
347    type Item = CurvePoint;
348    fn next(&mut self) -> Option<Self::Item> {
349        self.advance_flags()?;
350        self.advance_points();
351        let is_on_curve = self.cur_flags.contains(SimpleGlyphFlags::ON_CURVE_POINT);
352        Some(CurvePoint::new(self.cur_x, self.cur_y, is_on_curve))
353    }
354}
355
356impl<'a> PointIter<'a> {
357    fn new(flags: &'a [u8], x_coords: &'a [u8], y_coords: &'a [u8]) -> Self {
358        Self {
359            flags: FontData::new(flags).cursor(),
360            x_coords: FontData::new(x_coords).cursor(),
361            y_coords: FontData::new(y_coords).cursor(),
362            flag_repeats: 0,
363            cur_flags: SimpleGlyphFlags::empty(),
364            cur_x: 0,
365            cur_y: 0,
366        }
367    }
368
369    fn advance_flags(&mut self) -> Option<()> {
370        if self.flag_repeats == 0 {
371            self.cur_flags = SimpleGlyphFlags::from_bits_truncate(self.flags.read().ok()?);
372            self.flag_repeats = self
373                .cur_flags
374                .contains(SimpleGlyphFlags::REPEAT_FLAG)
375                .then(|| self.flags.read().ok())
376                .flatten()
377                .unwrap_or(0)
378                + 1;
379        }
380        self.flag_repeats -= 1;
381        Some(())
382    }
383
384    fn advance_points(&mut self) {
385        let x_short = self.cur_flags.contains(SimpleGlyphFlags::X_SHORT_VECTOR);
386        let x_same_or_pos = self
387            .cur_flags
388            .contains(SimpleGlyphFlags::X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR);
389        let y_short = self.cur_flags.contains(SimpleGlyphFlags::Y_SHORT_VECTOR);
390        let y_same_or_pos = self
391            .cur_flags
392            .contains(SimpleGlyphFlags::Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR);
393
394        let delta_x = match (x_short, x_same_or_pos) {
395            (true, false) => -(self.x_coords.read::<u8>().unwrap_or(0) as i16),
396            (true, true) => self.x_coords.read::<u8>().unwrap_or(0) as i16,
397            (false, false) => self.x_coords.read::<i16>().unwrap_or(0),
398            _ => 0,
399        };
400
401        let delta_y = match (y_short, y_same_or_pos) {
402            (true, false) => -(self.y_coords.read::<u8>().unwrap_or(0) as i16),
403            (true, true) => self.y_coords.read::<u8>().unwrap_or(0) as i16,
404            (false, false) => self.y_coords.read::<i16>().unwrap_or(0),
405            _ => 0,
406        };
407
408        self.cur_x = self.cur_x.wrapping_add(delta_x);
409        self.cur_y = self.cur_y.wrapping_add(delta_y);
410    }
411}
412
413//taken from ttf_parser https://docs.rs/ttf-parser/latest/src/ttf_parser/tables/glyf.rs.html#1-677
414/// Resolves coordinate arrays length.
415///
416/// The length depends on *Simple Glyph Flags*, so we have to process them all to find it.
417fn resolve_coords_len(data: &[u8], points_total: u16) -> Result<FieldLengths, ReadError> {
418    let mut cursor = FontData::new(data).cursor();
419    let mut flags_left = u32::from(points_total);
420    //let mut repeats;
421    let mut x_coords_len = 0;
422    let mut y_coords_len = 0;
423    //let mut flags_seen = 0;
424    while flags_left > 0 {
425        let flags: SimpleGlyphFlags = cursor.read()?;
426
427        // The number of times a glyph point repeats.
428        let repeats = if flags.contains(SimpleGlyphFlags::REPEAT_FLAG) {
429            let repeats: u8 = cursor.read()?;
430            u32::from(repeats) + 1
431        } else {
432            1
433        };
434
435        if repeats > flags_left {
436            return Err(ReadError::MalformedData("repeat count too large in glyf"));
437        }
438
439        // Non-obfuscated code below.
440        // Branchless version is surprisingly faster.
441        //
442        // if flags.x_short() {
443        //     // Coordinate is 1 byte long.
444        //     x_coords_len += repeats;
445        // } else if !flags.x_is_same_or_positive_short() {
446        //     // Coordinate is 2 bytes long.
447        //     x_coords_len += repeats * 2;
448        // }
449        // if flags.y_short() {
450        //     // Coordinate is 1 byte long.
451        //     y_coords_len += repeats;
452        // } else if !flags.y_is_same_or_positive_short() {
453        //     // Coordinate is 2 bytes long.
454        //     y_coords_len += repeats * 2;
455        // }
456        let x_short = SimpleGlyphFlags::X_SHORT_VECTOR;
457        let x_long = SimpleGlyphFlags::X_SHORT_VECTOR
458            | SimpleGlyphFlags::X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR;
459        let y_short = SimpleGlyphFlags::Y_SHORT_VECTOR;
460        let y_long = SimpleGlyphFlags::Y_SHORT_VECTOR
461            | SimpleGlyphFlags::Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR;
462        x_coords_len += ((flags & x_short).bits() != 0) as u32 * repeats;
463        x_coords_len += ((flags & x_long).bits() == 0) as u32 * repeats * 2;
464
465        y_coords_len += ((flags & y_short).bits() != 0) as u32 * repeats;
466        y_coords_len += ((flags & y_long).bits() == 0) as u32 * repeats * 2;
467
468        flags_left -= repeats;
469    }
470
471    Ok(FieldLengths {
472        flags: cursor.position()? as u32,
473        x_coords: x_coords_len,
474        y_coords: y_coords_len,
475    })
476    //Some((flags_len, x_coords_len, y_coords_len))
477}
478
479struct FieldLengths {
480    flags: u32,
481    x_coords: u32,
482    y_coords: u32,
483}
484
485/// Transform for a composite component.
486#[derive(Clone, Copy, Debug, PartialEq, Eq)]
487pub struct Transform {
488    /// X scale factor.
489    pub xx: F2Dot14,
490    /// YX skew factor.
491    pub yx: F2Dot14,
492    /// XY skew factor.
493    pub xy: F2Dot14,
494    /// Y scale factor.
495    pub yy: F2Dot14,
496}
497
498impl Default for Transform {
499    fn default() -> Self {
500        Self {
501            xx: F2Dot14::from_f32(1.0),
502            yx: F2Dot14::from_f32(0.0),
503            xy: F2Dot14::from_f32(0.0),
504            yy: F2Dot14::from_f32(1.0),
505        }
506    }
507}
508
509/// A reference to another glyph. Part of [CompositeGlyph].
510#[derive(Clone, Debug, PartialEq, Eq)]
511pub struct Component {
512    /// Component flags.
513    pub flags: CompositeGlyphFlags,
514    /// Glyph identifier.
515    pub glyph: GlyphId16,
516    /// Anchor for component placement.
517    pub anchor: Anchor,
518    /// Component transformation matrix.
519    pub transform: Transform,
520}
521
522/// Anchor position for a composite component.
523#[derive(Clone, Copy, Debug, PartialEq, Eq)]
524pub enum Anchor {
525    Offset { x: i16, y: i16 },
526    Point { base: u16, component: u16 },
527}
528
529impl<'a> CompositeGlyph<'a> {
530    /// Returns an iterator over the components of the composite glyph.
531    pub fn components(&self) -> impl Iterator<Item = Component> + 'a + Clone {
532        ComponentIter {
533            cur_flags: CompositeGlyphFlags::empty(),
534            done: false,
535            cursor: FontData::new(self.component_data()).cursor(),
536        }
537    }
538
539    /// Returns an iterator that yields the glyph identifier and flags of each
540    /// component in the composite glyph.
541    pub fn component_glyphs_and_flags(
542        &self,
543    ) -> impl Iterator<Item = (GlyphId16, CompositeGlyphFlags)> + 'a + Clone {
544        ComponentGlyphIdFlagsIter {
545            cur_flags: CompositeGlyphFlags::empty(),
546            done: false,
547            cursor: FontData::new(self.component_data()).cursor(),
548        }
549    }
550
551    /// Returns the component count and TrueType interpreter instructions
552    /// in a single pass.
553    pub fn count_and_instructions(&self) -> (usize, Option<&'a [u8]>) {
554        let mut iter = ComponentGlyphIdFlagsIter {
555            cur_flags: CompositeGlyphFlags::empty(),
556            done: false,
557            cursor: FontData::new(self.component_data()).cursor(),
558        };
559        let mut count = 0;
560        while iter.by_ref().next().is_some() {
561            count += 1;
562        }
563        let instructions = if iter
564            .cur_flags
565            .contains(CompositeGlyphFlags::WE_HAVE_INSTRUCTIONS)
566        {
567            iter.cursor
568                .read::<u16>()
569                .ok()
570                .map(|len| len as usize)
571                .and_then(|len| iter.cursor.read_array(len).ok())
572        } else {
573            None
574        };
575        (count, instructions)
576    }
577
578    /// Returns the TrueType interpreter instructions.
579    pub fn instructions(&self) -> Option<&'a [u8]> {
580        self.count_and_instructions().1
581    }
582}
583
584#[derive(Clone)]
585struct ComponentIter<'a> {
586    cur_flags: CompositeGlyphFlags,
587    done: bool,
588    cursor: Cursor<'a>,
589}
590
591impl Iterator for ComponentIter<'_> {
592    type Item = Component;
593
594    fn next(&mut self) -> Option<Self::Item> {
595        if self.done {
596            return None;
597        }
598        let flags: CompositeGlyphFlags = self.cursor.read().ok()?;
599        self.cur_flags = flags;
600        let glyph = self.cursor.read::<GlyphId16>().ok()?;
601        let args_are_words = flags.contains(CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS);
602        let args_are_xy_values = flags.contains(CompositeGlyphFlags::ARGS_ARE_XY_VALUES);
603        let anchor = match (args_are_xy_values, args_are_words) {
604            (true, true) => Anchor::Offset {
605                x: self.cursor.read().ok()?,
606                y: self.cursor.read().ok()?,
607            },
608            (true, false) => Anchor::Offset {
609                x: self.cursor.read::<i8>().ok()? as _,
610                y: self.cursor.read::<i8>().ok()? as _,
611            },
612            (false, true) => Anchor::Point {
613                base: self.cursor.read().ok()?,
614                component: self.cursor.read().ok()?,
615            },
616            (false, false) => Anchor::Point {
617                base: self.cursor.read::<u8>().ok()? as _,
618                component: self.cursor.read::<u8>().ok()? as _,
619            },
620        };
621        let mut transform = Transform::default();
622        if flags.contains(CompositeGlyphFlags::WE_HAVE_A_SCALE) {
623            transform.xx = self.cursor.read().ok()?;
624            transform.yy = transform.xx;
625        } else if flags.contains(CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE) {
626            transform.xx = self.cursor.read().ok()?;
627            transform.yy = self.cursor.read().ok()?;
628        } else if flags.contains(CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO) {
629            transform.xx = self.cursor.read().ok()?;
630            transform.yx = self.cursor.read().ok()?;
631            transform.xy = self.cursor.read().ok()?;
632            transform.yy = self.cursor.read().ok()?;
633        }
634        self.done = !flags.contains(CompositeGlyphFlags::MORE_COMPONENTS);
635
636        Some(Component {
637            flags,
638            glyph,
639            anchor,
640            transform,
641        })
642    }
643}
644
645/// Iterator that only returns glyph identifiers and flags for each component.
646///
647/// Significantly faster in cases where we're just processing the glyph
648/// tree, counting components or accessing instructions.
649#[derive(Clone)]
650struct ComponentGlyphIdFlagsIter<'a> {
651    cur_flags: CompositeGlyphFlags,
652    done: bool,
653    cursor: Cursor<'a>,
654}
655
656impl Iterator for ComponentGlyphIdFlagsIter<'_> {
657    type Item = (GlyphId16, CompositeGlyphFlags);
658
659    fn next(&mut self) -> Option<Self::Item> {
660        if self.done {
661            return None;
662        }
663        let flags: CompositeGlyphFlags = self.cursor.read().ok()?;
664        self.cur_flags = flags;
665        let glyph = self.cursor.read::<GlyphId16>().ok()?;
666        let args_are_words = flags.contains(CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS);
667        if args_are_words {
668            self.cursor.advance_by(4);
669        } else {
670            self.cursor.advance_by(2);
671        }
672        if flags.contains(CompositeGlyphFlags::WE_HAVE_A_SCALE) {
673            self.cursor.advance_by(2);
674        } else if flags.contains(CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE) {
675            self.cursor.advance_by(4);
676        } else if flags.contains(CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO) {
677            self.cursor.advance_by(8);
678        }
679        self.done = !flags.contains(CompositeGlyphFlags::MORE_COMPONENTS);
680        Some((glyph, flags))
681    }
682}
683
684#[cfg(feature = "experimental_traverse")]
685impl<'a> SomeTable<'a> for Component {
686    fn type_name(&self) -> &str {
687        "Component"
688    }
689
690    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
691        match idx {
692            0 => Some(Field::new("flags", self.flags.bits())),
693            1 => Some(Field::new("glyph", self.glyph)),
694            2 => match self.anchor {
695                Anchor::Point { base, .. } => Some(Field::new("base", base)),
696                Anchor::Offset { x, .. } => Some(Field::new("x", x)),
697            },
698            3 => match self.anchor {
699                Anchor::Point { component, .. } => Some(Field::new("component", component)),
700                Anchor::Offset { y, .. } => Some(Field::new("y", y)),
701            },
702            _ => None,
703        }
704    }
705}
706
707impl Anchor {
708    /// Compute the flags that describe this anchor
709    pub fn compute_flags(&self) -> CompositeGlyphFlags {
710        const I8_RANGE: Range<i16> = i8::MIN as i16..i8::MAX as i16 + 1;
711        const U8_MAX: u16 = u8::MAX as u16;
712
713        let mut flags = CompositeGlyphFlags::empty();
714        match self {
715            Anchor::Offset { x, y } => {
716                flags |= CompositeGlyphFlags::ARGS_ARE_XY_VALUES;
717                if !I8_RANGE.contains(x) || !I8_RANGE.contains(y) {
718                    flags |= CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS;
719                }
720            }
721            Anchor::Point { base, component } => {
722                if base > &U8_MAX || component > &U8_MAX {
723                    flags |= CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS;
724                }
725            }
726        }
727        flags
728    }
729}
730
731impl Transform {
732    /// Compute the flags that describe this transform
733    pub fn compute_flags(&self) -> CompositeGlyphFlags {
734        if self.yx != F2Dot14::ZERO || self.xy != F2Dot14::ZERO {
735            CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO
736        } else if self.xx != self.yy {
737            CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE
738        } else if self.xx != F2Dot14::ONE {
739            CompositeGlyphFlags::WE_HAVE_A_SCALE
740        } else {
741            CompositeGlyphFlags::empty()
742        }
743    }
744}
745
746impl PointCoord for F26Dot6 {
747    fn from_fixed(x: Fixed) -> Self {
748        x.to_f26dot6()
749    }
750
751    #[inline]
752    fn from_i32(x: i32) -> Self {
753        Self::from_i32(x)
754    }
755
756    #[inline]
757    fn to_f32(self) -> f32 {
758        self.to_f32()
759    }
760
761    #[inline]
762    fn midpoint(self, other: Self) -> Self {
763        // FreeType uses integer division on 26.6 to compute midpoints.
764        // See: https://github.com/freetype/freetype/blob/de8b92dd7ec634e9e2b25ef534c54a3537555c11/src/base/ftoutln.c#L123
765        Self::from_bits(midpoint_i32(self.to_bits(), other.to_bits()))
766    }
767}
768
769impl PointCoord for Fixed {
770    fn from_fixed(x: Fixed) -> Self {
771        x
772    }
773
774    fn from_i32(x: i32) -> Self {
775        Self::from_i32(x)
776    }
777
778    fn to_f32(self) -> f32 {
779        self.to_f32()
780    }
781
782    fn midpoint(self, other: Self) -> Self {
783        Self::from_bits(midpoint_i32(self.to_bits(), other.to_bits()))
784    }
785}
786
787impl PointCoord for i32 {
788    fn from_fixed(x: Fixed) -> Self {
789        x.to_i32()
790    }
791
792    fn from_i32(x: i32) -> Self {
793        x
794    }
795
796    fn to_f32(self) -> f32 {
797        self as f32
798    }
799
800    fn midpoint(self, other: Self) -> Self {
801        midpoint_i32(self, other)
802    }
803}
804
805// Midpoint function that avoids overflow on large values.
806#[inline(always)]
807fn midpoint_i32(a: i32, b: i32) -> i32 {
808    // Original overflowing code was: (a + b) / 2
809    // Choose wrapping arithmetic here because we shouldn't ever
810    // hit this outside of fuzzing or broken fonts _and_ this is
811    // called from the outline to path conversion code which is
812    // very performance sensitive
813    a.wrapping_add(b) / 2
814}
815
816impl PointCoord for f32 {
817    fn from_fixed(x: Fixed) -> Self {
818        x.to_f32()
819    }
820
821    fn from_i32(x: i32) -> Self {
822        x as f32
823    }
824
825    fn to_f32(self) -> f32 {
826        self
827    }
828
829    fn midpoint(self, other: Self) -> Self {
830        // HarfBuzz uses a lerp here so we copy the style to
831        // preserve compatibility
832        self + 0.5 * (other - self)
833    }
834}
835
836#[cfg(test)]
837mod tests {
838    use super::*;
839    use crate::{FontRef, GlyphId, TableProvider};
840
841    #[test]
842    fn simple_glyph() {
843        let font = FontRef::new(font_test_data::COLR_GRADIENT_RECT).unwrap();
844        let loca = font.loca(None).unwrap();
845        let glyf = font.glyf().unwrap();
846        let glyph = loca.get_glyf(GlyphId::new(0), &glyf).unwrap().unwrap();
847        assert_eq!(glyph.number_of_contours(), 2);
848        let simple_glyph = if let Glyph::Simple(simple) = glyph {
849            simple
850        } else {
851            panic!("expected simple glyph");
852        };
853        assert_eq!(
854            simple_glyph
855                .end_pts_of_contours()
856                .iter()
857                .map(|x| x.get())
858                .collect::<Vec<_>>(),
859            &[3, 7]
860        );
861        assert_eq!(
862            simple_glyph
863                .points()
864                .map(|pt| (pt.x, pt.y, pt.on_curve))
865                .collect::<Vec<_>>(),
866            &[
867                (5, 0, true),
868                (5, 100, true),
869                (45, 100, true),
870                (45, 0, true),
871                (10, 5, true),
872                (40, 5, true),
873                (40, 95, true),
874                (10, 95, true),
875            ]
876        );
877    }
878
879    // Test helper to enumerate all TrueType glyphs in the given font
880    fn all_glyphs(font_data: &[u8]) -> impl Iterator<Item = Option<Glyph>> {
881        let font = FontRef::new(font_data).unwrap();
882        let loca = font.loca(None).unwrap();
883        let glyf = font.glyf().unwrap();
884        let glyph_count = font.maxp().unwrap().num_glyphs() as u32;
885        (0..glyph_count).map(move |gid| loca.get_glyf(GlyphId::new(gid), &glyf).unwrap())
886    }
887
888    #[test]
889    fn simple_glyph_overlapping_contour_flag() {
890        let gids_with_overlap: Vec<_> = all_glyphs(font_test_data::VAZIRMATN_VAR)
891            .enumerate()
892            .filter_map(|(gid, glyph)| match glyph {
893                Some(Glyph::Simple(glyph)) if glyph.has_overlapping_contours() => Some(gid),
894                _ => None,
895            })
896            .collect();
897        // Only GID 3 has the overlap bit set
898        let expected_gids_with_overlap = vec![3];
899        assert_eq!(expected_gids_with_overlap, gids_with_overlap);
900    }
901
902    #[test]
903    fn composite_glyph_overlapping_contour_flag() {
904        let gids_components_with_overlap: Vec<_> = all_glyphs(font_test_data::VAZIRMATN_VAR)
905            .enumerate()
906            .filter_map(|(gid, glyph)| match glyph {
907                Some(Glyph::Composite(glyph)) => Some((gid, glyph)),
908                _ => None,
909            })
910            .flat_map(|(gid, glyph)| {
911                glyph
912                    .components()
913                    .enumerate()
914                    .filter_map(move |(comp_ix, comp)| {
915                        comp.flags
916                            .contains(CompositeGlyphFlags::OVERLAP_COMPOUND)
917                            .then_some((gid, comp_ix))
918                    })
919            })
920            .collect();
921        // Only GID 2, component 1 has the overlap bit set
922        let expected_gids_components_with_overlap = vec![(2, 1)];
923        assert_eq!(
924            expected_gids_components_with_overlap,
925            gids_components_with_overlap
926        );
927    }
928
929    #[test]
930    fn compute_anchor_flags() {
931        let anchor = Anchor::Offset { x: -128, y: 127 };
932        assert_eq!(
933            anchor.compute_flags(),
934            CompositeGlyphFlags::ARGS_ARE_XY_VALUES
935        );
936
937        let anchor = Anchor::Offset { x: -129, y: 127 };
938        assert_eq!(
939            anchor.compute_flags(),
940            CompositeGlyphFlags::ARGS_ARE_XY_VALUES | CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS
941        );
942        let anchor = Anchor::Offset { x: -1, y: 128 };
943        assert_eq!(
944            anchor.compute_flags(),
945            CompositeGlyphFlags::ARGS_ARE_XY_VALUES | CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS
946        );
947
948        let anchor = Anchor::Point {
949            base: 255,
950            component: 20,
951        };
952        assert_eq!(anchor.compute_flags(), CompositeGlyphFlags::empty());
953
954        let anchor = Anchor::Point {
955            base: 256,
956            component: 20,
957        };
958        assert_eq!(
959            anchor.compute_flags(),
960            CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS
961        )
962    }
963
964    #[test]
965    fn compute_transform_flags() {
966        fn make_xform(xx: f32, yx: f32, xy: f32, yy: f32) -> Transform {
967            Transform {
968                xx: F2Dot14::from_f32(xx),
969                yx: F2Dot14::from_f32(yx),
970                xy: F2Dot14::from_f32(xy),
971                yy: F2Dot14::from_f32(yy),
972            }
973        }
974
975        assert_eq!(
976            make_xform(1.0, 0., 0., 1.0).compute_flags(),
977            CompositeGlyphFlags::empty()
978        );
979        assert_eq!(
980            make_xform(2.0, 0., 0., 2.0).compute_flags(),
981            CompositeGlyphFlags::WE_HAVE_A_SCALE
982        );
983        assert_eq!(
984            make_xform(2.0, 0., 0., 1.0).compute_flags(),
985            CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE
986        );
987        assert_eq!(
988            make_xform(2.0, 0., 1.0, 1.0).compute_flags(),
989            CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO
990        );
991    }
992
993    #[test]
994    fn point_flags_and_marker_bits() {
995        let bits = [
996            PointFlags::OFF_CURVE_CUBIC,
997            PointFlags::ON_CURVE,
998            PointMarker::HAS_DELTA.0,
999            PointMarker::TOUCHED_X.0,
1000            PointMarker::TOUCHED_Y.0,
1001        ];
1002        // Ensure bits don't overlap
1003        for (i, a) in bits.iter().enumerate() {
1004            for b in &bits[i + 1..] {
1005                assert_eq!(a & b, 0);
1006            }
1007        }
1008    }
1009
1010    #[test]
1011    fn cubic_glyf() {
1012        let font = FontRef::new(font_test_data::CUBIC_GLYF).unwrap();
1013        let loca = font.loca(None).unwrap();
1014        let glyf = font.glyf().unwrap();
1015        let glyph = loca.get_glyf(GlyphId::new(2), &glyf).unwrap().unwrap();
1016        assert_eq!(glyph.number_of_contours(), 1);
1017        let simple_glyph = if let Glyph::Simple(simple) = glyph {
1018            simple
1019        } else {
1020            panic!("expected simple glyph");
1021        };
1022        assert_eq!(
1023            simple_glyph
1024                .points()
1025                .map(|pt| (pt.x, pt.y, pt.on_curve))
1026                .collect::<Vec<_>>(),
1027            &[
1028                (278, 710, true),
1029                (278, 470, true),
1030                (300, 500, false),
1031                (800, 500, false),
1032                (998, 470, true),
1033                (998, 710, true),
1034            ]
1035        );
1036    }
1037
1038    // Minimized test case from https://issues.oss-fuzz.com/issues/382732980
1039    // Add with overflow when computing midpoint of 1084092352 and 1085243712
1040    // during outline -> path conversion
1041    #[test]
1042    fn avoid_midpoint_overflow() {
1043        let a = F26Dot6::from_bits(1084092352);
1044        let b = F26Dot6::from_bits(1085243712);
1045        let expected = (a + b).to_bits() / 2;
1046        // Don't panic!
1047        let midpoint = a.midpoint(b);
1048        assert_eq!(midpoint.to_bits(), expected);
1049    }
1050}