Skip to main content

harfrust/hb/ot/gsub/
multiple.rs

1use crate::hb::buffer::GlyphPropsFlags;
2use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t;
3use crate::hb::ot_layout_gsubgpos::{Apply, WouldApply, WouldApplyContext};
4use read_fonts::tables::gsub::MultipleSubstFormat1;
5
6impl WouldApply for MultipleSubstFormat1<'_> {
7    fn would_apply(&self, ctx: &WouldApplyContext) -> bool {
8        ctx.glyphs.len() == 1
9            && self
10                .coverage()
11                .is_ok_and(|cov| cov.get(ctx.glyphs[0]).is_some())
12    }
13}
14
15impl Apply for MultipleSubstFormat1<'_> {
16    fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> {
17        let gid = ctx.buffer.cur(0).as_glyph();
18        let index = self.coverage().ok()?.get(gid)? as usize;
19        let substs = self.sequences().get(index).ok()?.substitute_glyph_ids();
20        match substs.len() {
21            // Spec disallows this, but Uniscribe allows it.
22            // https://github.com/harfbuzz/harfbuzz/issues/253
23            0 => ctx.buffer.delete_glyph(),
24
25            // Special-case to make it in-place and not consider this
26            // as a "multiplied" substitution.
27            1 => ctx.replace_glyph(substs.first()?.get().into()),
28
29            _ => {
30                let class = if ctx.buffer.cur(0).is_ligature() {
31                    GlyphPropsFlags::BASE_GLYPH
32                } else {
33                    GlyphPropsFlags::empty()
34                };
35                let lig_id = ctx.buffer.cur(0).lig_id();
36
37                for (i, subst) in substs.iter().enumerate() {
38                    let subst = subst.get().into();
39                    // If is attached to a ligature, don't disturb that.
40                    // https://github.com/harfbuzz/harfbuzz/issues/3069
41                    if lig_id == 0 {
42                        // Index is truncated to 4 bits anway, so we can safely cast to u8.
43                        ctx.buffer.cur_mut(0).set_lig_props_for_component(i as u8);
44                    }
45                    ctx.output_glyph_for_component(subst, class);
46                }
47
48                ctx.buffer.skip_glyph();
49            }
50        }
51        Some(())
52    }
53}