harfrust/hb/ot/gpos/
cursive.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_gsubgpos::OT::hb_ot_apply_context_t;
5use crate::hb::ot_layout_gsubgpos::{skipping_iterator_t, Apply};
6use crate::{Direction, GlyphPosition};
7use read_fonts::tables::gpos::CursivePosFormat1;
8
9impl Apply for CursivePosFormat1<'_> {
10 fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> {
11 let this = ctx.buffer.cur(0).as_glyph();
12
13 let coverage = self.coverage().ok()?;
14 let index_this = coverage.get(this)? as usize;
15 let records = self.entry_exit_record();
16 let offset_data = self.offset_data();
17 let entry_this = records.get(index_this)?.entry_anchor(offset_data)?.ok()?;
18
19 let mut iter = skipping_iterator_t::new(ctx, false);
20 iter.reset_fast(iter.buffer.idx);
21
22 let mut unsafe_from = 0;
23 if !iter.prev(Some(&mut unsafe_from)) {
24 ctx.buffer
25 .unsafe_to_concat_from_outbuffer(Some(unsafe_from), Some(ctx.buffer.idx + 1));
26 return None;
27 }
28
29 let i = iter.index();
30 let prev = iter.buffer.info[i].as_glyph();
31 let index_prev = coverage.get(prev)? as usize;
32 let Some(exit_prev) = records
33 .get(index_prev)
34 .and_then(|rec| rec.exit_anchor(offset_data).transpose().ok().flatten())
35 else {
36 iter.buffer
37 .unsafe_to_concat_from_outbuffer(Some(iter.index()), Some(iter.buffer.idx + 1));
38 return None;
39 };
40
41 let (exit_x, exit_y) = ctx.face.ot_tables.resolve_anchor(&exit_prev);
42 let (entry_x, entry_y) = ctx.face.ot_tables.resolve_anchor(&entry_this);
43 let exit_x = ctx.scale_x(exit_x);
44 let exit_y = ctx.scale_y(exit_y);
45 let entry_x = ctx.scale_x(entry_x);
46 let entry_y = ctx.scale_y(entry_y);
47
48 let direction = ctx.buffer.direction;
49 let j = ctx.buffer.idx;
50 ctx.buffer.unsafe_to_break(Some(i), Some(j + 1));
51
52 let pos = &mut ctx.buffer.pos;
53 match direction {
54 Direction::LeftToRight => {
55 pos[i].x_advance = exit_x + pos[i].x_offset;
56 let d = entry_x + pos[j].x_offset;
57 pos[j].x_advance -= d;
58 pos[j].x_offset -= d;
59 }
60 Direction::RightToLeft => {
61 let d = exit_x + pos[i].x_offset;
62 pos[i].x_advance -= d;
63 pos[i].x_offset -= d;
64 pos[j].x_advance = entry_x + pos[j].x_offset;
65 }
66 Direction::TopToBottom => {
67 pos[i].y_advance = exit_y + pos[i].y_offset;
68 let d = entry_y + pos[j].y_offset;
69 pos[j].y_advance -= d;
70 pos[j].y_offset -= d;
71 }
72 Direction::BottomToTop => {
73 let d = exit_y + pos[i].y_offset;
74 pos[i].y_advance -= d;
75 pos[i].y_offset -= d;
76 pos[j].y_advance = entry_y;
77 }
78 Direction::Invalid => {}
79 }
80
81 let mut child = i;
90 let mut parent = j;
91 let mut x_offset = entry_x - exit_x;
92 let mut y_offset = entry_y - exit_y;
93
94 if ctx.lookup_props as u16 & lookup_flags::RIGHT_TO_LEFT == 0 {
96 core::mem::swap(&mut child, &mut parent);
97 x_offset = -x_offset;
98 y_offset = -y_offset;
99 }
100
101 reverse_cursive_minor_offset(pos, child, direction, parent);
106
107 pos[child].set_attach_type(attach_type::CURSIVE);
108 pos[child].set_attach_chain((parent as isize - child as isize) as i16);
109
110 ctx.buffer.scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
111 if direction.is_horizontal() {
112 pos[child].y_offset = y_offset;
113 } else {
114 pos[child].x_offset = x_offset;
115 }
116
117 if pos[parent].attach_chain() == -pos[child].attach_chain() {
120 pos[parent].set_attach_chain(0);
121
122 if direction.is_horizontal() {
123 pos[parent].y_offset = 0;
124 } else {
125 pos[parent].x_offset = 0;
126 }
127 }
128
129 ctx.buffer.idx += 1;
130 Some(())
131 }
132}
133
134fn reverse_cursive_minor_offset(
135 pos: &mut [GlyphPosition],
136 i: usize,
137 direction: Direction,
138 new_parent: usize,
139) {
140 let chain = pos[i].attach_chain();
141 let attach_type = pos[i].attach_type();
142 if chain == 0 || attach_type & attach_type::CURSIVE == 0 {
143 return;
144 }
145
146 pos[i].set_attach_chain(0);
147
148 let j = (i as isize + isize::from(chain)) as _;
150 if j == new_parent {
151 return;
152 }
153
154 reverse_cursive_minor_offset(pos, j, direction, new_parent);
155
156 if direction.is_horizontal() {
157 pos[j].y_offset = -pos[i].y_offset;
158 } else {
159 pos[j].x_offset = -pos[i].x_offset;
160 }
161
162 pos[j].set_attach_chain(-chain);
163 pos[j].set_attach_type(attach_type);
164}