[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]);
                               })
                   ;
                 })