[subset] Add subsetting for GPOS Lookup Type 1: Single Adjustment Positioning Subtable
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 5c21980..7d57056 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -236,6 +236,11 @@
}
};
+template<typename Iterator>
+static inline void SinglePos_serialize (hb_serialize_context_t *c,
+ Iterator it,
+ ValueFormat valFormat);
+
struct AnchorFormat1
{
@@ -496,11 +501,52 @@
return_trace (true);
}
+ template<typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ void serialize (hb_serialize_context_t *c,
+ Iterator it,
+ ValueFormat valFormat)
+ {
+ if (unlikely (!c->extend_min (*this))) return;
+ if (unlikely (!c->check_assign (valueFormat, valFormat))) return;
+
+ auto vals = hb_second (*it);
+
+ + vals
+ | hb_apply ([=] (const Value& _)
+ {
+ c->copy (_);
+ })
+ ;
+
+ auto glyphs =
+ + it
+ | hb_map_retains_sorting (hb_first)
+ ;
+
+ coverage.serialize (c, this).serialize (c, glyphs);
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- // TODO(subset)
- return_trace (false);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ unsigned length = valueFormat.get_len ();
+
+ auto it =
+ + hb_iter (this+coverage)
+ | hb_filter (glyphset)
+ | hb_map_retains_sorting ([&] (hb_codepoint_t p)
+ {
+ return hb_pair (glyph_map[p], values.as_array (length));
+ })
+ ;
+
+ bool ret = bool (it);
+ SinglePos_serialize (c->serializer, it, valueFormat);
+ return_trace (ret);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -552,11 +598,58 @@
return_trace (true);
}
+ template<typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ void serialize (hb_serialize_context_t *c,
+ Iterator it,
+ ValueFormat valFormat)
+ {
+ if (unlikely (!c->extend_min (*this))) return;
+ if (unlikely (!c->check_assign (valueFormat, valFormat))) return;
+ if (unlikely (!c->check_assign (valueCount, it.len ()))) return;
+
+ + it
+ | hb_map (hb_second)
+ | hb_apply ([=] (hb_array_t<const Value> val_iter)
+ {
+ + val_iter
+ | hb_apply ([=] (const Value& _)
+ {
+ c->copy (_);
+ })
+ ;
+ })
+ ;
+
+ auto glyphs =
+ + it
+ | hb_map_retains_sorting (hb_first)
+ ;
+
+ coverage.serialize (c, this).serialize (c, glyphs);
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- // TODO(subset)
- return_trace (false);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ unsigned sub_length = valueFormat.get_len ();
+ unsigned total_length = (unsigned)valueCount * sub_length;
+
+ auto it =
+ + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
+ | hb_filter (glyphset, hb_first)
+ | hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _)
+ {
+ return hb_pair (glyph_map[_.first], values.as_array (total_length).sub_array (_.second * sub_length, sub_length));
+ })
+ ;
+
+ bool ret = bool (it);
+ SinglePos_serialize (c->serializer, it, valueFormat);
+ return_trace (ret);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -583,6 +676,55 @@
struct SinglePos
{
+ template<typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ unsigned get_format (Iterator glyph_val_iter_pairs)
+ {
+ unsigned subset_format = 1;
+ hb_array_t<const Value> first_val_iter = hb_second (*glyph_val_iter_pairs);
+
+ + glyph_val_iter_pairs
+ | hb_map (hb_second)
+ | hb_apply ([&] (hb_array_t<const Value> val_iter)
+ {
+ + hb_zip (val_iter, first_val_iter)
+ | hb_apply ([&] (const hb_pair_t<Value, Value>& _)
+ {
+ if (_.first != _.second)
+ {
+ subset_format = 2;
+ return;
+ }
+ })
+ ;
+ })
+ ;
+
+ return subset_format;
+ }
+
+
+ template<typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ void serialize (hb_serialize_context_t *c,
+ Iterator glyph_val_iter_pairs,
+ ValueFormat valFormat)
+ {
+ if (unlikely (!c->extend_min (u.format))) return;
+ unsigned format = 2;
+
+ if (glyph_val_iter_pairs) format = get_format (glyph_val_iter_pairs);
+
+ u.format = format;
+ switch (u.format) {
+ case 1: u.format1.serialize (c, glyph_val_iter_pairs, valFormat);
+ return;
+ case 2: u.format2.serialize (c, glyph_val_iter_pairs, valFormat);
+ return;
+ default:return;
+ }
+ }
+
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
@@ -603,6 +745,13 @@
} u;
};
+template<typename Iterator>
+static inline void
+SinglePos_serialize (hb_serialize_context_t *c,
+ Iterator it,
+ ValueFormat valFormat)
+{ c->start_embed<SinglePos> ()->serialize (c, it, valFormat); }
+
struct PairValueRecord
{