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<'_> = 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}
83