[subset] subsetting cmap14
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index c4cbd06..7678180 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -676,6 +676,70 @@
     }
   }
 
+  DefaultUVS* copy (hb_serialize_context_t *c,
+                    const hb_set_t *unicodes) const
+  {
+    DefaultUVS *out = c->start_embed<DefaultUVS> ();
+    if (unlikely (!out)) return nullptr;
+    auto snap = c->snapshot ();
+
+    HBUINT32 len;
+    len = 0;
+    if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
+    unsigned init_len = c->length ();
+
+    hb_codepoint_t lastCode = HB_MAP_VALUE_INVALID;
+    int count = -1;
+
+    + as_array ()
+    | hb_apply ([&] (const UnicodeValueRange& _)
+                {
+                  + hb_range ((unsigned)_.additionalCount + 1)
+                  | hb_apply ([&] (const unsigned addcnt)
+                              {
+                                unsigned curEntry = (unsigned)_.startUnicodeValue + addcnt;
+                                if (hb_set_has (unicodes, curEntry))
+                                {
+                                  count += 1;
+                                  if (lastCode == HB_MAP_VALUE_INVALID)
+                                  {
+                                    lastCode = curEntry;
+                                  } else if (lastCode + count != curEntry)
+                                  {
+                                    UnicodeValueRange rec;
+                                    rec.startUnicodeValue = lastCode;
+                                    rec.additionalCount = count - 1;
+                                    c->copy<UnicodeValueRange> (rec);
+  
+                                    lastCode = curEntry;
+                                    count = 0;
+                                  }
+                                }
+                              })
+                  ;
+                })
+    ;
+
+    if (lastCode != HB_MAP_VALUE_INVALID)
+    {
+      UnicodeValueRange rec;
+      rec.startUnicodeValue = lastCode;
+      rec.additionalCount = count;
+      c->copy<UnicodeValueRange> (rec);
+    }
+
+    if (c->length () - init_len == 0)
+    {
+      c->revert (snap);
+      return nullptr;
+    }
+    else
+    {
+      if (unlikely (!c->check_assign (out->len, (c->length () - init_len) / UnicodeValueRange::static_size))) return nullptr;
+      return out;
+    }
+  }
+
   public:
   DEFINE_SIZE_ARRAY (4, *this);
 };
@@ -718,6 +782,41 @@
     ;
   }
 
+  NonDefaultUVS* copy (hb_serialize_context_t *c,
+                       const hb_set_t *unicodes,
+                       const hb_set_t *glyphs,
+                       const hb_map_t *glyph_map) const
+  {
+    NonDefaultUVS *out = c->start_embed<NonDefaultUVS> ();
+    if (unlikely (!out)) return nullptr;
+
+    auto it =
+    + as_array ()
+    | hb_filter ([&] (const UVSMapping& _)
+                 {
+                   return hb_set_has (unicodes, _.unicodeValue) || hb_set_has (glyphs, _.glyphID);
+                 })
+    ;
+
+    if (!it) return nullptr;
+
+    HBUINT32 len;
+    len = it.len ();
+    if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
+
+    + it
+    | hb_apply ([&] (const UVSMapping& _)
+                {
+                  UVSMapping mapping;
+                  mapping.unicodeValue = _.unicodeValue;
+                  mapping.glyphID = glyph_map->get (_.glyphID);
+                  c->copy<UVSMapping> (mapping);
+                })
+    ;
+
+    return out;
+  }
+
   public:
   DEFINE_SIZE_ARRAY (4, *this);
 };
@@ -758,6 +857,52 @@
 		  nonDefaultUVS.sanitize (c, base));
   }
 
+  VariationSelectorRecord* copy (hb_serialize_context_t *c,
+                                 const hb_set_t *unicodes,
+                                 const hb_set_t *glyphs,
+                                 const hb_map_t *glyph_map,
+                                 const void *src_base,
+                                 const void *dst_base) const
+  {
+    auto snap = c->snapshot ();
+    auto *out = c->embed<VariationSelectorRecord> (*this);
+    if (unlikely (!out)) return nullptr;
+    
+    out->defaultUVS = 0;
+    out->nonDefaultUVS = 0;
+
+    bool drop = true;
+
+    if (defaultUVS != 0)
+    {
+      c->push ();
+      if (c->copy (src_base+defaultUVS, unicodes))
+      {
+        c->add_link (out->defaultUVS, c->pop_pack (), dst_base);
+        drop = false;
+      }
+      else c->pop_discard ();
+    }
+
+    if (nonDefaultUVS != 0)
+    {
+      c->push ();
+      if (c->copy (src_base+nonDefaultUVS, unicodes, glyphs, glyph_map))
+      {
+        c->add_link (out->nonDefaultUVS, c->pop_pack (), dst_base);
+        drop = false;
+      }
+      else c->pop_discard ();
+    }
+
+    if (drop)
+    {
+      c->revert (snap);
+      return nullptr;
+    }
+    else return out;
+  }
+
   HBUINT24	varSelector;	/* Variation selector. */
   LOffsetTo<DefaultUVS>
 		defaultUVS;	/* Offset to Default UVS Table.  May be 0. */
