From 3a0b05faf18afc5f1cfc436c55d0776d26b80e53 Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Thu, 6 Feb 2020 15:08:26 -0800 Subject: [PATCH 1/5] [subset] GPOS 5 MarkToLigature subsetting support --- src/hb-ot-layout-gpos-table.hh | 109 ++++++++++++++++-- test/subset/data/Makefile.am | 1 + test/subset/data/Makefile.sources | 1 + ...t1.keep-layout-retain-gids.41,42,43,44.otf | Bin 0 -> 2372 bytes ...t1.keep-layout-retain-gids.41,42,43,45.otf | Bin 0 -> 2380 bytes ...font1.keep-layout-retain-gids.41,42,43.otf | Bin 0 -> 2132 bytes ...font1.keep-layout-retain-gids.41,42,44.otf | Bin 0 -> 2304 bytes ...font1.keep-layout-retain-gids.41,42,45.otf | Bin 0 -> 2284 bytes ...s5_font1.keep-layout-retain-gids.41,42.otf | Bin 0 -> 2032 bytes ...s5_font1.keep-layout-retain-gids.41,43.otf | Bin 0 -> 2048 bytes ...gpos5_font1.keep-layout-retain-gids.41.otf | Bin 0 -> 1916 bytes ...gpos5_font1.keep-layout-retain-gids.42.otf | Bin 0 -> 1788 bytes ...ayout-retain-gids.retain-all-codepoint.otf | Bin 0 -> 3840 bytes .../gpos5_font1.keep-layout.41,42,43,44.otf | Bin 0 -> 1668 bytes .../gpos5_font1.keep-layout.41,42,43,45.otf | Bin 0 -> 1660 bytes .../gpos5_font1.keep-layout.41,42,43.otf | Bin 0 -> 1432 bytes .../gpos5_font1.keep-layout.41,42,44.otf | Bin 0 -> 1588 bytes .../gpos5_font1.keep-layout.41,42,45.otf | Bin 0 -> 1560 bytes .../gpos5_font1.keep-layout.41,42.otf | Bin 0 -> 1328 bytes .../gpos5_font1.keep-layout.41,43.otf | Bin 0 -> 1332 bytes .../gpos5_font1.keep-layout.41.otf | Bin 0 -> 1216 bytes .../gpos5_font1.keep-layout.42.otf | Bin 0 -> 1076 bytes ...font1.keep-layout.retain-all-codepoint.otf | Bin 0 -> 3840 bytes test/subset/data/fonts/gpos5_font1.otf | Bin 0 -> 4780 bytes test/subset/data/tests/layout.gpos5.tests | 18 +++ 25 files changed, 121 insertions(+), 8 deletions(-) create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43,44.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43,45.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,44.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,45.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,43.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.42.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.retain-all-codepoint.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43,44.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43,45.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,44.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,45.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,43.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.42.otf create mode 100644 test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.retain-all-codepoint.otf create mode 100644 test/subset/data/fonts/gpos5_font1.otf create mode 100644 test/subset/data/tests/layout.gpos5.tests diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index 2217d298f..63989bac7 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -544,8 +544,7 @@ struct AnchorMatrix hb_requires (hb_is_iterator (Iterator))> bool serialize (hb_serialize_context_t *c, unsigned num_rows, - AnchorMatrix const *offset_matrix, - const hb_map_t *layout_variation_idx_map, + const AnchorMatrix *offset_matrix, Iterator index_iter) { TRACE_SERIALIZE (this); @@ -566,6 +565,27 @@ struct AnchorMatrix return_trace (true); } + bool subset (hb_subset_context_t *c, + unsigned cols, + const hb_map_t *klass_mapping) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + + hb_vector_t indexes; + for (unsigned row : + hb_range ((unsigned) rows)) + { + + hb_range (cols) + | hb_filter (klass_mapping) + | hb_map ([=] (const unsigned col) { return row * cols + col; }) + | hb_sink (indexes) + ; + } + + out->serialize (c->serializer, (unsigned) rows, this, indexes.iter ()); + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const { TRACE_SANITIZE (this); @@ -2025,10 +2045,30 @@ typedef AnchorMatrix LigatureAttach; /* component-major-- * mark-minor-- * ordered by class--zero-based. */ -typedef OffsetListOf LigatureArray; - /* Array of LigatureAttach - * tables ordered by - * LigatureCoverage Index */ +/* Array of LigatureAttach tables ordered by LigatureCoverage Index */ +struct LigatureArray : OffsetListOf +{ + template + bool subset (hb_subset_context_t *c, + unsigned cols, + const hb_map_t *klass_mapping, + const LigatureArray &src_lig_array, + Iterator ligature_iter) + { + TRACE_SERIALIZE (this); + if (!ligature_iter.len ()) return_trace (false); + if (unlikely (!c->serializer->extend_min ((*this)))) return_trace (false); + + for (unsigned i : ligature_iter) + { + auto *out = serialize_append (c->serializer); + if (unlikely (!out)) break; + out->serialize_subset (c, src_lig_array.arrayZ[i], &src_lig_array, this, cols, klass_mapping); + } + return_trace (this->len); + } +}; struct MarkLigPosFormat1 { @@ -2130,8 +2170,61 @@ struct MarkLigPosFormat1 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping); + + if (!klass_mapping.get_population ()) return_trace (false); + out->classCount = klass_mapping.get_population (); + + auto mark_iter = + + hb_zip (this+markCoverage, this+markArray) + | hb_filter (glyphset, hb_first) + ; + + hb_sorted_vector_t new_coverage; + + mark_iter + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + if (!out->markCoverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + + out->markArray.serialize (c->serializer, out) + .serialize (c->serializer, &klass_mapping, &(this+markArray), + mark_iter + | hb_map (hb_second)); + + unsigned ligcount = (this+ligatureArray).len; + auto ligature_iter = + + hb_zip (this+ligatureCoverage, hb_range (ligcount)) + | hb_filter (glyphset, hb_first) + ; + + new_coverage.reset (); + + ligature_iter + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + if (!out->ligatureCoverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + + out->ligatureArray.serialize (c->serializer, out) + .subset (c, (unsigned) classCount, &klass_mapping, this+ligatureArray, + ligature_iter + | hb_map (hb_second)); + + return_trace (true); } bool sanitize (hb_sanitize_context_t *c) const diff --git a/test/subset/data/Makefile.am b/test/subset/data/Makefile.am index beb0a0411..47989b1c0 100644 --- a/test/subset/data/Makefile.am +++ b/test/subset/data/Makefile.am @@ -17,6 +17,7 @@ EXTRA_DIST += \ expected/layout.gpos2 \ expected/layout.gpos3 \ expected/layout.gpos4 \ + expected/layout.gpos5 \ expected/layout.gpos6 \ expected/layout.gpos8 \ expected/layout.gsub3 \ diff --git a/test/subset/data/Makefile.sources b/test/subset/data/Makefile.sources index bdc983552..718e7195c 100644 --- a/test/subset/data/Makefile.sources +++ b/test/subset/data/Makefile.sources @@ -16,6 +16,7 @@ TESTS = \ tests/layout.gpos2.tests \ tests/layout.gpos3.tests \ tests/layout.gpos4.tests \ + tests/layout.gpos5.tests \ tests/layout.gpos6.tests \ tests/layout.gpos8.tests \ tests/layout.gsub3.tests \ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..13a1fb7850b1db697631d89a87f6832d87cdea06 GIT binary patch literal 2372 zcmd^AeNa@_6+drbm&dY#MwSv3To5W$qx;^z_jWNxv#?;(#NvQ-XlRvi+m`$Ws{BpYih+NW7@QlCN^oO`RK>Ab*$5=?H}!Q(u~bp^32flcAduQ z^uPYud*_{Ve&?Qh&fRnG?62y;fhtIY9!LUxd1a;UujN130szYZO3mK=RW*0N{kI+f zI*h*Yy*0IE_JGF=kXnp5r>bTLYyVm8cL7p%A#OPAu(m-x6~XvI#QU3V*2Y)wnm@)| z?;;kO(XsZP>PHx#jkvJc;W?hZHmM&#MFUXj4(stYsMwE7@EU%qR;$CNO3A&0@n;ba zv^m|L)$_n&eh*?DmH?>0osg^milS7F9S%pAZ0(F?KXSED_9|niGH$IDJ`(F)2bGu#o1ughNX5pifecs&>mdssg^jQY z3ZMvzVJmD01~@RnPIv;IgmS2ar{Ec=f@-LRI;e+(V1-5?&;kx<12=R+7j(n(&>&$k$u38Rv>#A*To2wI@iJQf%9V~|myy+A=Rh_0;lb*45-6QKW zwOOCbel%yp#@xJ3y8MF8g+-s=Qe5(dt=k^kzC+Kj296hurqZ2{?|NeQo+r&^<(7)d zr}x)BTc|Enr~j`bU#(N8=d1H&Q6P)W>U39hr6?*5Mn%ii8&PR8suC|p@85`i5dBg# zr8(B3qGrbtOw17!LS+IsL)@ z&_LcyrKRBJ!S}x^w!C#+qQl2V+(R9wq|CZzN#nKo_6@XOYK^owXIrk+{o4O#@OJ1o z7hZdpj$Za(pIn;zpy8VJm3_aE46Z#d9J}`Y8{VIPIQ@@-k9;qW`RE^rwgS=-CG4b!{K*g5O2~x5 z2QjL+pCA!Ak&1XY1WjnQf(J>g8f-{Y9biYoa=}*+xiIEPe4Rm>)5p)DkTao`iCT@C zgJjU5PR1$wE%M319G5Z%(8T4&xQur*{);S#&6p!TR?o^@{$GZiK@EAZ4Jf){)}=GwE{b= lLa9c77Ve{vv?ozE!4ygx5;TR~nSM}9jWOB(J`*|<<6rzKQX~KX literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..51533581f11490b94578ef6059755d71b32c546b GIT binary patch literal 2380 zcmd^BeNa@_6+iF6E{|npC9>3@=z`EdrMmBPS>xBrht+6tK&-~rxPkSq$mi~Y3qosA zSlC@)i3EieTyWDF0~Tx4nwl}wNR3I8X(ySs)0Rp7qiO$WCzGZ&yX2Xn=k40WcKToc z?0s|3*FE=~bI*PAey@D*-f~ERlaK($;<7Ts(3RhR1ORgYs-*3E$}9h9`3n!g%%H7n zdu7$OI=`zMAlZm|W_jg$uI`~j!kO%p& z7S;g^0+?U}Y=W&&jAiVAT~H1cPzC$pARGcK)Bu56sD~zSLMyaE2Ye5@pc{I@2Lmt! z!*CYHU>rhl5qB*K{pS4227;f;i636CLp!V82K2`>@e zMED}Yn~7i~0!svr2$)eIf=C332qq#F5y4DEBN165azx~bhy{s6l!#~|Vi6I|L^2YI zB@#y@o=5_buwIEsCL$FP$z0sn)aE!!>@Guob%B918aacdrtx{3p|Z{Cvei2cI~uAR z9Zii6tIJli&S0slGgK(+uqF@C*xzn&5(!|P6Bk~JyXC8@flX-_Om*JpfX z`IDI|R%WeQZOG19lbiR|r}7KFwzlx=>((1tju%A9RAk=p^u|q_w`{d+D=sN5duC77 zzJs}%Tuti#IgSh%N_jVXVUgNPYw5IW3mJNUpWo}vJl%gf z(6ef+tR&~&q4y3%YTvviGsDLRoV_jImDBgzWo@_3ySu0Pa>Hb8W3cw>{$Km<_J0ug zP3W~>GT~X@t&!^!?;pNly}A1rGVj>(((xNVzSI5g$D@Di`NVtW1>bf1h)nrqIv_(k z?_(yX{QZ-wowaUTi%pUX zHp>NW*)n+KhUe_%iHP}Ek-QHgIhW_c_wLMwE_Plz*2i>z``J?mSCsUBW305jx-+={ z+8HJ)eZC&gqFd1E4+IZ}zcnOpnmQ(*nJ;{I%Zb6i_Ax`l1A~LBL!pUa@cfybgFCx- zduqF?sylbMHvOdPLiIWKfh+D;+i$ktJn{0$%V($i|32i4RCwNEyt6&{^i6p#_D-F< z-F{)>b|C0E*L7xW#5Z+3$P}CO{YMAw0ei38bE5mSyQSrLYip;!)7RnO_p_sS$Nvxr zjh%mSJoG{+IN5ux=SS{WIvH8HyXSXVA!BhMk)vNhH34YFieKk>sxU77|5Bv~|C(R)1pAqcXa)CT z9hy`<9qaJpO)3LAd5#JoTxh8W)C2eoxEKeNQ39Yf>IAhag{BeV{(ZNlWLqghhXqRG zITU(-3$?hosANUWf{!xP@J+lcDlr-NXP_RJX-GvaE+;%@Pkc;PK|16<@=?d^1i`2g z;Yft%;0Q_$;6fm)02@M83)CTKIba`Z4)i%1TW1mK6tu^qD3Oq-BiA6`2#E-VN_~lF zrx658mD-gP#rT)!)uI(*z6w{~I^|@=k9aBa_)I_v$KrVfq?WrcFtoG!G*^Wskd-ijhKIJH?v5Tt25 bl{!YXG0O;28^U!wwg!8-{EHgU7$5%xzI{?6 literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..b7a0bc625d42d2de4c452fbd5e84257dfaa811bc GIT binary patch literal 2132 zcmd^Adu)?c6#so)*L7Xlc&rn~tJ|0|LFo7F1`2c=Lj)aR%uG?RuHf!8YIU5{L^!D&pp52z4x5^ zo%`k7@Nypa#dYnWR=`@w zIJ>-Js#Nz`OJ?_JY`Qe!LL<8Ep2*840eV=uDV$9PjyV=y%MA|&?T&DhBy0QMxn zY=R&Nmg-gY^(}@qEtY}U5+SzK6kD1U8)?>u*^|a~V|zH9(DszE!0T6r^yrprX9wma z$67M_2SyE#tsjQj?240-j1;7DVum0C!!QC_7=*m465S*gl2}BNizMD7ktCC( zkff5Nk>n<+kfb7#T_lSnvrCy|g=Cdvjbt~;g(Me|;vz*PMIwbGDx|2SXr#DFDI}$c zR2QitsS>F&seB-nRE<(;zBuyesCQTuY&#RH#>VwX?4a*w?O^pF>$X7kZ>8Y!8E;N=0oeO+|EuKKoVN5FTaKY}ZRvr?Kz>Bu9Ep~`a5|#z ziddpYBiGMF&PVQxr2KQv`uAMwA=|~YLw5VcPWur4CsTVf%#;t*g0{)(4-ab&V~}%?B=h63vQQ_FE5izP91e zU!kn}Uj4e`gWhPtx#PO&uzQAHsV5&UIM{G``_DT!cC~fww8rxF4;*Q~#jZL&>H2ux zr(3N(FSU2{j1ShX@vZV{dch36V2$qCUUOpe?jr}HMPEhpFGO>X^hWy59PNI2{lS%6 zt*wtdykYU^(vExg%wD^E{obm#p0mcZ8&mmPwuBvA>IAMN+~@2ICzn;ba7DO+Ymnk2*k%hb*(^zxhCj7O=66cAFb|aT<6-!aWRs%v@ z@E5|zC4Cj@xVQ)KAfo`USrMNX`AKla&tWn=v6acAjYkD$IC(U4Gx!qY?q}A literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..bb7d74b52ce8bd7d33cf14172c539f479a4edce7 GIT binary patch literal 2304 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 literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..9b6e1589ff218a59d8421cc87f6eae3b13cb6bbd GIT binary patch literal 2032 zcmd^AeQZ-z6#u=h>$x#uiV{O2YGV8Y$+R60GtX-Y661gV>AAV*p5Hn5 zo^#*1_nlj_bZHGTumvfwS5{Zs4pz3G1TX-kT%EVLruK*Bzl4Fbm8=WStF7}ib%(bx z{*rNiP3<(P>C?JCz+`5;a&@z}70ZM}jBhet?Du&aKlsu82VgwH*x_fzh(XgwKEjaFJ8t09KsR2jyG`($I*wA z=*MZC!H4?ykVq2Aq>xGua*~V6NwkwFk|>cVlc(D4XLC$NOh9xBDI_xc5;a1kjNpELm>z6*HIa0?Fg$U~3@g4f`6W+T2Y|wk7)XkZp-CKP6)M<86k`>kAbd^_3 zpD}aR>^W{vW!2p31&fO<#g?r9N<|i%C9B9%WXTFfhf1Q_j%cjvmGe<;U(^)qi{7~q zy%K#in)Xkd`EOf#ujP71uhn|J$C}9(F?}E>!E>*TMv8v@Ix#F5-y6!y?S7%Vt1Ex& z&aFM$3lCIR6<=z&{6uWs$7eM2-c7qgog1Fka_aq>b(^ni(e}2tTaK;^99(y@{;SBv zo!|F-edO#H=4fB!%)b7^S5}_#o?i61CI@G~vFX(N7q)$NbN_GKZ*`q`G1BkfrwQGf zp-01$=C1BYq&q)&yrJ!o&m5ofr<$7)pExu*mv*js$^X1ow!T&?Sfl0pwY>9MWvs{> zvoDX0i|ttu%Wk~7zO!O~TMs=IdX_c^I@;O}-~1$&7c(6)_x8N?eDB>*X6>MMC->Yy ztn_lfW;pJgrPXPv$4ig3+}i!~-mUw)_U|>vOSE$wwlk8O!9O`?Bhi1I<@#<#_Ke>l zq+Zk2n@dh?(Z_FBE%YL9c$ZN!yvr~J23^Y)=9*BJl>Wb5&p{#!oWpdk=(v=~%F)#6 ziLBnA7!M5T140j%J*zM%4B|GV#0ZvI0t^;YiYYb2U@-DB{Y>tWyUH_{OQ0K`WDK2O zpDhdz59?7Gxw+|N!ee|sf-#-f=P^#o24pcx$|?8hjrYl^$ibw$b4&?6aZwF$SyizD zYglSQm<#d}__*Y5Kob|=ARcEF3=JP2O+|%p8S@z3Ubs>m#7=01K>lD;gQr!n_pvNB13 E0Z$^hg#Z8m literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..c28bed156d37aa42b8f3fd980c6be4b754e015da GIT binary patch literal 2048 zcmd^Adr*{B6hGgxEW69{QkE1&7m$K9-S4@8Phi1J4FhQ~6I@|AD*_9fjKKD$Mkc=>R$k02taLFz9u&xrh@?>tZ1)oCjKk& z*xdXDT*a3KCjm4L;u}jUZPjp0b&>pQh?hF-w$hJ(%eY0c?huz8WQZKokY8gZKF3j6 zyFIEas0kog0AM03ZQHBCstkqm^lPeYm3B=?+$h0e;w{xqckRSGz)}3u#7zLymm)Es zRsq8>n$o(;%6bK*`y;?##Q2L<{^B72G_@RM2%6Ocdp(}X)({d0@WEJEudKO!d3<@W zzdmAQ+&IPG7zNoBijolwA)uqggh2#E!BmK$M9hTQkN`=L40B;Vupod1(qSb71NM4Bg-PoA>5xOTI(?`iEIcAIYRc4TW6WdIrpL~h88>UTDLx@_PSWE~B&R$%civO;7noU& z7evXDnwGwB(c&dbmt|yTS+jFiu6iy}pQsQ2uM)2}QIL3jfV~2Nt#M>(;6l?qnPAp3>rRiy z7~6NZx3$GKbu@Lh%sQB3O&Bh^y3SYr**RI;wQY~PweBT3y3ipTn(b|?TWU^J^_Dvi zm7gm7-gCL*dgl*4=fBZ<2R!HY4<5O;@r>>4>aS(qwe;AwGap@Q{^~~epDj1rPQLCL zbnKUzc3IUa!wzj*yT{WW>*_D6Ic(SZ=iU{Kq5j12WFvNzz3JE~&)bqO$Cb&k4mswc zoaKwR`OF)9Gkp72`XWky+|rufUDJt;?pLwFSzl9gO2&c1t7Y2`!m z9pi-|U&_@%S=Db@A{WTP{VB(*ZtnfPtEs!KyG!d&k}nuT|M1^3Ug`e4;fvkc-gnzO zdS|=Kx7+LNlAN+cPT4MJ>@7R9>%fU4zO?UrN!NV|Cx*Pkmj-%{HXh%yTig8N3p>}( zuy#CsFndQy+uqMXKvN!dLzIi*0P7827|86S$+3b;H^g*OSv4?Y z%oyATE}(%hApn(L6Ql_aRjJf8OgWbal3~rvrV^V0S(9@p?dVcwVq!v>l~@LSifG_j zIwMA{qwz7sC$S2`iB005N9^iHa4*?JNzvr9eF)$673R`UzXdjOG8-upnY5)KL literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..7878d4b8f9f47be6e9ad958479c39459ea78453f GIT binary patch literal 1916 zcmd^AZBSHY6n^gRvMkFAqCkqGD@s9{?)};Y{9HgBQ^NsiXv~jQ)`Q5hu!|owR#t+< zqGCf9nx@m%j6v#Hm<`U@C}Y;x$7oYi!!-P9`fCogi`SxacbRmW{`IqW=RM~<=i@#1 zo^$uSZ)TiT zUb#T3zgcw_NQg4tyw&Gv#CqX4U>;_?w$|&Z`Q&H!?|`YBv9p#H6GzOSvj4Y?=hXU| z_at93RI~jiAXt2!J&h>VQ{ggibA!j{H78~dv&cSZYxD=3$KHm-`5lbyoB}B3NSF)| z1i@Uh)8}i^rJ`smqR$G^4Tk6jV|0p1OS2hgoWkKyC{AsO*}&P638yvlz3ZbZ5~BXp zp;6Wd=wWW0f|WB!c0Ia(l8mBT!`tIi5%o24|6deA{4k#gvD5f5|m*jR-+sh zs6sW?VF& zsr*1HsZLT|q!y4`NKOYiMRH2yl*y@(Q!Vi~wgk3QZL>XZYrb7_I3&Bf#=pgDuWSi6 zdwoIs%7(4}K%+n4Y4+C4x4Y}>?G?Iv&|cvUdIP&y8E+-`^1w0_b88bVN!DcBgp|~Y zX_F?WXJkGyWop*6>De=8+Gpj=o|F6NV|n?H&z<+g`~?nCk`>kIDkv;kxM=Z`rOVvK zC8f*DR^?c8tSSF>&9d69DS_~4Zdf}Ij+DN6HLM*Cn3~nV}j|U(aem_S35g8vi2X`-_IzuJa$SyHNdI==#B*y1qYk`5R04Txj5E z|H<2%FM2Mm`C5|$OW)mn@#AZ)U*75Ywe4=l`PV}IwMR9fQ!{jFc+S$%847h~1^PBN zo$y+sbN^5?lB2Un^D^k*w%2Q4(dO-_)Uvl}S+!c`Rjnj4%M)>Ih)jzdSrtjG`C&(U zQBPABJs*6D_WE0znoi#NB9a*~pRn|Hz5hz@cq)r_T)UrfWiXO|t6wwpxt3^ET0&p` znTETEf9c-e)6vsyiRNloIBk0>HkY(HQ@Rs@dU?>7&@J>Fjmori&6|j(xA}AW6maw2qU-$ zDaOGvOMt;@HkuQX4F(g3>HYY7xl40<9nYcD;ibaZ*qEM`5nE!;W<15c5ll%O zpUIlIY(NU5xNLk#Z+b{hKsx4(`

T;vwqiF{)w{wz1TJW*)#5@bZY=iFzKk0X)qp zz&_h!c9BQ4eoOGH=qE8xXKrP#zyv#U6aRF*TYvI#s$=Lk92Yn52iQbVFV7P_28y4|w7kT!vc zB0{J_F^D1}5H}`RB1A)i(MZH7CqjzwexL z&%JZ*oikmVHg&;+L$JXgZEu&p{BiOefN{Xq*|D*!2Xo;CoZqpox}&Ez(*H{K2=hti z^SXLgDE;5|UIiRO%(w4M#s=}MaDnaHnQu(QV|^e08vYZoS2H&ftf-!He$M`zm@iEv zvqPR6;%2r#4hY_4Y-kYCjcmfF+?@llWZYR+Kgs?-F@Je5mC4RrfWoG0%q3m|i1JL> zMF@i6?Aw=24qK?TP=&%4p|DjfY_%2U*v%TRZQ(_n92qG|Z&^L?!BoX1(|PBs=?+IB zTQxE5o>dsCK^uqSWH?X;7bm6yRj9#i_&5;@un3FMh$bvU3uI^rpcSjJjyKVcPHaFI zy3vcxcm`V$LmvpwA&Eg`uph%Xfamcdj^G$ZZ~~`r8gJk&oX17Hi}!FDS8x>{;yP~N z6MSa956PsEN*d{8P=JCIBH2%}OtM0PO?FAfaD;_AyWLL@EnB{l@yH>ofLzV z04YIILZtdhl}Y80DybT&I;jS!0aAmchDh_1CX=R+#w%*1>7*H?1xO2$79!nGx=gx4 zx=K24NGIJOJwSSp^bi?-GGsCoGE_1&GI+m6G&MM!-c5l%Qv7~J3iqXU#HF6$ zOg5g(NSy;aQ|ZA}I+l(1wMgOqeyQ7X&q&?zOgz1xm8J9K13el>l=D$m?s9v)6_r)h zHM3^d*7+WqGk4zn1@#LTNezpaENy)Fk*4NHmo0y+Wrbf>R82Pm!BFeURjb#mT^Ei- z+t#;tY-n&dxGVp2liZTKGM$@l%$Y}X`L;K2<;*iVXZ~vL?iaZqa!=&S{%I?}Z*z^g zCp}|c@8qbrf-j+KytXLoCT2qvgrS3lCDToH^y;qH6Nk;^dwR_JUFN)m>APh{^9`}Q ze@lLT{?wECs=lB19BVzhca#ohUZ4Z1;k|p``Td)`FYi2GJ~sOP;j!b_UK_cdI8$z( zGw;^j9M3m@f87+X1lE|nrsGQU<$*s={&xDMv&YY#E-y5iH|sowV6rYb^ckz55^AZ+O$*hEJ59sX=Uq%niav#5i0N5O5BGz5c*@;0hHgL^B1&fVaEUf literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout-retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..b7c424ec646f08de940a0d9a6ae718eb5b4ba0eb GIT binary patch literal 3840 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 literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..5d4fcee062c719845a678d7ce5779f80d6a44cfc GIT binary patch literal 1660 zcmZuxeN0nV6hH5^eLPAP-6%0Qv?3&u5k)p@bbf$7(VNw6p~Z(#;`I z`bCQ%0u?M+|4?K&zoygZrp%$6nbB;^7UD>jxnx-u=a{efG~Kxc-LmZ5+;h+Gob%58 zo%?cc&Xz4X5CwZd1gV*8*D4b3I*$UtFo0;yy3ILxKYjM=DFDeR`s&x^<*zAonHvF^ zU5Mjy@)o6)eU*=Ku>tX}LY>M0CA1Xt3lOWdoJxJ+=Zr@fXAvv4=$J9iypMPz;zX^^ zY++v&H6Tt$EYqnh29Rt<6E5Lo%2hg!iHIM=_-({Z2EEA~It*!8pTrdam@5IGKuiNg zQH;7$r>h~>@?bOs=Tboh9aM;dv&6zonP`q5JWl7NmPNz^d^kR>PhcKjpI9g1)1ycE zq8IqAnZQt#I6^vYbG}BoM59z{luI?rWtnpxH7gbrCM(iXQ_~a~YW;3bkym3f zb2^h^eR-kYXwVx~W=_3Okx^Er$R+6}MJ{LJj8*8IS;BA`Iy*4XhWXGLte90FV1-8Aq z#nfE+o)A-@6=aQ^V^dSbV0mAO-dA#};9KW)_dV}-{!6#nz>xD|$JySyyUwZ3Z~9tz z#kl%t^|_C)HQsvA^+(e~$I1Q9v)T@UatX9ofLhk!ayngc#uGa#dN?-t^3x^qsNnpG z1#*qM=zw;gkW!i_#1{#1S|RqTkjc+e@u~0fv-#FH_-OU_rOnH`D!dx2=>tujzNVt0 z_rXm*mS=j{0q^mB15;bEf=_rNzcS1x-#IJLCzh@f@&(C>-YEie23aLcs4X{vX#{57h2bwSALRzxUkc*?WE;G?fKgCdyelN zJUHO~v(?Gx+HSCpp(Y&me%q1e{?5y_hkGx3eYVc}w(bsRf3=UzTq<`Ld$e9{v&FWj zvB6SVSzT3Sby=NtuC1RJU+?+R>+e2vpvS-8@9S$m)AW($w3T((?GA_C+EQ0M-Ee7ytOiFoEnG6kQQD6ZL|PrDI;PeQ8X>aF9@gS zl99D08`2>IvM2W-dTccn3Wdn7h%#^xVc<>VM~Nfx`&h)2HVxAeP1>S=`NjXTB@hFN zQ#nl7uK@$-!30ZSClsMo4rW*kxxj%2DxnNiV1%uRjF?j#jxUCVkQ(MelS*jC;EHb| ztN<}Az?H!j&jB(an{X!`VH2N*t~~EohF%Egl9ik^=`0f`sh2%9#aK5ip+n?N{2w9N zQkVlNK$WS?<-p?3D7Y($P-f0#M&Gl4FD7p(Mp&FOWKF?KSeG!Rrx;VXBVj|jnSqfJ hxQ|*5_2^}A5G@OPI#6?PaH_Tx&vMpt4(ObezX9uu@l*f+ literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..54fc0684b25a0e0761f10cd5e45f0ed7c6793a66 GIT binary patch literal 1432 zcmZuxeN0Etwh3hEt>2;*5qYBz`6SVdjE+Wp_(GuSK24b92u*zu&#@ ze7yJWEvu?30~NG`3~~#Li}@RS$p8QZ0hkjdCRSMridmsEx_&KX$A z3ecW_SoFrF038aj;&kBNeBgTE=|IeX*SLSyVkeYKstL7v$**36ZN&x?B3iTfP~^Qp zFN8@I*>`RwQRD0Lc|1v-{hj{q)YHX984Cxl?GqcWoTuF2v6HUerV})w#!S^+f~T~* zamqH{U>|Atpyr16a{o>Lw__K+<^t2+^Fy42W`q#}JH0MYqO{u3z zW}0}37K-TxG519=S$t)$7;pUUNbio}M!%`e^|Gne-qP4Odh4o~D6(g`3IBT?6RW8> zIzsPhE(XQyYqOM@+@4RXsbVtwtnK!|FN2-Kp5Z|*ltnLURKJDpXs!-_*7|uLH~zM- ze>~0A&@40wI+~qNvzw`Ypnk6B)YPc>_%~wKO)+CC7+9E}9($+l?2$gMYya~dFC-WB zKY4o3@w&E=nscvlA>I8g*h{ZhqryLtL}&Yz{PNoPoqqsPEFuG~Su^dD{r=E121pE_ zlxvv}5z2s(SUg3GBqur$V2s!x+69S)am5pnsM5B-ga8v8Bz{nUnkwcqab+w7zKf9w-1k6h?DMdTAF4hr?1Ls}tj!R1CS8Wk@a`~s5C;Z(zV)JgCNYWzN{Gg>=~XaRmk cmc=1yH8MsRLM_0l)p$yLR~!D$i)2*(1e=tJr2qf` literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..d4c95a645054237bd3b836d60d73ee6aa8847739 GIT binary patch literal 1588 zcmZuxeN0nV6hH5^eLUJKxKUylViCwRV~RMKabyZI%{~|gbYXE*s(rLzOKJN6ai~aX zDgB~AhkPhVtVO*H)|nfJp%Q_pRHCOK;!5n+_mzBIny$x}(70;q3s- zQp8EcrE9VcU+wq^K$?uWe6LYc1A1D9{!+wRJ*Uy0zmxwbfMgVLt{#c_S>`a}5aM*b zk>AfgN0%YKi&$>d?5_doHZ!Jjq&w})d1*=J5eB| zfublzTWd5n5Nksy4niqZXgM8PE(tA_ic6G|loQbIc1NW$W*NYTvx|mA=HZpOtui4m zZd!Qj31QO`kWrL0MqX5+%gxc{=IV0SZ#LC5SSodTUcGYfDs^^NR<=4{Yudx9OB<{_ zXSAwcuHI|1)R-(9p3|;Y=Nk;_65?)EmvC0jQio(TFHEeJ1}WyLh*zb_)8va&N$rX zvwhxn^3YK8kZrJ`ud%cnLN^J`_gxAaZ6S6%L2Vu88vSA%lU} zF+WNgi|;2Qj@mRVMijLrkMYvSY#Ag#`hpJ=;dM|0Ca^*d?1l=os)2{KPy!t2pcV|E z0Sml=$bvqVk@dB(8nPmJ&?FLC38>|$^YC6-iJC!;eSiWeB)OA{u!zsXmmbxtL>3~x zM3YXF$_j9jc!dj7f^j1we2m;*|1*fU98w??D1(Nt2A14x0Jtkzp?J>9BNvT|7ao2U zVzW4vm^BSaSP98AS_u`gNkj_baZbUnD7#UUcWLC~v1iGMw8&D}uO5^f97U;v-i3YS M=(F@uK1fE#-zQYfZ2$lO literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..656792d7257a318a3ef675ece1643cd38e45d788 GIT binary patch literal 1560 zcmZuxdrVtZ82|2Vd%3h7Fr{R{47vviL^2r)i<7zWT(*fUFeb#gt)pGbqqMXI%4;G6 zTG~R(#(0%S!7kCk1oxg>HnSn3anWpvMne>1)WqzMIni5oG4(qw&S^Y1=lg!Y?|k=r zoO{p7+qW+dB+v{3NXpE~k*7glEda~_(BJRen^*9|$S=16M2%=WwzHrxqrzcoL%xhW zI5;eVbw-na6p}Ij0pxN3^c4b7Af$n! zC`MVW)z%TT)fW!F7|It*`(g#YH9~&1R1o63e?U(D3$>kOr8jY%F~k|0k`N=lZeD|JUy@`5^}Nu@Q) zcU6|?40@eGVNxkK$m*J+o%eTGvyt}<2|6ODMSqq&IFGwb&(gl}v6}A;R6B&@Q z`KJT>0#@)-m#OO)mZD^i4u{Pa-P+meYL6Mr$yz^m@NO|z_VG2I?WyfDTC0!okwqF_ z+NQGQwpX3494phg%gz;jX`k)<*7cR=`WLKs%6_f);>f+jmlRiWKj)t}Y(HIl>GJKi zI}ZkaZGUK+K4HJ8>E$U0PrG=iXKfC<-4Sh=JXkfXVtvp4nIe<;HY~-<)SX99X^!)W zT={jmb?ZQtOWkCAOWmletEw7#@F^F?F~jVH z>&)?ql~gS6=9gtRXSjsB7kPSe%gcNrFPcnvxALL$=bqL9+dvQNi{o!%+VG`tS+Vj!(z9H*3>jPn(U2^{U4Ri4u9wJ3=W+d_MGsz$E+9H-#4FcVr?BA zHd{wiS7VE%hUE&EuVLL*yG(*VJO1Q>d4ZOkJ`|qzJ5Zu|Vs4C^ZYKJhBd;hR%HJhS zrq3f408OlTQs$||;DZEXgyPADIbww|(My4-#O?1v0UbI+xj+O`YLQxmN01!QfEW?p z3SvgUh$J+P=kDKcr)Onk!wyJ?>|hQe7q(M=zn^49mW~e@47`f7+M8d`uA0}W|gC2BXgcLXgM-f$m2{uDMs6Y+XPyq@sz@?{t11E`>y)p$D zH!%D|r qgbH915g-Eb9Q=e*2`wmv=)>S!g!iIULElPTG4A7<$NAA19De~*x5ae; literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..cc2f5f7eec9f6ae43926362954770e7dbdbebcc8 GIT binary patch literal 1328 zcmZuxeQZ-z6hHU%_4W0G4X|yNVVk$PB`hMA$|gY~wwoKG*kxsAn($H9x0ccGcESwm z%s!ZH2i45!L~u)LqHa2(4nH7bV8O*`B#>w{i&^3aiGLxPzK)Bj=e7+JyJeoi5NrAE?0A*xW2_y878u05Au@Sz20M?w>8cZv@~c&=zZPw>tyr#2|p$ zh`7?_zSkc3x_t&fwGHv!&Y&j(YsfB)w;^uz%O3BizdHWHT)!Z0@S|bnlJGpn*C4L( z2NQ=hBG-ZVPQ+r+b0`9;R#f3EZXx6e%7VtSi2k<`4@JW9ME*^%WBxwG5|%(000Eu@ zLWtn)2?l$awmDZ0ISa{Ixtvv%tKjJ>gUUJq$5N>xH)t#X?=P*Gq{5Ah%PneUQ~83@ zwp!V;3V1?z&32csq2AZf&=`*N#`gRC32AL-on*J!?2^M9-X}}$-grU|#-&F>o#9v{ z9P=b(?|R7*2uN)#JTA4#aXI!h8jC$)Q%4A>ut)vMYF)LitV$;_R;4S8WtVHS^hj1| zdhL9cj%5X9CVTTj_DXhpR`Xw<_^(eprCZcb84QaV!wNi%cFtJfriD8|g|`92kSF{{ z%Vtyh#dI=RIWRJi8M40K+*Cck`|^`Y_m^j=IC}7Ce7NU1YV7b+!=RkpF%*3-G}#?K z-u*$xcd3gbKV`n3ID1LV&ZN$a&7Qon_q6Ae9pBRXVq4!jc>3cDgWp^m|6}NS^3=I4sZ_c$HoZG~LKbs(|6Om==k8iwYx0eBz2fhu>khc7rHfYjsrfu@ zRH{6RZI`k}dFfH5-220U;mzaGjPKd_3%cEHo~7LM{SVT1s-CWUCv^ST)zN|R~PAY#}5T>qp&}}=TiTk@-2S? zQ7cT+Hrdor41p@I~pQ2E+ht#u>2~ z2X1FU$N6QHe}m2S{}7ATffevA1U!ilh*$*)YcLN<$ngZ)idpeTfNy~5B5nh$MqYs@ oC%D*56c@Wm0`u@2avtphMiTJC7;+h2E#=bTJyqPQiN+%R1L=}l$N&HU literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..946c63c682a895516200f026e245c8759fa964d5 GIT binary patch literal 1332 zcmZuxeN0A|D?kIMK>-CNWo2UcaBmm@764dp`N4`Rcnq`vN&$VTQdqsL32U{>LG3!+OwvMHOzV~&jhzPcLX@dy4qaT; z>jHfNpD&}czcbjKb+)WDd-2GPLvq7cmx(ZV@{Fgq`8ASOYbDw)$#@e z!UPB#BydXb1^oU%hI`^j(|JjVJaNBJr-|gO=IJc`_3v0a$mYf>l37nOtVDm6l*k)R za=|O|2KmkB}TU zMI?V0$!{UXf%@5=cPB^Xr+$=kZ^_w{3!%mNsj&~+FEsWEU58)lczHu<|Gu+(Pt~=L z)LwjBh!ox5ihJqx>ooY&(H{>+FL7x{Q;PovM!AF@Xv>{GP3^D8pErR%dWJKwpCMHM zy%s3SC1x}I=-ec{Ww1y+Fs^($Rxy^7Pz9EEyB4)DS@s00Zt&A=`bUI)+@Fd_c{E&P71 literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.keep-layout.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..093f4eef098b4ba9a99288f429e86319a7bde68d GIT binary patch literal 1216 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 Date: Thu, 1 Oct 2020 16:44:16 -0700 Subject: [PATCH 2/5] [subset] Fixes to get GPOS 5 subsetting code compiling. --- src/hb-ot-layout-gpos-table.hh | 37 +++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index 63989bac7..7224410db 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -544,7 +544,8 @@ struct AnchorMatrix hb_requires (hb_is_iterator (Iterator))> bool serialize (hb_serialize_context_t *c, unsigned num_rows, - const AnchorMatrix *offset_matrix, + AnchorMatrix const *offset_matrix, + const hb_map_t *layout_variation_idx_map, Iterator index_iter) { TRACE_SERIALIZE (this); @@ -582,7 +583,11 @@ struct AnchorMatrix ; } - out->serialize (c->serializer, (unsigned) rows, this, indexes.iter ()); + out->serialize (c->serializer, + (unsigned) rows, + this, + c->plan->layout_variation_idx_map, + indexes.iter ()); return_trace (true); } @@ -2057,14 +2062,20 @@ struct LigatureArray : OffsetListOf Iterator ligature_iter) { TRACE_SERIALIZE (this); + if (!ligature_iter.len ()) return_trace (false); if (unlikely (!c->serializer->extend_min ((*this)))) return_trace (false); + for (unsigned i : ligature_iter) { auto *out = serialize_append (c->serializer); if (unlikely (!out)) break; - out->serialize_subset (c, src_lig_array.arrayZ[i], &src_lig_array, this, cols, klass_mapping); + out->serialize_subset (c, + src_lig_array.arrayZ[i], + &src_lig_array, + cols, + klass_mapping); } return_trace (this->len); } @@ -2179,7 +2190,7 @@ struct MarkLigPosFormat1 hb_map_t klass_mapping; Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping); - + if (!klass_mapping.get_population ()) return_trace (false); out->classCount = klass_mapping.get_population (); @@ -2200,9 +2211,13 @@ struct MarkLigPosFormat1 return_trace (false); out->markArray.serialize (c->serializer, out) - .serialize (c->serializer, &klass_mapping, &(this+markArray), + mark_iter - | hb_map (hb_second)); - + .serialize (c->serializer, + &klass_mapping, + c->plan->layout_variation_idx_map, + &(this+markArray), + + mark_iter + | hb_map (hb_second)); + unsigned ligcount = (this+ligatureArray).len; auto ligature_iter = + hb_zip (this+ligatureCoverage, hb_range (ligcount)) @@ -2221,8 +2236,12 @@ struct MarkLigPosFormat1 return_trace (false); out->ligatureArray.serialize (c->serializer, out) - .subset (c, (unsigned) classCount, &klass_mapping, this+ligatureArray, + ligature_iter - | hb_map (hb_second)); + .subset (c, + (unsigned) classCount, + &klass_mapping, + this+ligatureArray, + + ligature_iter + | hb_map (hb_second)); return_trace (true); } From 093909b2ffb1d938206b4a543652ae02c99491b2 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 5 Oct 2020 13:14:53 -0700 Subject: [PATCH 3/5] [subset] Fix wrong offset base for subsetting LigatureArray. Offsets from LigatureArray must be relative to the beginning of the LigatureArray table. For the serialization mechanism to use the correct beginning point the LigatureArray must be created using the push()/pop() mechanism. So convert LigatureArray subsetting to use serialize_subset() instead of a manually called serialize and subset. --- src/hb-ot-layout-gpos-table.hh | 78 ++++++++++++++++------------------ 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index 7224410db..8b69da270 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -548,6 +548,7 @@ struct AnchorMatrix const hb_map_t *layout_variation_idx_map, Iterator index_iter) { + // TODO(grieger): can serialize with an iterator of anchor's? TRACE_SERIALIZE (this); if (!index_iter) return_trace (false); if (unlikely (!c->extend_min ((*this)))) return_trace (false); @@ -573,6 +574,7 @@ struct AnchorMatrix TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); + // TODO(grieger): shouldn't need to use an allocated vector to do this. hb_vector_t indexes; for (unsigned row : + hb_range ((unsigned) rows)) { @@ -2055,27 +2057,31 @@ struct LigatureArray : OffsetListOf { template - bool subset (hb_subset_context_t *c, - unsigned cols, - const hb_map_t *klass_mapping, - const LigatureArray &src_lig_array, - Iterator ligature_iter) + bool subset (hb_subset_context_t *c, + Iterator coverage, + unsigned class_count, + const hb_map_t *klass_mapping) const { - TRACE_SERIALIZE (this); + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - if (!ligature_iter.len ()) return_trace (false); - if (unlikely (!c->serializer->extend_min ((*this)))) return_trace (false); + auto *out = c->serializer->start_embed (this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - - for (unsigned i : ligature_iter) + unsigned ligature_count = 0; + for (hb_codepoint_t gid : coverage) { - auto *out = serialize_append (c->serializer); - if (unlikely (!out)) break; - out->serialize_subset (c, - src_lig_array.arrayZ[i], - &src_lig_array, - cols, - klass_mapping); + ligature_count++; + if (!glyphset.has (gid)) continue; + + auto *matrix = out->serialize_append (c->serializer); + if (unlikely (!matrix)) return_trace (false); + + matrix->serialize_subset (c, + this->arrayZ[ligature_count - 1], + this, + class_count, + klass_mapping); } return_trace (this->len); } @@ -2181,7 +2187,7 @@ struct MarkLigPosFormat1 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); const hb_map_t &glyph_map = *c->plan->glyph_map; auto *out = c->serializer->start_embed (*this); @@ -2199,15 +2205,14 @@ struct MarkLigPosFormat1 | hb_filter (glyphset, hb_first) ; - hb_sorted_vector_t new_coverage; + auto new_mark_coverage = + mark_iter - | hb_map (hb_first) - | hb_map (glyph_map) - | hb_sink (new_coverage) + | hb_map_retains_sorting (hb_first) + | hb_map_retains_sorting (glyph_map) ; if (!out->markCoverage.serialize (c->serializer, out) - .serialize (c->serializer, new_coverage.iter ())) + .serialize (c->serializer, new_mark_coverage)) return_trace (false); out->markArray.serialize (c->serializer, out) @@ -2218,30 +2223,18 @@ struct MarkLigPosFormat1 + mark_iter | hb_map (hb_second)); - unsigned ligcount = (this+ligatureArray).len; - auto ligature_iter = - + hb_zip (this+ligatureCoverage, hb_range (ligcount)) - | hb_filter (glyphset, hb_first) - ; - - new_coverage.reset (); - + ligature_iter - | hb_map (hb_first) - | hb_map (glyph_map) - | hb_sink (new_coverage) + auto new_ligature_coverage = + + hb_iter (this + ligatureCoverage) + | hb_filter (glyphset) + | hb_map_retains_sorting (glyph_map) ; if (!out->ligatureCoverage.serialize (c->serializer, out) - .serialize (c->serializer, new_coverage.iter ())) + .serialize (c->serializer, new_ligature_coverage)) return_trace (false); - out->ligatureArray.serialize (c->serializer, out) - .subset (c, - (unsigned) classCount, - &klass_mapping, - this+ligatureArray, - + ligature_iter - | hb_map (hb_second)); + out->ligatureArray.serialize_subset (c, ligatureArray, this, + hb_iter (this+ligatureCoverage), classCount, &klass_mapping); return_trace (true); } @@ -2276,6 +2269,7 @@ struct MarkLigPosFormat1 DEFINE_SIZE_STATIC (12); }; + struct MarkLigPos { template From 1d9801e01290a62cfb802971061b2cc9f7c43bc1 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 5 Oct 2020 14:41:55 -0700 Subject: [PATCH 4/5] [subset] In AnchorMatrix::subset eliminate the use of dynamically allocated vector. --- src/hb-ot-layout-gpos-table.hh | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index 8b69da270..b7eee4d9b 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -548,7 +548,6 @@ struct AnchorMatrix const hb_map_t *layout_variation_idx_map, Iterator index_iter) { - // TODO(grieger): can serialize with an iterator of anchor's? TRACE_SERIALIZE (this); if (!index_iter) return_trace (false); if (unlikely (!c->extend_min ((*this)))) return_trace (false); @@ -574,22 +573,16 @@ struct AnchorMatrix TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - // TODO(grieger): shouldn't need to use an allocated vector to do this. - hb_vector_t indexes; - for (unsigned row : + hb_range ((unsigned) rows)) - { - + hb_range (cols) - | hb_filter (klass_mapping) - | hb_map ([=] (const unsigned col) { return row * cols + col; }) - | hb_sink (indexes) - ; - } + auto indexes = + + hb_range (rows * cols) + | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % cols); }) + ; out->serialize (c->serializer, (unsigned) rows, this, c->plan->layout_variation_idx_map, - indexes.iter ()); + indexes); return_trace (true); } From be33704c003732a7a45b8136736b42ca54be98b3 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Fri, 9 Oct 2020 16:46:46 -0700 Subject: [PATCH 5/5] Add gpos 5 tests to meson build file. --- test/subset/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/test/subset/meson.build b/test/subset/meson.build index 9153e6914..48d85581c 100644 --- a/test/subset/meson.build +++ b/test/subset/meson.build @@ -9,6 +9,7 @@ tests = [ 'layout.gpos2', 'layout.gpos3', 'layout.gpos4', + 'layout.gpos5', 'layout.gpos6', 'layout.gpos8', 'layout.gsub3',