1 | use crate::buffer::Buffer; |
2 | use crate::plan::ShapePlan; |
3 | use crate::Face; |
4 | |
5 | pub fn apply(plan: &ShapePlan, face: &Face, buffer: &mut Buffer) -> 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 | |
44 | trait TrackTableExt { |
45 | fn hor_tracking(&self, ptem: f32) -> Option<i32>; |
46 | fn ver_tracking(&self, ptem: f32) -> Option<i32>; |
47 | } |
48 | |
49 | impl 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 | |
59 | trait 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 | |
69 | impl 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::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 | } |
116 | |