From fd489433a8a223068d904e04d4ce8bafa82900c7 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Mar 2021 16:21:17 -0700 Subject: [PATCH] [indic] Fix cluster-merging logic with cluster-level=1 Was producing non-monotonic cluster numbers because our faulty logic was not merging clusters if something from before base and after base had switched positions. Fixes https://github.com/harfbuzz/harfbuzz/issues/2272 --- src/hb-ot-shape-complex-indic.cc | 28 ++++++++++++++++-- ...36d056bad6d478fc0bf7397bd52dc3bd197d5f.ttf | Bin 0 -> 2920 bytes .../shaping/data/in-house/tests/cluster.tests | 1 + 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 test/shaping/data/in-house/fonts/6f36d056bad6d478fc0bf7397bd52dc3bd197d5f.ttf diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc index 09742b391..a4f2d9a84 100644 --- a/src/hb-ot-shape-complex-indic.cc +++ b/src/hb-ot-shape-complex-indic.cc @@ -752,7 +752,28 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, * We could use buffer->sort() for this, if there was no special * reordering of pre-base stuff happening later... * We don't want to merge_clusters all of that, which buffer->sort() - * would. + * would. Here's a concrete example: + * + * Assume there's a pre-base consonant and explicit Halant before base, + * followed by a prebase-reordering (left) Matra: + * + * C,H,ZWNJ,B,M + * + * At this point in reordering we would have: + * + * M,C,H,ZWNJ,B + * + * whereas in final reordering we will bring the Matra closer to Base: + * + * C,H,ZWNJ,M,B + * + * That's why we don't want to merge-clusters anything before the Base + * at this point. But if something moved from after Base to before it, + * we should merge clusters from base to them. In final-reordering, we + * only move things around before base, and merge-clusters up to base. + * These two merge-clusters from the two sides of base will interlock + * to merge things correctly. See: + * https://github.com/harfbuzz/harfbuzz/issues/2272 */ if (indic_plan->is_old_spec || end - start > 127) buffer->merge_clusters (base, end); @@ -762,17 +783,18 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, for (unsigned int i = base; i < end; i++) if (info[i].syllable() != 255) { + unsigned int min = i; unsigned int max = i; unsigned int j = start + info[i].syllable(); while (j != i) { + min = hb_min (min, j); max = hb_max (max, j); unsigned int next = start + info[j].syllable(); info[j].syllable() = 255; /* So we don't process j later again. */ j = next; } - if (i != max) - buffer->merge_clusters (i, max + 1); + buffer->merge_clusters (hb_max (base, min), max + 1); } } diff --git a/test/shaping/data/in-house/fonts/6f36d056bad6d478fc0bf7397bd52dc3bd197d5f.ttf b/test/shaping/data/in-house/fonts/6f36d056bad6d478fc0bf7397bd52dc3bd197d5f.ttf new file mode 100644 index 0000000000000000000000000000000000000000..395f423691eabc744fe7cb5a351d5ee850bb529b GIT binary patch literal 2920 zcma)8TWlLu8vf52dmKB79mnHKoWz-U96NFD<6D))O`3){Z3u~)7D`ohaTAkxah%d5 zEtOURiKj&f@lpv1qG40b{Ow!FUlW-=SC7Llcsh`n}hb#1-#pIy+c`5fyviO~TfevE%aLqsm!<8dppC7Ddb z!{JCDPsEccuPnQj0QUyCTd{LZix{g~5VIbyB@C6#fur4S_akSu(~q2fyek??Hv8%# zvxoC5k)efWGA?hQ9_{XEm(A18X*L{8M}jd=?a_mwR6L-@hdQ-UwW}%A;PAJ!dxA&j zW9bud-$cVeM=;vrw)t$%4sBorE|yE>&-fKyq&OiHsbC}=P9(HMySv>T;IUXT8PkP_ zvTX4Px5AN>#}m^HUn3$YIkF8kEf|gGV{oSTxI^uAyKI3bo6ny1`-p9QTs~4xm*1yaJeQzIVN4f3 zmYX!K3D>)--yaP6{VE<=xrCd--y#L0TXSm8a9Gn4*x(fzh4U8u} zyqLLjgIx~}WZG17sD64J_BOX}(W_KLZH7HzFqMe8ktHpNEFeutmXS1BemjuvoI5bn zZgJI4s=nw%TkmRbwBx}*+srL@Ux%)AiPCCQh=i#@de|m9b>O{y^pH>>i zFU~Ez)XiB2>^B9w^rEOyCc?)9G$_4B5yFy4hsPUpYxl9-%(NcmP^Kv<@uMcI%^ufH ziG!YYiS6%EB;4rgI#%E0Fe{CoU~Pk=!L82i=VrMqvLIc>vkH@p?uw9!zlqU8k|ePY z(QAX%EH&?!rGq@RJ45Q|W2wQ})7^XIXXetWVF#%0<|lO@UbOVSiQCI&bYi|Mv}eNh z@Fer($#kO}?c5_>aH(2<@!wv5ndW`#@8m|u|I{CBAkTG1jsJ>IB01?Y&qoaoG0=$+p=MsDM2eJ^%ifA;mii1EhtADZt>ZCx+*Sl<+Oq{~~&csKt5z9Z(_yZjUp znD{mJA|fFE9QcW*D&OWc|1G({dT#wQc+_flC{urP5^SaA~xZ z-t7T6EObh+nyiq|;Ht=sfnF7XRcXzEBC`W71JWm&JUxemE z*u9QRrFqI?x6m5LS`nOCFyz6IgS-Jbi+wuw3>fDyY|rA%(C}TBZH}D`y}LO6zfIxy zy;dIvIuGCS@U#dIfAwOU>$h31Q~(}M`4w>Nb=0A3IFp!(nVHNitcF>cjn%Tcy21tg zZxr$iXLH3R%ffP2jMn1D6YGZL$Yw9BUd$EN@=Har;@H^Of$g~+(2>pW!1mQ0(D|!& zzL*z$jrVM*PPy(eQCKZ52{ofG5rc6spjuoEh>4o2N);KuY51QwPTbgMKU-YVsRjLj z1GO*uob5oIq_c&KE2J#u*Vf7ZMDBc%{DxMAU*uK>BS$YWqn|`~;lB*uMJD*lKVlST zg}WjP4WZ4@{|fGYiW(Z`s^{F$#y=;#W#!|BHu|5vYDkqBPTeO4eoqX-vV`QVlVaTc zh)2}B@IV~f`4M|;I8}6RB{t!oY-CWxXu(zSnxl&w$OlakQwUnzU}464cso+@zS`zC O-V4>;f>SnD%>M;U%?&&N literal 0 HcmV?d00001 diff --git a/test/shaping/data/in-house/tests/cluster.tests b/test/shaping/data/in-house/tests/cluster.tests index 928843f0f..f1889900b 100644 --- a/test/shaping/data/in-house/tests/cluster.tests +++ b/test/shaping/data/in-house/tests/cluster.tests @@ -1,2 +1,3 @@ ../fonts/4fac3929fc3332834e93673780ec0fe94342d193.ttf:--cluster-level=2:U+0078,U+030A,U+0058,U+030A:[gid2=0+1083|gid3=1@-1132,-8+0|gid1=2+1200|gid3=3@-1190,349+0] ../fonts/43ef465752be9af900745f72fe29cb853a1401a5.ttf:--cluster-level=1:U+05D4,U+05B7,U+05E9,U+05BC,U+05C1,U+05B8,U+05DE,U+05B4,U+05DD:[uni05DD=8+1359|uni05B4=7@111,0+0|uni05DE=6+1391|uni05B8=5+0|uni05BC=3+0|uni05C1=3+0|uni05E9=2+1451|uni05B7=1@28,0+0|uni05D4=0+1338] +../fonts/6f36d056bad6d478fc0bf7397bd52dc3bd197d5f.ttf:--cluster-level=1:U+099B,U+09CB,U+09C8,U+09C2,U+09CB,U+098C:[evowelsigninibeng=0+346|aivowelsignbeng=0+346|evowelsignbeng=0+346|chabeng=0+687|uuvowelsignlongbeng=0@-96,0+0|aavowelsignbeng=0+266|aavowelsignbeng=4+266|lvocalicbeng=5+639]