[subset] Assemble font
diff --git a/src/hb-open-file-private.hh b/src/hb-open-file-private.hh
index 762783f..6317239 100644
--- a/src/hb-open-file-private.hh
+++ b/src/hb-open-file-private.hh
@@ -56,6 +56,13 @@
   int cmp (Tag t) const
   { return t.cmp (tag); }
 
+  static int cmp (const void *pa, const void *pb)
+  {
+    const TableRecord *a = (const TableRecord *) pa;
+    const TableRecord *b = (const TableRecord *) pb;
+    return b->cmp (a->tag);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -64,7 +71,7 @@
 
   Tag		tag;		/* 4-byte identifier. */
   CheckSum	checkSum;	/* CheckSum for this table. */
-  HBUINT32	offset;		/* Offset from beginning of TrueType font
+  Offset32	offset;		/* Offset from beginning of TrueType font
 				 * file. */
   HBUINT32	length;		/* Length of this table. */
   public:
@@ -118,6 +125,35 @@
   }
 
   public:
+
+  inline bool serialize (hb_serialize_context_t *c,
+			 hb_tag_t sfnt_tag,
+			 Supplier<hb_tag_t> &tags,
+			 Supplier<hb_blob_t *> &blobs,
+			 unsigned int table_count)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    sfnt_version.set (sfnt_tag);
+    if (unlikely (!tables.serialize (c, table_count))) return_trace (false);
+    for (unsigned int i = 0; i < table_count; i++)
+    {
+      TableRecord &rec = tables.array[i];
+      hb_blob_t *blob = blobs[i];
+      rec.tag.set (tags[0]);
+      rec.length.set (hb_blob_get_length (blob));
+      rec.checkSum.set_for_data (hb_blob_get_data (blob, nullptr), rec.length);
+      rec.offset.serialize (c, this);
+      void *p = c->allocate_size<void> (rec.length);
+      if (unlikely (!p)) return false;
+      memcpy (p, hb_blob_get_data (blob, nullptr), rec.length);
+      if (rec.length % 4)
+	p = c->allocate_size<void> (4 - rec.length % 4);
+    }
+    tables.qsort ();
+    return_trace (true);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -249,6 +285,18 @@
     }
   }
 
+  inline bool serialize_single (hb_serialize_context_t *c,
+				hb_tag_t sfnt_tag,
+			        Supplier<hb_tag_t> &tags,
+			        Supplier<hb_blob_t *> &blobs,
+			        unsigned int table_count)
+  {
+    TRACE_SERIALIZE (this);
+    assert (sfnt_tag != TTCTag);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    return_trace (u.fontFace.serialize (c, sfnt_tag, tags, blobs, table_count));
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index 04e4a4e..be3ecb4 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -499,15 +499,16 @@
 template <typename Type>
 struct Supplier
 {
-  inline Supplier (const Type *array, unsigned int len_)
+  inline Supplier (const Type *array, unsigned int len_, unsigned int stride_=sizeof(Type))
   {
     head = array;
     len = len_;
+    stride = stride_;
   }
   inline const Type operator [] (unsigned int i) const
   {
     if (unlikely (i >= len)) return Type ();
-    return head[i];
+    return * (const Type *) ((const char *) head + stride * i);
   }
 
   inline void advance (unsigned int count)
@@ -515,7 +516,7 @@
     if (unlikely (count > len))
       count = len;
     len -= count;
-    head += count;
+    head = (const Type *) ((const char *) head + stride * count);
   }
 
   private:
@@ -523,6 +524,7 @@
   inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */
 
   unsigned int len;
+  unsigned int stride;
   const Type *head;
 };
 
@@ -717,6 +719,13 @@
   inline bool is_null (void) const { return 0 == *this; }
   public:
   DEFINE_SIZE_STATIC (sizeof(Type));
+
+  inline void *serialize (hb_serialize_context_t *c, const void *base)
+  {
+    void *t = c->start_embed<void> ();
+    this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
+    return t;
+  }
 };
 
 typedef Offset<HBUINT16> Offset16;
@@ -786,9 +795,7 @@
 
   inline Type& serialize (hb_serialize_context_t *c, const void *base)
   {
-    Type *t = c->start_embed<Type> ();
-    this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
-    return *t;
+    return * (Type *) Offset<OffsetType>::serialize (c, base);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
@@ -928,6 +935,11 @@
     return -1;
   }
 
