Merge branch 'master' into iter
diff --git a/docs/usermanual-clusters.xml b/docs/usermanual-clusters.xml
index 228cc56..b8d9191 100644
--- a/docs/usermanual-clusters.xml
+++ b/docs/usermanual-clusters.xml
@@ -492,7 +492,7 @@
     </para>
     <para>
       But this initial cluster-merging behavior makes it impossible
-      client programs to implement some features (such as to
+      for client programs to implement some features (such as to
       color diacritic marks differently from their base
       characters). That is why, in level 1, HarfBuzz does not perform
       the initial merging step.
@@ -684,7 +684,7 @@
       <para>
 	There may be other problems encountered with ligatures under
 	level 2, such as if the direction of the text is forced to
-	opposite of its natural direction (for example, Arabic text
+	the opposite of its natural direction (for example, Arabic text
 	that is forced into left-to-right directionality). But,
 	generally speaking, these other scenarios are minor corner
 	cases that are too obscure for most client programs to need to
diff --git a/docs/usermanual-getting-started.xml b/docs/usermanual-getting-started.xml
index cc867e0..1f26df8 100644
--- a/docs/usermanual-getting-started.xml
+++ b/docs/usermanual-getting-started.xml
@@ -223,7 +223,7 @@
     <orderedlist numeration="arabic">
       <listitem override="2">
 	<para>
-          Guess the script, language and direction of the buffer.
+          Set the script, language and direction of the buffer.
 	</para>
       </listitem>
     </orderedlist>
@@ -275,14 +275,14 @@
     </orderedlist>
     <programlisting language="C">
       for (i = 0; i &lt; glyph_count; ++i) {
-      glyphid = glyph_info[i].codepoint;
-      x_offset = glyph_pos[i].x_offset / 64.0;
-      y_offset = glyph_pos[i].y_offset / 64.0;
-      x_advance = glyph_pos[i].x_advance / 64.0;
-      y_advance = glyph_pos[i].y_advance / 64.0;
-      draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
-      cursor_x += x_advance;
-      cursor_y += y_advance;
+          glyphid = glyph_info[i].codepoint;
+          x_offset = glyph_pos[i].x_offset / 64.0;
+          y_offset = glyph_pos[i].y_offset / 64.0;
+          x_advance = glyph_pos[i].x_advance / 64.0;
+          y_advance = glyph_pos[i].y_advance / 64.0;
+          draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
+          cursor_x += x_advance;
+          cursor_y += y_advance;
       }
     </programlisting>
     <orderedlist numeration="arabic">
diff --git a/docs/usermanual-install-harfbuzz.xml b/docs/usermanual-install-harfbuzz.xml
index a885d00..a1e7ab0 100644
--- a/docs/usermanual-install-harfbuzz.xml
+++ b/docs/usermanual-install-harfbuzz.xml
@@ -423,6 +423,18 @@
 	    </para>
 	  </listitem>
 	</varlistentry>	
+
+	<varlistentry>
+	  <term><command>--enable-gtk-doc</command></term>
+	  <listitem>
+	    <para>
+	      Use <ulink url="https://www.gtk.org/gtk-doc/">GTK-Doc</ulink>. <emphasis>(Default = no)</emphasis>
+	    </para>
+	    <para>
+	      This option enables the building of the documentation.
+	    </para>
+	  </listitem>
+	</varlistentry>
       </variablelist>
     </section>
     
diff --git a/src/hb-aat-fdsc-table.hh b/src/hb-aat-fdsc-table.hh
index a1af595..1188e35 100644
--- a/src/hb-aat-fdsc-table.hh
+++ b/src/hb-aat-fdsc-table.hh
@@ -74,7 +74,7 @@
 
 struct fdsc
 {
-  enum { tableTag = HB_AAT_TAG_fdsc };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_fdsc;
 
   enum {
     Weight	 = HB_TAG ('w','g','h','t'),
diff --git a/src/hb-aat-layout-ankr-table.hh b/src/hb-aat-layout-ankr-table.hh
index f6f1246..236e4aa 100644
--- a/src/hb-aat-layout-ankr-table.hh
+++ b/src/hb-aat-layout-ankr-table.hh
@@ -58,7 +58,7 @@
 
 struct ankr
 {
-  enum { tableTag = HB_AAT_TAG_ankr };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_ankr;
 
   const Anchor &get_anchor (hb_codepoint_t glyph_id,
 			    unsigned int i,
diff --git a/src/hb-aat-layout-bsln-table.hh b/src/hb-aat-layout-bsln-table.hh
index 5bc59cb..9139d28 100644
--- a/src/hb-aat-layout-bsln-table.hh
+++ b/src/hb-aat-layout-bsln-table.hh
@@ -116,7 +116,7 @@
 
 struct bsln
 {
-  enum { tableTag = HB_AAT_TAG_bsln };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_bsln;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh
index 85332b0..27ade28 100644
--- a/src/hb-aat-layout-common.hh
+++ b/src/hb-aat-layout-common.hh
@@ -77,7 +77,7 @@
 template <typename T>
 struct LookupSegmentSingle
 {
-  enum { TerminationWordCount = 2 };
+  static constexpr unsigned TerminationWordCount = 2u;
 
   int cmp (hb_codepoint_t g) const
   { return g < first ? -1 : g <= last ? 0 : +1 ; }
@@ -136,7 +136,7 @@
 template <typename T>
 struct LookupSegmentArray
 {
-  enum { TerminationWordCount = 2 };
+  static constexpr unsigned TerminationWordCount = 2u;
 
   const T* get_value (hb_codepoint_t glyph_id, const void *base) const
   {
@@ -207,7 +207,7 @@
 template <typename T>
 struct LookupSingle
 {
-  enum { TerminationWordCount = 1 };
+  static constexpr unsigned TerminationWordCount = 1u;
 
   int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
 
@@ -511,9 +511,10 @@
   const Entry<Extra> *get_entries () const
   { return (this+entryTable).arrayZ; }
 
-  const Entry<Extra> *get_entryZ (int state, unsigned int klass) const
+  const Entry<Extra> &get_entry (int state, unsigned int klass) const
   {
-    if (unlikely (klass >= nClasses)) return nullptr;
+    if (unlikely (klass >= nClasses))
+      klass = StateTable<Types, Entry<Extra> >::CLASS_OUT_OF_BOUNDS;
 
     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
     const Entry<Extra> *entries = (this+entryTable).arrayZ;
@@ -521,7 +522,7 @@
     unsigned int entry = states[state * nClasses + klass];
     DEBUG_MSG (APPLY, nullptr, "e%u", entry);
 
-    return &entries[entry];
+    return entries[entry];
   }
 
   bool sanitize (hb_sanitize_context_t *c,
@@ -529,6 +530,7 @@
   {
     TRACE_SANITIZE (this);
     if (unlikely (!(c->check_struct (this) &&
+		    nClasses >= 4 /* Ensure pre-defined classes fit.  */ &&
 		    classTable.sanitize (c, this)))) return_trace (false);
 
     const HBUSHORT *states = (this+stateArrayTable).arrayZ;
@@ -571,7 +573,7 @@
 				       -min_state,
 				       row_stride)))
 	  return_trace (false);
-	if ((c->max_ops -= state_neg - min_state) < 0)
+	if ((c->max_ops -= state_neg - min_state) <= 0)
 	  return_trace (false);
 	{ /* Sweep new states. */
 	  const HBUSHORT *stop = &states[min_state * num_classes];
@@ -590,7 +592,7 @@
 				       max_state + 1,
 				       row_stride)))
 	  return_trace (false);
-	if ((c->max_ops -= max_state - state_pos + 1) < 0)
+	if ((c->max_ops -= max_state - state_pos + 1) <= 0)
 	  return_trace (false);
 	{ /* Sweep new states. */
 	  if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes)))
@@ -606,7 +608,7 @@
 
       if (unlikely (!c->check_array (entries, num_entries)))
 	return_trace (false);
-      if ((c->max_ops -= num_entries - entry) < 0)
+      if ((c->max_ops -= num_entries - entry) <= 0)
 	return_trace (false);
       { /* Sweep new entries. */
 	const Entry<Extra> *stop = &entries[num_entries];
@@ -669,7 +671,7 @@
 
 struct ObsoleteTypes
 {
-  enum { extended = false };
+  static constexpr bool extended = false;
   typedef HBUINT16 HBUINT;
   typedef HBUINT8 HBUSHORT;
   typedef ClassTable<HBUINT8> ClassTypeNarrow;
@@ -699,7 +701,7 @@
 };
 struct ExtendedTypes
 {
-  enum { extended = true };
+  static constexpr bool extended = true;
   typedef HBUINT32 HBUINT;
   typedef HBUINT16 HBUSHORT;
   typedef Lookup<HBUINT16> ClassTypeNarrow;
@@ -745,16 +747,13 @@
       buffer->clear_output ();
 
     int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
-    bool last_was_dont_advance = false;
     for (buffer->idx = 0; buffer->successful;)
     {
       unsigned int klass = buffer->idx < buffer->len ?
 			   machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
 			   (unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
       DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
-      const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
-      if (unlikely (!entry))
-	break;
+      const Entry<EntryData> &entry = machine.get_entry (state, klass);
 
       /* Unsafe-to-break before this if not in state 0, as things might
        * go differently if we start from state 0 here.
@@ -765,31 +764,28 @@
 	/* If there's no action and we're just epsilon-transitioning to state 0,
 	 * safe to break. */
 	if (c->is_actionable (this, entry) ||
-	    !(entry->newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
-	      entry->flags == context_t::DontAdvance))
+	    !(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
+	      entry.flags == context_t::DontAdvance))
 	  buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
       }
 
       /* Unsafe-to-break if end-of-text would kick in here. */
       if (buffer->idx + 2 <= buffer->len)
       {
-	const Entry<EntryData> *end_entry = machine.get_entryZ (state, 0);
+	const Entry<EntryData> &end_entry = machine.get_entry (state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT);
 	if (c->is_actionable (this, end_entry))
 	  buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
       }
 
-      if (unlikely (!c->transition (this, entry)))
-	break;
+      c->transition (this, entry);
 
-      last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
-
-      state = machine.new_state (entry->newState);
+      state = machine.new_state (entry.newState);
       DEBUG_MSG (APPLY, nullptr, "s%d", state);
 
       if (buffer->idx == buffer->len)
 	break;
 
-      if (!last_was_dont_advance)
+      if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
 	buffer->next_glyph ();
     }
 
diff --git a/src/hb-aat-layout-feat-table.hh b/src/hb-aat-layout-feat-table.hh
index acc4d04..ab23ee0 100644
--- a/src/hb-aat-layout-feat-table.hh
+++ b/src/hb-aat-layout-feat-table.hh
@@ -154,7 +154,7 @@
 
 struct feat
 {
-  enum { tableTag = HB_AAT_TAG_feat };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_feat;
 
   bool has_data () const { return version.to_int (); }
 
diff --git a/src/hb-aat-layout-just-table.hh b/src/hb-aat-layout-just-table.hh
index d39945a..d53f8f1 100644
--- a/src/hb-aat-layout-just-table.hh
+++ b/src/hb-aat-layout-just-table.hh
@@ -382,7 +382,7 @@
 
 struct just
 {
-  enum { tableTag = HB_AAT_TAG_just };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_just;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh
index b86c513..a64c807 100644
--- a/src/hb-aat-layout-kerx-table.hh
+++ b/src/hb-aat-layout-kerx-table.hh
@@ -170,11 +170,11 @@
     DEFINE_SIZE_STATIC (2);
   };
 
-  static bool performAction (const Entry<EntryData> *entry)
-  { return entry->data.kernActionIndex != 0xFFFF; }
+  static bool performAction (const Entry<EntryData> &entry)
+  { return entry.data.kernActionIndex != 0xFFFF; }
 
-  static unsigned int kernActionIndex (const Entry<EntryData> *entry)
-  { return entry->data.kernActionIndex; }
+  static unsigned int kernActionIndex (const Entry<EntryData> &entry)
+  { return entry.data.kernActionIndex; }
 };
 template <>
 struct Format1Entry<false>
@@ -192,11 +192,11 @@
 
   typedef void EntryData;
 
-  static bool performAction (const Entry<EntryData> *entry)
-  { return entry->flags & Offset; }
+  static bool performAction (const Entry<EntryData> &entry)
+  { return entry.flags & Offset; }
 
-  static unsigned int kernActionIndex (const Entry<EntryData> *entry)
-  { return entry->flags & Offset; }
+  static unsigned int kernActionIndex (const Entry<EntryData> &entry)
+  { return entry.flags & Offset; }
 };
 
 template <typename KernSubTableHeader>
@@ -210,7 +210,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = true };
+    static constexpr bool in_place = true;
     enum
     {
       DontAdvance	= Format1EntryT::DontAdvance,
@@ -228,15 +228,15 @@
 	crossStream (table->header.coverage & table->header.CrossStream) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
       return Format1EntryT::performAction (entry);
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
-      unsigned int flags = entry->flags;
+      unsigned int flags = entry.flags;
 
       if (flags & Format1EntryT::Reset)
 	depth = 0;
@@ -259,7 +259,7 @@
 	if (!c->sanitizer.check_array (actions, depth, tuple_count))
 	{
 	  depth = 0;
-	  return false;
+	  return;
 	}
 
 	hb_mask_t kern_mask = c->plan->kern_mask;
@@ -334,8 +334,6 @@
 	  }
 	}
       }
-
-      return true;
     }
 
     private:
@@ -471,7 +469,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = true };
+    static constexpr bool in_place = true;
     enum Flags
     {
       Mark		= 0x8000,	/* If set, remember this glyph as the marked glyph. */
@@ -498,16 +496,16 @@
 	mark (0) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
-      return entry->data.ankrActionIndex != 0xFFFF;
+      return entry.data.ankrActionIndex != 0xFFFF;
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
 
-      if (mark_set && entry->data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
+      if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
       {
 	hb_glyph_position_t &o = buffer->cur_pos();
 	switch (action_type)
@@ -515,9 +513,8 @@
 	  case 0: /* Control Point Actions.*/
 	  {
 	    /* indexed into glyph outline. */
-	    const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex];
-	    if (!c->sanitizer.check_array (data, 2))
-	      return false;
+	    const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
+	    if (!c->sanitizer.check_array (data, 2)) return;
 	    HB_UNUSED unsigned int markControlPoint = *data++;
 	    HB_UNUSED unsigned int currControlPoint = *data++;
 	    hb_position_t markX = 0;
@@ -532,7 +529,7 @@
 							      currControlPoint,
 							      HB_DIRECTION_LTR /*XXX*/,
 							      &currX, &currY))
-	      return true; /* True, such that the machine continues. */
+	      return;
 
 	    o.x_offset = markX - currX;
 	    o.y_offset = markY - currY;
@@ -542,9 +539,8 @@
 	  case 1: /* Anchor Point Actions. */
 	  {
 	   /* Indexed into 'ankr' table. */
-	    const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex];
-	    if (!c->sanitizer.check_array (data, 2))
-	      return false;
+	    const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
+	    if (!c->sanitizer.check_array (data, 2)) return;
 	    unsigned int markAnchorPoint = *data++;
 	    unsigned int currAnchorPoint = *data++;
 	    const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint,
@@ -561,9 +557,8 @@
 
 	  case 2: /* Control Point Coordinate Actions. */
 	  {
-	    const FWORD *data = (const FWORD *) &ankrData[entry->data.ankrActionIndex];
-	    if (!c->sanitizer.check_array (data, 4))
-	      return false;
+	    const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex];
+	    if (!c->sanitizer.check_array (data, 4)) return;
 	    int markX = *data++;
 	    int markY = *data++;
 	    int currX = *data++;
@@ -579,13 +574,11 @@
 	buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
       }
 
-      if (entry->flags & Mark)
+      if (entry.flags & Mark)
       {
 	mark_set = true;
 	mark = buffer->idx;
       }
-
-      return true;
     }
 
     private:
