Skip to main content

ttf_view/tables/cmap/
format2.rs

1use crate::{
2    tables::cmap::GlyphId,
3    types::{int16, uint16},
4};
5
6#[repr(C)]
7#[non_exhaustive]
8pub struct CmapSubtableFormat2Repr {
9    pub sub_header_keys: [uint16; 256],
10    sub_headers: [SubHeaderRepr; 0],
11    glyph_id_array: [uint16; 0],
12}
13
14#[repr(C)]
15#[non_exhaustive]
16pub struct SubHeaderRepr {
17    pub first_code: uint16,
18    pub entry_count: uint16,
19    pub id_delta: int16,
20    pub id_range_offset: uint16,
21}
22
23impl CmapSubtableFormat2Repr {
24    pub fn sub_headers(&self) -> &[SubHeaderRepr] {
25        let max_offset = self.sub_header_keys.iter().max().unwrap().get();
26        let count = (max_offset / 8) + 1;
27        unsafe { std::slice::from_raw_parts(self.sub_headers.as_ptr(), count as _) }
28    }
29    pub const fn sub_header(&self, high_byte: u8) -> &SubHeaderRepr {
30        let offset = self.sub_header_keys[high_byte as usize].get();
31        unsafe { &*self.sub_headers.as_ptr().byte_add(offset as usize) }
32    }
33    pub const fn sub_header_zero(&self) -> &SubHeaderRepr {
34        unsafe { &*self.sub_headers.as_ptr() }
35    }
36
37    pub const fn map_one(&self, single_byte: u8) -> GlyphId {
38        self.sub_header_zero().map(single_byte)
39    }
40    pub const fn map_two(&self, high_byte: u8, low_byte: u8) -> GlyphId {
41        self.sub_header(high_byte).map(low_byte)
42    }
43}
44
45impl SubHeaderRepr {
46    pub const fn map(&self, low_byte: u8) -> GlyphId {
47        let offset = (low_byte as u16).checked_sub(self.first_code.get())?;
48        if offset > self.entry_count.get() {
49            return GlyphId::NOTDEF;
50        }
51
52        let mut result = unsafe {
53            (&*std::ptr::from_ref(&self.id_range_offset)
54                .byte_add(self.id_range_offset.get() as _)
55                .add(offset as _))
56                .get()
57        };
58        if result != 0 {
59            result = result.wrapping_add_signed(self.id_delta.get());
60        }
61
62        GlyphId::new(result)
63    }
64}