Merge branch 'master' into cff-subset
diff --git a/NEWS b/NEWS
index cb8a28f..04579d6 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,11 @@
+Overview of changes leading to 2.1.1
+Monday, November 5, 2018
+====================================
+- AAT improvements:
+  o Implement 'mort' table.
+  o Implement 'kern' subtables Format 1 and Format 3.
+
+
 Overview of changes leading to 2.1.0
 Tuesday, October 30, 2018
 ====================================
diff --git a/configure.ac b/configure.ac
index 21d48f3..48ee9ce 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [2.1.0],
+        [2.1.1],
         [https://github.com/harfbuzz/harfbuzz/issues/new],
         [harfbuzz],
         [http://harfbuzz.org/])
diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh
index d2242c5..ca2fdb4 100644
--- a/src/hb-aat-layout-kerx-table.hh
+++ b/src/hb-aat-layout-kerx-table.hh
@@ -637,12 +637,12 @@
     unsigned int subtable_type = get_type ();
     TRACE_DISPATCH (this, subtable_type);
     switch (subtable_type) {
-    case 0	:		return_trace (c->dispatch (u.format0));
-    case 1	:		return_trace (c->dispatch (u.format1));
-    case 2	:		return_trace (c->dispatch (u.format2));
-    case 4	:		return_trace (c->dispatch (u.format4));
-    case 6	:		return_trace (c->dispatch (u.format6));
-    default:			return_trace (c->default_return_value ());
+    case 0:	return_trace (c->dispatch (u.format0));
+    case 1:	return_trace (c->dispatch (u.format1));
+    case 2:	return_trace (c->dispatch (u.format2));
+    case 4:	return_trace (c->dispatch (u.format4));
+    case 6:	return_trace (c->dispatch (u.format6));
+    default:	return_trace (c->default_return_value ());
     }
   }
 
diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc
index 80bf2d7..5a4e227 100644
--- a/src/hb-aat-layout.cc
+++ b/src/hb-aat-layout.cc
@@ -172,88 +172,19 @@
  * mort/morx/kerx/trak
  */
 
-static inline const AAT::mort&
-_get_mort (hb_face_t *face, hb_blob_t **blob = nullptr)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
-  {
-    if (blob)
-      *blob = hb_blob_get_empty ();
-    return Null(AAT::mort);
-  }
-  const AAT::mort& mort = *(hb_ot_face_data (face)->mort.get ());
-  if (blob)
-    *blob = hb_ot_face_data (face)->mort.get_blob ();
-  return mort;
-}
-static inline const AAT::morx&
-_get_morx (hb_face_t *face, hb_blob_t **blob = nullptr)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
-  {
-    if (blob)
-      *blob = hb_blob_get_empty ();
-    return Null(AAT::morx);
-  }
-  const AAT::morx& morx = *(hb_ot_face_data (face)->morx.get ());
-  if (blob)
-    *blob = hb_ot_face_data (face)->morx.get_blob ();
-  return morx;
-}
-static inline const AAT::kerx&
-_get_kerx (hb_face_t *face, hb_blob_t **blob = nullptr)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
-  {
-    if (blob)
-      *blob = hb_blob_get_empty ();
-    return Null(AAT::kerx);
-  }
-  const AAT::kerx& kerx = *(hb_ot_face_data (face)->kerx.get ());
-  if (blob)
-    *blob = hb_ot_face_data (face)->kerx.get_blob ();
-  return kerx;
-}
-static inline const AAT::ankr&
-_get_ankr (hb_face_t *face, hb_blob_t **blob = nullptr)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
-  {
-    if (blob)
-      *blob = hb_blob_get_empty ();
-    return Null(AAT::ankr);
-  }
-  const AAT::ankr& ankr = *(hb_ot_face_data (face)->ankr.get ());
-  if (blob)
-    *blob = hb_ot_face_data (face)->ankr.get_blob ();
-  return ankr;
-}
-static inline const AAT::trak&
-_get_trak (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(AAT::trak);
-  return *(hb_ot_face_data (face)->trak.get ());
-}
-static inline const AAT::ltag&
-_get_ltag (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(AAT::ltag);
-  return *(hb_ot_face_data (face)->ltag.get ());
-}
-
 
 void
 hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
 			   hb_aat_map_t *map)
 {
-  const AAT::morx& morx = _get_morx (mapper->face, nullptr);
+  const AAT::morx& morx = *mapper->face->table.morx;
   if (morx.has_data ())
   {
     morx.compile_flags (mapper, map);
     return;
   }
 
-  const AAT::mort& mort = _get_mort (mapper->face, nullptr);
+  const AAT::mort& mort = *mapper->face->table.mort;
   if (mort.has_data ())
   {
     mort.compile_flags (mapper, map);
@@ -265,8 +196,8 @@
 hb_bool_t
 hb_aat_layout_has_substitution (hb_face_t *face)
 {
-  return _get_morx (face).has_data () ||
-	 _get_mort (face).has_data ();
+  return face->table.morx->has_data () ||
+	 face->table.mort->has_data ();
 }
 
 void
@@ -274,20 +205,20 @@
 			  hb_font_t *font,
 			  hb_buffer_t *buffer)
 {
-  hb_blob_t *blob;
-
-  const AAT::morx& morx = _get_morx (font->face, &blob);
+  hb_blob_t *morx_blob = font->face->table.morx.get_blob ();
+  const AAT::morx& morx = *morx_blob->as<AAT::morx> ();
   if (morx.has_data ())
   {
-    AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
+    AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
     morx.apply (&c);
     return;
   }
 
-  const AAT::mort& mort = _get_mort (font->face, &blob);
+  hb_blob_t *mort_blob = font->face->table.morx.get_blob ();
+  const AAT::mort& mort = *mort_blob->as<AAT::mort> ();
   if (mort.has_data ())
   {
-    AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
+    AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
     mort.apply (&c);
     return;
   }
@@ -297,7 +228,7 @@
 hb_bool_t
 hb_aat_layout_has_positioning (hb_face_t *face)
 {
-  return _get_kerx (face).has_data ();
+  return face->table.kerx->has_data ();
 }
 
 void
@@ -305,21 +236,22 @@
 			hb_font_t *font,
 			hb_buffer_t *buffer)
 {
-  hb_blob_t *blob;
-  const AAT::kerx& kerx = _get_kerx (font->face, &blob);
+  hb_blob_t *kerx_blob = font->face->table.kerx.get_blob ();
+  const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
 
-  hb_blob_t *ankr_blob;
-  const AAT::ankr& ankr = _get_ankr (font->face, &ankr_blob);
+  hb_blob_t *ankr_blob = font->face->table.ankr.get_blob ();;
+  const AAT::ankr& ankr = *font->face->table.ankr;
 
-  AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
+  AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob);
   c.set_ankr_table (&ankr, ankr_blob->data + ankr_blob->length);
   kerx.apply (&c);
 }
 
+
 hb_bool_t
 hb_aat_layout_has_tracking (hb_face_t *face)
 {
-  return _get_trak (face).has_data ();
+  return face->table.trak->has_data ();
 }
 
 void
@@ -327,15 +259,16 @@
 		     hb_font_t *font,
 		     hb_buffer_t *buffer)
 {
-  const AAT::trak& trak = _get_trak (font->face);
+  const AAT::trak& trak = *font->face->table.trak;
 
   AAT::hb_aat_apply_context_t c (plan, font, buffer);
   trak.apply (&c);
 }
 
+
 hb_language_t
 _hb_aat_language_get (hb_face_t *face,
 		      unsigned int i)
 {
-  return _get_ltag (face).get_language (i);
+  return face->table.ltag->get_language (i);
 }
diff --git a/src/hb-atomic.hh b/src/hb-atomic.hh
index 697de19..49c2809 100644
--- a/src/hb-atomic.hh
+++ b/src/hb-atomic.hh
@@ -290,6 +290,9 @@
   inline T *get (void) const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
   inline bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
 
+  inline T * operator -> (void) const { return get (); }
+  template <typename C> inline operator C * (void) const { return get (); }
+
   mutable T *v;
 };
 
