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