[instance] instantiate fvar table

Added an old->new axes_indices mapping in the subset plan
This commit is contained in:
Qunxin Liu 2022-08-08 13:47:39 -07:00 committed by Garret Rieger
parent 486fc2271a
commit 0a6c16a313
5 changed files with 100 additions and 5 deletions

View File

@ -47,6 +47,44 @@ struct InstanceRecord
hb_array_t<const HBFixed> 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<const HBFixed> coords = get_coordinates (axis_count);
const hb_hashmap_t<hb_tag_t, float> *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<NameID> (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<const AxisRecord> get_axes () const
{ return hb_array (&(this+firstAxis), axisCount); }

View File

@ -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'),

View File

@ -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);
}
@ -685,7 +689,7 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
if (has_avar)
seg_maps = &StructAfter<OT::SegmentMaps> (*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<hb_tag_t, float> ());
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;

View File

@ -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<hb_tag_t, int> *axes_location;
//user specified axes location map
hb_hashmap_t<hb_tag_t, float> *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;

View File

@ -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<const OT::HVAR> (plan, buf);
case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf);
#endif
case HB_OT_TAG_fvar:
if (plan->user_axes_location->is_empty ()) return _passthrough (plan, tag);
return _subset<const OT::fvar> (plan, buf);
case HB_OT_TAG_STAT:
/*TODO(qxliu): change the condition as we support more complex
* instancing operation*/