[instance] instantiate STAT table when axes are pinned at fixed locations

restricting ranges is not supported yet.
This commit is contained in:
Qunxin Liu 2022-06-30 09:36:19 -07:00 committed by Garret Rieger
parent 2a4773e43d
commit df55f840cb
5 changed files with 237 additions and 29 deletions

View File

@ -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<const StatAxisRecord> 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<const StatAxisRecord> axis_records,
const hb_hashmap_t<hb_tag_t, float> *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<const StatAxisRecord> axis_records) const
{
TRACE_SUBSET (this);
const hb_hashmap_t<hb_tag_t, float>* 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<const StatAxisRecord> 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<const StatAxisRecord> axis_records,
const hb_hashmap_t<hb_tag_t, float> *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<const StatAxisRecord> axis_records) const
{
TRACE_SUBSET (this);
const hb_hashmap_t<hb_tag_t, float>* 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<const StatAxisRecord> 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<const StatAxisRecord> axis_records,
const hb_hashmap_t<hb_tag_t, float> *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<const StatAxisRecord> axis_records) const
{
TRACE_SUBSET (this);
const hb_hashmap_t<hb_tag_t, float>* 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<const StatAxisRecord> axis_records,
const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
{
hb_array_t<const AxisValueRecord> 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<const StatAxisRecord> axis_records) const
{
TRACE_SUBSET (this);
const hb_hashmap_t<hb_tag_t, float> *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<AxisValueFormat4> (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, typename ...Ts>
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<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (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<Offset16To<AxisValue>>
{
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<const StatAxisRecord> 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<UnsizedArrayOf<Offset16To<AxisValue>>>
NNOffset32To<AxisValueOffsetArray>
offsetToAxisValueOffsets;
/* Offset in bytes from the beginning of
* the STAT table to the start of the design

View File

@ -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<hb_hashmap_t<hb_tag_t, float>> ()))
input->axes_location->init_shallow ();
input->axes_location = hb_hashmap_create<hb_tag_t, float> ();
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);
}

View File

@ -691,6 +691,9 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
plan->check_success (plan->sanitized_table_cache = hb_hashmap_create<hb_tag_t, hb::unique_ptr<hb_blob_t>> ());
plan->check_success (plan->axes_location = hb_hashmap_create<hb_tag_t, int> ());
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->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);
}

View File

@ -109,6 +109,8 @@ struct hb_subset_plan_t
hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>>* sanitized_table_cache;
//normalized axes location map
hb_hashmap_t<hb_tag_t, int> *axes_location;
//user specified axes location map
hb_hashmap_t<hb_tag_t, float> *user_axes_location;
bool all_axes_pinned;
public:

View File

@ -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<const OT::HVAR> (plan, buf);
case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (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<const OT::STAT> (plan, buf);
else return _passthrough (plan, tag);
default:
if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)