From 0a6c16a313443eb4130aca4e39e2a9a792f8ba03 Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Mon, 8 Aug 2022 13:47:39 -0700 Subject: [PATCH] [instance] instantiate fvar table Added an old->new axes_indices mapping in the subset plan --- src/hb-ot-var-fvar-table.hh | 80 +++++++++++++++++++++++++++++++++++++ src/hb-subset-input.cc | 1 - src/hb-subset-plan.cc | 14 +++++-- src/hb-subset-plan.hh | 6 +++ src/hb-subset.cc | 4 ++ 5 files changed, 100 insertions(+), 5 deletions(-) diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh index b9b49f228..c65db02c9 100644 --- a/src/hb-ot-var-fvar-table.hh +++ b/src/hb-ot-var-fvar-table.hh @@ -47,6 +47,44 @@ struct InstanceRecord hb_array_t get_coordinates (unsigned int axis_count) const { return coordinatesZ.as_array (axis_count); } + bool subset (hb_subset_context_t *c, + unsigned axis_count, + bool has_postscript_nameid) const + { + TRACE_SUBSET (this); + if (unlikely (!c->serializer->embed (subfamilyNameID))) return_trace (false); + if (unlikely (!c->serializer->embed (flags))) return_trace (false); + + const hb_array_t coords = get_coordinates (axis_count); + const hb_hashmap_t *axes_location = c->plan->user_axes_location; + for (unsigned i = 0 ; i < axis_count; i++) + { + unsigned *axis_tag; + // only keep instances whose coordinates == pinned axis location + if (!c->plan->axes_old_index_tag_map->has (i, &axis_tag)) continue; + + if (axes_location->has (*axis_tag) && + fabsf (axes_location->get (*axis_tag) - coords[i].to_float ()) > 0.001f) + return_trace (false); + + if (!c->plan->axes_index_map->has (i)) + continue; + + if (!c->serializer->embed (coords[i])) + return_trace (false); + } + + if (has_postscript_nameid) + { + NameID name_id; + name_id = StructAfter (coords); + if (!c->serializer->embed (name_id)) + return_trace (false); + } + + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const { TRACE_SANITIZE (this); @@ -321,6 +359,48 @@ struct fvar } } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + unsigned retained_axis_count = c->plan->axes_index_map->get_population (); + if (!retained_axis_count) //all axes are pinned + return_trace (false); + + fvar *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (!c->serializer->check_assign (out->axisCount, retained_axis_count, HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + + bool has_postscript_nameid = false; + if (instanceSize >= axisCount * 4 + 6) + has_postscript_nameid = true; + + if (!c->serializer->check_assign (out->instanceSize, retained_axis_count * 4 + (has_postscript_nameid ? 6 : 4), + HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + + auto axes_records = get_axes (); + for (unsigned i = 0 ; i < (unsigned)axisCount; i++) + { + if (!c->plan->axes_index_map->has (i)) continue; + if (unlikely (!c->serializer->embed (axes_records[i]))) + return_trace (false); + } + + if (!c->serializer->check_assign (out->firstAxis, get_size (), HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + + for (unsigned i = 0 ; i < (unsigned)instanceCount; i++) + { + const InstanceRecord *instance = get_instance (i); + auto snap = c->serializer->snapshot (); + if (!instance->subset (c, axisCount, has_postscript_nameid)) + c->serializer->revert (snap); + } + return_trace (true); + } + public: hb_array_t get_axes () const { return hb_array (&(this+firstAxis), axisCount); } diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc index 14ae210d4..2c5e6daf1 100644 --- a/src/hb-subset-input.cc +++ b/src/hb-subset-input.cc @@ -89,7 +89,6 @@ hb_subset_input_create_or_fail (void) hb_tag_t default_no_subset_tables[] = { HB_TAG ('a', 'v', 'a', 'r'), - HB_TAG ('f', 'v', 'a', 'r'), HB_TAG ('g', 'a', 's', 'p'), HB_TAG ('c', 'v', 't', ' '), HB_TAG ('f', 'p', 'g', 'm'), diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index c872cabc5..e2590cb80 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -663,18 +663,22 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan) seg_maps = face->table.avar->get_segment_maps (); bool axis_not_pinned = false; - unsigned axis_count = 0; + unsigned old_axis_idx = 0, new_axis_idx = 0; for (const auto& axis : axes) { hb_tag_t axis_tag = axis.get_axis_tag (); + plan->axes_old_index_tag_map->set (old_axis_idx, axis_tag); + if (!plan->user_axes_location->has (axis_tag)) { axis_not_pinned = true; + plan->axes_index_map->set (old_axis_idx, new_axis_idx); + new_axis_idx++; } else { int normalized_v = axis.normalize_axis_value (plan->user_axes_location->get (axis_tag)); - if (has_avar && axis_count < face->table.avar->get_axis_count ()) + if (has_avar && old_axis_idx < face->table.avar->get_axis_count ()) { normalized_v = seg_maps->map (normalized_v); } @@ -684,8 +688,8 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan) } if (has_avar) seg_maps = &StructAfter (*seg_maps); - - axis_count++; + + old_axis_idx++; } plan->all_axes_pinned = !axis_not_pinned; } @@ -755,6 +759,8 @@ hb_subset_plan_create_or_fail (hb_face_t *face, 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->check_success (plan->axes_index_map = hb_map_create ()); + plan->check_success (plan->axes_old_index_tag_map = hb_map_create ()); plan->all_axes_pinned = false; plan->pinned_at_default = true; diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index 98a45e5f6..0050aae9c 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -67,6 +67,8 @@ struct hb_subset_plan_t hb_map_destroy (gpos_features); hb_map_destroy (colrv1_layers); hb_map_destroy (colr_palettes); + hb_map_destroy (axes_index_map); + hb_map_destroy (axes_old_index_tag_map); hb_hashmap_destroy (gsub_langsys); hb_hashmap_destroy (gpos_langsys); @@ -158,6 +160,10 @@ struct hb_subset_plan_t hb_hashmap_t *axes_location; //user specified axes location map hb_hashmap_t *user_axes_location; + //retained old axis index -> new axis index mapping in fvar axis array + hb_map_t *axes_index_map; + //axis_index->axis_tag mapping in fvar axis array + hb_map_t *axes_old_index_tag_map; bool all_axes_pinned; bool pinned_at_default; diff --git a/src/hb-subset.cc b/src/hb-subset.cc index 1a0bcbd1f..5e116be07 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -50,6 +50,7 @@ #include "hb-ot-color-cbdt-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" +#include "hb-ot-var-fvar-table.hh" #include "hb-ot-var-gvar-table.hh" #include "hb-ot-var-hvar-table.hh" #include "hb-ot-math-table.hh" @@ -475,6 +476,9 @@ _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_fvar: + if (plan->user_axes_location->is_empty ()) return _passthrough (plan, tag); + return _subset (plan, buf); case HB_OT_TAG_STAT: /*TODO(qxliu): change the condition as we support more complex * instancing operation*/