@@ -979,8 +972,8 @@
 {
   friend struct KerxTable<kerx>;
 
-  enum { tableTag = HB_AAT_TAG_kerx };
-  enum { minVersion = 2u };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_kerx;
+  static constexpr unsigned minVersion = 2u;
 
   typedef KerxSubTableHeader SubTableHeader;
   typedef SubTableHeader::Types Types;
diff --git a/src/hb-aat-layout-lcar-table.hh b/src/hb-aat-layout-lcar-table.hh
index 27c601d..4be799f 100644
--- a/src/hb-aat-layout-lcar-table.hh
+++ b/src/hb-aat-layout-lcar-table.hh
@@ -40,7 +40,7 @@
 
 struct lcar
 {
-  enum { tableTag = HB_AAT_TAG_lcar };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_lcar;
 
   unsigned int get_lig_carets (hb_font_t      *font,
 			       hb_direction_t  direction,
diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index d8a90bb..4a1d959 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -54,7 +54,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = true };
+    static constexpr bool in_place = true;
     enum Flags
     {
       MarkFirst		= 0x8000,	/* If set, make the current glyph the first
@@ -74,15 +74,15 @@
 	start (0), end (0) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
-      return (entry->flags & Verb) && start < end;
+      return (entry.flags & Verb) && start < end;
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
-      unsigned int flags = entry->flags;
+      unsigned int flags = entry.flags;
 
       if (flags & MarkFirst)
 	start = buffer->idx;
@@ -152,8 +152,6 @@
 	  }
 	}
       }
-
-      return true;
     }
 
     public:
@@ -204,7 +202,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = true };
+    static constexpr bool in_place = true;
     enum Flags
     {
       SetMark		= 0x8000,	/* If set, make the current glyph the marked glyph. */
@@ -223,39 +221,39 @@
 	subs (table+table->substitutionTables) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
 
       if (buffer->idx == buffer->len && !mark_set)
         return false;
 
-      return entry->data.markIndex != 0xFFFF || entry->data.currentIndex != 0xFFFF;
+      return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
 
       /* Looks like CoreText applies neither mark nor current substitution for
        * end-of-text if mark was not explicitly set. */
       if (buffer->idx == buffer->len && !mark_set)
-        return true;
+        return;
 
       const GlyphID *replacement;
 
       replacement = nullptr;
       if (Types::extended)
       {
-	if (entry->data.markIndex != 0xFFFF)
+	if (entry.data.markIndex != 0xFFFF)
 	{
-	  const Lookup<GlyphID> &lookup = subs[entry->data.markIndex];
+	  const Lookup<GlyphID> &lookup = subs[entry.data.markIndex];
 	  replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
 	}
       }
       else
       {
-	unsigned int offset = entry->data.markIndex + buffer->info[mark].codepoint;
+	unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
 	const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
 	replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
 	if (!replacement->sanitize (&c->sanitizer) || !*replacement)
@@ -272,15 +270,15 @@
       unsigned int idx = MIN (buffer->idx, buffer->len - 1);
       if (Types::extended)
       {
-	if (entry->data.currentIndex != 0xFFFF)
+	if (entry.data.currentIndex != 0xFFFF)
 	{
-	  const Lookup<GlyphID> &lookup = subs[entry->data.currentIndex];
+	  const Lookup<GlyphID> &lookup = subs[entry.data.currentIndex];
 	  replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
 	}
       }
       else
       {
-	unsigned int offset = entry->data.currentIndex + buffer->info[idx].codepoint;
+	unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
 	const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
 	replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
 	if (!replacement->sanitize (&c->sanitizer) || !*replacement)
@@ -292,13 +290,11 @@
 	ret = true;
       }
 
-      if (entry->flags & SetMark)
+      if (entry.flags & SetMark)
       {
 	mark_set = true;
 	mark = buffer->idx;
       }
-
-      return true;
     }
 
     public:
@@ -385,11 +381,11 @@
     DEFINE_SIZE_STATIC (2);
   };
 
-  static bool performAction (const Entry<EntryData> *entry)
-  { return entry->flags & PerformAction; }
+  static bool performAction (const Entry<EntryData> &entry)
+  { return entry.flags & PerformAction; }
 
-  static unsigned int ligActionIndex (const Entry<EntryData> *entry)
-  { return entry->data.ligActionIndex; }
+  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
+  { return entry.data.ligActionIndex; }
 };
 template <>
 struct LigatureEntry<false>
@@ -407,11 +403,11 @@
 
   typedef void EntryData;
 
-  static bool performAction (const Entry<EntryData> *entry)
-  { return entry->flags & Offset; }
+  static bool performAction (const Entry<EntryData> &entry)
+  { return entry.flags & Offset; }
 
-  static unsigned int ligActionIndex (const Entry<EntryData> *entry)
-  { return entry->flags & Offset; }
+  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
+  { return entry.flags & Offset; }
 };
 
 
@@ -425,7 +421,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = false };
+    static constexpr bool in_place = false;
     enum
     {
       DontAdvance	= LigatureEntryT::DontAdvance,
@@ -453,26 +449,23 @@
 	match_length (0) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
       return LigatureEntryT::performAction (entry);
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
 
       DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
-      if (entry->flags & LigatureEntryT::SetComponent)
+      if (entry.flags & LigatureEntryT::SetComponent)
       {
-        if (unlikely (match_length >= ARRAY_LENGTH (match_positions)))
-	  return false;
-
 	/* Never mark same index twice, in case DontAdvance was used... */
-	if (match_length && match_positions[match_length - 1] == buffer->out_len)
+	if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
 	  match_length--;
 
-	match_positions[match_length++] = buffer->out_len;
+	match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
 	DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
       }
 
@@ -482,10 +475,10 @@
 	unsigned int end = buffer->out_len;
 
 	if (unlikely (!match_length))
-	  return true;
+	  return;
 
 	if (buffer->idx >= buffer->len)
-	  return false; // TODO Work on previous instead?
+	  return; /* TODO Work on previous instead? */
 
 	unsigned int cursor = match_length;
 
@@ -506,9 +499,9 @@
 	  }
 
 	  DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
-	  buffer->move_to (match_positions[--cursor]);
+	  buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]);
 
-	  if (unlikely (!actionData->sanitize (&c->sanitizer))) return false;
+	  if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
 	  action = *actionData;
 
 	  uint32_t uoffset = action & LigActionOffset;
@@ -518,7 +511,7 @@
 	  unsigned int component_idx = buffer->cur().codepoint + offset;
 	  component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
 	  const HBUINT16 &componentData = component[component_idx];
-	  if (unlikely (!componentData.sanitize (&c->sanitizer))) return false;
+	  if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
 	  ligature_idx += componentData;
 
 	  DEBUG_MSG (APPLY, nullptr, "Action store %u last %u",
@@ -528,23 +521,23 @@
 	  {
 	    ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
 	    const GlyphID &ligatureData = ligature[ligature_idx];
-	    if (unlikely (!ligatureData.sanitize (&c->sanitizer))) return false;
+	    if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
 	    hb_codepoint_t lig = ligatureData;
 
 	    DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
 	    buffer->replace_glyph (lig);
 
-	    unsigned int lig_end = match_positions[match_length - 1] + 1;
+	    unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
 	    /* Now go and delete all subsequent components. */
-	    while (match_length - 1 > cursor)
+	    while (match_length - 1u > cursor)
 	    {
 	      DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
-	      buffer->move_to (match_positions[--match_length]);
+	      buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]);
 	      buffer->replace_glyph (DELETED_GLYPH);
 	    }
 
 	    buffer->move_to (lig_end);
-	    buffer->merge_out_clusters (match_positions[cursor], buffer->out_len);
+	    buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
 	  }
 
 	  actionData++;
@@ -552,8 +545,6 @@
 	while (!(action & LigActionLast));
 	buffer->move_to (end);
       }
-
-      return true;
     }
 
     public:
