From a0f810effcb497e77be25328a251e608b5863999 Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Fri, 28 Jul 2023 15:04:47 -0700 Subject: [PATCH 01/15] [instancer] add struct glyph_variations_t for gvar -Add compile_peak_coords () in tuple_delta_t -Add compile_shared_tuples () for glyph_variations_t --- src/hb-ot-var-common.hh | 33 ++++++++++++ src/hb-ot-var-gvar-table.hh | 105 ++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh index 9e813f6d2..caddfe416 100644 --- a/src/hb-ot-var-common.hh +++ b/src/hb-ot-var-common.hh @@ -449,6 +449,9 @@ struct tuple_delta_t hb_vector_t compiled_tuple_header; hb_vector_t compiled_deltas; + /* compiled peak coords, empty for non-gvar tuples */ + hb_vector_t compiled_peak_coords; + tuple_delta_t () = default; tuple_delta_t (const tuple_delta_t& o) = default; @@ -552,6 +555,36 @@ struct tuple_delta_t return out; } + bool compile_peak_coords (const hb_map_t& axes_index_map, + const hb_map_t& axes_old_index_tag_map) + { + unsigned axis_count = axes_index_map.get_population (); + if (unlikely (!compiled_peak_coords.alloc (axis_count * F2DOT14::static_size))) + return false; + + unsigned orig_axis_count = axes_old_index_tag_map.get_population (); + for (unsigned i = 0; i < orig_axis_count; i++) + { + if (!axes_index_map.has (i)) + continue; + + hb_tag_t axis_tag = axes_old_index_tag_map.get (i); + Triple *coords; + F2DOT14 peak_coord; + if (axis_tuples.has (axis_tag, &coords)) + peak_coord.set_float (coords->middle); + else + peak_coord.set_int (0); + + /* push F2DOT14 value into char vector */ + int16_t val = peak_coord.to_int (); + compiled_peak_coords.push (static_cast (val >> 8)); + compiled_peak_coords.push (static_cast (val & 0xFF)); + } + + return !compiled_peak_coords.in_error (); + } + /* deltas should be compiled already before we compile tuple * variation header cause we need to fill in the size of the * serialized data for this tuple variation */ diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh index b5099ac07..66da68295 100644 --- a/src/hb-ot-var-gvar-table.hh +++ b/src/hb-ot-var-gvar-table.hh @@ -76,6 +76,111 @@ struct contour_point_vector_t : hb_vector_t struct GlyphVariationData : TupleVariationData {}; +struct glyph_variations_t +{ + using tuple_variations_t = TupleVariationData::tuple_variations_t; + hb_vector_t glyph_variations; + + hb_vector_t compiled_shared_tuples; + private: + unsigned shared_tuples_count = 0; + + /* shared coords-> index map after instantiation */ + hb_hashmap_t*, unsigned> shared_tuples_idx_map; + + public: + unsigned compiled_shared_tuples_count () const + { return shared_tuples_count; } + + bool compile_shared_tuples (const hb_map_t& axes_index_map, + const hb_map_t& axes_old_index_tag_map) + { + /* key is pointer to compiled_peak_coords inside each tuple, hashing + * function will always deref pointers first */ + hb_hashmap_t*, unsigned> coords_count_map; + + /* count the num of shared coords */ + for (tuple_variations_t& vars: glyph_variations) + { + for (tuple_delta_t& var : vars.tuple_vars) + { + if (!var.compile_peak_coords (axes_index_map, axes_old_index_tag_map)) + return false; + unsigned* count; + if (coords_count_map.has (&(var.compiled_peak_coords), &count)) + coords_count_map.set (&(var.compiled_peak_coords), *count + 1); + else + coords_count_map.set (&(var.compiled_peak_coords), 1); + } + } + + if (!coords_count_map || coords_count_map.in_error ()) + return false; + + /* add only those coords that are used more than once into the vector and sort */ + hb_vector_t*> shared_coords; + if (unlikely (!shared_coords.alloc (coords_count_map.get_population ()))) + return false; + + for (const auto _ : coords_count_map.iter ()) + { + if (_.second == 1) continue; + shared_coords.push (_.first); + } + + /* no shared tuples: no coords are used more than once */ + if (!shared_coords) return true; + /* sorting based on the coords frequency first (high to low), then compare + * the coords bytes */ + hb_qsort (shared_coords.arrayZ, shared_coords.length, sizeof (hb_vector_t*), _cmp_coords, (void *) (&coords_count_map)); + + /* build shared_coords->idx map and shared tuples byte array */ + + shared_tuples_count = hb_min (0xFFFu + 1, shared_coords.length); + unsigned len = shared_tuples_count * (shared_coords[0]->length); + if (unlikely (!compiled_shared_tuples.alloc (len))) + return false; + + for (unsigned i = 0; i < shared_tuples_count; i++) + { + shared_tuples_idx_map.set (shared_coords[i], i); + /* add a concat() in hb_vector_t? */ + for (char c : shared_coords[i]->iter ()) + compiled_shared_tuples.push (c); + } + + return true; + } + + static int _cmp_coords (const void *pa, const void *pb, void *arg) + { + const hb_hashmap_t*, unsigned>* coords_count_map = + reinterpret_cast*, unsigned>*> (arg); + + /* shared_coords is hb_vector_t*> so casting pa/pb + * to be a pointer to a pointer */ + const hb_vector_t** a = reinterpret_cast**> (const_cast(pa)); + const hb_vector_t** b = reinterpret_cast**> (const_cast(pb)); + + bool has_a = coords_count_map->has (*a); + bool has_b = coords_count_map->has (*b); + + if (has_a && has_b) + { + unsigned a_num = coords_count_map->get (*a); + unsigned b_num = coords_count_map->get (*b); + + if (a_num != b_num) + return b_num - a_num; + + return (*b)->as_array().cmp ((*a)->as_array ()); + } + else if (has_a) return -1; + else if (has_b) return 1; + else return 0; + } +}; + struct gvar { static constexpr hb_tag_t tableTag = HB_OT_TAG_gvar; From eb116e163e0bb8476cdd53a07630389d25ec3b97 Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Fri, 28 Jul 2023 15:27:07 -0700 Subject: [PATCH 02/15] [instancer] Add new_gid->contour_points vector map in subset plan - Add an API in Glyph to export original contour_points vector, which is needed by infer_deltas when merging tuple variations with the same tent --- src/OT/glyf/Glyph.hh | 57 +++++++++++++++++++++++++++++++ src/hb-ot-var-gvar-table.hh | 34 ------------------ src/hb-subset-plan-member-list.hh | 3 ++ src/hb-subset-plan.cc | 32 +++++++++++++++++ src/hb-subset-plan.hh | 34 ++++++++++++++++++ 5 files changed, 126 insertions(+), 34 deletions(-) diff --git a/src/OT/glyf/Glyph.hh b/src/OT/glyf/Glyph.hh index 2611c1e21..2b2184fea 100644 --- a/src/OT/glyf/Glyph.hh +++ b/src/OT/glyf/Glyph.hh @@ -103,6 +103,63 @@ struct Glyph } } + bool get_all_points_without_var (const hb_face_t *face, + contour_point_vector_t &points /* OUT */) const + { + switch (type) { + case SIMPLE: + if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points))) + return false; + break; + case COMPOSITE: + { + for (auto &item : get_composite_iterator ()) + if (unlikely (!item.get_points (points))) return false; + break; + } +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: + { + for (auto &item : get_var_composite_iterator ()) + if (unlikely (!item.get_points (points))) return false; + break; + } +#endif + case EMPTY: + break; + } + + /* Init phantom points */ + if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; + hb_array_t phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); + { + int lsb = 0; + int h_delta = face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ? + (int) header->xMin - lsb : 0; + HB_UNUSED int tsb = 0; + int v_orig = (int) header->yMax + +#ifndef HB_NO_VERTICAL + ((void) face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb) +#else + 0 +#endif + ; + unsigned h_adv = face->table.hmtx->get_advance_without_var_unscaled (gid); + unsigned v_adv = +#ifndef HB_NO_VERTICAL + face->table.vmtx->get_advance_without_var_unscaled (gid) +#else + - face->get_upem () +#endif + ; + phantoms[PHANTOM_LEFT].x = h_delta; + phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta; + phantoms[PHANTOM_TOP].y = v_orig; + phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; + } + return true; + } + void update_mtx (const hb_subset_plan_t *plan, int xMin, int xMax, int yMin, int yMax, diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh index 66da68295..180d9058c 100644 --- a/src/hb-ot-var-gvar-table.hh +++ b/src/hb-ot-var-gvar-table.hh @@ -39,40 +39,6 @@ namespace OT { -struct contour_point_t -{ - void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false) - { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; } - - void transform (const float (&matrix)[4]) - { - float x_ = x * matrix[0] + y * matrix[2]; - y = x * matrix[1] + y * matrix[3]; - x = x_; - } - HB_ALWAYS_INLINE - void translate (const contour_point_t &p) { x += p.x; y += p.y; } - - - float x; - float y; - uint8_t flag; - bool is_end_point; -}; - -struct contour_point_vector_t : hb_vector_t -{ - void extend (const hb_array_t &a) - { - unsigned int old_len = length; - if (unlikely (!resize (old_len + a.length, false))) - return; - auto arrayZ = this->arrayZ + old_len; - unsigned count = a.length; - hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0])); - } -}; - struct GlyphVariationData : TupleVariationData {}; diff --git a/src/hb-subset-plan-member-list.hh b/src/hb-subset-plan-member-list.hh index 8e61055f4..01d8b0f8b 100644 --- a/src/hb-subset-plan-member-list.hh +++ b/src/hb-subset-plan-member-list.hh @@ -123,6 +123,9 @@ HB_SUBSET_PLAN_MEMBER (mutable hb_vector_t, bounds_width_vec) //boundsHeight map: new gid->boundsHeight, boundsHeight=yMax - yMin HB_SUBSET_PLAN_MEMBER (mutable hb_vector_t, bounds_height_vec) +//map: new_gid -> contour points vector +HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(), new_gid_contour_points_map) + #ifdef HB_EXPERIMENTAL_API // name table overrides map: hb_ot_name_record_ids_t-> name string new value or // None to indicate should remove diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index a2090b727..c293ba3ba 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -1045,6 +1045,36 @@ _update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan) if (vvar_store_cache) _vmtx.var_table->get_var_store ().destroy_cache (vvar_store_cache); } + +static bool +_get_instance_glyphs_contour_points (hb_subset_plan_t *plan) +{ + /* contour_points vector only needed for updating gvar table (infer delta) + * during partial instancing */ + if (plan->user_axes_location.is_empty () || plan->all_axes_pinned) + return true; + + OT::glyf_accelerator_t glyf (plan->source); + + for (auto &_ : plan->new_to_old_gid_list) + { + hb_codepoint_t new_gid = _.first; + contour_point_vector_t all_points; + if (new_gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) + { + if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points))) + return false; + continue; + } + + hb_codepoint_t old_gid = _.second; + if (unlikely (!glyf.glyph_for_gid (old_gid).get_all_points_without_var (plan->source, all_points))) + return false; + if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points))) + return false; + } + return true; +} #endif hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, @@ -1148,6 +1178,8 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, #ifndef HB_NO_VAR _update_instance_metrics_map_from_cff2 (this); + if (!check_success (_get_instance_glyphs_contour_points (this))) + return; #endif if (attach_accelerator_data) diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index d156de05d..a05d1d1a6 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -67,6 +67,40 @@ struct head_maxp_info_t typedef struct head_maxp_info_t head_maxp_info_t; +struct contour_point_t +{ + void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false) + { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; } + + void transform (const float (&matrix)[4]) + { + float x_ = x * matrix[0] + y * matrix[2]; + y = x * matrix[1] + y * matrix[3]; + x = x_; + } + HB_ALWAYS_INLINE + void translate (const contour_point_t &p) { x += p.x; y += p.y; } + + + float x; + float y; + uint8_t flag; + bool is_end_point; +}; + +struct contour_point_vector_t : hb_vector_t +{ + void extend (const hb_array_t &a) + { + unsigned int old_len = length; + if (unlikely (!resize (old_len + a.length, false))) + return; + auto arrayZ = this->arrayZ + old_len; + unsigned count = a.length; + hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0])); + } +}; + namespace OT { struct cff1_subset_accelerator_t; struct cff2_subset_accelerator_t; From 198612c1c83d3b19b953a2fcc73406287104e5a2 Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Fri, 28 Jul 2023 15:41:54 -0700 Subject: [PATCH 03/15] [instancer] add decompile_glyph_variations () for gvar --- src/hb-ot-var-common.hh | 1 + src/hb-ot-var-gvar-table.hh | 81 +++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh index caddfe416..2c8f21309 100644 --- a/src/hb-ot-var-common.hh +++ b/src/hb-ot-var-common.hh @@ -1488,6 +1488,7 @@ struct TupleVariationData bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); } unsigned int get_count () const { return (*this) & CountMask; } TupleVarCount& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } + explicit operator bool () const { return get_count (); } protected: enum Flags diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh index 180d9058c..0cb7939ba 100644 --- a/src/hb-ot-var-gvar-table.hh +++ b/src/hb-ot-var-gvar-table.hh @@ -58,6 +58,50 @@ struct glyph_variations_t unsigned compiled_shared_tuples_count () const { return shared_tuples_count; } + bool create_from_glyphs_var_data (unsigned axis_count, + const hb_array_t shared_tuples, + const hb_subset_plan_t *plan, + const hb_hashmap_t& new_gid_var_data_map) + { + if (unlikely (!glyph_variations.alloc (plan->new_to_old_gid_list.length, true))) + return false; + + auto it = hb_iter (plan->new_to_old_gid_list); + for (auto &_ : it) + { + hb_codepoint_t new_gid = _.first; + contour_point_vector_t *all_contour_points; + if (!new_gid_var_data_map.has (new_gid) || + !plan->new_gid_contour_points_map.has (new_gid, &all_contour_points)) + return false; + hb_bytes_t var_data = new_gid_var_data_map.get (new_gid); + + const GlyphVariationData* p = reinterpret_cast (var_data.arrayZ); + hb_vector_t shared_indices; + GlyphVariationData::tuple_iterator_t iterator; + tuple_variations_t tuple_vars; + + /* in case variation data is empty, push an empty struct into the vector, + * keep the vector in sync with the new_to_old_gid_list */ + if (!var_data || ! p->has_data () || !all_contour_points->length || + !GlyphVariationData::get_tuple_iterator (var_data, axis_count, + var_data.arrayZ, + shared_indices, &iterator)) + { + glyph_variations.push (std::move (tuple_vars)); + continue; + } + + if (!p->decompile_tuple_variations (all_contour_points->length, true /* is_gvar */, + iterator, &(plan->axes_old_index_tag_map), + shared_indices, shared_tuples, + tuple_vars /* OUT */)) + return false; + glyph_variations.push (std::move (tuple_vars)); + } + return !glyph_variations.in_error () && glyph_variations.length == plan->new_to_old_gid_list.length; + } + bool compile_shared_tuples (const hb_map_t& axes_index_map, const hb_map_t& axes_old_index_tag_map) { @@ -165,6 +209,32 @@ struct gvar bool sanitize (hb_sanitize_context_t *c) const { return sanitize_shallow (c); } + bool decompile_glyph_variations (const hb_subset_plan_t *plan, + glyph_variations_t& glyph_vars /* OUT */) const + { + + hb_hashmap_t new_gid_var_data_map; + auto it = hb_iter (plan->new_to_old_gid_list); + if (it->first == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) + { + new_gid_var_data_map.set (0, hb_bytes_t ()); + it++; + } + + for (auto &_ : it) + { + hb_codepoint_t new_gid = _.first; + hb_codepoint_t old_gid = _.second; + hb_bytes_t var_data_bytes = get_glyph_var_data_bytes (old_gid); + new_gid_var_data_map.set (new_gid, var_data_bytes); + } + + if (new_gid_var_data_map.in_error ()) return false; + + hb_array_t shared_tuples = (this+sharedTuples).as_array ((unsigned) sharedTupleCount * (unsigned) axisCount); + return glyph_vars.create_from_glyphs_var_data (axisCount, shared_tuples, plan, new_gid_var_data_map); + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -282,6 +352,17 @@ struct gvar return likely (var_data.length >= GlyphVariationData::min_size) ? var_data : hb_bytes_t (); } + const hb_bytes_t get_glyph_var_data_bytes (hb_codepoint_t gid) const + { + unsigned start_offset = get_offset (glyphCountX, gid); + unsigned end_offset = get_offset (glyphCountX, gid+1); + if (unlikely (end_offset < start_offset)) return hb_bytes_t (); + unsigned length = end_offset - start_offset; + const char *p = (const char*) this + (unsigned) dataZ + start_offset; + hb_bytes_t var_data{p, length}; + return likely (length >= GlyphVariationData::min_size) ? var_data : hb_bytes_t (); + } + bool is_long_offset () const { return flags & 1; } unsigned get_offset (unsigned glyph_count, unsigned i) const From 3c86b096a9bf310a00086a7ed566cf1436da786c Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Fri, 28 Jul 2023 16:18:51 -0700 Subject: [PATCH 04/15] [instancer] Add instantiate () and compile_bytes() for gvar -Also add support for using shared_points and shared_tuples --- src/hb-ot-var-common.hh | 85 +++++++++++++++++++++++++++++++------ src/hb-ot-var-cvar-table.hh | 7 ++- src/hb-ot-var-gvar-table.hh | 29 +++++++++++++ src/test-tuple-varstore.cc | 2 +- 4 files changed, 106 insertions(+), 17 deletions(-) diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh index 2c8f21309..76d9db82e 100644 --- a/src/hb-ot-var-common.hh +++ b/src/hb-ot-var-common.hh @@ -588,10 +588,10 @@ struct tuple_delta_t /* deltas should be compiled already before we compile tuple * variation header cause we need to fill in the size of the * serialized data for this tuple variation */ - //TODO(qxliu):add option to use sharedTuples in gvar bool compile_tuple_var_header (const hb_map_t& axes_index_map, unsigned points_data_length, - const hb_map_t& axes_old_index_tag_map) + const hb_map_t& axes_old_index_tag_map, + const hb_hashmap_t*, unsigned>* shared_tuples_idx_map) { if (!compiled_deltas) return false; @@ -607,14 +607,25 @@ struct tuple_delta_t hb_array_t coords (p, end - p); /* encode peak coords */ - unsigned peak_count = encode_peak_coords(coords, flag, axes_index_map, axes_old_index_tag_map); - if (!peak_count) return false; + unsigned peak_count = 0; + unsigned *shared_tuple_idx; + if (shared_tuples_idx_map && + shared_tuples_idx_map->has (&compiled_peak_coords, &shared_tuple_idx)) + { + flag = *shared_tuple_idx; + } + else + { + peak_count = encode_peak_coords(coords, flag, axes_index_map, axes_old_index_tag_map); + if (!peak_count) return false; + } /* encode interim coords, it's optional so returned num could be 0 */ unsigned interim_count = encode_interm_coords (coords.sub_array (peak_count), flag, axes_index_map, axes_old_index_tag_map); - //TODO(qxliu): add option to use shared_points in gvar - flag |= TupleVariationHeader::TuppleIndex::PrivatePointNumbers; + /* pointdata length = 0 implies "use shared points" */ + if (points_data_length) + flag |= TupleVariationHeader::TuppleIndex::PrivatePointNumbers; unsigned serialized_data_size = points_data_length + compiled_deltas.length; TupleVariationHeader *o = reinterpret_cast (compiled_tuple_header.begin ()); @@ -943,6 +954,16 @@ struct TupleVariationData /* referenced point set-> count map, used in finding shared points */ hb_hashmap_t*, unsigned> point_set_count_map; + /* empty for non-gvar tuples. + * shared_points_bytes is just a copy of some value in the point_data_map, + * which will be freed during map destruction. Save it for serialization, so + * no need to do find_shared_points () again */ + hb_bytes_t shared_points_bytes; + + /* total compiled byte size as TupleVariationData format, initialized to its + * min_size: 4 */ + unsigned compiled_byte_size = 4; + public: ~tuple_variations_t () { fini (); } void fini () @@ -955,7 +976,15 @@ struct TupleVariationData } unsigned get_var_count () const - { return tuple_vars.length; } + { + unsigned count = tuple_vars.length; + if (shared_points_bytes.length) + count |= TupleVarCount::SharedPointNumbers; + return count; + } + + unsigned get_compiled_byte_size () const + { return compiled_byte_size; } bool create_from_tuple_var_data (tuple_iterator_t iterator, unsigned tuple_var_count, @@ -1220,19 +1249,30 @@ struct TupleVariationData return res; } - void instantiate (const hb_hashmap_t& normalized_axes_location, - const hb_hashmap_t& axes_triple_distances) + bool instantiate (const hb_hashmap_t& normalized_axes_location, + const hb_hashmap_t& axes_triple_distances, + contour_point_vector_t* contour_points = nullptr) { + if (!tuple_vars) return true; change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances); merge_tuple_variations (); + return !tuple_vars.in_error (); } bool compile_bytes (const hb_map_t& axes_index_map, - const hb_map_t& axes_old_index_tag_map) + const hb_map_t& axes_old_index_tag_map, + bool use_shared_points, + const hb_hashmap_t*, unsigned>* shared_tuples_idx_map = nullptr) { // compile points set and store data in hashmap if (!compile_all_point_sets ()) return false; + + if (use_shared_points) + { + shared_points_bytes = find_shared_points (); + compiled_byte_size += shared_points_bytes.length; + } // compile delta and tuple var header for each tuple variation for (auto& tuple: tuple_vars) { @@ -1244,8 +1284,11 @@ struct TupleVariationData if (!tuple.compile_deltas ()) return false; - if (!tuple.compile_tuple_var_header (axes_index_map, points_data->length, axes_old_index_tag_map)) + unsigned points_data_length = (*points_data != shared_points_bytes) ? points_data->length : 0; + if (!tuple.compile_tuple_var_header (axes_index_map, points_data_length, axes_old_index_tag_map, + shared_tuples_idx_map)) return false; + compiled_byte_size += tuple.compiled_tuple_header.length + points_data_length + tuple.compiled_deltas.length; } return true; } @@ -1262,9 +1305,12 @@ struct TupleVariationData return_trace (true); } - bool serialize_var_data (hb_serialize_context_t *c) const + bool serialize_var_data (hb_serialize_context_t *c, bool is_gvar) const { TRACE_SERIALIZE (this); + if (is_gvar) + shared_points_bytes.copy (c); + for (const auto& tuple: tuple_vars) { const hb_vector_t* points_set = &(tuple.indices); @@ -1272,10 +1318,20 @@ struct TupleVariationData if (!point_data_map.has (points_set, &point_data)) return_trace (false); - point_data->copy (c); + if (!is_gvar || *point_data != shared_points_bytes) + point_data->copy (c); + tuple.compiled_deltas.as_array ().copy (c); if (c->in_error ()) return_trace (false); } + + /* padding for gvar */ + if (is_gvar && (compiled_byte_size % 2)) + { + HBUINT8 pad; + pad = 0; + if (!c->embed (pad)) return_trace (false); + } return_trace (true); } }; @@ -1479,12 +1535,13 @@ struct TupleVariationData if (!is_gvar) data_offset += 4; if (!c->check_assign (out->data, data_offset, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); - return tuple_variations.serialize_var_data (c); + return tuple_variations.serialize_var_data (c, is_gvar); } protected: struct TupleVarCount : HBUINT16 { + friend struct tuple_variations_t; bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); } unsigned int get_count () const { return (*this) & CountMask; } TupleVarCount& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } diff --git a/src/hb-ot-var-cvar-table.hh b/src/hb-ot-var-cvar-table.hh index fee39eff3..99c435e34 100644 --- a/src/hb-ot-var-cvar-table.hh +++ b/src/hb-ot-var-cvar-table.hh @@ -168,8 +168,11 @@ struct cvar tuple_variations)) return_trace (false); - tuple_variations.instantiate (c->plan->axes_location, c->plan->axes_triple_distances); - if (!tuple_variations.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map)) + if (!tuple_variations.instantiate (c->plan->axes_location, c->plan->axes_triple_distances)) + return_trace (false); + + if (!tuple_variations.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map, + false /* do not use shared points */)) return_trace (false); return_trace (serialize (c->serializer, tuple_variations)); diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh index 0cb7939ba..5e05ed0af 100644 --- a/src/hb-ot-var-gvar-table.hh +++ b/src/hb-ot-var-gvar-table.hh @@ -102,6 +102,35 @@ struct glyph_variations_t return !glyph_variations.in_error () && glyph_variations.length == plan->new_to_old_gid_list.length; } + bool instantiate (const hb_subset_plan_t *plan) + { + unsigned count = plan->new_to_old_gid_list.length; + for (unsigned i = 0; i < count; i++) + { + hb_codepoint_t new_gid = plan->new_to_old_gid_list[i].first; + contour_point_vector_t *all_points; + if (!plan->new_gid_contour_points_map.has (new_gid, &all_points)) + return false; + if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, all_points)) + return false; + } + return true; + } + + bool compile_bytes (const hb_map_t& axes_index_map, + const hb_map_t& axes_old_index_tag_map) + { + if (!compile_shared_tuples (axes_index_map, axes_old_index_tag_map)) + return false; + for (tuple_variations_t& vars: glyph_variations) + if (!vars.compile_bytes (axes_index_map, axes_old_index_tag_map, + true, /* use shared points*/ + &shared_tuples_idx_map)) + return false; + + return true; + } + bool compile_shared_tuples (const hb_map_t& axes_index_map, const hb_map_t& axes_old_index_tag_map) { diff --git a/src/test-tuple-varstore.cc b/src/test-tuple-varstore.cc index 32d2ea457..c9086b93c 100644 --- a/src/test-tuple-varstore.cc +++ b/src/test-tuple-varstore.cc @@ -115,7 +115,7 @@ test_decompile_cvar () hb_map_t axes_index_map; axes_index_map.set (0, 0); - bool res = tuple_variations.compile_bytes (axes_index_map, axis_idx_tag_map); + bool res = tuple_variations.compile_bytes (axes_index_map, axis_idx_tag_map, false); assert (res); assert (tuple_variations.tuple_vars[0].compiled_tuple_header.length == 6); const char tuple_var_header_1[] = "\x0\x51\xa0\x0\xc0\x0"; From 746b112faf6adcd4a9d7325b067c4ba46a973a95 Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Mon, 7 Aug 2023 09:26:42 -0700 Subject: [PATCH 05/15] [instancer] add serialize () for gvar --- src/hb-ot-var-common.hh | 6 +- src/hb-ot-var-cvar-table.hh | 1 + src/hb-ot-var-gvar-table.hh | 114 ++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh index 76d9db82e..ae1f3785b 100644 --- a/src/hb-ot-var-common.hh +++ b/src/hb-ot-var-common.hh @@ -975,6 +975,7 @@ struct TupleVariationData tuple_vars.fini (); } + explicit operator bool () const { return bool (tuple_vars); } unsigned get_var_count () const { unsigned count = tuple_vars.length; @@ -1517,9 +1518,12 @@ struct TupleVariationData bool serialize (hb_serialize_context_t *c, bool is_gvar, - tuple_variations_t& tuple_variations) const + const tuple_variations_t& tuple_variations) const { TRACE_SERIALIZE (this); + /* empty tuple variations, just return and skip serialization. */ + if (!tuple_variations) return_trace (true); + auto *out = c->start_embed (this); if (unlikely (!c->extend_min (out))) return_trace (false); diff --git a/src/hb-ot-var-cvar-table.hh b/src/hb-ot-var-cvar-table.hh index 99c435e34..adb81769b 100644 --- a/src/hb-ot-var-cvar-table.hh +++ b/src/hb-ot-var-cvar-table.hh @@ -131,6 +131,7 @@ struct cvar TupleVariationData::tuple_variations_t& tuple_variations) const { TRACE_SERIALIZE (this); + if (!tuple_variations) return_trace (false); if (unlikely (!c->embed (version))) return_trace (false); return_trace (tupleVariationData.serialize (c, false, tuple_variations)); diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh index 5e05ed0af..5b9e64243 100644 --- a/src/hb-ot-var-gvar-table.hh +++ b/src/hb-ot-var-gvar-table.hh @@ -58,6 +58,15 @@ struct glyph_variations_t unsigned compiled_shared_tuples_count () const { return shared_tuples_count; } + unsigned compiled_byte_size () const + { + unsigned byte_size = 0; + for (const auto& _ : glyph_variations) + byte_size += _.get_compiled_byte_size (); + + return byte_size; + } + bool create_from_glyphs_var_data (unsigned axis_count, const hb_array_t shared_tuples, const hb_subset_plan_t *plan, @@ -218,6 +227,66 @@ struct glyph_variations_t else if (has_b) return 1; else return 0; } + + template + bool serialize_glyph_var_data (hb_serialize_context_t *c, + Iterator it, + bool long_offset, + unsigned num_glyphs, + char* glyph_var_data_offsets /* OUT: glyph var data offsets array */) const + { + TRACE_SERIALIZE (this); + + if (long_offset) + { + ((HBUINT32 *) glyph_var_data_offsets)[0] = 0; + glyph_var_data_offsets += 4; + } + else + { + ((HBUINT16 *) glyph_var_data_offsets)[0] = 0; + glyph_var_data_offsets += 2; + } + unsigned glyph_offset = 0; + hb_codepoint_t last_gid = 0; + unsigned idx = 0; + + TupleVariationData* cur_glyph = c->start_embed (); + if (!cur_glyph) return_trace (false); + for (auto &_ : it) + { + hb_codepoint_t gid = _.first; + if (long_offset) + for (; last_gid < gid; last_gid++) + ((HBUINT32 *) glyph_var_data_offsets)[last_gid] = glyph_offset; + else + for (; last_gid < gid; last_gid++) + ((HBUINT16 *) glyph_var_data_offsets)[last_gid] = glyph_offset / 2; + + if (idx >= glyph_variations.length) return_trace (false); + if (!cur_glyph->serialize (c, true, glyph_variations[idx])) return_trace (false); + TupleVariationData* next_glyph = c->start_embed (); + glyph_offset += (char *) next_glyph - (char *) cur_glyph; + + if (long_offset) + ((HBUINT32 *) glyph_var_data_offsets)[gid] = glyph_offset; + else + ((HBUINT16 *) glyph_var_data_offsets)[gid] = glyph_offset / 2; + + last_gid++; + idx++; + cur_glyph = next_glyph; + } + + if (long_offset) + for (; last_gid < num_glyphs; last_gid++) + ((HBUINT32 *) glyph_var_data_offsets)[last_gid] = glyph_offset; + else + for (; last_gid < num_glyphs; last_gid++) + ((HBUINT16 *) glyph_var_data_offsets)[last_gid] = glyph_offset / 2; + return_trace (true); + } }; struct gvar @@ -264,6 +333,51 @@ struct gvar return glyph_vars.create_from_glyphs_var_data (axisCount, shared_tuples, plan, new_gid_var_data_map); } + template + bool serialize (hb_serialize_context_t *c, + const glyph_variations_t& glyph_vars, + Iterator it, + unsigned axis_count, + unsigned num_glyphs) const + { + TRACE_SERIALIZE (this); + gvar *out = c->allocate_min (); + if (unlikely (!out)) return_trace (false); + + out->version.major = 1; + out->version.minor = 0; + out->axisCount = axis_count; + out->glyphCountX = hb_min (0xFFFFu, num_glyphs); + + unsigned glyph_var_data_size = glyph_vars.compiled_byte_size (); + bool long_offset = glyph_var_data_size & ~0xFFFFu; + out->flags = long_offset ? 1 : 0; + + HBUINT8 *glyph_var_data_offsets = c->allocate_size ((long_offset ? 4 : 2) * (num_glyphs + 1), false); + if (!glyph_var_data_offsets) return_trace (false); + + /* shared tuples */ + unsigned shared_tuple_count = glyph_vars.compiled_shared_tuples_count (); + out->sharedTupleCount = shared_tuple_count; + + if (!shared_tuple_count) + out->sharedTuples = 0; + else + { + hb_array_t shared_tuples = glyph_vars.compiled_shared_tuples.as_array ().copy (c); + if (!shared_tuples.arrayZ) return_trace (false); + out->sharedTuples = shared_tuples.arrayZ - (char *) out; + } + + char *glyph_var_data = c->start_embed (); + if (!glyph_var_data) return_trace (false); + out->dataZ = glyph_var_data - (char *) out; + + return_trace (glyph_vars.serialize_glyph_var_data (c, it, long_offset, num_glyphs, + (char *) glyph_var_data_offsets)); + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); From fb44727401d36adc14615deda91574a6e7ec2cd6 Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Mon, 7 Aug 2023 09:44:41 -0700 Subject: [PATCH 06/15] [instancer] add instantiate () for gvar --- src/hb-ot-var-common.hh | 11 ++++++++--- src/hb-ot-var-gvar-table.hh | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh index ae1f3785b..e1de07901 100644 --- a/src/hb-ot-var-common.hh +++ b/src/hb-ot-var-common.hh @@ -1088,7 +1088,7 @@ struct TupleVariationData void merge_tuple_variations () { hb_vector_t new_vars; - hb_hashmap_t, unsigned> m; + hb_hashmap_t*, unsigned> m; unsigned i = 0; for (const tuple_delta_t& var : tuple_vars) { @@ -1096,14 +1096,14 @@ struct TupleVariationData if (var.axis_tuples.is_empty ()) continue; unsigned *idx; - if (m.has (var.axis_tuples, &idx)) + if (m.has (&(var.axis_tuples), &idx)) { new_vars[*idx] += var; } else { new_vars.push (var); - m.set (var.axis_tuples, i); + m.set (&(var.axis_tuples), i); i++; } } @@ -1256,6 +1256,11 @@ struct TupleVariationData { if (!tuple_vars) return true; change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances); + /* compute inferred deltas only for gvar */ + if (contour_points) + if (!calc_inferred_deltas (*contour_points)) + return false; + merge_tuple_variations (); return !tuple_vars.in_error (); } diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh index 5b9e64243..3f9e10612 100644 --- a/src/hb-ot-var-gvar-table.hh +++ b/src/hb-ot-var-gvar-table.hh @@ -378,9 +378,31 @@ struct gvar (char *) glyph_var_data_offsets)); } + bool instantiate (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + glyph_variations_t glyph_vars; + if (!decompile_glyph_variations (c->plan, glyph_vars)) + return_trace (false); + + if (!glyph_vars.instantiate (c->plan)) return_trace (false); + if (!glyph_vars.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map)) + return_trace (false); + + unsigned axis_count = c->plan->axes_index_map.get_population (); + unsigned num_glyphs = c->plan->num_output_glyphs (); + auto it = hb_iter (c->plan->new_to_old_gid_list); + return_trace (serialize (c->serializer, glyph_vars, it, axis_count, num_glyphs)); + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); + if (c->plan->all_axes_pinned) + return_trace (false); + + if (c->plan->normalized_coords) + return_trace (instantiate (c)); unsigned glyph_count = version.to_int () ? c->plan->source->get_num_glyphs () : 0; From 5a4694b6934f9e3ca3dc89cc905b4351920085b6 Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Mon, 7 Aug 2023 09:55:30 -0700 Subject: [PATCH 07/15] [instancer] add calc_inferred_deltas() for gvar --- src/hb-ot-var-common.hh | 104 +++++++++++++++++++++++++++++++++++++ src/test-tuple-varstore.cc | 3 +- 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh index e1de07901..b0b870198 100644 --- a/src/hb-ot-var-common.hh +++ b/src/hb-ot-var-common.hh @@ -914,6 +914,99 @@ struct tuple_delta_t } return encoded_len; } + + bool calc_inferred_deltas (const contour_point_vector_t& orig_points) + { + unsigned point_count = orig_points.length; + if (point_count != indices.length) + return false; + + unsigned ref_count = 0; + hb_vector_t end_points; + + for (unsigned i = 0; i < point_count; i++) + { + if (indices.arrayZ[i]) + ref_count++; + if (orig_points.arrayZ[i].is_end_point) + end_points.push (i); + } + /* all points are referened, nothing to do */ + if (ref_count == point_count) + return true; + if (unlikely (end_points.in_error ())) return false; + + hb_set_t inferred_idxes; + unsigned start_point = 0; + for (unsigned end_point : end_points) + { + /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */ + unsigned unref_count = 0; + for (unsigned i = start_point; i < end_point + 1; i++) + unref_count += indices.arrayZ[i]; + unref_count = (end_point - start_point + 1) - unref_count; + + unsigned j = start_point; + if (unref_count == 0 || unref_count > end_point - start_point) + goto no_more_gaps; + for (;;) + { + /* Locate the next gap of unreferenced points between two referenced points prev and next. + * Note that a gap may wrap around at left (start_point) and/or at right (end_point). + */ + unsigned int prev, next, i; + for (;;) + { + i = j; + j = next_index (i, start_point, end_point); + if (indices.arrayZ[i] && !indices.arrayZ[j]) break; + } + prev = j = i; + for (;;) + { + i = j; + j = next_index (i, start_point, end_point); + if (!indices.arrayZ[i] && indices.arrayZ[j]) break; + } + next = j; + /* Infer deltas for all unref points in the gap between prev and next */ + i = prev; + for (;;) + { + i = next_index (i, start_point, end_point); + if (i == next) break; + deltas_x.arrayZ[i] = infer_delta (orig_points.arrayZ[i].x, orig_points.arrayZ[prev].x, orig_points.arrayZ[next].x, + deltas_x.arrayZ[prev], deltas_x.arrayZ[next]); + deltas_y.arrayZ[i] = infer_delta (orig_points.arrayZ[i].y, orig_points.arrayZ[prev].y, orig_points.arrayZ[next].y, + deltas_y.arrayZ[prev], deltas_y.arrayZ[next]); + inferred_idxes.add (i); + if (--unref_count == 0) goto no_more_gaps; + } + } + no_more_gaps: + start_point = end_point + 1; + } + + for (unsigned i : inferred_idxes) + indices[i] = true; + return true; + } + + static float infer_delta (float target_val, float prev_val, float next_val, float prev_delta, float next_delta) + { + if (prev_val == next_val) + return (prev_delta == next_delta) ? prev_delta : 0.f; + else if (target_val <= hb_min (prev_val, next_val)) + return (prev_val < next_val) ? prev_delta : next_delta; + else if (target_val >= hb_max (prev_val, next_val)) + return (prev_val > next_val) ? prev_delta : next_delta; + + float r = (target_val - prev_val) / (next_val - prev_val); + return prev_delta + r * (next_delta - prev_delta); + } + + static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end) + { return (i >= end) ? start : (i + 1); } }; struct TupleVariationData @@ -1055,6 +1148,7 @@ struct TupleVariationData return true; } + private: void change_tuple_variations_axis_limits (const hb_hashmap_t& normalized_axes_location, const hb_hashmap_t& axes_triple_distances) { @@ -1250,6 +1344,16 @@ struct TupleVariationData return res; } + bool calc_inferred_deltas (contour_point_vector_t& contour_points) + { + for (tuple_delta_t& var : tuple_vars) + if (!var.calc_inferred_deltas (contour_points)) + return false; + + return true; + } + + public: bool instantiate (const hb_hashmap_t& normalized_axes_location, const hb_hashmap_t& axes_triple_distances, contour_point_vector_t* contour_points = nullptr) diff --git a/src/test-tuple-varstore.cc b/src/test-tuple-varstore.cc index c9086b93c..f1286e749 100644 --- a/src/test-tuple-varstore.cc +++ b/src/test-tuple-varstore.cc @@ -83,8 +83,7 @@ test_decompile_cvar () hb_hashmap_t axes_triple_distances; axes_triple_distances.set (axis_tag, TripleDistances (1.f, 1.f)); - tuple_variations.change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances); - tuple_variations.merge_tuple_variations (); + tuple_variations.instantiate (normalized_axes_location, axes_triple_distances); assert (tuple_variations.tuple_vars[0].indices.length == 65); assert (tuple_variations.tuple_vars[1].indices.length == 65); From 1d91622ddf082cd0777e9ae67876fe13fc7e454d Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Tue, 18 Jul 2023 09:52:40 -0700 Subject: [PATCH 08/15] [instancer] add a hashing impl for floating point type --- src/hb-algs.hh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hb-algs.hh b/src/hb-algs.hh index 6cabc7fb0..ea9705716 100644 --- a/src/hb-algs.hh +++ b/src/hb-algs.hh @@ -367,6 +367,10 @@ struct hb_enable_if (std::is_integral::value && sizeof (T) > sizeof (uint32_t))> constexpr auto impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (uint32_t) (v ^ (v >> 32)) * 2654435761u /* Knuth's multiplicative hash */) + template ::value)> constexpr auto + impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, fasthash32 (std::addressof (v), sizeof (T), 0xf437ffe6)) + template constexpr auto impl (const T& v, hb_priority<0>) const HB_RETURN (uint32_t, std::hash>{} (hb_deref (v))) From 366ffd1ef0f26cf719ee45e08f59fc9fb4b38a05 Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Mon, 7 Aug 2023 10:32:47 -0700 Subject: [PATCH 09/15] [instancer] fix move constructor for tuple_delta_t --- src/hb-ot-var-common.hh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh index b0b870198..0a92e00df 100644 --- a/src/hb-ot-var-common.hh +++ b/src/hb-ot-var-common.hh @@ -455,14 +455,20 @@ struct tuple_delta_t tuple_delta_t () = default; tuple_delta_t (const tuple_delta_t& o) = default; - tuple_delta_t (tuple_delta_t&& o) : tuple_delta_t () + friend void swap (tuple_delta_t& a, tuple_delta_t& b) { - axis_tuples = std::move (o.axis_tuples); - indices = std::move (o.indices); - deltas_x = std::move (o.deltas_x); - deltas_y = std::move (o.deltas_y); + hb_swap (a.axis_tuples, b.axis_tuples); + hb_swap (a.indices, b.indices); + hb_swap (a.deltas_x, b.deltas_x); + hb_swap (a.deltas_y, b.deltas_y); + hb_swap (a.compiled_tuple_header, b.compiled_tuple_header); + hb_swap (a.compiled_deltas, b.compiled_deltas); + hb_swap (a.compiled_peak_coords, b.compiled_peak_coords); } + tuple_delta_t (tuple_delta_t&& o) : tuple_delta_t () + { hb_swap (*this, o); } + tuple_delta_t& operator = (tuple_delta_t&& o) { hb_swap (*this, o); From 0065658e96c79f8b51c2a702908e84d9d23e0971 Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Mon, 7 Aug 2023 11:12:02 -0700 Subject: [PATCH 10/15] [instancer] enable cvar instancing code --- src/hb-subset-input.cc | 1 - src/hb-subset.cc | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc index 93f961f2d..c16160a25 100644 --- a/src/hb-subset-input.cc +++ b/src/hb-subset-input.cc @@ -75,7 +75,6 @@ hb_subset_input_t::hb_subset_input_t () HB_TAG ('V', 'D', 'M', 'X'), HB_TAG ('D', 'S', 'I', 'G'), HB_TAG ('M', 'V', 'A', 'R'), - HB_TAG ('c', 'v', 'a', 'r'), }; sets.no_subset_tables->add_array (default_no_subset_tables, ARRAY_LENGTH (default_no_subset_tables)); diff --git a/src/hb-subset.cc b/src/hb-subset.cc index 1f97dbed2..100ce87d5 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -520,6 +520,9 @@ _subset_table (hb_subset_plan_t *plan, case HB_OT_TAG_avar: if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); return _subset (plan, buf); + case HB_OT_TAG_cvar: + if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); + return _subset (plan, buf); case HB_OT_TAG_STAT: if (!plan->user_axes_location.is_empty ()) return _subset (plan, buf); else return _passthrough (plan, tag); From 32cfa37e2edd6a8dbc07c75c010fd2fc68c4346a Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Mon, 8 May 2023 13:30:39 -0700 Subject: [PATCH 11/15] [instancer] command line support for partial instancing -Also updated hb_subset_input_set_axis_range (), so user can define default value as well --- src/hb-subset-input.cc | 19 ++++++---- src/hb-subset.h | 3 +- util/hb-subset.cc | 82 +++++++++++++++++++++++++++++++++--------- 3 files changed, 81 insertions(+), 23 deletions(-) diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc index c16160a25..aade5585f 100644 --- a/src/hb-subset-input.cc +++ b/src/hb-subset-input.cc @@ -478,16 +478,21 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input, * @axis_tag: Tag of the axis * @axis_min_value: Minimum value of the axis variation range to set * @axis_max_value: Maximum value of the axis variation range to set + * @axis_def_value: Default value of the axis variation range to set, in case of + * null, it'll be determined automatically * * Restricting the range of variation on an axis in the given subset input object. - * New min/max values will be clamped if they're not within the fvar axis range. + * New min/default/max values will be clamped if they're not within the fvar axis range. + * If the new default value is null: + * If the fvar axis default value is within the new range, then new default + * value is the same as original default value. * If the fvar axis default value is not within the new range, the new default * value will be changed to the new min or max value, whichever is closer to the fvar * axis default. * - * Note: input min value can not be bigger than input max value - * Note: currently this API does not support changing axis limits yet.It'd be only - * used internally for setting axis limits in the internal data structures + * Note: input min value can not be bigger than input max value. If the input + * default value is not within the new min/max range, it'll be clamped. + * Note: currently it supports gvar and cvar tables only. * * Return value: `true` if success, `false` otherwise * @@ -498,7 +503,8 @@ hb_subset_input_set_axis_range (hb_subset_input_t *input, hb_face_t *face, hb_tag_t axis_tag, float axis_min_value, - float axis_max_value) + float axis_max_value, + float *axis_def_value /* IN, maybe NULL */) { if (axis_min_value > axis_max_value) return false; @@ -509,7 +515,8 @@ hb_subset_input_set_axis_range (hb_subset_input_t *input, float new_min_val = hb_clamp(axis_min_value, axis_info.min_value, axis_info.max_value); float new_max_val = hb_clamp(axis_max_value, axis_info.min_value, axis_info.max_value); - float new_default_val = hb_clamp(axis_info.default_value, new_min_val, new_max_val); + float new_default_val = axis_def_value ? *axis_def_value : axis_info.default_value; + new_default_val = hb_clamp(new_default_val, new_min_val, new_max_val); return input->axes_location.set (axis_tag, Triple (new_min_val, new_default_val, new_max_val)); } #endif diff --git a/src/hb-subset.h b/src/hb-subset.h index 93f1f7f10..4c356997f 100644 --- a/src/hb-subset.h +++ b/src/hb-subset.h @@ -181,7 +181,8 @@ hb_subset_input_set_axis_range (hb_subset_input_t *input, hb_face_t *face, hb_tag_t axis_tag, float axis_min_value, - float axis_max_value); + float axis_max_value, + float *axis_def_value); HB_EXTERN hb_bool_t hb_subset_input_override_name_table (hb_subset_input_t *input, diff --git a/util/hb-subset.cc b/util/hb-subset.cc index 599c7dc4e..e416db238 100644 --- a/util/hb-subset.cc +++ b/util/hb-subset.cc @@ -707,33 +707,83 @@ parse_instance (const char *name, return false; } - if (strcmp (s, "drop") == 0) - { - if (!hb_subset_input_pin_axis_to_default (subset_main->input, subset_main->face, axis_tag)) - { - g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, - "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag)); - return false; - } - } - else + char *pp = s; + pp = strpbrk (pp, ":"); + if (pp) // partial instancing { errno = 0; - char *p; - float axis_value = strtof (s, &p); - if (errno || s == p) + char *pend; + float min_val = strtof (s, &pend); + if (errno || s == pend || pend != pp) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Failed parsing axis value at: '%s'", s); return false; } - - if (!hb_subset_input_pin_axis_location (subset_main->input, subset_main->face, axis_tag, axis_value)) + pp++; + float max_val = strtof (pp, &pend); + /* we need to specify 2 values or 3 values for partial instancing: + * at least new min and max values, new default is optional */ + if (errno || pp == pend || (*pend != ':' && *pend != '\0')) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, - "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag)); + "Failed parsing axis value at: '%s'", s); return false; } + /* 3 values are specified */ + float *def_val_p = nullptr; + float def_val; + if (*pend == ':') + { + def_val = max_val; + def_val_p = &def_val; + pp = pend + 1; + max_val = strtof (pp, &pend); + if (errno || pp == pend || *pend != '\0') + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Failed parsing axis value at: '%s'", s); + return false; + } + } + if (!hb_subset_input_set_axis_range (subset_main->input, subset_main->face, axis_tag, min_val, max_val, def_val_p)) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Error: axis: '%c%c%c%c', not present in fvar or invalid range with min:%.6f max:%.6f", + HB_UNTAG (axis_tag), min_val, max_val); + return false; + } + } + else + { + if (strcmp (s, "drop") == 0) + { + if (!hb_subset_input_pin_axis_to_default (subset_main->input, subset_main->face, axis_tag)) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag)); + return false; + } + } + else + { + errno = 0; + char *p; + float axis_value = strtof (s, &p); + if (errno || s == p) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Failed parsing axis value at: '%s'", s); + return false; + } + + if (!hb_subset_input_pin_axis_location (subset_main->input, subset_main->face, axis_tag, axis_value)) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Cannot pin axis: '%c%c%c%c', not present in fvar", HB_UNTAG (axis_tag)); + return false; + } + } } s = strtok(nullptr, "="); } From 77b158c72d355e8e5e32f0d9748174041fddc8dd Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Mon, 7 Aug 2023 16:02:02 -0700 Subject: [PATCH 12/15] [instancer] add tests for gvar partial instancing --- test/subset/data/Makefile.am | 1 + test/subset/data/Makefile.sources | 1 + ...all-codepoint.wght=200-300-500,wdth=80-90.ttf | Bin 0 -> 8256 bytes ...retain-all-codepoint.wght=300-600,wdth=85.ttf | Bin 0 -> 7244 bytes ...all-codepoint.wght=200-300-500,wdth=80-90.ttf | Bin 0 -> 7452 bytes ...retain-all-codepoint.wght=300-600,wdth=85.ttf | Bin 0 -> 6780 bytes .../profiles/no-tables-with-item-variations.txt | 1 + .../data/tests/glyf_partial_instancing.tests | 13 +++++++++++++ test/subset/generate-expected-outputs.py | 1 + test/subset/meson.build | 1 + 10 files changed, 18 insertions(+) create mode 100644 test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf create mode 100644 test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf create mode 100644 test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf create mode 100644 test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf create mode 100644 test/subset/data/profiles/no-tables-with-item-variations.txt create mode 100644 test/subset/data/tests/glyf_partial_instancing.tests diff --git a/test/subset/data/Makefile.am b/test/subset/data/Makefile.am index 980bddb07..4d46a6151 100644 --- a/test/subset/data/Makefile.am +++ b/test/subset/data/Makefile.am @@ -72,6 +72,7 @@ EXTRA_DIST += \ expected/collect_name_ids \ expected/instantiate_colrv1 \ expected/instantiate_cff2_update_metrics \ + expected/glyf_partial_instancing \ fonts \ profiles \ $(NULL) diff --git a/test/subset/data/Makefile.sources b/test/subset/data/Makefile.sources index 919ec7391..ba2a1a2f4 100644 --- a/test/subset/data/Makefile.sources +++ b/test/subset/data/Makefile.sources @@ -63,6 +63,7 @@ TESTS = \ tests/collect_name_ids.tests \ tests/instantiate_colrv1.tests \ tests/instantiate_cff2_update_metrics.tests \ + tests/glyf_partial_instancing.tests \ $(NULL) # TODO: re-enable once colrv1 subsetting is stabilized. diff --git a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.ABC.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf new file mode 100644 index 0000000000000000000000000000000000000000..92b190bed9be06a2135f87506a53b932fe51106d GIT binary patch literal 8256 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 MGHx4miVY(AU(YZzvH$=8 literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf new file mode 100644 index 0000000000000000000000000000000000000000..74343354d2dd2325d2941f7c2bf6c71c6cfd1433 GIT binary patch literal 6780 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 Date: Tue, 8 Aug 2023 08:33:11 -0700 Subject: [PATCH 13/15] fix bots. -Also disable partial instancing tests for now, cause the command option is wrapped by experimental_api --- test/subset/data/Makefile.am | 1 - test/subset/data/Makefile.sources | 1 - test/subset/meson.build | 2 +- util/hb-subset.cc | 4 ++++ 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/test/subset/data/Makefile.am b/test/subset/data/Makefile.am index 4d46a6151..980bddb07 100644 --- a/test/subset/data/Makefile.am +++ b/test/subset/data/Makefile.am @@ -72,7 +72,6 @@ EXTRA_DIST += \ expected/collect_name_ids \ expected/instantiate_colrv1 \ expected/instantiate_cff2_update_metrics \ - expected/glyf_partial_instancing \ fonts \ profiles \ $(NULL) diff --git a/test/subset/data/Makefile.sources b/test/subset/data/Makefile.sources index ba2a1a2f4..919ec7391 100644 --- a/test/subset/data/Makefile.sources +++ b/test/subset/data/Makefile.sources @@ -63,7 +63,6 @@ TESTS = \ tests/collect_name_ids.tests \ tests/instantiate_colrv1.tests \ tests/instantiate_cff2_update_metrics.tests \ - tests/glyf_partial_instancing.tests \ $(NULL) # TODO: re-enable once colrv1 subsetting is stabilized. diff --git a/test/subset/meson.build b/test/subset/meson.build index 9a993c19d..188d3dadd 100644 --- a/test/subset/meson.build +++ b/test/subset/meson.build @@ -65,7 +65,7 @@ tests = [ 'collect_name_ids', 'instantiate_colrv1', 'instantiate_cff2_update_metrics', - 'glyf_partial_instancing', + #'glyf_partial_instancing', ] repack_tests = [ diff --git a/util/hb-subset.cc b/util/hb-subset.cc index e416db238..bd3df8f57 100644 --- a/util/hb-subset.cc +++ b/util/hb-subset.cc @@ -707,6 +707,7 @@ parse_instance (const char *name, return false; } +#ifdef HB_EXPERIMENTAL_API char *pp = s; pp = strpbrk (pp, ":"); if (pp) // partial instancing @@ -756,6 +757,7 @@ parse_instance (const char *name, } else { +#endif if (strcmp (s, "drop") == 0) { if (!hb_subset_input_pin_axis_to_default (subset_main->input, subset_main->face, axis_tag)) @@ -784,7 +786,9 @@ parse_instance (const char *name, return false; } } +#ifdef HB_EXPERIMENTAL_API } +#endif s = strtok(nullptr, "="); } From bea26446d2063cadb0cd83c1c627d3eed95cbcf6 Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Tue, 15 Aug 2023 14:20:54 -0700 Subject: [PATCH 14/15] [instancer] reference all points for gvar If a point is not referenced and delta is not inferred, set delta to 0 --- src/hb-ot-var-common.hh | 16 ++++++++++++++-- ...-codepoint.wght=200-300-500,wdth=80-90.ttf | Bin 7452 -> 7292 bytes ...ain-all-codepoint.wght=300-600,wdth=85.ttf | Bin 6780 -> 6760 bytes 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh index 0a92e00df..d35b10cd1 100644 --- a/src/hb-ot-var-common.hh +++ b/src/hb-ot-var-common.hh @@ -993,8 +993,20 @@ struct tuple_delta_t start_point = end_point + 1; } - for (unsigned i : inferred_idxes) - indices[i] = true; + for (unsigned i = 0; i < point_count; i++) + { + /* if points are not referenced and deltas are not inferred, set to 0. + * reference all points for gvar */ + if ( !indices[i]) + { + if (!inferred_idxes.has (i)) + { + deltas_x.arrayZ[i] = 0.f; + deltas_y.arrayZ[i] = 0.f; + } + indices[i] = true; + } + } return true; } diff --git a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=200-300-500,wdth=80-90.ttf index 503c755838e73b7ebe1e761f205182b63d59764e..2e55653057963b1911308c25114baf1ecaca7ef4 100644 GIT binary patch delta 379 zcmXwvze@sP7{|ZQd++)4tRV!?L>d~T7DbCgi0|qK3yLHQ3;iMjgjWTqU?eJL@McLMJ-Iecz9TBYA z40v7Mi#E@7S6(+K8)^9dd_I}@idbws_WjWDA>5l}dQWC~X*AL-D;~EN%x24NSttp- zJKP)&&7wfjiDahJ4ElYUb%Ug7Vqf6R;g!LlQWK~-kwULmK&Kl6ecrfkV={NF%As!>&doQQfO1c7unQx~3$_L+B| HYOMbO@?&N@ delta 531 zcmexkF~@2`858f6i4_(+>t-`EFfee1FfcINP25w(#NM*mf>DE!rDx^B1)Ect6j(Q_ za9v=MV_*cTVq#zil5z|zK$3yM3QXEEx-&LSUc^4F9w_O+;H$vO;F|za4CDZTZvwN- zQ7Btm0mxTiW6(-qVqiD`k@reqkvR%sOGz>?;s8ty5|4#N86H0T{rmCbhd{u=@#xXR zhamPd28Cvp58~n!GyJZxtBARzF8L0-NQpJ|el*K$aj7&4q|W|6#eN7A5?!JwH< z;`wt4h6@)6XnepSDPhKNs+q;)@@13gMuzBSHjT4qH5isIZDg1%#HlTV#}ks1Z8;_D zSr{0bS^hIJ{{P>|@V}W2!~*&oueCE77~2^@$~%DJgI8q($XE_|C^jLOEewo}Al*Db W>)C*+7#V;nC$Hr!-~5TEiyr{YG;6y6 diff --git a/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf b/test/subset/data/expected/glyf_partial_instancing/Roboto-Variable.composite.no-tables-with-item-variations.retain-all-codepoint.wght=300-600,wdth=85.ttf index 74343354d2dd2325d2941f7c2bf6c71c6cfd1433..fc890fb96db4015d8ba95379ffe2bbefb188d483 100644 GIT binary patch delta 249 zcmexk^1@_7x?lKv*v#@=S^4>eMurQ`Y%e4wUoaRL zv`7i3@E`g5<;%NwpFe;3VrBK}^%p2$;Amv{)y$&)`LnuRBZFNto5ZbK5)6k9wJO0qtZ5+S$OQH#v)yZ}KeWSDPzXSwsOeK3P5h delta 236 zcmaE1^2cOCx?lwZ1H-?xg7n-KtSv?i3|wC(R_KW_&jE_QNH0q)vI_B5W?*1x0rJ00 z+!M`MF6791)~EaOVB~~kj*tr%8ZliS)NXw!z|4l#gI997qfA_Ap;|WAp?Vy zBm*N3z$E$if}-Nz6DPiZKLG+KxwybIkT}O+*v#@=S^4>eMurQ`Y%e4wUoaRLG)fAm z@E`g5<;%NwpFe;3VrBK}^%p4MVEEO{qW<}_x?LlKT{D}+Ew)<{42KRiPL5%b+nmD6 GA_@R&UstgJ From dd8d35766bb31ef43848180c419c621be302ac5d Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Tue, 22 Aug 2023 12:54:50 -0700 Subject: [PATCH 15/15] [instancer] enable partial instancing tests when experimental api is on --- src/hb-ot-var-common.hh | 2 +- test/subset/meson.build | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh index d35b10cd1..1d8be0568 100644 --- a/src/hb-ot-var-common.hh +++ b/src/hb-ot-var-common.hh @@ -937,7 +937,7 @@ struct tuple_delta_t if (orig_points.arrayZ[i].is_end_point) end_points.push (i); } - /* all points are referened, nothing to do */ + /* all points are referenced, nothing to do */ if (ref_count == point_count) return true; if (unlikely (end_points.in_error ())) return false; diff --git a/test/subset/meson.build b/test/subset/meson.build index 188d3dadd..be4f69bbf 100644 --- a/test/subset/meson.build +++ b/test/subset/meson.build @@ -65,9 +65,12 @@ tests = [ 'collect_name_ids', 'instantiate_colrv1', 'instantiate_cff2_update_metrics', - #'glyf_partial_instancing', ] +if get_option('experimental_api') + tests += 'glyf_partial_instancing' +endif + repack_tests = [ 'basic', 'prioritization',