diff --git a/src/hb-common.cc b/src/hb-common.cc
index d7c1921..37be8a3 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -281,7 +281,7 @@
 free_langs (void)
 {
 retry:
-  hb_language_item_t *first_lang = langs.get ();
+  hb_language_item_t *first_lang = langs;
   if (unlikely (!langs.cmpexch (first_lang, nullptr)))
     goto retry;
 
@@ -298,7 +298,7 @@
 lang_find_or_insert (const char *key)
 {
 retry:
-  hb_language_item_t *first_lang = langs.get ();
+  hb_language_item_t *first_lang = langs;
 
   for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
     if (*lang == key)
@@ -408,7 +408,7 @@
 {
   static hb_atomic_ptr_t <hb_language_t> default_language;
 
-  hb_language_t language = default_language.get ();
+  hb_language_t language = default_language;
   if (unlikely (language == HB_LANGUAGE_INVALID))
   {
     language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1);
diff --git a/src/hb-dsalgs.hh b/src/hb-dsalgs.hh
index f2bff06..9ccd7f2 100644
--- a/src/hb-dsalgs.hh
+++ b/src/hb-dsalgs.hh
@@ -553,11 +553,9 @@
 
   inline unsigned int get_size (void) const { return len * sizeof (Type); }
 
-  template <typename T> inline operator  T * (void) { return arrayZ; }
-  template <typename T> inline operator const T * (void) const { return arrayZ; }
+  template <typename T> inline operator  T * (void) const { return arrayZ; }
 
-  inline Type * operator & (void) { return arrayZ; }
-  inline const Type * operator & (void) const { return arrayZ; }
+  inline Type * operator & (void) const { return arrayZ; }
 
   inline hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
   {
diff --git a/src/hb-face.cc b/src/hb-face.cc
index 50ab10e..8e73105 100644
--- a/src/hb-face.cc
+++ b/src/hb-face.cc
@@ -132,6 +132,8 @@
   face->upem = 0;
   face->num_glyphs = (unsigned int) -1;
 
+  face->table.init0 (face);
+
   return face;
 }
 
@@ -263,7 +265,7 @@
 {
   if (!hb_object_destroy (face)) return;
 
-  for (hb_face_t::plan_node_t *node = face->shape_plans.get (); node; )
+  for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
   {
     hb_face_t::plan_node_t *next = node->next;
     hb_shape_plan_destroy (node->shape_plan);
@@ -275,6 +277,8 @@
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 
+  face->table.fini ();
+
   if (face->destroy)
     face->destroy (face->user_data);
 
@@ -547,8 +551,7 @@
 hb_face_collect_unicodes (hb_face_t *face,
 			  hb_set_t  *out)
 {
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
-  hb_ot_face_data (face)->cmap->collect_unicodes (out);
+  face->table.cmap->collect_unicodes (out);
 }
 
 /**
@@ -564,8 +567,7 @@
 hb_face_collect_variation_selectors (hb_face_t *face,
 				     hb_set_t  *out)
 {
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
-  hb_ot_face_data (face)->cmap->collect_variation_selectors (out);
+  face->table.cmap->collect_variation_selectors (out);
 }
 
 /**
@@ -582,8 +584,7 @@
 				    hb_codepoint_t variation_selector,
 				    hb_set_t  *out)
 {
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
-  hb_ot_face_data (face)->cmap->collect_variation_unicodes (variation_selector, out);
+  face->table.cmap->collect_variation_unicodes (variation_selector, out);
 }
 
 
diff --git a/src/hb-face.hh b/src/hb-face.hh
index 520bdfd..726f688 100644
--- a/src/hb-face.hh
+++ b/src/hb-face.hh
@@ -33,6 +33,7 @@
 
 #include "hb-shaper.hh"
 #include "hb-shape-plan.hh"
+#include "hb-ot-face.hh"
 
 
 /*
@@ -53,6 +54,8 @@
 
   struct hb_shaper_data_t shaper_data;	/* Various shaper data. */
 
+  hb_ot_face_t table;
+
   /* Cache */
   struct plan_node_t
   {
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index 971241f..24ee3d5 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -71,7 +71,7 @@
 static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)
 {
   hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data;
-  hb_graphite2_tablelist_t *tlist = face_data->tlist.get ();
+  hb_graphite2_tablelist_t *tlist = face_data->tlist;
 
   hb_blob_t *blob = nullptr;
 
@@ -94,7 +94,7 @@
     p->tag = tag;
 
 retry:
-    hb_graphite2_tablelist_t *tlist = face_data->tlist.get ();
+    hb_graphite2_tablelist_t *tlist = face_data->tlist;
     p->next = tlist;
 
     if (unlikely (!face_data->tlist.cmpexch (tlist, p)))
@@ -110,7 +110,7 @@
 static void hb_graphite2_release_table(const void *data, const void *table_buffer)
 {
   hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data;
-  hb_graphite2_tablelist_t *tlist = face_data->tlist.get();
+  hb_graphite2_tablelist_t *tlist = face_data->tlist;
 
   hb_graphite2_tablelist_t *prev = nullptr;
   hb_graphite2_tablelist_t *curr = tlist;
@@ -164,7 +164,7 @@
 void
 _hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data)
 {
-  hb_graphite2_tablelist_t *tlist = data->tlist.get ();
+  hb_graphite2_tablelist_t *tlist = data->tlist;
 
   while (tlist)
   {
diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index 465bbb1..f58050d 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -795,6 +795,7 @@
 
   inline const Returned * operator -> (void) const { return get (); }
   inline const Returned & operator * (void) const { return *get (); }
+  template <typename C> inline operator const C * (void) const { return get (); }
 
   inline Data * get_data (void) const
   {
diff --git a/src/hb-null.hh b/src/hb-null.hh
index 43bba9c..bc9438d 100644
--- a/src/hb-null.hh
+++ b/src/hb-null.hh
@@ -114,20 +114,14 @@
 
   inline hb_nonnull_ptr_t (T *v_ = nullptr) : v (v_) {}
   inline T * operator = (T *v_) { return v = v_; }
-  inline T * operator -> (void) { return get (); }
-  inline const T * operator -> (void) const { return get (); }
-  inline T & operator * (void) { return *get (); }
-  inline const T & operator * (void) const { return *get (); }
-  inline T ** operator & (void) { return &v; }
-  inline const T ** operator & (void) const { return &v; }
-  template <typename C> inline operator C * (void) { return get (); }
+  inline T * operator -> (void) const { return get (); }
+  inline T & operator * (void) const { return *get (); }
+  inline T ** operator & (void) const { return &v; }
+  /* Only auto-cast to const types. */
   template <typename C> inline operator const C * (void) const { return get (); }
-  inline operator char * (void) { return (char *) get (); }
   inline operator const char * (void) const { return (const char *) get (); }
-  inline T * get (void) { return v ? v : const_cast<T *> (&Null(T)); }
-  inline const T * get (void) const { return v ? v : const_cast<T *> (&Null(T)); }
-  inline T * get_raw (void) { return v; }
-  inline const T * get_raw (void) const { return v; }
+  inline T * get (void) const { return v ? v : const_cast<T *> (&Null(T)); }
+  inline T * get_raw (void) const { return v; }
 
   T *v;
 };
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index a1c5a97..399c46b 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -1016,40 +1016,33 @@
     {
       this->blob = hb_sanitize_context_t().reference_table<cmap> (face);
       const cmap *table = this->blob->as<cmap> ();
-      const CmapSubtableFormat14 *subtable_uvs = nullptr;
       bool symbol;
-      subtable = table->find_best_subtable (&symbol);
-
-      /* UVS subtable. */
-      if (!subtable_uvs)
+      this->subtable = table->find_best_subtable (&symbol);
+      this->subtable_uvs = &Null(CmapSubtableFormat14);
       {
 	const CmapSubtable *st = table->find_subtable (0, 5);
 	if (st && st->u.format == 14)
 	  subtable_uvs = &st->u.format14;
       }
-      /* Meh. */
-      if (!subtable_uvs) subtable_uvs = &Null(CmapSubtableFormat14);
-
-      this->subtable_uvs = subtable_uvs;
 
       this->get_glyph_data = subtable;
       if (unlikely (symbol))
       {
-	this->get_glyph_func = get_glyph_from_symbol<CmapSubtable>;
+	this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>;
       } else {
 	switch (subtable->u.format) {
 	/* Accelerate format 4 and format 12. */
 	default:
-	  this->get_glyph_func = get_glyph_from<CmapSubtable>;
+	  this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
 	  break;
 	case 12:
-	  this->get_glyph_func = get_glyph_from<CmapSubtableFormat12>;
+	  this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>;
 	  break;
 	case  4:
 	  {
 	    this->format4_accel.init (&subtable->u.format4);
 	    this->get_glyph_data = &this->format4_accel;
-	    this->get_glyph_func = this->format4_accel.get_glyph_func;
+	    this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
 	  }
 	  break;
 	}
@@ -1064,7 +1057,29 @@
     inline bool get_nominal_glyph (hb_codepoint_t  unicode,
 				   hb_codepoint_t *glyph) const
     {
-      return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
+      if (unlikely (!this->get_glyph_funcZ)) return false;
+      return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
+    }
+    inline unsigned int get_nominal_glyphs (unsigned int count,
+					    const hb_codepoint_t *first_unicode,
+					    unsigned int unicode_stride,
+					    hb_codepoint_t *first_glyph,
+					    unsigned int glyph_stride) const
+    {
+      if (unlikely (!this->get_glyph_funcZ)) return 0;
+
+      hb_cmap_get_glyph_func_t get_glyph_funcZ = this->get_glyph_funcZ;
+      const void *get_glyph_data = this->get_glyph_data;
+
+      unsigned int done;
+      for (done = 0;
+	   done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph);
+	   done++)
+      {
+	first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
+	first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
+      }
+      return done;
     }
 
     inline bool get_variation_glyph (hb_codepoint_t  unicode,
@@ -1134,10 +1149,10 @@
     }
 
     private:
-    const CmapSubtable *subtable;
-    const CmapSubtableFormat14 *subtable_uvs;
+    hb_nonnull_ptr_t<const CmapSubtable> subtable;
+    hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs;
 
-    hb_cmap_get_glyph_func_t get_glyph_func;
+    hb_cmap_get_glyph_func_t get_glyph_funcZ;
     const void *get_glyph_data;
 
     CmapSubtableFormat4::accelerator_t format4_accel;
diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc
index b87ed56..cac289b 100644
--- a/src/hb-ot-color.cc
+++ b/src/hb-ot-color.cc
@@ -50,42 +50,6 @@
  **/
 
 
-static inline const OT::COLR&
-_get_colr (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::COLR);
-  return *(hb_ot_face_data (face)->COLR.get ());
-}
-
-static inline const OT::CBDT_accelerator_t&
-_get_cbdt (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::CBDT_accelerator_t);
-  return *(hb_ot_face_data (face)->CBDT.get ());
-}
-
-static inline const OT::CPAL&
-_get_cpal (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::CPAL);
-  return *(hb_ot_face_data (face)->CPAL.get ());
-}
-
-static inline const OT::sbix_accelerator_t&
-_get_sbix (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::sbix_accelerator_t);
-  return *(hb_ot_face_data (face)->sbix.get ());
-}
-
-static inline const OT::SVG_accelerator_t&
-_get_svg (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::SVG_accelerator_t);
-  return *(hb_ot_face_data (face)->SVG.get ());
-}
-
-
 /*
  * CPAL
  */
@@ -102,7 +66,7 @@
 hb_bool_t
 hb_ot_color_has_palettes (hb_face_t *face)
 {
-  return _get_cpal (face).has_data ();
+  return face->table.CPAL->has_data ();
 }
 
 /**
@@ -117,7 +81,7 @@
 unsigned int
 hb_ot_color_palette_get_count (hb_face_t *face)
 {
-  return _get_cpal (face).get_palette_count ();
+  return face->table.CPAL->get_palette_count ();
 }
 
 /**
@@ -137,7 +101,7 @@
 hb_ot_color_palette_get_name_id (hb_face_t *face,
 				 unsigned int palette_index)
 {
-  return _get_cpal (face).get_palette_name_id (palette_index);
+  return face->table.CPAL->get_palette_name_id (palette_index);
 }
 
 /**
@@ -153,7 +117,7 @@
 hb_ot_color_palette_color_get_name_id (hb_face_t *face,
 				       unsigned int color_index)
 {
-  return _get_cpal (face).get_color_name_id (color_index);
+  return face->table.CPAL->get_color_name_id (color_index);
 }
 
 /**
@@ -169,7 +133,7 @@
 hb_ot_color_palette_get_flags (hb_face_t *face,
 			       unsigned int palette_index)
 {
-  return _get_cpal(face).get_palette_flags (palette_index);
+  return face->table.CPAL->get_palette_flags (palette_index);
 }
 
 /**
@@ -203,7 +167,7 @@
 				unsigned int  *colors_count  /* IN/OUT.  May be NULL. */,
 				hb_color_t    *colors        /* OUT.     May be NULL. */)
 {
-  return _get_cpal (face).get_palette_colors (palette_index, start_offset, colors_count, colors);
+  return face->table.CPAL->get_palette_colors (palette_index, start_offset, colors_count, colors);
 }
 
 
@@ -222,7 +186,7 @@
 hb_bool_t
 hb_ot_color_has_layers (hb_face_t *face)
 {
-  return _get_colr (face).has_data ();
+  return face->table.COLR->has_data ();
 }
 
 /**
@@ -245,7 +209,7 @@
 			      unsigned int        *count, /* IN/OUT.  May be NULL. */
 			      hb_ot_color_layer_t *layers /* OUT.     May be NULL. */)
 {
-  return _get_colr (face).get_glyph_layers (glyph, start_offset, count, layers);
+  return face->table.COLR->get_glyph_layers (glyph, start_offset, count, layers);
 }
 
 
@@ -266,7 +230,7 @@
 hb_bool_t
 hb_ot_color_has_svg (hb_face_t *face)
 {
-  return _get_svg (face).has_data ();
+  return face->table.SVG->has_data ();
 }
 
 /**
@@ -283,7 +247,7 @@
 hb_blob_t *
 hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph)
 {
-  return _get_svg (face).reference_blob_for_glyph (glyph);
+  return face->table.SVG->reference_blob_for_glyph (glyph);
 }
 
 
@@ -304,7 +268,7 @@
 hb_bool_t
 hb_ot_color_has_png (hb_face_t *face)
 {
-  return _get_cbdt (face).has_data () || _get_sbix (face).has_data ();
+  return face->table.CBDT->has_data () || face->table.sbix->has_data ();
 }
 
 /**
@@ -325,11 +289,11 @@
 {
   hb_blob_t *blob = hb_blob_get_empty ();
 
-  if (_get_sbix (font->face).has_data ())
-    blob = _get_sbix (font->face).reference_png (font, glyph, nullptr, nullptr, nullptr);
+  if (font->face->table.sbix->has_data ())
+    blob = font->face->table.sbix->reference_png (font, glyph, nullptr, nullptr, nullptr);
 
-  if (!blob->length && _get_cbdt (font->face).has_data ())
-    blob = _get_cbdt (font->face).reference_png (font, glyph);
+  if (!blob->length && font->face->table.CBDT->has_data ())
+    blob = font->face->table.CBDT->reference_png (font, glyph);
 
   return blob;
 }
diff --git a/src/hb-ot-face.cc b/src/hb-ot-face.cc
index 1c6370d..9188f53 100644
--- a/src/hb-ot-face.cc
+++ b/src/hb-ot-face.cc
@@ -42,7 +42,7 @@
 #include "hb-ot-layout-gpos-table.hh"
 
 
-void hb_ot_face_data_t::init0 (hb_face_t *face)
+void hb_ot_face_t::init0 (hb_face_t *face)
 {
   this->face = face;
 #define HB_OT_TABLE(Namespace, Type) Type.init0 ();
@@ -51,7 +51,7 @@
 #undef HB_OT_ACCELERATOR
 #undef HB_OT_TABLE
 }
-void hb_ot_face_data_t::fini (void)
+void hb_ot_face_t::fini (void)
 {
 #define HB_OT_TABLE(Namespace, Type) Type.fini ();
 #define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
@@ -59,23 +59,3 @@
 #undef HB_OT_ACCELERATOR
 #undef HB_OT_TABLE
 }
-
-hb_ot_face_data_t *
-_hb_ot_face_data_create (hb_face_t *face)
-{
-  hb_ot_face_data_t *data = (hb_ot_face_data_t *) calloc (1, sizeof (hb_ot_face_data_t));
-  if (unlikely (!data))
-    return nullptr;
-
-  data->init0 (face);
-
-  return data;
-}
-
-void
-_hb_ot_face_data_destroy (hb_ot_face_data_t *data)
-{
-  data->fini ();
-  free (data);
-}
-
diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh
index 9719ad4..987dae3 100644
--- a/src/hb-ot-face.hh
+++ b/src/hb-ot-face.hh
@@ -34,34 +34,11 @@
 #include "hb-machinery.hh"
 
 
-#define hb_ot_face_data(face) ((hb_ot_face_data_t *) face->shaper_data.ot.get_relaxed ())
-
-
 /*
- * hb_ot_face_data_t
+ * hb_ot_face_t
  */
 
-/* Most of these tables are NOT needed for shaping.  But we need to hook them *somewhere*.
- * This is as good as any place. */
 #define HB_OT_TABLES \
-    /* OpenType shaping. */ \
-    HB_OT_ACCELERATOR(OT, GDEF) \
-    HB_OT_ACCELERATOR(OT, GSUB) \
-    HB_OT_ACCELERATOR(OT, GPOS) \
-    HB_OT_TABLE(OT, JSTF) \
-    HB_OT_TABLE(OT, BASE) \
-    /* AAT shaping. */ \
-    HB_OT_TABLE(AAT, morx) \
-    HB_OT_TABLE(AAT, mort) \
-    HB_OT_TABLE(AAT, kerx) \
-    HB_OT_TABLE(AAT, ankr) \
-    HB_OT_TABLE(AAT, trak) \
-    /* OpenType variations. */ \
-    HB_OT_TABLE(OT, fvar) \
-    HB_OT_TABLE(OT, avar) \
-    HB_OT_TABLE(OT, MVAR) \
-    /* OpenType math. */ \
-    HB_OT_TABLE(OT, MATH) \
     /* OpenType fundamentals. */ \
     HB_OT_ACCELERATOR(OT, cmap) \
     HB_OT_ACCELERATOR(OT, hmtx) \
@@ -73,7 +50,25 @@
     HB_OT_ACCELERATOR(OT, cff2) \
     HB_OT_TABLE(OT, VORG) \
     HB_OT_ACCELERATOR(OT, name) \
+    /* OpenType shaping. */ \
+    HB_OT_ACCELERATOR(OT, GDEF) \
+    HB_OT_ACCELERATOR(OT, GSUB) \
+    HB_OT_ACCELERATOR(OT, GPOS) \
+    HB_OT_TABLE(OT, BASE) \
+    HB_OT_TABLE(OT, JSTF) \
+    /* AAT shaping. */ \
+    HB_OT_TABLE(AAT, mort) \
+    HB_OT_TABLE(AAT, morx) \
+    HB_OT_TABLE(AAT, kerx) \
+    HB_OT_TABLE(AAT, ankr) \
+    HB_OT_TABLE(AAT, trak) \
     HB_OT_TABLE(AAT, ltag) \
+    /* OpenType variations. */ \
+    HB_OT_TABLE(OT, fvar) \
+    HB_OT_TABLE(OT, avar) \
+    HB_OT_TABLE(OT, MVAR) \
+    /* OpenType math. */ \
+    HB_OT_TABLE(OT, MATH) \
     /* OpenType color fonts. */ \
     HB_OT_TABLE(OT, COLR) \
     HB_OT_TABLE(OT, CPAL) \
@@ -89,7 +84,7 @@
 #undef HB_OT_ACCELERATOR
 #undef HB_OT_TABLE
 
-struct hb_ot_face_data_t
+struct hb_ot_face_t
 {
   HB_INTERNAL void init0 (hb_face_t *face);
   HB_INTERNAL void fini (void);
@@ -117,11 +112,4 @@
 };
 
 
-HB_INTERNAL hb_ot_face_data_t *
-_hb_ot_face_data_create (hb_face_t *face);
-
-HB_INTERNAL void
-_hb_ot_face_data_destroy (hb_ot_face_data_t *data);
-
-
 #endif /* HB_OT_FACE_HH */
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index d41f322..44b5a48 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -63,8 +63,8 @@
 			 hb_codepoint_t *glyph,
 			 void *user_data HB_UNUSED)
 {
-  const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
-  return ot_face->cmap.get ()->get_nominal_glyph (unicode, glyph);
+  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+  return ot_face->cmap->get_nominal_glyph (unicode, glyph);
 }
 
 static unsigned int
@@ -77,17 +77,10 @@
 			  unsigned int glyph_stride,
 			  void *user_data HB_UNUSED)
 {
-  const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
-  const OT::cmap_accelerator_t &cmap = *ot_face->cmap.get ();
-  unsigned int done;
-  for (done = 0;
-       done < count && cmap.get_nominal_glyph (*first_unicode, first_glyph);
-       done++)
-  {
-    first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
-    first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-  }
-  return done;
+  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+  return ot_face->cmap->get_nominal_glyphs (count,
+					    first_unicode, unicode_stride,
+					    first_glyph, glyph_stride);
 }
 
 static hb_bool_t
