rustybuzz/hb/ot/layout/GPOS/
cursive_pos.rs1use crate::hb::buffer::HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
2use crate::hb::ot_layout_common::lookup_flags;
3use crate::hb::ot_layout_gpos_table::attach_type;
4use crate::hb::ot_layout_gpos_table::AnchorExt;
5use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t;
6use crate::hb::ot_layout_gsubgpos::{skipping_iterator_t, Apply};
7use crate::{Direction, GlyphPosition};
8use ttf_parser::gpos::CursiveAdjustment;
9
10impl Apply for CursiveAdjustment<'_> {
11 fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> {
12 let this = ctx.buffer.cur(0).as_glyph();
13
14 let index_this = self.coverage.get(this)?;
15 let entry_this = self.sets.entry(index_this)?;
16
17 let mut iter = skipping_iterator_t::new(ctx, ctx.buffer.idx, false);
18
19 let mut unsafe_from = 0;
20 if !iter.prev(Some(&mut unsafe_from)) {
21 ctx.buffer
22 .unsafe_to_concat_from_outbuffer(Some(unsafe_from), Some(ctx.buffer.idx + 1));
23 return None;
24 }
25
26 let i = iter.index();
27 let prev = ctx.buffer.info[i].as_glyph();
28 let index_prev = self.coverage.get(prev)?;
29 let Some(exit_prev) = self.sets.exit(index_prev) else {
30 ctx.buffer
31 .unsafe_to_concat_from_outbuffer(Some(iter.index()), Some(ctx.buffer.idx + 1));
32 return None;
33 };
34
35 let (exit_x, exit_y) = exit_prev.get(ctx.face);
36 let (entry_x, entry_y) = entry_this.get(ctx.face);
37
38 let direction = ctx.buffer.direction;
39 let j = ctx.buffer.idx;
40 ctx.buffer.unsafe_to_break(Some(i), Some(j + 1));
41
42 let pos = &mut ctx.buffer.pos;
43 match direction {
44 Direction::LeftToRight => {
45 pos[i].x_advance = exit_x + pos[i].x_offset;
46 let d = entry_x + pos[j].x_offset;
47 pos[j].x_advance -= d;
48 pos[j].x_offset -= d;
49 }
50 Direction::RightToLeft => {
51 let d = exit_x + pos[i].x_offset;
52 pos[i].x_advance -= d;
53 pos[i].x_offset -= d;
54 pos[j].x_advance = entry_x + pos[j].x_offset;
55 }
56 Direction::TopToBottom => {
57 pos[i].y_advance = exit_y + pos[i].y_offset;
58 let d = entry_y + pos[j].y_offset;
59 pos[j].y_advance -= d;
60 pos[j].y_offset -= d;
61 }
62 Direction::BottomToTop => {
63 let d = exit_y + pos[i].y_offset;
64 pos[i].y_advance -= d;
65 pos[i].y_offset -= d;
66 pos[j].y_advance = entry_y;
67 }
68 Direction::Invalid => {}
69 }
70
71 let mut child = i;
80 let mut parent = j;
81 let mut x_offset = entry_x - exit_x;
82 let mut y_offset = entry_y - exit_y;
83
84 if ctx.lookup_props as u16 & lookup_flags::RIGHT_TO_LEFT == 0 {
86 core::mem::swap(&mut child, &mut parent);
87 x_offset = -x_offset;
88 y_offset = -y_offset;
89 }
90
91 reverse_cursive_minor_offset(pos, child, direction, parent);
96
97 pos[child].set_attach_type(attach_type::CURSIVE);
98 pos[child].set_attach_chain((parent as isize - child as isize) as i16);
99
100 ctx.buffer.scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
101 if direction.is_horizontal() {
102 pos[child].y_offset = y_offset;
103 } else {
104 pos[child].x_offset = x_offset;
105 }
106
107 if pos[parent].attach_chain() == -pos[child].attach_chain() {
110 pos[parent].set_attach_chain(0);
111
112 if direction.is_horizontal() {
113 pos[parent].y_offset = 0;
114 } else {
115 pos[parent].x_offset = 0;
116 }
117 }
118
119 ctx.buffer.idx += 1;
120 Some(())
121 }
122}
123
124fn reverse_cursive_minor_offset(
125 pos: &mut [GlyphPosition],
126 i: usize,
127 direction: Direction,
128 new_parent: usize,
129) {
130 let chain = pos[i].attach_chain();
131 let attach_type = pos[i].attach_type();
132 if chain == 0 || attach_type & attach_type::CURSIVE == 0 {
133 return;
134 }
135
136 pos[i].set_attach_chain(0);
137
138 let j = (i as isize + isize::from(chain)) as _;
140 if j == new_parent {
141 return;
142 }
143
144 reverse_cursive_minor_offset(pos, j, direction, new_parent);
145
146 if direction.is_horizontal() {
147 pos[j].y_offset = -pos[i].y_offset;
148 } else {
149 pos[j].x_offset = -pos[i].x_offset;
150 }
151
152 pos[j].set_attach_chain(-chain);
153 pos[j].set_attach_type(attach_type);
154}