read_fonts/tables/
ankr.rs

1//! The [anchor point](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6ankr.html) table.
2
3use super::aat::LookupU16;
4
5include!("../../generated/generated_ankr.rs");
6
7impl<'a> Ankr<'a> {
8    /// Returns the set of anchor points for the given glyph.
9    pub fn anchor_points(&self, glyph_id: GlyphId) -> Result<&'a [AnchorPoint], ReadError> {
10        let glyph_id: GlyphId16 = glyph_id.try_into().map_err(|_| ReadError::OutOfBounds)?;
11        let entry_offset = self.lookup_table()?.value(glyph_id.to_u16())?;
12        let full_offset = (self.glyph_data_table_offset() as usize)
13            .checked_add(entry_offset as usize)
14            .ok_or(ReadError::OutOfBounds)?;
15        let data = self
16            .offset_data()
17            .split_off(full_offset)
18            .ok_or(ReadError::OutOfBounds)?;
19        Ok(GlyphDataEntry::read(data)?.anchor_points())
20    }
21}
22
23#[cfg(test)]
24mod tests {
25    use font_test_data::bebuffer::BeBuffer;
26
27    use super::*;
28
29    #[test]
30    fn anchor_points() {
31        let mut buf = BeBuffer::new();
32        // lookup table (glyph_id -> offset)
33        #[rustfmt::skip]
34        let lookup = [
35            0_u16, // format
36            0, 8, 24, 32 // offsets to anchor points
37        ];
38        let lookup_size = lookup.len() as u32 * 2;
39        // header
40        buf = buf.extend([0u32, 0x0000000C, 12 + lookup_size]);
41        buf = buf.extend(lookup);
42        // glyph entry data
43        #[rustfmt::skip]
44        let expected_anchor_points: [&[(i16, i16)]; 4] = [
45            &[(-20, 20)],
46            &[(42, -10), (-200, 300), (i16::MIN, i16::MAX)],
47            &[(0, 4)],
48            &[(0, 0), (64, -64)],
49        ];
50        for entry in &expected_anchor_points {
51            buf = buf
52                .push(entry.len() as u32)
53                .extend(entry.iter().flat_map(|x| [x.0, x.1]));
54        }
55        let ankr = Ankr::read(buf.data().into()).unwrap();
56        let anchor_points = (0..4)
57            .map(|gid| {
58                let points = ankr.anchor_points(GlyphId::new(gid)).unwrap();
59                points
60                    .iter()
61                    .map(|point| (point.x(), point.y()))
62                    .collect::<Vec<_>>()
63            })
64            .collect::<Vec<_>>();
65        assert!(expected_anchor_points.iter().eq(anchor_points.iter()));
66    }
67}