[instance] instantiate STAT table when axes are pinned at fixed locations
restricting ranges is not supported yet.
This commit is contained in:
parent
2a4773e43d
commit
df55f840cb
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue