[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. */
|
// 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
|
struct AxisValueFormat1
|
||||||
{
|
{
|
||||||
unsigned int get_axis_index () const { return axisIndex; }
|
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_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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
|
@ -92,6 +148,37 @@ struct AxisValueFormat2
|
||||||
|
|
||||||
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
|
@ -124,6 +211,37 @@ struct AxisValueFormat3
|
||||||
|
|
||||||
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
|
@ -172,12 +290,47 @@ struct AxisValueFormat4
|
||||||
const AxisValueRecord &get_axis_record (unsigned int axis_index) const
|
const AxisValueRecord &get_axis_record (unsigned int axis_index) const
|
||||||
{ return axisValues.as_array (axisCount)[axis_index]; }
|
{ 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; }
|
hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
|
||||||
|
|
||||||
bool sanitize (hb_sanitize_context_t *c) const
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
return_trace (c->check_struct (this));
|
return_trace (likely (c->check_struct (this) &&
|
||||||
|
axisValues.sanitize (c, axisCount)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
|
@ -263,27 +431,35 @@ struct AxisValue
|
||||||
DEFINE_SIZE_UNION (2, format);
|
DEFINE_SIZE_UNION (2, format);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StatAxisRecord
|
struct AxisValueOffsetArray: UnsizedArrayOf<Offset16To<AxisValue>>
|
||||||
{
|
{
|
||||||
int cmp (hb_tag_t key) const { return tag.cmp (key); }
|
bool subset (hb_subset_context_t *c,
|
||||||
|
unsigned axisValueCount,
|
||||||
hb_ot_name_id_t get_name_id () const { return nameID; }
|
unsigned& count,
|
||||||
|
const hb_array_t<const StatAxisRecord> axis_records) const
|
||||||
bool sanitize (hb_sanitize_context_t *c) const
|
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SUBSET (this);
|
||||||
return_trace (c->check_struct (this));
|
auto *out = c->serializer->start_embed (this);
|
||||||
}
|
if (unlikely (!out)) return_trace (false);
|
||||||
|
|
||||||
protected:
|
auto axisValueOffsets = as_array (axisValueCount);
|
||||||
Tag tag; /* A tag identifying the axis of design variation. */
|
count = 0;
|
||||||
NameID nameID; /* The name ID for entries in the 'name' table that
|
for (const auto& offset : axisValueOffsets)
|
||||||
* provide a display string for this axis. */
|
{
|
||||||
HBUINT16 ordering; /* A value that applications can use to determine
|
if (!offset) continue;
|
||||||
* primary sorting of face names, or for ordering
|
auto o_snap = c->serializer->snapshot ();
|
||||||
* of descriptors when composing family or face names. */
|
auto *o = c->serializer->embed (offset);
|
||||||
public:
|
if (!o) return_trace (false);
|
||||||
DEFINE_SIZE_STATIC (8);
|
if (!o->serialize_subset (c, offset, this, axis_records))
|
||||||
|
{
|
||||||
|
c->serializer->revert (o_snap);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return_trace (count);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct STAT
|
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
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
|
@ -381,7 +578,7 @@ struct STAT
|
||||||
* set to zero; if designAxisCount is greater
|
* set to zero; if designAxisCount is greater
|
||||||
* than zero, must be greater than zero. */
|
* than zero, must be greater than zero. */
|
||||||
HBUINT16 axisValueCount; /* The number of axis value tables. */
|
HBUINT16 axisValueCount; /* The number of axis value tables. */
|
||||||
NNOffset32To<UnsizedArrayOf<Offset16To<AxisValue>>>
|
NNOffset32To<AxisValueOffsetArray>
|
||||||
offsetToAxisValueOffsets;
|
offsetToAxisValueOffsets;
|
||||||
/* Offset in bytes from the beginning of
|
/* Offset in bytes from the beginning of
|
||||||
* the STAT table to the start of the design
|
* 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 ())
|
for (auto& set : input->sets_iter ())
|
||||||
set = hb_set_create ();
|
set = hb_set_create ();
|
||||||
|
|
||||||
if ((input->axes_location = hb_object_create<hb_hashmap_t<hb_tag_t, float>> ()))
|
input->axes_location = hb_hashmap_create<hb_tag_t, float> ();
|
||||||
input->axes_location->init_shallow ();
|
|
||||||
|
|
||||||
if (!input->axes_location || input->in_error ())
|
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 ('D', 'S', 'I', 'G'),
|
||||||
HB_TAG ('M', 'V', 'A', 'R'),
|
HB_TAG ('M', 'V', 'A', 'R'),
|
||||||
HB_TAG ('c', '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,
|
input->sets.no_subset_tables->add_array (default_no_subset_tables,
|
||||||
ARRAY_LENGTH (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 ())
|
for (hb_set_t* set : input->sets_iter ())
|
||||||
hb_set_destroy (set);
|
hb_set_destroy (set);
|
||||||
|
|
||||||
if (input->axes_location)
|
hb_hashmap_destroy (input->axes_location);
|
||||||
{
|
|
||||||
hb_object_destroy (input->axes_location);
|
|
||||||
input->axes_location->fini_shallow ();
|
|
||||||
hb_free (input->axes_location);
|
|
||||||
}
|
|
||||||
|
|
||||||
hb_free (input);
|
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->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->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;
|
plan->all_axes_pinned = false;
|
||||||
|
|
||||||
if (unlikely (plan->in_error ())) {
|
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->axes_location);
|
||||||
hb_hashmap_destroy (plan->sanitized_table_cache);
|
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);
|
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;
|
hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>>* sanitized_table_cache;
|
||||||
//normalized axes location map
|
//normalized axes location map
|
||||||
hb_hashmap_t<hb_tag_t, int> *axes_location;
|
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;
|
bool all_axes_pinned;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#include "hb-ot-var-gvar-table.hh"
|
#include "hb-ot-var-gvar-table.hh"
|
||||||
#include "hb-ot-var-hvar-table.hh"
|
#include "hb-ot-var-hvar-table.hh"
|
||||||
#include "hb-ot-math-table.hh"
|
#include "hb-ot-math-table.hh"
|
||||||
|
#include "hb-ot-stat-table.hh"
|
||||||
#include "hb-repacker.hh"
|
#include "hb-repacker.hh"
|
||||||
|
|
||||||
using OT::Layout::GSUB;
|
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_HVAR: return _subset<const OT::HVAR> (plan, buf);
|
||||||
case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf);
|
case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf);
|
||||||
#endif
|
#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:
|
default:
|
||||||
if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)
|
if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)
|
||||||
|
|
Loading…
Reference in New Issue