@@ -98,8 +91,8 @@
 			   hb_codepoint_t *glyph,
 			   void *user_data HB_UNUSED)
 {
-  const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
-  return ot_face->cmap.get ()->get_variation_glyph (unicode, variation_selector, glyph);
+  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+  return ot_face->cmap->get_variation_glyph (unicode, variation_selector, glyph);
 }
 
 static void
@@ -111,8 +104,8 @@
 			    unsigned advance_stride,
 			    void *user_data HB_UNUSED)
 {
-  const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
-  const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx.get ();
+  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+  const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
 
   for (unsigned int i = 0; i < count; i++)
   {
@@ -131,8 +124,8 @@
 			    unsigned advance_stride,
 			    void *user_data HB_UNUSED)
 {
-  const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
-  const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx.get ();
+  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+  const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
 
   for (unsigned int i = 0; i < count; i++)
   {
@@ -150,11 +143,11 @@
 			  hb_position_t *y,
 			  void *user_data HB_UNUSED)
 {
-  const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
 
   *x = font->get_glyph_h_advance (glyph) / 2;
 
-  const OT::VORG &VORG = *ot_face->VORG.get ();
+  const OT::VORG &VORG = *ot_face->VORG;
   if (VORG.has_data ())
   {
     *y = font->em_scale_y (VORG.get_y_origin (glyph));
@@ -164,7 +157,7 @@
   hb_glyph_extents_t extents = {0};
   if (ot_face->glyf->get_extents (glyph, &extents))
   {
-    const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx.get ();
+    const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
     hb_position_t tsb = vmtx.get_side_bearing (glyph);
     *y = font->em_scale_y (extents.y_bearing + tsb);
     return true;
@@ -184,7 +177,7 @@
 			 hb_glyph_extents_t *extents,
 			 void *user_data HB_UNUSED)
 {
-  const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
   bool ret = ot_face->sbix->get_extents (font, glyph, extents);
   if (!ret)
     ret = ot_face->glyf->get_extents (glyph, extents);
@@ -209,7 +202,7 @@
                       char *name, unsigned int size,
                       void *user_data HB_UNUSED)
 {
-  const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
   return ot_face->post->get_glyph_name (glyph, name, size);
 }
 
@@ -220,7 +213,7 @@
                            hb_codepoint_t *glyph,
                            void *user_data HB_UNUSED)
 {
-  const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
   return ot_face->post->get_glyph_from_name (name, len, glyph);
 }
 
@@ -230,8 +223,8 @@
 			  hb_font_extents_t *metrics,
 			  void *user_data HB_UNUSED)
 {
-  const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
-  const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx.get ();
+  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+  const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
   metrics->ascender = font->em_scale_y (hmtx.ascender);
   metrics->descender = font->em_scale_y (hmtx.descender);
   metrics->line_gap = font->em_scale_y (hmtx.line_gap);
@@ -245,8 +238,8 @@
 			  hb_font_extents_t *metrics,
 			  void *user_data HB_UNUSED)
 {
-  const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
-  const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx.get ();
+  const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
+  const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
   metrics->ascender = font->em_scale_x (vmtx.ascender);
   metrics->descender = font->em_scale_x (vmtx.descender);
   metrics->line_gap = font->em_scale_x (vmtx.line_gap);
@@ -311,11 +304,8 @@
 void
 hb_ot_font_set_funcs (hb_font_t *font)
 {
-  if (unlikely (!hb_ot_shaper_face_data_ensure (font->face))) return;
-  hb_ot_face_data_t *ot_face = hb_ot_face_data (font->face);
-
   hb_font_set_funcs (font,
 		     _hb_ot_get_font_funcs (),
-		     ot_face,
+		     &font->face->table,
 		     nullptr);
 }
diff --git a/src/hb-ot-kern-table.hh b/src/hb-ot-kern-table.hh
index 5bc9e43..66e827d 100644
--- a/src/hb-ot-kern-table.hh
+++ b/src/hb-ot-kern-table.hh
@@ -155,6 +155,7 @@
   DEFINE_SIZE_STATIC (6);
 };
 
+template <typename KernSubTableHeader>
 struct KernSubTableFormat0
 {
   inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
@@ -186,11 +187,13 @@
   }
 
   protected:
-  BinSearchArrayOf<KernPair> pairs;	/* Array of kerning pairs. */
+  KernSubTableHeader		header;
+  BinSearchArrayOf<KernPair>	pairs;	/* Array of kerning pairs. */
   public:
-  DEFINE_SIZE_ARRAY (8, pairs);
+  DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 8, pairs);
 };
 
