rustybuzz/hb/ot/layout/GPOS/
mark_mark_pos.rs

1use crate::hb::ot::layout::GPOS::mark_array::MarkArrayExt;
2use crate::hb::ot_layout::{
3    _hb_glyph_info_get_lig_comp, _hb_glyph_info_get_lig_id, _hb_glyph_info_is_mark,
4};
5use crate::hb::ot_layout_common::lookup_flags;
6use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t;
7use crate::hb::ot_layout_gsubgpos::{skipping_iterator_t, Apply};
8use ttf_parser::gpos::MarkToMarkAdjustment;
9
10impl Apply for MarkToMarkAdjustment<'_> {
11    fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> {
12        let buffer = &ctx.buffer;
13        let mark1_glyph = ctx.buffer.cur(0).as_glyph();
14        let mark1_index = self.mark1_coverage.get(mark1_glyph)?;
15
16        // Now we search backwards for a suitable mark glyph until a non-mark glyph
17        let mut iter = skipping_iterator_t::new(ctx, buffer.idx, false);
18        iter.set_lookup_props(ctx.lookup_props & !u32::from(lookup_flags::IGNORE_FLAGS));
19
20        let mut unsafe_from = 0;
21        if !iter.prev(Some(&mut unsafe_from)) {
22            ctx.buffer
23                .unsafe_to_concat_from_outbuffer(Some(unsafe_from), Some(ctx.buffer.idx + 1));
24            return None;
25        }
26
27        let iter_idx = iter.index();
28        if !_hb_glyph_info_is_mark(&buffer.info[iter_idx]) {
29            ctx.buffer
30                .unsafe_to_concat_from_outbuffer(Some(iter_idx), Some(buffer.idx + 1));
31            return None;
32        }
33
34        let id1 = _hb_glyph_info_get_lig_id(buffer.cur(0));
35        let id2 = _hb_glyph_info_get_lig_id(&buffer.info[iter_idx]);
36        let comp1 = _hb_glyph_info_get_lig_comp(buffer.cur(0));
37        let comp2 = _hb_glyph_info_get_lig_comp(&buffer.info[iter_idx]);
38
39        let matches = if id1 == id2 {
40            // Marks belonging to the same base
41            // or marks belonging to the same ligature component.
42            id1 == 0 || comp1 == comp2
43        } else {
44            // If ligature ids don't match, it may be the case that one of the marks
45            // itself is a ligature.  In which case match.
46            (id1 > 0 && comp1 == 0) || (id2 > 0 && comp2 == 0)
47        };
48
49        if !matches {
50            ctx.buffer
51                .unsafe_to_concat_from_outbuffer(Some(iter_idx), Some(buffer.idx + 1));
52            return None;
53        }
54
55        let mark2_glyph = buffer.info[iter_idx].as_glyph();
56        let mark2_index = self.mark2_coverage.get(mark2_glyph)?;
57
58        self.marks
59            .apply(ctx, self.mark2_matrix, mark1_index, mark2_index, iter_idx)
60    }
61}