From 832a6f99b34f334b1e82b8e3a7ad137e823d203c Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 4 Jun 2014 16:57:42 -0400 Subject: [PATCH] [indic] Don't reorder reph/pref if ligature was expanded Normally if you want to, say, conditionally prevent a 'pref', you would use blocking contextual matching. Some designers instead form the 'pref' form, then undo it in context. To detect that we now also remember glyphs that went through MultipleSubst. In the only place that this is used, Uniscribe seems to only care about the "last" transformation between Ligature and Multiple substitions. Ie. if you ligate, expand, and ligate again, it moves the pref, but if you ligate and expand it doesn't. That's why we clear the MULTIPLIED bit when setting LIGATED. Micro-test added. Test: U+0D2F,0D4D,0D30 with font from: [1] https://code.google.com/a/google.com/p/noto-alpha/issues/detail?id=186#c29 --- src/hb-ot-layout-gsub-table.hh | 2 +- src/hb-ot-layout-gsubgpos-private.hh | 20 ++++++++++++++---- src/hb-ot-layout-private.hh | 16 +++++++++++++- src/hb-ot-shape-complex-indic.cc | 4 ++-- test/shaping/Makefile.am | 5 ++++- ...6bc2deab3846f1a682085f70c67d0421014144.ttf | Bin 0 -> 2828 bytes test/shaping/tests/MANIFEST | 1 + 7 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 test/shaping/fonts/sha1sum/226bc2deab3846f1a682085f70c67d0421014144.ttf diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index d73ddc1d9..2e867e3de 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -295,7 +295,7 @@ struct Sequence for (unsigned int i = 0; i < count; i++) { _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i); - c->output_glyph (substitute.array[i], klass); + c->output_glyph_for_component (substitute.array[i], klass); } c->buffer->skip_glyph (); diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh index c8926c0fb..4521eecf5 100644 --- a/src/hb-ot-layout-gsubgpos-private.hh +++ b/src/hb-ot-layout-gsubgpos-private.hh @@ -567,13 +567,25 @@ struct hb_apply_context_t inline void _set_glyph_props (hb_codepoint_t glyph_index, unsigned int class_guess = 0, - bool ligature = false) const + bool ligature = false, + bool component = false) const { unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) & HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED; if (ligature) + { add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED; + /* In the only place that the MULTIPLIED bit is used, Uniscribe + * seems to only care about the "last" transformation between + * Ligature and Multiple substitions. Ie. if you ligate, expand, + * and ligate again, it forgives the multiplication and acts as + * if only ligation happened. As such, clear MULTIPLIED bit. + */ + add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED; + } + if (component) + add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED; if (likely (has_glyph_classes)) _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index)); else if (class_guess) @@ -596,10 +608,10 @@ struct hb_apply_context_t _set_glyph_props (glyph_index, class_guess, true); buffer->replace_glyph (glyph_index); } - inline void output_glyph (hb_codepoint_t glyph_index, - unsigned int class_guess) const + inline void output_glyph_for_component (hb_codepoint_t glyph_index, + unsigned int class_guess) const { - _set_glyph_props (glyph_index, class_guess); + _set_glyph_props (glyph_index, class_guess, false, true); buffer->output_glyph (glyph_index); } }; diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh index 4f03e1b0e..3ded92fec 100644 --- a/src/hb-ot-layout-private.hh +++ b/src/hb-ot-layout-private.hh @@ -50,9 +50,11 @@ typedef enum /* The following are used internally; not derived from GDEF. */ HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED = 0x10u, HB_OT_LAYOUT_GLYPH_PROPS_LIGATED = 0x20u, + HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED = 0x40u, HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED | - HB_OT_LAYOUT_GLYPH_PROPS_LIGATED + HB_OT_LAYOUT_GLYPH_PROPS_LIGATED | + HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED } hb_ot_layout_glyph_class_mask_t; @@ -381,6 +383,18 @@ _hb_glyph_info_ligated (const hb_glyph_info_t *info) return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED); } +static inline bool +_hb_glyph_info_multiplied (const hb_glyph_info_t *info) +{ + return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED); +} + +static inline bool +_hb_glyph_info_ligated_and_didnt_multiply (const hb_glyph_info_t *info) +{ + return _hb_glyph_info_ligated (info) && !_hb_glyph_info_multiplied (info); +} + /* Allocation / deallocation. */ static inline void diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc index 77a79a579..4b122201c 100644 --- a/src/hb-ot-shape-complex-indic.cc +++ b/src/hb-ot-shape-complex-indic.cc @@ -1446,7 +1446,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, if (start + 1 < end && info[start].indic_position() == POS_RA_TO_BECOME_REPH && ((info[start].indic_category() == OT_Repha) ^ - _hb_glyph_info_ligated (&info[start]))) + _hb_glyph_info_ligated_and_didnt_multiply (&info[start]))) { unsigned int new_reph_pos; reph_position_t reph_pos = indic_plan->config->reph_pos; @@ -1599,7 +1599,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, * If pref len is longer than one, then only reorder if it ligated. If * pref len is one, only reorder if it didn't ligate with other things. */ if (_hb_glyph_info_substituted (&info[i]) && - ((pref_len == 1) ^ _hb_glyph_info_ligated (&info[i]))) + ((pref_len == 1) ^ _hb_glyph_info_ligated_and_didnt_multiply (&info[i]))) { /* * 2. Try to find a target position the same way as for pre-base matra. diff --git a/test/shaping/Makefile.am b/test/shaping/Makefile.am index db3ebbcca..cefd4803c 100644 --- a/test/shaping/Makefile.am +++ b/test/shaping/Makefile.am @@ -34,7 +34,10 @@ CLEANFILES += \ hb_test_tools.py[co] \ $(NULL) -TESTS = tests/context-matching.tests +TESTS = \ + tests/context-matching.tests \ + tests/indic-pref-blocking.tests \ + $(NULL) TEST_EXTENSIONS = \ .tests \ diff --git a/test/shaping/fonts/sha1sum/226bc2deab3846f1a682085f70c67d0421014144.ttf b/test/shaping/fonts/sha1sum/226bc2deab3846f1a682085f70c67d0421014144.ttf new file mode 100644 index 0000000000000000000000000000000000000000..70c0c0a8393091a2b184a8e899b14a6c43044cf1 GIT binary patch literal 2828 zcma)84Nz3q6+ZXv+qdg3i;Dc%j-?2=B!ooWg#|~NUx9=PKh^#qb&9L*0=l~}ED98@ zkO?NnpV=n0WfBwP52jFUNp%Qnv{EwuB*oa63?vgLGbZWSX%Y=ar%l-^2FdBc(KgN9AY@inY=8^@Fb zpxORxzq_@OQm7Yn73j2p+wU=E*h=A_{Vi>52sU?=jx2(IGw5E#SQ)u$x*y=IZv2g2kT+>*J+6SJd>VZ(i8*^Cw@qpq@K)<9v^3Yu)}-uw{GK*GuX*hBjZ@ zQ{?D+Qod*Y0(Ih}->8>sEF$%b=F7|7KJ{kkta@Re%XL^3Um6qg#JnOA-?P8}=$_r` z=h9&5k(YL>U;lDiy_j=k2hz{67@tEdsg#3A>;NVw%}6mZs)S6ZL*_s-((QSeHZ^CoCiN085n!#_s={%zrCn+b1<;w3F*VGUE}Ym zW8Iz0#lk=KidnyYQGI)4LcMwY_|R4LR^bD`=-U45(C`doR>x8gEZ?PUqIoX(U^pgt zPEJZxfC4Z8Dvf3$*CJVmfh~sPt({+v464`e3U2NmIJtMj>uY`|3f~Z!qNJy1V$9gl zP*GF=Ino zvevV9?cERGe@}VoiKS(k-&=Us?27|OE-G77=X%%q))j~L{_0Q5Tg1$ctzSG<(cj&^ zzSY%xVrZ{D3wWy4F6ktEA@f3-$tBHCL5jKTvn0c190-4|<_-VB zx+_kYBA3OdVlK&486MSoAe&rNOy#ih&0V0FX3otLu6+Cd*$P52i4>P}ZmcCb3kzZ` zQC0P?>t$kVvAfH&<$&H7`$c=p4(^LB6GgRJUp$hFzDUSk6h0)X4~c#`d%-ug$gXSE zVaE>f9p@tR-IJa2h?stGKRV?F_3zTLXs4LbDMxos{B70@wMym-fJEd{cvR{`?lOq@ zcxc`5zss~k8E{umt3t{?`@*nN1@c{m!PMl>5T(6z zh^~u7ktTA)D)EFwl1r0dcjx$~^EJ~8Z<19*P9yd+KVk!K54?Uh+!r3@(+P4~%(6T} zLpYWGLm}NHUyZ*rescV^DPAPpdeD|RemivawS+I39Vfbh znlaL78M!GyL9EKK@?o?^-+o$39;&7F8n+1+xS#Qhc*(1;{$sWRup|sZ7Dk~6lQ4^E z!Xm6no7?Ye^D9l-E8erAp~d41*4GA@YuQi_z9zA?xf`22b#9-R1-7O;DGOxyRB0Lz zM3?3^w{DwN!E^hx9Xc$DbA=qmGRWL?#K1HU8IJ*3wt&Z!(Bk77Sa3%vq4vJ@& z$eGOQu*Pz+rassV>w3jlmwgFsBxpNjd~fC;&pDcH6D)G}q{vlLFa%j5PxDM`G&F*z|0di<_0cVo#M@qf4q%qj+ zrE+cl0p=i8YxBxz3>=9T8SJtr8zP>r$=HL4o<-CbG6jCDxLMQjxX?u#C`6~|3MxHY z*hQh(CvrT!vqk@Ji8EIvUs#OK_qX`ln1AIj-OZc|T0N$6dlW