ttf_parser/tables/cmap/
format12.rs

1use core::convert::TryFrom;
2
3use crate::parser::{FromData, LazyArray32, Stream};
4use crate::GlyphId;
5
6#[derive(Clone, Copy)]
7pub struct SequentialMapGroup {
8    pub start_char_code: u32,
9    pub end_char_code: u32,
10    pub start_glyph_id: u32,
11}
12
13impl FromData for SequentialMapGroup {
14    const SIZE: usize = 12;
15
16    #[inline]
17    fn parse(data: &[u8]) -> Option<Self> {
18        let mut s = Stream::new(data);
19        Some(SequentialMapGroup {
20            start_char_code: s.read::<u32>()?,
21            end_char_code: s.read::<u32>()?,
22            start_glyph_id: s.read::<u32>()?,
23        })
24    }
25}
26
27
28/// A [format 12](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-12-segmented-coverage)
29/// subtable.
30#[derive(Clone, Copy)]
31pub struct Subtable12<'a> {
32    groups: LazyArray32<'a, SequentialMapGroup>,
33}
34
35impl<'a> Subtable12<'a> {
36    /// Parses a subtable from raw data.
37    pub fn parse(data: &'a [u8]) -> Option<Self> {
38        let mut s = Stream::new(data);
39        s.skip::<u16>(); // format
40        s.skip::<u16>(); // reserved
41        s.skip::<u32>(); // length
42        s.skip::<u32>(); // language
43        let count = s.read::<u32>()?;
44        let groups = s.read_array32::<SequentialMapGroup>(count)?;
45        Some(Self { groups })
46    }
47
48    /// Returns a glyph index for a code point.
49    pub fn glyph_index(&self, code_point: u32) -> Option<GlyphId> {
50        let (_, group) = self.groups.binary_search_by(|range| {
51            use core::cmp::Ordering;
52
53            if range.start_char_code > code_point {
54                Ordering::Greater
55            } else if range.end_char_code < code_point {
56                Ordering::Less
57            } else {
58                Ordering::Equal
59            }
60        })?;
61
62        let id = group.start_glyph_id.checked_add(code_point)?.checked_sub(group.start_char_code)?;
63        return u16::try_from(id).ok().map(GlyphId);
64    }
65
66    /// Calls `f` for each codepoint defined in this table.
67    pub fn codepoints(&self, mut f: impl FnMut(u32)) {
68        for group in self.groups {
69            for code_point in group.start_char_code..=group.end_char_code {
70                f(code_point);
71            }
72        }
73    }
74}
75
76impl core::fmt::Debug for Subtable12<'_> {
77    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
78        write!(f, "Subtable12 {{ ... }}")
79    }
80}