Coverage Report

Created: 2026-09-01 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}