Skip to main content

ttf_view/tables/glyf/
simple.rs

1use crate::{
2    tables::glyf::Glyph,
3    types::{int16, uint16},
4};
5use std::ptr::NonNull;
6
7#[repr(C)]
8pub struct SimpleGlyph {
9    base: Glyph,
10    end_pts_of_contours: [uint16; 0],
11    // : instruction_length: uint16,
12    // : instructions: [u8; instruction_length],
13    // : flags: [u8; variable],
14    // : x_coordinates: [u8/i16; variable],
15    // : y_coordinates: [u8/i16; variable],
16}
17
18const impl std::ops::Deref for SimpleGlyph {
19    type Target = Glyph;
20    fn deref(&self) -> &Self::Target {
21        &self.base
22    }
23}
24
25impl SimpleGlyph {
26    pub const fn end_pts_of_contours(&self) -> &[uint16] {
27        let len = self.number_of_contours.get() as usize;
28        unsafe { std::slice::from_raw_parts(self.end_pts_of_contours.as_ptr(), len) }
29    }
30    pub const fn instruction_length(&self) -> uint16 {
31        unsafe { *self.end_pts_of_contours().as_ptr_range().end }
32    }
33    pub const fn instructions(&self) -> &[u8] {
34        let len_ptr = self.end_pts_of_contours().as_ptr_range().end;
35        let len = unsafe { *len_ptr }.get() as usize;
36        unsafe { std::slice::from_raw_parts(len_ptr.byte_add(2).cast(), len) }
37    }
38    pub const fn flags_ptr(&self) -> NonNull<PointFlags> {
39        let ptr = self.instructions().as_ptr_range().end.cast_mut();
40        unsafe { NonNull::new_unchecked(ptr.cast()) }
41    }
42}
43
44bitflags::bitflags! {
45    #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
46    pub struct PointFlags: u8 {
47        const ON_CURVE_POINT = 0x01;
48        const X_IS_SHORT = 0x02;
49        const Y_IS_SHORT = 0x04;
50        const REPEAT_FLAG = 0x08;
51        const X_IS_SAME_OR_POS = 0x10;
52        const Y_IS_SAME_OR_POS = 0x20;
53        const OVERLAP_SIMPLE = 0x40;
54        const RESERVED = 0x80;
55    }
56}
57
58impl PointFlags {
59    pub const fn on_curve(&self) -> bool {
60        self.intersects(Self::ON_CURVE_POINT)
61    }
62    pub const fn is_x_short(&self) -> bool {
63        self.intersects(Self::X_IS_SHORT)
64    }
65    pub const fn is_y_short(&self) -> bool {
66        self.intersects(Self::Y_IS_SHORT)
67    }
68    pub const fn is_repeating(&self) -> bool {
69        self.intersects(Self::REPEAT_FLAG)
70    }
71    pub const fn is_x_same_or_pos(&self) -> bool {
72        self.intersects(Self::X_IS_SAME_OR_POS)
73    }
74    pub const fn is_y_same_or_pos(&self) -> bool {
75        self.intersects(Self::Y_IS_SAME_OR_POS)
76    }
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub struct Point {
81    pub flags: PointFlags,
82    pub dx: i16,
83    pub dy: i16,
84}
85
86/// PointsIter<'a> will iterate through all flags, and parse the points.
87///
88/// Flags need to be read until we get past (last end point index + 1)
89pub struct PointsIter<'a> {
90    end_points_of_contours: NonNull<uint16>,
91    number_of_contours: u16,
92    point_index: u16,
93    repeat_flag: PointFlags,
94    repeat_count: u8,
95    flags_ptr: NonNull<PointFlags>,
96    x_coords: NonNull<()>,
97    y_coords: NonNull<()>,
98    _phantom: std::marker::PhantomData<&'a ()>,
99}
100
101fn find_lengths(mut ptr: NonNull<PointFlags>, mut points_left: u32) -> (u32, u32, u32) {
102    let started_from = ptr;
103    let mut xs_len = 0;
104    let mut ys_len = 0;
105
106    while points_left > 0 {
107        let flag = unsafe { ptr.read() };
108        unsafe { ptr = ptr.byte_add(1) };
109
110        let count = if flag.is_repeating() {
111            unsafe {
112                let repeats = ptr.read().bits();
113                ptr = ptr.byte_add(1);
114                1 + repeats as u32
115            }
116        } else {
117            1
118        };
119
120        points_left = points_left.saturating_sub(count);
121
122        // | short | same_or_pos | value | size |
123        // |-------|-------------|-------|------|
124        // | 0 | 0 | int16 | 2 |
125        // | 0 | 1 | 0     | 0 |
126        // | 1 | 0 | - u8  | 1 |
127        // | 1 | 1 | + u8  | 1 |
128
129        xs_len += flag.is_x_short() as u32 * count;
130        const X_FLAGS: PointFlags = PointFlags::X_IS_SHORT.union(PointFlags::X_IS_SAME_OR_POS);
131        xs_len += !flag.intersects(X_FLAGS) as u32 * count * 2;
132
133        ys_len += flag.is_y_short() as u32 * count;
134        const Y_FLAGS: PointFlags = PointFlags::Y_IS_SHORT.union(PointFlags::Y_IS_SAME_OR_POS);
135        ys_len += !flag.intersects(Y_FLAGS) as u32 * count * 2;
136    }
137
138    let flags_len = unsafe { ptr.offset_from_unsigned(started_from) } as u32;
139    (flags_len, xs_len, ys_len)
140}
141
142impl<'a> PointsIter<'a> {
143    pub fn new(glyph: &'a SimpleGlyph) -> Self {
144        let flags_ptr = glyph.flags_ptr();
145        let points_count = glyph.end_pts_of_contours().last().map_or(0, |x| x.get() as u32) + 1;
146        let (flags_len, xs_len, _ys_len) = find_lengths(flags_ptr, points_count);
147
148        Self {
149            end_points_of_contours: NonNull::from_ref(&glyph.end_pts_of_contours).cast(),
150            number_of_contours: glyph.number_of_contours.get() as u16,
151            point_index: 0,
152            repeat_flag: PointFlags::default(),
153            repeat_count: 0,
154            flags_ptr,
155            x_coords: unsafe { flags_ptr.byte_add(flags_len as _).cast() },
156            y_coords: unsafe { flags_ptr.byte_add((flags_len + xs_len) as _).cast() },
157            _phantom: Default::default(),
158        }
159    }
160    pub const fn end_points_of_contours(&self) -> &[uint16] {
161        let len = self.number_of_contours as usize;
162        unsafe { std::slice::from_raw_parts(self.end_points_of_contours.as_ptr(), len) }
163    }
164    pub fn contour_index(&self, point_index: u16) -> Option<u16> {
165        self.end_points_of_contours().iter().position(|x| *x >= point_index).map(|x| x as u16)
166    }
167}
168
169impl<'a> Iterator for PointsIter<'a> {
170    type Item = (u16, Point);
171    fn next(&mut self) -> Option<Self::Item> {
172        let flag = unsafe {
173            if self.repeat_count != 0 {
174                self.repeat_count -= 1;
175                self.repeat_flag
176            } else {
177                let next = self.flags_ptr.read();
178                self.flags_ptr = self.flags_ptr.byte_add(1);
179                if next.is_repeating() {
180                    self.repeat_flag = next;
181                    self.repeat_count = self.flags_ptr.read().bits();
182                    self.flags_ptr = self.flags_ptr.byte_add(1);
183                }
184                next
185            }
186        };
187
188        use PointFlags as PF;
189        // | short | same_or_pos | value | size |
190        // |-------|-------------|-------|------|
191        // | 0 | 0 | int16 | 2 |
192        // | 0 | 1 | 0     | 0 |
193        // | 1 | 0 | - u8  | 1 |
194        // | 1 | 1 | + u8  | 1 |
195
196        let dx = unsafe {
197            match (flag.intersects(PF::X_IS_SHORT), flag.intersects(PF::X_IS_SAME_OR_POS)) {
198                (false, false) => {
199                    let dx = self.x_coords.cast::<int16>().as_ref().get();
200                    self.x_coords = self.x_coords.byte_add(2);
201                    dx
202                },
203                (false, true) => 0,
204                (true, false) => {
205                    let dx = self.x_coords.cast::<u8>().read();
206                    self.x_coords = self.x_coords.byte_add(1);
207                    -(dx as i16)
208                },
209                (true, true) => {
210                    let dx = self.x_coords.cast::<u8>().read();
211                    self.x_coords = self.x_coords.byte_add(1);
212                    dx as i16
213                },
214            }
215        };
216        let dy = unsafe {
217            match (flag.intersects(PF::Y_IS_SHORT), flag.intersects(PF::Y_IS_SAME_OR_POS)) {
218                (false, false) => {
219                    let dy = self.y_coords.cast::<int16>().as_ref().get();
220                    self.y_coords = self.y_coords.byte_add(2);
221                    dy
222                },
223                (false, true) => 0,
224                (true, false) => {
225                    let dy = self.y_coords.cast::<u8>().read();
226                    self.y_coords = self.y_coords.byte_add(1);
227                    -(dy as i16)
228                },
229                (true, true) => {
230                    let dy = self.y_coords.cast::<u8>().read();
231                    self.y_coords = self.y_coords.byte_add(1);
232                    dy as i16
233                },
234            }
235        };
236
237        let idx = self.point_index;
238        self.point_index = self.point_index.wrapping_add(1);
239
240        Some((idx, Point { flags: flag, dx, dy }))
241    }
242}