[instancer] add struct glyph_variations_t for gvar

-Add compile_peak_coords () in tuple_delta_t
-Add compile_shared_tuples () for glyph_variations_t
pull/4368/head
Qunxin Liu 1 year ago
parent cb92210b4c
commit a0f810effc
  1. 33
      src/hb-ot-var-common.hh
  2. 105
      src/hb-ot-var-gvar-table.hh

@ -449,6 +449,9 @@ struct tuple_delta_t
hb_vector_t<char> compiled_tuple_header;
hb_vector_t<char> compiled_deltas;
/* compiled peak coords, empty for non-gvar tuples */
hb_vector_t<char> compiled_peak_coords;
tuple_delta_t () = default;
tuple_delta_t (const tuple_delta_t& o) = default;
@ -552,6 +555,36 @@ struct tuple_delta_t
return out;
}
bool compile_peak_coords (const hb_map_t& axes_index_map,
const hb_map_t& axes_old_index_tag_map)
{
unsigned axis_count = axes_index_map.get_population ();
if (unlikely (!compiled_peak_coords.alloc (axis_count * F2DOT14::static_size)))
return false;
unsigned orig_axis_count = axes_old_index_tag_map.get_population ();
for (unsigned i = 0; i < orig_axis_count; i++)
{
if (!axes_index_map.has (i))
continue;
hb_tag_t axis_tag = axes_old_index_tag_map.get (i);
Triple *coords;
F2DOT14 peak_coord;
if (axis_tuples.has (axis_tag, &coords))
peak_coord.set_float (coords->middle);
else
peak_coord.set_int (0);
/* push F2DOT14 value into char vector */
int16_t val = peak_coord.to_int ();
compiled_peak_coords.push (static_cast<char> (val >> 8));
compiled_peak_coords.push (static_cast<char> (val & 0xFF));
}
return !compiled_peak_coords.in_error ();
}
/* deltas should be compiled already before we compile tuple
* variation header cause we need to fill in the size of the
* serialized data for this tuple variation */

@ -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;

Loading…
Cancel
Save