From 96ed20725c99275f286a9a9cf461548731b6828c Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Tue, 4 Apr 2023 10:33:58 -0700 Subject: [PATCH] [instancer] update bound metrics for CFF2 instancing --- src/hb-ot-head-table.hh | 20 +++- src/hb-ot-var-hvar-table.hh | 3 + src/hb-subset-plan.cc | 88 ++++++++++++++++++ test/subset/data/Makefile.am | 1 + test/subset/data/Makefile.sources | 1 + ....retain-all-codepoint.wght=650,CNTR=50.otf | Bin 41760 -> 41760 bytes ....default.retain-all-codepoint.wght=800.otf | Bin 0 -> 1508 bytes ...ain-gids.retain-all-codepoint.wght=800.otf | Bin 0 -> 1508 bytes test/subset/data/fonts/Cantarell-VF-ABC.otf | Bin 0 -> 2508 bytes .../instantiate_cff2_update_metrics.tests | 15 +++ test/subset/meson.build | 1 + 11 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.default.retain-all-codepoint.wght=800.otf create mode 100644 test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.retain-gids.retain-all-codepoint.wght=800.otf create mode 100644 test/subset/data/fonts/Cantarell-VF-ABC.otf create mode 100644 test/subset/data/tests/instantiate_cff2_update_metrics.tests diff --git a/src/hb-ot-head-table.hh b/src/hb-ot-head-table.hh index 798e82da6..770cf52d1 100644 --- a/src/hb-ot-head-table.hh +++ b/src/hb-ot-head-table.hh @@ -63,7 +63,25 @@ struct head bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - return_trace (serialize (c->serializer)); + head *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (c->plan->normalized_coords) + { + if (unlikely (!c->serializer->check_assign (out->xMin, c->plan->head_maxp_info.xMin, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + if (unlikely (!c->serializer->check_assign (out->xMax, c->plan->head_maxp_info.xMax, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + if (unlikely (!c->serializer->check_assign (out->yMin, c->plan->head_maxp_info.yMin, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + if (unlikely (!c->serializer->check_assign (out->yMax, c->plan->head_maxp_info.yMax, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + } + return_trace (true); } enum mac_style_flag_t { diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh index 53355c507..00a8e1f0b 100644 --- a/src/hb-ot-var-hvar-table.hh +++ b/src/hb-ot-var-hvar-table.hh @@ -265,6 +265,9 @@ struct HVARVVAR rsbMap.sanitize (c, this)); } + const VariationStore& get_var_store () const + { return this+varStore; } + void listup_index_maps (hb_vector_t &index_maps) const { index_maps.push (&(this+advMap)); diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 76e127bd7..a30fa9d94 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -36,6 +36,7 @@ #include "hb-ot-layout-gpos-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-cff1-table.hh" +#include "hb-ot-cff2-table.hh" #include "OT/Color/COLR/COLR.hh" #include "OT/Color/COLR/colrv1-closure.hh" #include "OT/Color/CPAL/CPAL.hh" @@ -854,6 +855,89 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan) } plan->all_axes_pinned = !axis_not_pinned; } + +static void +_update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan) +{ + if (!plan->normalized_coords) return; + OT::cff2::accelerator_t cff2 (plan->source); + if (!cff2.is_valid ()) return; + + hb_font_t *font = nullptr; + if (unlikely (!plan->check_success (font = _get_hb_font_with_variations (plan)))) + { + hb_font_destroy (font); + return; + } + + hb_glyph_extents_t extents = {0x7FFF, -0x7FFF}; + OT::hmtx_accelerator_t _hmtx (plan->source); + float *hvar_store_cache = nullptr; + if (_hmtx.has_data () && _hmtx.var_table.get_length ()) + hvar_store_cache = _hmtx.var_table->get_var_store ().create_cache (); + + OT::vmtx_accelerator_t _vmtx (plan->source); + float *vvar_store_cache = nullptr; + if (_vmtx.has_data () && _vmtx.var_table.get_length ()) + vvar_store_cache = _vmtx.var_table->get_var_store ().create_cache (); + + for (auto p : *plan->glyph_map) + { + hb_codepoint_t old_gid = p.first; + hb_codepoint_t new_gid = p.second; + if (!cff2.get_extents (font, old_gid, &extents)) continue; + bool has_bounds_info = true; + if (extents.x_bearing == 0 && extents.width == 0 && + extents.height == 0 && extents.y_bearing == 0) + has_bounds_info = false; + + if (has_bounds_info) + { + plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, extents.x_bearing); + plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, extents.x_bearing + extents.width); + plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, extents.y_bearing); + plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, extents.y_bearing + extents.height); + } + + if (_hmtx.has_data ()) + { + int hori_aw = _hmtx.get_advance_without_var_unscaled (old_gid); + if (_hmtx.var_table.get_length ()) + hori_aw += (int) roundf (_hmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords, + hvar_store_cache)); + int lsb = extents.x_bearing; + if (!has_bounds_info) + { + if (!_hmtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb)) + continue; + } + plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb)); + plan->bounds_width_map.set (new_gid, extents.width); + } + + if (_vmtx.has_data ()) + { + int vert_aw = _vmtx.get_advance_without_var_unscaled (old_gid); + if (_vmtx.var_table.get_length ()) + vert_aw += (int) roundf (_vmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords, + vvar_store_cache)); + + int tsb = extents.y_bearing; + if (!has_bounds_info) + { + if (!_vmtx.get_leading_bearing_without_var_unscaled (old_gid, &tsb)) + continue; + } + plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb)); + plan->bounds_height_map.set (new_gid, extents.height); + } + } + hb_font_destroy (font); + if (hvar_store_cache) + _hmtx.var_table->get_var_store ().destroy_cache (hvar_store_cache); + if (vvar_store_cache) + _vmtx.var_table->get_var_store ().destroy_cache (vvar_store_cache); +} #endif hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, @@ -942,6 +1026,10 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, if (unlikely (in_error ())) return; +#ifndef HB_NO_VAR + _update_instance_metrics_map_from_cff2 (this); +#endif + if (attach_accelerator_data) { hb_multimap_t gid_to_unicodes; diff --git a/test/subset/data/Makefile.am b/test/subset/data/Makefile.am index fe17d701f..db2bf7f44 100644 --- a/test/subset/data/Makefile.am +++ b/test/subset/data/Makefile.am @@ -70,6 +70,7 @@ EXTRA_DIST += \ expected/apply_cvar_delta \ expected/collect_name_ids \ expected/instantiate_colrv1 \ + expected/instantiate_cff2_update_metrics \ fonts \ profiles \ $(NULL) diff --git a/test/subset/data/Makefile.sources b/test/subset/data/Makefile.sources index 607955d67..d0662d928 100644 --- a/test/subset/data/Makefile.sources +++ b/test/subset/data/Makefile.sources @@ -61,6 +61,7 @@ TESTS = \ tests/apply_cvar_delta.tests \ tests/collect_name_ids.tests \ tests/instantiate_colrv1.tests \ + tests/instantiate_cff2_update_metrics.tests \ $(NULL) # TODO: re-enable once colrv1 subsetting is stabilized. diff --git a/test/subset/data/expected/instantiate_cff2/AdobeVFPrototype.default.retain-all-codepoint.wght=650,CNTR=50.otf b/test/subset/data/expected/instantiate_cff2/AdobeVFPrototype.default.retain-all-codepoint.wght=650,CNTR=50.otf index c76dabb5924f2c1047ce61b911eee1809da1f764..a870015b323c9dad8eea2d3475bf5fd0741d9459 100644 GIT binary patch delta 1156 zcmZvcOGs2<6vzMH`3B1=AL!`J_)49z867Fh3NbB($p=Oam=cF z;e>5$CG>z?NkOy;v%qB(EeeG;Zi2QIsnzZOT^|h5z>hQc+;hG;_y0e4rsid8UXqsr zkrTs!@&Pyyj}H!P8PPBK{Tm6!FC<2?i%SmQy?3_7HEYN0m}?x0cTzvUoQzUwKi=FN z?aylX4z0hKf=~C4&#lE*N7$R@8rNgbqUwpuTI3HNMNB|V(l&ETCvp&q&tP5Ci$uvIRA`N$vd9hlxy&%vhM*pWR~Aqtv#jrD&cp|dc?ij64!VF+ znS@)vGrD5vR9=HTP54J)m!ALPAca{ zAEQyA3X9g7{FEr@NR`LKa_wbPBHKd*LH;QGX{}1{ar#5yND^hT*Fm_m!(}HsB z+OWddkV-N4z+4+UQZaU%655r93h?S z7)x4Y09jnDux>&aA5lbd3~HKh!L$=|B$HB!{v+H7 RVlN~*v8?>h{-l>r{sjQf!*>7x delta 1156 zcmZvcK}b|l6o&tM@1$swIZ4b|4d&Q5qcbvDNmN)kI!1_&;DCr_TE-xRBnGvl;uUk-0gp0W&evpdPxcMIPuwLY+fU7r?8QaL9Bau0LQ8o+GH* zxYkDh3lwWN_Ng$osapEO^fy5>K19xt@CF{*011+s4WHyCB$s;}lYPXhd#Ja}DfsnW zE({@}hY{6tv|S`d9wBOWBccY$ReN4f(w9WUjI-FUyy0Y4^-(Rs8)YTFAHxptP6Gp~`hit!KNSI-btG34nu<9-8rl@uUf+3fNg_*4giSVa%56i|aj zYoq;{_LZq+9<*eyI6(`%Q5pfg%*1Z&Ro|Q>kJJ9Q^rg|HPP0IfWe^8RHGO0HC=$Az z1xU-&=%>G4jX3#UN*g1`Nh{kQ)0VV;3(OS#B8Nzk1vkscF^CF27ddimN+B|2<7PMI zUF66{aBO@=iIj5jk`P z2ib-N*-VDY(NzYnkB4!PM9cq!Bib$5KiSU1q>eO^8Zu7KlM6&@R0TEmWE@BwUXXS0y~81YS(oE&Ob@t9LByJ*W2*0;ZI=*vU4I!eer2 zqnXdqiKWgug0Ly#hL`N8nuA5;6U)$mq)u^2WuULY@BByPqnzWX8*cwm-kJ5hvdMq3 CVc%K+ diff --git a/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.default.retain-all-codepoint.wght=800.otf b/test/subset/data/expected/instantiate_cff2_update_metrics/Cantarell-VF-ABC.default.retain-all-codepoint.wght=800.otf new file mode 100644 index 0000000000000000000000000000000000000000..def60cff6c7b881a754d7cb783a64a8a7d5dc16f GIT binary patch literal 1508 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