@@ -661,7 +652,7 @@
 
   struct driver_context_t
   {
-    enum { in_place = false };
+    static constexpr bool in_place = false;
     enum Flags
     {
       SetMark		= 0x8000,	/* If set, mark the current glyph. */
@@ -714,28 +705,29 @@
 		      hb_aat_apply_context_t *c_) :
 	ret (false),
 	c (c_),
-	mark_set (false),
 	mark (0),
 	insertionAction (table+table->insertionAction) {}
 
     bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
-			const Entry<EntryData> *entry)
+			const Entry<EntryData> &entry)
     {
-      return (entry->flags & (CurrentInsertCount | MarkedInsertCount)) &&
-	     (entry->data.currentInsertIndex != 0xFFFF ||entry->data.markedInsertIndex != 0xFFFF);
+      return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
+	     (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
     }
-    bool transition (StateTableDriver<Types, EntryData> *driver,
-		     const Entry<EntryData> *entry)
+    void transition (StateTableDriver<Types, EntryData> *driver,
+		     const Entry<EntryData> &entry)
     {
       hb_buffer_t *buffer = driver->buffer;
-      unsigned int flags = entry->flags;
+      unsigned int flags = entry.flags;
 
-      if (entry->data.markedInsertIndex != 0xFFFF && mark_set)
+      unsigned mark_loc = buffer->out_len;
+
+      if (entry.data.markedInsertIndex != 0xFFFF)
       {
 	unsigned int count = (flags & MarkedInsertCount);
-	unsigned int start = entry->data.markedInsertIndex;
+	unsigned int start = entry.data.markedInsertIndex;
 	const GlyphID *glyphs = &insertionAction[start];
-	if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
+	if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
 
 	bool before = flags & MarkedInsertBefore;
 
@@ -755,12 +747,15 @@
 	buffer->unsafe_to_break_from_outbuffer (mark, MIN (buffer->idx + 1, buffer->len));
       }
 
-      if (entry->data.currentInsertIndex != 0xFFFF)
+      if (flags & SetMark)
+	mark = mark_loc;
+
+      if (entry.data.currentInsertIndex != 0xFFFF)
       {
 	unsigned int count = (flags & CurrentInsertCount) >> 5;
-	unsigned int start = entry->data.currentInsertIndex;
+	unsigned int start = entry.data.currentInsertIndex;
 	const GlyphID *glyphs = &insertionAction[start];
-	if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
+	if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
 
 	bool before = flags & CurrentInsertBefore;
 
@@ -791,21 +786,12 @@
 	 */
 	buffer->move_to ((flags & DontAdvance) ? end : end + count);
       }
-
-      if (flags & SetMark)
-      {
-	mark_set = true;
-	mark = buffer->out_len;
-      }
-
-      return true;
     }
 
     public:
     bool ret;
     private:
     hb_aat_apply_context_t *c;
-    bool mark_set;
     unsigned int mark;
     const UnsizedArrayOf<GlyphID> &insertionAction;
   };
@@ -1097,7 +1083,7 @@
 template <typename Types>
 struct mortmorx
 {
-  enum { tableTag = HB_AAT_TAG_morx };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx;
 
   bool has_data () const { return version != 0; }
 
@@ -1159,11 +1145,11 @@
 
 struct morx : mortmorx<ExtendedTypes>
 {
-  enum { tableTag = HB_AAT_TAG_morx };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx;
 };
 struct mort : mortmorx<ObsoleteTypes>
 {
-  enum { tableTag = HB_AAT_TAG_mort };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_mort;
 };
 
 
diff --git a/src/hb-aat-layout-trak-table.hh b/src/hb-aat-layout-trak-table.hh
index 3fe7d43..0c8e455 100644
--- a/src/hb-aat-layout-trak-table.hh
+++ b/src/hb-aat-layout-trak-table.hh
@@ -160,7 +160,7 @@
 
 struct trak
 {
-  enum { tableTag = HB_AAT_TAG_trak };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_trak;
 
   bool has_data () const { return version.to_int (); }
 
diff --git a/src/hb-aat-ltag-table.hh b/src/hb-aat-ltag-table.hh
index 9a6a280..6f34a00 100644
--- a/src/hb-aat-ltag-table.hh
+++ b/src/hb-aat-ltag-table.hh
@@ -60,7 +60,7 @@
 
 struct ltag
 {
-  enum { tableTag = HB_AAT_TAG_ltag };
+  static constexpr hb_tag_t tableTag = HB_AAT_TAG_ltag;
 
   hb_language_t get_language (unsigned int i) const
   {
diff --git a/src/hb-algs.hh b/src/hb-algs.hh
index 90f4c87..b4e79e8 100644
--- a/src/hb-algs.hh
+++ b/src/hb-algs.hh
@@ -272,10 +272,13 @@
 template <typename T> static inline T*
 hb_addressof (const T& arg)
 {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
   /* https://en.cppreference.com/w/cpp/memory/addressof */
   return reinterpret_cast<T*>(
 	   &const_cast<char&>(
 	      reinterpret_cast<const volatile char&>(arg)));
+#pragma GCC diagnostic pop
 }
 
 /* ASCII tag/character handling */
@@ -570,26 +573,26 @@
 
 struct HbOpOr
 {
-  enum { passthru_left = true };
-  enum { passthru_right = true };
+  static constexpr bool passthru_left = true;
+  static constexpr bool passthru_right = true;
   template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
 };
 struct HbOpAnd
 {
-  enum { passthru_left = false };
-  enum { passthru_right = false };
+  static constexpr bool passthru_left = false;
+  static constexpr bool passthru_right = false;
   template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
 };
 struct HbOpMinus
 {
-  enum { passthru_left = true };
-  enum { passthru_right = false };
+  static constexpr bool passthru_left = true;
+  static constexpr bool passthru_right = false;
   template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
 };
 struct HbOpXor
 {
-  enum { passthru_left = true };
-  enum { passthru_right = true };
+  static constexpr bool passthru_left = true;
+  static constexpr bool passthru_right = true;
   template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
 };
 
diff --git a/src/hb-array.hh b/src/hb-array.hh
index 6fd362f..62075c4 100644
--- a/src/hb-array.hh
+++ b/src/hb-array.hh
@@ -55,7 +55,7 @@
    * Iterator implementation.
    */
   typedef Type& __item_t__;
-  enum { is_random_access_iterator = true };
+  static constexpr bool is_random_access_iterator = true;
   Type& __item_at__ (unsigned i) const
   {
     if (unlikely (i >= length)) return CrapOrNull (Type);
@@ -200,8 +200,8 @@
 {
   typedef hb_iter_t<hb_sorted_array_t<Type>, Type&> iter_base_t;
   HB_ITER_USING (iter_base_t);
-  enum { is_random_access_iterator = true };
-  enum { is_sorted_iterator = true };
+  static constexpr bool is_random_access_iterator = true;
+  static constexpr bool is_sorted_iterator = true;
 
   hb_sorted_array_t () : hb_array_t<Type> () {}
   hb_sorted_array_t (const hb_array_t<Type> &o) : hb_array_t<Type> (o) {}
diff --git a/src/hb-buffer.hh b/src/hb-buffer.hh
index 8a3170c..330f88b 100644
--- a/src/hb-buffer.hh
+++ b/src/hb-buffer.hh
@@ -119,7 +119,7 @@
   /* Text before / after the main buffer contents.
    * Always in Unicode, and ordered outward.
    * Index 0 is for "pre-context", 1 for "post-context". */
-  enum { CONTEXT_LENGTH = 5 };
+  static constexpr unsigned CONTEXT_LENGTH = 5u;
   hb_codepoint_t context[2][CONTEXT_LENGTH];
   unsigned int context_len[2];
 
diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh
index 7b0b829..72e9e06 100644
--- a/src/hb-cff-interp-common.hh
+++ b/src/hb-cff-interp-common.hh
@@ -477,7 +477,7 @@
   unsigned int get_count () const { return count; }
   bool is_empty () const { return count == 0; }
 
-  enum { kSizeLimit = LIMIT };
+  static constexpr unsigned kSizeLimit = LIMIT;
 
   protected:
   bool error;
diff --git a/src/hb-common.h b/src/hb-common.h
index 247a02d..2b29e44 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -108,7 +108,7 @@
 typedef uint32_t hb_tag_t;
 
 #define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF)))
-#define HB_UNTAG(tag)   (((tag)>>24)&0xFF), (((tag)>>16)&0xFF), (((tag)>>8)&0xFF), ((tag)&0xFF)
+#define HB_UNTAG(tag)   (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)&0xFF)
 
 #define HB_TAG_NONE HB_TAG(0,0,0,0)
 #define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
diff --git a/src/hb-font.cc b/src/hb-font.cc
index afd20df..817a1a7 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -139,13 +139,10 @@
     for (unsigned int i = 0; i < count; i++)
     {
       if (!font->get_nominal_glyph (*first_unicode, first_glyph))
-        return i;
+	return i;
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-      first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
-      first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-#pragma GCC diagnostic pop
+      first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
     }
     return count;
   }
@@ -241,11 +238,8 @@
     for (unsigned int i = 0; i < count; i++)
     {
       *first_advance = font->get_glyph_h_advance (*first_glyph);
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-      first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-      first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
-#pragma GCC diagnostic pop
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
     return;
   }
@@ -256,10 +250,7 @@
   for (unsigned int i = 0; i < count; i++)
   {
     *first_advance = font->parent_scale_x_distance (*first_advance);
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
-#pragma GCC diagnostic pop
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
@@ -279,11 +270,8 @@
     for (unsigned int i = 0; i < count; i++)
     {
       *first_advance = font->get_glyph_v_advance (*first_glyph);
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-      first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-      first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
-#pragma GCC diagnostic pop
+      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
     }
     return;
   }
@@ -294,10 +282,7 @@
   for (unsigned int i = 0; i < count; i++)
   {
     *first_advance = font->parent_scale_y_distance (*first_advance);
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
-#pragma GCC diagnostic pop
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index 2f866f4..1900f30 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -228,11 +228,8 @@
        done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode));
        done++)
   {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-    first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
-    first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-#pragma GCC diagnostic pop
+    first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
+    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
   }
   /* We don't need to do ft_font->symbol dance here, since HB calls the singular
    * nominal_glyph() for what we don't handle here. */
@@ -295,11 +292,8 @@
     }
 
     *first_advance = (v * mult + (1<<9)) >> 10;
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-    first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
-#pragma GCC diagnostic pop
+    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
diff --git a/src/hb-iter.hh b/src/hb-iter.hh
index 0f0b4de..b538ddf 100644
--- a/src/hb-iter.hh
+++ b/src/hb-iter.hh
@@ -54,10 +54,10 @@
 {
   typedef Iter iter_t;
   typedef Item item_t;
-  enum { item_size = hb_static_size (Item) };
-  enum { is_iterator = true };
-  enum { is_random_access_iterator = false };
-  enum { is_sorted_iterator = false };
+  static constexpr unsigned item_size = hb_static_size (Item);
+  static constexpr bool is_iterator = true;
+  static constexpr bool is_random_access_iterator = false;
+  static constexpr bool is_sorted_iterator = false;
 
   private:
   /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
@@ -213,7 +213,7 @@
   hb_map_iter_t (const Iter& it, Proj&& f) : it (it), f (f) {}
 
   typedef decltype (hb_declval (Proj) (hb_declval (typename Iter::item_t))) __item_t__;
-  enum { is_random_access_iterator = Iter::is_random_access_iterator };
+  static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
   __item_t__ __item__ () const { return f (*it); }
   __item_t__ __item_at__ (unsigned i) const { return f (it[i]); }
   bool __more__ () const { return bool (it); }
@@ -255,7 +255,7 @@
   { while (it && !p (f (*it))) ++it; }
 
   typedef typename Iter::item_t __item_t__;
-  enum { is_sorted_iterator = Iter::is_sorted_iterator };
+  static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
   __item_t__ __item__ () const { return *it; }
   bool __more__ () const { return bool (it); }
   void __next__ () { do ++it; while (it && !p (f (*it))); }
@@ -295,12 +295,12 @@
   hb_zip_iter_t (A a, B b) : a (a), b (b) {}
 
   typedef hb_pair_t<typename A::item_t, typename B::item_t> __item_t__;
-  enum { is_random_access_iterator =
+  static constexpr bool is_random_access_iterator =
 	   A::is_random_access_iterator &&
-	   B::is_random_access_iterator };
-  enum { is_sorted_iterator =
+	   B::is_random_access_iterator;
+  static constexpr bool is_sorted_iterator =
 	   A::is_sorted_iterator &&
-	   B::is_sorted_iterator };
+	   B::is_sorted_iterator;
   __item_t__ __item__ () const { return __item_t__ (*a, *b); }
   __item_t__ __item_at__ (unsigned i) const { return __item_t__ (a[i], b[i]); }
   bool __more__ () const { return a && b; }
diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index f1ac848..ccad561 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -64,6 +64,22 @@
 template<typename Type>
 static inline Type& StructAtOffset(void *P, unsigned int offset)
 { return * reinterpret_cast<Type*> ((char *) P + offset); }
+template<typename Type>
+static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int offset)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+  return * reinterpret_cast<Type*> ((char *) P + offset);
+#pragma GCC diagnostic pop
+}
+template<typename Type>
+static inline Type& StructAtOffsetUnaligned(void *P, unsigned int offset)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+  return * reinterpret_cast<Type*> ((char *) P + offset);
+#pragma GCC diagnostic pop
+}
 
 /* StructAfter<T>(X) returns the struct T& that is placed after X.
  * Works with X of variable size also.  X must implement get_size() */