+template <typename KernSubTableHeader>
 struct KernSubTableFormat1
 {
   typedef void EntryData;
@@ -309,10 +312,11 @@
   }
 
   protected:
+  KernSubTableHeader					header;
   AAT::StateTable<AAT::MortTypes, EntryData>		machine;
   OffsetTo<UnsizedArrayOf<FWORD>, HBUINT16, false>	kernAction;
   public:
-  DEFINE_SIZE_STATIC (10);
+  DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 10);
 };
 
 struct KernClassTable
@@ -333,6 +337,7 @@
   DEFINE_SIZE_ARRAY (4, classes);
 };
 
+template <typename KernSubTableHeader>
 struct KernSubTableFormat2
 {
   inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
@@ -393,20 +398,19 @@
   }
 
   protected:
-  HBUINT16	rowWidth;	/* The width, in bytes, of a row in the table. */
-  OffsetTo<KernClassTable>
-		leftClassTable;	/* Offset from beginning of this subtable to
-				 * left-hand class table. */
-  OffsetTo<KernClassTable>
-		rightClassTable;/* Offset from beginning of this subtable to
-				 * right-hand class table. */
-  OffsetTo<FWORD>
-		array;		/* Offset from beginning of this subtable to
-				 * the start of the kerning array. */
+  KernSubTableHeader		header;
+  HBUINT16			rowWidth;	/* The width, in bytes, of a row in the table. */
+  OffsetTo<KernClassTable>	leftClassTable;	/* Offset from beginning of this subtable to
+						 * left-hand class table. */
+  OffsetTo<KernClassTable>	rightClassTable;/* Offset from beginning of this subtable to
+						 * right-hand class table. */
+  OffsetTo<FWORD>		array;		/* Offset from beginning of this subtable to
+						 * the start of the kerning array. */
   public:
-  DEFINE_SIZE_MIN (8);
+  DEFINE_SIZE_MIN (KernSubTableHeader::static_size + 8);
 };
 
+template <typename KernSubTableHeader>
 struct KernSubTableFormat3
 {
   inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
@@ -448,70 +452,81 @@
   }
 
   protected:
-  HBUINT16	glyphCount;	/* The number of glyphs in this font. */
-  HBUINT8	kernValueCount;	/* The number of kerning values. */
-  HBUINT8	leftClassCount;	/* The number of left-hand classes. */
-  HBUINT8	rightClassCount;/* The number of right-hand classes. */
-  HBUINT8	flags;		/* Set to zero (reserved for future use). */
-  UnsizedArrayOf<FWORD>
-		kernValueZ;	/* The kerning values.
-				 * Length kernValueCount. */
+  KernSubTableHeader	header;
+  HBUINT16		glyphCount;	/* The number of glyphs in this font. */
+  HBUINT8		kernValueCount;	/* The number of kerning values. */
+  HBUINT8		leftClassCount;	/* The number of left-hand classes. */
+  HBUINT8		rightClassCount;/* The number of right-hand classes. */
+  HBUINT8		flags;		/* Set to zero (reserved for future use). */
+  UnsizedArrayOf<FWORD>	kernValueZ;	/* The kerning values.
+					 * Length kernValueCount. */
 #if 0
-  UnsizedArrayOf<HBUINT8>
-		leftClass;	/* The left-hand classes.
-				 * Length glyphCount. */
-  UnsizedArrayOf<HBUINT8>
-		RightClass;	/* The right-hand classes.
-				 * Length glyphCount. */
-  UnsizedArrayOf<HBUINT8>
-		kernIndex;	/* The indices into the kernValue array.
-				 * Length leftClassCount * rightClassCount */
+  UnsizedArrayOf<HBUINT8>leftClass;	/* The left-hand classes.
+					 * Length glyphCount. */
+  UnsizedArrayOf<HBUINT8>rightClass;	/* The right-hand classes.
+					 * Length glyphCount. */
+  UnsizedArrayOf<HBUINT8>kernIndex;	/* The indices into the kernValue array.
+					 * Length leftClassCount * rightClassCount */
 #endif
   public:
-  DEFINE_SIZE_ARRAY (6, kernValueZ);
+  DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 6, kernValueZ);
 };
 
+template <typename KernSubTableHeader>
 struct KernSubTable
 {
-  inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int format) const
+  inline unsigned int get_size (void) const { return u.header.length; }
+  inline unsigned int get_type (void) const { return u.header.format; }
+
+  inline bool is_simple (void) const
+  { return !(u.header.coverage & (u.header.CrossStream | u.header.Variation)); }
+
+  inline bool is_horizontal (void) const
+  { return (u.header.coverage & u.header.Direction) == u.header.DirectionHorizontal; }
+
+  inline bool is_override (void) const
+  { return bool (u.header.coverage & u.header.Override); }
+
+  inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
   {
-    switch (format) {
+    switch (get_type ()) {
     /* This method hooks up to hb_font_t's get_h_kerning.  Only support Format0. */
     case 0: return u.format0.get_kerning (left, right);
     default:return 0;
     }
   }
 
-  inline void apply (AAT::hb_aat_apply_context_t *c, unsigned int format) const
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
   {
-    /* TODO Switch to dispatch(). */
-    switch (format) {
-    case 0: u.format0.apply (c); return;
-    case 1: u.format1.apply (c); return;
-    case 2: u.format2.apply (c); return;
-    case 3: u.format3.apply (c); return;
-    default:			 return;
+    unsigned int subtable_type = get_type ();
+    TRACE_DISPATCH (this, subtable_type);
+    switch (subtable_type) {
+    case 0:	return_trace (c->dispatch (u.format0));
+    case 1:	return_trace (c->dispatch (u.format1));
+    case 2:	return_trace (c->dispatch (u.format2));
+    case 3:	return_trace (c->dispatch (u.format3));
+    default:	return_trace (c->default_return_value ());
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int format) const
+  inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    switch (format) {
-    case 0: return_trace (u.format0.sanitize (c));
-    case 1: return_trace (u.format1.sanitize (c));
-    case 2: return_trace (u.format2.sanitize (c));
-    case 3: return_trace (u.format3.sanitize (c));
-    default:return_trace (true);
-    }
+    if (unlikely (!u.header.sanitize (c) ||
+		  u.header.length < u.header.min_size ||
+		  !c->check_range (this, u.header.length))) return_trace (false);
+
+    return_trace (dispatch (c));
   }
 
   protected:
   union {
-  KernSubTableFormat0	format0;
-  KernSubTableFormat1	format1;
-  KernSubTableFormat2	format2;
-  KernSubTableFormat3	format3;
+  KernSubTableHeader				header;
+  KernSubTableFormat0<KernSubTableHeader>	format0;
+  KernSubTableFormat1<KernSubTableHeader>	format1;
+  KernSubTableFormat2<KernSubTableHeader>	format2;
+  KernSubTableFormat3<KernSubTableHeader>	format3;
   } u;
   public:
   DEFINE_SIZE_MIN (0);
@@ -519,42 +534,6 @@
 
 
 template <typename T>
-struct KernSubTableWrapper
-{
-  /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
-  inline const T* thiz (void) const { return static_cast<const T *> (this); }
-
-  inline bool is_supported (void) const
-  { return !(thiz()->coverage & T::CheckFlags); }
-
-  inline bool is_horizontal (void) const
-  { return (thiz()->coverage & T::Direction) == T::CheckHorizontal; }
-
-  inline bool is_override (void) const
-  { return bool (thiz()->coverage & T::Override); }
-
-  inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
-  { return thiz()->subtable.get_kerning (left, right, thiz()->format); }
-
-  inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
-  { return is_supported () && is_horizontal () ? get_kerning (left, right) : 0; }
-
-  inline void apply (AAT::hb_aat_apply_context_t *c) const
-  { thiz()->subtable.apply (c, thiz()->format); }
-
-  inline unsigned int get_size (void) const { return thiz()->length; }
-
-  inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (thiz()) &&
-		  thiz()->length >= T::min_size &&
-		  c->check_range (thiz(), thiz()->length) &&
-		  thiz()->subtable.sanitize (c, thiz()->format));
-  }
-};
-
-template <typename T>
 struct KernTable
 {
   /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
@@ -562,36 +541,42 @@
 
   inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
   {
+    typedef KernSubTable<typename T::SubTableHeader> SubTable;
+
     int v = 0;
-    const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (&thiz()->dataZ);
+    const SubTable *st = CastP<SubTable> (&thiz()->dataZ);
     unsigned int count = thiz()->nTables;
     for (unsigned int i = 0; i < count; i++)
     {
-      if (st->is_supported () && st->is_override ())
+      if (!st->is_simple () || !st->is_horizontal ())
+        continue;
+      if (st->is_override ())
         v = 0;
-      v += st->get_h_kerning (left, right);
-      st = &StructAfter<typename T::SubTableWrapper> (*st);
+      v += st->get_kerning (left, right);
+      st = &StructAfter<SubTable> (*st);
     }
     return v;
   }
 
   inline void apply (AAT::hb_aat_apply_context_t *c) const
   {
+    typedef KernSubTable<typename T::SubTableHeader> SubTable;
+
     c->set_lookup_index (0);
-    const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (&thiz()->dataZ);
+    const SubTable *st = CastP<SubTable> (&thiz()->dataZ);
     unsigned int count = thiz()->nTables;
     /* If there's an override subtable, skip subtables before that. */
     unsigned int last_override = 0;
     for (unsigned int i = 0; i < count; i++)
     {
-      if (st->is_supported () && st->is_override ())
+      if (st->is_simple () && st->is_override ())
         last_override = i;
-      st = &StructAfter<typename T::SubTableWrapper> (*st);
+      st = &StructAfter<SubTable> (*st);
     }
-    st = CastP<typename T::SubTableWrapper> (&thiz()->dataZ);
+    st = CastP<SubTable> (&thiz()->dataZ);
     for (unsigned int i = 0; i < count; i++)
     {
-      if (!st->is_supported ())
+      if (!st->is_simple ())
         goto skip;
 
       if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->is_horizontal ())
@@ -605,12 +590,12 @@
 
       c->sanitizer.set_object (*st);
 
-      st->apply (c);
+      st->dispatch (c);
 
       (void) c->buffer->message (c->font, "end kern subtable %d", c->lookup_index);
 
     skip:
-      st = &StructAfter<typename T::SubTableWrapper> (*st);
+      st = &StructAfter<SubTable> (*st);
     }
   }
 
