rustybuzz/hb/
aat_layout_trak_table.rs

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