@@ -97,19 +113,19 @@
 #define DEFINE_SIZE_STATIC(size) \
   DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)) \
   unsigned int get_size () const { return (size); } \
-  enum { null_size = (size) }; \
-  enum { min_size = (size) }; \
+  static constexpr unsigned null_size = (size); \
+  static constexpr unsigned min_size = (size); \
   enum { static_size = (size) }
 
 #define DEFINE_SIZE_UNION(size, _member) \
   DEFINE_COMPILES_ASSERTION ((void) this->u._member.static_size) \
   DEFINE_INSTANCE_ASSERTION (sizeof(this->u._member) == (size)) \
-  enum { null_size = (size) }; \
+  static constexpr unsigned null_size = (size); \
   enum { min_size = (size) }
 
 #define DEFINE_SIZE_MIN(size) \
   DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)) \
-  enum { null_size = (size) }; \
+  static constexpr unsigned null_size = (size); \
   enum { min_size = (size) }
 
 #define DEFINE_SIZE_UNBOUNDED(size) \
@@ -119,7 +135,7 @@
 #define DEFINE_SIZE_ARRAY(size, array) \
   DEFINE_COMPILES_ASSERTION ((void) (array)[0].static_size) \
   DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof ((array)[0])) \
-  enum { null_size = (size) }; \
+  static constexpr unsigned null_size = (size); \
   enum { min_size = (size) }
 
 #define DEFINE_SIZE_ARRAY_SIZED(size, array) \
@@ -134,7 +150,7 @@
 template <typename Context, typename Return, unsigned int MaxDebugDepth>
 struct hb_dispatch_context_t
 {
-  enum { max_debug_depth = MaxDebugDepth };
+  static constexpr unsigned max_debug_depth = MaxDebugDepth;
   typedef Return return_t;
   template <typename T, typename F>
   bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; }
diff --git a/src/hb-map.hh b/src/hb-map.hh
index a825de4..8905421 100644
--- a/src/hb-map.hh
+++ b/src/hb-map.hh
@@ -163,7 +163,7 @@
   static constexpr hb_codepoint_t INVALID = HB_MAP_VALUE_INVALID;
 
   /* Map interface. */
-  enum { SENTINEL = INVALID };
+  static constexpr hb_codepoint_t SENTINEL = INVALID;
   typedef hb_codepoint_t value_t;
   value_t operator [] (hb_codepoint_t k) const { return get (k); }
   bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh
index 8c623b0..453b4fb 100644
--- a/src/hb-open-type.hh
+++ b/src/hb-open-type.hh
@@ -156,7 +156,7 @@
 
 /* Script/language-system/feature index */
 struct Index : HBUINT16 {
-  enum { NOT_FOUND_INDEX = 0xFFFFu };
+  static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu;
 };
 DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
 
