rustybuzz/hb/
aat_layout_trak_table.rs

1#[cfg(not(feature = "std"))]
2use core_maths::CoreFloat;
3
4use super::buffer::hb_buffer_t;
5use super::hb_font_t;
6use super::ot_shape_plan::hb_ot_shape_plan_t;
7
8pub fn apply(plan: &hb_ot_shape_plan_t, face: &hb_font_t, buffer: &mut hb_buffer_t) -> Option<()> {
9    let trak_mask = plan.trak_mask;
10
11    let ptem = face.points_per_em?;
12    if ptem <= 0.0 {
13        return None;
14    }
15
16    let trak = face.tables().trak?;
17
18    if !buffer.have_positions {
19        buffer.clear_positions();
20    }
21
22    if buffer.direction.is_horizontal() {
23        let tracking = trak.hor_tracking(ptem)?;
24        let advance_to_add = tracking;
25        let offset_to_add = tracking / 2;
26        foreach_grapheme!(buffer, start, end, {
27            if buffer.info[start].mask & trak_mask != 0 {
28                buffer.pos[start].x_advance += advance_to_add;
29                buffer.pos[start].x_offset += offset_to_add;
30            }
31        });
32    } else {
33        let tracking = trak.ver_tracking(ptem)?;
34        let advance_to_add = tracking;
35        let offset_to_add = tracking / 2;
36        foreach_grapheme!(buffer, start, end, {
37            if buffer.info[start].mask & trak_mask != 0 {
38                buffer.pos[start].y_advance += advance_to_add;
39                buffer.pos[start].y_offset += offset_to_add;
40            }
41        });
42    }
43
44    Some(())
45}
46
47trait TrackTableExt {
48    fn hor_tracking(&self, ptem: f32) -> Option<i32>;
49    fn ver_tracking(&self, ptem: f32) -> Option<i32>;
50}
51
52impl TrackTableExt for ttf_parser::trak::Table<'_> {
53    fn hor_tracking(&self, ptem: f32) -> Option<i32> {
54        self.horizontal.tracking(ptem)
55    }
56
57    fn ver_tracking(&self, ptem: f32) -> Option<i32> {
58        self.vertical.tracking(ptem)
59    }
60}
61
62trait TrackTableDataExt {
63    fn tracking(&self, ptem: f32) -> Option<i32>;
64    fn interpolate_at(
65        &self,
66        idx: u16,
67        target_size: f32,
68        track: &ttf_parser::trak::Track,
69    ) -> Option<f32>;
70}
71
72impl TrackTableDataExt for ttf_parser::trak::TrackData<'_> {
73    fn tracking(&self, ptem: f32) -> Option<i32> {
74        // Choose track.
75        let track = self.tracks.into_iter().find(|t| t.value == 0.0)?;
76
77        // Choose size.
78        if self.sizes.is_empty() {
79            return None;
80        }
81
82        let mut idx = self
83            .sizes
84            .into_iter()
85            .position(|s| s.0 >= ptem)
86            .unwrap_or(self.sizes.len() as usize - 1);
87
88        idx = idx.saturating_sub(1);
89
90        self.interpolate_at(idx as u16, ptem, &track)
91            .map(|n| n.round() as i32)
92    }
93
94    fn interpolate_at(
95        &self,
96        idx: u16,
97        target_size: f32,
98        track: &ttf_parser::trak::Track,
99    ) -> Option<f32> {
100        debug_assert!(idx < self.sizes.len() - 1);
101
102        let s0 = self.sizes.get(idx)?.0;
103        let s1 = self.sizes.get(idx + 1)?.0;
104
105        let t = if s0 == s1 {
106            0.0
107        } else {
108            (target_size - s0) / (s1 - s0)
109        };
110
111        let n =
112            t * (track.values.get(idx + 1)? as f32) + (1.0 - t) * (track.values.get(idx)? as f32);
113
114        Some(n)
115    }
116}