/src/ttf-parser/src/tables/cmap/format12.rs
Line | Count | Source |
1 | | use core::convert::TryFrom; |
2 | | |
3 | | use crate::GlyphId; |
4 | | use crate::parser::{FromData, LazyArray32, Stream}; |
5 | | |
6 | | #[derive(Clone, Copy)] |
7 | | pub struct SequentialMapGroup { |
8 | | pub start_char_code: u32, |
9 | | pub end_char_code: u32, |
10 | | pub start_glyph_id: u32, |
11 | | } |
12 | | |
13 | | impl FromData for SequentialMapGroup { |
14 | | const SIZE: usize = 12; |
15 | | |
16 | | #[inline] |
17 | 39.8k | fn parse(data: &[u8]) -> Option<Self> { |
18 | 39.8k | let mut s = Stream::new(data); |
19 | | Some(SequentialMapGroup { |
20 | 39.8k | start_char_code: s.read::<u32>()?, |
21 | 39.8k | end_char_code: s.read::<u32>()?, |
22 | 39.8k | start_glyph_id: s.read::<u32>()?, |
23 | | }) |
24 | 39.8k | } |
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)] |
30 | | pub struct Subtable12<'a> { |
31 | | groups: LazyArray32<'a, SequentialMapGroup>, |
32 | | } |
33 | | |
34 | | impl<'a> Subtable12<'a> { |
35 | | /// Parses a subtable from raw data. |
36 | 6.01k | pub fn parse(data: &'a [u8]) -> Option<Self> { |
37 | 6.01k | let mut s = Stream::new(data); |
38 | 6.01k | s.skip::<u16>(); // format |
39 | 6.01k | s.skip::<u16>(); // reserved |
40 | 6.01k | s.skip::<u32>(); // length |
41 | 6.01k | s.skip::<u32>(); // language |
42 | 6.01k | let count = s.read::<u32>()?; |
43 | 5.98k | let groups = s.read_array32::<SequentialMapGroup>(count)?; |
44 | 5.57k | Some(Self { groups }) |
45 | 6.01k | } |
46 | | |
47 | | /// Returns a glyph index for a code point. |
48 | 5.27k | pub fn glyph_index(&self, code_point: u32) -> Option<GlyphId> { |
49 | 18.1k | let (_, group) = self.groups.binary_search_by(|range| { |
50 | | use core::cmp::Ordering; |
51 | | |
52 | 18.1k | if range.start_char_code > code_point { |
53 | 4.30k | Ordering::Greater |
54 | 13.8k | } else if range.end_char_code < code_point { |
55 | 8.52k | Ordering::Less |
56 | | } else { |
57 | 5.29k | Ordering::Equal |
58 | | } |
59 | 18.1k | })?; |
60 | | |
61 | 2.51k | let id = group |
62 | 2.51k | .start_glyph_id |
63 | 2.51k | .checked_add(code_point)? |
64 | 2.20k | .checked_sub(group.start_char_code)?; |
65 | 2.20k | u16::try_from(id).ok().map(GlyphId) |
66 | 5.27k | } |
67 | | |
68 | | /// Iterate over each codepoint defined in this table. |
69 | 0 | pub fn codepoints_iter(self) -> impl Iterator<Item = u32> + 'a { |
70 | 0 | self.groups |
71 | 0 | .into_iter() |
72 | 0 | .flat_map(|group| group.start_char_code..=group.end_char_code) |
73 | 0 | } |
74 | | |
75 | | /// Calls `f` for each codepoint defined in this table. |
76 | | pub fn codepoints(&self, f: impl FnMut(u32)) { |
77 | | self.codepoints_iter().for_each(f) |
78 | | } |
79 | | } |
80 | | |
81 | | impl core::fmt::Debug for Subtable12<'_> { |
82 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
83 | 0 | write!(f, "Subtable12 {{ ... }}") |
84 | 0 | } |
85 | | } |