From df55f840cb4cf2d5cfe9e93e289aa59e7d592f7f Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Thu, 30 Jun 2022 09:36:19 -0700 Subject: [PATCH] [instance] instantiate STAT table when axes are pinned at fixed locations restricting ranges is not supported yet. --- src/hb-ot-stat-table.hh | 237 ++++++++++++++++++++++++++++++++++++---- src/hb-subset-input.cc | 11 +- src/hb-subset-plan.cc | 10 ++ src/hb-subset-plan.hh | 2 + src/hb-subset.cc | 6 + 5 files changed, 237 insertions(+), 29 deletions(-) diff --git a/src/hb-ot-stat-table.hh b/src/hb-ot-stat-table.hh index 6f0a369e2..e3a2e89a0 100644 --- a/src/hb-ot-stat-table.hh +++ b/src/hb-ot-stat-table.hh @@ -57,6 +57,31 @@ enum // Reserved = 0xFFFC /* Reserved for future use — set to zero. */ }; +struct StatAxisRecord +{ + int cmp (hb_tag_t key) const { return tag.cmp (key); } + + hb_ot_name_id_t get_name_id () const { return nameID; } + + hb_tag_t get_axis_tag () const { return tag; } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + Tag tag; /* A tag identifying the axis of design variation. */ + NameID nameID; /* The name ID for entries in the 'name' table that + * provide a display string for this axis. */ + HBUINT16 ordering; /* A value that applications can use to determine + * primary sorting of face names, or for ordering + * of descriptors when composing family or face names. */ + public: + DEFINE_SIZE_STATIC (8); +}; + struct AxisValueFormat1 { unsigned int get_axis_index () const { return axisIndex; } @@ -64,6 +89,37 @@ struct AxisValueFormat1 hb_ot_name_id_t get_value_name_id () const { return valueNameID; } + hb_tag_t get_axis_tag (const hb_array_t axis_records) const + { + unsigned axis_idx = get_axis_index (); + return axis_records[axis_idx].get_axis_tag (); + } + + bool keep_axis_value (const hb_array_t axis_records, + const hb_hashmap_t *user_axes_location) const + { + hb_tag_t axis_tag = get_axis_tag (axis_records); + float axis_value = get_value (); + + if (!user_axes_location->has (axis_tag) || + fabs(axis_value - user_axes_location->get (axis_tag)) < 0.001) + return true; + + return false; + } + + bool subset (hb_subset_context_t *c, + const hb_array_t axis_records) const + { + TRACE_SUBSET (this); + const hb_hashmap_t* user_axes_location = c->plan->user_axes_location; + + if (keep_axis_value (axis_records, user_axes_location)) + return_trace (c->serializer->embed (this)); + + return_trace (false); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -92,6 +148,37 @@ struct AxisValueFormat2 hb_ot_name_id_t get_value_name_id () const { return valueNameID; } + hb_tag_t get_axis_tag (const hb_array_t axis_records) const + { + unsigned axis_idx = get_axis_index (); + return axis_records[axis_idx].get_axis_tag (); + } + + bool keep_axis_value (const hb_array_t axis_records, + const hb_hashmap_t *user_axes_location) const + { + hb_tag_t axis_tag = get_axis_tag (axis_records); + float axis_value = get_value (); + + if (!user_axes_location->has (axis_tag) || + fabs(axis_value - user_axes_location->get (axis_tag)) < 0.001) + return true; + + return false; + } + + bool subset (hb_subset_context_t *c, + const hb_array_t axis_records) const + { + TRACE_SUBSET (this); + const hb_hashmap_t* user_axes_location = c->plan->user_axes_location; + + if (keep_axis_value (axis_records, user_axes_location)) + return_trace (c->serializer->embed (this)); + + return_trace (false); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -124,6 +211,37 @@ struct AxisValueFormat3 hb_ot_name_id_t get_value_name_id () const { return valueNameID; } + hb_tag_t get_axis_tag (const hb_array_t axis_records) const + { + unsigned axis_idx = get_axis_index (); + return axis_records[axis_idx].get_axis_tag (); + } + + bool keep_axis_value (const hb_array_t axis_records, + const hb_hashmap_t *user_axes_location) const + { + hb_tag_t axis_tag = get_axis_tag (axis_records); + float axis_value = get_value (); + + if (!user_axes_location->has (axis_tag) || + fabs(axis_value - user_axes_location->get (axis_tag)) < 0.001) + return true; + + return false; + } + + bool subset (hb_subset_context_t *c, + const hb_array_t axis_records) const + { + TRACE_SUBSET (this); + const hb_hashmap_t* user_axes_location = c->plan->user_axes_location; + + if (keep_axis_value (axis_records, user_axes_location)) + return_trace (c->serializer->embed (this)); + + return_trace (false); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -172,12 +290,47 @@ struct AxisValueFormat4 const AxisValueRecord &get_axis_record (unsigned int axis_index) const { return axisValues.as_array (axisCount)[axis_index]; } + bool keep_axis_value (const hb_array_t axis_records, + const hb_hashmap_t *user_axes_location) const + { + hb_array_t axis_value_records = axisValues.as_array (axisCount); + + for (const auto& rec : axis_value_records) + { + unsigned axis_idx = rec.get_axis_index (); + float axis_value = rec.get_value (); + hb_tag_t axis_tag = axis_records[axis_idx].get_axis_tag (); + + if (user_axes_location->has (axis_tag) && + fabs(axis_value - user_axes_location->get (axis_tag)) > 0.001) + return false; + } + + return true; + } + + bool subset (hb_subset_context_t *c, + const hb_array_t axis_records) const + { + TRACE_SUBSET (this); + const hb_hashmap_t *user_axes_location = c->plan->user_axes_location; + if (!keep_axis_value (axis_records, user_axes_location)) + return_trace (false); + + unsigned total_size = min_size + axisCount * AxisValueRecord::static_size; + auto *out = c->serializer->allocate_size (total_size); + if (unlikely (!out)) return_trace (false); + memcpy (out, this, total_size); + return_trace (true); + } + hb_ot_name_id_t get_value_name_id () const { return valueNameID; } bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); + return_trace (likely (c->check_struct (this) && + axisValues.sanitize (c, axisCount))); } protected: @@ -234,6 +387,21 @@ struct AxisValue } } + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + TRACE_DISPATCH (this, u.format); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); + switch (u.format) { + case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...)); + case 4: return_trace (c->dispatch (u.format4, std::forward (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -263,27 +431,35 @@ struct AxisValue DEFINE_SIZE_UNION (2, format); }; -struct StatAxisRecord +struct AxisValueOffsetArray: UnsizedArrayOf> { - int cmp (hb_tag_t key) const { return tag.cmp (key); } - - hb_ot_name_id_t get_name_id () const { return nameID; } - - bool sanitize (hb_sanitize_context_t *c) const + bool subset (hb_subset_context_t *c, + unsigned axisValueCount, + unsigned& count, + const hb_array_t axis_records) const { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (this); + if (unlikely (!out)) return_trace (false); - protected: - Tag tag; /* A tag identifying the axis of design variation. */ - NameID nameID; /* The name ID for entries in the 'name' table that - * provide a display string for this axis. */ - HBUINT16 ordering; /* A value that applications can use to determine - * primary sorting of face names, or for ordering - * of descriptors when composing family or face names. */ - public: - DEFINE_SIZE_STATIC (8); + auto axisValueOffsets = as_array (axisValueCount); + count = 0; + for (const auto& offset : axisValueOffsets) + { + if (!offset) continue; + auto o_snap = c->serializer->snapshot (); + auto *o = c->serializer->embed (offset); + if (!o) return_trace (false); + if (!o->serialize_subset (c, offset, this, axis_records)) + { + c->serializer->revert (o_snap); + continue; + } + count++; + } + + return_trace (count); + } }; struct STAT @@ -345,6 +521,27 @@ struct STAT ; } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + STAT *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + auto designAxes = get_design_axes (); + for (unsigned i = 0; i < (unsigned)designAxisCount; i++) + if (unlikely (!c->serializer->embed (designAxes[i]))) + return_trace (false); + + if (designAxisCount) + c->serializer->check_assign (out->designAxesOffset, this->get_size (), + HB_SERIALIZE_ERROR_INT_OVERFLOW); + + unsigned count = 0; + out->offsetToAxisValueOffsets.serialize_subset (c, offsetToAxisValueOffsets, this, + axisValueCount, count, designAxes); + return_trace (c->serializer->check_assign (out->axisValueCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -381,7 +578,7 @@ struct STAT * set to zero; if designAxisCount is greater * than zero, must be greater than zero. */ HBUINT16 axisValueCount; /* The number of axis value tables. */ - NNOffset32To>> + NNOffset32To offsetToAxisValueOffsets; /* Offset in bytes from the beginning of * the STAT table to the start of the design diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc index 06f9f9844..7d1949627 100644 --- a/src/hb-subset-input.cc +++ b/src/hb-subset-input.cc @@ -48,8 +48,7 @@ hb_subset_input_create_or_fail (void) for (auto& set : input->sets_iter ()) set = hb_set_create (); - if ((input->axes_location = hb_object_create> ())) - input->axes_location->init_shallow (); + input->axes_location = hb_hashmap_create (); if (!input->axes_location || input->in_error ()) { @@ -99,7 +98,6 @@ hb_subset_input_create_or_fail (void) HB_TAG ('D', 'S', 'I', 'G'), HB_TAG ('M', 'V', 'A', 'R'), HB_TAG ('c', 'v', 'a', 'r'), - HB_TAG ('S', 'T', 'A', 'T'), }; input->sets.no_subset_tables->add_array (default_no_subset_tables, ARRAY_LENGTH (default_no_subset_tables)); @@ -249,12 +247,7 @@ hb_subset_input_destroy (hb_subset_input_t *input) for (hb_set_t* set : input->sets_iter ()) hb_set_destroy (set); - if (input->axes_location) - { - hb_object_destroy (input->axes_location); - input->axes_location->fini_shallow (); - hb_free (input->axes_location); - } + hb_hashmap_destroy (input->axes_location); hb_free (input); } diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index e405a4611..6dd0a2880 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -691,6 +691,9 @@ hb_subset_plan_create_or_fail (hb_face_t *face, plan->check_success (plan->sanitized_table_cache = hb_hashmap_create> ()); plan->check_success (plan->axes_location = hb_hashmap_create ()); + plan->check_success (plan->user_axes_location = hb_hashmap_create ()); + if (plan->user_axes_location && input->axes_location) + *plan->user_axes_location = *input->axes_location; plan->all_axes_pinned = false; if (unlikely (plan->in_error ())) { @@ -784,6 +787,13 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_hashmap_destroy (plan->axes_location); hb_hashmap_destroy (plan->sanitized_table_cache); + if (plan->user_axes_location) + { + hb_object_destroy (plan->user_axes_location); + plan->user_axes_location->fini_shallow (); + hb_free (plan->user_axes_location); + } + hb_free (plan); } diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index 49edacc5f..8912ae70d 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -109,6 +109,8 @@ struct hb_subset_plan_t hb_hashmap_t>* sanitized_table_cache; //normalized axes location map hb_hashmap_t *axes_location; + //user specified axes location map + hb_hashmap_t *user_axes_location; bool all_axes_pinned; public: diff --git a/src/hb-subset.cc b/src/hb-subset.cc index bcbe73df0..f62e7e895 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -53,6 +53,7 @@ #include "hb-ot-var-gvar-table.hh" #include "hb-ot-var-hvar-table.hh" #include "hb-ot-math-table.hh" +#include "hb-ot-stat-table.hh" #include "hb-repacker.hh" using OT::Layout::GSUB; @@ -453,6 +454,11 @@ _subset_table (hb_subset_plan_t *plan, case HB_OT_TAG_HVAR: return _subset (plan, buf); case HB_OT_TAG_VVAR: return _subset (plan, buf); #endif + case HB_OT_TAG_STAT: + /*TODO(qxliu): change the condition as we support more complex + * instancing operation*/ + if (plan->all_axes_pinned) return _subset (plan, buf); + else return _passthrough (plan, tag); default: if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)