@@ -621,13 +606,15 @@
 		  thiz()->version != T::VERSION))
       return_trace (false);
 
-    const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (&thiz()->dataZ);
+    typedef KernSubTable<typename T::SubTableHeader> SubTable;
+
+    const SubTable *st = CastP<SubTable> (&thiz()->dataZ);
     unsigned int count = thiz()->nTables;
     for (unsigned int i = 0; i < count; i++)
     {
       if (unlikely (!st->sanitize (c)))
 	return_trace (false);
-      st = &StructAfter<typename T::SubTableWrapper> (*st);
+      st = &StructAfter<SubTable> (*st);
     }
 
     return_trace (true);
@@ -640,11 +627,8 @@
 
   static const uint16_t VERSION = 0x0000u;
 
-  struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper>
+  struct SubTableHeader
   {
-    friend struct KernTable<KernOT>;
-    friend struct KernSubTableWrapper<SubTableWrapper>;
-
     enum Coverage
     {
       Direction		= 0x01u,
@@ -654,18 +638,22 @@
 
       Variation		= 0x00u, /* Not supported. */
 
-      CheckFlags	= 0x06u,
-      CheckHorizontal	= 0x01u
+      DirectionHorizontal= 0x01u
     };
 
-    protected:
+    inline bool sanitize (hb_sanitize_context_t *c) const
+    {
+      TRACE_SANITIZE (this);
+      return_trace (c->check_struct (this));
+    }
+
+    public:
     HBUINT16	versionZ;	/* Unused. */
     HBUINT16	length;		/* Length of the subtable (including this header). */
     HBUINT8	format;		/* Subtable format. */
     HBUINT8	coverage;	/* Coverage bits. */
-    KernSubTable subtable;	/* Subtable data. */
     public:
-    DEFINE_SIZE_MIN (6);
+    DEFINE_SIZE_STATIC (6);
   };
 
   protected:
@@ -682,11 +670,8 @@
 
   static const uint32_t VERSION = 0x00010000u;
 
-  struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper>
+  struct SubTableHeader
   {
-    friend struct KernTable<KernAAT>;
-    friend struct KernSubTableWrapper<SubTableWrapper>;
-
     enum Coverage
     {
       Direction		= 0x80u,
@@ -695,19 +680,23 @@
 
       Override		= 0x00u, /* Not supported. */
 
-      CheckFlags	= 0x60u,
-      CheckHorizontal	= 0x00u
+      DirectionHorizontal= 0x00u
     };
 
-    protected:
+    inline bool sanitize (hb_sanitize_context_t *c) const
+    {
+      TRACE_SANITIZE (this);
+      return_trace (c->check_struct (this));
+    }
+
+    public:
     HBUINT32	length;		/* Length of the subtable (including this header). */
     HBUINT8	coverage;	/* Coverage bits. */
     HBUINT8	format;		/* Subtable format. */
     HBUINT16	tupleIndex;	/* The tuple index (used for variations fonts).
 				 * This value specifies which tuple this subtable covers. */
-    KernSubTable subtable;	/* Subtable data. */
     public:
-    DEFINE_SIZE_MIN (8);
+    DEFINE_SIZE_STATIC (8);
   };
 
   protected:
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index 5847953..ea5f1c0 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -410,7 +410,7 @@
 
   struct accelerator_t
   {
-    HB_INTERNAL inline void init (hb_face_t *face);
+    HB_INTERNAL void init (hb_face_t *face);
 
     inline void fini (void)
     {
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 399ede4..743a979 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1736,18 +1736,21 @@
 }
 
 
+struct GPOS_accelerator_t : GPOS::accelerator_t {};
+
+
 /* Out-of-class implementation for methods recursing */
 
 template <typename context_t>
 /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
 {
-  const PosLookup &l = _get_gpos_relaxed (c->face)->get_lookup (lookup_index);
+  const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
   return l.dispatch (c);
 }
 
 /*static*/ inline bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
 {
-  const PosLookup &l = _get_gpos_relaxed (c->face).get_lookup (lookup_index);
+  const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
   unsigned int saved_lookup_props = c->lookup_props;
   unsigned int saved_lookup_index = c->lookup_index;
   c->set_lookup_index (lookup_index);
@@ -1758,8 +1761,6 @@
   return ret;
 }
 
-struct GPOS_accelerator_t : GPOS::accelerator_t {};
-
 
 } /* namespace OT */
 
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index d24ea59..cef6421 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1487,6 +1487,9 @@
 };
 
 
+struct GSUB_accelerator_t : GSUB::accelerator_t {};
+
+
 /* Out-of-class implementation for methods recursing */
 
 /*static*/ inline bool ExtensionSubst::is_reverse (void) const
@@ -1500,13 +1503,13 @@
 template <typename context_t>
 /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
 {
-  const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index);
+  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
   return l.dispatch (c);
 }
 
 /*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
 {
-  const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index);
+  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
   unsigned int saved_lookup_props = c->lookup_props;
   unsigned int saved_lookup_index = c->lookup_index;
   c->set_lookup_index (lookup_index);
@@ -1517,8 +1520,6 @@
   return ret;
 }
 
-struct GSUB_accelerator_t : GSUB::accelerator_t {};
-
 } /* namespace OT */
 
 
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index 0d9eeae..eccbcf4 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -491,7 +491,7 @@
 			iter_input (), iter_context (),
 			font (font_), face (font->face), buffer (buffer_),
 			recurse_func (nullptr),
-			gdef (_get_gdef (face)),
+			gdef (*face->table.GDEF->table),
 			var_store (gdef.get_var_store ()),
 			direction (buffer_->props.direction),
 			lookup_mask (1),
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index f1f09c7..6da1d3f 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -53,55 +53,6 @@
  **/
 
 
-static inline const OT::kern&
-_get_kern (hb_face_t *face, hb_blob_t **blob = nullptr)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
-  {
-    if (blob)
-      *blob = hb_blob_get_empty ();
-    return Null(OT::kern);
-  }
-  const OT::kern& kern = *(hb_ot_face_data (face)->kern.get ());
-  if (blob)
-    *blob = hb_ot_face_data (face)->kern.get_blob ();
-  return kern;
-}
-const OT::GDEF& _get_gdef (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GDEF);
-  return *hb_ot_face_data (face)->GDEF->table;
-}
-static hb_blob_t * _get_gsub_blob (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return hb_blob_get_empty ();
-  return hb_ot_face_data (face)->GSUB->blob;
-}
-static inline const OT::GSUB& _get_gsub (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GSUB);
-  return *hb_ot_face_data (face)->GSUB->table;
-}
-const OT::GSUB& _get_gsub_relaxed (hb_face_t *face)
-{
-  return *hb_ot_face_data (face)->GSUB.get_relaxed ()->table;
-}
-static hb_blob_t * _get_gpos_blob (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return hb_blob_get_empty ();
-  return hb_ot_face_data (face)->GPOS->blob;
-}
-static inline const OT::GPOS& _get_gpos (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GPOS);
-  return *hb_ot_face_data (face)->GPOS->table;
-}
-const OT::GPOS& _get_gpos_relaxed (hb_face_t *face)
-{
-  return *hb_ot_face_data (face)->GPOS.get_relaxed ()->table;
-}
-
-
 /*
  * kern
  */
@@ -109,7 +60,7 @@
 hb_bool_t
 hb_ot_layout_has_kerning (hb_face_t *face)
 {
-  return _get_kern (face).has_data ();
+  return face->table.kern->has_data ();
 }
 
 void
@@ -117,8 +68,8 @@
 		   hb_font_t *font,
 		   hb_buffer_t  *buffer)
 {
-  hb_blob_t *blob;
-  const AAT::kern& kern = _get_kern (font->face, &blob);
+  hb_blob_t *blob = font->face->table.kern.get_blob ();
+  const AAT::kern& kern = *blob->as<AAT::kern> ();
 
   AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
 
@@ -232,14 +183,14 @@
   return false;
 }
 
-inline void
+void
 OT::GDEF::accelerator_t::init (hb_face_t *face)
 {
   this->blob = hb_sanitize_context_t().reference_table<GDEF> (face);
 
   if (unlikely (_hb_ot_blacklist_gdef (this->blob->length,
-				       _get_gsub_blob (face)->length,
-				       _get_gpos_blob (face)->length)))
+				       face->table.GSUB->blob->length,
+				       face->table.GPOS->blob->length)))
   {
     hb_blob_destroy (this->blob);
     this->blob = hb_blob_get_empty ();
@@ -254,7 +205,7 @@
 {
   _hb_buffer_assert_gsubgpos_vars (buffer);
 
-  const OT::GDEF &gdef = _get_gdef (font->face);
+  const OT::GDEF &gdef = *font->face->table.GDEF->table;
   unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
   {
@@ -269,7 +220,7 @@
 hb_bool_t
 hb_ot_layout_has_glyph_classes (hb_face_t *face)
 {
-  return _get_gdef (face).has_glyph_classes ();
+  return face->table.GDEF->table->has_glyph_classes ();
 }
 
 /**
@@ -281,7 +232,7 @@
 hb_ot_layout_get_glyph_class (hb_face_t      *face,
 			      hb_codepoint_t  glyph)
 {
-  return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
+  return (hb_ot_layout_glyph_class_t) face->table.GDEF->table->get_glyph_class (glyph);
 }
 
 /**
@@ -294,7 +245,7 @@
 				  hb_ot_layout_glyph_class_t  klass,
 				  hb_set_t                   *glyphs /* OUT */)
 {
-  return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
+  return face->table.GDEF->table->get_glyphs_in_class (klass, glyphs);
 }
 
 unsigned int
@@ -304,7 +255,10 @@
 				unsigned int   *point_count /* IN/OUT */,
 				unsigned int   *point_array /* OUT */)
 {
-  return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
+  return face->table.GDEF->table->get_attach_points (glyph,
+						     start_offset,
+						     point_count,
+						     point_array);
 }
 
 unsigned int
@@ -315,7 +269,12 @@
 				  unsigned int   *caret_count /* IN/OUT */,
 				  hb_position_t  *caret_array /* OUT */)
 {
-  return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
+  return font->face->table.GDEF->table->get_lig_carets (font,
+							direction,
+							glyph,
+							start_offset,
+							caret_count,
+							caret_array);
 }
 
 