@@ -788,11 +933,44 @@
     record.bsearch (variation_selector).collect_unicodes (out, this);
   }
 
+  void serialize (hb_serialize_context_t *c,
+                  const hb_set_t *unicodes,
+                  const hb_set_t *glyphs,
+                  const hb_map_t *glyph_map,
+                  const void *src_base)
+  {
+    auto snap = c->snapshot ();
+    unsigned table_initpos = c->length ();
+    const char* init_tail = c->tail;
+
+    if (unlikely (!c->extend_min (*this))) return;
+    this->format = 14;
+
+    const CmapSubtableFormat14 *src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (src_base);
+    + hb_iter (src_tbl->record)
+    | hb_apply ([&] (const VariationSelectorRecord& _)
+                {
+                  c->copy (_, unicodes, glyphs, glyph_map, src_base, this);
+                })
+    ;
+
+    if (c->length () - table_initpos ==  CmapSubtableFormat14::min_size)
+    {
+      c->revert (snap);
+    }
+    else
+    {
+      int tail_len = init_tail - c->tail;
+      c->check_assign (this->length, c->length () - table_initpos + tail_len);
+      c->check_assign (this->record.len, (c->length () - table_initpos - CmapSubtableFormat14::min_size) / VariationSelectorRecord::static_size);
+    }
+  }
+
   void closure_glyphs (const hb_set_t      *unicodes,
                        hb_set_t            *glyphset) const
   {
     + hb_iter (record)
-    | hb_filter ([&] (const VariationSelectorRecord& _) { return _.nonDefaultUVS != 0 && hb_set_has (unicodes, _.varSelector); })
+    | hb_filter ([&] (const VariationSelectorRecord& _) { return _.nonDefaultUVS != 0; })
     | hb_map (&VariationSelectorRecord::nonDefaultUVS)
     | hb_map (hb_add (this))
     | hb_apply ([=] (const NonDefaultUVS& _) { _.closure_glyphs (unicodes, glyphset); })
@@ -852,11 +1030,16 @@
 	   hb_requires (hb_is_iterator (Iterator))>
   void serialize (hb_serialize_context_t *c,
 		  Iterator it,
-		  unsigned format)
+                  unsigned format,
+                  const hb_set_t *unicodes,
+                  const hb_set_t *glyphs,
+                  const hb_map_t *glyph_map,
+                  const void *src_base)
   {
     switch (format) {
     case  4: u.format4.serialize (c, it);  return;
     case 12: u.format12.serialize (c, it); return;
+    case 14: u.format14.serialize (c, unicodes, glyphs, glyph_map, src_base); return;
     default: return;
     }
   }
@@ -915,12 +1098,17 @@
   template<typename Iterator,
 	   hb_requires (hb_is_iterator (Iterator))>
   EncodingRecord* copy (hb_serialize_context_t *c,
-			Iterator it,
-			unsigned format,
-			void *base,
-			/* INOUT */ unsigned *objidx) const
+                        Iterator it,
+                        unsigned format,
+                        const void *src_base,
+                        const void *dst_base,
+                        /* INOUT */ unsigned *objidx,
+                        const hb_set_t *unicodes,
+                        const hb_set_t *glyphs,
+                        const hb_map_t *glyph_map) const
   {
     TRACE_SERIALIZE (this);
+    auto snap = c->snapshot ();
     auto *out = c->embed (this);
     if (unlikely (!out)) return_trace (nullptr);
     out->subtable = 0;
@@ -929,13 +1117,21 @@
     {
       CmapSubtable *cmapsubtable = c->push<CmapSubtable> ();
       unsigned origin_length = c->length ();
-      cmapsubtable->serialize (c, it, format);
+      cmapsubtable->serialize (c, it, format, unicodes, glyphs, glyph_map, &(src_base+subtable));
       if (c->length () - origin_length > 0) *objidx = c->pop_pack ();
       else c->pop_discard ();
     }
 
-    c->add_link (out->subtable, *objidx, base);
-    return_trace (out);
+    if (*objidx == 0)
+    {
+      c->revert (snap);
+      return_trace (nullptr);
+    }
+    else
+    {
+      c->add_link (out->subtable, *objidx, dst_base);
+      return_trace (out);
+    }
   }
 
   HBUINT16	platformID;	/* Platform ID. */
