Skip to main content

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