[GPOS] Count decomposed pieces as one ligature component Non-first pieces of a MultipleSubst now add no extra component, so a decomposed glyph absorbed into a ligature counts as the single component it started as, and its marks attach where MarkBasePos would. Part of https://github.com/harfbuzz/harfbuzz/issues/4969
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh index 0437e44..e525797 100644 --- a/src/hb-ot-layout-gsubgpos.hh +++ b/src/hb-ot-layout-gsubgpos.hh
@@ -1482,7 +1482,7 @@ return_trace (false); } - total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]); + total_component_count += _hb_glyph_info_get_lig_num_comps_in_ligation (&buffer->info[skippy_iter.idx]); } *end_position = skippy_iter.idx + 1; @@ -1586,7 +1586,7 @@ } last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); - last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); + last_num_components = _hb_glyph_info_get_lig_num_comps_in_ligation (&buffer->cur()); components_so_far += last_num_components; /* Skip the base glyph */
diff --git a/src/hb-ot-layout.hh b/src/hb-ot-layout.hh index 945e735..ca7ea81 100644 --- a/src/hb-ot-layout.hh +++ b/src/hb-ot-layout.hh
@@ -567,6 +567,20 @@ return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED; } +static inline unsigned int +_hb_glyph_info_get_lig_num_comps_in_ligation (const hb_glyph_info_t *info) +{ + /* When a glyph is decomposed by a MultipleSubst and its pieces later become + * components of a ligature, the pieces belong to the same ligature component + * as the first piece, matching how MarkBasePos attaches marks only to the + * first piece. So the non-first pieces contribute no extra component. + * https://github.com/harfbuzz/harfbuzz/issues/4969 */ + if (_hb_glyph_info_multiplied (info) && + _hb_glyph_info_get_lig_comp (info)) + return 0; + return _hb_glyph_info_get_lig_num_comps (info); +} + static inline bool _hb_glyph_info_ligated_and_didnt_multiply (const hb_glyph_info_t *info) {
diff --git a/test/shape/data/in-house/fonts/1af868501dfcfd16184116b966f7fb2bd310623c.ttf b/test/shape/data/in-house/fonts/1af868501dfcfd16184116b966f7fb2bd310623c.ttf new file mode 100644 index 0000000..f450682 --- /dev/null +++ b/test/shape/data/in-house/fonts/1af868501dfcfd16184116b966f7fb2bd310623c.ttf Binary files differ
diff --git a/test/shape/data/in-house/fonts/73c3222a2992bac9067663888d2a1503774976bb.ttf b/test/shape/data/in-house/fonts/73c3222a2992bac9067663888d2a1503774976bb.ttf new file mode 100644 index 0000000..fe64522 --- /dev/null +++ b/test/shape/data/in-house/fonts/73c3222a2992bac9067663888d2a1503774976bb.ttf Binary files differ
diff --git a/test/shape/data/in-house/tests/mark-attachment.tests b/test/shape/data/in-house/tests/mark-attachment.tests index d2e7ab6..72b27f3 100644 --- a/test/shape/data/in-house/tests/mark-attachment.tests +++ b/test/shape/data/in-house/tests/mark-attachment.tests
@@ -1,3 +1,5 @@ ../fonts/98b7887cff91f722b92a8ff800120954606354f9.ttf;;U+100F,U+103C,U+102F,U+1036;[uni103C102F=0+150|uni100F=0+550|uni1036=0@-150,0+0] ../fonts/55db4d5539b0f7f0b5e6cdb3ce6dd1eab6b3392a.ttf;;U+066E,U+064E,U+0644,U+064E;[fatha-ar=0@359,727+0|_lam.bowl=0+537|fatha-ar=0@20,370+0|behDotless_lam-ar.init=0+246] ../fonts/55db4d5539b0f7f0b5e6cdb3ce6dd1eab6b3392a.ttf;--features=-liga;U+066E,U+064E,U+0644,U+064E;[fatha-ar=2@369,717+0|_lam.bowl=2+537|_lam=2+108|fatha-ar=0@20,370+0|behDotless-ar.init=0+220] +../fonts/73c3222a2992bac9067663888d2a1503774976bb.ttf;;U+0628,U+064E,U+0645,U+064E,U+0644,U+064E;[fatha-ar=0@533,333+0|_lam.bowl=0+500|fatha-ar=0@22,222+0|fatha-ar=0@11,111+0|beh_meem_lam-ar=0+700] +../fonts/1af868501dfcfd16184116b966f7fb2bd310623c.ttf;;U+0628,U+064E,U+0644,U+064E,U+0647,U+064E;[fatha-ar=0@33,333+0|fatha-ar=0@22,222+0|fatha-ar=0@11,111+0|beh_lam_heh-ar=0+700]