[subset] fixed GPOS device table sanitize & serialize (#2087)
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 32c9c5e..c469366 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -155,6 +155,22 @@
return ret;
}
+ void serialize_copy (hb_serialize_context_t *c, const void *src_base, const void *dst_base, const Value *values) const
+ {
+ unsigned int format = *this;
+ if (!format) return;
+
+ if (format & xPlacement) c->copy (*values++);
+ if (format & yPlacement) c->copy (*values++);
+ if (format & xAdvance) c->copy (*values++);
+ if (format & yAdvance) c->copy (*values++);
+
+ if (format & xPlaDevice) copy_device (c, src_base, dst_base, values++);
+ if (format & yPlaDevice) copy_device (c, src_base, dst_base, values++);
+ if (format & xAdvDevice) copy_device (c, src_base, dst_base, values++);
+ if (format & yAdvDevice) copy_device (c, src_base, dst_base, values++);
+ }
+
private:
bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
{
@@ -173,6 +189,27 @@
return true;
}
+ bool copy_device (hb_serialize_context_t *c, const void *src_base, const void *dst_base, const Value *src_value) const
+ {
+ Value *dst_value = c->copy (*src_value);
+
+ if (!dst_value) return false;
+ if (*dst_value == 0) return true;
+
+ *dst_value = 0;
+ c->push ();
+ if ((src_base + get_device (src_value)).copy (c))
+ {
+ c->add_link (*dst_value, c->pop_pack (), dst_base);
+ return true;
+ }
+ else
+ {
+ c->pop_discard ();
+ return false;
+ }
+ }
+
static inline OffsetTo<Device>& get_device (Value* value)
{
return *static_cast<OffsetTo<Device> *> (value);
@@ -240,6 +277,7 @@
template<typename Iterator>
static void SinglePos_serialize (hb_serialize_context_t *c,
+ const void *src,
Iterator it,
ValueFormat valFormat);
@@ -542,13 +580,19 @@
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
+ const void *src,
Iterator it,
ValueFormat valFormat)
{
- if (unlikely (!c->extend_min (*this))) return;
+ auto out = c->extend_min (*this);
+ if (unlikely (!out)) return;
if (unlikely (!c->check_assign (valueFormat, valFormat))) return;
- c->copy_all (hb_second (*it));
+ + it
+ | hb_map (hb_second)
+ | hb_apply ([&] (hb_array_t<const Value> _)
+ { valFormat.serialize_copy (c, src, out, &_); })
+ ;
auto glyphs =
+ it
@@ -572,7 +616,7 @@
;
bool ret = bool (it);
- SinglePos_serialize (c->serializer, it, valueFormat);
+ SinglePos_serialize (c->serializer, this, it, valueFormat);
return_trace (ret);
}
@@ -630,14 +674,20 @@
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
+ const void *src,
Iterator it,
ValueFormat valFormat)
{
- if (unlikely (!c->extend_min (*this))) return;
+ auto out = c->extend_min (*this);
+ if (unlikely (!out)) return;
if (unlikely (!c->check_assign (valueFormat, valFormat))) return;
if (unlikely (!c->check_assign (valueCount, it.len ()))) return;
- for (auto iter : it) c->copy_all (iter.second);
+ + it
+ | hb_map (hb_second)
+ | hb_apply ([&] (hb_array_t<const Value> _)
+ { valFormat.serialize_copy (c, src, out, &_); })
+ ;
auto glyphs =
+ it
@@ -668,7 +718,7 @@
;
bool ret = bool (it);
- SinglePos_serialize (c->serializer, it, valueFormat);
+ SinglePos_serialize (c->serializer, this, it, valueFormat);
return_trace (ret);
}
@@ -714,6 +764,7 @@
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
+ const void *src,
Iterator glyph_val_iter_pairs,
ValueFormat valFormat)
{
@@ -724,9 +775,9 @@
u.format = format;
switch (u.format) {
- case 1: u.format1.serialize (c, glyph_val_iter_pairs, valFormat);
+ case 1: u.format1.serialize (c, src, glyph_val_iter_pairs, valFormat);
return;
- case 2: u.format2.serialize (c, glyph_val_iter_pairs, valFormat);
+ case 2: u.format2.serialize (c, src, glyph_val_iter_pairs, valFormat);
return;
default:return;
}
@@ -755,9 +806,10 @@
template<typename Iterator>
static void
SinglePos_serialize (hb_serialize_context_t *c,
+ const void *src,
Iterator it,
ValueFormat valFormat)
-{ c->start_embed<SinglePos> ()->serialize (c, it, valFormat); }
+{ c->start_embed<SinglePos> ()->serialize (c, src, it, valFormat); }
struct PairValueRecord
@@ -767,16 +819,28 @@
int cmp (hb_codepoint_t k) const
{ return secondGlyph.cmp (k); }
+ struct serialize_closure_t
+ {
+ const void *src_base;
+ void *dst_base;
+ const ValueFormat *valueFormats;
+ unsigned len1; /* valueFormats[0].get_len() */
+ const hb_map_t *glyph_map;
+ };
+
bool serialize (hb_serialize_context_t *c,
- unsigned length,
- const hb_map_t &glyph_map) const
+ serialize_closure_t *closure) const
{
TRACE_SERIALIZE (this);
auto *out = c->start_embed (*this);
if (unlikely (!c->extend_min (out))) return_trace (false);
- out->secondGlyph = glyph_map[secondGlyph];
- return_trace (c->copy (values, length));
+ out->secondGlyph = (*closure->glyph_map)[secondGlyph];
+
+ closure->valueFormats[0].serialize_copy (c, closure->src_base, closure->dst_base, &values[0]);
+ closure->valueFormats[1].serialize_copy (c, closure->src_base, closure->dst_base, &values[closure->len1]);
+
+ return_trace (true);
}
protected:
@@ -867,12 +931,21 @@
unsigned len2 = valueFormats[1].get_len ();
unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
+ PairValueRecord::serialize_closure_t closure =
+ {
+ this,
+ out,
+ valueFormats,
+ len1,
+ &glyph_map
+ };
+
const PairValueRecord *record = &firstPairValueRecord;
unsigned count = len, num = 0;
for (unsigned i = 0; i < count; i++)
{
if (!glyphset.has (record->secondGlyph)) continue;
- if (record->serialize (c->serializer, len1 + len2, glyph_map)) num++;
+ if (record->serialize (c->serializer, &closure)) num++;
record = &StructAtOffset<const PairValueRecord> (record, record_size);
}
@@ -1005,7 +1078,7 @@
unsigned int len2 = valueFormat[1].get_len ();
PairSet::sanitize_closure_t closure =
{
- this,
+ &pairSet,
valueFormat,
len1,
1 + len1 + len2
@@ -1099,7 +1172,8 @@
out->classDef2.serialize_subset (c, classDef2, this, out, &klass2_map);
out->class2Count = klass2_map.get_population ();
- unsigned record_len = valueFormat1.get_len () + valueFormat2.get_len ();
+ unsigned len1 = valueFormat1.get_len ();
+ unsigned len2 = valueFormat2.get_len ();
+ hb_range ((unsigned) class1Count)
| hb_filter (klass1_map)
@@ -1109,9 +1183,9 @@
| hb_filter (klass2_map)
| hb_apply ([&] (const unsigned class2_idx)
{
- unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_len;
- for (unsigned i = 0; i < record_len; i++)
- c->serializer->copy (values[idx+i]);
+ unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+ valueFormat1.serialize_copy (c->serializer, this, out, &values[idx]);
+ valueFormat2.serialize_copy (c->serializer, this, out, &values[idx + len1]);
})
;
})