Coverage Report

Created: 2026-05-30 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ttf-parser/src/tables/trak.rs
Line
Count
Source
1
//! A [Tracking Table](
2
//! https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html) implementation.
3
4
use crate::parser::{Fixed, FromData, LazyArray16, Offset, Offset16, Offset32, Stream};
5
6
#[derive(Clone, Copy, Debug)]
7
struct TrackTableRecord {
8
    value: Fixed,
9
    name_id: u16,
10
    offset: Offset16, // Offset from start of the table.
11
}
12
13
impl FromData for TrackTableRecord {
14
    const SIZE: usize = 8;
15
16
    #[inline]
17
50.6k
    fn parse(data: &[u8]) -> Option<Self> {
18
50.6k
        let mut s = Stream::new(data);
19
        Some(TrackTableRecord {
20
50.6k
            value: s.read::<Fixed>()?,
21
50.6k
            name_id: s.read::<u16>()?,
22
50.6k
            offset: s.read::<Offset16>()?,
23
        })
24
50.6k
    }
25
}
26
27
/// A single track.
28
#[derive(Clone, Copy, Debug)]
29
pub struct Track<'a> {
30
    /// A track value.
31
    pub value: f32,
32
    /// The `name` table index for the track's name.
33
    pub name_index: u16,
34
    /// A list of tracking values for each size.
35
    pub values: LazyArray16<'a, i16>,
36
}
37
38
/// A list of tracks.
39
#[derive(Clone, Copy, Default, Debug)]
40
pub struct Tracks<'a> {
41
    data: &'a [u8], // the whole table
42
    records: LazyArray16<'a, TrackTableRecord>,
43
    sizes_count: u16,
44
}
45
46
impl<'a> Tracks<'a> {
47
    /// Returns a track at index.
48
50.6k
    pub fn get(&self, index: u16) -> Option<Track<'a>> {
49
50.6k
        let record = self.records.get(index)?;
50
50.6k
        let mut s = Stream::new(self.data.get(record.offset.to_usize()..)?);
51
        Some(Track {
52
50.6k
            value: record.value.0,
53
50.6k
            values: s.read_array16::<i16>(self.sizes_count)?,
54
50.6k
            name_index: record.name_id,
55
        })
56
50.6k
    }
57
58
    /// Returns the number of tracks.
59
50.6k
    pub fn len(&self) -> u16 {
60
50.6k
        self.records.len()
61
50.6k
    }
62
63
    /// Checks if there are any tracks.
64
0
    pub fn is_empty(&self) -> bool {
65
0
        self.records.is_empty()
66
0
    }
67
}
68
69
impl<'a> IntoIterator for Tracks<'a> {
70
    type Item = Track<'a>;
71
    type IntoIter = TracksIter<'a>;
72
73
    #[inline]
74
5
    fn into_iter(self) -> Self::IntoIter {
75
5
        TracksIter {
76
5
            tracks: self,
77
5
            index: 0,
78
5
        }
79
5
    }
80
}
81
82
/// An iterator over [`Tracks`].
83
#[allow(missing_debug_implementations)]
84
pub struct TracksIter<'a> {
85
    tracks: Tracks<'a>,
86
    index: u16,
87
}
88
89
impl<'a> Iterator for TracksIter<'a> {
90
    type Item = Track<'a>;
91
92
50.6k
    fn next(&mut self) -> Option<Self::Item> {
93
50.6k
        if self.index < self.tracks.len() {
94
50.6k
            self.index += 1;
95
50.6k
            self.tracks.get(self.index - 1)
96
        } else {
97
5
            None
98
        }
99
50.6k
    }
100
}
101
102
/// A track data.
103
#[derive(Clone, Copy, Default, Debug)]
104
pub struct TrackData<'a> {
105
    /// A list of tracks.
106
    pub tracks: Tracks<'a>,
107
    /// A list of sizes.
108
    pub sizes: LazyArray16<'a, Fixed>,
109
}
110
111
impl<'a> TrackData<'a> {
112
327
    fn parse(offset: usize, data: &'a [u8]) -> Option<Self> {
113
327
        let mut s = Stream::new_at(data, offset)?;
114
274
        let tracks_count = s.read::<u16>()?;
115
270
        let sizes_count = s.read::<u16>()?;
116
264
        let size_table_offset = s.read::<Offset32>()?; // Offset from start of the table.
117
118
207
        let tracks = Tracks {
119
252
            data,
120
252
            records: s.read_array16::<TrackTableRecord>(tracks_count)?,
121
207
            sizes_count,
122
        };
123
124
        // TODO: Isn't the size table is directly after the tracks table?!
125
        //       Why we need an offset then?
126
70
        let sizes = {
127
207
            let mut s = Stream::new_at(data, size_table_offset.to_usize())?;
128
139
            s.read_array16::<Fixed>(sizes_count)?
129
        };
130
131
70
        Some(TrackData { tracks, sizes })
132
327
    }
133
}
134
135
/// A [Tracking Table](
136
/// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html).
137
#[derive(Clone, Copy, Debug)]
138
pub struct Table<'a> {
139
    /// Horizontal track data.
140
    pub horizontal: TrackData<'a>,
141
    /// Vertical track data.
142
    pub vertical: TrackData<'a>,
143
}
144
145
impl<'a> Table<'a> {
146
    /// Parses a table from raw data.
147
417
    pub fn parse(data: &'a [u8]) -> Option<Self> {
148
417
        let mut s = Stream::new(data);
149
150
417
        let version = s.read::<u32>()?;
151
412
        if version != 0x00010000 {
152
94
            return None;
153
318
        }
154
155
318
        let format = s.read::<u16>()?;
156
313
        if format != 0 {
157
20
            return None;
158
293
        }
159
160
293
        let hor_offset = s.read::<Option<Offset16>>()?;
161
289
        let ver_offset = s.read::<Option<Offset16>>()?;
162
285
        s.skip::<u16>(); // reserved
163
164
285
        let horizontal = if let Some(offset) = hor_offset {
165
226
            TrackData::parse(offset.to_usize(), data)?
166
        } else {
167
59
            TrackData::default()
168
        };
169
170
111
        let vertical = if let Some(offset) = ver_offset {
171
101
            TrackData::parse(offset.to_usize(), data)?
172
        } else {
173
10
            TrackData::default()
174
        };
175
176
28
        Some(Table {
177
28
            horizontal,
178
28
            vertical,
179
28
        })
180
417
    }
181
}