1 | use crate::hb::ot::layout::GPOS::mark_array::MarkArrayExt; |
2 | use crate::hb::ot_layout::{_hb_glyph_info_get_lig_comp, _hb_glyph_info_get_lig_id}; |
3 | use crate::hb::ot_layout_common::lookup_flags; |
4 | use crate::hb::ot_layout_gsubgpos::OT::hb_ot_apply_context_t; |
5 | use crate::hb::ot_layout_gsubgpos::{match_t, skipping_iterator_t, Apply}; |
6 | use ttf_parser::gpos::MarkToLigatureAdjustment; |
7 | |
8 | impl Apply for MarkToLigatureAdjustment<'_> { |
9 | fn apply(&self, ctx: &mut hb_ot_apply_context_t) -> Option<()> { |
10 | let buffer = &ctx.buffer; |
11 | let mark_glyph = ctx.buffer.cur(0).as_glyph(); |
12 | let mark_index = self.mark_coverage.get(mark_glyph)?; |
13 | |
14 | // Due to borrowing rules, we have this piece of code before creating the |
15 | // iterator, unlike in harfbuzz. |
16 | if ctx.last_base_until > buffer.idx as u32 { |
17 | ctx.last_base_until = 0; |
18 | ctx.last_base = -1; |
19 | } |
20 | |
21 | // Now we search backwards for a non-mark glyph |
22 | let mut iter = skipping_iterator_t::new(ctx, 0, false); |
23 | iter.set_lookup_props(u32::from(lookup_flags::IGNORE_MARKS)); |
24 | |
25 | let mut j = buffer.idx; |
26 | while j > ctx.last_base_until as usize { |
27 | let mut _match = iter.match_(&buffer.info[j - 1]); |
28 | if _match == match_t::MATCH { |
29 | ctx.last_base = j as i32 - 1; |
30 | break; |
31 | } |
32 | j -= 1; |
33 | } |
34 | |
35 | ctx.last_base_until = buffer.idx as u32; |
36 | |
37 | if ctx.last_base == -1 { |
38 | ctx.buffer |
39 | .unsafe_to_concat_from_outbuffer(Some(0), Some(buffer.idx + 1)); |
40 | return None; |
41 | } |
42 | |
43 | let idx = ctx.last_base as usize; |
44 | |
45 | // Checking that matched glyph is actually a ligature by GDEF is too strong; disabled |
46 | |
47 | let lig_glyph = buffer.info[idx].as_glyph(); |
48 | let Some(lig_index) = self.ligature_coverage.get(lig_glyph) else { |
49 | ctx.buffer |
50 | .unsafe_to_concat_from_outbuffer(Some(idx), Some(buffer.idx + 1)); |
51 | return None; |
52 | }; |
53 | let lig_attach = self.ligature_array.get(lig_index)?; |
54 | |
55 | // Find component to attach to |
56 | let comp_count = lig_attach.rows; |
57 | if comp_count == 0 { |
58 | ctx.buffer |
59 | .unsafe_to_concat_from_outbuffer(Some(idx), Some(buffer.idx + 1)); |
60 | return None; |
61 | } |
62 | |
63 | // We must now check whether the ligature ID of the current mark glyph |
64 | // is identical to the ligature ID of the found ligature. If yes, we |
65 | // can directly use the component index. If not, we attach the mark |
66 | // glyph to the last component of the ligature. |
67 | let lig_id = _hb_glyph_info_get_lig_id(&buffer.info[idx]); |
68 | let mark_id = _hb_glyph_info_get_lig_id(buffer.cur(0)); |
69 | let mark_comp = u16::from(_hb_glyph_info_get_lig_comp(buffer.cur(0))); |
70 | let matches = lig_id != 0 && lig_id == mark_id && mark_comp > 0; |
71 | let comp_index = if matches { |
72 | mark_comp.min(comp_count) |
73 | } else { |
74 | comp_count |
75 | } - 1; |
76 | |
77 | self.marks |
78 | .apply(ctx, lig_attach, mark_index, comp_index, idx) |
79 | } |
80 | } |
81 | |