summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh')
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh275
1 files changed, 251 insertions, 24 deletions
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh
index 9e813f6d2d..23d7f7cc3d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh
@@ -230,7 +230,7 @@ struct VarStoreInstancer
/* according to the spec, if colr table has varStore but does not have
* varIdxMap, then an implicit identity mapping is used */
float operator() (uint32_t varIdx, unsigned short offset = 0) const
- { return varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords); }
+ { return coords ? varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords) : 0; }
const VariationStore *varStore;
const DeltaSetIndexMap *varIdxMap;
@@ -449,17 +449,26 @@ 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;
- tuple_delta_t (tuple_delta_t&& o) : tuple_delta_t ()
+ friend void swap (tuple_delta_t& a, tuple_delta_t& b)
{
- axis_tuples = std::move (o.axis_tuples);
- indices = std::move (o.indices);
- deltas_x = std::move (o.deltas_x);
- deltas_y = std::move (o.deltas_y);
+ hb_swap (a.axis_tuples, b.axis_tuples);
+ hb_swap (a.indices, b.indices);
+ hb_swap (a.deltas_x, b.deltas_x);
+ hb_swap (a.deltas_y, b.deltas_y);
+ hb_swap (a.compiled_tuple_header, b.compiled_tuple_header);
+ hb_swap (a.compiled_deltas, b.compiled_deltas);
+ hb_swap (a.compiled_peak_coords, b.compiled_peak_coords);
}
+ tuple_delta_t (tuple_delta_t&& o) : tuple_delta_t ()
+ { hb_swap (*this, o); }
+
tuple_delta_t& operator = (tuple_delta_t&& o)
{
hb_swap (*this, o);
@@ -552,13 +561,43 @@ 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 */
- //TODO(qxliu):add option to use sharedTuples in gvar
bool compile_tuple_var_header (const hb_map_t& axes_index_map,
unsigned points_data_length,
- const hb_map_t& axes_old_index_tag_map)
+ const hb_map_t& axes_old_index_tag_map,
+ const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* shared_tuples_idx_map)
{
if (!compiled_deltas) return false;
@@ -574,14 +613,25 @@ struct tuple_delta_t
hb_array_t<F2DOT14> coords (p, end - p);
/* encode peak coords */
- unsigned peak_count = encode_peak_coords(coords, flag, axes_index_map, axes_old_index_tag_map);
- if (!peak_count) return false;
+ unsigned peak_count = 0;
+ unsigned *shared_tuple_idx;
+ if (shared_tuples_idx_map &&
+ shared_tuples_idx_map->has (&compiled_peak_coords, &shared_tuple_idx))
+ {
+ flag = *shared_tuple_idx;
+ }
+ else
+ {
+ peak_count = encode_peak_coords(coords, flag, axes_index_map, axes_old_index_tag_map);
+ if (!peak_count) return false;
+ }
/* encode interim coords, it's optional so returned num could be 0 */
unsigned interim_count = encode_interm_coords (coords.sub_array (peak_count), flag, axes_index_map, axes_old_index_tag_map);
- //TODO(qxliu): add option to use shared_points in gvar
- flag |= TupleVariationHeader::TuppleIndex::PrivatePointNumbers;
+ /* pointdata length = 0 implies "use shared points" */
+ if (points_data_length)
+ flag |= TupleVariationHeader::TuppleIndex::PrivatePointNumbers;
unsigned serialized_data_size = points_data_length + compiled_deltas.length;
TupleVariationHeader *o = reinterpret_cast<TupleVariationHeader *> (compiled_tuple_header.begin ());
@@ -870,6 +920,111 @@ struct tuple_delta_t
}
return encoded_len;
}
+
+ bool calc_inferred_deltas (const contour_point_vector_t& orig_points)
+ {
+ unsigned point_count = orig_points.length;
+ if (point_count != indices.length)
+ return false;
+
+ unsigned ref_count = 0;
+ hb_vector_t<unsigned> end_points;
+
+ for (unsigned i = 0; i < point_count; i++)
+ {
+ if (indices.arrayZ[i])
+ ref_count++;
+ if (orig_points.arrayZ[i].is_end_point)
+ end_points.push (i);
+ }
+ /* all points are referenced, nothing to do */
+ if (ref_count == point_count)
+ return true;
+ if (unlikely (end_points.in_error ())) return false;
+
+ hb_set_t inferred_idxes;
+ unsigned start_point = 0;
+ for (unsigned end_point : end_points)
+ {
+ /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
+ unsigned unref_count = 0;
+ for (unsigned i = start_point; i < end_point + 1; i++)
+ unref_count += indices.arrayZ[i];
+ unref_count = (end_point - start_point + 1) - unref_count;
+
+ unsigned j = start_point;
+ if (unref_count == 0 || unref_count > end_point - start_point)
+ goto no_more_gaps;
+ for (;;)
+ {
+ /* Locate the next gap of unreferenced points between two referenced points prev and next.
+ * Note that a gap may wrap around at left (start_point) and/or at right (end_point).
+ */
+ unsigned int prev, next, i;
+ for (;;)
+ {
+ i = j;
+ j = next_index (i, start_point, end_point);
+ if (indices.arrayZ[i] && !indices.arrayZ[j]) break;
+ }
+ prev = j = i;
+ for (;;)
+ {
+ i = j;
+ j = next_index (i, start_point, end_point);
+ if (!indices.arrayZ[i] && indices.arrayZ[j]) break;
+ }
+ next = j;
+ /* Infer deltas for all unref points in the gap between prev and next */
+ i = prev;
+ for (;;)
+ {
+ i = next_index (i, start_point, end_point);
+ if (i == next) break;
+ deltas_x.arrayZ[i] = infer_delta (orig_points.arrayZ[i].x, orig_points.arrayZ[prev].x, orig_points.arrayZ[next].x,
+ deltas_x.arrayZ[prev], deltas_x.arrayZ[next]);
+ deltas_y.arrayZ[i] = infer_delta (orig_points.arrayZ[i].y, orig_points.arrayZ[prev].y, orig_points.arrayZ[next].y,
+ deltas_y.arrayZ[prev], deltas_y.arrayZ[next]);
+ inferred_idxes.add (i);
+ if (--unref_count == 0) goto no_more_gaps;
+ }
+ }
+ no_more_gaps:
+ start_point = end_point + 1;
+ }
+
+ for (unsigned i = 0; i < point_count; i++)
+ {
+ /* if points are not referenced and deltas are not inferred, set to 0.
+ * reference all points for gvar */
+ if ( !indices[i])
+ {
+ if (!inferred_idxes.has (i))
+ {
+ deltas_x.arrayZ[i] = 0.f;
+ deltas_y.arrayZ[i] = 0.f;
+ }
+ indices[i] = true;
+ }
+ }
+ return true;
+ }
+
+ static float infer_delta (float target_val, float prev_val, float next_val, float prev_delta, float next_delta)
+ {
+ if (prev_val == next_val)
+ return (prev_delta == next_delta) ? prev_delta : 0.f;
+ else if (target_val <= hb_min (prev_val, next_val))
+ return (prev_val < next_val) ? prev_delta : next_delta;
+ else if (target_val >= hb_max (prev_val, next_val))
+ return (prev_val > next_val) ? prev_delta : next_delta;
+
+ float r = (target_val - prev_val) / (next_val - prev_val);
+ return prev_delta + r * (next_delta - prev_delta);
+ }
+
+ static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end)
+ { return (i >= end) ? start : (i + 1); }
};
struct TupleVariationData
@@ -910,7 +1065,22 @@ struct TupleVariationData
/* referenced point set-> count map, used in finding shared points */
hb_hashmap_t<const hb_vector_t<bool>*, unsigned> point_set_count_map;
+ /* empty for non-gvar tuples.
+ * shared_points_bytes is just a copy of some value in the point_data_map,
+ * which will be freed during map destruction. Save it for serialization, so
+ * no need to do find_shared_points () again */
+ hb_bytes_t shared_points_bytes;
+
+ /* total compiled byte size as TupleVariationData format, initialized to its
+ * min_size: 4 */
+ unsigned compiled_byte_size = 4;
+
public:
+ tuple_variations_t () = default;
+ tuple_variations_t (const tuple_variations_t&) = delete;
+ tuple_variations_t& operator=(const tuple_variations_t&) = delete;
+ tuple_variations_t (tuple_variations_t&&) = default;
+ tuple_variations_t& operator=(tuple_variations_t&&) = default;
~tuple_variations_t () { fini (); }
void fini ()
{
@@ -921,8 +1091,17 @@ struct TupleVariationData
tuple_vars.fini ();
}
+ explicit operator bool () const { return bool (tuple_vars); }
unsigned get_var_count () const
- { return tuple_vars.length; }
+ {
+ unsigned count = tuple_vars.length;
+ if (shared_points_bytes.length)
+ count |= TupleVarCount::SharedPointNumbers;
+ return count;
+ }
+
+ unsigned get_compiled_byte_size () const
+ { return compiled_byte_size; }
bool create_from_tuple_var_data (tuple_iterator_t iterator,
unsigned tuple_var_count,
@@ -992,6 +1171,7 @@ struct TupleVariationData
return true;
}
+ private:
void change_tuple_variations_axis_limits (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances)
{
@@ -1025,7 +1205,7 @@ struct TupleVariationData
void merge_tuple_variations ()
{
hb_vector_t<tuple_delta_t> new_vars;
- hb_hashmap_t<hb_hashmap_t<hb_tag_t, Triple>, unsigned> m;
+ hb_hashmap_t<const hb_hashmap_t<hb_tag_t, Triple>*, unsigned> m;
unsigned i = 0;
for (const tuple_delta_t& var : tuple_vars)
{
@@ -1033,14 +1213,14 @@ struct TupleVariationData
if (var.axis_tuples.is_empty ()) continue;
unsigned *idx;
- if (m.has (var.axis_tuples, &idx))
+ if (m.has (&(var.axis_tuples), &idx))
{
new_vars[*idx] += var;
}
else
{
new_vars.push (var);
- m.set (var.axis_tuples, i);
+ m.set (&(var.axis_tuples), i);
i++;
}
}
@@ -1187,19 +1367,45 @@ struct TupleVariationData
return res;
}
- void instantiate (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
- const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances)
+ bool calc_inferred_deltas (contour_point_vector_t& contour_points)
{
+ for (tuple_delta_t& var : tuple_vars)
+ if (!var.calc_inferred_deltas (contour_points))
+ return false;
+
+ return true;
+ }
+
+ public:
+ bool instantiate (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
+ const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances,
+ contour_point_vector_t* contour_points = nullptr)
+ {
+ if (!tuple_vars) return true;
change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances);
+ /* compute inferred deltas only for gvar */
+ if (contour_points)
+ if (!calc_inferred_deltas (*contour_points))
+ return false;
+
merge_tuple_variations ();
+ return !tuple_vars.in_error ();
}
bool compile_bytes (const hb_map_t& axes_index_map,
- const hb_map_t& axes_old_index_tag_map)
+ const hb_map_t& axes_old_index_tag_map,
+ bool use_shared_points,
+ const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* shared_tuples_idx_map = nullptr)
{
// compile points set and store data in hashmap
if (!compile_all_point_sets ())
return false;
+
+ if (use_shared_points)
+ {
+ shared_points_bytes = find_shared_points ();
+ compiled_byte_size += shared_points_bytes.length;
+ }
// compile delta and tuple var header for each tuple variation
for (auto& tuple: tuple_vars)
{
@@ -1211,8 +1417,11 @@ struct TupleVariationData
if (!tuple.compile_deltas ())
return false;
- if (!tuple.compile_tuple_var_header (axes_index_map, points_data->length, axes_old_index_tag_map))
+ unsigned points_data_length = (*points_data != shared_points_bytes) ? points_data->length : 0;
+ if (!tuple.compile_tuple_var_header (axes_index_map, points_data_length, axes_old_index_tag_map,
+ shared_tuples_idx_map))
return false;
+ compiled_byte_size += tuple.compiled_tuple_header.length + points_data_length + tuple.compiled_deltas.length;
}
return true;
}
@@ -1229,9 +1438,12 @@ struct TupleVariationData
return_trace (true);
}
- bool serialize_var_data (hb_serialize_context_t *c) const
+ bool serialize_var_data (hb_serialize_context_t *c, bool is_gvar) const
{
TRACE_SERIALIZE (this);
+ if (is_gvar)
+ shared_points_bytes.copy (c);
+
for (const auto& tuple: tuple_vars)
{
const hb_vector_t<bool>* points_set = &(tuple.indices);
@@ -1239,10 +1451,20 @@ struct TupleVariationData
if (!point_data_map.has (points_set, &point_data))
return_trace (false);
- point_data->copy (c);
+ if (!is_gvar || *point_data != shared_points_bytes)
+ point_data->copy (c);
+
tuple.compiled_deltas.as_array ().copy (c);
if (c->in_error ()) return_trace (false);
}
+
+ /* padding for gvar */
+ if (is_gvar && (compiled_byte_size % 2))
+ {
+ HBUINT8 pad;
+ pad = 0;
+ if (!c->embed (pad)) return_trace (false);
+ }
return_trace (true);
}
};
@@ -1428,9 +1650,12 @@ struct TupleVariationData
bool serialize (hb_serialize_context_t *c,
bool is_gvar,
- tuple_variations_t& tuple_variations) const
+ const tuple_variations_t& tuple_variations) const
{
TRACE_SERIALIZE (this);
+ /* empty tuple variations, just return and skip serialization. */
+ if (!tuple_variations) return_trace (true);
+
auto *out = c->start_embed (this);
if (unlikely (!c->extend_min (out))) return_trace (false);
@@ -1446,15 +1671,17 @@ struct TupleVariationData
if (!is_gvar) data_offset += 4;
if (!c->check_assign (out->data, data_offset, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
- return tuple_variations.serialize_var_data (c);
+ return tuple_variations.serialize_var_data (c, is_gvar);
}
protected:
struct TupleVarCount : HBUINT16
{
+ friend struct tuple_variations_t;
bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); }
unsigned int get_count () const { return (*this) & CountMask; }
TupleVarCount& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
+ explicit operator bool () const { return get_count (); }
protected:
enum Flags