ttf_parser/tables/
glyf.rs

1//! A [Glyph Data Table](
2//! https://docs.microsoft.com/en-us/typography/opentype/spec/glyf) implementation.
3
4use core::num::NonZeroU16;
5
6use crate::parser::{LazyArray16, NumFrom, Stream, F2DOT14};
7use crate::{loca, GlyphId, OutlineBuilder, Rect, RectF, Transform};
8
9pub(crate) struct Builder<'a> {
10    pub builder: &'a mut dyn OutlineBuilder,
11    pub transform: Transform,
12    is_default_ts: bool, // `bool` is faster than `Option` or `is_default`.
13    // We have to always calculate the bbox, because `gvar` doesn't store one
14    // and in case of a malformed bbox in `glyf`.
15    pub bbox: RectF,
16    first_on_curve: Option<Point>,
17    first_off_curve: Option<Point>,
18    last_off_curve: Option<Point>,
19}
20
21impl<'a> Builder<'a> {
22    #[inline]
23    pub fn new(transform: Transform, bbox: RectF, builder: &'a mut dyn OutlineBuilder) -> Self {
24        Builder {
25            builder,
26            transform,
27            is_default_ts: transform.is_default(),
28            bbox,
29            first_on_curve: None,
30            first_off_curve: None,
31            last_off_curve: None,
32        }
33    }
34
35    #[inline]
36    fn move_to(&mut self, mut x: f32, mut y: f32) {
37        if !self.is_default_ts {
38            self.transform.apply_to(&mut x, &mut y);
39        }
40
41        self.bbox.extend_by(x, y);
42
43        self.builder.move_to(x, y);
44    }
45
46    #[inline]
47    fn line_to(&mut self, mut x: f32, mut y: f32) {
48        if !self.is_default_ts {
49            self.transform.apply_to(&mut x, &mut y);
50        }
51
52        self.bbox.extend_by(x, y);
53
54        self.builder.line_to(x, y);
55    }
56
57    #[inline]
58    fn quad_to(&mut self, mut x1: f32, mut y1: f32, mut x: f32, mut y: f32) {
59        if !self.is_default_ts {
60            self.transform.apply_to(&mut x1, &mut y1);
61            self.transform.apply_to(&mut x, &mut y);
62        }
63
64        self.bbox.extend_by(x1, y1);
65        self.bbox.extend_by(x, y);
66
67        self.builder.quad_to(x1, y1, x, y);
68    }
69
70    // Useful links:
71    //
72    // - https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
73    // - https://stackoverflow.com/a/20772557
74    #[inline]
75    pub fn push_point(&mut self, x: f32, y: f32, on_curve_point: bool, last_point: bool) {
76        let p = Point { x, y };
77        if self.first_on_curve.is_none() {
78            if on_curve_point {
79                self.first_on_curve = Some(p);
80                self.move_to(p.x, p.y);
81            } else {
82                if let Some(offcurve) = self.first_off_curve {
83                    let mid = offcurve.lerp(p, 0.5);
84                    self.first_on_curve = Some(mid);
85                    self.last_off_curve = Some(p);
86                    self.move_to(mid.x, mid.y);
87                } else {
88                    self.first_off_curve = Some(p);
89                }
90            }
91        } else {
92            match (self.last_off_curve, on_curve_point) {
93                (Some(offcurve), true) => {
94                    self.last_off_curve = None;
95                    self.quad_to(offcurve.x, offcurve.y, p.x, p.y);
96                }
97                (Some(offcurve), false) => {
98                    self.last_off_curve = Some(p);
99                    let mid = offcurve.lerp(p, 0.5);
100                    self.quad_to(offcurve.x, offcurve.y, mid.x, mid.y);
101                }
102                (None, true) => {
103                    self.line_to(p.x, p.y);
104                }
105                (None, false) => {
106                    self.last_off_curve = Some(p);
107                }
108            }
109        }
110
111        if last_point {
112            self.finish_contour();
113        }
114    }
115
116    #[inline]
117    fn finish_contour(&mut self) {
118        if let (Some(offcurve1), Some(offcurve2)) = (self.first_off_curve, self.last_off_curve) {
119            self.last_off_curve = None;
120            let mid = offcurve2.lerp(offcurve1, 0.5);
121            self.quad_to(offcurve2.x, offcurve2.y, mid.x, mid.y);
122        }
123
124        if let (Some(p), Some(offcurve1)) = (self.first_on_curve, self.first_off_curve) {
125            self.quad_to(offcurve1.x, offcurve1.y, p.x, p.y);
126        } else if let (Some(p), Some(offcurve2)) = (self.first_on_curve, self.last_off_curve) {
127            self.quad_to(offcurve2.x, offcurve2.y, p.x, p.y);
128        } else if let Some(p) = self.first_on_curve {
129            self.line_to(p.x, p.y);
130        }
131
132        self.first_on_curve = None;
133        self.first_off_curve = None;
134        self.last_off_curve = None;
135
136        self.builder.close();
137    }
138}
139
140#[derive(Clone, Copy, Debug)]
141pub(crate) struct CompositeGlyphInfo {
142    pub glyph_id: GlyphId,
143    pub transform: Transform,
144    #[allow(dead_code)]
145    pub flags: CompositeGlyphFlags,
146}
147
148#[derive(Clone)]
149pub(crate) struct CompositeGlyphIter<'a> {
150    stream: Stream<'a>,
151}
152
153impl<'a> CompositeGlyphIter<'a> {
154    #[inline]
155    pub fn new(data: &'a [u8]) -> Self {
156        CompositeGlyphIter {
157            stream: Stream::new(data),
158        }
159    }
160}
161
162impl<'a> Iterator for CompositeGlyphIter<'a> {
163    type Item = CompositeGlyphInfo;
164
165    #[inline]
166    fn next(&mut self) -> Option<Self::Item> {
167        let flags = CompositeGlyphFlags(self.stream.read::<u16>()?);
168        let glyph_id = self.stream.read::<GlyphId>()?;
169
170        let mut ts = Transform::default();
171
172        if flags.args_are_xy_values() {
173            if flags.arg_1_and_2_are_words() {
174                ts.e = f32::from(self.stream.read::<i16>()?);
175                ts.f = f32::from(self.stream.read::<i16>()?);
176            } else {
177                ts.e = f32::from(self.stream.read::<i8>()?);
178                ts.f = f32::from(self.stream.read::<i8>()?);
179            }
180        }
181
182        if flags.we_have_a_two_by_two() {
183            ts.a = self.stream.read::<F2DOT14>()?.to_f32();
184            ts.b = self.stream.read::<F2DOT14>()?.to_f32();
185            ts.c = self.stream.read::<F2DOT14>()?.to_f32();
186            ts.d = self.stream.read::<F2DOT14>()?.to_f32();
187        } else if flags.we_have_an_x_and_y_scale() {
188            ts.a = self.stream.read::<F2DOT14>()?.to_f32();
189            ts.d = self.stream.read::<F2DOT14>()?.to_f32();
190        } else if flags.we_have_a_scale() {
191            ts.a = self.stream.read::<F2DOT14>()?.to_f32();
192            ts.d = ts.a;
193        }
194
195        if !flags.more_components() {
196            // Finish the iterator even if stream still has some data.
197            self.stream.jump_to_end();
198        }
199
200        Some(CompositeGlyphInfo {
201            glyph_id,
202            transform: ts,
203            flags,
204        })
205    }
206}
207
208// Due to some optimization magic, using f32 instead of i16
209// makes the code ~10% slower. At least on my machine.
210// I guess it's due to the fact that with i16 the struct
211// fits into the machine word.
212#[derive(Clone, Copy, Debug)]
213pub(crate) struct GlyphPoint {
214    pub x: i16,
215    pub y: i16,
216    /// Indicates that a point is a point on curve
217    /// and not a control point.
218    pub on_curve_point: bool,
219    pub last_point: bool,
220}
221
222#[derive(Clone, Default)]
223pub(crate) struct GlyphPointsIter<'a> {
224    endpoints: EndpointsIter<'a>,
225    flags: FlagsIter<'a>,
226    x_coords: CoordsIter<'a>,
227    y_coords: CoordsIter<'a>,
228    pub points_left: u16, // Number of points left in the glyph.
229}
230
231#[cfg(feature = "variable-fonts")]
232impl GlyphPointsIter<'_> {
233    #[inline]
234    pub fn current_contour(&self) -> u16 {
235        self.endpoints.index - 1
236    }
237}
238
239impl<'a> Iterator for GlyphPointsIter<'a> {
240    type Item = GlyphPoint;
241
242    #[inline]
243    fn next(&mut self) -> Option<Self::Item> {
244        self.points_left = self.points_left.checked_sub(1)?;
245
246        // TODO: skip empty contours
247
248        let last_point = self.endpoints.next();
249        let flags = self.flags.next()?;
250        Some(GlyphPoint {
251            x: self
252                .x_coords
253                .next(flags.x_short(), flags.x_is_same_or_positive_short()),
254            y: self
255                .y_coords
256                .next(flags.y_short(), flags.y_is_same_or_positive_short()),
257            on_curve_point: flags.on_curve_point(),
258            last_point,
259        })
260    }
261}
262
263/// A simple flattening iterator for glyph's endpoints.
264///
265/// Translates endpoints like: 2 4 7
266/// into flags: 0 0 1 0 1 0 0 1
267#[derive(Clone, Copy, Default)]
268struct EndpointsIter<'a> {
269    endpoints: LazyArray16<'a, u16>, // Each endpoint indicates a contour end.
270    index: u16,
271    left: u16,
272}
273
274impl<'a> EndpointsIter<'a> {
275    #[inline]
276    fn new(endpoints: LazyArray16<'a, u16>) -> Option<Self> {
277        Some(EndpointsIter {
278            endpoints,
279            index: 1,
280            left: endpoints.get(0)?,
281        })
282    }
283
284    #[inline]
285    fn next(&mut self) -> bool {
286        if self.left == 0 {
287            if let Some(end) = self.endpoints.get(self.index) {
288                let prev = self.endpoints.get(self.index - 1).unwrap_or(0);
289                // Malformed font can have endpoints not in increasing order,
290                // so we have to use checked_sub.
291                self.left = end.saturating_sub(prev);
292                self.left = self.left.saturating_sub(1);
293            }
294
295            // Always advance the index, so we can check the current contour number.
296            if let Some(n) = self.index.checked_add(1) {
297                self.index = n;
298            }
299
300            true
301        } else {
302            self.left -= 1;
303            false
304        }
305    }
306}
307
308#[derive(Clone, Default)]
309struct FlagsIter<'a> {
310    stream: Stream<'a>,
311    // Number of times the `flags` should be used
312    // before reading the next one from `stream`.
313    repeats: u8,
314    flags: SimpleGlyphFlags,
315}
316
317impl<'a> FlagsIter<'a> {
318    #[inline]
319    fn new(data: &'a [u8]) -> Self {
320        FlagsIter {
321            stream: Stream::new(data),
322            repeats: 0,
323            flags: SimpleGlyphFlags(0),
324        }
325    }
326}
327
328impl<'a> Iterator for FlagsIter<'a> {
329    type Item = SimpleGlyphFlags;
330
331    #[inline]
332    fn next(&mut self) -> Option<Self::Item> {
333        if self.repeats == 0 {
334            self.flags = SimpleGlyphFlags(self.stream.read::<u8>().unwrap_or(0));
335            if self.flags.repeat_flag() {
336                self.repeats = self.stream.read::<u8>().unwrap_or(0);
337            }
338        } else {
339            self.repeats -= 1;
340        }
341
342        Some(self.flags)
343    }
344}
345
346#[derive(Clone, Default)]
347struct CoordsIter<'a> {
348    stream: Stream<'a>,
349    prev: i16, // Points are stored as deltas, so we have to keep the previous one.
350}
351
352impl<'a> CoordsIter<'a> {
353    #[inline]
354    fn new(data: &'a [u8]) -> Self {
355        CoordsIter {
356            stream: Stream::new(data),
357            prev: 0,
358        }
359    }
360
361    #[inline]
362    fn next(&mut self, is_short: bool, is_same_or_short: bool) -> i16 {
363        // See https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#simple-glyph-description
364        // for details about Simple Glyph Flags processing.
365
366        // We've already checked the coords data, so it's safe to fallback to 0.
367
368        let mut n = 0;
369        if is_short {
370            n = i16::from(self.stream.read::<u8>().unwrap_or(0));
371            if !is_same_or_short {
372                n = -n;
373            }
374        } else if !is_same_or_short {
375            n = self.stream.read::<i16>().unwrap_or(0);
376        }
377
378        self.prev = self.prev.wrapping_add(n);
379        self.prev
380    }
381}
382
383#[derive(Clone, Copy, Debug)]
384struct Point {
385    x: f32,
386    y: f32,
387}
388
389impl Point {
390    #[inline]
391    fn lerp(self, other: Point, t: f32) -> Point {
392        Point {
393            x: self.x + t * (other.x - self.x),
394            y: self.y + t * (other.y - self.y),
395        }
396    }
397}
398
399// https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#simple-glyph-description
400#[derive(Clone, Copy, Default)]
401struct SimpleGlyphFlags(u8);
402
403#[rustfmt::skip]
404impl SimpleGlyphFlags {
405    #[inline] fn on_curve_point(self) -> bool { self.0 & 0x01 != 0 }
406    #[inline] fn x_short(self) -> bool { self.0 & 0x02 != 0 }
407    #[inline] fn y_short(self) -> bool { self.0 & 0x04 != 0 }
408    #[inline] fn repeat_flag(self) -> bool { self.0 & 0x08 != 0 }
409    #[inline] fn x_is_same_or_positive_short(self) -> bool { self.0 & 0x10 != 0 }
410    #[inline] fn y_is_same_or_positive_short(self) -> bool { self.0 & 0x20 != 0 }
411}
412
413// https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description
414#[derive(Clone, Copy, Debug)]
415pub(crate) struct CompositeGlyphFlags(u16);
416
417#[rustfmt::skip]
418impl CompositeGlyphFlags {
419    #[inline] pub fn arg_1_and_2_are_words(self) -> bool { self.0 & 0x0001 != 0 }
420    #[inline] pub fn args_are_xy_values(self) -> bool { self.0 & 0x0002 != 0 }
421    #[inline] pub fn we_have_a_scale(self) -> bool { self.0 & 0x0008 != 0 }
422    #[inline] pub fn more_components(self) -> bool { self.0 & 0x0020 != 0 }
423    #[inline] pub fn we_have_an_x_and_y_scale(self) -> bool { self.0 & 0x0040 != 0 }
424    #[inline] pub fn we_have_a_two_by_two(self) -> bool { self.0 & 0x0080 != 0 }
425}
426
427// It's not defined in the spec, so we are using our own value.
428pub(crate) const MAX_COMPONENTS: u8 = 32;
429
430#[allow(clippy::comparison_chain)]
431#[inline]
432fn outline_impl(
433    loca_table: loca::Table,
434    glyf_table: &[u8],
435    data: &[u8],
436    depth: u8,
437    builder: &mut Builder,
438) -> Option<Option<Rect>> {
439    if depth >= MAX_COMPONENTS {
440        return None;
441    }
442
443    let mut s = Stream::new(data);
444    let number_of_contours = s.read::<i16>()?;
445    s.advance(8); // Skip bbox. We use calculated one.
446
447    if number_of_contours > 0 {
448        // Simple glyph.
449
450        // u16 casting is safe, since we already checked that the value is positive.
451        let number_of_contours = NonZeroU16::new(number_of_contours as u16)?;
452        for point in parse_simple_outline(s.tail()?, number_of_contours)? {
453            builder.push_point(
454                f32::from(point.x),
455                f32::from(point.y),
456                point.on_curve_point,
457                point.last_point,
458            );
459        }
460    } else if number_of_contours < 0 {
461        // Composite glyph.
462        for comp in CompositeGlyphIter::new(s.tail()?) {
463            if let Some(range) = loca_table.glyph_range(comp.glyph_id) {
464                if let Some(glyph_data) = glyf_table.get(range) {
465                    let transform = Transform::combine(builder.transform, comp.transform);
466                    let mut b = Builder::new(transform, builder.bbox, builder.builder);
467                    outline_impl(loca_table, glyf_table, glyph_data, depth + 1, &mut b)?;
468
469                    // Take updated bbox.
470                    builder.bbox = b.bbox;
471                }
472            }
473        }
474    }
475
476    if builder.bbox.is_default() {
477        return Some(None);
478    }
479
480    Some(builder.bbox.to_rect())
481}
482
483#[inline]
484pub(crate) fn parse_simple_outline(
485    glyph_data: &[u8],
486    number_of_contours: NonZeroU16,
487) -> Option<GlyphPointsIter> {
488    let mut s = Stream::new(glyph_data);
489    let endpoints = s.read_array16::<u16>(number_of_contours.get())?;
490
491    let points_total = endpoints.last()?.checked_add(1)?;
492
493    // Contours with a single point should be ignored.
494    // But this is not an error, so we should return an "empty" iterator.
495    if points_total == 1 {
496        return Some(GlyphPointsIter::default());
497    }
498
499    // Skip instructions byte code.
500    let instructions_len = s.read::<u16>()?;
501    s.advance(usize::from(instructions_len));
502
503    let flags_offset = s.offset();
504    let (x_coords_len, y_coords_len) = resolve_coords_len(&mut s, points_total)?;
505    let x_coords_offset = s.offset();
506    let y_coords_offset = x_coords_offset + usize::num_from(x_coords_len);
507    let y_coords_end = y_coords_offset + usize::num_from(y_coords_len);
508
509    Some(GlyphPointsIter {
510        endpoints: EndpointsIter::new(endpoints)?,
511        flags: FlagsIter::new(glyph_data.get(flags_offset..x_coords_offset)?),
512        x_coords: CoordsIter::new(glyph_data.get(x_coords_offset..y_coords_offset)?),
513        y_coords: CoordsIter::new(glyph_data.get(y_coords_offset..y_coords_end)?),
514        points_left: points_total,
515    })
516}
517
518/// Resolves coordinate arrays length.
519///
520/// The length depends on *Simple Glyph Flags*, so we have to process them all to find it.
521fn resolve_coords_len(s: &mut Stream, points_total: u16) -> Option<(u32, u32)> {
522    let mut flags_left = u32::from(points_total);
523    let mut repeats;
524    let mut x_coords_len = 0;
525    let mut y_coords_len = 0;
526    while flags_left > 0 {
527        let flags = SimpleGlyphFlags(s.read::<u8>()?);
528
529        // The number of times a glyph point repeats.
530        repeats = if flags.repeat_flag() {
531            let repeats = s.read::<u8>()?;
532            u32::from(repeats) + 1
533        } else {
534            1
535        };
536
537        if repeats > flags_left {
538            return None;
539        }
540
541        // No need to check for `*_coords_len` overflow since u32 is more than enough.
542
543        // Non-obfuscated code below.
544        // Branchless version is surprisingly faster.
545        //
546        // if flags.x_short() {
547        //     // Coordinate is 1 byte long.
548        //     x_coords_len += repeats;
549        // } else if !flags.x_is_same_or_positive_short() {
550        //     // Coordinate is 2 bytes long.
551        //     x_coords_len += repeats * 2;
552        // }
553        // if flags.y_short() {
554        //     // Coordinate is 1 byte long.
555        //     y_coords_len += repeats;
556        // } else if !flags.y_is_same_or_positive_short() {
557        //     // Coordinate is 2 bytes long.
558        //     y_coords_len += repeats * 2;
559        // }
560
561        x_coords_len += (flags.0 & 0x02 != 0) as u32 * repeats;
562        x_coords_len += (flags.0 & (0x02 | 0x10) == 0) as u32 * (repeats * 2);
563
564        y_coords_len += (flags.0 & 0x04 != 0) as u32 * repeats;
565        y_coords_len += (flags.0 & (0x04 | 0x20) == 0) as u32 * (repeats * 2);
566
567        flags_left -= repeats;
568    }
569
570    Some((x_coords_len, y_coords_len))
571}
572
573/// A [Glyph Data Table](
574/// https://docs.microsoft.com/en-us/typography/opentype/spec/glyf).
575#[derive(Clone, Copy)]
576pub struct Table<'a> {
577    pub(crate) data: &'a [u8],
578    loca_table: loca::Table<'a>,
579}
580
581impl core::fmt::Debug for Table<'_> {
582    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
583        write!(f, "Table {{ ... }}")
584    }
585}
586
587impl<'a> Table<'a> {
588    /// Parses a table from raw data.
589    #[inline]
590    pub fn parse(loca_table: loca::Table<'a>, data: &'a [u8]) -> Option<Self> {
591        Some(Table { loca_table, data })
592    }
593
594    /// Outlines a glyph.
595    #[inline]
596    pub fn outline(&self, glyph_id: GlyphId, builder: &mut dyn OutlineBuilder) -> Option<Rect> {
597        let mut b = Builder::new(Transform::default(), RectF::new(), builder);
598        let glyph_data = self.get(glyph_id)?;
599        outline_impl(self.loca_table, self.data, glyph_data, 0, &mut b)?
600    }
601
602    /// The bounding box of the glyph. Unlike the `outline` method, this method does not
603    /// calculate the bounding box manually by outlining the glyph, but instead uses the
604    /// bounding box in the `glyf` program. As a result, this method will be much faster,
605    /// but the bounding box could be more inaccurate.
606    #[inline]
607    pub fn bbox(&self, glyph_id: GlyphId) -> Option<Rect> {
608        let glyph_data = self.get(glyph_id)?;
609
610        let mut s = Stream::new(glyph_data);
611        // number of contours
612        let _ = s.read::<i16>()?;
613        Some(Rect {
614            x_min: s.read::<i16>()?,
615            y_min: s.read::<i16>()?,
616            x_max: s.read::<i16>()?,
617            y_max: s.read::<i16>()?,
618        })
619    }
620
621    #[inline]
622    pub(crate) fn get(&self, glyph_id: GlyphId) -> Option<&'a [u8]> {
623        let range = self.loca_table.glyph_range(glyph_id)?;
624        self.data.get(range)
625    }
626
627    /// Returns the number of points in this outline.
628    pub(crate) fn outline_points(&self, glyph_id: GlyphId) -> u16 {
629        self.outline_points_impl(glyph_id).unwrap_or(0)
630    }
631
632    fn outline_points_impl(&self, glyph_id: GlyphId) -> Option<u16> {
633        let data = self.get(glyph_id)?;
634        let mut s = Stream::new(data);
635        let number_of_contours = s.read::<i16>()?;
636
637        // Skip bbox.
638        s.advance(8);
639
640        if number_of_contours > 0 {
641            // Simple glyph.
642            let number_of_contours = NonZeroU16::new(number_of_contours as u16)?;
643            let glyph_points = parse_simple_outline(s.tail()?, number_of_contours)?;
644            Some(glyph_points.points_left)
645        } else if number_of_contours < 0 {
646            // Composite glyph.
647            let components = CompositeGlyphIter::new(s.tail()?);
648            Some(components.clone().count() as u16)
649        } else {
650            // An empty glyph.
651            None
652        }
653    }
654}