|
|
|
@ -76,6 +76,111 @@ struct contour_point_vector_t : hb_vector_t<contour_point_t> |
|
|
|
|
struct GlyphVariationData : TupleVariationData |
|
|
|
|
{}; |
|
|
|
|
|
|
|
|
|
struct glyph_variations_t |
|
|
|
|
{ |
|
|
|
|
using tuple_variations_t = TupleVariationData::tuple_variations_t; |
|
|
|
|
hb_vector_t<tuple_variations_t> glyph_variations; |
|
|
|
|
|
|
|
|
|
hb_vector_t<char> compiled_shared_tuples; |
|
|
|
|
private: |
|
|
|
|
unsigned shared_tuples_count = 0; |
|
|
|
|
|
|
|
|
|
/* shared coords-> index map after instantiation */ |
|
|
|
|
hb_hashmap_t<const hb_vector_t<char>*, unsigned> shared_tuples_idx_map; |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
unsigned compiled_shared_tuples_count () const |
|
|
|
|
{ return shared_tuples_count; } |
|
|
|
|
|
|
|
|
|
bool compile_shared_tuples (const hb_map_t& axes_index_map, |
|
|
|
|
const hb_map_t& axes_old_index_tag_map) |
|
|
|
|
{ |
|
|
|
|
/* key is pointer to compiled_peak_coords inside each tuple, hashing
|
|
|
|
|
* function will always deref pointers first */ |
|
|
|
|
hb_hashmap_t<const hb_vector_t<char>*, unsigned> coords_count_map; |
|
|
|
|
|
|
|
|
|
/* count the num of shared coords */ |
|
|
|
|
for (tuple_variations_t& vars: glyph_variations) |
|
|
|
|
{ |
|
|
|
|
for (tuple_delta_t& var : vars.tuple_vars) |
|
|
|
|
{ |
|
|
|
|
if (!var.compile_peak_coords (axes_index_map, axes_old_index_tag_map)) |
|
|
|
|
return false; |
|
|
|
|
unsigned* count; |
|
|
|
|
if (coords_count_map.has (&(var.compiled_peak_coords), &count)) |
|
|
|
|
coords_count_map.set (&(var.compiled_peak_coords), *count + 1); |
|
|
|
|
else |
|
|
|
|
coords_count_map.set (&(var.compiled_peak_coords), 1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!coords_count_map || coords_count_map.in_error ()) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
/* add only those coords that are used more than once into the vector and sort */ |
|
|
|
|
hb_vector_t<const hb_vector_t<char>*> shared_coords; |
|
|
|
|
if (unlikely (!shared_coords.alloc (coords_count_map.get_population ()))) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
for (const auto _ : coords_count_map.iter ()) |
|
|
|
|
{ |
|
|
|
|
if (_.second == 1) continue; |
|
|
|
|
shared_coords.push (_.first); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* no shared tuples: no coords are used more than once */ |
|
|
|
|
if (!shared_coords) return true; |
|
|
|
|
/* sorting based on the coords frequency first (high to low), then compare
|
|
|
|
|
* the coords bytes */ |
|
|
|
|
hb_qsort (shared_coords.arrayZ, shared_coords.length, sizeof (hb_vector_t<char>*), _cmp_coords, (void *) (&coords_count_map)); |
|
|
|
|
|
|
|
|
|
/* build shared_coords->idx map and shared tuples byte array */ |
|
|
|
|
|
|
|
|
|
shared_tuples_count = hb_min (0xFFFu + 1, shared_coords.length); |
|
|
|
|
unsigned len = shared_tuples_count * (shared_coords[0]->length); |
|
|
|
|
if (unlikely (!compiled_shared_tuples.alloc (len))) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < shared_tuples_count; i++) |
|
|
|
|
{ |
|
|
|
|
shared_tuples_idx_map.set (shared_coords[i], i); |
|
|
|
|
/* add a concat() in hb_vector_t? */ |
|
|
|
|
for (char c : shared_coords[i]->iter ()) |
|
|
|
|
compiled_shared_tuples.push (c); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int _cmp_coords (const void *pa, const void *pb, void *arg) |
|
|
|
|
{ |
|
|
|
|
const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* coords_count_map = |
|
|
|
|
reinterpret_cast<const hb_hashmap_t<const hb_vector_t<char>*, unsigned>*> (arg); |
|
|
|
|
|
|
|
|
|
/* shared_coords is hb_vector_t<const hb_vector_t<char>*> so casting pa/pb
|
|
|
|
|
* to be a pointer to a pointer */ |
|
|
|
|
const hb_vector_t<char>** a = reinterpret_cast<const hb_vector_t<char>**> (const_cast<void*>(pa)); |
|
|
|
|
const hb_vector_t<char>** b = reinterpret_cast<const hb_vector_t<char>**> (const_cast<void*>(pb)); |
|
|
|
|
|
|
|
|
|
bool has_a = coords_count_map->has (*a); |
|
|
|
|
bool has_b = coords_count_map->has (*b); |
|
|
|
|
|
|
|
|
|
if (has_a && has_b) |
|
|
|
|
{ |
|
|
|
|
unsigned a_num = coords_count_map->get (*a); |
|
|
|
|
unsigned b_num = coords_count_map->get (*b); |
|
|
|
|
|
|
|
|
|
if (a_num != b_num) |
|
|
|
|
return b_num - a_num; |
|
|
|
|
|
|
|
|
|
return (*b)->as_array().cmp ((*a)->as_array ()); |
|
|
|
|
} |
|
|
|
|
else if (has_a) return -1; |
|
|
|
|
else if (has_b) return 1; |
|
|
|
|
else return 0; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct gvar |
|
|
|
|
{ |
|
|
|
|
static constexpr hb_tag_t tableTag = HB_OT_TAG_gvar; |
|
|
|
|