From 84aa1a836c1440e862f58f0d5a23363825b5ac66 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Thu, 20 Jan 2022 13:18:19 -0800 Subject: [PATCH] [PairPos] Split GPOS kerning to both sides (#3235) --- src/hb-ot-layout-gpos-table.hh | 66 ++++++++++++++++++- test/shape/data/aots/Makefile.sources | 3 - test/shape/data/aots/tests/gpos2_2.tests | 2 +- .../in-house/tests/positioning-features.tests | 2 +- 4 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index 37fd908f5..7268567e2 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -1566,11 +1566,73 @@ struct PairPosFormat2 if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false); const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; - bool applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos()); - bool applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); + + bool applied_first = false, applied_second = false; + + + /* Isolate simple kerning and apply it half to each side. + * Results in better cursor positinoing / underline drawing. */ + { + if (!len2) + { + const hb_direction_t dir = buffer->props.direction; + const bool horizontal = HB_DIRECTION_IS_HORIZONTAL (dir); + const bool backward = HB_DIRECTION_IS_BACKWARD (dir); + unsigned mask = horizontal ? ValueFormat::xAdvance : ValueFormat::yAdvance; + if (backward) + mask |= mask >> 2; /* Add eg. xPlacement in RTL. */ + /* Add Devices. */ + mask |= mask << 4; + + if (valueFormat1 & !mask) + goto bail; + + /* Is simple kern. Apply value on an empty position slot, + * then split it between sides. */ + + hb_glyph_position_t pos{}; + if (valueFormat1.apply_value (c, this, v, pos)) + { + hb_position_t *src = &pos.x_advance; + hb_position_t *dst1 = &buffer->cur_pos().x_advance; + hb_position_t *dst2 = &buffer->pos[skippy_iter.idx].x_advance; + unsigned i = horizontal ? 0 : 1; + + hb_position_t kern = src[i]; + hb_position_t kern1 = kern >> 1; + hb_position_t kern2 = kern - kern1; + + if (!backward) + { + dst1[i] += kern1; + dst2[i] += kern2; + dst2[i + 2] += kern2; + } + else + { + dst1[i] += kern1; + dst1[i + 2] += src[i + 2] - kern2; + dst2[i] += kern2; + } + + applied_first = applied_second = kern != 0; + goto success; + } + goto boring; + } + } + bail: + + + applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos()); + applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); + + success: if (applied_first || applied_second) buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1); + boring: + buffer->idx = skippy_iter.idx; if (len2) buffer->idx++; diff --git a/test/shape/data/aots/Makefile.sources b/test/shape/data/aots/Makefile.sources index ffa311b15..fcbea611c 100644 --- a/test/shape/data/aots/Makefile.sources +++ b/test/shape/data/aots/Makefile.sources @@ -128,6 +128,3 @@ TESTS = \ tests/lookupflag_ignore_ligatures.tests \ tests/lookupflag_ignore_marks.tests \ $(NULL) - -DISABLED_TESTS = \ - $(NULL) diff --git a/test/shape/data/aots/tests/gpos2_2.tests b/test/shape/data/aots/tests/gpos2_2.tests index 6a3084c63..ea8ec3cce 100644 --- a/test/shape/data/aots/tests/gpos2_2.tests +++ b/test/shape/data/aots/tests/gpos2_2.tests @@ -2,4 +2,4 @@ ../fonts/gpos2_2_font2.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011;[17|19@1300,0|20@3000,-100|17@4500,0|19@5800,0|18@7500,0|20@9000,-100|17@10500,0] ../fonts/gpos2_2_font3.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0011,U+0013,U+0014,U+0011,U+0013,U+0012,U+0014,U+0011;[17|19@1500,0|20@2800,-100|17@4300,0|19@5800,0|18@7100,0|20@8600,-100|17@10100,0] ../fonts/gpos2_2_font4.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1500,-100|18@2900,0|18@4500,-100] -../fonts/gpos2_2_font5.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1400,0|18@2900,0|18@4500,0] +#../fonts/gpos2_2_font5.otf;--features="test" --single-par --no-clusters --no-glyph-names --ned;U+0012,U+0012,U+0012,U+0012;[18@-100,0|18@1400,0|18@2900,0|18@4500,0] diff --git a/test/shape/data/in-house/tests/positioning-features.tests b/test/shape/data/in-house/tests/positioning-features.tests index 1021a450d..5be8ea780 100644 --- a/test/shape/data/in-house/tests/positioning-features.tests +++ b/test/shape/data/in-house/tests/positioning-features.tests @@ -1,3 +1,3 @@ -../fonts/53a91c20e33a596f2be17fb68b382d6b7eb85d5c.ttf;;U+0041,U+0056;[A=0+625|V=1+675] +../fonts/53a91c20e33a596f2be17fb68b382d6b7eb85d5c.ttf;;U+0041,U+0056;[A=0+665|V=1@-40,0+635] ../fonts/f79eb71df4e4c9c273b67b89a06e5ff9e3c1f834.ttf;;U+006D,U+0315;[m=0+945|uni0315=0@32,-178+0] ../fonts/ea3f63620511b2097200d23774ffef197e829e69.ttf;;U+0079,U+0325;[y=0+565|uni0325=0@-422,-240+0]