@@ -328,8 +287,8 @@
 		    hb_tag_t   table_tag)
 {
   switch (table_tag) {
-    case HB_OT_TAG_GSUB: return _get_gsub (face);
-    case HB_OT_TAG_GPOS: return _get_gpos (face);
+    case HB_OT_TAG_GSUB: return *face->table.GSUB->table;
+    case HB_OT_TAG_GPOS: return *face->table.GPOS->table;
     default:             return Null(OT::GSUBGPOS);
   }
 }
@@ -501,7 +460,12 @@
 				   hb_tag_t      language_tag,
 				   unsigned int *language_index)
 {
-  return hb_ot_layout_script_select_language (face, table_tag, script_index, 1, &language_tag, language_index);
+  return hb_ot_layout_script_select_language (face,
+					      table_tag,
+					      script_index,
+					      1,
+					      &language_tag,
+					      language_index);
 }
 
 /**
@@ -879,8 +843,6 @@
 				    hb_set_t     *glyphs_after,  /* OUT.  May be NULL */
 				    hb_set_t     *glyphs_output  /* OUT.  May be NULL */)
 {
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
-
   OT::hb_collect_glyphs_context_t c (face,
 				     glyphs_before,
 				     glyphs_input,
@@ -891,13 +853,13 @@
   {
     case HB_OT_TAG_GSUB:
     {
-      const OT::SubstLookup& l = hb_ot_face_data (face)->GSUB->table->get_lookup (lookup_index);
+      const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
       l.collect_glyphs (&c);
       return;
     }
     case HB_OT_TAG_GPOS:
     {
-      const OT::PosLookup& l = hb_ot_face_data (face)->GPOS->table->get_lookup (lookup_index);
+      const OT::PosLookup& l = face->table.GPOS->table->get_lookup (lookup_index);
       l.collect_glyphs (&c);
       return;
     }
@@ -944,7 +906,7 @@
 hb_bool_t
 hb_ot_layout_has_substitution (hb_face_t *face)
 {
-  return _get_gsub (face).has_data ();
+  return face->table.GSUB->table->has_data ();
 }
 
 /**
@@ -959,8 +921,10 @@
 				      unsigned int          glyphs_length,
 				      hb_bool_t             zero_context)
 {
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
-  return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
+  return hb_ot_layout_lookup_would_substitute_fast (face,
+						    lookup_index,
+						    glyphs, glyphs_length,
+						    zero_context);
 }
 
 hb_bool_t
@@ -970,12 +934,12 @@
 					   unsigned int          glyphs_length,
 					   hb_bool_t             zero_context)
 {
-  if (unlikely (lookup_index >= hb_ot_face_data (face)->GSUB->lookup_count)) return false;
+  if (unlikely (lookup_index >= face->table.GSUB->lookup_count)) return false;
   OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
 
-  const OT::SubstLookup& l = hb_ot_face_data (face)->GSUB->table->get_lookup (lookup_index);
+  const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
 
-  return l.would_apply (&c, &hb_ot_face_data (face)->GSUB->accels[lookup_index]);
+  return l.would_apply (&c, &face->table.GSUB->accels[lookup_index]);
 }
 
 void
@@ -998,7 +962,7 @@
   hb_map_t done_lookups;
   OT::hb_closure_context_t c (face, glyphs, &done_lookups);
 
-  const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
+  const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
 
   l.closure (&c, lookup_index);
 }
@@ -1018,7 +982,7 @@
 {
   hb_map_t done_lookups;
   OT::hb_closure_context_t c (face, glyphs, &done_lookups);
-  const OT::GSUB& gsub = _get_gsub (face);
+  const OT::GSUB& gsub = *face->table.GSUB->table;
 
   unsigned int iteration_count = 0;
   unsigned int glyphs_length;
@@ -1047,7 +1011,7 @@
 hb_bool_t
 hb_ot_layout_has_positioning (hb_face_t *face)
 {
-  return _get_gpos (face).has_data ();
+  return face->table.GPOS->table->has_data ();
 }
 
 void
@@ -1081,7 +1045,7 @@
 			      unsigned int    *range_start,       /* OUT.  May be NULL */
 			      unsigned int    *range_end          /* OUT.  May be NULL */)
 {
-  const OT::GPOS &gpos = _get_gpos (face);
+  const OT::GPOS &gpos = *face->table.GPOS->table;
   const hb_tag_t tag = HB_TAG ('s','i','z','e');
 
   unsigned int num_features = gpos.get_feature_count ();
@@ -1254,8 +1218,8 @@
   typedef OT::SubstLookup Lookup;
 
   GSUBProxy (hb_face_t *face) :
-    table (*hb_ot_face_data (face)->GSUB->table),
-    accels (hb_ot_face_data (face)->GSUB->accels) {}
+    table (*face->table.GSUB->table),
+    accels (face->table.GSUB->accels) {}
 
   const OT::GSUB &table;
   const OT::hb_ot_layout_lookup_accelerator_t *accels;
@@ -1268,8 +1232,8 @@
   typedef OT::PosLookup Lookup;
 
   GPOSProxy (hb_face_t *face) :
-    table (*hb_ot_face_data (face)->GPOS->table),
-    accels (hb_ot_face_data (face)->GPOS->accels) {}
+    table (*face->table.GPOS->table),
+    accels (face->table.GPOS->accels) {}
 
   const OT::GPOS &table;
   const OT::hb_ot_layout_lookup_accelerator_t *accels;
@@ -1427,8 +1391,7 @@
 #if 0
 static const OT::BASE& _get_base (hb_face_t *face)
 {
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::BASE);
-  return *hb_ot_face_data (face)->BASE;
+  return *face->table.BASE;
 }
 
 hb_bool_t
diff --git a/src/hb-ot-layout.hh b/src/hb-ot-layout.hh
index b29f87c..437ae47 100644
--- a/src/hb-ot-layout.hh
+++ b/src/hb-ot-layout.hh
@@ -38,19 +38,9 @@
 #include "hb-set-digest.hh"
 
 
-namespace OT
-{
-  struct GDEF;
-  struct GSUB;
-  struct GPOS;
-}
-
-HB_INTERNAL const OT::GDEF& _get_gdef (hb_face_t *face);
-HB_INTERNAL const OT::GSUB& _get_gsub_relaxed (hb_face_t *face);
-HB_INTERNAL const OT::GPOS& _get_gpos_relaxed (hb_face_t *face);
-
 struct hb_ot_shape_plan_t;
 
+
 /*
  * kern
  */
diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh
index e209359..54c4e7f 100644
--- a/src/hb-ot-math-table.hh
+++ b/src/hb-ot-math-table.hh
@@ -700,10 +700,10 @@
 				     hb_font_t		   *font) const
   { return (this+mathConstants).get_value (constant, font); }
 
-  inline const MathGlyphInfo &get_math_glyph_info (void) const
+  inline const MathGlyphInfo &get_glyph_info (void) const
   { return this+mathGlyphInfo; }
 
-  inline const MathVariants &get_math_variants (void) const
+  inline const MathVariants &get_variants (void) const
   { return this+mathVariants; }
 
   protected:
diff --git a/src/hb-ot-math.cc b/src/hb-ot-math.cc
index 92c2948..bd31bf5 100644
--- a/src/hb-ot-math.cc
+++ b/src/hb-ot-math.cc
@@ -40,14 +40,6 @@
  **/
 
 
-static inline const OT::MATH&
-_get_math (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::MATH);
-  hb_ot_face_data_t * data = hb_ot_face_data (face);
-  return *(data->MATH.get ());
-}
-
 /*
  * OT::MATH
  */
@@ -66,7 +58,7 @@
 hb_bool_t
 hb_ot_math_has_data (hb_face_t *face)
 {
-  return _get_math (face).has_data ();
+  return face->table.MATH->has_data ();
 }
 
 /**
@@ -88,8 +80,7 @@
 hb_ot_math_get_constant (hb_font_t *font,
 			 hb_ot_math_constant_t constant)
 {
-  const OT::MATH &math = _get_math (font->face);
-  return math.get_constant(constant, font);
+  return font->face->table.MATH->get_constant(constant, font);
 }
 
 /**
@@ -105,8 +96,7 @@
 hb_ot_math_get_glyph_italics_correction (hb_font_t *font,
 					 hb_codepoint_t glyph)
 {
-  const OT::MATH &math = _get_math (font->face);
-  return math.get_math_glyph_info().get_italics_correction (glyph, font);
+  return font->face->table.MATH->get_glyph_info().get_italics_correction (glyph, font);
 }
 
 /**
@@ -122,8 +112,7 @@
 hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
 					    hb_codepoint_t glyph)
 {
-  const OT::MATH &math = _get_math (font->face);
-  return math.get_math_glyph_info().get_top_accent_attachment (glyph, font);
+  return font->face->table.MATH->get_glyph_info().get_top_accent_attachment (glyph, font);
 }
 
 /**
@@ -139,8 +128,7 @@
 hb_ot_math_is_glyph_extended_shape (hb_face_t *face,
 				    hb_codepoint_t glyph)
 {
-  const OT::MATH &math = _get_math (face);
-  return math.get_math_glyph_info().is_extended_shape (glyph);
+  return face->table.MATH->get_glyph_info().is_extended_shape (glyph);
 }
 
 /**
@@ -166,8 +154,10 @@
 			      hb_ot_math_kern_t kern,
 			      hb_position_t correction_height)
 {
-  const OT::MATH &math = _get_math (font->face);
-  return math.get_math_glyph_info().get_kerning (glyph, kern, correction_height, font);
+  return font->face->table.MATH->get_glyph_info().get_kerning (glyph,
+							       kern,
+							       correction_height,
+							       font);
 }
 
 /**
@@ -197,11 +187,10 @@
 			       unsigned int *variants_count, /* IN/OUT */
 			       hb_ot_math_glyph_variant_t *variants /* OUT */)
 {
-  const OT::MATH &math = _get_math (font->face);
-  return math.get_math_variants().get_glyph_variants (glyph, direction, font,
-						      start_offset,
-						      variants_count,
-						      variants);
+  return font->face->table.MATH->get_variants().get_glyph_variants (glyph, direction, font,
+								    start_offset,
+								    variants_count,
+								    variants);
 }
 
 /**
@@ -222,8 +211,7 @@
 hb_ot_math_get_min_connector_overlap (hb_font_t *font,
 				      hb_direction_t direction)
 {
-  const OT::MATH &math = _get_math (font->face);
-  return math.get_math_variants().get_min_connector_overlap (direction, font);
+  return font->face->table.MATH->get_variants().get_min_connector_overlap (direction, font);
 }
 
 /**
@@ -255,10 +243,11 @@
 			       hb_ot_math_glyph_part_t *parts, /* OUT */
 			       hb_position_t *italics_correction /* OUT */)
 {
-  const OT::MATH &math = _get_math (font->face);
-  return math.get_math_variants().get_glyph_parts (glyph, direction, font,
-						   start_offset,
-						   parts_count,
-						   parts,
-						   italics_correction);
+  return font->face->table.MATH->get_variants().get_glyph_parts (glyph,
+								 direction,
+								 font,
+								 start_offset,
+								 parts_count,
+								 parts,
+								 italics_correction);
 }
