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

1use crate::hb::ot_layout_gpos_table::ValueRecordExt;
2use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t;
3use crate::hb::ot_layout_gsubgpos::{skipping_iterator_t, Apply};
4use ttf_parser::gpos::{PairAdjustment, ValueRecord};
5
6impl Apply for PairAdjustment<'_> {
7    fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> {
8        let first_glyph = ctx.buffer.cur(0).as_glyph();
9        let first_glyph_coverage_index = self.coverage().get(first_glyph)?;
10
11        let mut iter = skipping_iterator_t::new(ctx, ctx.buffer.idx, false);
12
13        let mut unsafe_to = 0;
14        if !iter.next(Some(&mut unsafe_to)) {
15            ctx.buffer
16                .unsafe_to_concat(Some(ctx.buffer.idx), Some(unsafe_to));
17            return None;
18        }
19
20        let second_glyph_index = iter.index();
21        let second_glyph = ctx.buffer.info[second_glyph_index].as_glyph();
22
23        let finish = |ctx: &mut hb_ot_apply_context_t, iter_index: &mut usize, has_record2| {
24            if has_record2 {
25                *iter_index += 1;
26                // https://github.com/harfbuzz/harfbuzz/issues/3824
27                // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116
28                ctx.buffer
29                    .unsafe_to_break(Some(ctx.buffer.idx), Some(*iter_index + 1));
30            }
31
32            ctx.buffer.idx = *iter_index;
33
34            Some(())
35        };
36
37        let boring = |ctx: &mut hb_ot_apply_context_t, iter_index: &mut usize, has_record2| {
38            ctx.buffer
39                .unsafe_to_concat(Some(ctx.buffer.idx), Some(second_glyph_index + 1));
40            finish(ctx, iter_index, has_record2)
41        };
42
43        let success =
44            |ctx: &mut hb_ot_apply_context_t, iter_index: &mut usize, flag1, flag2, has_record2| {
45                if flag1 || flag2 {
46                    ctx.buffer
47                        .unsafe_to_break(Some(ctx.buffer.idx), Some(second_glyph_index + 1));
48                    finish(ctx, iter_index, has_record2)
49                } else {
50                    boring(ctx, iter_index, has_record2)
51                }
52            };
53
54        let bail = |ctx: &mut hb_ot_apply_context_t,
55                    iter_index: &mut usize,
56                    records: (ValueRecord, ValueRecord)| {
57            let has_record1 = !records.0.is_empty();
58            let has_record2 = !records.1.is_empty();
59
60            let flag1 = has_record1 && records.0.apply(ctx, ctx.buffer.idx);
61            let flag2 = has_record2 && records.1.apply(ctx, second_glyph_index);
62
63            success(ctx, iter_index, flag1, flag2, has_record2)
64        };
65
66        let records = match self {
67            Self::Format1 { sets, .. } => {
68                sets.get(first_glyph_coverage_index)?.get(second_glyph)?
69            }
70            Self::Format2 {
71                classes, matrix, ..
72            } => {
73                let classes = (classes.0.get(first_glyph), classes.1.get(second_glyph));
74
75                let records = match matrix.get(classes) {
76                    Some(v) => v,
77                    None => {
78                        ctx.buffer
79                            .unsafe_to_concat(Some(ctx.buffer.idx), Some(iter.index() + 1));
80                        return None;
81                    }
82                };
83
84                return bail(ctx, &mut iter.buf_idx, records);
85            }
86        };
87
88        bail(ctx, &mut iter.buf_idx, records)
89    }
90}