@@ -950,27 +1146,33 @@
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
 
-  template<typename Iterator,
-	   hb_requires (hb_is_iterator (Iterator))>
+  template<typename Iterator, typename EncodingRecIter,
+           hb_requires (hb_is_iterator (Iterator))>
   void serialize (hb_serialize_context_t *c,
-		  Iterator it,
-		  const EncodingRecord *unicode_bmp,
-		  const EncodingRecord *unicode_ucs4,
-		  const EncodingRecord *ms_bmp,
-		  const EncodingRecord *ms_ucs4)
+                  Iterator it,
+                  EncodingRecIter encodingrec_iter,
+                  const void *src_base,
+                  const hb_set_t *unicodes,
+                  const hb_set_t *glyphs,
+                  const hb_map_t *glyph_map)
   {
     if (unlikely (!c->extend_min ((*this))))  return;
     this->version = 0;
 
-    unsigned numTables = (unicode_bmp ? 1 : 0) + (unicode_ucs4 ? 1 : 0) + (ms_bmp ? 1 : 0) + (ms_ucs4 ? 1 : 0);
-    if (unlikely (!c->check_assign(this->encodingRecord.len, numTables))) return;
+    unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
 
-    unsigned format4objidx = 0, format12objidx = 0;
-    if (unicode_bmp) c->copy (unicode_bmp, it, 4u, this, &format4objidx);
-    if (unicode_ucs4) c->copy (unicode_ucs4, it, 12u, this, &format12objidx);
-    if (ms_bmp) c->copy (ms_bmp, it, 4u, this, &format4objidx);
-    if (ms_ucs4) c->copy (ms_ucs4, it, 12u, this, &format12objidx);
+    + encodingrec_iter
+    | hb_apply ([&] (const EncodingRecord& _)
+                {
+                  unsigned format = (src_base+_.subtable).u.format;
 
+                  if (format == 4) c->copy (_, it, 4u, src_base, this, &format4objidx, unicodes, glyphs, glyph_map);
+                  else if (format == 12) c->copy (_, it, 12u, src_base, this, &format12objidx, unicodes, glyphs, glyph_map);
+                  else if (format == 14) c->copy (_, it, 14u, src_base, this, &format14objidx, unicodes, glyphs, glyph_map);
+                })
+    ;
+
+    c->check_assign(this->encodingRecord.len, (c->length () - cmap::min_size)/EncodingRecord::static_size);
   }
 
   void closure_glyphs (const hb_set_t      *unicodes,
@@ -991,12 +1193,45 @@
     cmap *cmap_prime = c->serializer->start_embed<cmap> ();
     if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false);
 
-    const EncodingRecord *unicode_bmp = find_encodingrec (0, 3);
-    const EncodingRecord *unicode_ucs4 = find_encodingrec (0, 4);
-    const EncodingRecord *ms_bmp = find_encodingrec (3, 1);
-    const EncodingRecord *ms_ucs4 = find_encodingrec (3, 10);
-    bool has_format12 = find_subtable (12);
+    const EncodingRecord *unicode_bmp= nullptr, *unicode_ucs4 = nullptr, *ms_bmp = nullptr, *ms_ucs4 = nullptr;
+    bool has_format12 = false, has_format14 = false;
+   
+    auto encodingrec_iter =
+    + hb_iter (encodingRecord)
+    | hb_filter ([&] (const EncodingRecord& _)
+              {
+                unsigned format = (this + _.subtable).u.format;
+                if (format == 12) has_format12 = true;
+                if (format == 14) has_format14 = true;
 
+                const EncodingRecord *table = hb_addressof (_);
+                if (_.platformID == 0 && _.encodingID == 3)
+                {
+                  unicode_bmp = table;
+                  return true;
+                }
+                else if (_.platformID == 0 && _.encodingID == 4)
+                {
+                  unicode_ucs4 = table;
+                  return true;
+                }
+                else if (_.platformID == 3 && _.encodingID == 1)
+                {
+                  ms_bmp = table;
+                  return true;
+                }
+                else if (_.platformID == 3 && _.encodingID == 10)
+                {
+                  ms_ucs4 = table;
+                  return true;
+                }
+                else if (format == 14) return true;
+                else return false;
+              })
+    ;
+    
+    
+    if (unlikely (!encodingrec_iter.len ())) return_trace (false);
     if (unlikely (!unicode_bmp && !ms_bmp)) return_trace (false);
     if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false);
 
@@ -1014,7 +1249,7 @@
 	      })
     ;
 
-    cmap_prime->serialize (c->serializer, it, unicode_bmp, unicode_ucs4, ms_bmp, ms_ucs4);
+    cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan->unicodes, c->plan->_glyphset, c->plan->glyph_map);
     return_trace (true);
   }