+  inline void qsort (void)
+  {
+    ::qsort (array, len, sizeof (Type), Type::cmp);
+  }
+
   private:
   inline bool sanitize_shallow (hb_sanitize_context_t *c) const
   {
@@ -1072,6 +1084,15 @@
     return_trace (c->check_struct (this));
   }
 
+  inline void set (unsigned int v)
+  {
+    len.set (v);
+    assert (len == v);
+    entrySelectorZ.set (MAX (1u, _hb_bit_storage (v)) - 1);
+    searchRangeZ.set (16 * (1u << entrySelectorZ));
+    rangeShiftZ.set (16 * MAX (0, (int) v - searchRangeZ));
+  }
+
   protected:
   HBUINT16	len;
   HBUINT16	searchRangeZ;
diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index a80ac72..e6bd8ea 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -84,28 +84,28 @@
   inline hb_mask_t get_global_mask (void) const { return global_mask; }
 
   inline hb_mask_t get_mask (hb_tag_t feature_tag, unsigned int *shift = nullptr) const {
-    const feature_map_t *map = features.bsearch (&feature_tag);
+    const feature_map_t *map = features.bsearch (feature_tag);
     if (shift) *shift = map ? map->shift : 0;
     return map ? map->mask : 0;
   }
 
   inline bool needs_fallback (hb_tag_t feature_tag) const {
-    const feature_map_t *map = features.bsearch (&feature_tag);
+    const feature_map_t *map = features.bsearch (feature_tag);
     return map ? map->needs_fallback : false;
   }
 
   inline hb_mask_t get_1_mask (hb_tag_t feature_tag) const {
-    const feature_map_t *map = features.bsearch (&feature_tag);
+    const feature_map_t *map = features.bsearch (feature_tag);
     return map ? map->_1_mask : 0;
   }
 
   inline unsigned int get_feature_index (unsigned int table_index, hb_tag_t feature_tag) const {
-    const feature_map_t *map = features.bsearch (&feature_tag);
+    const feature_map_t *map = features.bsearch (feature_tag);
     return map ? map->index[table_index] : HB_OT_LAYOUT_NO_FEATURE_INDEX;
   }
 
   inline unsigned int get_feature_stage (unsigned int table_index, hb_tag_t feature_tag) const {
-    const feature_map_t *map = features.bsearch (&feature_tag);
+    const feature_map_t *map = features.bsearch (feature_tag);
     return map ? map->stage[table_index] : (unsigned int) -1;
   }
 
diff --git a/src/hb-private.hh b/src/hb-private.hh
index 75cc38f..118f292 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -380,6 +380,12 @@
   return (size > 0) && (count >= ((unsigned int) -1) / size);
 }
 
+static inline unsigned int
+_hb_ceil_to_4 (unsigned int v)
+{
+  return ((v - 1) & 3) + 1;
+}
+
 
 
 /* arrays and maps */
@@ -493,34 +499,34 @@
   }
 
   template <typename T>
-  inline Type *lsearch (T *x)
+  inline Type *lsearch (const T &x)
   {
     for (unsigned int i = 0; i < len; i++)
-      if (0 == this->array[i].cmp (x))
+      if (0 == this->array[i].cmp (&x))
 	return &array[i];
     return nullptr;
   }
 
   template <typename T>
-  inline Type *bsearch (T *x)
+  inline Type *bsearch (const T &x)
   {
     unsigned int i;
     return bfind (x, &i) ? &array[i] : nullptr;
   }
   template <typename T>
-  inline const Type *bsearch (T *x) const
+  inline const Type *bsearch (const T &x) const
   {
     unsigned int i;
     return bfind (x, &i) ? &array[i] : nullptr;
   }
   template <typename T>
-  inline bool bfind (T *x, unsigned int *i) const
+  inline bool bfind (const T &x, unsigned int *i) const
   {
     int min = 0, max = (int) this->len - 1;
     while (min <= max)
     {
       int mid = (min + max) / 2;
-      int c = this->array[mid].cmp (x);
+      int c = this->array[mid].cmp (&x);
       if (c < 0)
         max = mid - 1;
       else if (c > 0)
@@ -531,7 +537,7 @@
 	return true;
       }
     }
-    if (max < 0 || (max < (int) this->len && this->array[max].cmp (x) > 0))
+    if (max < 0 || (max < (int) this->len && this->array[max].cmp (&x) > 0))
       max++;
     *i = max;
     return false;
