ttf_parser/tables/cmap/
format2.rs
1use core::convert::TryFrom;
8
9use crate::parser::{Stream, FromData};
10
11#[derive(Clone, Copy)]
12struct SubHeaderRecord {
13 first_code: u16,
14 entry_count: u16,
15 id_delta: i16,
16 id_range_offset: u16,
17}
18
19impl FromData for SubHeaderRecord {
20 const SIZE: usize = 8;
21
22 #[inline]
23 fn parse(data: &[u8]) -> Option<Self> {
24 let mut s = Stream::new(data);
25 Some(SubHeaderRecord {
26 first_code: s.read::<u16>()?,
27 entry_count: s.read::<u16>()?,
28 id_delta: s.read::<i16>()?,
29 id_range_offset: s.read::<u16>()?,
30 })
31 }
32}
33
34pub fn parse(data: &[u8], code_point: u32) -> Option<u16> {
35 let code_point = u16::try_from(code_point).ok()?;
37
38 let code_point = code_point;
39 let high_byte = code_point >> 8;
40 let low_byte = code_point & 0x00FF;
41
42 let mut s = Stream::new(data);
43 s.skip::<u16>(); s.skip::<u16>(); s.skip::<u16>(); let sub_header_keys = s.read_array16::<u16>(256)?;
47 let sub_headers_count = sub_header_keys.into_iter().map(|n| n / 8).max()? + 1;
49
50 let sub_headers_offset = s.offset();
52 let sub_headers = s.read_array16::<SubHeaderRecord>(sub_headers_count)?;
53
54 let i = if code_point < 0xff {
55 0
57 } else {
58 sub_header_keys.get(high_byte)? / 8
60 };
61
62 let sub_header = sub_headers.get(i)?;
63
64 let first_code = sub_header.first_code;
65 let range_end = first_code.checked_add(sub_header.entry_count)?;
66 if low_byte < first_code || low_byte >= range_end {
67 return None;
68 }
69
70 let index_offset = usize::from(low_byte.checked_sub(first_code)?) * u16::SIZE;
73
74 let offset =
77 sub_headers_offset
78 + SubHeaderRecord::SIZE * usize::from(i + 1)
80 - u16::SIZE
82 + usize::from(sub_header.id_range_offset)
84 + index_offset;
86
87 let glyph: u16 = Stream::read_at(data, offset)?;
88 if glyph == 0 {
89 return None;
90 }
91
92 u16::try_from((i32::from(glyph) + i32::from(sub_header.id_delta)) % 65536).ok()
93}
94
95pub fn codepoints(data: &[u8], mut f: impl FnMut(u32)) -> Option<()> {
96 let mut s = Stream::new(data);
97 s.skip::<u16>(); s.skip::<u16>(); s.skip::<u16>(); let sub_header_keys = s.read_array16::<u16>(256)?;
101
102 let sub_headers_count = sub_header_keys.into_iter().map(|n| n / 8).max()? + 1;
104 let sub_headers = s.read_array16::<SubHeaderRecord>(sub_headers_count)?;
105
106 for first_byte in 0u16..256 {
107 let i = sub_header_keys.get(first_byte)? / 8;
108 let sub_header = sub_headers.get(i)?;
109 let first_code = sub_header.first_code;
110
111 if i == 0 {
112 let range_end = first_code.checked_add(sub_header.entry_count)?;
114 if first_byte >= first_code && first_byte < range_end {
115 f(u32::from(first_byte));
116 }
117 } else {
118 let base = first_code.checked_add(first_byte << 8)?;
120 for k in 0..sub_header.entry_count {
121 let code_point = base.checked_add(k)?;
122 f(u32::from(code_point));
123 }
124 }
125 }
126
127 Some(())
128}
129
130#[cfg(test)]
131mod tests {
132 use crate::parser::FromData;
133 use super::{parse, codepoints};
134
135 #[test]
136 fn collect_codepoints() {
137 let mut data = vec![
138 0x00, 0x02, 0x02, 0x16, 0x00, 0x00, ];
142
143 data.extend(std::iter::repeat(0x00).take(256 * u16::SIZE));
145 data[6 + 0x28 * u16::SIZE + 1] = 0x08;
146
147 data.extend(&[
148 0x00, 0xFE, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, ]);
159
160 let mut vec = vec![];
163 codepoints(&data, |c| vec.push(c));
164 assert_eq!(vec, [10256, 10257, 10258, 254, 255]);
165 }
166
167 #[test]
168 fn codepoint_at_range_end() {
169 let mut data = vec![
170 0x00, 0x02, 0x02, 0x14, 0x00, 0x00, ];
174
175 data.extend(std::iter::repeat(0x00).take(256 * u16::SIZE));
177 data.extend(&[
178 0x00, 0x28, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x03, 0xE8, 0x03, 0xE8, ]);
188
189 assert_eq!(parse(&data, 39), None);
190 assert_eq!(parse(&data, 40), Some(100));
191 assert_eq!(parse(&data, 41), Some(1000));
192 assert_eq!(parse(&data, 42), None);
193 }
194}