harfrust/hb/
ot_layout_gpos_table.rs1use super::buffer::*;
2use super::font_funcs::FontFuncsDispatch;
3use super::hb_font_t;
4use super::ot_layout::*;
5use super::ot_shape_plan::hb_ot_shape_plan_t;
6use crate::Direction;
7
8pub fn position(
9 plan: &hb_ot_shape_plan_t,
10 face: &hb_font_t,
11 font_funcs: &mut FontFuncsDispatch,
12 buffer: &mut hb_buffer_t,
13) {
14 apply_layout_table(plan, face, font_funcs, buffer, face.ot_tables.gpos.as_ref());
15}
16
17pub mod attach_type {
18 pub const MARK: u8 = 1;
19 pub const CURSIVE: u8 = 2;
20}
21
22fn propagate_attachment_offsets(
24 pos: &mut [GlyphPosition],
25 len: usize,
26 i: usize,
27 direction: Direction,
28 nesting_level: usize,
29) {
30 let chain = pos[i].attach_chain();
33 let kind = pos[i].attach_type();
34
35 pos[i].set_attach_chain(0);
36
37 let j = (i as isize + isize::from(chain)) as usize;
38 if j >= len {
39 return;
40 }
41
42 if nesting_level == 0 {
43 return;
44 }
45
46 if pos[j].attach_chain() != 0 {
47 propagate_attachment_offsets(pos, len, j, direction, nesting_level - 1);
48 }
49
50 match kind {
51 attach_type::MARK => {
52 pos[i].x_offset = pos[i].x_offset.saturating_add(pos[j].x_offset);
53 pos[i].y_offset = pos[i].y_offset.saturating_add(pos[j].y_offset);
54
55 if j < i {
57 if direction.is_forward() {
60 for k in j..i {
61 pos[i].x_offset = pos[i].x_offset.saturating_sub(pos[k].x_advance);
62 pos[i].y_offset = pos[i].y_offset.saturating_sub(pos[k].y_advance);
63 }
64 } else {
65 for k in j + 1..i + 1 {
66 pos[i].x_offset = pos[i].x_offset.saturating_add(pos[k].x_advance);
67 pos[i].y_offset = pos[i].y_offset.saturating_add(pos[k].y_advance);
68 }
69 }
70 } else {
71 if direction.is_forward() {
74 for k in i..j {
75 pos[i].x_offset = pos[i].x_offset.saturating_add(pos[k].x_advance);
76 pos[i].y_offset = pos[i].y_offset.saturating_add(pos[k].y_advance);
77 }
78 } else {
79 for k in i + 1..j + 1 {
80 pos[i].x_offset = pos[i].x_offset.saturating_sub(pos[k].x_advance);
81 pos[i].y_offset = pos[i].y_offset.saturating_sub(pos[k].y_advance);
82 }
83 }
84 }
85 }
86 attach_type::CURSIVE => {
87 if direction.is_horizontal() {
88 pos[i].y_offset = pos[i].y_offset.saturating_add(pos[j].y_offset);
89 } else {
90 pos[i].x_offset = pos[i].x_offset.saturating_add(pos[j].x_offset);
91 }
92 }
93 _ => {}
94 }
95}
96
97pub mod GPOS {
98 use super::*;
99
100 pub fn position_start(_: &hb_font_t, buffer: &mut hb_buffer_t) {
101 let len = buffer.len;
102 for pos in &mut buffer.pos[..len] {
103 pos.set_attach_chain(0);
104 pos.set_attach_type(0);
105 }
106 }
107
108 pub fn position_finish_advances(_: &hb_font_t, _: &mut hb_buffer_t) {
109 }
111
112 pub fn position_finish_offsets(_: &hb_font_t, buffer: &mut hb_buffer_t) {
113 buffer.assert_gsubgpos_vars();
114
115 let len = buffer.len;
116 let direction = buffer.direction;
117
118 if buffer.scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT != 0 {
120 if buffer.direction.is_forward() {
122 for i in 0..len {
123 if buffer.pos[i].attach_chain() != 0 {
124 propagate_attachment_offsets(
125 &mut buffer.pos,
126 len,
127 i,
128 direction,
129 MAX_NESTING_LEVEL,
130 );
131 }
132 }
133 } else {
134 for i in (0..len).rev() {
135 if buffer.pos[i].attach_chain() != 0 {
136 propagate_attachment_offsets(
137 &mut buffer.pos,
138 len,
139 i,
140 direction,
141 MAX_NESTING_LEVEL,
142 );
143 }
144 }
145 }
146 }
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
155 fn propagate_attachment_offsets_saturates_deep_mark_chains() {
156 let len = MAX_NESTING_LEVEL + 2;
157 let mut pos = vec![GlyphPosition::default(); len];
158
159 for i in 1..len {
160 pos[i].x_offset = 40_000_000;
161 pos[i].y_offset = 40_000_000;
162 pos[i].set_attach_type(attach_type::MARK);
163 pos[i].set_attach_chain(-1);
164 }
165
166 propagate_attachment_offsets(
167 &mut pos,
168 len,
169 len - 1,
170 Direction::LeftToRight,
171 MAX_NESTING_LEVEL,
172 );
173
174 assert_eq!(pos[len - 1].x_offset, i32::MAX);
175 assert_eq!(pos[len - 1].y_offset, i32::MAX);
176 }
177}