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        // This used to use a `Cursor` but that implies saturating
264        // arithmetic, bounds checking and `Result` building for each byte
265        // read.
266        //
267        // A byte slice iterator is just a pointer comparison and is
268        // significantly faster.
269        let coords = self
270            .glyph_data()
271            .get(read_flags_bytes..)
272            .ok_or(ReadError::OutOfBounds)?;
273        let mut bytes = coords.iter();
274        let mut x = 0i32;
275        for (&point_flags, point) in flags.iter().zip(points.as_mut()) {
276            let mut delta = 0i32;
277            let flag = SimpleGlyphFlags::from_bits_truncate(point_flags.0);
278            if flag.contains(SimpleGlyphFlags::X_SHORT_VECTOR) {
279                delta = *bytes.next().ok_or(ReadError::OutOfBounds)? as i32;
280                if !flag.contains(SimpleGlyphFlags::X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) {
281                    delta = -delta;
282                }
283            } else if !flag.contains(SimpleGlyphFlags::X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) {
284                let hi = *bytes.next().ok_or(ReadError::OutOfBounds)?;
285                let lo = *bytes.next().ok_or(ReadError::OutOfBounds)?;
286                delta = i16::from_be_bytes([hi, lo]) as i32;
287            }
288            x = x.wrapping_add(delta);
289            point.x = C::from_i32(x);
290        }
291        let mut y = 0i32;
292        for (point_flags, point) in flags.iter_mut().zip(points.as_mut()) {
293            let mut delta = 0i32;
294            let flag = SimpleGlyphFlags::from_bits_truncate(point_flags.0);
295            if flag.contains(SimpleGlyphFlags::Y_SHORT_VECTOR) {
296                delta = *bytes.next().ok_or(ReadError::OutOfBounds)? as i32;
297                if !flag.contains(SimpleGlyphFlags::Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) {
298                    delta = -delta;
299                }
300            } else if !flag.contains(SimpleGlyphFlags::Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) {
301                let hi = *bytes.next().ok_or(ReadError::OutOfBounds)?;
302                let lo = *bytes.next().ok_or(ReadError::OutOfBounds)?;
303                delta = i16::from_be_bytes([hi, lo]) as i32;
304            }
305            y = y.wrapping_add(delta);
306            point.y = C::from_i32(y);
307            let flags_mask = if cfg!(feature = "spec_next") {
308                PointFlags::CURVE_MASK
309            } else {
310                // Drop the cubic bit if the spec_next feature is not enabled
311                PointFlags::ON_CURVE
312            };
313            point_flags.0 &= flags_mask;
314        }
315        Ok(())
316    }
317
318    /// Returns an iterator over the points in the glyph.
319    ///
320    /// ## Performance
321    ///
322    /// This is slower than [read_points_fast](Self::read_points_fast) but
323    /// provides access to the points without requiring a preallocated buffer.
324    pub fn points(&self) -> impl Iterator<Item = CurvePoint> + 'a + Clone {
325        self.points_impl()
326            .unwrap_or_else(|| PointIter::new(&[], &[], &[]))
327    }
328
329    fn points_impl(&self) -> Option<PointIter<'a>> {
330        let end_points = self.end_pts_of_contours();
331        let n_points = end_points.last()?.get().checked_add(1)?;
332        let data = self.glyph_data();
333        let lens = resolve_coords_len(data, n_points).ok()?;
334        let total_len = lens.flags + lens.x_coords + lens.y_coords;
335        if data.len() < total_len as usize {
336            return None;
337        }
338
339        let (flags, data) = data.split_at(lens.flags as usize);
340        let (x_coords, y_coords) = data.split_at(lens.x_coords as usize);
341
342        Some(PointIter::new(flags, x_coords, y_coords))
343    }
344}
345
346/// Point with an associated on-curve flag in a simple glyph.
347///
348/// This type is a simpler representation of the data in the blob.
349#[derive(Clone, Copy, Debug, PartialEq, Eq)]
350pub struct CurvePoint {
351    /// X coordinate.
352    pub x: i16,
353    /// Y coordinate.
354    pub y: i16,
355    /// True if this is an on-curve point.
356    pub on_curve: bool,
357}
358
359impl CurvePoint {
360    /// Construct a new `CurvePoint`
361    pub fn new(x: i16, y: i16, on_curve: bool) -> Self {
362        Self { x, y, on_curve }
363    }
364
365    /// Convenience method to construct an on-curve point
366    pub fn on_curve(x: i16, y: i16) -> Self {
367        Self::new(x, y, true)
368    }
369
370    /// Convenience method to construct an off-curve point
371    pub fn off_curve(x: i16, y: i16) -> Self {
372        Self::new(x, y, false)
373    }
374}
375
376#[derive(Clone)]
377struct PointIter<'a> {
378    flags: Cursor<'a>,
379    x_coords: Cursor<'a>,
380    y_coords: Cursor<'a>,
381    flag_repeats: u16,
382    cur_flags: SimpleGlyphFlags,
383    cur_x: i16,
384    cur_y: i16,
385}
386
387impl Iterator for PointIter<'_> {
388    type Item = CurvePoint;
389    fn next(&mut self) -> Option<Self::Item> {
390        self.advance_flags()?;
391        self.advance_points();
392        let is_on_curve = self.cur_flags.contains(SimpleGlyphFlags::ON_CURVE_POINT);
393        Some(CurvePoint::new(self.cur_x, self.cur_y, is_on_curve))
394    }
395}
396
397impl<'a> PointIter<'a> {
398    fn new(flags: &'a [u8], x_coords: &'a [u8], y_coords: &'a [u8]) -> Self {
399        Self {
400            flags: FontData::new(flags).cursor(),
401            x_coords: FontData::new(x_coords).cursor(),
402            y_coords: FontData::new(y_coords).cursor(),
403            flag_repeats: 0,
404            cur_flags: SimpleGlyphFlags::empty(),
405            cur_x: 0,
406            cur_y: 0,
407        }
408    }
409
410    fn advance_flags(&mut self) -> Option<()> {
411        if self.flag_repeats == 0 {
412            self.cur_flags = SimpleGlyphFlags::from_bits_truncate(self.flags.read().ok()?);
413            self.flag_repeats = self
414                .cur_flags
415                .contains(SimpleGlyphFlags::REPEAT_FLAG)
416                .then(|| self.flags.read::<u8>().ok())
417                .flatten()
418                .unwrap_or(0) as u16
419                + 1;
420        }
421        self.flag_repeats -= 1;
422        Some(())
423    }
424
425    fn advance_points(&mut self) {
426        let x_short = self.cur_flags.contains(SimpleGlyphFlags::X_SHORT_VECTOR);
427        let x_same_or_pos = self
428            .cur_flags
429            .contains(SimpleGlyphFlags::X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR);
430        let y_short = self.cur_flags.contains(SimpleGlyphFlags::Y_SHORT_VECTOR);
431        let y_same_or_pos = self
432            .cur_flags
433            .contains(SimpleGlyphFlags::Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR);
434
435        let delta_x = match (x_short, x_same_or_pos) {
436            (true, false) => -(self.x_coords.read::<u8>().unwrap_or(0) as i16),
437            (true, true) => self.x_coords.read::<u8>().unwrap_or(0) as i16,
438            (false, false) => self.x_coords.read::<i16>().unwrap_or(0),
439            _ => 0,
440        };
441
442        let delta_y = match (y_short, y_same_or_pos) {
443            (true, false) => -(self.y_coords.read::<u8>().unwrap_or(0) as i16),
444            (true, true) => self.y_coords.read::<u8>().unwrap_or(0) as i16,
445            (false, false) => self.y_coords.read::<i16>().unwrap_or(0),
446            _ => 0,
447        };
448
449        self.cur_x = self.cur_x.wrapping_add(delta_x);
450        self.cur_y = self.cur_y.wrapping_add(delta_y);
451    }
452}
453
454//taken from ttf_parser https://docs.rs/ttf-parser/latest/src/ttf_parser/tables/glyf.rs.html#1-677
455/// Resolves coordinate arrays length.
456///
457/// The length depends on *Simple Glyph Flags*, so we have to process them all to find it.
458fn resolve_coords_len(data: &[u8], points_total: u16) -> Result<FieldLengths, ReadError> {
459    let mut cursor = FontData::new(data).cursor();
460    let mut flags_left = u32::from(points_total);
461    //let mut repeats;
462    let mut x_coords_len = 0;
463    let mut y_coords_len = 0;
464    //let mut flags_seen = 0;
465    while flags_left > 0 {
466        let flags: SimpleGlyphFlags = cursor.read()?;
467
468        // The number of times a glyph point repeats.
469        let repeats = if flags.contains(SimpleGlyphFlags::REPEAT_FLAG) {
470            let repeats: u8 = cursor.read()?;
471            u32::from(repeats) + 1
472        } else {
473            1
474        };
475
476        if repeats > flags_left {
477            return Err(ReadError::MalformedData("repeat count too large in glyf"));
478        }
479
480        // Non-obfuscated code below.
481        // Branchless version is surprisingly faster.
482        //
483        // if flags.x_short() {
484        //     // Coordinate is 1 byte long.
485        //     x_coords_len += repeats;
486        // } else if !flags.x_is_same_or_positive_short() {
487        //     // Coordinate is 2 bytes long.
488        //     x_coords_len += repeats * 2;
489        // }
490        // if flags.y_short() {
491        //     // Coordinate is 1 byte long.
492        //     y_coords_len += repeats;
493        // } else if !flags.y_is_same_or_positive_short() {
494        //     // Coordinate is 2 bytes long.
495        //     y_coords_len += repeats * 2;
496        // }
497        let x_short = SimpleGlyphFlags::X_SHORT_VECTOR;
498        let x_long = SimpleGlyphFlags::X_SHORT_VECTOR
499            | SimpleGlyphFlags::X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR;
500        let y_short = SimpleGlyphFlags::Y_SHORT_VECTOR;
501        let y_long = SimpleGlyphFlags::Y_SHORT_VECTOR
502            | SimpleGlyphFlags::Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR;
503        x_coords_len += ((flags & x_short).bits() != 0) as u32 * repeats;
504        x_coords_len += ((flags & x_long).bits() == 0) as u32 * repeats * 2;
505
506        y_coords_len += ((flags & y_short).bits() != 0) as u32 * repeats;
507        y_coords_len += ((flags & y_long).bits() == 0) as u32 * repeats * 2;
508
509        flags_left -= repeats;
510    }
511
512    Ok(FieldLengths {
513        flags: cursor.position()? as u32,
514        x_coords: x_coords_len,
515        y_coords: y_coords_len,
516    })
517    //Some((flags_len, x_coords_len, y_coords_len))
518}
519
520struct FieldLengths {
521    flags: u32,
522    x_coords: u32,
523    y_coords: u32,
524}
525
526/// Transform for a composite component.
527#[derive(Clone, Copy, Debug, PartialEq, Eq)]
528pub struct Transform {
529    /// X scale factor.
530    pub xx: F2Dot14,
531    /// YX skew factor.
532    pub yx: F2Dot14,
533    /// XY skew factor.
534    pub xy: F2Dot14,
535    /// Y scale factor.
536    pub yy: F2Dot14,
537}
538
539impl Default for Transform {
540    fn default() -> Self {
541        Self {
542            xx: F2Dot14::from_f32(1.0),
543            yx: F2Dot14::from_f32(0.0),
544            xy: F2Dot14::from_f32(0.0),
545            yy: F2Dot14::from_f32(1.0),
546        }
547    }
548}
549
550/// A reference to another glyph. Part of [CompositeGlyph].
551#[derive(Clone, Debug, PartialEq, Eq)]
552pub struct Component {
553    /// Component flags.
554    pub flags: CompositeGlyphFlags,
555    /// Glyph identifier.
556    pub glyph: GlyphId16,
557    /// Anchor for component placement.
558    pub anchor: Anchor,
559    /// Component transformation matrix.
560    pub transform: Transform,
561}
562
563/// Anchor position for a composite component.
564#[derive(Clone, Copy, Debug, PartialEq, Eq)]
565pub enum Anchor {
566    Offset { x: i16, y: i16 },
567    Point { base: u16, component: u16 },
568}
569
570impl<'a> CompositeGlyph<'a> {
571    /// Returns an iterator over the components of the composite glyph.
572    pub fn components(&self) -> impl Iterator<Item = Component> + 'a + Clone {
573        ComponentIter {
574            cur_flags: CompositeGlyphFlags::empty(),
575            done: false,
576            cursor: FontData::new(self.component_data()).cursor(),
577        }
578    }
579
580    /// Returns an iterator that yields the glyph identifier and flags of each
581    /// component in the composite glyph.
582    pub fn component_glyphs_and_flags(
583        &self,
584    ) -> impl Iterator<Item = (GlyphId16, CompositeGlyphFlags)> + 'a + Clone {
585        ComponentGlyphIdFlagsIter {
586            cur_flags: CompositeGlyphFlags::empty(),
587            done: false,
588            cursor: FontData::new(self.component_data()).cursor(),
589        }
590    }
591
592    /// Returns the component count and TrueType interpreter instructions
593    /// in a single pass.
594    pub fn count_and_instructions(&self) -> (usize, Option<&'a [u8]>) {
595        let mut iter = ComponentGlyphIdFlagsIter {
596            cur_flags: CompositeGlyphFlags::empty(),
597            done: false,
598            cursor: FontData::new(self.component_data()).cursor(),
599        };
600        let mut count = 0;
601        while iter.by_ref().next().is_some() {
602            count += 1;
603        }
604        let instructions = if iter
605            .cur_flags
606            .contains(CompositeGlyphFlags::WE_HAVE_INSTRUCTIONS)
607        {
608            iter.cursor
609                .read::<u16>()
610                .ok()
611                .map(|len| len as usize)
612                .and_then(|len| iter.cursor.read_array(len).ok())
613        } else {
614            None
615        };
616        (count, instructions)
617    }
618
619    /// Returns the TrueType interpreter instructions.
620    pub fn instructions(&self) -> Option<&'a [u8]> {
621        self.count_and_instructions().1
622    }
623}
624
625#[derive(Clone)]
626struct ComponentIter<'a> {
627    cur_flags: CompositeGlyphFlags,
628    done: bool,
629    cursor: Cursor<'a>,
630}
631
632impl Iterator for ComponentIter<'_> {
633    type Item = Component;
634
635    fn next(&mut self) -> Option<Self::Item> {
636        if self.done {
637            return None;
638        }
639        let flags: CompositeGlyphFlags = self.cursor.read().ok()?;
640        self.cur_flags = flags;
641        let glyph = self.cursor.read::<GlyphId16>().ok()?;
642        let args_are_words = flags.contains(CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS);
643        let args_are_xy_values = flags.contains(CompositeGlyphFlags::ARGS_ARE_XY_VALUES);
644        let anchor = match (args_are_xy_values, args_are_words) {
645            (true, true) => Anchor::Offset {
646                x: self.cursor.read().ok()?,
647                y: self.cursor.read().ok()?,
648            },
649            (true, false) => Anchor::Offset {
650                x: self.cursor.read::<i8>().ok()? as _,
651                y: self.cursor.read::<i8>().ok()? as _,
652            },
653            (false, true) => Anchor::Point {
654                base: self.cursor.read().ok()?,
655                component: self.cursor.read().ok()?,
656            },
657            (false, false) => Anchor::Point {
658                base: self.cursor.read::<u8>().ok()? as _,
659                component: self.cursor.read::<u8>().ok()? as _,
660            },
661        };
662        let mut transform = Transform::default();
663        if flags.contains(CompositeGlyphFlags::WE_HAVE_A_SCALE) {
664            transform.xx = self.cursor.read().ok()?;
665            transform.yy = transform.xx;
666        } else if flags.contains(CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE) {
667            transform.xx = self.cursor.read().ok()?;
668            transform.yy = self.cursor.read().ok()?;
669        } else if flags.contains(CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO) {
670            transform.xx = self.cursor.read().ok()?;
671            transform.yx = self.cursor.read().ok()?;
672            transform.xy = self.cursor.read().ok()?;
673            transform.yy = self.cursor.read().ok()?;
674        }
675        self.done = !flags.contains(CompositeGlyphFlags::MORE_COMPONENTS);
676
677        Some(Component {
678            flags,
679            glyph,
680            anchor,
681            transform,
682        })
683    }
684}
685
686/// Iterator that only returns glyph identifiers and flags for each component.
687///
688/// Significantly faster in cases where we're just processing the glyph
689/// tree, counting components or accessing instructions.
690#[derive(Clone)]
691struct ComponentGlyphIdFlagsIter<'a> {
692    cur_flags: CompositeGlyphFlags,
693    done: bool,
694    cursor: Cursor<'a>,
695}
696
697impl Iterator for ComponentGlyphIdFlagsIter<'_> {
698    type Item = (GlyphId16, CompositeGlyphFlags);
699
700    fn next(&mut self) -> Option<Self::Item> {
701        if self.done {
702            return None;
703        }
704        let flags: CompositeGlyphFlags = self.cursor.read().ok()?;
705        self.cur_flags = flags;
706        let glyph = self.cursor.read::<GlyphId16>().ok()?;
707        let args_are_words = flags.contains(CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS);
708        if args_are_words {
709            self.cursor.advance_by(4);
710        } else {
711            self.cursor.advance_by(2);
712        }
713        if flags.contains(CompositeGlyphFlags::WE_HAVE_A_SCALE) {
714            self.cursor.advance_by(2);
715        } else if flags.contains(CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE) {
716            self.cursor.advance_by(4);
717        } else if flags.contains(CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO) {
718            self.cursor.advance_by(8);
719        }
720        self.done = !flags.contains(CompositeGlyphFlags::MORE_COMPONENTS);
721        Some((glyph, flags))
722    }
723}
724
725impl Anchor {
726    /// Compute the flags that describe this anchor
727    pub fn compute_flags(&self) -> CompositeGlyphFlags {
728        const I8_RANGE: Range<i16> = i8::MIN as i16..i8::MAX as i16 + 1;
729        const U8_MAX: u16 = u8::MAX as u16;
730
731        let mut flags = CompositeGlyphFlags::empty();
732        match self {
733            Anchor::Offset { x, y } => {
734                flags |= CompositeGlyphFlags::ARGS_ARE_XY_VALUES;
735                if !I8_RANGE.contains(x) || !I8_RANGE.contains(y) {
736                    flags |= CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS;
737                }
738            }
739            Anchor::Point { base, component } => {
740                if base > &U8_MAX || component > &U8_MAX {
741                    flags |= CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS;
742                }
743            }
744        }
745        flags
746    }
747}
748
749impl Transform {
750    /// Compute the flags that describe this transform
751    pub fn compute_flags(&self) -> CompositeGlyphFlags {
752        if self.yx != F2Dot14::ZERO || self.xy != F2Dot14::ZERO {
753            CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO
754        } else if self.xx != self.yy {
755            CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE
756        } else if self.xx != F2Dot14::ONE {
757            CompositeGlyphFlags::WE_HAVE_A_SCALE
758        } else {
759            CompositeGlyphFlags::empty()
760        }
761    }
762}
763
764impl PointCoord for F26Dot6 {
765    fn from_fixed(x: Fixed) -> Self {
766        x.to_f26dot6()
767    }
768
769    #[inline]
770    fn from_i32(x: i32) -> Self {
771        Self::from_i32(x)
772    }
773
774    #[inline]
775    fn to_f32(self) -> f32 {
776        self.to_f32()
777    }
778
779    #[inline]
780    fn midpoint(self, other: Self) -> Self {
781        // FreeType uses integer division on 26.6 to compute midpoints.
782        // See: https://github.com/freetype/freetype/blob/de8b92dd7ec634e9e2b25ef534c54a3537555c11/src/base/ftoutln.c#L123
783        Self::from_bits(midpoint_i32(self.to_bits(), other.to_bits()))
784    }
785}
786
787impl PointCoord for Fixed {
788    fn from_fixed(x: Fixed) -> Self {
789        x
790    }
791
792    fn from_i32(x: i32) -> Self {
793        Self::from_i32(x)
794    }
795
796    fn to_f32(self) -> f32 {
797        self.to_f32()
798    }
799
800    fn midpoint(self, other: Self) -> Self {
801        Self::from_bits(midpoint_i32(self.to_bits(), other.to_bits()))
802    }
803}
804
805impl PointCoord for i32 {
806    fn from_fixed(x: Fixed) -> Self {
807        x.to_i32()
808    }
809
810    fn from_i32(x: i32) -> Self {
811        x
812    }
813
814    fn to_f32(self) -> f32 {
815        self as f32
816    }
817
818    fn midpoint(self, other: Self) -> Self {
819        midpoint_i32(self, other)
820    }
821}
822
823// Midpoint function that avoids overflow on large values.
824#[inline(always)]
825fn midpoint_i32(a: i32, b: i32) -> i32 {
826    // Original overflowing code was: (a + b) / 2
827    // Choose wrapping arithmetic here because we shouldn't ever
828    // hit this outside of fuzzing or broken fonts _and_ this is
829    // called from the outline to path conversion code which is
830    // very performance sensitive
831    a.wrapping_add(b) / 2
832}
833
834impl PointCoord for f32 {
835    fn from_fixed(x: Fixed) -> Self {
836        x.to_f32()
837    }
838
839    fn from_i32(x: i32) -> Self {
840        x as f32
841    }
842
843    fn to_f32(self) -> f32 {
844        self
845    }
846
847    fn midpoint(self, other: Self) -> Self {
848        // HarfBuzz uses a lerp here so we copy the style to
849        // preserve compatibility
850        self + 0.5 * (other - self)
851    }
852}
853
854#[cfg(test)]
855mod tests {
856    use super::*;
857    use crate::{FontRef, GlyphId, TableProvider};
858
859    #[test]
860    fn simple_glyph() {
861        let font = FontRef::new(font_test_data::COLR_GRADIENT_RECT).unwrap();
862        let loca = font.loca(None).unwrap();
863        let glyf = font.glyf().unwrap();
864        let glyph = loca
865            .get(GlyphId::new(0), &glyf)
866            .and_then(|g| g.into_glyph())
867            .unwrap();
868        assert_eq!(glyph.number_of_contours(), 2);
869        let simple_glyph = if let Glyph::Simple(simple) = glyph {
870            simple
871        } else {
872            panic!("expected simple glyph");
873        };
874        assert_eq!(
875            simple_glyph
876                .end_pts_of_contours()
877                .iter()
878                .map(|x| x.get())
879                .collect::<Vec<_>>(),
880            &[3, 7]
881        );
882        assert_eq!(
883            simple_glyph
884                .points()
885                .map(|pt| (pt.x, pt.y, pt.on_curve))
886                .collect::<Vec<_>>(),
887            &[
888                (5, 0, true),
889                (5, 100, true),
890                (45, 100, true),
891                (45, 0, true),
892                (10, 5, true),
893                (40, 5, true),
894                (40, 95, true),
895                (10, 95, true),
896            ]
897        );
898    }
899
900    // Test helper to enumerate all TrueType glyphs in the given font
901    fn all_glyphs(font_data: &[u8]) -> impl Iterator<Item = Option<Glyph<'_>>> {
902        let font = FontRef::new(font_data).unwrap();
903        let loca = font.loca(None).unwrap();
904        let glyf = font.glyf().unwrap();
905        let glyph_count = font.maxp().unwrap().num_glyphs() as u32;
906        (0..glyph_count).map(move |gid| {
907            loca.get(GlyphId::new(gid), &glyf)
908                .and_then(|g| g.into_glyph())
909        })
910    }
911
912    #[test]
913    fn simple_glyph_overlapping_contour_flag() {
914        let gids_with_overlap: Vec<_> = all_glyphs(font_test_data::VAZIRMATN_VAR)
915            .enumerate()
916            .filter_map(|(gid, glyph)| match glyph {
917                Some(Glyph::Simple(glyph)) if glyph.has_overlapping_contours() => Some(gid),
918                _ => None,
919            })
920            .collect();
921        // Only GID 3 has the overlap bit set
922        let expected_gids_with_overlap = vec![3];
923        assert_eq!(expected_gids_with_overlap, gids_with_overlap);
924    }
925
926    #[test]
927    fn composite_glyph_overlapping_contour_flag() {
928        let gids_components_with_overlap: Vec<_> = all_glyphs(font_test_data::VAZIRMATN_VAR)
929            .enumerate()
930            .filter_map(|(gid, glyph)| match glyph {
931                Some(Glyph::Composite(glyph)) => Some((gid, glyph)),
932                _ => None,
933            })
934            .flat_map(|(gid, glyph)| {
935                glyph
936                    .components()
937                    .enumerate()
938                    .filter_map(move |(comp_ix, comp)| {
939                        comp.flags
940                            .contains(CompositeGlyphFlags::OVERLAP_COMPOUND)
941                            .then_some((gid, comp_ix))
942                    })
943            })
944            .collect();
945        // Only GID 2, component 1 has the overlap bit set
946        let expected_gids_components_with_overlap = vec![(2, 1)];
947        assert_eq!(
948            expected_gids_components_with_overlap,
949            gids_components_with_overlap
950        );
951    }
952
953    #[test]
954    fn compute_anchor_flags() {
955        let anchor = Anchor::Offset { x: -128, y: 127 };
956        assert_eq!(
957            anchor.compute_flags(),
958            CompositeGlyphFlags::ARGS_ARE_XY_VALUES
959        );
960
961        let anchor = Anchor::Offset { x: -129, y: 127 };
962        assert_eq!(
963            anchor.compute_flags(),
964            CompositeGlyphFlags::ARGS_ARE_XY_VALUES | CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS
965        );
966        let anchor = Anchor::Offset { x: -1, y: 128 };
967        assert_eq!(
968            anchor.compute_flags(),
969            CompositeGlyphFlags::ARGS_ARE_XY_VALUES | CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS
970        );
971
972        let anchor = Anchor::Point {
973            base: 255,
974            component: 20,
975        };
976        assert_eq!(anchor.compute_flags(), CompositeGlyphFlags::empty());
977
978        let anchor = Anchor::Point {
979            base: 256,
980            component: 20,
981        };
982        assert_eq!(
983            anchor.compute_flags(),
984            CompositeGlyphFlags::ARG_1_AND_2_ARE_WORDS
985        )
986    }
987
988    #[test]
989    fn compute_transform_flags() {
990        fn make_xform(xx: f32, yx: f32, xy: f32, yy: f32) -> Transform {
991            Transform {
992                xx: F2Dot14::from_f32(xx),
993                yx: F2Dot14::from_f32(yx),
994                xy: F2Dot14::from_f32(xy),
995                yy: F2Dot14::from_f32(yy),
996            }
997        }
998
999        assert_eq!(
1000            make_xform(1.0, 0., 0., 1.0).compute_flags(),
1001            CompositeGlyphFlags::empty()
1002        );
1003        assert_eq!(
1004            make_xform(2.0, 0., 0., 2.0).compute_flags(),
1005            CompositeGlyphFlags::WE_HAVE_A_SCALE
1006        );
1007        assert_eq!(
1008            make_xform(2.0, 0., 0., 1.0).compute_flags(),
1009            CompositeGlyphFlags::WE_HAVE_AN_X_AND_Y_SCALE
1010        );
1011        assert_eq!(
1012            make_xform(2.0, 0., 1.0, 1.0).compute_flags(),
1013            CompositeGlyphFlags::WE_HAVE_A_TWO_BY_TWO
1014        );
1015    }
1016
1017    #[test]
1018    fn point_flags_and_marker_bits() {
1019        let bits = [
1020            PointFlags::OFF_CURVE_CUBIC,
1021            PointFlags::ON_CURVE,
1022            PointMarker::HAS_DELTA.0,
1023            PointMarker::TOUCHED_X.0,
1024            PointMarker::TOUCHED_Y.0,
1025        ];
1026        // Ensure bits don't overlap
1027        for (i, a) in bits.iter().enumerate() {
1028            for b in &bits[i + 1..] {
1029                assert_eq!(a & b, 0);
1030            }
1031        }
1032    }
1033
1034    #[test]
1035    fn cubic_glyf() {
1036        let font = FontRef::new(font_test_data::CUBIC_GLYF).unwrap();
1037        let loca = font.loca(None).unwrap();
1038        let glyf = font.glyf().unwrap();
1039        let glyph = loca
1040            .get(GlyphId::new(2), &glyf)
1041            .and_then(|g| g.into_glyph())
1042            .unwrap();
1043        assert_eq!(glyph.number_of_contours(), 1);
1044        let simple_glyph = if let Glyph::Simple(simple) = glyph {
1045            simple
1046        } else {
1047            panic!("expected simple glyph");
1048        };
1049        assert_eq!(
1050            simple_glyph
1051                .points()
1052                .map(|pt| (pt.x, pt.y, pt.on_curve))
1053                .collect::<Vec<_>>(),
1054            &[
1055                (278, 710, true),
1056                (278, 470, true),
1057                (300, 500, false),
1058                (800, 500, false),
1059                (998, 470, true),
1060                (998, 710, true),
1061            ]
1062        );
1063    }
1064
1065    // Minimized test case from https://issues.oss-fuzz.com/issues/382732980
1066    // Add with overflow when computing midpoint of 1084092352 and 1085243712
1067    // during outline -> path conversion
1068    #[test]
1069    fn avoid_midpoint_overflow() {
1070        let a = F26Dot6::from_bits(1084092352);
1071        let b = F26Dot6::from_bits(1085243712);
1072        let expected = (a + b).to_bits() / 2;
1073        // Don't panic!
1074        let midpoint = a.midpoint(b);
1075        assert_eq!(midpoint.to_bits(), expected);
1076    }
1077
1078    // SimpleGlyph should not panic on truncated data.
1079    //
1080    // SimpleGlyph has a variable-length array (end_pts_of_contours) followed
1081    // by a scalar field (instruction_length). The MIN_SIZE validation only
1082    // checks that the fixed-size fields fit, but doesn't account for the
1083    // array's runtime length. This causes a panic when accessing fields
1084    // that come after the array if the data is truncated.
1085    #[test]
1086    fn simple_glyph_truncated_data() {
1087        use font_test_data::bebuffer::BeBuffer;
1088
1089        // Build a SimpleGlyph with number_of_contours = 100
1090        // This means end_pts_of_contours should be 200 bytes,
1091        // pushing instruction_length to offset 210.
1092        // But we only provide 12 bytes (MIN_SIZE).
1093        let buf = BeBuffer::new()
1094            .push(100_i16) // number_of_contours = 100
1095            .push(0_i16) // x_min
1096            .push(0_i16) // y_min
1097            .push(0_i16) // x_max
1098            .push(0_i16) // y_max
1099            .push(0_u16); // would be first element of end_pts_of_contours
1100
1101        // Parsing succeeds - we have MIN_SIZE (12) bytes
1102        let glyph = SimpleGlyph::read(buf.data().into()).unwrap();
1103        assert_eq!(glyph.number_of_contours(), 100);
1104
1105        // return default value instead of panicking
1106        assert_eq!(glyph.instruction_length(), 0);
1107    }
1108
1109    // The flags run can encode up to two bytes per point (a flag plus a repeat
1110    // count). read_points_fast must agree with the points() iterator even when
1111    // the flags section is longer than the point count.
1112    #[test]
1113    fn read_points_fast_long_flags() {
1114        use font_test_data::bebuffer::BeBuffer;
1115        // 1 contour, 3 points. Each point is its own REPEAT_FLAG entry with a
1116        // repeat count of 0, so the flags section is 6 bytes for 3 points and
1117        // there are no coordinate bytes. flag 0x39 = ON_CURVE | REPEAT_FLAG |
1118        // X_IS_SAME_OR_POSITIVE | Y_IS_SAME_OR_POSITIVE.
1119        let buf = BeBuffer::new()
1120            .push(1_i16) // number_of_contours
1121            .extend([0_i16; 4]) // bounding box
1122            .push(2_u16) // end_pts_of_contours[0] => 3 points
1123            .push(0_u16) // instruction_length
1124            .extend([0x39u8, 0x00, 0x39, 0x00, 0x39, 0x00]);
1125
1126        let glyph = SimpleGlyph::read(buf.data().into()).unwrap();
1127        assert_eq!(glyph.num_points(), 3);
1128
1129        let expected: Vec<_> = glyph.points().map(|p| (p.x as i32, p.y as i32)).collect();
1130
1131        let mut points = vec![Point::default(); 3];
1132        let mut flags = vec![PointFlags::default(); 3];
1133        glyph
1134            .read_points_fast::<i32>(&mut points, &mut flags)
1135            .unwrap();
1136        let actual: Vec<_> = points.iter().map(|p| (p.x, p.y)).collect();
1137
1138        assert_eq!(actual, expected);
1139    }
1140
1141    #[test]
1142    fn point_iter_repeat_count_255_does_not_overflow() {
1143        // repeat byte 0xFF means the same flag applies to 256 points total
1144        let flags = [SimpleGlyphFlags::REPEAT_FLAG.bits(), 0xFF];
1145        // 256 coords of 2 bytes each
1146        let coords = [0u8; 256 * 2];
1147        let iter = PointIter::new(&flags, &coords, &coords);
1148        assert_eq!(iter.count(), 256);
1149    }
1150
1151    #[test]
1152    fn read_points_fast_does_not_panic_on_empty_glyph_with_padding() {
1153        let glyph_bytes: &[u8] = &[
1154            0x00, 0x00, // numberOfContours = 0
1155            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // bbox
1156            0x00, 0x00, // instructionLength = 0
1157            0x00, // trailing pad byte
1158        ];
1159        let glyph = SimpleGlyph::read(FontData::new(glyph_bytes)).expect("parses");
1160        assert_eq!(glyph.num_points(), 0);
1161        let mut points: Vec<Point<f32>> = vec![];
1162        let mut flags: Vec<PointFlags> = vec![];
1163        assert!(glyph.read_points_fast(&mut points, &mut flags).is_ok());
1164    }
1165}