ttf_parser/tables/cmap/
format12.rs1use 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#[derive(Clone, Copy)]
31pub struct Subtable12<'a> {
32 groups: LazyArray32<'a, SequentialMapGroup>,
33}
34
35impl<'a> Subtable12<'a> {
36 pub fn parse(data: &'a [u8]) -> Option<Self> {
38 let mut s = Stream::new(data);
39 s.skip::<u16>(); s.skip::<u16>(); s.skip::<u32>(); s.skip::<u32>(); let count = s.read::<u32>()?;
44 let groups = s.read_array32::<SequentialMapGroup>(count)?;
45 Some(Self { groups })
46 }
47
48 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 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}