@@ -353,7 +353,7 @@
 struct UnsizedArrayOf
 {
   typedef Type item_t;
-  enum { item_size = hb_static_size (Type) };
+  static constexpr unsigned item_size = hb_static_size (Type);
 
   HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (UnsizedArrayOf, Type);
 
@@ -509,7 +509,7 @@
 struct ArrayOf
 {
   typedef Type item_t;
-  enum { item_size = hb_static_size (Type) };
+  static constexpr unsigned item_size = hb_static_size (Type);
 
   HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOf, Type, LenType);
 
@@ -689,7 +689,7 @@
 template <typename Type, typename LenType=HBUINT16>
 struct HeadlessArrayOf
 {
-  enum { item_size = Type::static_size };
+  static constexpr unsigned item_size = Type::static_size;
 
   HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (HeadlessArrayOf, Type, LenType);
 
@@ -918,7 +918,7 @@
 template <typename Type>
 struct VarSizedBinSearchArrayOf
 {
-  enum { item_size = Type::static_size };
+  static constexpr unsigned item_size = Type::static_size;
 
   HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (VarSizedBinSearchArrayOf, Type);
 
diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh
index 073dd7e..1effdf0 100644
--- a/src/hb-ot-cff1-table.hh
+++ b/src/hb-ot-cff1-table.hh
@@ -984,7 +984,7 @@
 
 struct cff1
 {
-  enum { tableTag = HB_OT_TAG_cff1 };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_cff1;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh
index cd37863..a7b0ba9 100644
--- a/src/hb-ot-cff2-table.hh
+++ b/src/hb-ot-cff2-table.hh
@@ -408,7 +408,7 @@
 
 struct cff2
 {
-  enum { tableTag = HB_OT_TAG_cff2 };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_cff2;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 0882dc8..3846d46 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -841,7 +841,7 @@
 
 struct cmap
 {
-  enum { tableTag = HB_OT_TAG_cmap };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
 
   struct subset_plan
   {
@@ -1054,11 +1054,8 @@
 	   done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph);
 	   done++)
       {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-	first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
-	first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-#pragma GCC diagnostic pop
+	first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
+	first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
       }
       return done;
     }
diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh
index 939aeb1..71c31af 100644
--- a/src/hb-ot-color-cbdt-table.hh
+++ b/src/hb-ot-color-cbdt-table.hh
@@ -332,7 +332,7 @@
 {
   friend struct CBDT;
 
-  enum { tableTag = HB_OT_TAG_CBLC };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_CBLC;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -378,7 +378,7 @@
 
 struct CBDT
 {
-  enum { tableTag = HB_OT_TAG_CBDT };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_CBDT;
 
   struct accelerator_t
   {
diff --git a/src/hb-ot-color-colr-table.hh b/src/hb-ot-color-colr-table.hh
index cdb986a..a57911a 100644
--- a/src/hb-ot-color-colr-table.hh
+++ b/src/hb-ot-color-colr-table.hh
@@ -87,7 +87,7 @@
 
 struct COLR
 {
-  enum { tableTag = HB_OT_TAG_COLR };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
 
   bool has_data () const { return numBaseGlyphs; }
 
diff --git a/src/hb-ot-color-cpal-table.hh b/src/hb-ot-color-cpal-table.hh
index 81451d3..4070493 100644
--- a/src/hb-ot-color-cpal-table.hh
+++ b/src/hb-ot-color-cpal-table.hh
@@ -107,7 +107,7 @@
 
 struct CPAL
 {
-  enum { tableTag = HB_OT_TAG_CPAL };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_CPAL;
 
   bool has_data () const { return numPalettes; }
 
diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh
index ed93d65..f6bdbb3 100644
--- a/src/hb-ot-color-sbix-table.hh
+++ b/src/hb-ot-color-sbix-table.hh
@@ -130,7 +130,7 @@
 
 struct sbix
 {
-  enum { tableTag = HB_OT_TAG_sbix };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_sbix;
 
   bool has_data () const { return version; }
 
diff --git a/src/hb-ot-color-svg-table.hh b/src/hb-ot-color-svg-table.hh
index 46f20d7..6e8eddf 100644
--- a/src/hb-ot-color-svg-table.hh
+++ b/src/hb-ot-color-svg-table.hh
@@ -73,7 +73,7 @@
 
 struct SVG
 {
-  enum { tableTag = HB_OT_TAG_SVG };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_SVG;
 
   bool has_data () const { return svgDocEntries; }
 
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index 81bc97f..20b09df 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -112,11 +112,8 @@
   for (unsigned int i = 0; i < count; i++)
   {
     *first_advance = font->em_scale_x (hmtx.get_advance (*first_glyph, font));
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-    first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
-#pragma GCC diagnostic pop
+    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
@@ -135,11 +132,8 @@
   for (unsigned int i = 0; i < count; i++)
   {
     *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font));
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-    first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
-    first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
-#pragma GCC diagnostic pop
+    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
   }
 }
 
diff --git a/src/hb-ot-gasp-table.hh b/src/hb-ot-gasp-table.hh
index d328fd2..94fff58 100644
--- a/src/hb-ot-gasp-table.hh
+++ b/src/hb-ot-gasp-table.hh
@@ -57,7 +57,7 @@
 
 struct gasp
 {
-  enum { tableTag = HB_OT_TAG_gasp };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_gasp;
 
   const GaspRange &get_gasp_range (unsigned int i) const
   { return gaspRanges[i]; }
diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh
index f568cf0..c2b38b0 100644
--- a/src/hb-ot-glyf-table.hh
+++ b/src/hb-ot-glyf-table.hh
@@ -45,7 +45,7 @@
 {
   friend struct glyf;
 
-  enum { tableTag = HB_OT_TAG_loca };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_loca;
 
   bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
   {
@@ -71,7 +71,7 @@
 
 struct glyf
 {
-  enum { tableTag = HB_OT_TAG_glyf };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf;
 
   bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
   {
diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh
index 02ae8d8..95229c5 100644
--- a/src/hb-ot-hdmx-table.hh
+++ b/src/hb-ot-hdmx-table.hh
@@ -119,7 +119,7 @@
 
 struct hdmx
 {
-  enum { tableTag = HB_OT_TAG_hdmx };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_hdmx;
 
   unsigned int get_size () const
   { return min_size + numRecords * sizeDeviceRecord; }
diff --git a/src/hb-ot-head-table.hh b/src/hb-ot-head-table.hh
index 41062ca..3c0bb3d 100644
--- a/src/hb-ot-head-table.hh
+++ b/src/hb-ot-head-table.hh
@@ -45,7 +45,7 @@
 {
   friend struct OffsetTable;
 
-  enum { tableTag = HB_OT_TAG_head };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_head;
 
   unsigned int get_upem () const
   {
diff --git a/src/hb-ot-hhea-table.hh b/src/hb-ot-hhea-table.hh
index 7bc1817..c3155b7 100644
--- a/src/hb-ot-hhea-table.hh
+++ b/src/hb-ot-hhea-table.hh
@@ -86,10 +86,10 @@
 };
 
 struct hhea : _hea<hhea> {
-  enum { tableTag = HB_OT_TAG_hhea };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_hhea;
 };
 struct vhea : _hea<vhea> {
-  enum { tableTag = HB_OT_TAG_vhea };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_vhea;
 };
 
 
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index 0a16678..a95a56f 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -323,14 +323,14 @@
 };
 
 struct hmtx : hmtxvmtx<hmtx, hhea> {
-  enum { tableTag = HB_OT_TAG_hmtx };
-  enum { variationsTag = HB_OT_TAG_HVAR };
-  enum { os2Tag = HB_OT_TAG_OS2 };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx;
+  static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR;
+  static constexpr hb_tag_t os2Tag = HB_OT_TAG_OS2;
 };
 struct vmtx : hmtxvmtx<vmtx, vhea> {
-  enum { tableTag = HB_OT_TAG_vmtx };
-  enum { variationsTag = HB_OT_TAG_VVAR };
-  enum { os2Tag = HB_TAG_NONE };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx;
+  static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR;
+  static constexpr hb_tag_t os2Tag = HB_TAG_NONE;
 };
 
 struct hmtx_accelerator_t : hmtx::accelerator_t {};
diff --git a/src/hb-ot-kern-table.hh b/src/hb-ot-kern-table.hh
index 5e75d08..ec6a3c8 100644
--- a/src/hb-ot-kern-table.hh
+++ b/src/hb-ot-kern-table.hh
@@ -160,7 +160,7 @@
 
 struct KernOTSubTableHeader
 {
-  enum { apple = false };
+  static constexpr bool apple = false;
   typedef AAT::ObsoleteTypes Types;
 
   unsigned int tuple_count () const { return 0; }
@@ -197,8 +197,8 @@
 {
   friend struct AAT::KerxTable<KernOT>;
 
-  enum { tableTag = HB_OT_TAG_kern };
-  enum { minVersion = 0u };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
+  static constexpr unsigned minVersion = 0u;
 
   typedef KernOTSubTableHeader SubTableHeader;
   typedef SubTableHeader::Types Types;
@@ -215,7 +215,7 @@
 
 struct KernAATSubTableHeader
 {
-  enum { apple = true };
+  static constexpr bool apple = true;
   typedef AAT::ObsoleteTypes Types;
 
   unsigned int tuple_count () const { return 0; }
@@ -252,8 +252,8 @@
 {
   friend struct AAT::KerxTable<KernAAT>;
 
-  enum { tableTag = HB_OT_TAG_kern };
-  enum { minVersion = 0x00010000u };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
+  static constexpr unsigned minVersion = 0x00010000u;
 
   typedef KernAATSubTableHeader SubTableHeader;
   typedef SubTableHeader::Types Types;
@@ -269,7 +269,7 @@
 
 struct kern
 {
-  enum { tableTag = HB_OT_TAG_kern };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
 
   bool has_data () const { return u.version32; }
   unsigned int get_type () const { return u.major; }
diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh
index 6c39932..dd0fba1 100644
--- a/src/hb-ot-layout-base-table.hh
+++ b/src/hb-ot-layout-base-table.hh
@@ -464,7 +464,7 @@
 
 struct BASE
 {
-  enum { tableTag = HB_OT_TAG_BASE };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_BASE;
 
   const Axis &get_axis (hb_direction_t direction) const
   { return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; }
diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh
index ec05694..c163140 100644
--- a/src/hb-ot-layout-common.hh
+++ b/src/hb-ot-layout-common.hh
@@ -1036,7 +1036,7 @@
 struct Coverage
 {
   /* Map interface. */
-  enum { SENTINEL = NOT_COVERED };
+  static constexpr unsigned SENTINEL = NOT_COVERED;
   typedef unsigned int value_t;
   value_t operator [] (hb_codepoint_t k) const { return get (k); }
   bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
@@ -1123,7 +1123,7 @@
     hb_iter_t<iter_t, hb_codepoint_t>,
     hb_iter_mixin_t<iter_t, hb_codepoint_t>
   {
-    enum { is_sorted_iterator = true };
+    static constexpr bool is_sorted_iterator = true;
     iter_t (const Coverage &c_ = Null(Coverage))
     {
       memset (this, 0, sizeof (*this));
@@ -1481,7 +1481,7 @@
 struct ClassDef
 {
   /* Map interface. */
-  enum { SENTINEL = 0 };
+  static constexpr unsigned SENTINEL = 0;
   typedef unsigned int value_t;
   value_t operator [] (hb_codepoint_t k) const { return get (k); }
   bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
@@ -1969,7 +1969,7 @@
 
 struct FeatureVariations
 {
-  enum { NOT_FOUND_INDEX = 0xFFFFFFFFu };
+  static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFFFFFu;
 
   bool find_index (const int *coords, unsigned int coord_len,
 			  unsigned int *index) const
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index 58be094..06c26fb 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -341,7 +341,7 @@
 
 struct GDEF
 {
-  enum { tableTag = HB_OT_TAG_GDEF };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
 
   enum GlyphClasses {
     UnclassifiedGlyph	= 0,
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index dcb2545..485458a 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1597,7 +1597,7 @@
 
 struct GPOS : GSUBGPOS
 {
-  enum { tableTag = HB_OT_TAG_GPOS };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
 
   const PosLookup& get_lookup (unsigned int i) const
   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 074c7bb..1b60ce2 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1363,7 +1363,7 @@
 
 struct GSUB : GSUBGPOS
 {
-  enum { tableTag = HB_OT_TAG_GSUB };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
 
   const SubstLookup& get_lookup (unsigned int i) const
   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index f3a59a6..4b10e4d 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -2644,7 +2644,7 @@
   { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
 	   .find_index (coords, num_coords, index); }
   const Feature& get_feature_variation (unsigned int feature_index,
-					       unsigned int variations_index) const
+					unsigned int variations_index) const
   {
     if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
 	version.to_int () >= 0x00010001u)
diff --git a/src/hb-ot-layout-jstf-table.hh b/src/hb-ot-layout-jstf-table.hh
index 3beedc4..1dd31d5 100644
--- a/src/hb-ot-layout-jstf-table.hh
+++ b/src/hb-ot-layout-jstf-table.hh
@@ -195,7 +195,7 @@
 
 struct JSTF
 {
-  enum { tableTag = HB_OT_TAG_JSTF };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_JSTF;
 
   unsigned int get_script_count () const
   { return scriptList.len; }
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 672d4ee..d32be04 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -1299,8 +1299,8 @@
 
 struct GSUBProxy
 {
-  enum { table_index = 0 };
-  enum { inplace = false };
+  static constexpr unsigned table_index = 0u;
+  static constexpr bool inplace = false;
   typedef OT::SubstLookup Lookup;
 
   GSUBProxy (hb_face_t *face) :
@@ -1313,8 +1313,8 @@
 
 struct GPOSProxy
 {
-  enum { table_index = 1 };
-  enum { inplace = true };
+  static constexpr unsigned table_index = 1u;
+  static constexpr bool inplace = true;
   typedef OT::PosLookup Lookup;
 
   GPOSProxy (hb_face_t *face) :
@@ -1387,7 +1387,7 @@
   if (likely (!lookup.is_reverse ()))
   {
     /* in/out forward substitution/positioning */
-    if (Proxy::table_index == 0)
+    if (Proxy::table_index == 0u)
       buffer->clear_output ();
     buffer->idx = 0;
 
@@ -1404,7 +1404,7 @@
   else
   {
     /* in-place backward substitution/positioning */
-    if (Proxy::table_index == 0)
+    if (Proxy::table_index == 0u)
       buffer->remove_output ();
     buffer->idx = buffer->len - 1;
 
diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh
index ae0016f..62bf072 100644
--- a/src/hb-ot-math-table.hh
+++ b/src/hb-ot-math-table.hh
@@ -679,7 +679,7 @@
 
 struct MATH
 {
-  enum { tableTag = HB_OT_TAG_MATH };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH;
 
   bool has_data () const { return version.to_int (); }
 
diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index 3bbc803..e4b67ab 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -71,7 +71,7 @@
 
 struct maxp
 {
-  enum { tableTag = HB_OT_TAG_maxp };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_maxp;
 
   unsigned int get_num_glyphs () const { return numGlyphs; }
 
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 2d5ac63..c8ababd 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -151,7 +151,7 @@
 
 struct name
 {
-  enum { tableTag = HB_OT_TAG_name };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_name;
 
   unsigned int get_size () const
   { return min_size + count * nameRecordZ.item_size; }
diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh
index 4c1812c..68dd63e 100644
--- a/src/hb-ot-os2-table.hh
+++ b/src/hb-ot-os2-table.hh
@@ -92,7 +92,7 @@
 
 struct OS2
 {
-  enum { tableTag = HB_OT_TAG_OS2 };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_OS2;
 
   bool has_data () const { return this != &Null (OS2); }
 
diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh
index a799b86..43c1143 100644
--- a/src/hb-ot-post-table.hh
+++ b/src/hb-ot-post-table.hh
@@ -71,7 +71,7 @@
 
 struct post
 {
-  enum { tableTag = HB_OT_TAG_post };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_post;
 
   bool subset (hb_subset_plan_t *plan) const
   {
diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc
index d3afdff..f9d4a75 100644
--- a/src/hb-ot-shape-fallback.cc
+++ b/src/hb-ot-shape-fallback.cc
@@ -180,12 +180,18 @@
 static void
 zero_mark_advances (hb_buffer_t *buffer,
 		    unsigned int start,
-		    unsigned int end)
+		    unsigned int end,
+		    bool adjust_offsets_when_zeroing)
 {
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = start; i < end; i++)
     if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
     {
+      if (adjust_offsets_when_zeroing)
+      {
+	buffer->pos[i].x_offset -= buffer->pos[i].x_advance;
+	buffer->pos[i].y_offset -= buffer->pos[i].y_advance;
+      }
       buffer->pos[i].x_advance = 0;
       buffer->pos[i].y_advance = 0;
     }
@@ -303,7 +309,8 @@
 		      hb_font_t *font,
 		      hb_buffer_t  *buffer,
 		      unsigned int base,
-		      unsigned int end)
+		      unsigned int end,
+		      bool adjust_offsets_when_zeroing)
 {
   hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
 
@@ -314,11 +321,15 @@
 				&base_extents))
   {
     /* If extents don't work, zero marks and go home. */
-    zero_mark_advances (buffer, base + 1, end);
+    zero_mark_advances (buffer, base + 1, end, adjust_offsets_when_zeroing);
     return;
   }
-  base_extents.x_bearing += buffer->pos[base].x_offset;
   base_extents.y_bearing += buffer->pos[base].y_offset;
+  /* Use horizontal advance for horizontal positioning.
+   * Generally a better idea.  Also works for zero-ink glyphs.  See:
+   * https://github.com/harfbuzz/harfbuzz/issues/1532 */
+  base_extents.x_bearing = 0;
+  base_extents.width = font->get_glyph_h_advance (buffer->info[base].codepoint);
 
   unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]);
   /* Use integer for num_lig_components such that it doesn't convert to unsigned
@@ -394,7 +405,8 @@
 		  hb_font_t *font,
 		  hb_buffer_t  *buffer,
 		  unsigned int start,
-		  unsigned int end)
+		  unsigned int end,
+		  bool adjust_offsets_when_zeroing)
 {
   if (end - start < 2)
     return;
@@ -410,7 +422,7 @@
 	if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j])))
 	  break;
 
-      position_around_base (plan, font, buffer, i, j);
+      position_around_base (plan, font, buffer, i, j, adjust_offsets_when_zeroing);
 
       i = j - 1;
     }
@@ -419,7 +431,8 @@
 void
 _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan,
 				     hb_font_t *font,
-				     hb_buffer_t  *buffer)
+				     hb_buffer_t  *buffer,
+				     bool adjust_offsets_when_zeroing)
 {
   _hb_buffer_assert_gsubgpos_vars (buffer);
 
@@ -428,10 +441,10 @@
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 1; i < count; i++)
     if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) {
-      position_cluster (plan, font, buffer, start, i);
+      position_cluster (plan, font, buffer, start, i, adjust_offsets_when_zeroing);
       start = i;
     }
-  position_cluster (plan, font, buffer, start, count);
+  position_cluster (plan, font, buffer, start, count, adjust_offsets_when_zeroing);
 }
 
 
diff --git a/src/hb-ot-shape-fallback.hh b/src/hb-ot-shape-fallback.hh
index 12f18ed..5faf5f2 100644
--- a/src/hb-ot-shape-fallback.hh
+++ b/src/hb-ot-shape-fallback.hh
@@ -34,7 +34,8 @@
 
 HB_INTERNAL void _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan,
 						      hb_font_t *font,
-						      hb_buffer_t  *buffer);
+						      hb_buffer_t  *buffer,
+						      bool adjust_offsets_when_zeroing);
 
 HB_INTERNAL void _hb_ot_shape_fallback_mark_position_recategorize_marks (const hb_ot_shape_plan_t *plan,
 									 hb_font_t *font,
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 6e5ce15..e9d97c9 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -428,6 +428,20 @@
 	_hb_glyph_info_set_continuation (&info[i]);
       }
     }
+    /* Or part of the Other_Grapheme_Extend that is not marks.
+     * As of Unicode 11 that is just:
+     *
+     * 200C          ; Other_Grapheme_Extend # Cf       ZERO WIDTH NON-JOINER
+     * FF9E..FF9F    ; Other_Grapheme_Extend # Lm   [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+     * E0020..E007F  ; Other_Grapheme_Extend # Cf  [96] TAG SPACE..CANCEL TAG
+     *
+     * ZWNJ is special, we don't want to merge it as there's no need, and keeping
+     * it separate results in more granular clusters.  Ignore Katakana for now.
+     * Tags are used for Emoji sub-region flag sequences:
+     * https://github.com/harfbuzz/harfbuzz/issues/1556
+     */
+    else if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0xE0020u, 0xE007Fu)))
+      _hb_glyph_info_set_continuation (&info[i]);
   }
 }
 
@@ -891,7 +905,8 @@
 					&pos[i].y_offset);
 
   if (c->plan->fallback_mark_positioning)
-    _hb_ot_shape_fallback_mark_position (c->plan, c->font, c->buffer);
+    _hb_ot_shape_fallback_mark_position (c->plan, c->font, c->buffer,
+					 adjust_offsets_when_zeroing);
 }
 
 static inline void
diff --git a/src/hb-ot-stat-table.hh b/src/hb-ot-stat-table.hh
index d85958b..04a2ee9 100644
--- a/src/hb-ot-stat-table.hh
+++ b/src/hb-ot-stat-table.hh
@@ -225,7 +225,7 @@
 
 struct STAT
 {
-  enum { tableTag = HB_OT_TAG_STAT };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-var-avar-table.hh b/src/hb-ot-var-avar-table.hh
index 67a60f5e..c4a192d 100644
--- a/src/hb-ot-var-avar-table.hh
+++ b/src/hb-ot-var-avar-table.hh
@@ -99,7 +99,7 @@
 
 struct avar
 {
-  enum { tableTag = HB_OT_TAG_avar };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_avar;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh
index 92d164c..78cb3c8 100644
--- a/src/hb-ot-var-fvar-table.hh
+++ b/src/hb-ot-var-fvar-table.hh
@@ -96,7 +96,7 @@
 
 struct fvar
 {
-  enum { tableTag = HB_OT_TAG_fvar };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_fvar;
 
   bool has_data () const { return version.to_int (); }
 
diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh
index 2640f07..a8d9fe3 100644
--- a/src/hb-ot-var-hvar-table.hh
+++ b/src/hb-ot-var-hvar-table.hh
@@ -100,8 +100,8 @@
 
 struct HVARVVAR
 {
-  enum { HVARTag = HB_OT_TAG_HVAR };
-  enum { VVARTag = HB_OT_TAG_VVAR };
+  static constexpr hb_tag_t HVARTag = HB_OT_TAG_HVAR;
+  static constexpr hb_tag_t VVARTag = HB_OT_TAG_VVAR;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -140,10 +140,10 @@
 };
 
 struct HVAR : HVARVVAR {
-  enum { tableTag = HB_OT_TAG_HVAR };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_HVAR;
 };
 struct VVAR : HVARVVAR {
-  enum { tableTag = HB_OT_TAG_VVAR };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_VVAR;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-var-mvar-table.hh b/src/hb-ot-var-mvar-table.hh
index a5eeddc..0dd63e5 100644
--- a/src/hb-ot-var-mvar-table.hh
+++ b/src/hb-ot-var-mvar-table.hh
@@ -58,7 +58,7 @@
 
 struct MVAR
 {
-  enum { tableTag = HB_OT_TAG_MVAR };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_MVAR;
 
   bool sanitize (hb_sanitize_context_t *c) const
   {
diff --git a/src/hb-ot-vorg-table.hh b/src/hb-ot-vorg-table.hh
index f11c745..0202fcc 100644
--- a/src/hb-ot-vorg-table.hh
+++ b/src/hb-ot-vorg-table.hh
@@ -57,7 +57,7 @@
 
 struct VORG
 {
-  enum { tableTag = HB_OT_TAG_VORG };
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_VORG;
 
   bool has_data () const { return version.to_int (); }
 
diff --git a/src/hb-set-digest.hh b/src/hb-set-digest.hh
index 9f49af1..7ec275e 100644
--- a/src/hb-set-digest.hh
+++ b/src/hb-set-digest.hh
@@ -48,8 +48,8 @@
 template <typename mask_t, unsigned int shift>
 struct hb_set_digest_lowest_bits_t
 {
-  enum { mask_bytes = sizeof (mask_t) };
-  enum { mask_bits = sizeof (mask_t) * 8 };
+  static constexpr unsigned mask_bytes = sizeof (mask_t);
+  static constexpr unsigned mask_bits = sizeof (mask_t) * 8;
   enum { num_bits = 0
 		  + (mask_bytes >= 1 ? 3 : 0)
 		  + (mask_bytes >= 2 ? 1 : 0)
diff --git a/src/hb-set.hh b/src/hb-set.hh
index c3c981b..c0f6b88 100644
--- a/src/hb-set.hh
+++ b/src/hb-set.hh
@@ -161,7 +161,7 @@
     }
 
     typedef unsigned long long elt_t;
-    enum { PAGE_BITS = 512 };
+    static constexpr unsigned PAGE_BITS = 512;
     static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
 
     static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
@@ -169,10 +169,10 @@
 
     typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
 
-    enum { ELT_BITS = sizeof (elt_t) * 8 };
-    enum { ELT_MASK = ELT_BITS - 1 };
-    enum { BITS = sizeof (vector_t) * 8 };
-    enum { MASK = BITS - 1 };
+    static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
+    static constexpr unsigned ELT_MASK = ELT_BITS - 1;
+    static constexpr unsigned BITS = sizeof (vector_t) * 8;
+    static constexpr unsigned MASK = BITS - 1;
     static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
 
     elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
@@ -366,7 +366,7 @@
   }
 
   /* Map interface. */
-  enum { SENTINEL = false };
+  static constexpr bool SENTINEL = false;
   typedef bool value_t;
   value_t operator [] (hb_codepoint_t k) const { return get (k); }
   bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
@@ -682,7 +682,7 @@
     hb_iter_t<iter_t, hb_codepoint_t>,
     hb_iter_mixin_t<iter_t, hb_codepoint_t>
   {
-    enum { is_sorted_iterator = true };
+    static constexpr bool is_sorted_iterator = true;
     iter_t (const hb_set_t &s_ = Null(hb_set_t)) :
       s (&s_), v (INVALID), l (s->get_population () + 1) { __next__ (); }
 
diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc
index a864540..5133a4d 100644
--- a/src/hb-subset-cff1.cc
+++ b/src/hb-subset-cff1.cc
@@ -882,7 +882,7 @@
 
   /* name INDEX */
   {
-    assert (cff->nameIndex == c.head - c.start);
+    assert (cff->nameIndex == (unsigned) (c.head - c.start));
     CFF1NameIndex *dest = c.start_embed<CFF1NameIndex> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c, *acc.nameIndex)))
@@ -894,7 +894,7 @@
 
   /* top dict INDEX */
   {
-    assert (plan.offsets.topDictInfo.offset == c.head - c.start);
+    assert (plan.offsets.topDictInfo.offset == (unsigned) (c.head - c.start));
     CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict> > ();
     if (dest == nullptr) return false;
     cff1_top_dict_op_serializer_t topSzr;
@@ -910,7 +910,7 @@
 
   /* String INDEX */
   {
-    assert (plan.offsets.stringIndexInfo.offset == c.head - c.start);
+    assert (plan.offsets.stringIndexInfo.offset == (unsigned) (c.head - c.start));
     CFF1StringIndex *dest = c.start_embed<CFF1StringIndex> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c, *acc.stringIndex, plan.offsets.stringIndexInfo.offSize, plan.sidmap)))
@@ -923,7 +923,7 @@
   /* global subrs */
   {
     assert (plan.offsets.globalSubrsInfo.offset != 0);
-    assert (plan.offsets.globalSubrsInfo.offset == c.head - c.start);
+    assert (plan.offsets.globalSubrsInfo.offset == (unsigned) (c.head - c.start));
 
     CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
     if (unlikely (dest == nullptr)) return false;
@@ -937,7 +937,7 @@
   /* Encoding */
   if (plan.subset_encoding)
   {
-    assert (plan.offsets.encodingOffset == c.head - c.start);
+    assert (plan.offsets.encodingOffset == (unsigned) (c.head - c.start));
     Encoding *dest = c.start_embed<Encoding> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c,
@@ -954,7 +954,7 @@
   /* Charset */
   if (plan.subset_charset)
   {
-    assert (plan.offsets.charsetInfo.offset == c.head - c.start);
+    assert (plan.offsets.charsetInfo.offset == (unsigned) (c.head - c.start));
     Charset *dest = c.start_embed<Charset> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c,
@@ -970,7 +970,7 @@
   /* FDSelect */
   if (acc.fdSelect != &Null(CFF1FDSelect))
   {
-    assert (plan.offsets.FDSelectInfo.offset == c.head - c.start);
+    assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start));
 
     if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.length, *acc.fdSelect, acc.fdCount,
 					      plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
@@ -984,7 +984,7 @@
   /* FDArray (FD Index) */
   if (acc.fdArray != &Null(CFF1FDArray))
   {
-    assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
+    assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start));
     CFF1FDArray  *fda = c.start_embed<CFF1FDArray> ();
     if (unlikely (fda == nullptr)) return false;
     cff1_font_dict_op_serializer_t  fontSzr;
@@ -999,7 +999,7 @@
 
   /* CharStrings */
   {
-    assert (plan.offsets.charStringsInfo.offset == c.head - c.start);
+    assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start));
     CFF1CharStrings  *cs = c.start_embed<CFF1CharStrings> ();
     if (unlikely (cs == nullptr)) return false;
     if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
@@ -1010,7 +1010,7 @@
   }
 
   /* private dicts & local subrs */
-  assert (plan.offsets.privateDictInfo.offset == c.head - c.start);
+  assert (plan.offsets.privateDictInfo.offset == (unsigned) (c.head - c.start));
   for (unsigned int i = 0; i < acc.privateDicts.length; i++)
   {
     if (plan.fdmap.includes (i))
diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc
index 8d32b7d..73a292d 100644
--- a/src/hb-subset-cff2.cc
+++ b/src/hb-subset-cff2.cc
@@ -453,7 +453,7 @@
 
   /* top dict */
   {
-    assert (cff2->topDict == c.head - c.start);
+    assert (cff2->topDict == (unsigned) (c.head - c.start));
     cff2->topDictSize.set (plan.offsets.topDictInfo.size);
     TopDict &dict = cff2 + cff2->topDict;
     cff2_top_dict_op_serializer_t topSzr;
@@ -466,7 +466,7 @@
 
   /* global subrs */
   {
-    assert (cff2->topDict + plan.offsets.topDictInfo.size == c.head - c.start);
+    assert (cff2->topDict + plan.offsets.topDictInfo.size == (unsigned) (c.head - c.start));
     CFF2Subrs *dest = c.start_embed <CFF2Subrs> ();
     if (unlikely (dest == nullptr)) return false;
     if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs)))
@@ -479,7 +479,7 @@
   /* variation store */
   if (acc.varStore != &Null(CFF2VariationStore))
   {
-    assert (plan.offsets.varStoreOffset == c.head - c.start);
+    assert (plan.offsets.varStoreOffset == (unsigned) (c.head - c.start));
     CFF2VariationStore *dest = c.start_embed<CFF2VariationStore> ();
     if (unlikely (!dest->serialize (&c, acc.varStore)))
     {
@@ -491,7 +491,7 @@
   /* FDSelect */
   if (acc.fdSelect != &Null(CFF2FDSelect))
   {
-    assert (plan.offsets.FDSelectInfo.offset == c.head - c.start);
+    assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start));
 
     if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.length, *(const FDSelect *)acc.fdSelect, acc.fdArray->count,
 					      plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
@@ -504,7 +504,7 @@
 
   /* FDArray (FD Index) */
   {
-    assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
+    assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start));
     CFF2FDArray  *fda = c.start_embed<CFF2FDArray> ();
     if (unlikely (fda == nullptr)) return false;
     cff_font_dict_op_serializer_t  fontSzr;
@@ -519,7 +519,7 @@
 
   /* CharStrings */
   {
-    assert (plan.offsets.charStringsInfo.offset == c.head - c.start);
+    assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start));
     CFF2CharStrings  *cs = c.start_embed<CFF2CharStrings> ();
     if (unlikely (cs == nullptr)) return false;
     if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
@@ -530,7 +530,7 @@
   }
 
   /* private dicts & local subrs */
-  assert (plan.offsets.privateDictsOffset == c.head - c.start);
+  assert (plan.offsets.privateDictsOffset == (unsigned) (c.head - c.start));
   for (unsigned int i = 0; i < acc.privateDicts.length; i++)
   {
     if (plan.fdmap.includes (i))
diff --git a/src/hb-vector.hh b/src/hb-vector.hh
index 27f4101..00f4479 100644
--- a/src/hb-vector.hh
+++ b/src/hb-vector.hh
@@ -36,7 +36,7 @@
 struct hb_vector_t
 {
   typedef Type item_t;
-  enum { item_size = hb_static_size (Type) };
+  static constexpr unsigned item_size = hb_static_size (Type);
 
   HB_NO_COPY_ASSIGN_TEMPLATE (hb_vector_t, Type);
   hb_vector_t ()  { init (); }
diff --git a/src/hb.hh b/src/hb.hh
index ffefa62..0b535af 100644
--- a/src/hb.hh
+++ b/src/hb.hh
@@ -29,7 +29,7 @@
 #ifndef HB_HH
 #define HB_HH
 
-#ifndef HB_NO_DIAGNOSTIC_PRAGMAS
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC
 #if defined(__GNUC__) || defined(__clang__)
 /* Rules:
  *
@@ -43,14 +43,21 @@
  */
 
 /* Setup.  Don't sort order within this category. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING
 #pragma GCC diagnostic warning "-Wall"
 #pragma GCC diagnostic warning "-Wextra"
+#endif
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED
 #pragma GCC diagnostic ignored "-Wpragmas"
 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
 #pragma GCC diagnostic ignored "-Wunknown-warning-option"
+#endif
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING
 //#pragma GCC diagnostic warning "-Weverything"
+#endif
 
 /* Error.  Should never happen. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_ERROR
 #pragma GCC diagnostic error   "-Wc++11-narrowing"
 #pragma GCC diagnostic error   "-Wcast-align"
 #pragma GCC diagnostic error   "-Wdelete-non-virtual-dtor"
@@ -65,6 +72,7 @@
 #pragma GCC diagnostic error   "-Wpointer-arith"
 #pragma GCC diagnostic error   "-Wredundant-decls"
 #pragma GCC diagnostic error   "-Wreorder"
+#pragma GCC diagnostic error   "-Wsign-compare"
 #pragma GCC diagnostic error   "-Wstrict-prototypes"
 #pragma GCC diagnostic error   "-Wstring-conversion"
 #pragma GCC diagnostic error   "-Wswitch-enum"
@@ -74,9 +82,12 @@
 #pragma GCC diagnostic error   "-Wunused-local-typedefs"
 #pragma GCC diagnostic error   "-Wunused-value"
 #pragma GCC diagnostic error   "-Wunused-variable"
+#pragma GCC diagnostic error   "-Wvla"
 #pragma GCC diagnostic error   "-Wwrite-strings"
+#endif
 
 /* Warning.  To be investigated if happens. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING
 #pragma GCC diagnostic warning "-Wbuiltin-macro-redefined"
 #pragma GCC diagnostic warning "-Wdisabled-optimization"
 #pragma GCC diagnostic warning "-Wformat=2"
@@ -84,18 +95,20 @@
 #pragma GCC diagnostic warning "-Wlogical-op"
 #pragma GCC diagnostic warning "-Wmaybe-uninitialized"
 #pragma GCC diagnostic warning "-Wmissing-format-attribute"
-#pragma GCC diagnostic warning "-Wsign-compare"
 #pragma GCC diagnostic warning "-Wundef"
-#pragma GCC diagnostic warning "-Wvla"
+#endif
 
 /* Ignored currently, but should be fixed at some point. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED
 #pragma GCC diagnostic ignored "-Wconversion"			// TODO fix
 #pragma GCC diagnostic ignored "-Wformat-signedness"		// TODO fix
 #pragma GCC diagnostic ignored "-Wshadow"			// TODO fix
 #pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"	// TODO fix
 #pragma GCC diagnostic ignored "-Wunused-parameter"		// TODO fix
+#endif
 
 /* Ignored intentionally. */
+#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED
 #pragma GCC diagnostic ignored "-Wclass-memaccess"
 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
 #pragma GCC diagnostic ignored "-Wformat-zero-length"
@@ -103,6 +116,7 @@
 #pragma GCC diagnostic ignored "-Wpacked" // Erratic impl in clang
 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
 #pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
 
 #endif
 #endif
diff --git a/src/test-iter.cc b/src/test-iter.cc
index e3b258f..2b23901 100644
--- a/src/test-iter.cc
+++ b/src/test-iter.cc
@@ -40,7 +40,7 @@
   array_iter_t (hb_array_t<T> arr_) : arr (arr_) {}
 
   typedef T& __item_t__;
-  enum { is_random_access_iterator = true };
+  static constexpr bool is_random_access_iterator = true;
   T& __item_at__ (unsigned i) const { return arr[i]; }
   void __forward__ (unsigned n) { arr += n; }
   void __rewind__ (unsigned n) { arr -= n; }
diff --git a/test/shaping/data/in-house/fonts/8d9c4b193808b8bde94389ba7831c1fc6f9e794e.ttf b/test/shaping/data/in-house/fonts/8d9c4b193808b8bde94389ba7831c1fc6f9e794e.ttf
new file mode 100644
index 0000000..f1b84a4
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/8d9c4b193808b8bde94389ba7831c1fc6f9e794e.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/tests/arabic-fallback-shaping.tests b/test/shaping/data/in-house/tests/arabic-fallback-shaping.tests
index 274829c..8b7ced0 100644
--- a/test/shaping/data/in-house/tests/arabic-fallback-shaping.tests
+++ b/test/shaping/data/in-house/tests/arabic-fallback-shaping.tests
@@ -1 +1 @@
-../fonts/df768b9c257e0c9c35786c47cae15c46571d56be.ttf::U+0633,U+064F,U+0644,U+064E,U+0651,U+0627,U+0651,U+0650,U+0645,U+062A,U+06CC:[uni06CC.fina=10+1655|uni062A.medi=9+868|uni0645.init=8+1098|uni0650=2@221,0+0|uni0651=2@260,736+0|uni064E=2@935,1259+0|uni0651=2@974,736+0|uni06440627.fina=2+1470|uni064F=0@558,-10+0|uni0633.init=0+1585]
+../fonts/df768b9c257e0c9c35786c47cae15c46571d56be.ttf::U+0633,U+064F,U+0644,U+064E,U+0651,U+0627,U+0651,U+0650,U+0645,U+062A,U+06CC:[uni06CC.fina=10+1655|uni062A.medi=9+868|uni0645.init=8+1098|uni0650=2@148,0+0|uni0651=2@187,736+0|uni064E=2@883,1259+0|uni0651=2@922,736+0|uni06440627.fina=2+1470|uni064F=0@629,-10+0|uni0633.init=0+1585]
diff --git a/test/shaping/data/in-house/tests/cluster.tests b/test/shaping/data/in-house/tests/cluster.tests
index fd0a0fe..928843f 100644
--- a/test/shaping/data/in-house/tests/cluster.tests
+++ b/test/shaping/data/in-house/tests/cluster.tests
@@ -1,2 +1,2 @@
-../fonts/4fac3929fc3332834e93673780ec0fe94342d193.ttf:--cluster-level=2:U+0078,U+030A,U+0058,U+030A:[gid2=0+1083|gid3=1@-1131,-8+0|gid1=2+1200|gid3=3@-1190,349+0]
+../fonts/4fac3929fc3332834e93673780ec0fe94342d193.ttf:--cluster-level=2:U+0078,U+030A,U+0058,U+030A:[gid2=0+1083|gid3=1@-1132,-8+0|gid1=2+1200|gid3=3@-1190,349+0]
 ../fonts/43ef465752be9af900745f72fe29cb853a1401a5.ttf:--cluster-level=1:U+05D4,U+05B7,U+05E9,U+05BC,U+05C1,U+05B8,U+05DE,U+05B4,U+05DD:[uni05DD=8+1359|uni05B4=7@111,0+0|uni05DE=6+1391|uni05B8=5+0|uni05BC=3+0|uni05C1=3+0|uni05E9=2+1451|uni05B7=1@28,0+0|uni05D4=0+1338]
diff --git a/test/shaping/data/in-house/tests/emoji.tests b/test/shaping/data/in-house/tests/emoji.tests
index 8d9b254..7ee01f3 100644
--- a/test/shaping/data/in-house/tests/emoji.tests
+++ b/test/shaping/data/in-house/tests/emoji.tests
@@ -1,4 +1,5 @@
-../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0055,U+E0053,U+E0064,U+E0065,U+E007F:[u1F3F4=0+2126|space=1+0|space=2+0|space=3+0|space=4+0|space=5+0]
+../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0055,U+E0053,U+E0064,U+E0065,U+E007F:[u1F3F4=0+2126|space=0+0|space=0+0|space=0+0|space=0+0|space=0+0]
 ../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0064,U+E0065,U+E007F:[de=0+3200]
 ../fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf:--font-funcs=ot --direction=l:U+1F481,U+1F3FB,U+200D,U+2642,U+FE0F:[gid7=0+2550]
 ../fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf:--font-funcs=ot --direction=r:U+1F481,U+1F3FB,U+200D,U+2642,U+FE0F:[gid7=0+2550]
+../fonts/8d9c4b193808b8bde94389ba7831c1fc6f9e794e.ttf::U+1F3F4,U+E0067,U+E0062,U+E0077,U+E006C,U+E0073,U+E007F:[.notdef=0+1229|space=0+0|space=0+0|space=0+0|space=0+0|space=0+0|space=0+0]
diff --git a/test/shaping/data/in-house/tests/fallback-positioning.tests b/test/shaping/data/in-house/tests/fallback-positioning.tests
index 5047d84..0ffee50 100644
--- a/test/shaping/data/in-house/tests/fallback-positioning.tests
+++ b/test/shaping/data/in-house/tests/fallback-positioning.tests
@@ -1,2 +1,2 @@
-../fonts/8228d035fcd65d62ec9728fb34f42c63be93a5d3.ttf::U+0078,U+0301,U+0058,U+0301:[x=0+1030|acutecomb=0@-21,-27+0|X=2+1295|acutecomb=2@-147,320+0]
-../fonts/856ff9562451293cbeff6f396d4e3877c4f0a436.ttf::U+0061,U+035C,U+0062:[uni0061=0+512|uni035C=0@-64,-128+0|uni0062=2+512]
+../fonts/8228d035fcd65d62ec9728fb34f42c63be93a5d3.ttf::U+0078,U+0301,U+0058,U+0301:[x=0+1030|acutecomb=0@-19,-27+0|X=2+1295|acutecomb=2@-151,320+0]
+../fonts/856ff9562451293cbeff6f396d4e3877c4f0a436.ttf::U+0061,U+035C,U+0062:[uni0061=0+512|uni035C=0@0,-128+0|uni0062=2+512]
diff --git a/test/shaping/data/in-house/tests/macos.tests b/test/shaping/data/in-house/tests/macos.tests
index 859992c..12cb83f 100644
--- a/test/shaping/data/in-house/tests/macos.tests
+++ b/test/shaping/data/in-house/tests/macos.tests
@@ -4,8 +4,8 @@
 /System/Library/Fonts/Times.dfont@39c954614d3f3317b28564db06d5b7b7a6ff0e39:--font-funcs ot:U+0066,U+0069:[fi=0+1139]
 /Library/Fonts/Khmer MN.ttc@5f5b1072df99b7355d3066ea85fe82969d13c94a:--font-funcs ot:U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A:[km_qa=0+1025|km_ka=1+1025|km_sa.sub=1+517|km_ro=4+593|km_vs_ae=5+605|km_kha=5+1025|km_mo.sub=5+0|km_ro=9+593]
 /Library/Fonts/Tamil MN.ttc@37a2020c3f86ebcc45e02c1de5fdf81e2676989d:--font-funcs ot:U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1:[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1149|tgc_ku=2+1962|tgc_k=4+1592|tgc_ka=6+1592|tgc_p=7+1370|tgc_pa=9+1370|tgc_tt=10+1596|tgc_ttu=12+1833]
-/System/Library/Fonts/Times.dfont@39c954614d3f3317b28564db06d5b7b7a6ff0e39:--font-funcs ot:U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1@-480,588+0|fi=3+1139|Z=5+1251]
-/System/Library/Fonts/LucidaGrande.ttc@d89a9d7e57767bfe3b5a4cfd22bb1e9dbe03a062:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@-7,0+0|samekhhebrew=0+1361]
+/System/Library/Fonts/Times.dfont@39c954614d3f3317b28564db06d5b7b7a6ff0e39:--font-funcs ot:U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1@-551,588+0|fi=3+1139|Z=5+1251]
+/System/Library/Fonts/LucidaGrande.ttc@d89a9d7e57767bfe3b5a4cfd22bb1e9dbe03a062:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@51,0+0|samekhhebrew=0+1361]
 /Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--font-funcs ot:U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098]
 /Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[T=0+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006]
 /System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647]
@@ -15,6 +15,7 @@
 /System/Library/Fonts/SFNSDisplay.ttf@92787c30716672737e9059bc367c15d04fbc1ced:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid225=0+1105|gid584=1@-105,0+979|gid3=2+490|gid4=3+1227|gid265=4@-65,0+1227|gid3=5+490|gid225=6+1130|gid728=7@-80,0+569|gid3=8+490|gid265=9+1227|gid505=10@-65,0+997|gid3=11+490|gid728=12+609|gid225=13@-40,0+1170|gid3=14+490|gid584=15+1004|gid225=16@-80,0+1130|gid3=17+490|gid225=18+1105|gid576=19@-105,0+1068]
 /System/Library/Fonts/SFNSDisplay.ttf@92787c30716672737e9059bc367c15d04fbc1ced:--font-ptem 9 --font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid225=0@46,0+1197|gid584=1@-59,0+1071|gid3=2@46,0+582|gid4=3@46,0+1319|gid265=4@-19,0+1319|gid3=5@46,0+582|gid225=6@46,0+1222|gid728=7@-34,0+661|gid3=8@46,0+582|gid265=9@46,0+1319|gid505=10@-19,0+1089|gid3=11@46,0+582|gid728=12@46,0+701|gid225=13@6,0+1262|gid3=14@46,0+582|gid584=15@46,0+1096|gid225=16@-34,0+1222|gid3=17@46,0+582|gid225=18@46,0+1197|gid576=19@-59,0+1160]
 /System/Library/Fonts/Apple Color Emoji.ttc@d2fe8a134483aa48a43a9d1e4b7204d37a4abdf5:--remove-default-ignorables --font-funcs ot:U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466:[u1F46A.MWGB=0+800]
+Library/Fonts/Zapfino.ttf@9ee799ffb09516ead6b0cf6f2ca807276e150748:--font-funcs ot:U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F:[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333]
 
 # 10.13.6 https://gist.github.com/ebraminio/d432e831b3f7ebe30245dde5775e1c7e
 /System/Library/Fonts/Helvetica.ttc@8a928f9866299d2455f41360202b7a3b48503a5e:--font-funcs ot:U+006D,U+0300:[m=0+1706|gravecmb=0@-284,10+0]
@@ -22,8 +23,8 @@
 /System/Library/Fonts/Times.ttc@896098b6979306ad84355025459f7c68b029139c:--font-funcs ot:U+0066,U+0069:[fi=0+1139]
 /Library/Fonts/Khmer MN.ttc@782ba6cf3fca0512ab348dfe08345a2d5dc5bf2c:--font-funcs ot:U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A:[km_qa=0+1025|km_ka=1+1025|km_sa.sub=1+517|km_ro=4+593|km_vs_ae=5+605|km_kha=5+1025|km_mo.sub=5+0|km_ro=9+593]
 /Library/Fonts/Tamil MN.ttc@3de37f3f8f3cb6015b093fbd6e9d323daaf6fb1d:--font-funcs ot:U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1:[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1149|tgc_ku=2+1962|tgc_k=4+1592|tgc_ka=6+1592|tgc_p=7+1370|tgc_pa=9+1370|tgc_tt=10+1596|tgc_ttu=12+1833]
-/System/Library/Fonts/Times.ttc@896098b6979306ad84355025459f7c68b029139c:--font-funcs ot:U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1@-480,588+0|fi=3+1139|Z=5+1251]
-/System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@-7,0+0|samekhhebrew=0+1361]
+/System/Library/Fonts/Times.ttc@896098b6979306ad84355025459f7c68b029139c:--font-funcs ot:U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1@-551,588+0|fi=3+1139|Z=5+1251]
+/System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@51,0+0|samekhhebrew=0+1361]
 /Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098]
 /Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[T=0+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006]
 /System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647]
@@ -33,3 +34,4 @@
 /System/Library/Fonts/SFNSDisplay.ttf@c8948f464ff822a5f9bbf2e12d0e4e32268815aa:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid282=0+1055|gid658=1@-135,0+914|gid3=2+420|gid4=3+1227|gid332=4@-65,0+1227|gid3=5+420|gid282=6+1075|gid813=7@-115,0+516|gid3=8+420|gid332=9+1217|gid572=10@-75,0+953|gid3=11+420|gid813=12+546|gid282=13@-85,0+1105|gid3=14+420|gid658=15+914|gid282=16@-135,0+1055|gid3=17+420|gid282=18+1055|gid649=19@-135,0+999]
 /System/Library/Fonts/SFNSDisplay.ttf@c8948f464ff822a5f9bbf2e12d0e4e32268815aa:--font-ptem 9 --font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid282=0@46,0+1147|gid658=1@-89,0+1006|gid3=2@46,0+512|gid4=3@46,0+1319|gid332=4@-19,0+1319|gid3=5@46,0+512|gid282=6@46,0+1167|gid813=7@-69,0+608|gid3=8@46,0+512|gid332=9@46,0+1309|gid572=10@-29,0+1045|gid3=11@46,0+512|gid813=12@46,0+638|gid282=13@-39,0+1197|gid3=14@46,0+512|gid658=15@46,0+1006|gid282=16@-89,0+1147|gid3=17@46,0+512|gid282=18@46,0+1147|gid649=19@-89,0+1091]
 /System/Library/Fonts/Apple Color Emoji.ttc@2e09b1f3d42c3821cc6c4ac5b6ce16237ab0d496:--remove-default-ignorables --font-funcs ot:U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466:[u1F46A.MWGB=0+800]
+Library/Fonts/Zapfino.ttf@99a1e15163c3e9567d5b1019c45e9254dae63b08:--font-funcs ot:U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F:[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333]
diff --git a/test/shaping/data/text-rendering-tests/DISABLED b/test/shaping/data/text-rendering-tests/DISABLED
index b071904..8539c0e 100644
--- a/test/shaping/data/text-rendering-tests/DISABLED
+++ b/test/shaping/data/text-rendering-tests/DISABLED
@@ -1,6 +1,3 @@
-tests/MORX-31.tests
-tests/MORX-41.tests
-
 # Non-Unicode cmap
 tests/CMAP-3.tests
 
diff --git a/test/shaping/data/text-rendering-tests/Makefile.sources b/test/shaping/data/text-rendering-tests/Makefile.sources
index 052a612..ccbbb37 100644
--- a/test/shaping/data/text-rendering-tests/Makefile.sources
+++ b/test/shaping/data/text-rendering-tests/Makefile.sources
@@ -51,6 +51,7 @@
 	tests/MORX-29.tests \
 	tests/MORX-2.tests \
 	tests/MORX-30.tests \
+	tests/MORX-31.tests \
 	tests/MORX-32.tests \
 	tests/MORX-33.tests \
 	tests/MORX-34.tests \
@@ -61,6 +62,7 @@
 	tests/MORX-39.tests \
 	tests/MORX-3.tests \
 	tests/MORX-40.tests \
+	tests/MORX-41.tests \
 	tests/MORX-4.tests \
 	tests/MORX-5.tests \
 	tests/MORX-6.tests \
diff --git a/test/shaping/data/text-rendering-tests/extract-tests.py b/test/shaping/data/text-rendering-tests/extract-tests.py
index 27d5686..f1722b5 100755
--- a/test/shaping/data/text-rendering-tests/extract-tests.py
+++ b/test/shaping/data/text-rendering-tests/extract-tests.py
@@ -48,7 +48,7 @@
 		opts = opts + ' --variations=%s' % variations
 	print ("../fonts/%s:%s:%s:%s" % (font, opts, unistr(text), glyphstr(glyphs)))
 
-for elt in html.findall(".//*[@class='should-not-crash'][@ft:id]", namespaces):
+for elt in html.findall(".//*[@class='expected-no-crash'][@ft:id]", namespaces):
 	found = True
 	name = elt.get(ns('ft:id'))
 	text = elt.get(ns('ft:render'))
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-14.tests b/test/shaping/data/text-rendering-tests/tests/MORX-14.tests
index 1369247..d01f2e9 100644
--- a/test/shaping/data/text-rendering-tests/tests/MORX-14.tests
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-14.tests
@@ -1,2 +1,2 @@
 ../fonts/TestMORXFourteen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0043,U+0044,U+0045:[B|C@626,0|D@1222,0|E@1896,0|A@2452,0]
-../fonts/TestMORXFourteen.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042,U+0042,U+0042,U+0043,U+0043,U+0043,U+0044,U+0044,U+0044,U+0042,U+0043,U+0044,U+0043,U+0045:[B|B@626,0|B@1252,0|C@1878,0|C@2474,0|C@3070,0|D@3666,0|D@4340,0|D@5014,0|B@5688,0|C@6314,0|D@6910,0|C@7584,0|E@8180,0|A@8736,0]
+../fonts/TestMORXFourteen.ttf::U+0041,U+0042,U+0042,U+0042,U+0043,U+0043,U+0043,U+0044,U+0044,U+0044,U+0042,U+0043,U+0044,U+0043,U+0045:*
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-32.tests b/test/shaping/data/text-rendering-tests/tests/MORX-32.tests
index 87c1152..6f3ae88 100644
--- a/test/shaping/data/text-rendering-tests/tests/MORX-32.tests
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-32.tests
@@ -1,4 +1,4 @@
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[X|A@364,0|Y@1194,0]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0042,U+0059:[X|B@364,0|Y@1194,0]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[I|N@830,0|S@1660,0|A@2490,0]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[I|N@830,0|S@1660,0|X@2490,0|A@2854,0|Y@3684,0]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B|I@830,0|N@1660,0|S@2490,0]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0042,U+0059:[X|I@364,0|N@1194,0|S@2024,0|B@2854,0|Y@3684,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-41.tests b/test/shaping/data/text-rendering-tests/tests/MORX-41.tests
index 84dca89..815bebe 100644
--- a/test/shaping/data/text-rendering-tests/tests/MORX-41.tests
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-41.tests
@@ -1,4 +1,4 @@
 ../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0063:[a_c]
 ../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0062,U+0063:[b_c]
-../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0063,U+0063:[c]
-../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0062,U+0063,U+0063:[a|b_c@561,0|c@1631,0]
+../fonts/TestMORXFourtyone.ttf::U+0063,U+0063:*
+../fonts/TestMORXFourtyone.ttf::U+0061,U+0062,U+0063,U+0063:*