diff --git a/src/hb-ot-name.cc b/src/hb-ot-name.cc
index f5ac18d..4c88660 100644
--- a/src/hb-ot-name.cc
+++ b/src/hb-ot-name.cc
@@ -42,13 +42,6 @@
  **/
 
 
-static inline const OT::name_accelerator_t&
-_get_name (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::name_accelerator_t);
-  return *(hb_ot_face_data (face)->name.get ());
-}
-
 /**
  * hb_ot_name_list_names:
  * @face: font face.
@@ -65,7 +58,7 @@
 hb_ot_name_list_names (hb_face_t    *face,
 		       unsigned int *num_entries /* OUT */)
 {
-  const OT::name_accelerator_t &name = _get_name (face);
+  const OT::name_accelerator_t &name = *face->table.name;
   if (num_entries) *num_entries = name.names.len;
   return name.names.arrayZ();
 }
@@ -124,7 +117,7 @@
 		    unsigned int    *text_size /* IN/OUT */,
 		    typename utf_t::codepoint_t *text /* OUT */)
 {
-  const OT::name_accelerator_t &name = _get_name (face);
+  const OT::name_accelerator_t &name = *face->table.name;
 
   if (!language)
     language = hb_language_from_string ("en", 2);
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index 8e56dde..50a5213 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -279,7 +279,7 @@
 {
   arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data;
 
-  arabic_fallback_plan_destroy (arabic_plan->fallback_plan.get ());
+  arabic_fallback_plan_destroy (arabic_plan->fallback_plan);
 
   free (data);
 }
@@ -389,7 +389,7 @@
     return;
 
 retry:
-  arabic_fallback_plan_t *fallback_plan = arabic_plan->fallback_plan.get ();
+  arabic_fallback_plan_t *fallback_plan = arabic_plan->fallback_plan;
   if (unlikely (!fallback_plan))
   {
     /* This sucks.  We need a font to build the fallback plan... */
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 8c5e38e..98c29a4 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -258,16 +258,17 @@
 
 HB_SHAPER_DATA_ENSURE_DEFINE(ot, face)
 
+struct hb_ot_face_data_t {};
+
 hb_ot_face_data_t *
 _hb_ot_shaper_face_data_create (hb_face_t *face)
 {
-  return _hb_ot_face_data_create (face);
+  return (hb_ot_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
 
 void
 _hb_ot_shaper_face_data_destroy (hb_ot_face_data_t *data)
 {
-  _hb_ot_face_data_destroy (data);
 }
 
 
diff --git a/src/hb-ot-var.cc b/src/hb-ot-var.cc
index 64087be..c97e9c4 100644
--- a/src/hb-ot-var.cc
+++ b/src/hb-ot-var.cc
@@ -47,20 +47,6 @@
  * fvar/avar
  */
 
-static inline const OT::fvar&
-_get_fvar (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::fvar);
-  hb_ot_face_data_t *layout = hb_ot_face_data (face);
-  return *(layout->fvar.get ());
-}
-static inline const OT::avar&
-_get_avar (hb_face_t *face)
-{
-  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::avar);
-  hb_ot_face_data_t *layout = hb_ot_face_data (face);
-  return *(layout->avar.get ());
-}
 
 /**
  * hb_ot_var_has_data:
@@ -76,7 +62,7 @@
 hb_bool_t
 hb_ot_var_has_data (hb_face_t *face)
 {
-  return _get_fvar (face).has_data ();
+  return face->table.fvar->has_data ();
 }
 
 /**
@@ -87,8 +73,7 @@
 unsigned int
 hb_ot_var_get_axis_count (hb_face_t *face)
 {
-  const OT::fvar &fvar = _get_fvar (face);
-  return fvar.get_axis_count ();
+  return face->table.fvar->get_axis_count ();
 }
 
 /**
@@ -102,8 +87,7 @@
 		    unsigned int     *axes_count /* IN/OUT */,
 		    hb_ot_var_axis_t *axes_array /* OUT */)
 {
-  const OT::fvar &fvar = _get_fvar (face);
-  return fvar.get_axis_infos (start_offset, axes_count, axes_array);
+  return face->table.fvar->get_axis_infos (start_offset, axes_count, axes_array);
 }
 
 /**
@@ -117,8 +101,7 @@
 		     unsigned int     *axis_index,
 		     hb_ot_var_axis_t *axis_info)
 {
-  const OT::fvar &fvar = _get_fvar (face);
-  return fvar.find_axis (axis_tag, axis_index, axis_info);
+  return face->table.fvar->find_axis (axis_tag, axis_index, axis_info);
 }
 
 
@@ -137,7 +120,7 @@
   for (unsigned int i = 0; i < coords_length; i++)
     coords[i] = 0;
 
-  const OT::fvar &fvar = _get_fvar (face);
+  const OT::fvar &fvar = *face->table.fvar;
   for (unsigned int i = 0; i < variations_length; i++)
   {
     unsigned int axis_index;
@@ -146,8 +129,7 @@
       coords[axis_index] = fvar.normalize_axis_value (axis_index, variations[i].value);
   }
 
-  const OT::avar &avar = _get_avar (face);
-  avar.map_coords (coords, coords_length);
+  face->table.avar->map_coords (coords, coords_length);
 }
 
 /**
@@ -161,10 +143,9 @@
 			    const float *design_coords, /* IN */
 			    int *normalized_coords /* OUT */)
 {
-  const OT::fvar &fvar = _get_fvar (face);
+  const OT::fvar &fvar = *face->table.fvar;
   for (unsigned int i = 0; i < coords_length; i++)
     normalized_coords[i] = fvar.normalize_axis_value (i, design_coords[i]);
 
-  const OT::avar &avar = _get_avar (face);
-  avar.map_coords (normalized_coords, coords_length);
+  face->table.avar->map_coords (normalized_coords, coords_length);
 }
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 8d002f8..f2f2101 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -532,7 +532,7 @@
 
 
 retry:
-  hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans.get ();
+  hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans;
 
   /* Don't look for plan in the cache if there were variation coordinates XXX Fix me. */
   if (!hb_coords_present (coords, num_coords))
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 26b99ed..e77825b 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -853,7 +853,13 @@
 
 #undef MAX_ITEMS
 
-  OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language));
+  hb_tag_t lang_tag;
+  unsigned int lang_count = 1;
+  hb_ot_tags_from_script_and_language (buffer->props.script,
+				       buffer->props.language,
+				       nullptr, nullptr,
+				       &lang_count, &lang_tag);
+  OPENTYPE_TAG language_tag = hb_uint32_swap (lang_count ? lang_tag : HB_TAG_NONE);
   hb_vector_t<TEXTRANGE_PROPERTIES*> range_properties;
   hb_vector_t<int> range_char_counts;
 
diff --git a/src/hb-version.h b/src/hb-version.h
index 68af8f8..ec150d5 100644
--- a/src/hb-version.h
+++ b/src/hb-version.h
@@ -38,9 +38,9 @@
 
 #define HB_VERSION_MAJOR 2
 #define HB_VERSION_MINOR 1
-#define HB_VERSION_MICRO 0
+#define HB_VERSION_MICRO 1
 
