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