|
|
|
@ -61,13 +61,16 @@ static bool ClassDef_remap_and_serialize ( |
|
|
|
|
struct hb_collect_feature_substitutes_with_var_context_t |
|
|
|
|
{ |
|
|
|
|
const hb_map_t *axes_index_tag_map; |
|
|
|
|
const hb_hashmap_t<hb_tag_t, int> *axes_location; |
|
|
|
|
const hb_hashmap_t<hb_tag_t, Triple> *axes_location; |
|
|
|
|
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *record_cond_idx_map; |
|
|
|
|
hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map; |
|
|
|
|
bool& insert_catch_all_feature_variation_record; |
|
|
|
|
|
|
|
|
|
// not stored in subset_plan
|
|
|
|
|
hb_set_t *feature_indices; |
|
|
|
|
bool apply; |
|
|
|
|
bool variation_applied; |
|
|
|
|
bool universal; |
|
|
|
|
unsigned cur_record_idx; |
|
|
|
|
hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> *conditionset_map; |
|
|
|
|
}; |
|
|
|
@ -2905,9 +2908,9 @@ struct VariationStore |
|
|
|
|
enum Cond_with_Var_flag_t |
|
|
|
|
{ |
|
|
|
|
KEEP_COND_WITH_VAR = 0, |
|
|
|
|
DROP_COND_WITH_VAR = 1, |
|
|
|
|
DROP_RECORD_WITH_VAR = 2, |
|
|
|
|
MEM_ERR_WITH_VAR = 3, |
|
|
|
|
KEEP_RECORD_WITH_VAR = 1, |
|
|
|
|
DROP_COND_WITH_VAR = 2, |
|
|
|
|
DROP_RECORD_WITH_VAR = 3, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct ConditionFormat1 |
|
|
|
@ -2940,29 +2943,42 @@ struct ConditionFormat1 |
|
|
|
|
|
|
|
|
|
hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex); |
|
|
|
|
|
|
|
|
|
//axis not pinned, keep the condition
|
|
|
|
|
if (!c->axes_location->has (axis_tag)) |
|
|
|
|
Triple axis_range (-1.f, 0.f, 1.f); |
|
|
|
|
if (c->axes_location->has (axis_tag)) |
|
|
|
|
axis_range = c->axes_location->get (axis_tag); |
|
|
|
|
|
|
|
|
|
int axis_min_val = axis_range.minimum; |
|
|
|
|
int axis_default_val = axis_range.middle; |
|
|
|
|
int axis_max_val = axis_range.maximum; |
|
|
|
|
|
|
|
|
|
int16_t filter_min_val = filterRangeMinValue.to_int (); |
|
|
|
|
int16_t filter_max_val = filterRangeMaxValue.to_int (); |
|
|
|
|
|
|
|
|
|
if (axis_default_val < filter_min_val || |
|
|
|
|
axis_default_val > filter_max_val) |
|
|
|
|
c->apply = false; |
|
|
|
|
|
|
|
|
|
//condition not met, drop the entire record
|
|
|
|
|
if (axis_min_val > filter_max_val || axis_max_val < filter_min_val || |
|
|
|
|
filter_min_val > filter_max_val) |
|
|
|
|
return DROP_RECORD_WITH_VAR; |
|
|
|
|
|
|
|
|
|
//condition met and axis pinned, drop the condition
|
|
|
|
|
if (c->axes_location->has (axis_tag) && |
|
|
|
|
c->axes_location->get (axis_tag).is_point ()) |
|
|
|
|
return DROP_COND_WITH_VAR; |
|
|
|
|
|
|
|
|
|
if (filter_max_val != axis_max_val || filter_min_val != axis_min_val) |
|
|
|
|
{ |
|
|
|
|
// add axisIndex->value into the hashmap so we can check if the record is
|
|
|
|
|
// unique with variations
|
|
|
|
|
int16_t min_val = filterRangeMinValue.to_int (); |
|
|
|
|
int16_t max_val = filterRangeMaxValue.to_int (); |
|
|
|
|
hb_codepoint_t val = (max_val << 16) + min_val; |
|
|
|
|
hb_codepoint_t val = (filter_max_val << 16) + filter_min_val; |
|
|
|
|
|
|
|
|
|
condition_map->set (axisIndex, val); |
|
|
|
|
return KEEP_COND_WITH_VAR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//axis pinned, check if condition is met
|
|
|
|
|
//TODO: add check for axis Ranges
|
|
|
|
|
int v = c->axes_location->get (axis_tag); |
|
|
|
|
|
|
|
|
|
//condition not met, drop the entire record
|
|
|
|
|
if (v < filterRangeMinValue.to_int () || v > filterRangeMaxValue.to_int ()) |
|
|
|
|
return DROP_RECORD_WITH_VAR; |
|
|
|
|
|
|
|
|
|
//axis pinned and condition met, drop the condition
|
|
|
|
|
return DROP_COND_WITH_VAR; |
|
|
|
|
return KEEP_RECORD_WITH_VAR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool evaluate (const int *coords, unsigned int coord_len) const |
|
|
|
@ -3001,7 +3017,7 @@ struct Condition |
|
|
|
|
{ |
|
|
|
|
switch (u.format) { |
|
|
|
|
case 1: return u.format1.keep_with_variations (c, condition_map); |
|
|
|
|
default:return KEEP_COND_WITH_VAR; |
|
|
|
|
default: c->apply = false; return KEEP_COND_WITH_VAR; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -3046,45 +3062,50 @@ struct ConditionSet |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const |
|
|
|
|
void keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const |
|
|
|
|
{ |
|
|
|
|
hb_map_t *condition_map = hb_map_create (); |
|
|
|
|
if (unlikely (!condition_map)) return MEM_ERR_WITH_VAR; |
|
|
|
|
if (unlikely (!condition_map)) return; |
|
|
|
|
hb::shared_ptr<hb_map_t> p {condition_map}; |
|
|
|
|
|
|
|
|
|
hb_set_t *cond_set = hb_set_create (); |
|
|
|
|
if (unlikely (!cond_set)) return MEM_ERR_WITH_VAR; |
|
|
|
|
if (unlikely (!cond_set)) return; |
|
|
|
|
hb::shared_ptr<hb_set_t> s {cond_set}; |
|
|
|
|
|
|
|
|
|
c->apply = true; |
|
|
|
|
bool should_keep = false; |
|
|
|
|
unsigned num_kept_cond = 0, cond_idx = 0; |
|
|
|
|
for (const auto& offset : conditions) |
|
|
|
|
{ |
|
|
|
|
Cond_with_Var_flag_t ret = (this+offset).keep_with_variations (c, condition_map); |
|
|
|
|
// one condition is not met, drop the entire record
|
|
|
|
|
// condition is not met or condition out of range, drop the entire record
|
|
|
|
|
if (ret == DROP_RECORD_WITH_VAR) |
|
|
|
|
return DROP_RECORD_WITH_VAR; |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
// axis not pinned, keep this condition
|
|
|
|
|
if (ret == KEEP_COND_WITH_VAR) |
|
|
|
|
{ |
|
|
|
|
should_keep = true; |
|
|
|
|
cond_set->add (cond_idx); |
|
|
|
|
num_kept_cond++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (ret == KEEP_RECORD_WITH_VAR) |
|
|
|
|
should_keep = true; |
|
|
|
|
|
|
|
|
|
cond_idx++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// all conditions met
|
|
|
|
|
if (num_kept_cond == 0) return DROP_COND_WITH_VAR; |
|
|
|
|
if (!should_keep) return; |
|
|
|
|
|
|
|
|
|
//check if condition_set is unique with variations
|
|
|
|
|
if (c->conditionset_map->has (p)) |
|
|
|
|
//duplicate found, drop the entire record
|
|
|
|
|
return DROP_RECORD_WITH_VAR; |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
c->conditionset_map->set (p, 1); |
|
|
|
|
c->record_cond_idx_map->set (c->cur_record_idx, s); |
|
|
|
|
|
|
|
|
|
return KEEP_COND_WITH_VAR; |
|
|
|
|
if (should_keep && num_kept_cond == 0) |
|
|
|
|
c->universal = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool subset (hb_subset_context_t *c, |
|
|
|
@ -3289,12 +3310,11 @@ struct FeatureVariationRecord |
|
|
|
|
void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c, |
|
|
|
|
const void *base) const |
|
|
|
|
{ |
|
|
|
|
// ret == 1, all conditions met
|
|
|
|
|
if ((base+conditions).keep_with_variations (c) == DROP_COND_WITH_VAR && |
|
|
|
|
c->apply) |
|
|
|
|
(base+conditions).keep_with_variations (c); |
|
|
|
|
if (c->apply && !c->variation_applied) |
|
|
|
|
{ |
|
|
|
|
(base+substitutions).collect_feature_substitutes_with_variations (c); |
|
|
|
|
c->apply = false; // set variations only once
|
|
|
|
|
c->variation_applied = true; // set variations only once
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -3361,7 +3381,12 @@ struct FeatureVariations |
|
|
|
|
{ |
|
|
|
|
c->cur_record_idx = i; |
|
|
|
|
varRecords[i].collect_feature_substitutes_with_variations (c, this); |
|
|
|
|
if (c->universal) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
if (c->variation_applied && !c->universal && |
|
|
|
|
!c->record_cond_idx_map->is_empty ()) |
|
|
|
|
c->insert_catch_all_feature_variation_record = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
FeatureVariations* copy (hb_serialize_context_t *c) const |
|
|
|
|