-#define HB_VERSION_STRING "2.1.0"
+#define HB_VERSION_STRING "2.1.1"
 
 #define HB_VERSION_ATLEAST(major,minor,micro) \
 	((major)*10000+(minor)*100+(micro) <= \
diff --git a/test/api/.valgrind-suppressions b/test/api/.valgrind-suppressions
deleted file mode 100644
index e69de29..0000000
--- a/test/api/.valgrind-suppressions
+++ /dev/null
diff --git a/test/api/Makefile.am b/test/api/Makefile.am
index 0891527..bd5f13a 100644
--- a/test/api/Makefile.am
+++ b/test/api/Makefile.am
@@ -153,9 +153,9 @@
 
 # Check tests under valgrind.  Saves log to log-valgrind.txt
 VALGRIND_FLAGS = \
-	--tool=memcheck --suppressions=$(srcdir)/.valgrind-suppressions \
+	--tool=memcheck \
 	--track-origins=yes \
-	--leak-check=yes
+	--leak-check=yes \
 	$(EXTRA_VALGRIND_FLAGS)
 #	Can't do for now: --show-reachable=yes
 CLEANFILES +=  log-valgrind.txt
diff --git a/test/api/test-ot-face.c b/test/api/test-ot-face.c
index da23fe5..d6eefba 100644
--- a/test/api/test-ot-face.c
+++ b/test/api/test-ot-face.c
@@ -33,7 +33,8 @@
 
 
 static void
-test_face (hb_face_t *face)
+test_face (hb_face_t *face,
+	   hb_codepoint_t cp)
 {
   hb_font_t *font = hb_font_create (face);
   hb_ot_font_set_funcs (font);
@@ -41,35 +42,35 @@
   hb_set_t *set = hb_set_create ();
   hb_face_collect_unicodes (face, set);
   hb_face_collect_variation_selectors (face, set);
-  hb_face_collect_variation_unicodes (face, 0, set);
+  hb_face_collect_variation_unicodes (face, cp, set);
 
   hb_codepoint_t g;
   hb_position_t x, y;
   hb_glyph_extents_t extents;
   char buf[5] = {0};
-  hb_font_get_nominal_glyph (font, 0, &g);
-  hb_font_get_variation_glyph (font, 0, 0, &g);
-  hb_font_get_glyph_h_advance (font, g);
-  hb_font_get_glyph_v_advance (font, g);
-  hb_font_get_glyph_h_origin (font, g, &x, &y);
-  hb_font_get_glyph_v_origin (font, g, &x, &y);
-  hb_font_get_glyph_extents (font, g, &extents);
-  hb_font_get_glyph_contour_point (font, g, 0, &x, &y);
-  hb_font_get_glyph_name (font, g, buf, sizeof (buf));
+  hb_font_get_nominal_glyph (font, cp, &g);
+  hb_font_get_variation_glyph (font, cp, cp, &g);
+  hb_font_get_glyph_h_advance (font, cp);
+  hb_font_get_glyph_v_advance (font, cp);
+  hb_font_get_glyph_h_origin (font, cp, &x, &y);
+  hb_font_get_glyph_v_origin (font, cp, &x, &y);
+  hb_font_get_glyph_extents (font, cp, &extents);
+  hb_font_get_glyph_contour_point (font, cp, 0, &x, &y);
+  hb_font_get_glyph_name (font, cp, buf, sizeof (buf));
   hb_font_get_glyph_from_name (font, buf, strlen (buf), &g);
 
   hb_ot_color_has_palettes (face);
   hb_ot_color_palette_get_count (face);
-  hb_ot_color_palette_get_name_id (face, 0);
-  hb_ot_color_palette_color_get_name_id (face, 0);
-  hb_ot_color_palette_get_flags (face, 0);
-  hb_ot_color_palette_get_colors (face, 0, 0, NULL, NULL);
+  hb_ot_color_palette_get_name_id (face, cp);
+  hb_ot_color_palette_color_get_name_id (face, cp);
+  hb_ot_color_palette_get_flags (face, cp);
+  hb_ot_color_palette_get_colors (face, cp, 0, NULL, NULL);
   hb_ot_color_has_layers (face);
-  hb_ot_color_glyph_get_layers (face, 0, 0, NULL, NULL);
+  hb_ot_color_glyph_get_layers (face, cp, 0, NULL, NULL);
   hb_ot_color_has_svg (face);
-  hb_blob_destroy (hb_ot_color_glyph_reference_svg (face, 0));
+  hb_blob_destroy (hb_ot_color_glyph_reference_svg (face, cp));
   hb_ot_color_has_png (face);
-  hb_blob_destroy (hb_ot_color_glyph_reference_png (font, 0));
+  hb_blob_destroy (hb_ot_color_glyph_reference_png (font, cp));
 
   hb_ot_layout_has_glyph_classes (face);
   hb_ot_layout_has_substitution (face);
@@ -77,19 +78,19 @@
 
   hb_ot_math_has_data (face);
   hb_ot_math_get_constant (font, HB_OT_MATH_CONSTANT_MATH_LEADING);
-  hb_ot_math_get_glyph_italics_correction (font, 0);
-  hb_ot_math_get_glyph_top_accent_attachment (font, 0);
-  hb_ot_math_is_glyph_extended_shape (face, 0);
-  hb_ot_math_get_glyph_kerning (font, 0, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0);
-  hb_ot_math_get_glyph_variants (font, 0, HB_DIRECTION_TTB, 0, NULL, NULL);
+  hb_ot_math_get_glyph_italics_correction (font, cp);
+  hb_ot_math_get_glyph_top_accent_attachment (font, cp);
+  hb_ot_math_is_glyph_extended_shape (face, cp);
+  hb_ot_math_get_glyph_kerning (font, cp, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0);
+  hb_ot_math_get_glyph_variants (font, cp, HB_DIRECTION_TTB, 0, NULL, NULL);
   hb_ot_math_get_min_connector_overlap (font, HB_DIRECTION_RTL);
-  hb_ot_math_get_glyph_assembly (font, 0, HB_DIRECTION_BTT, 0, NULL, NULL, NULL);
+  hb_ot_math_get_glyph_assembly (font, cp, HB_DIRECTION_BTT, 0, NULL, NULL, NULL);
 
   unsigned int len = sizeof (buf);
   hb_ot_name_list_names (face, NULL);
-  hb_ot_name_get_utf8 (face, 0, NULL, &len, buf);
-  hb_ot_name_get_utf16 (face, 0, NULL, NULL, NULL);
-  hb_ot_name_get_utf32 (face, 0, NULL, NULL, NULL);
+  hb_ot_name_get_utf8 (face, cp, NULL, &len, buf);
+  hb_ot_name_get_utf16 (face, cp, NULL, NULL, NULL);
+  hb_ot_name_get_utf32 (face, cp, NULL, NULL, NULL);
 
   hb_ot_var_get_axis_count (face);
   hb_ot_var_get_axes (face, 0, NULL, NULL);
@@ -104,7 +105,7 @@
 static void
 test_ot_face_empty (void)
 {
-  test_face (hb_face_get_empty ());
+  test_face (hb_face_get_empty (), 0);
 }
 
 int
diff --git a/test/api/test-ot-name.c b/test/api/test-ot-name.c
index 431ee3a..71a8727 100644
--- a/test/api/test-ot-name.c
+++ b/test/api/test-ot-name.c
@@ -27,10 +27,11 @@
 
 #include <hb-ot.h>
 
+static hb_face_t *face;
+
 static void
 test_ot_layout_feature_get_name_ids_and_characters (void)
 {
-  hb_face_t *face = hb_test_open_font_file ("fonts/cv01.otf");
   hb_tag_t cv01 = HB_TAG ('c','v','0','1');
   unsigned int feature_index;
   if (!hb_ot_layout_language_find_feature (face,
@@ -68,8 +69,24 @@
   g_assert_cmpint (char_count, ==, 2);
   g_assert_cmpint (characters[0], ==, 10);
   g_assert_cmpint (characters[1], ==, 24030);
+}
 
-  hb_face_destroy (face);
+static void
+test_ot_name (void)
+{
+  unsigned int num_entries;
+  const hb_ot_name_entry_t *entries;
+  entries = hb_ot_name_list_names (face, &num_entries);
+  g_assert_cmpuint (12, ==, num_entries);
+  hb_ot_name_id_t name_id = entries[3].name_id;
+  g_assert_cmpuint (3, ==, name_id);
+  hb_language_t lang = entries[3].language;
+  g_assert_cmpstr ("en", ==, hb_language_to_string (lang));
+  char text[10];
+  unsigned int text_size = 10;
+  g_assert_cmpuint (27, ==, hb_ot_name_get_utf8 (face, name_id, lang, &text_size, text));
+  g_assert_cmpuint (9, ==, text_size);
+  g_assert_cmpstr (text, ==, "FontForge");
 }
 
 int
@@ -78,6 +95,10 @@
   g_test_init (&argc, &argv, NULL);
 
   hb_test_add (test_ot_layout_feature_get_name_ids_and_characters);
+  hb_test_add (test_ot_name);
 
-  return hb_test_run ();
+  face = hb_test_open_font_file ("fonts/cv01.otf");
+  unsigned int status = hb_test_run ();
+  hb_face_destroy (face);
+  return status;
 }
diff --git a/test/fuzzing/Makefile.am b/test/fuzzing/Makefile.am
index 2506088..54178ff 100644
--- a/test/fuzzing/Makefile.am
+++ b/test/fuzzing/Makefile.am
@@ -68,5 +68,7 @@
 check:
 	EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" $(srcdir)/run-shape-fuzzer-tests.py
 	EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" $(srcdir)/run-subset-fuzzer-tests.py
+check-valgrind:
+	$(AM_V_at)RUN_VALGRIND=1 $(MAKE) $(AM_MAKEFLGS) check
 
 -include $(top_srcdir)/git.mk
diff --git a/test/fuzzing/hb-shape-fuzzer.cc b/test/fuzzing/hb-shape-fuzzer.cc
index fedf56e..70ad08b 100644
--- a/test/fuzzing/hb-shape-fuzzer.cc
+++ b/test/fuzzing/hb-shape-fuzzer.cc
@@ -32,28 +32,11 @@
     hb_buffer_add_utf32 (buffer, text32, sizeof (text32) / sizeof (text32[0]), 0, -1);
     hb_buffer_guess_segment_properties (buffer);
     hb_shape (font, buffer, NULL, 0);
-
-    unsigned int len = hb_buffer_get_length (buffer);
-    hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, NULL);
-    //hb_glyph_position_t *positions = hb_buffer_get_glyph_positions (buffer, NULL);
-    for (unsigned int i = 0; i < len; i++)
-    {
-      hb_glyph_info_t info = infos[i];
-      //hb_glyph_position_t pos = positions[i];
-
-      hb_glyph_extents_t extents;
-      hb_font_get_glyph_extents (font, info.codepoint, &extents);
-
-      hb_ot_color_glyph_get_layers (face, info.codepoint, 0, nullptr, nullptr);
-      hb_blob_destroy (hb_ot_color_glyph_reference_svg (face, info.codepoint));
-      hb_blob_destroy (hb_ot_color_glyph_reference_png (font, info.codepoint));
-    }
-
     hb_buffer_destroy (buffer);
-  }
 
-  /* Misc calls on face. */
-  test_face (face);
+    /* Misc calls on face. */
+    test_face (face, text32[15]);
+  }
 
   hb_font_destroy (font);
   hb_face_destroy (face);
diff --git a/util/options.cc b/util/options.cc
index e185e24..eecd5db 100644
--- a/util/options.cc
+++ b/util/options.cc
@@ -325,6 +325,7 @@
     return false;
   }
 
+  text_opts->text_len = -1;
   text_opts->text = g_strdup (arg);
   return true;
 }
@@ -370,6 +371,7 @@
     s = p;
   }
 
+  text_opts->text_len = gs->len;
   text_opts->text = g_string_free (gs, FALSE);
   return true;
 }
@@ -727,7 +729,11 @@
 text_options_t::get_line (unsigned int *len)
 {
   if (text) {
-    if (!line) line = text;
+    if (!line)
+    {
+      line = text;
+      line_len = text_len;
+    }
     if (line_len == (unsigned int) -1)
       line_len = strlen (line);
 
diff --git a/util/options.hh b/util/options.hh
index b185ed9..9f57972 100644
--- a/util/options.hh
+++ b/util/options.hh
@@ -506,6 +506,7 @@
     text_before = nullptr;
     text_after = nullptr;
 
+    text_len = -1;
     text = nullptr;
     text_file = nullptr;
 
@@ -542,6 +543,7 @@
   char *text_before;
   char *text_after;
 
+  int text_len;
   char *text;
   char *text_file;