diff --git a/src/hb-set-private.hh b/src/hb-set-private.hh
index 54dd610..d71d412 100644
--- a/src/hb-set-private.hh
+++ b/src/hb-set-private.hh
@@ -470,7 +470,7 @@
 
     page_map_t map = {get_major (*codepoint), 0};
     unsigned int i;
-    page_map.bfind (&map, &i);
+    page_map.bfind (map, &i);
     if (i < page_map.len)
     {
       if (pages[page_map[i].index].next (codepoint))
@@ -541,7 +541,7 @@
   {
     page_map_t map = {get_major (g), pages.len};
     unsigned int i;
-    if (!page_map.bfind (&map, &i))
+    if (!page_map.bfind (map, &i))
     {
       if (!resize (pages.len + 1))
 	return nullptr;
@@ -555,7 +555,7 @@
   inline page_t *page_for (hb_codepoint_t g)
   {
     page_map_t key = {get_major (g)};
-    const page_map_t *found = page_map.bsearch (&key);
+    const page_map_t *found = page_map.bsearch (key);
     if (found)
       return &pages[found->index];
     return nullptr;
@@ -563,7 +563,7 @@
   inline const page_t *page_for (hb_codepoint_t g) const
   {
     page_map_t key = {get_major (g)};
-    const page_map_t *found = page_map.bsearch (&key);
+    const page_map_t *found = page_map.bsearch (key);
     if (found)
       return &pages[found->index];
     return nullptr;
diff --git a/src/hb-subset.cc b/src/hb-subset.cc
index f9119c3..ed4394d 100644
--- a/src/hb-subset.cc
+++ b/src/hb-subset.cc
@@ -32,6 +32,7 @@
 #include "hb-subset-private.hh"
 #include "hb-subset-plan.hh"
 
+#include "hb-open-file-private.hh"
 #include "hb-ot-glyf-table.hh"
 
 
@@ -142,21 +143,59 @@
 {
   hb_subset_face_data_t *data = (hb_subset_face_data_t *) user_data;
 
+  data->tables.finish ();
+
   free (data);
 }
 
 static hb_blob_t *
+_hb_subset_face_data_reference_blob (hb_subset_face_data_t *data)
+{
+
+  unsigned int table_count = data->tables.len;
+  unsigned int face_length = table_count * 16 + 12;
+
+  for (unsigned int i = 0; i < table_count; i++)
+    face_length += _hb_ceil_to_4 (hb_blob_get_length (data->tables.array[i].blob));
+
+  char *buf = (char *) malloc (face_length);
+  if (unlikely (!buf))
+    return nullptr;
+
+  OT::hb_serialize_context_t c (buf, face_length);
+  OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
+
+  bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
+  hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
+
+  OT::Supplier<hb_tag_t>    tags_supplier  (&data->tables[0].tag, table_count, sizeof (data->tables[0]));
+  OT::Supplier<hb_blob_t *> blobs_supplier (&data->tables[0].blob, table_count, sizeof (data->tables[0]));
+  bool ret = f->serialize_single (&c,
+				  sfnt_tag,
+				  tags_supplier,
+				  blobs_supplier,
+				  table_count);
+
+  c.end_serialize ();
+
+  if (unlikely (!ret))
+  {
+    free (buf);
+    return nullptr;
+  }
+
+  return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);
+}
+
+static hb_blob_t *
 _hb_subset_face_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data)
 {
   hb_subset_face_data_t *data = (hb_subset_face_data_t *) user_data;
 
   if (!tag)
-  {
-    /* TODO Compile face blob... */
-    return nullptr;
-  }
+    return _hb_subset_face_data_reference_blob (data);
 
-  hb_subset_face_data_t::table_entry_t *entry = data->tables.lsearch (&tag);
+  hb_subset_face_data_t::table_entry_t *entry = data->tables.lsearch (tag);
   if (entry)
     return hb_blob_reference (entry->blob);
 
@@ -182,7 +221,7 @@
 
   hb_subset_face_data_t *data = (hb_subset_face_data_t *) face->user_data;
 
-  hb_subset_face_data_t::table_entry_t *entry = data->tables.lsearch (&tag);
+  hb_subset_face_data_t::table_entry_t *entry = data->tables.lsearch (tag);
   if (unlikely (!entry))
     return false;