Backed out changeset 815c0c1d5619 (bug 1226175) for bustage on a CLOSED TREE
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 20 Nov 2015 08:03:13 +0100
changeset 273509 f0ecb8d583b435135519bd58f3cba0f771f72d4f
parent 273508 aff31c38715020c8fb3c878bee84a5fa0c3e4cec
child 273510 9bdf5bae3a63659e14c17ee7384d86a1c9bfcbd1
push id29705
push userkwierso@gmail.com
push dateFri, 20 Nov 2015 22:36:48 +0000
treeherdermozilla-central@e3d9cf3dc326 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1226175
milestone45.0a1
backs out815c0c1d5619a4a122108148f303db3ed05c2247
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 815c0c1d5619 (bug 1226175) for bustage on a CLOSED TREE
gfx/harfbuzz/src/Makefile.am
gfx/harfbuzz/src/hb-buffer-private.hh
gfx/harfbuzz/src/hb-buffer.cc
gfx/harfbuzz/src/hb-font-private.hh
gfx/harfbuzz/src/hb-font.cc
gfx/harfbuzz/src/hb-ft.cc
gfx/harfbuzz/src/hb-open-type-private.hh
gfx/harfbuzz/src/hb-ot-font.cc
gfx/harfbuzz/src/hb-ot-layout-common-private.hh
gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
gfx/harfbuzz/src/hb-ot-layout-private.hh
gfx/harfbuzz/src/hb-ot-layout.cc
gfx/harfbuzz/src/hb-ot-map-private.hh
gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
gfx/harfbuzz/src/hb-ot-shape-complex-hangul.cc
gfx/harfbuzz/src/hb-ot-shape-complex-hebrew.cc
gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
gfx/harfbuzz/src/hb-ot-shape-complex-tibetan.cc
gfx/harfbuzz/src/hb-ot-shape-complex-use.cc
gfx/harfbuzz/src/hb-ot-shape-fallback-private.hh
gfx/harfbuzz/src/hb-ot-shape-fallback.cc
gfx/harfbuzz/src/hb-ot-shape-normalize.cc
gfx/harfbuzz/src/hb-ot-shape.cc
gfx/harfbuzz/src/hb-private.hh
gfx/harfbuzz/src/hb-unicode-private.hh
gfx/harfbuzz/src/hb-utf-private.hh
gfx/harfbuzz/src/hb-version.h
--- a/gfx/harfbuzz/src/Makefile.am
+++ b/gfx/harfbuzz/src/Makefile.am
@@ -10,17 +10,16 @@ DISTCLEANFILES =
 MAINTAINERCLEANFILES =
 DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
 
 # The following warning options are useful for debugging: -Wpadded
 #AM_CXXFLAGS =
 
 # Convenience targets:
 lib: $(BUILT_SOURCES) libharfbuzz.la
-fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la
 
 lib_LTLIBRARIES = libharfbuzz.la
 
 HBCFLAGS =
 HBLIBS =
 HBNONPCLIBS =
 HBDEPS =
 HBSOURCES =  \
@@ -215,32 +214,16 @@ libharfbuzz_la_LDFLAGS = $(AM_LDFLAGS) -
 libharfbuzz_la_LIBADD = $(HBLIBS)
 EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
 pkginclude_HEADERS = $(HBHEADERS)
 nodist_pkginclude_HEADERS = $(HBNODISTHEADERS)
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = harfbuzz.pc
 EXTRA_DIST += harfbuzz.pc.in
 
-FUZZING_CPPFLAGS= \
-	-DHB_MAX_NESTING_LEVEL=3 \
-	-DHB_SANITIZE_MAX_EDITS=3 \
-	-DHB_BUFFER_MAX_EXPANSION_FACTOR=3 \
-	-DHB_BUFFER_MAX_LEN_MIN=8 \
-	-DHB_BUFFER_MAX_LEN_DEFAULT=128 \
-	$(NULL)
-EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la
-libharfbuzz_fuzzing_la_LINK = $(libharfbuzz_la_LINK)
-libharfbuzz_fuzzing_la_SOURCES = $(libharfbuzz_la_SOURCES)
-libharfbuzz_fuzzing_la_CPPFLAGS = $(libharfbuzz_la_CPPFLAGS) $(FUZZING_CPPFLAGS)
-libharfbuzz_fuzzing_la_LDFLAGS = $(libharfbuzz_la_LDFLAGS)
-libharfbuzz_fuzzing_la_LIBADD = $(libharfbuzz_la_LIBADD)
-EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_la_DEPENDENCIES)
-CLEANFILES += libharfbuzz-fuzzing.la
-
 if HAVE_ICU
 lib_LTLIBRARIES += libharfbuzz-icu.la
 libharfbuzz_icu_la_SOURCES = hb-icu.cc
 libharfbuzz_icu_la_CPPFLAGS = $(ICU_CFLAGS)
 libharfbuzz_icu_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
 libharfbuzz_icu_la_LIBADD = $(ICU_LIBS) libharfbuzz.la
 pkginclude_HEADERS += hb-icu.h
 pkgconfig_DATA += harfbuzz-icu.pc
--- a/gfx/harfbuzz/src/hb-buffer-private.hh
+++ b/gfx/harfbuzz/src/hb-buffer-private.hh
@@ -30,63 +30,33 @@
 #ifndef HB_BUFFER_PRIVATE_HH
 #define HB_BUFFER_PRIVATE_HH
 
 #include "hb-private.hh"
 #include "hb-object-private.hh"
 #include "hb-unicode-private.hh"
 
 
-#ifndef HB_BUFFER_MAX_EXPANSION_FACTOR
-#define HB_BUFFER_MAX_EXPANSION_FACTOR 32
-#endif
-#ifndef HB_BUFFER_MAX_LEN_MIN
-#define HB_BUFFER_MAX_LEN_MIN 8192
-#endif
-#ifndef HB_BUFFER_MAX_LEN_DEFAULT
-#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
-#endif
-
 ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
 ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
 
-HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
-HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
-
-enum hb_buffer_scratch_flags_t {
-  HB_BUFFER_SCRATCH_FLAG_DEFAULT			= 0x00000000u,
-  HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII			= 0x00000001u,
-  HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES		= 0x00000002u,
-  HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK		= 0x00000004u,
-  HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE		= 0x00000008u,
-  HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT		= 0x00000010u,
-  /* Reserved for complex shapers' internal use. */
-  HB_BUFFER_SCRATCH_FLAG_COMPLEX0			= 0x01000000u,
-  HB_BUFFER_SCRATCH_FLAG_COMPLEX1			= 0x02000000u,
-  HB_BUFFER_SCRATCH_FLAG_COMPLEX2			= 0x04000000u,
-  HB_BUFFER_SCRATCH_FLAG_COMPLEX3			= 0x08000000u,
-};
-HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
-
 
 /*
  * hb_buffer_t
  */
 
 struct hb_buffer_t {
   hb_object_header_t header;
   ASSERT_POD ();
 
   /* Information about how the text in the buffer should be treated */
   hb_unicode_funcs_t *unicode; /* Unicode functions */
   hb_buffer_flags_t flags; /* BOT / EOT / etc. */
   hb_buffer_cluster_level_t cluster_level;
   hb_codepoint_t replacement; /* U+FFFD or something else. */
-  hb_buffer_scratch_flags_t scratch_flags; /* Have space-flallback, etc. */
-  unsigned int max_len; /* Maximum allowed len. */
 
   /* Buffer contents */
   hb_buffer_content_type_t content_type;
   hb_segment_properties_t props; /* Script, language, direction */
 
   bool in_error; /* Allocation failed */
   bool have_output; /* Whether we have an output buffer going on */
   bool have_positions; /* Whether we have positions */
@@ -101,18 +71,18 @@ struct hb_buffer_t {
   hb_glyph_position_t *pos;
 
   inline hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
   inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
 
   inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
   inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
 
-  inline hb_glyph_info_t &prev (void) { return out_info[out_len ? out_len - 1 : 0]; }
-  inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; }
+  inline hb_glyph_info_t &prev (void) { return out_info[out_len - 1]; }
+  inline hb_glyph_info_t prev (void) const { return info[out_len - 1]; }
 
   inline bool has_separate_output (void) const { return info != out_info; }
 
   unsigned int serial;
 
   /* These reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
   uint8_t allocated_var_bytes[8];
   const char *allocated_var_owner[8];
@@ -169,23 +139,22 @@ struct hb_buffer_t {
   /* Copies glyph at idx to output and advance idx.
    * If there's no output, just advance idx. */
   inline void
   next_glyph (void)
   {
     if (have_output)
     {
       if (unlikely (out_info != info || out_len != idx)) {
-	if (unlikely (!make_room_for (1, 1)))
-	  goto done;
+	if (unlikely (!make_room_for (1, 1))) return;
 	out_info[out_len] = info[idx];
       }
       out_len++;
     }
-  done:
+
     idx++;
   }
 
   /* Advance idx without copying to output. */
   inline void skip_glyph (void) { idx++; }
 
   inline void reset_masks (hb_mask_t mask)
   {
--- a/gfx/harfbuzz/src/hb-buffer.cc
+++ b/gfx/harfbuzz/src/hb-buffer.cc
@@ -86,21 +86,16 @@ hb_segment_properties_hash (const hb_seg
 
 /* Internal API */
 
 bool
 hb_buffer_t::enlarge (unsigned int size)
 {
   if (unlikely (in_error))
     return false;
-  if (unlikely (size > max_len))
-  {
-    in_error = true;
-    return false;
-  }
 
   unsigned int new_allocated = allocated;
   hb_glyph_position_t *new_pos = NULL;
   hb_glyph_info_t *new_info = NULL;
   bool separate_out = out_info != info;
 
   if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
     goto done;
@@ -198,17 +193,16 @@ hb_buffer_t::reset (void)
 void
 hb_buffer_t::clear (void)
 {
   if (unlikely (hb_object_is_inert (this)))
     return;
 
   hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
   props = default_props;
-  scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
 
   content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
   in_error = false;
   have_output = false;
   have_positions = false;
 
   idx = 0;
   len = 0;
@@ -319,75 +313,62 @@ hb_buffer_t::swap_buffers (void)
 }
 
 
 void
 hb_buffer_t::replace_glyphs (unsigned int num_in,
 			     unsigned int num_out,
 			     const uint32_t *glyph_data)
 {
-  if (unlikely (!make_room_for (num_in, num_out)))
-    goto done;
-  {
+  if (unlikely (!make_room_for (num_in, num_out))) return;
 
   merge_clusters (idx, idx + num_in);
 
   hb_glyph_info_t orig_info = info[idx];
   hb_glyph_info_t *pinfo = &out_info[out_len];
   for (unsigned int i = 0; i < num_out; i++)
   {
     *pinfo = orig_info;
     pinfo->codepoint = glyph_data[i];
     pinfo++;
   }
 
+  idx  += num_in;
   out_len += num_out;
-  }
-done:
-  idx  += num_in;
 }
 
 void
 hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
 {
-  if (unlikely (!make_room_for (0, 1)))
-    goto done;
+  if (unlikely (!make_room_for (0, 1))) return;
 
   out_info[out_len] = info[idx];
   out_info[out_len].codepoint = glyph_index;
 
   out_len++;
-done:
-  ;
 }
 
 void
 hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
 {
-  if (unlikely (!make_room_for (0, 1)))
-    goto done;
+  if (unlikely (!make_room_for (0, 1))) return;
 
   out_info[out_len] = glyph_info;
 
   out_len++;
-done:
-  ;
 }
 
 void
 hb_buffer_t::copy_glyph (void)
 {
-  if (unlikely (!make_room_for (0, 1)))
-    goto done;
+  if (unlikely (!make_room_for (0, 1))) return;
 
   out_info[out_len] = info[idx];
 
   out_len++;
-done:
-  ;
 }
 
 bool
 hb_buffer_t::move_to (unsigned int i)
 {
   if (!have_output)
   {
     assert (i <= len);
@@ -395,17 +376,17 @@ hb_buffer_t::move_to (unsigned int i)
     return true;
   }
 
   assert (i <= out_len + (len - idx));
 
   if (out_len < i)
   {
     unsigned int count = i - out_len;
-    if (unlikely (!make_room_for (count, count))) return false; // XXX verify bailout
+    if (unlikely (!make_room_for (count, count))) return false;
 
     memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));
     idx += count;
     out_len += count;
   }
   else if (out_len > i)
   {
     /* Tricky part: rewinding... */
@@ -422,25 +403,23 @@ hb_buffer_t::move_to (unsigned int i)
 
   return true;
 }
 
 void
 hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
 {
   if (unlikely (out_info != info || out_len != idx)) {
-    if (unlikely (!make_room_for (1, 1)))
-      goto out;
+    if (unlikely (!make_room_for (1, 1))) return;
     out_info[out_len] = info[idx];
   }
   out_info[out_len].codepoint = glyph_index;
 
+  idx++;
   out_len++;
-out:
-  idx++;
 }
 
 
 void
 hb_buffer_t::set_masks (hb_mask_t    value,
 			hb_mask_t    mask,
 			unsigned int cluster_start,
 			unsigned int cluster_end)
@@ -730,18 +709,16 @@ void hb_buffer_t::deallocate_var_all (vo
 hb_buffer_t *
 hb_buffer_create (void)
 {
   hb_buffer_t *buffer;
 
   if (!(buffer = hb_object_create<hb_buffer_t> ()))
     return hb_buffer_get_empty ();
 
-  buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
-
   buffer->reset ();
 
   return buffer;
 }
 
 /**
  * hb_buffer_get_empty:
  *
@@ -756,18 +733,16 @@ hb_buffer_get_empty (void)
 {
   static const hb_buffer_t _hb_buffer_nil = {
     HB_OBJECT_HEADER_STATIC,
 
     const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
     HB_BUFFER_FLAG_DEFAULT,
     HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
     HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
-    HB_BUFFER_SCRATCH_FLAG_DEFAULT,
-    HB_BUFFER_MAX_LEN_DEFAULT,
 
     HB_BUFFER_CONTENT_TYPE_INVALID,
     HB_SEGMENT_PROPERTIES_DEFAULT,
     true, /* in_error */
     true, /* have_output */
     true  /* have_positions */
 
     /* Zero is good enough for everything else. */
--- a/gfx/harfbuzz/src/hb-font-private.hh
+++ b/gfx/harfbuzz/src/hb-font-private.hh
@@ -56,37 +56,35 @@
   /* ^--- Add new callbacks here */
 
 struct hb_font_funcs_t {
   hb_object_header_t header;
   ASSERT_POD ();
 
   hb_bool_t immutable;
 
+  /* Don't access these directly.  Call hb_font_get_*() instead. */
+
+  struct {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+  } get;
+
   struct {
 #define HB_FONT_FUNC_IMPLEMENT(name) void *name;
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
   } user_data;
 
   struct {
 #define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
   } destroy;
-
-  /* Don't access these directly.  Call font->get_*() instead. */
-  union get_t {
-    struct get_funcs_t {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
-      HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
-    } f;
-    void (*array[]) (void);
-  } get;
 };
 
 
 
 /*
  * hb_font_t
  */
 
@@ -141,130 +139,116 @@ struct hb_font_t {
   inline void parent_scale_position (hb_position_t *x, hb_position_t *y) {
     *x = parent_scale_x_position (*x);
     *y = parent_scale_y_position (*y);
   }
 
 
   /* Public getters */
 
-  HB_INTERNAL bool has_func (unsigned int i);
-
-  /* has_* ... */
-#define HB_FONT_FUNC_IMPLEMENT(name) \
-  bool \
-  has_##name##_func (void) \
-  { \
-    hb_font_funcs_t *funcs = this->klass; \
-    unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
-    return has_func (i); \
-  }
-  HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
-
   inline hb_bool_t has_glyph (hb_codepoint_t unicode)
   {
     hb_codepoint_t glyph;
     return get_glyph (unicode, 0, &glyph);
   }
 
   inline hb_bool_t get_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
 			      hb_codepoint_t *glyph)
   {
     *glyph = 0;
-    return klass->get.f.glyph (this, user_data,
-			       unicode, variation_selector, glyph,
-			       klass->user_data.glyph);
+    return klass->get.glyph (this, user_data,
+			     unicode, variation_selector, glyph,
+			     klass->user_data.glyph);
   }
 
   inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
   {
-    return klass->get.f.glyph_h_advance (this, user_data,
-					 glyph,
-					 klass->user_data.glyph_h_advance);
+    return klass->get.glyph_h_advance (this, user_data,
+				       glyph,
+				       klass->user_data.glyph_h_advance);
   }
 
   inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
   {
-    return klass->get.f.glyph_v_advance (this, user_data,
-					 glyph,
-					 klass->user_data.glyph_v_advance);
+    return klass->get.glyph_v_advance (this, user_data,
+				       glyph,
+				       klass->user_data.glyph_v_advance);
   }
 
   inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
 				       hb_position_t *x, hb_position_t *y)
   {
     *x = *y = 0;
-    return klass->get.f.glyph_h_origin (this, user_data,
-					glyph, x, y,
-					klass->user_data.glyph_h_origin);
+    return klass->get.glyph_h_origin (this, user_data,
+				      glyph, x, y,
+				      klass->user_data.glyph_h_origin);
   }
 
   inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
 				       hb_position_t *x, hb_position_t *y)
   {
     *x = *y = 0;
-    return klass->get.f.glyph_v_origin (this, user_data,
-					glyph, x, y,
-					klass->user_data.glyph_v_origin);
+    return klass->get.glyph_v_origin (this, user_data,
+				      glyph, x, y,
+				      klass->user_data.glyph_v_origin);
   }
 
   inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
   {
-    return klass->get.f.glyph_h_kerning (this, user_data,
-					 left_glyph, right_glyph,
-					 klass->user_data.glyph_h_kerning);
+    return klass->get.glyph_h_kerning (this, user_data,
+				       left_glyph, right_glyph,
+				       klass->user_data.glyph_h_kerning);
   }
 
   inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
   {
-    return klass->get.f.glyph_v_kerning (this, user_data,
-					 top_glyph, bottom_glyph,
-					 klass->user_data.glyph_v_kerning);
+    return klass->get.glyph_v_kerning (this, user_data,
+				       top_glyph, bottom_glyph,
+				       klass->user_data.glyph_v_kerning);
   }
 
   inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
 				      hb_glyph_extents_t *extents)
   {
     memset (extents, 0, sizeof (*extents));
-    return klass->get.f.glyph_extents (this, user_data,
-				       glyph,
-				       extents,
-				       klass->user_data.glyph_extents);
+    return klass->get.glyph_extents (this, user_data,
+				     glyph,
+				     extents,
+				     klass->user_data.glyph_extents);
   }
 
   inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
 					    hb_position_t *x, hb_position_t *y)
   {
     *x = *y = 0;
-    return klass->get.f.glyph_contour_point (this, user_data,
-					     glyph, point_index,
-					     x, y,
-					     klass->user_data.glyph_contour_point);
+    return klass->get.glyph_contour_point (this, user_data,
+					   glyph, point_index,
+					   x, y,
+					   klass->user_data.glyph_contour_point);
   }
 
   inline hb_bool_t get_glyph_name (hb_codepoint_t glyph,
 				   char *name, unsigned int size)
   {
     if (size) *name = '\0';
-    return klass->get.f.glyph_name (this, user_data,
-				    glyph,
-				    name, size,
-				    klass->user_data.glyph_name);
+    return klass->get.glyph_name (this, user_data,
+				  glyph,
+				  name, size,
+				  klass->user_data.glyph_name);
   }
 
   inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
 					hb_codepoint_t *glyph)
   {
     *glyph = 0;
     if (len == -1) len = strlen (name);
-    return klass->get.f.glyph_from_name (this, user_data,
-					 name, len,
-					 glyph,
-					 klass->user_data.glyph_from_name);
+    return klass->get.glyph_from_name (this, user_data,
+				       name, len,
+				       glyph,
+				       klass->user_data.glyph_from_name);
   }
 
 
   /* A bit higher-level, and with fallback */
 
   inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
 					       hb_direction_t direction,
 					       hb_position_t *x, hb_position_t *y)
@@ -309,68 +293,28 @@ struct hb_font_t {
       {
 	hb_position_t dx, dy;
 	guess_v_origin_minus_h_origin (glyph, &dx, &dy);
 	*x += dx; *y += dy;
       }
     }
   }
 
-  inline void add_glyph_h_origin (hb_codepoint_t glyph,
-				  hb_position_t *x, hb_position_t *y)
-  {
-    hb_position_t origin_x, origin_y;
-
-    get_glyph_h_origin (glyph, &origin_x, &origin_y);
-
-    *x += origin_x;
-    *y += origin_y;
-  }
-  inline void add_glyph_v_origin (hb_codepoint_t glyph,
-				  hb_position_t *x, hb_position_t *y)
-  {
-    hb_position_t origin_x, origin_y;
-
-    get_glyph_v_origin (glyph, &origin_x, &origin_y);
-
-    *x += origin_x;
-    *y += origin_y;
-  }
   inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
 					      hb_direction_t direction,
 					      hb_position_t *x, hb_position_t *y)
   {
     hb_position_t origin_x, origin_y;
 
     get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
 
     *x += origin_x;
     *y += origin_y;
   }
 
-  inline void subtract_glyph_h_origin (hb_codepoint_t glyph,
-				       hb_position_t *x, hb_position_t *y)
-  {
-    hb_position_t origin_x, origin_y;
-
-    get_glyph_h_origin (glyph, &origin_x, &origin_y);
-
-    *x -= origin_x;
-    *y -= origin_y;
-  }
-  inline void subtract_glyph_v_origin (hb_codepoint_t glyph,
-				       hb_position_t *x, hb_position_t *y)
-  {
-    hb_position_t origin_x, origin_y;
-
-    get_glyph_v_origin (glyph, &origin_x, &origin_y);
-
-    *x -= origin_x;
-    *y -= origin_y;
-  }
   inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
 						   hb_direction_t direction,
 						   hb_position_t *x, hb_position_t *y)
   {
     hb_position_t origin_x, origin_y;
 
     get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
 
--- a/gfx/harfbuzz/src/hb-font.cc
+++ b/gfx/harfbuzz/src/hb-font.cc
@@ -40,294 +40,198 @@
 #include <string.h>
 
 
 /*
  * hb_font_funcs_t
  */
 
 static hb_bool_t
-hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED,
+hb_font_get_glyph_nil (hb_font_t *font,
 		       void *font_data HB_UNUSED,
 		       hb_codepoint_t unicode,
 		       hb_codepoint_t variation_selector,
 		       hb_codepoint_t *glyph,
 		       void *user_data HB_UNUSED)
 {
+  if (font->parent)
+    return font->parent->get_glyph (unicode, variation_selector, glyph);
+
   *glyph = 0;
   return false;
 }
-static hb_bool_t
-hb_font_get_glyph_parent (hb_font_t *font,
-			  void *font_data HB_UNUSED,
-			  hb_codepoint_t unicode,
-			  hb_codepoint_t variation_selector,
-			  hb_codepoint_t *glyph,
-			  void *user_data HB_UNUSED)
-{
-  return font->parent->get_glyph (unicode, variation_selector, glyph);
-}
 
 static hb_position_t
-hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED,
+hb_font_get_glyph_h_advance_nil (hb_font_t *font,
 				 void *font_data HB_UNUSED,
 				 hb_codepoint_t glyph,
 				 void *user_data HB_UNUSED)
 {
+  if (font->parent)
+    return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
+
   return font->x_scale;
 }
-static hb_position_t
-hb_font_get_glyph_h_advance_parent (hb_font_t *font,
-				    void *font_data HB_UNUSED,
-				    hb_codepoint_t glyph,
-				    void *user_data HB_UNUSED)
-{
-  return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
-}
 
 static hb_position_t
-hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED,
+hb_font_get_glyph_v_advance_nil (hb_font_t *font,
 				 void *font_data HB_UNUSED,
 				 hb_codepoint_t glyph,
 				 void *user_data HB_UNUSED)
 {
+  if (font->parent)
+    return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
+
   return font->y_scale;
 }
-static hb_position_t
-hb_font_get_glyph_v_advance_parent (hb_font_t *font,
-				    void *font_data HB_UNUSED,
-				    hb_codepoint_t glyph,
-				    void *user_data HB_UNUSED)
-{
-  return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
-}
 
 static hb_bool_t
-hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
+hb_font_get_glyph_h_origin_nil (hb_font_t *font,
 				void *font_data HB_UNUSED,
 				hb_codepoint_t glyph,
 				hb_position_t *x,
 				hb_position_t *y,
 				void *user_data HB_UNUSED)
 {
+  if (font->parent) {
+    hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
+    if (ret)
+      font->parent_scale_position (x, y);
+    return ret;
+  }
+
   *x = *y = 0;
   return false;
 }
-static hb_bool_t
-hb_font_get_glyph_h_origin_parent (hb_font_t *font,
-				   void *font_data HB_UNUSED,
-				   hb_codepoint_t glyph,
-				   hb_position_t *x,
-				   hb_position_t *y,
-				   void *user_data HB_UNUSED)
-{
-  hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
-  if (ret)
-    font->parent_scale_position (x, y);
-  return ret;
-}
 
 static hb_bool_t
-hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
+hb_font_get_glyph_v_origin_nil (hb_font_t *font,
 				void *font_data HB_UNUSED,
 				hb_codepoint_t glyph,
 				hb_position_t *x,
 				hb_position_t *y,
 				void *user_data HB_UNUSED)
 {
+  if (font->parent) {
+    hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
+    if (ret)
+      font->parent_scale_position (x, y);
+    return ret;
+  }
+
   *x = *y = 0;
   return false;
 }
-static hb_bool_t
-hb_font_get_glyph_v_origin_parent (hb_font_t *font,
-				   void *font_data HB_UNUSED,
-				   hb_codepoint_t glyph,
-				   hb_position_t *x,
-				   hb_position_t *y,
-				   void *user_data HB_UNUSED)
-{
-  hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
-  if (ret)
-    font->parent_scale_position (x, y);
-  return ret;
-}
 
 static hb_position_t
-hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
+hb_font_get_glyph_h_kerning_nil (hb_font_t *font,
 				 void *font_data HB_UNUSED,
 				 hb_codepoint_t left_glyph,
 				 hb_codepoint_t right_glyph,
 				 void *user_data HB_UNUSED)
 {
+  if (font->parent)
+    return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
+
   return 0;
 }
-static hb_position_t
-hb_font_get_glyph_h_kerning_parent (hb_font_t *font,
-				    void *font_data HB_UNUSED,
-				    hb_codepoint_t left_glyph,
-				    hb_codepoint_t right_glyph,
-				    void *user_data HB_UNUSED)
-{
-  return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
-}
 
 static hb_position_t
-hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
+hb_font_get_glyph_v_kerning_nil (hb_font_t *font,
 				 void *font_data HB_UNUSED,
 				 hb_codepoint_t top_glyph,
 				 hb_codepoint_t bottom_glyph,
 				 void *user_data HB_UNUSED)
 {
+  if (font->parent)
+    return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
+
   return 0;
 }
-static hb_position_t
-hb_font_get_glyph_v_kerning_parent (hb_font_t *font,
-				    void *font_data HB_UNUSED,
-				    hb_codepoint_t top_glyph,
-				    hb_codepoint_t bottom_glyph,
-				    void *user_data HB_UNUSED)
-{
-  return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
-}
 
 static hb_bool_t
-hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
+hb_font_get_glyph_extents_nil (hb_font_t *font,
 			       void *font_data HB_UNUSED,
 			       hb_codepoint_t glyph,
 			       hb_glyph_extents_t *extents,
 			       void *user_data HB_UNUSED)
 {
+  if (font->parent) {
+    hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
+    if (ret) {
+      font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
+      font->parent_scale_distance (&extents->width, &extents->height);
+    }
+    return ret;
+  }
+
   memset (extents, 0, sizeof (*extents));
   return false;
 }
-static hb_bool_t
-hb_font_get_glyph_extents_parent (hb_font_t *font,
-				  void *font_data HB_UNUSED,
-				  hb_codepoint_t glyph,
-				  hb_glyph_extents_t *extents,
-				  void *user_data HB_UNUSED)
-{
-  hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
-  if (ret) {
-    font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
-    font->parent_scale_distance (&extents->width, &extents->height);
-  }
-  return ret;
-}
 
 static hb_bool_t
-hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
+hb_font_get_glyph_contour_point_nil (hb_font_t *font,
 				     void *font_data HB_UNUSED,
 				     hb_codepoint_t glyph,
 				     unsigned int point_index,
 				     hb_position_t *x,
 				     hb_position_t *y,
 				     void *user_data HB_UNUSED)
 {
+  if (font->parent) {
+    hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
+    if (ret)
+      font->parent_scale_position (x, y);
+    return ret;
+  }
+
   *x = *y = 0;
   return false;
 }
-static hb_bool_t
-hb_font_get_glyph_contour_point_parent (hb_font_t *font,
-					void *font_data HB_UNUSED,
-					hb_codepoint_t glyph,
-					unsigned int point_index,
-					hb_position_t *x,
-					hb_position_t *y,
-					void *user_data HB_UNUSED)
-{
-  hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
-  if (ret)
-    font->parent_scale_position (x, y);
-  return ret;
-}
 
 static hb_bool_t
-hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED,
+hb_font_get_glyph_name_nil (hb_font_t *font,
 			    void *font_data HB_UNUSED,
 			    hb_codepoint_t glyph,
 			    char *name, unsigned int size,
 			    void *user_data HB_UNUSED)
 {
+  if (font->parent)
+    return font->parent->get_glyph_name (glyph, name, size);
+
   if (size) *name = '\0';
   return false;
 }
-static hb_bool_t
-hb_font_get_glyph_name_parent (hb_font_t *font,
-			       void *font_data HB_UNUSED,
-			       hb_codepoint_t glyph,
-			       char *name, unsigned int size,
-			       void *user_data HB_UNUSED)
-{
-  return font->parent->get_glyph_name (glyph, name, size);
-}
 
 static hb_bool_t
-hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED,
+hb_font_get_glyph_from_name_nil (hb_font_t *font,
 				 void *font_data HB_UNUSED,
 				 const char *name, int len, /* -1 means nul-terminated */
 				 hb_codepoint_t *glyph,
 				 void *user_data HB_UNUSED)
 {
+  if (font->parent)
+    return font->parent->get_glyph_from_name (name, len, glyph);
+
   *glyph = 0;
   return false;
 }
-static hb_bool_t
-hb_font_get_glyph_from_name_parent (hb_font_t *font,
-				    void *font_data HB_UNUSED,
-				    const char *name, int len, /* -1 means nul-terminated */
-				    hb_codepoint_t *glyph,
-				    void *user_data HB_UNUSED)
-{
-  return font->parent->get_glyph_from_name (name, len, glyph);
-}
 
 
 static const hb_font_funcs_t _hb_font_funcs_nil = {
   HB_OBJECT_HEADER_STATIC,
 
   true, /* immutable */
 
   {
-#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
-    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
-  },
-  {
-#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
-    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
-  },
-  {
 #define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
   }
 };
-static const hb_font_funcs_t _hb_font_funcs_parent = {
-  HB_OBJECT_HEADER_STATIC,
-
-  true, /* immutable */
-
-  {
-#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
-    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
-  },
-  {
-#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
-    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
-  },
-  {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_parent,
-    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
-  }
-};
 
 
 /**
  * hb_font_funcs_create: (Xconstructor)
  *
  * 
  *
  * Return value: (transfer full): 
@@ -337,34 +241,34 @@ static const hb_font_funcs_t _hb_font_fu
 hb_font_funcs_t *
 hb_font_funcs_create (void)
 {
   hb_font_funcs_t *ffuncs;
 
   if (!(ffuncs = hb_object_create<hb_font_funcs_t> ()))
     return hb_font_funcs_get_empty ();
 
-  ffuncs->get = _hb_font_funcs_parent.get;
+  ffuncs->get = _hb_font_funcs_nil.get;
 
   return ffuncs;
 }
 
 /**
  * hb_font_funcs_get_empty:
  *
  * 
  *
  * Return value: (transfer full): 
  *
  * Since: 0.9.2
  **/
 hb_font_funcs_t *
 hb_font_funcs_get_empty (void)
 {
-  return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_parent);
+  return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil);
 }
 
 /**
  * hb_font_funcs_reference: (skip)
  * @ffuncs: font functions.
  *
  * 
  *
@@ -489,36 +393,29 @@ hb_font_funcs_set_##name##_func (hb_font
       destroy (user_data);                                               \
     return;                                                              \
   }                                                                      \
                                                                          \
   if (ffuncs->destroy.name)                                              \
     ffuncs->destroy.name (ffuncs->user_data.name);                       \
                                                                          \
   if (func) {                                                            \
-    ffuncs->get.f.name = func;                                           \
+    ffuncs->get.name = func;                                             \
     ffuncs->user_data.name = user_data;                                  \
     ffuncs->destroy.name = destroy;                                      \
   } else {                                                               \
-    ffuncs->get.f.name = hb_font_get_##name##_parent;                    \
+    ffuncs->get.name = hb_font_get_##name##_nil;                         \
     ffuncs->user_data.name = NULL;                                       \
     ffuncs->destroy.name = NULL;                                         \
   }                                                                      \
 }
 
 HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
 
-bool
-hb_font_t::has_func (unsigned int i)
-{
-  if (parent && parent != hb_font_get_empty () && parent->has_func (i))
-    return true;
-  return this->klass->get.array[i] != _hb_font_funcs_parent.get.array[i];
-}
 
 /* Public getters */
 
 /**
  * hb_font_get_glyph:
  * @font: a font.
  * @unicode: 
  * @variation_selector: 
@@ -956,17 +853,16 @@ hb_font_create (hb_face_t *face)
   hb_font_t *font;
 
   if (unlikely (!face))
     face = hb_face_get_empty ();
   if (!(font = hb_object_create<hb_font_t> ()))
     return hb_font_get_empty ();
 
   hb_face_make_immutable (face);
-  font->parent = hb_font_get_empty ();
   font->face = hb_face_reference (face);
   font->klass = hb_font_funcs_get_empty ();
 
   font->x_scale = font->y_scale = hb_face_get_upem (face);
 
   return font;
 }
 
@@ -1016,18 +912,18 @@ hb_font_get_empty (void)
   static const hb_font_t _hb_font_nil = {
     HB_OBJECT_HEADER_STATIC,
 
     true, /* immutable */
 
     NULL, /* parent */
     const_cast<hb_face_t *> (&_hb_face_nil),
 
-    1000, /* x_scale */
-    1000, /* y_scale */
+    0, /* x_scale */
+    0, /* y_scale */
 
     0, /* x_ppem */
     0, /* y_ppem */
 
     const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
     NULL, /* user_data */
     NULL, /* destroy */
 
--- a/gfx/harfbuzz/src/hb-ft.cc
+++ b/gfx/harfbuzz/src/hb-ft.cc
@@ -212,16 +212,28 @@ hb_ft_get_glyph_v_advance (hb_font_t *fo
     v = -v;
 
   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
    * have a Y growing upward.  Hence the extra negation. */
   return (-v + (1<<9)) >> 10;
 }
 
 static hb_bool_t
+hb_ft_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
+			  void *font_data HB_UNUSED,
+			  hb_codepoint_t glyph HB_UNUSED,
+			  hb_position_t *x HB_UNUSED,
+			  hb_position_t *y HB_UNUSED,
+			  void *user_data HB_UNUSED)
+{
+  /* We always work in the horizontal coordinates. */
+  return true;
+}
+
+static hb_bool_t
 hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
 			  void *font_data,
 			  hb_codepoint_t glyph,
 			  hb_position_t *x,
 			  hb_position_t *y,
 			  void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
@@ -255,16 +267,27 @@ hb_ft_get_glyph_h_kerning (hb_font_t *fo
 
   FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
   if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
     return 0;
 
   return kerningv.x;
 }
 
+static hb_position_t
+hb_ft_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
+			   void *font_data HB_UNUSED,
+			   hb_codepoint_t top_glyph HB_UNUSED,
+			   hb_codepoint_t bottom_glyph HB_UNUSED,
+			   void *user_data HB_UNUSED)
+{
+  /* FreeType API doesn't support vertical kerning */
+  return 0;
+}
+
 static hb_bool_t
 hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
 			 void *font_data,
 			 hb_codepoint_t glyph,
 			 hb_glyph_extents_t *extents,
 			 void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
@@ -272,26 +295,16 @@ hb_ft_get_glyph_extents (hb_font_t *font
 
   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
     return false;
 
   extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
   extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
   extents->width = ft_face->glyph->metrics.width;
   extents->height = -ft_face->glyph->metrics.height;
-  if (font->x_scale < 0)
-  {
-    extents->x_bearing = -extents->x_bearing;
-    extents->width = -extents->width;
-  }
-  if (font->y_scale < 0)
-  {
-    extents->y_bearing = -extents->y_bearing;
-    extents->height = -extents->height;
-  }
   return true;
 }
 
 static hb_bool_t
 hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
 			       void *font_data,
 			       hb_codepoint_t glyph,
 			       unsigned int point_index,
@@ -362,62 +375,33 @@ hb_ft_get_glyph_from_name (hb_font_t *fo
         len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
       return true;
   }
 
   return *glyph != 0;
 }
 
 
-static hb_font_funcs_t *static_ft_funcs = NULL;
-
-#ifdef HB_USE_ATEXIT
-static
-void free_static_ft_funcs (void)
-{
-  hb_font_funcs_destroy (static_ft_funcs);
-}
-#endif
-
 static void
 _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
 {
-retry:
-  hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
+  static const hb_font_funcs_t ft_ffuncs = {
+    HB_OBJECT_HEADER_STATIC,
 
-  if (unlikely (!funcs))
-  {
-    funcs = hb_font_funcs_create ();
+    true, /* immutable */
 
-    hb_font_funcs_set_glyph_func (funcs, hb_ft_get_glyph, NULL, NULL);
-    hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, NULL, NULL);
-    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, NULL, NULL);
-    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, NULL, NULL);
-    hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, NULL, NULL);
-    hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, NULL, NULL);
-    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, NULL, NULL);
-    hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, NULL, NULL);
-    hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, NULL, NULL);
-    hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, NULL, NULL);
-    hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, NULL, NULL);
-
-    hb_font_funcs_make_immutable (funcs);
-
-    if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, NULL, funcs)) {
-      hb_font_funcs_destroy (funcs);
-      goto retry;
+    {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_ft_get_##name,
+      HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
     }
-
-#ifdef HB_USE_ATEXIT
-    atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
-#endif
   };
 
   hb_font_set_funcs (font,
-		     funcs,
+		     const_cast<hb_font_funcs_t *> (&ft_ffuncs),
 		     _hb_ft_font_create (ft_face, unref),
 		     (hb_destroy_func_t) _hb_ft_font_destroy);
 }
 
 
 static hb_blob_t *
 reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
 {
--- a/gfx/harfbuzz/src/hb-open-type-private.hh
+++ b/gfx/harfbuzz/src/hb-open-type-private.hh
@@ -180,17 +180,17 @@ struct hb_dispatch_context_t
 
 #define TRACE_SANITIZE(this) \
 	hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	 "");
 
 /* This limits sanitizing time on really broken fonts. */
 #ifndef HB_SANITIZE_MAX_EDITS
-#define HB_SANITIZE_MAX_EDITS 8
+#define HB_SANITIZE_MAX_EDITS 100
 #endif
 
 struct hb_sanitize_context_t :
        hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
 {
   inline hb_sanitize_context_t (void) :
 	debug_depth (0),
 	start (NULL), end (NULL),
@@ -394,19 +394,19 @@ struct Sanitizer
 #define TRACE_SERIALIZE(this) \
 	hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
 	(&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
 	 "");
 
 
 struct hb_serialize_context_t
 {
-  inline hb_serialize_context_t (void *start_, unsigned int size)
+  inline hb_serialize_context_t (void *start, unsigned int size)
   {
-    this->start = (char *) start_;
+    this->start = (char *) start;
     this->end = this->start + size;
 
     this->ran_out_of_room = false;
     this->head = this->start;
     this->debug_depth = 0;
   }
 
   template <typename Type>
@@ -490,20 +490,20 @@ struct hb_serialize_context_t
   inline Type *extend (Type &obj)
   {
     unsigned int size = obj.get_size ();
     assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
     if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
     return reinterpret_cast<Type *> (&obj);
   }
 
-  inline void truncate (void *new_head)
+  inline void truncate (void *head)
   {
-    assert (this->start < new_head && new_head <= this->head);
-    this->head = (char *) new_head;
+    assert (this->start < head && head <= this->head);
+    this->head = (char *) head;
   }
 
   unsigned int debug_depth;
   char *start, *end, *head;
   bool ran_out_of_room;
 };
 
 template <typename Type>
--- a/gfx/harfbuzz/src/hb-ot-font.cc
+++ b/gfx/harfbuzz/src/hb-ot-font.cc
@@ -41,36 +41,30 @@ struct hb_ot_face_metrics_accelerator_t
 {
   unsigned int num_metrics;
   unsigned int num_advances;
   unsigned int default_advance;
   const OT::_mtx *table;
   hb_blob_t *blob;
 
   inline void init (hb_face_t *face,
-		    hb_tag_t _hea_tag, hb_tag_t _mtx_tag)
+		    hb_tag_t _hea_tag, hb_tag_t _mtx_tag,
+		    unsigned int default_advance_)
   {
-    this->default_advance = face->get_upem ();
+    this->default_advance = default_advance_;
+    this->num_metrics = face->get_num_glyphs ();
 
     hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
     const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
     this->num_advances = _hea->numberOfLongMetrics;
     hb_blob_destroy (_hea_blob);
 
     this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
-
-    /* Cap num_metrics() and num_advances() based on table length. */
-    unsigned int len = hb_blob_get_length (this->blob);
-    if (unlikely (this->num_advances * 4 > len))
-      this->num_advances = len / 4;
-    this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2;
-
-    /* We MUST set num_metrics to zero if num_advances is zero.
-     * Our get_advance() depends on that. */
-    if (unlikely (!this->num_advances))
+    if (unlikely (!this->num_advances ||
+		  2 * (this->num_advances + this->num_metrics) > hb_blob_get_length (this->blob)))
     {
       this->num_metrics = this->num_advances = 0;
       hb_blob_destroy (this->blob);
       this->blob = hb_blob_get_empty ();
     }
     this->table = OT::Sanitizer<OT::_mtx>::lock_instance (this->blob);
   }
 
@@ -246,19 +240,21 @@ struct hb_ot_font_t
 static hb_ot_font_t *
 _hb_ot_font_create (hb_face_t *face)
 {
   hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
 
   if (unlikely (!ot_font))
     return NULL;
 
+  unsigned int upem = face->get_upem ();
+
   ot_font->cmap.init (face);
-  ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx);
-  ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx); /* TODO Can we do this lazily? */
+  ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, upem>>1);
+  ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, upem); /* TODO Can we do this lazily? */
   ot_font->glyf.init (face);
 
   return ot_font;
 }
 
 static void
 _hb_ot_font_destroy (hb_ot_font_t *ot_font)
 {
@@ -300,77 +296,129 @@ hb_ot_get_glyph_v_advance (hb_font_t *fo
 			   hb_codepoint_t glyph,
 			   void *user_data HB_UNUSED)
 {
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph));
 }
 
 static hb_bool_t
+hb_ot_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
+			  void *font_data HB_UNUSED,
+			  hb_codepoint_t glyph HB_UNUSED,
+			  hb_position_t *x HB_UNUSED,
+			  hb_position_t *y HB_UNUSED,
+			  void *user_data HB_UNUSED)
+{
+  /* We always work in the horizontal coordinates. */
+  return true;
+}
+
+static hb_bool_t
+hb_ot_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
+			  void *font_data,
+			  hb_codepoint_t glyph,
+			  hb_position_t *x,
+			  hb_position_t *y,
+			  void *user_data HB_UNUSED)
+{
+  /* TODO */
+  return false;
+}
+
+static hb_position_t
+hb_ot_get_glyph_h_kerning (hb_font_t *font,
+			   void *font_data,
+			   hb_codepoint_t left_glyph,
+			   hb_codepoint_t right_glyph,
+			   void *user_data HB_UNUSED)
+{
+  /* TODO */
+  return 0;
+}
+
+static hb_position_t
+hb_ot_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
+			   void *font_data HB_UNUSED,
+			   hb_codepoint_t top_glyph HB_UNUSED,
+			   hb_codepoint_t bottom_glyph HB_UNUSED,
+			   void *user_data HB_UNUSED)
+{
+  /* OpenType doesn't have vertical-kerning other than GPOS. */
+  return 0;
+}
+
+static hb_bool_t
 hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
 			 void *font_data,
 			 hb_codepoint_t glyph,
 			 hb_glyph_extents_t *extents,
 			 void *user_data HB_UNUSED)
 {
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   bool ret = ot_font->glyf.get_extents (glyph, extents);
   extents->x_bearing = font->em_scale_x (extents->x_bearing);
   extents->y_bearing = font->em_scale_y (extents->y_bearing);
   extents->width     = font->em_scale_x (extents->width);
   extents->height    = font->em_scale_y (extents->height);
   return ret;
 }
 
-
-static hb_font_funcs_t *static_ot_funcs = NULL;
+static hb_bool_t
+hb_ot_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
+			       void *font_data,
+			       hb_codepoint_t glyph,
+			       unsigned int point_index,
+			       hb_position_t *x,
+			       hb_position_t *y,
+			       void *user_data HB_UNUSED)
+{
+  /* TODO */
+  return false;
+}
 
-#ifdef HB_USE_ATEXIT
-static
-void free_static_ot_funcs (void)
+static hb_bool_t
+hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
+		      void *font_data,
+		      hb_codepoint_t glyph,
+		      char *name, unsigned int size,
+		      void *user_data HB_UNUSED)
 {
-  hb_font_funcs_destroy (static_ot_funcs);
+  /* TODO */
+  return false;
 }
-#endif
+
+static hb_bool_t
+hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
+			   void *font_data,
+			   const char *name, int len, /* -1 means nul-terminated */
+			   hb_codepoint_t *glyph,
+			   void *user_data HB_UNUSED)
+{
+  /* TODO */
+  return false;
+}
+
 
 static hb_font_funcs_t *
 _hb_ot_get_font_funcs (void)
 {
-retry:
-  hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
+  static const hb_font_funcs_t ot_ffuncs = {
+    HB_OBJECT_HEADER_STATIC,
 
-  if (unlikely (!funcs))
-  {
-    funcs = hb_font_funcs_create ();
+    true, /* immutable */
 
-    hb_font_funcs_set_glyph_func (funcs, hb_ot_get_glyph, NULL, NULL);
-    hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL);
-    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL);
-    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, NULL, NULL);
-    //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, NULL, NULL);
-    //hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, NULL, NULL); TODO
-    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, NULL, NULL);
-    hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, NULL, NULL);
-    //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, NULL, NULL); TODO
-    //hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, NULL, NULL); TODO
-    //hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, NULL, NULL); TODO
-
-    hb_font_funcs_make_immutable (funcs);
-
-    if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, NULL, funcs)) {
-      hb_font_funcs_destroy (funcs);
-      goto retry;
+    {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_ot_get_##name,
+      HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
     }
-
-#ifdef HB_USE_ATEXIT
-    atexit (free_static_ot_funcs); /* First person registers atexit() callback. */
-#endif
   };
 
-  return funcs;
+  return const_cast<hb_font_funcs_t *> (&ot_ffuncs);
 }
 
 
 /**
  * Since: 0.9.28
  **/
 void
 hb_ot_font_set_funcs (hb_font_t *font)
--- a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
@@ -29,34 +29,28 @@
 #ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH
 #define HB_OT_LAYOUT_COMMON_PRIVATE_HH
 
 #include "hb-ot-layout-private.hh"
 #include "hb-open-type-private.hh"
 #include "hb-set-private.hh"
 
 
-#ifndef HB_MAX_NESTING_LEVEL
-#define HB_MAX_NESTING_LEVEL	6
-#endif
-#ifndef HB_MAX_CONTEXT_LENGTH
-#define HB_MAX_CONTEXT_LENGTH	64
-#endif
-
-
 namespace OT {
 
 
 #define TRACE_DISPATCH(this, format) \
 	hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	 "format %d", (int) format);
 
 
 #define NOT_COVERED		((unsigned int) -1)
+#define MAX_NESTING_LEVEL	6
+#define MAX_CONTEXT_LENGTH	64
 
 
 
 /*
  *
  * OpenType Layout Common Table Formats
  *
  */
@@ -574,21 +568,16 @@ struct LookupFlag : USHORT
     UseMarkFilteringSet	= 0x0010u,
     Reserved		= 0x00E0u,
     MarkAttachmentType	= 0xFF00u
   };
   public:
   DEFINE_SIZE_STATIC (2);
 };
 
-} /* namespace OT */
-/* This has to be outside the namespace. */
-HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
-namespace OT {
-
 struct Lookup
 {
   inline unsigned int get_subtable_count (void) const { return subTable.len; }
 
   template <typename SubTableType>
   inline const SubTableType& get_subtable (unsigned int i) const
   { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }
 
--- a/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
@@ -421,17 +421,16 @@ struct MarkArray : ArrayOf<MarkRecord>	/
 
     mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
     glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
 
     hb_glyph_position_t &o = buffer->cur_pos();
     o.x_offset = base_x - mark_x;
     o.y_offset = base_y - mark_y;
     o.attach_lookback() = buffer->idx - glyph_pos;
-    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
 
     buffer->idx++;
     return_trace (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -989,17 +988,16 @@ struct CursivePosFormat1
     /* If child was already connected to someone else, walk through its old
      * chain and reverse the link direction, such that the whole tree of its
      * previous connection now attaches to new parent.  Watch out for case
      * where new parent is on the path from old chain...
      */
     reverse_cursive_minor_offset (pos, child, c->direction, parent);
 
     pos[child].cursive_chain() = parent - child;
-    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE;
     if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
       pos[child].y_offset = y_offset;
     else
       pos[child].x_offset = x_offset;
 
     buffer->idx = j;
     return_trace (true);
   }
@@ -1596,24 +1594,22 @@ GPOS::position_finish (hb_font_t *font H
 {
   _hb_buffer_assert_gsubgpos_vars (buffer);
 
   unsigned int len;
   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
   hb_direction_t direction = buffer->props.direction;
 
   /* Handle cursive connections */
-  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE)
-    for (unsigned int i = 0; i < len; i++)
-      fix_cursive_minor_offset (pos, i, direction);
+  for (unsigned int i = 0; i < len; i++)
+    fix_cursive_minor_offset (pos, i, direction);
 
   /* Handle attachments */
-  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
-    for (unsigned int i = 0; i < len; i++)
-      fix_mark_attachment (pos, i, direction);
+  for (unsigned int i = 0; i < len; i++)
+    fix_mark_attachment (pos, i, direction);
 }
 
 
 /* Out-of-class implementation for methods recursing */
 
 template <typename context_t>
 /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
 {
--- a/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
@@ -625,17 +625,17 @@ struct Ligature
       c->replace_glyph (ligGlyph);
       return_trace (true);
     }
 
     bool is_mark_ligature = false;
     unsigned int total_component_count = 0;
 
     unsigned int match_length = 0;
-    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
+    unsigned int match_positions[MAX_CONTEXT_LENGTH];
 
     if (likely (!match_input (c, count,
 			      &component[1],
 			      match_glyph,
 			      NULL,
 			      &match_length,
 			      match_positions,
 			      &is_mark_ligature,
@@ -965,17 +965,17 @@ struct ReverseChainSingleSubstFormat1
   {
     TRACE_WOULD_APPLY (this);
     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
+    if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
       return_trace (false); /* No chaining to this type */
 
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
 
--- a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
@@ -69,17 +69,17 @@ struct hb_closure_context_t :
   hb_face_t *face;
   hb_set_t *glyphs;
   recurse_func_t recurse_func;
   unsigned int nesting_level_left;
   unsigned int debug_depth;
 
   hb_closure_context_t (hb_face_t *face_,
 			hb_set_t *glyphs_,
-		        unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
+		        unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
 			  face (face_),
 			  glyphs (glyphs_),
 			  recurse_func (NULL),
 			  nesting_level_left (nesting_level_left_),
 			  debug_depth (0) {}
 
   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
 };
@@ -191,17 +191,17 @@ struct hb_collect_glyphs_context_t :
   unsigned int nesting_level_left;
   unsigned int debug_depth;
 
   hb_collect_glyphs_context_t (hb_face_t *face_,
 			       hb_set_t  *glyphs_before, /* OUT. May be NULL */
 			       hb_set_t  *glyphs_input,  /* OUT. May be NULL */
 			       hb_set_t  *glyphs_after,  /* OUT. May be NULL */
 			       hb_set_t  *glyphs_output, /* OUT. May be NULL */
-			       unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
+			       unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
 			      face (face_),
 			      before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
 			      input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
 			      after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
 			      output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
 			      recurse_func (NULL),
 			      recursed_lookups (),
 			      nesting_level_left (nesting_level_left_),
@@ -350,21 +350,21 @@ struct hb_apply_context_t :
       /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
       matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
       matcher.set_mask (context_match ? -1 : c->lookup_mask);
     }
     inline void set_lookup_props (unsigned int lookup_props)
     {
       matcher.set_lookup_props (lookup_props);
     }
-    inline void set_match_func (matcher_t::match_func_t match_func_,
-				const void *match_data_,
+    inline void set_match_func (matcher_t::match_func_t match_func,
+				const void *match_data,
 				const USHORT glyph_data[])
     {
-      matcher.set_match_func (match_func_, match_data_);
+      matcher.set_match_func (match_func, match_data);
       match_glyph_data = glyph_data;
     }
 
     inline void reset (unsigned int start_index_,
 		       unsigned int num_items_)
     {
       idx = start_index_;
       num_items = num_items_;
@@ -478,17 +478,17 @@ struct hb_apply_context_t :
 		      hb_font_t *font_,
 		      hb_buffer_t *buffer_) :
 			table_index (table_index_),
 			font (font_), face (font->face), buffer (buffer_),
 			direction (buffer_->props.direction),
 			lookup_mask (1),
 			auto_zwj (true),
 			recurse_func (NULL),
-			nesting_level_left (HB_MAX_NESTING_LEVEL),
+			nesting_level_left (MAX_NESTING_LEVEL),
 			lookup_props (0),
 			gdef (*hb_ot_layout_from_face (face)->gdef),
 			has_glyph_classes (gdef.has_glyph_classes ()),
 			iter_input (),
 			iter_context (),
 			lookup_index ((unsigned int) -1),
 			debug_depth (0) {}
 
@@ -699,23 +699,23 @@ static inline bool would_match_input (hb
   return true;
 }
 static inline bool match_input (hb_apply_context_t *c,
 				unsigned int count, /* Including the first glyph (not matched) */
 				const USHORT input[], /* Array of input values--start with second glyph */
 				match_func_t match_func,
 				const void *match_data,
 				unsigned int *end_offset,
-				unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
+				unsigned int match_positions[MAX_CONTEXT_LENGTH],
 				bool *p_is_mark_ligature = NULL,
 				unsigned int *p_total_component_count = NULL)
 {
   TRACE_APPLY (NULL);
 
-  if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
+  if (unlikely (count > MAX_CONTEXT_LENGTH)) return_trace (false);
 
   hb_buffer_t *buffer = c->buffer;
 
   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
   skippy_iter.reset (buffer->idx, count - 1);
   skippy_iter.set_match_func (match_func, match_data, input);
 
   /*
@@ -779,17 +779,17 @@ static inline bool match_input (hb_apply
 
   if (p_total_component_count)
     *p_total_component_count = total_component_count;
 
   return_trace (true);
 }
 static inline bool ligate_input (hb_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph */
-				 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
+				 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
 				 unsigned int match_length,
 				 hb_codepoint_t lig_glyph,
 				 bool is_mark_ligature,
 				 unsigned int total_component_count)
 {
   TRACE_APPLY (NULL);
 
   hb_buffer_t *buffer = c->buffer;
@@ -831,23 +831,24 @@ static inline bool ligate_input (hb_appl
   unsigned int components_so_far = last_num_components;
 
   if (!is_mark_ligature)
   {
     _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
     if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
     {
       _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
+      _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0);
     }
   }
   c->replace_glyph_with_ligature (lig_glyph, klass);
 
   for (unsigned int i = 1; i < count; i++)
   {
-    while (buffer->idx < match_positions[i] && !buffer->in_error)
+    while (buffer->idx < match_positions[i])
     {
       if (!is_mark_ligature) {
 	unsigned int new_lig_comp = components_so_far - last_num_components +
 				    MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components);
 	_hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
       }
       buffer->next_glyph ();
     }
@@ -938,17 +939,17 @@ static inline void recurse_lookups (cont
 				    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
 {
   for (unsigned int i = 0; i < lookupCount; i++)
     c->recurse (lookupRecord[i].lookupListIndex);
 }
 
 static inline bool apply_lookup (hb_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph */
-				 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
+				 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
 				 unsigned int lookupCount,
 				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
 				 unsigned int match_length)
 {
   TRACE_APPLY (NULL);
 
   hb_buffer_t *buffer = c->buffer;
   unsigned int end;
@@ -983,23 +984,23 @@ static inline bool apply_lookup (hb_appl
     if (!delta)
         continue;
 
     /* Recursed lookup changed buffer len.  Adjust. */
 
     /* end can't go back past the current match position.
      * Note: this is only true because we do NOT allow MultipleSubst
      * with zero sequence len. */
-    end = MAX (MIN((int) match_positions[idx] + 1, (int) new_len), int (end) + delta);
+    end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
 
     unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
 
     if (delta > 0)
     {
-      if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
+      if (unlikely (delta + count > MAX_CONTEXT_LENGTH))
 	break;
     }
     else
     {
       /* NOTE: delta is negative. */
       delta = MAX (delta, (int) next - (int) count);
       next -= delta;
     }
@@ -1088,17 +1089,17 @@ static inline bool context_would_apply_l
 static inline bool context_apply_lookup (hb_apply_context_t *c,
 					 unsigned int inputCount, /* Including the first glyph (not matched) */
 					 const USHORT input[], /* Array of input values--start with second glyph */
 					 unsigned int lookupCount,
 					 const LookupRecord lookupRecord[],
 					 ContextApplyLookupContext &lookup_context)
 {
   unsigned int match_length = 0;
-  unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
+  unsigned int match_positions[MAX_CONTEXT_LENGTH];
   return match_input (c,
 		      inputCount, input,
 		      lookup_context.funcs.match, lookup_context.match_data,
 		      &match_length, match_positions)
       && apply_lookup (c,
 		       inputCount, match_positions,
 		       lookupCount, lookupRecord,
 		       match_length);
@@ -1615,17 +1616,17 @@ static inline bool chain_context_apply_l
 					       const USHORT input[], /* Array of input values--start with second glyph */
 					       unsigned int lookaheadCount,
 					       const USHORT lookahead[],
 					       unsigned int lookupCount,
 					       const LookupRecord lookupRecord[],
 					       ChainContextApplyLookupContext &lookup_context)
 {
   unsigned int match_length = 0;
-  unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
+  unsigned int match_positions[MAX_CONTEXT_LENGTH];
   return match_input (c,
 		      inputCount, input,
 		      lookup_context.funcs.match, lookup_context.match_data[1],
 		      &match_length, match_positions)
       && match_backtrack (c,
 			  backtrackCount, backtrack,
 			  lookup_context.funcs.match, lookup_context.match_data[0])
       && match_lookahead (c,
--- a/gfx/harfbuzz/src/hb-ot-layout-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-private.hh
@@ -44,33 +44,32 @@ hb_ot_layout_table_find_feature (hb_face
 				 hb_tag_t      feature_tag,
 				 unsigned int *feature_index);
 
 
 /*
  * GDEF
  */
 
-enum hb_ot_layout_glyph_props_flags_t
+typedef enum
 {
   /* The following three match LookupFlags::Ignore* numbers. */
   HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH	= 0x02u,
   HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE	= 0x04u,
   HB_OT_LAYOUT_GLYPH_PROPS_MARK		= 0x08u,
 
   /* The following are used internally; not derived from GDEF. */
   HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED	= 0x10u,
   HB_OT_LAYOUT_GLYPH_PROPS_LIGATED	= 0x20u,
   HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED	= 0x40u,
 
   HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE     = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
 					  HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
 					  HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
-};
-HB_MARK_AS_FLAG_T (hb_ot_layout_glyph_props_flags_t);
+} hb_ot_layout_glyph_class_mask_t;
 
 
 /*
  * GSUB/GPOS
  */
 
 HB_INTERNAL hb_bool_t
 hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
@@ -176,17 +175,18 @@ HB_INTERNAL void
 #define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
 
 
 /*
  * Buffer var routines.
  */
 
 /* buffer var allocations, used during the entire shaping process */
-#define unicode_props()		var2.u16[0]
+#define unicode_props0()	var2.u8[0]
+#define unicode_props1()	var2.u8[1]
 
 /* buffer var allocations, used during the GSUB/GPOS processing */
 #define glyph_props()		var1.u16[0] /* GDEF glyph properties */
 #define lig_props()		var1.u8[2] /* GSUB/GPOS ligature tracking */
 #define syllable()		var1.u8[3] /* GSUB/GPOS shaping boundaries */
 
 
 /* loop over syllables */
@@ -209,159 +209,84 @@ static inline unsigned int
     ;
 
   return start;
 }
 
 
 /* unicode_props */
 
-/* Design:
- * unicode_props() is a two-byte number.  The low byte includes:
- * - General_Category: 5 bits.
- * - A bit each for:
- *   * Is it Default_Ignorable(); we have a modified Default_Ignorable().
- *   * Is it U+200D ZWJ?
- *   * Is it U+200C ZWNJ?
- *
- * The high-byte has different meanings, switched by the Gen-Cat:
- * - For Mn,Mc,Me: the modified Combining_Class.
- * - For Ws: index of which space character this is, if space fallback
- *   is needed, ie. we don't set this by default, only if asked to.
- *
- * If needed, we can use the ZWJ/ZWNJ to use the high byte as well,
- * freeing two more bits.
- */
-
-enum hb_unicode_props_flags_t {
-  UPROPS_MASK_ZWJ       = 0x20u,
-  UPROPS_MASK_ZWNJ      = 0x40u,
-  UPROPS_MASK_IGNORABLE = 0x80u,
-  UPROPS_MASK_GEN_CAT   = 0x1Fu
+enum {
+  MASK0_ZWJ       = 0x20u,
+  MASK0_ZWNJ      = 0x40u,
+  MASK0_IGNORABLE = 0x80u,
+  MASK0_GEN_CAT   = 0x1Fu
 };
-HB_MARK_AS_FLAG_T (hb_unicode_props_flags_t);
 
 static inline void
-_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
+_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
 {
-  hb_unicode_funcs_t *unicode = buffer->unicode;
-  unsigned int u = info->codepoint;
-  unsigned int gen_cat = (unsigned int) unicode->general_category (u);
-  unsigned int props = gen_cat;
-
-  if (u >= 0x80)
-  {
-    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
-    if (unlikely (unicode->is_default_ignorable (u)))
-    {
-      buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
-      props |=  UPROPS_MASK_IGNORABLE;
-      if (u == 0x200Cu) props |= UPROPS_MASK_ZWNJ;
-      if (u == 0x200Du) props |= UPROPS_MASK_ZWJ;
-    }
-    else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK (gen_cat)))
-    {
-      /* Only Mn and Mc can have non-zero ccc:
-       * http://www.unicode.org/policies/stability_policy.html#Property_Value
-       * """
-       * Canonical_Combining_Class, General_Category
-       * All characters other than those with General_Category property values
-       * Spacing_Mark (Mc) and Nonspacing_Mark (Mn) have the Canonical_Combining_Class
-       * property value 0.
-       * 1.1.5+
-       * """
-       *
-       * Also, all Mn's that are Default_Ignorable, have ccc=0, hence
-       * the "else if".
-       */
-      props |= unicode->modified_combining_class (info->codepoint)<<8;
-    }
-  }
-
-  info->unicode_props() = props;
+  /* XXX This shouldn't be inlined, or at least not while is_default_ignorable() is inline. */
+  info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
+			   (unicode->is_default_ignorable (info->codepoint) ? MASK0_IGNORABLE : 0) |
+			   (info->codepoint == 0x200Cu ? MASK0_ZWNJ : 0) |
+			   (info->codepoint == 0x200Du ? MASK0_ZWJ : 0);
+  info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
 }
 
 static inline void
 _hb_glyph_info_set_general_category (hb_glyph_info_t *info,
 				     hb_unicode_general_category_t gen_cat)
 {
-  /* Clears top-byte. */
-  info->unicode_props() = (unsigned int) gen_cat | (info->unicode_props() & (0xFF & ~UPROPS_MASK_GEN_CAT));
+  info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~MASK0_GEN_CAT);
 }
 
 static inline hb_unicode_general_category_t
 _hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
 {
-  return (hb_unicode_general_category_t) (info->unicode_props() & UPROPS_MASK_GEN_CAT);
+  return (hb_unicode_general_category_t) (info->unicode_props0() & MASK0_GEN_CAT);
 }
 
-static inline bool
-_hb_glyph_info_is_unicode_mark (const hb_glyph_info_t *info)
-{
-  return HB_UNICODE_GENERAL_CATEGORY_IS_MARK (info->unicode_props() & UPROPS_MASK_GEN_CAT);
-}
 static inline void
 _hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
 					     unsigned int modified_class)
 {
-  if (unlikely (!_hb_glyph_info_is_unicode_mark (info)))
-    return;
-  info->unicode_props() = (modified_class<<8) | (info->unicode_props() & 0xFF);
+  info->unicode_props1() = modified_class;
 }
+
 static inline unsigned int
 _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
 {
-  return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0;
-}
-
-static inline bool
-_hb_glyph_info_is_unicode_space (const hb_glyph_info_t *info)
-{
-  return _hb_glyph_info_get_general_category (info) ==
-	 HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
-}
-static inline void
-_hb_glyph_info_set_unicode_space_fallback_type (hb_glyph_info_t *info, hb_unicode_funcs_t::space_t s)
-{
-  if (unlikely (!_hb_glyph_info_is_unicode_space (info)))
-    return;
-  info->unicode_props() = (((unsigned int) s)<<8) | (info->unicode_props() & 0xFF);
-}
-static inline hb_unicode_funcs_t::space_t
-_hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info)
-{
-  return _hb_glyph_info_is_unicode_space (info) ?
-	 (hb_unicode_funcs_t::space_t) (info->unicode_props()>>8) :
-	 hb_unicode_funcs_t::NOT_SPACE;
+  return info->unicode_props1();
 }
 
 static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
 
 static inline hb_bool_t
 _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
 {
-  return (info->unicode_props() & UPROPS_MASK_IGNORABLE) && !_hb_glyph_info_ligated (info);
+  return (info->unicode_props0() & MASK0_IGNORABLE) && !_hb_glyph_info_ligated (info);
 }
 
 static inline hb_bool_t
 _hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
 {
-  return !!(info->unicode_props() & UPROPS_MASK_ZWNJ);
+  return !!(info->unicode_props0() & MASK0_ZWNJ);
 }
 
 static inline hb_bool_t
 _hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
 {
-  return !!(info->unicode_props() & UPROPS_MASK_ZWJ);
+  return !!(info->unicode_props0() & MASK0_ZWJ);
 }
 
 static inline void
 _hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
 {
-  info->unicode_props() ^= UPROPS_MASK_ZWNJ | UPROPS_MASK_ZWJ;
+  info->unicode_props0() ^= MASK0_ZWNJ | MASK0_ZWJ;
 }
 
 /* lig_props: aka lig_id / lig_comp
  *
  * When a ligature is formed:
  *
  *   - The ligature glyph and any marks in between all the same newly allocated
  *     lig_id,
@@ -525,29 +450,32 @@ static inline void
 }
 
 
 /* Allocation / deallocation. */
 
 static inline void
 _hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
 {
-  HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props);
+  HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props0);
+  HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props1);
 }
 
 static inline void
 _hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
 {
-  HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props0);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1);
 }
 
 static inline void
 _hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
 {
-  HB_BUFFER_ASSERT_VAR (buffer, unicode_props);
+  HB_BUFFER_ASSERT_VAR (buffer, unicode_props0);
+  HB_BUFFER_ASSERT_VAR (buffer, unicode_props1);
 }
 
 static inline void
 _hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
 {
   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
   HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
   HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
--- a/gfx/harfbuzz/src/hb-ot-layout.cc
+++ b/gfx/harfbuzz/src/hb-ot-layout.cc
@@ -885,17 +885,17 @@ struct GPOSProxy
 template <typename Obj>
 static inline bool
 apply_forward (OT::hb_apply_context_t *c,
 	       const Obj &obj,
 	       const hb_ot_layout_lookup_accelerator_t &accel)
 {
   bool ret = false;
   hb_buffer_t *buffer = c->buffer;
-  while (buffer->idx < buffer->len && !buffer->in_error)
+  while (buffer->idx < buffer->len)
   {
     if (accel.may_have (buffer->cur().codepoint) &&
 	(buffer->cur().mask & c->lookup_mask) &&
 	c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
 	obj.apply (c))
       ret = true;
     else
       buffer->next_glyph ();
--- a/gfx/harfbuzz/src/hb-ot-map-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-map-private.hh
@@ -154,19 +154,33 @@ struct hb_ot_map_t
 
 enum hb_ot_map_feature_flags_t {
   F_NONE		= 0x0000u,
   F_GLOBAL		= 0x0001u, /* Feature applies to all characters; results in no mask allocated for it. */
   F_HAS_FALLBACK	= 0x0002u, /* Has fallback implementation, so include mask bit even if feature not found. */
   F_MANUAL_ZWJ		= 0x0004u, /* Don't skip over ZWJ when matching. */
   F_GLOBAL_SEARCH	= 0x0008u  /* If feature not found in LangSys, look for it in global feature list and pick one. */
 };
-HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
 /* Macro version for where const is desired. */
 #define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r)))
+static inline hb_ot_map_feature_flags_t
+operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
+{ return hb_ot_map_feature_flags_t ((unsigned int) l | (unsigned int) r); }
+static inline hb_ot_map_feature_flags_t
+operator & (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
+{ return hb_ot_map_feature_flags_t ((unsigned int) l & (unsigned int) r); }
+static inline hb_ot_map_feature_flags_t
+operator ~ (hb_ot_map_feature_flags_t r)
+{ return hb_ot_map_feature_flags_t (~(unsigned int) r); }
+static inline hb_ot_map_feature_flags_t&
+operator |= (hb_ot_map_feature_flags_t &l, hb_ot_map_feature_flags_t r)
+{ l = l | r; return l; }
+static inline hb_ot_map_feature_flags_t&
+operator &= (hb_ot_map_feature_flags_t& l, hb_ot_map_feature_flags_t r)
+{ l = l & r; return l; }
 
 
 struct hb_ot_map_builder_t
 {
   public:
 
   HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_,
 				   const hb_segment_properties_t *props_);
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
@@ -23,48 +23,19 @@
  *
  * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-ot-shape-complex-arabic-private.hh"
 #include "hb-ot-shape-private.hh"
 
 
-#ifndef HB_DEBUG_ARABIC
-#define HB_DEBUG_ARABIC (HB_DEBUG+0)
-#endif
-
-
 /* buffer var allocations */
 #define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
 
-#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
-
-/* See:
- * https://github.com/behdad/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
-#define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat) \
-	(FLAG_SAFE (gen_cat) & \
-	 (FLAG (HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED) | \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE) | \
-	  /*FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |*/ \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) | \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | \
-	  /*FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) |*/ \
-	  /*FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) |*/ \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) | \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER) | \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER) | \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL) | \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL) | \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL) | \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL)))
-
 
 /*
  * Joining types:
  */
 
 /*
  * Bits used in the joining tables
  */
@@ -108,32 +79,28 @@ static const hb_tag_t arabic_features[] 
   HB_TAG('m','e','d','i'),
   HB_TAG('m','e','d','2'),
   HB_TAG('i','n','i','t'),
   HB_TAG_NONE
 };
 
 
 /* Same order as the feature array */
-enum arabic_action_t {
+enum {
   ISOL,
   FINA,
   FIN2,
   FIN3,
   MEDI,
   MED2,
   INIT,
 
   NONE,
 
-  ARABIC_NUM_FEATURES = NONE,
-
-  /* We abuse the same byte for other things... */
-  STCH_FIXED,
-  STCH_REPEATING,
+  ARABIC_NUM_FEATURES = NONE
 };
 
 static const struct arabic_state_table_entry {
 	uint8_t prev_action;
 	uint8_t curr_action;
 	uint16_t next_state;
 } arabic_state_table[][NUM_STATE_MACHINE_COLS] =
 {
@@ -168,21 +135,16 @@ nuke_joiners (const hb_ot_shape_plan_t *
 	      hb_buffer_t *buffer);
 
 static void
 arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
 		       hb_font_t *font,
 		       hb_buffer_t *buffer);
 
 static void
-record_stch (const hb_ot_shape_plan_t *plan,
-	     hb_font_t *font,
-	     hb_buffer_t *buffer);
-
-static void
 collect_features_arabic (hb_ot_shape_planner_t *plan)
 {
   hb_ot_map_builder_t *map = &plan->map;
 
   /* We apply features according to the Arabic spec, with pauses
    * in between most.
    *
    * The pause between init/medi/... and rlig is required.  See eg:
@@ -198,19 +160,16 @@ collect_features_arabic (hb_ot_shape_pla
    * rlig and calt.  Otherwise the IranNastaliq's ALLAH ligature won't
    * work.  However, testing shows that rlig and calt are applied
    * together for Mongolian in Uniscribe.  As such, we only add a
    * pause for Arabic, not other scripts.
    */
 
   map->add_gsub_pause (nuke_joiners);
 
-  map->add_global_bool_feature (HB_TAG('s','t','c','h'));
-  map->add_gsub_pause (record_stch);
-
   map->add_global_bool_feature (HB_TAG('c','c','m','p'));
   map->add_global_bool_feature (HB_TAG('l','o','c','l'));
 
   map->add_gsub_pause (NULL);
 
   for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
   {
     bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]);
@@ -244,31 +203,28 @@ struct arabic_shape_plan_t
   ASSERT_POD ();
 
   /* The "+ 1" in the next array is to accommodate for the "NONE" command,
    * which is not an OpenType feature, but this simplifies the code by not
    * having to do a "if (... < NONE) ..." and just rely on the fact that
    * mask_array[NONE] == 0. */
   hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
 
+  bool do_fallback;
   arabic_fallback_plan_t *fallback_plan;
-
-  unsigned int do_fallback : 1;
-  unsigned int has_stch : 1;
 };
 
 void *
 data_create_arabic (const hb_ot_shape_plan_t *plan)
 {
   arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
   if (unlikely (!arabic_plan))
     return NULL;
 
   arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
-  arabic_plan->has_stch = !!plan->map.get_1_mask (HB_TAG ('s','t','c','h'));
   for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
     arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
     arabic_plan->do_fallback = arabic_plan->do_fallback &&
 			       (FEATURE_IS_SYRIAC (arabic_features[i]) ||
 			        plan->map.needs_fallback (arabic_features[i]));
   }
 
   return arabic_plan;
@@ -359,16 +315,18 @@ setup_masks_arabic_plan (const arabic_sh
   arabic_joining (buffer);
   if (script == HB_SCRIPT_MONGOLIAN)
     mongolian_variation_selectors (buffer);
 
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
     info[i].mask |= arabic_plan->mask_array[info[i].arabic_shaping_action()];
+
+  HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
 }
 
 static void
 setup_masks_arabic (const hb_ot_shape_plan_t *plan,
 		    hb_buffer_t              *buffer,
 		    hb_font_t                *font HB_UNUSED)
 {
   const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
@@ -408,213 +366,24 @@ retry:
       arabic_fallback_plan_destroy (fallback_plan);
       goto retry;
     }
   }
 
   arabic_fallback_plan_shape (fallback_plan, font, buffer);
 }
 
-/*
- * Stretch feature: "stch".
- * See example here:
- * https://www.microsoft.com/typography/OpenTypeDev/syriac/intro.htm
- * We implement this in a generic way, such that the Arabic subtending
- * marks can use it as well.
- */
-
-static void
-record_stch (const hb_ot_shape_plan_t *plan,
-	     hb_font_t *font,
-	     hb_buffer_t *buffer)
-{
-  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
-  if (!arabic_plan->has_stch)
-    return;
-
-  /* 'stch' feature was just applied.  Look for anything that multiplied,
-   * and record it for stch treatment later.  Note that rtlm, frac, etc
-   * are applied before stch, but we assume that they didn't result in
-   * anything multiplying into 5 pieces, so it's safe-ish... */
-
-  unsigned int count = buffer->len;
-  hb_glyph_info_t *info = buffer->info;
-  for (unsigned int i = 0; i < count; i++)
-    if (unlikely (_hb_glyph_info_multiplied (&info[i])))
-    {
-      unsigned int comp = _hb_glyph_info_get_lig_comp (&info[i]);
-      info[i].arabic_shaping_action() = comp % 2 ? STCH_REPEATING : STCH_FIXED;
-      buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH;
-    }
-}
-
-static void
-apply_stch (const hb_ot_shape_plan_t *plan,
-	    hb_buffer_t              *buffer,
-	    hb_font_t                *font)
-{
-  if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH)))
-    return;
-
-  /* The Arabic shaper currently always processes in RTL mode, so we should
-   * stretch / position the stretched pieces to the left / preceding glyphs. */
-
-  /* We do a two pass implementation:
-   * First pass calculates the exact number of extra glyphs we need,
-   * We then enlarge buffer to have that much room,
-   * Second pass applies the stretch, copying things to the end of buffer.
-   */
-
-  /* 30 = 2048 / 70.
-   * https://www.microsoft.com/typography/cursivescriptguidelines.mspx */
-  hb_position_t overlap = font->x_scale / 30;
-  DEBUG_MSG (ARABIC, NULL, "overlap for stretching is %d", overlap);
-  int sign = font->x_scale < 0 ? -1 : +1;
-  unsigned int extra_glyphs_needed = 0; // Set during MEASURE, used during CUT
-  typedef enum { MEASURE, CUT } step_t;
-
-  for (step_t step = MEASURE; step <= CUT; step = (step_t) (step + 1))
-  {
-    unsigned int count = buffer->len;
-    hb_glyph_info_t *info = buffer->info;
-    hb_glyph_position_t *pos = buffer->pos;
-    unsigned int new_len = count + extra_glyphs_needed; // write head during CUT
-    unsigned int j = new_len;
-    for (unsigned int i = count; i; i--)
-    {
-      if (!hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
-      {
-        if (step == CUT)
-	{
-	  --j;
-	  info[j] = info[i - 1];
-	  pos[j] = pos[i - 1];
-	}
-        continue;
-      }
-
-      /* Yay, justification! */
-
-      hb_position_t w_total = 0; // Total to be filled
-      hb_position_t w_fixed = 0; // Sum of fixed tiles
-      hb_position_t w_repeating = 0; // Sum of repeating tiles
-      int n_fixed = 0;
-      int n_repeating = 0;
-
-      unsigned int end = i;
-      while (i &&
-	     hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
-      {
-	i--;
-	hb_glyph_extents_t extents;
-	if (!font->get_glyph_extents (info[i].codepoint, &extents))
-	  extents.width = 0;
-	extents.width -= overlap;
-	if (info[i].arabic_shaping_action() == STCH_FIXED)
-	{
-	  w_fixed += extents.width;
-	  n_fixed++;
-	}
-	else
-	{
-	  w_repeating += extents.width;
-	  n_repeating++;
-	}
-      }
-      unsigned int start = i;
-      unsigned int context = i;
-      while (context &&
-	     !hb_in_range<unsigned> (info[context - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING) &&
-	     (_hb_glyph_info_is_default_ignorable (&info[context - 1]) ||
-	      HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_category (&info[context - 1]))))
-      {
-	context--;
-	w_total += pos[context].x_advance;
-      }
-      i++; // Don't touch i again.
-
-      DEBUG_MSG (ARABIC, NULL, "%s stretch at (%d,%d,%d)",
-		 step == MEASURE ? "measuring" : "cutting", context, start, end);
-      DEBUG_MSG (ARABIC, NULL, "rest of word:    count=%d width %d", start - context, w_total);
-      DEBUG_MSG (ARABIC, NULL, "fixed tiles:     count=%d width=%d", n_fixed, w_fixed);
-      DEBUG_MSG (ARABIC, NULL, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
-
-      /* Number of additional times to repeat each repeating tile. */
-      int n_copies = 0;
-
-      hb_position_t w_remaining = w_total - w_fixed - overlap;
-      if (sign * w_remaining > sign * w_repeating && sign * w_repeating > 0)
-	n_copies = (sign * w_remaining + sign * w_repeating / 4) / (sign * w_repeating) - 1;
-
-      if (step == MEASURE)
-      {
-	extra_glyphs_needed += n_copies * n_repeating;
-	DEBUG_MSG (ARABIC, NULL, "will add extra %d copies of repeating tiles", n_copies);
-      }
-      else
-      {
-        hb_position_t x_offset = -overlap;
-	for (unsigned int k = end; k > start; k--)
-	{
-	  hb_glyph_extents_t extents;
-	  if (!font->get_glyph_extents (info[k - 1].codepoint, &extents))
-	    extents.width = 0;
-	  extents.width -= overlap;
-
-	  unsigned int repeat = 1;
-	  if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
-	    repeat += n_copies;
-
-	  DEBUG_MSG (ARABIC, NULL, "appending %d copies of glyph %d; j=%d",
-		     repeat, info[k - 1].codepoint, j);
-	  for (unsigned int n = 0; n < repeat; n++)
-	  {
-	    x_offset -= extents.width;
-	    pos[k - 1].x_offset = x_offset;
-	    /* Append copy. */
-	    --j;
-	    info[j] = info[k - 1];
-	    pos[j] = pos[k - 1];
-	  }
-	}
-      }
-    }
-
-    if (step == MEASURE)
-    {
-      if (unlikely (!buffer->ensure (count + extra_glyphs_needed)))
-        break;
-    }
-    else
-    {
-      assert (j == 0);
-      buffer->len = new_len;
-    }
-  }
-}
-
-
-static void
-postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan,
-			   hb_buffer_t              *buffer,
-			   hb_font_t                *font)
-{
-  apply_stch (plan, buffer, font);
-
-  HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
-}
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
 {
   "arabic",
   collect_features_arabic,
   NULL, /* override_features */
   data_create_arabic,
   data_destroy_arabic,
-  NULL, /* preprocess_text */
-  postprocess_glyphs_arabic,
+  NULL, /* preprocess_text_arabic */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   NULL, /* decompose */
   NULL, /* compose */
   setup_masks_arabic,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
@@ -30,16 +30,15 @@
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
 {
   "default",
   NULL, /* collect_features */
   NULL, /* override_features */
   NULL, /* data_create */
   NULL, /* data_destroy */
   NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   NULL, /* decompose */
   NULL, /* compose */
   NULL, /* setup_masks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
   true, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-hangul.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-hangul.cc
@@ -183,17 +183,17 @@ preprocess_text_hangul (const hb_ot_shap
    */
 
   buffer->clear_output ();
   unsigned int start = 0, end = 0; /* Extent of most recently seen syllable;
 				    * valid only if start < end
 				    */
   unsigned int count = buffer->len;
 
-  for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
+  for (buffer->idx = 0; buffer->idx < count;)
   {
     hb_codepoint_t u = buffer->cur().codepoint;
 
     if (isHangulTone (u))
     {
       /*
        * We could cache the width of the tone marks and the existence of dotted-circle,
        * but the use of the Hangul tone mark characters seems to be rare enough that
@@ -406,19 +406,18 @@ setup_masks_hangul (const hb_ot_shape_pl
 }
 
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
 {
   "hangul",
   collect_features_hangul,
   override_features_hangul,
-  data_create_hangul,
-  data_destroy_hangul,
+  data_create_hangul, /* data_create */
+  data_destroy_hangul, /* data_destroy */
   preprocess_text_hangul,
-  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
   NULL, /* decompose */
   NULL, /* compose */
-  setup_masks_hangul,
+  setup_masks_hangul, /* setup_masks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-hebrew.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-hebrew.cc
@@ -158,16 +158,15 @@ compose_hebrew (const hb_ot_shape_normal
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
 {
   "hebrew",
   NULL, /* collect_features */
   NULL, /* override_features */
   NULL, /* data_create */
   NULL, /* data_destroy */
   NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   NULL, /* decompose */
   compose_hebrew,
   NULL, /* setup_masks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
@@ -751,17 +751,17 @@ initial_reordering_consonant_syllable (c
 	base = start;
 	has_reph = true;
     }
 
     switch (indic_plan->config->base_pos)
     {
       default:
         assert (false);
-	HB_FALLTHROUGH;
+	/* fallthrough */
 
       case BASE_POS_LAST:
       {
 	/* -> starting from the end of the syllable, move backwards */
 	unsigned int i = end;
 	bool seen_below = false;
 	do {
 	  i--;
@@ -1238,37 +1238,37 @@ insert_dotted_circles (const hb_ot_shape
   dottedcircle.codepoint = 0x25CCu;
   set_indic_properties (dottedcircle);
   dottedcircle.codepoint = dottedcircle_glyph;
 
   buffer->clear_output ();
 
   buffer->idx = 0;
   unsigned int last_syllable = 0;
-  while (buffer->idx < buffer->len && !buffer->in_error)
+  while (buffer->idx < buffer->len)
   {
     unsigned int syllable = buffer->cur().syllable();
     syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
     if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
     {
       last_syllable = syllable;
 
-      hb_glyph_info_t ginfo = dottedcircle;
-      ginfo.cluster = buffer->cur().cluster;
-      ginfo.mask = buffer->cur().mask;
-      ginfo.syllable() = buffer->cur().syllable();
+      hb_glyph_info_t info = dottedcircle;
+      info.cluster = buffer->cur().cluster;
+      info.mask = buffer->cur().mask;
+      info.syllable() = buffer->cur().syllable();
       /* TODO Set glyph_props? */
 
       /* Insert dottedcircle after possible Repha. */
       while (buffer->idx < buffer->len &&
 	     last_syllable == buffer->cur().syllable() &&
 	     buffer->cur().indic_category() == OT_Repha)
         buffer->next_glyph ();
 
-      buffer->output_info (ginfo);
+      buffer->output_info (info);
     }
     else
       buffer->next_glyph ();
   }
 
   buffer->swap_buffers ();
 }
 
@@ -1626,18 +1626,18 @@ final_reordering_syllable (const hb_ot_s
 		   !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS)))
 	      new_pos--;
 
 	    /* In Khmer coeng model, a H,Ra can go *after* matras.  If it goes after a
 	     * split matra, it should be reordered to *before* the left part of such matra. */
 	    if (new_pos > start && info[new_pos - 1].indic_category() == OT_M)
 	    {
 	      unsigned int old_pos = i;
-	      for (unsigned int j = base + 1; j < old_pos; j++)
-		if (info[j].indic_category() == OT_M)
+	      for (unsigned int i = base + 1; i < old_pos; i++)
+		if (info[i].indic_category() == OT_M)
 		{
 		  new_pos--;
 		  break;
 		}
 	    }
 	  }
 
 	  if (new_pos > start && is_halant_or_coeng (info[new_pos - 1]))
@@ -1829,16 +1829,15 @@ compose_indic (const hb_ot_shape_normali
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
 {
   "indic",
   collect_features_indic,
   override_features_indic,
   data_create_indic,
   data_destroy_indic,
   NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   decompose_indic,
   compose_indic,
   setup_masks_indic,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
@@ -450,22 +450,22 @@ insert_dotted_circles (const hb_ot_shape
   while (buffer->idx < buffer->len)
   {
     unsigned int syllable = buffer->cur().syllable();
     syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
     if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
     {
       last_syllable = syllable;
 
-      hb_glyph_info_t ginfo = dottedcircle;
-      ginfo.cluster = buffer->cur().cluster;
-      ginfo.mask = buffer->cur().mask;
-      ginfo.syllable() = buffer->cur().syllable();
+      hb_glyph_info_t info = dottedcircle;
+      info.cluster = buffer->cur().cluster;
+      info.mask = buffer->cur().mask;
+      info.syllable() = buffer->cur().syllable();
 
-      buffer->output_info (ginfo);
+      buffer->output_info (info);
     }
     else
       buffer->next_glyph ();
   }
 
   buffer->swap_buffers ();
 }
 
@@ -502,33 +502,31 @@ final_reordering (const hb_ot_shape_plan
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old =
 {
   "default",
   NULL, /* collect_features */
   NULL, /* override_features */
   NULL, /* data_create */
   NULL, /* data_destroy */
   NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   NULL, /* decompose */
   NULL, /* compose */
   NULL, /* setup_masks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
 
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
 {
   "myanmar",
   collect_features_myanmar,
   override_features_myanmar,
   NULL, /* data_create */
   NULL, /* data_destroy */
   NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   NULL, /* decompose */
   NULL, /* compose */
   setup_masks_myanmar,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
   false, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
@@ -105,25 +105,16 @@ struct hb_ot_complex_shaper_t
    * Called during shape().
    * Shapers can use to modify text before shaping starts.
    * May be NULL.
    */
   void (*preprocess_text) (const hb_ot_shape_plan_t *plan,
 			   hb_buffer_t              *buffer,
 			   hb_font_t                *font);
 
-  /* postprocess_glyphs()
-   * Called during shape().
-   * Shapers can use to modify glyphs after shaping ends.
-   * May be NULL.
-   */
-  void (*postprocess_glyphs) (const hb_ot_shape_plan_t *plan,
-			      hb_buffer_t              *buffer,
-			      hb_font_t                *font);
-
 
   hb_ot_shape_normalization_mode_t normalization_preference;
 
   /* decompose()
    * Called during shape()'s normalization.
    * May be NULL.
    */
   bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
@@ -134,17 +134,17 @@ thai_pua_shape (hb_codepoint_t u, thai_a
   };
   static const thai_pua_mapping_t RD_mappings[] = {
     {0x0E0Du, 0xF70Fu, 0xF89Au}, /* YO YING */
     {0x0E10u, 0xF700u, 0xF89Eu}, /* THO THAN */
     {0x0000u, 0x0000u, 0x0000u}
   };
 
   switch (action) {
-    default: assert (false); HB_FALLTHROUGH;
+    default: assert (false); /* Fallthrough */
     case NOP: return u;
     case SD:  pua_mappings = SD_mappings; break;
     case SDL: pua_mappings = SDL_mappings; break;
     case SL:  pua_mappings = SL_mappings; break;
     case RD:  pua_mappings = RD_mappings; break;
   }
   for (; pua_mappings->u; pua_mappings++)
     if (pua_mappings->u == u)
@@ -310,32 +310,32 @@ preprocess_text_thai (const hb_ot_shape_
    * is adequate here. */
 #define IS_SARA_AM(x) (((x) & ~0x0080u) == 0x0E33u)
 #define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0x0E33u + 0x0E4Du)
 #define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
 #define IS_TONE_MARK(x) (hb_in_ranges ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u))
 
   buffer->clear_output ();
   unsigned int count = buffer->len;
-  for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
+  for (buffer->idx = 0; buffer->idx < count;)
   {
     hb_codepoint_t u = buffer->cur().codepoint;
     if (likely (!IS_SARA_AM (u))) {
       buffer->next_glyph ();
       continue;
     }
 
     /* Is SARA AM. Decompose and reorder. */
     hb_codepoint_t decomposed[2] = {hb_codepoint_t (NIKHAHIT_FROM_SARA_AM (u)),
 				    hb_codepoint_t (SARA_AA_FROM_SARA_AM (u))};
     buffer->replace_glyphs (1, 2, decomposed);
     if (unlikely (buffer->in_error))
       return;
 
-    /* Make Nikhahit be recognized as a ccc=0 mark when zeroing widths. */
+    /* Make Nikhahit be recognized as a mark when zeroing widths. */
     unsigned int end = buffer->out_len;
     _hb_glyph_info_set_general_category (&buffer->out_info[end - 2], HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK);
 
     /* Ok, let's see... */
     unsigned int start = end - 2;
     while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
       start--;
 
@@ -367,16 +367,15 @@ preprocess_text_thai (const hb_ot_shape_
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
 {
   "thai",
   NULL, /* collect_features */
   NULL, /* override_features */
   NULL, /* data_create */
   NULL, /* data_destroy */
   preprocess_text_thai,
-  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   NULL, /* decompose */
   NULL, /* compose */
   NULL, /* setup_masks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
   false,/* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-tibetan.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-tibetan.cc
@@ -47,16 +47,15 @@ collect_features_tibetan (hb_ot_shape_pl
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_tibetan =
 {
   "default",
   collect_features_tibetan,
   NULL, /* override_features */
   NULL, /* data_create */
   NULL, /* data_destroy */
   NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
   NULL, /* decompose */
   NULL, /* compose */
   NULL, /* setup_masks */
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
   true, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-use.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-use.cc
@@ -485,46 +485,52 @@ insert_dotted_circles (const hb_ot_shape
     if ((info[i].syllable() & 0x0F) == broken_cluster)
     {
       has_broken_syllables = true;
       break;
     }
   if (likely (!has_broken_syllables))
     return;
 
+
+  hb_codepoint_t dottedcircle_glyph;
+  if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
+    return;
+
   hb_glyph_info_t dottedcircle = {0};
   if (!font->get_glyph (0x25CCu, 0, &dottedcircle.codepoint))
     return;
   dottedcircle.use_category() = hb_use_get_categories (0x25CC);
 
   buffer->clear_output ();
 
   buffer->idx = 0;
+
   unsigned int last_syllable = 0;
-  while (buffer->idx < buffer->len && !buffer->in_error)
+  while (buffer->idx < buffer->len)
   {
     unsigned int syllable = buffer->cur().syllable();
     syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
     if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
     {
       last_syllable = syllable;
 
-      hb_glyph_info_t ginfo = dottedcircle;
-      ginfo.cluster = buffer->cur().cluster;
-      ginfo.mask = buffer->cur().mask;
-      ginfo.syllable() = buffer->cur().syllable();
+      hb_glyph_info_t info = dottedcircle;
+      info.cluster = buffer->cur().cluster;
+      info.mask = buffer->cur().mask;
+      info.syllable() = buffer->cur().syllable();
       /* TODO Set glyph_props? */
 
       /* Insert dottedcircle after possible Repha. */
       while (buffer->idx < buffer->len &&
 	     last_syllable == buffer->cur().syllable() &&
 	     buffer->cur().use_category() == USE_R)
         buffer->next_glyph ();
 
-      buffer->output_info (ginfo);
+      buffer->output_info (info);
     }
     else
       buffer->next_glyph ();
   }
 
   buffer->swap_buffers ();
 }
 
@@ -565,16 +571,15 @@ compose_use (const hb_ot_shape_normalize
 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
 {
   "use",
   collect_features_use,
   NULL, /* override_features */
   data_create_use,
   data_destroy_use,
   NULL, /* preprocess_text */
-  NULL, /* postprocess_glyphs */
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
   NULL, /* decompose */
   compose_use,
   setup_masks_use,
   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
   false, /* fallback_position */
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-fallback-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-fallback-private.hh
@@ -40,14 +40,10 @@ HB_INTERNAL void _hb_ot_shape_fallback_p
 								    hb_font_t *font,
 								    hb_buffer_t  *buffer);
 
 
 HB_INTERNAL void _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
 					     hb_font_t *font,
 					     hb_buffer_t  *buffer);
 
-HB_INTERNAL void _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
-					       hb_font_t *font,
-					       hb_buffer_t  *buffer);
-
 
 #endif /* HB_OT_SHAPE_FALLBACK_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-shape-fallback.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-fallback.cc
@@ -219,17 +219,17 @@ position_mark (const hb_ot_shape_plan_t 
     case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
       if (buffer->props.direction == HB_DIRECTION_LTR) {
 	pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing;
         break;
       } else if (buffer->props.direction == HB_DIRECTION_RTL) {
 	pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
         break;
       }
-      HB_FALLTHROUGH;
+      /* Fall through */
 
     default:
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
     case HB_UNICODE_COMBINING_CLASS_BELOW:
     case HB_UNICODE_COMBINING_CLASS_ABOVE:
       /* Center align. */
       pos.x_offset += base_extents.x_bearing + (base_extents.width - mark_extents.width) / 2 - mark_extents.x_bearing;
@@ -254,17 +254,16 @@ position_mark (const hb_ot_shape_plan_t 
   switch (combining_class)
   {
     case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
     case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
     case HB_UNICODE_COMBINING_CLASS_BELOW:
     case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
       /* Add gap, fall-through. */
       base_extents.height -= y_gap;
-      HB_FALLTHROUGH;
 
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
       pos.y_offset = base_extents.y_bearing + base_extents.height - mark_extents.y_bearing;
       /* Never shift up "below" marks. */
       if ((y_gap > 0) == (pos.y_offset > 0))
       {
 	base_extents.height -= pos.y_offset;
@@ -275,17 +274,16 @@ position_mark (const hb_ot_shape_plan_t 
 
     case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
     case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
     case HB_UNICODE_COMBINING_CLASS_ABOVE:
     case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
       /* Add gap, fall-through. */
       base_extents.y_bearing += y_gap;
       base_extents.height -= y_gap;
-      HB_FALLTHROUGH;
 
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
       pos.y_offset = base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height);
       /* Don't shift down "above" marks too much. */
       if ((y_gap > 0) != (pos.y_offset > 0))
       {
 	unsigned int correction = -pos.y_offset / 2;
@@ -479,75 +477,8 @@ void
       pos[idx].y_advance += kern1;
       pos[skippy_iter.idx].y_advance += kern2;
       pos[skippy_iter.idx].y_offset += kern2;
     }
 
     idx = skippy_iter.idx;
   }
 }
-
-
-/* Adjusts width of various spaces. */
-void
-_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
-			      hb_font_t *font,
-			      hb_buffer_t  *buffer)
-{
-  if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
-    return;
-
-  hb_glyph_info_t *info = buffer->info;
-  hb_glyph_position_t *pos = buffer->pos;
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i]))
-    {
-      hb_unicode_funcs_t::space_t space_type = _hb_glyph_info_get_unicode_space_fallback_type (&info[i]);
-      hb_codepoint_t glyph;
-      typedef hb_unicode_funcs_t t;
-      switch (space_type)
-      {
-	case t::NOT_SPACE: /* Shouldn't happen. */
-	case t::SPACE:
-	  break;
-
-	case t::SPACE_EM:
-	case t::SPACE_EM_2:
-	case t::SPACE_EM_3:
-	case t::SPACE_EM_4:
-	case t::SPACE_EM_5:
-	case t::SPACE_EM_6:
-	case t::SPACE_EM_16:
-	  pos[i].x_advance = (font->x_scale + ((int) space_type)/2) / (int) space_type;
-	  break;
-
-	case t::SPACE_4_EM_18:
-	  pos[i].x_advance = font->x_scale * 4 / 18;
-	  break;
-
-	case t::SPACE_FIGURE:
-	  for (char u = '0'; u <= '9'; u++)
-	    if (font->get_glyph (u, 0, &glyph))
-	    {
-	      pos[i].x_advance = font->get_glyph_h_advance (glyph);
-	      break;
-	    }
-	  break;
-
-	case t::SPACE_PUNCTUATION:
-	  if (font->get_glyph ('.', 0, &glyph))
-	    pos[i].x_advance = font->get_glyph_h_advance (glyph);
-	  else if (font->get_glyph (',', 0, &glyph))
-	    pos[i].x_advance = font->get_glyph_h_advance (glyph);
-	  break;
-
-	case t::SPACE_NARROW:
-	  /* Half-space?
-	   * Unicode doc http://www.unicode.org/charts/PDF/U2000.pdf says ~1/4 or 1/5 of EM.
-	   * However, in my testing, many fonts have their regular space being about that
-	   * size.  To me, a percentage of the space width makes more sense.  Half is as
-	   * good as any. */
-	  pos[i].x_advance /= 2;
-	  break;
-      }
-    }
-}
--- a/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
@@ -57,22 +57,34 @@
  *   - When a font has a precomposed character for a sequence but the 'ccmp'
  *     feature in the font is not adequate, use the precomposed character
  *     which typically has better mark positioning.
  *
  *   - When a font does not support a combining mark, but supports it precomposed
  *     with previous base, use that.  This needs the itemizer to have this
  *     knowledge too.  We need to provide assistance to the itemizer.
  *
- *   - When a font does not support a character but supports its canonical
- *     decomposition, well, use the decomposition.
+ *   - When a font does not support a character but supports its decomposition,
+ *     well, use the decomposition (preferring the canonical decomposition, but
+ *     falling back to the compatibility decomposition if necessary).  The
+ *     compatibility decomposition is really nice to have, for characters like
+ *     ellipsis, or various-sized space characters.
  *
  *   - The complex shapers can customize the compose and decompose functions to
  *     offload some of their requirements to the normalizer.  For example, the
  *     Indic shaper may want to disallow recomposing of two matras.
+ *
+ *   - We try compatibility decomposition if decomposing through canonical
+ *     decomposition alone failed to find a sequence that the font supports.
+ *     We don't try compatibility decomposition recursively during the canonical
+ *     decomposition phase.  This has minimal impact.  There are only a handful
+ *     of Greek letter that have canonical decompositions that include characters
+ *     with compatibility decomposition.  Those can be found using this command:
+ *
+ *     egrep  "`echo -n ';('; grep ';<' UnicodeData.txt | cut -d';' -f1 | tr '\n' '|'; echo ') '`" UnicodeData.txt
  */
 
 static bool
 decompose_unicode (const hb_ot_shape_normalize_context_t *c,
 		   hb_codepoint_t  ab,
 		   hb_codepoint_t *a,
 		   hb_codepoint_t *b)
 {
@@ -93,18 +105,18 @@ set_glyph (hb_glyph_info_t &info, hb_fon
 {
   font->get_glyph (info.codepoint, 0, &info.glyph_index());
 }
 
 static inline void
 output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
 {
   buffer->cur().glyph_index() = glyph;
-  buffer->output_glyph (unichar); /* This is very confusing indeed. */
-  _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer);
+  buffer->output_glyph (unichar);
+  _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode);
 }
 
 static inline void
 next_char (hb_buffer_t *buffer, hb_codepoint_t glyph)
 {
   buffer->cur().glyph_index() = glyph;
   buffer->next_glyph ();
 }
@@ -154,76 +166,65 @@ decompose (const hb_ot_shape_normalize_c
       return 2;
     }
     return 1;
   }
 
   return 0;
 }
 
+/* Returns 0 if didn't decompose, number of resulting characters otherwise. */
+static inline unsigned int
+decompose_compatibility (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t u)
+{
+  unsigned int len, i;
+  hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN];
+  hb_codepoint_t glyphs[HB_UNICODE_MAX_DECOMPOSITION_LEN];
+
+  len = c->buffer->unicode->decompose_compatibility (u, decomposed);
+  if (!len)
+    return 0;
+
+  for (i = 0; i < len; i++)
+    if (!c->font->get_glyph (decomposed[i], 0, &glyphs[i]))
+      return 0;
+
+  for (i = 0; i < len; i++)
+    output_char (c->buffer, decomposed[i], glyphs[i]);
+
+  return len;
+}
+
 static inline void
 decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shortest)
 {
   hb_buffer_t * const buffer = c->buffer;
   hb_codepoint_t u = buffer->cur().codepoint;
   hb_codepoint_t glyph;
 
+  /* Kind of a cute waterfall here... */
   if (shortest && c->font->get_glyph (u, 0, &glyph))
-  {
-    next_char (buffer, glyph);
-    return;
-  }
-
-  if (decompose (c, shortest, u))
-  {
-    skip_char (buffer);
-    return;
-  }
-
-  if (!shortest && c->font->get_glyph (u, 0, &glyph))
-  {
     next_char (buffer, glyph);
-    return;
-  }
-
-  if (_hb_glyph_info_is_unicode_space (&buffer->cur()))
-  {
-    hb_codepoint_t space_glyph;
-    hb_unicode_funcs_t::space_t space_type = buffer->unicode->space_fallback_type (u);
-    if (space_type != hb_unicode_funcs_t::NOT_SPACE && c->font->get_glyph (0x0020u, 0, &space_glyph))
-    {
-      _hb_glyph_info_set_unicode_space_fallback_type (&buffer->cur(), space_type);
-      next_char (buffer, space_glyph);
-      buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK;
-      return;
-    }
-  }
-
-  if (u == 0x2011u)
-  {
-    /* U+2011 is the only sensible character that is a no-break version of another character
-     * and not a space.  The space ones are handled already.  Handle this lone one. */
-    hb_codepoint_t other_glyph;
-    if (c->font->get_glyph (0x2010u, 0, &other_glyph))
-    {
-      next_char (buffer, other_glyph);
-      return;
-    }
-  }
-
-  next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
+  else if (decompose (c, shortest, u))
+    skip_char (buffer);
+  else if (!shortest && c->font->get_glyph (u, 0, &glyph))
+    next_char (buffer, glyph);
+  else if (decompose_compatibility (c, u))
+    skip_char (buffer);
+  else
+    next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
 }
 
 static inline void
 handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
 {
   /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
   hb_buffer_t * const buffer = c->buffer;
   hb_font_t * const font = c->font;
-  for (; buffer->idx < end - 1 && !buffer->in_error;) {
+  for (; buffer->idx < end - 1;) {
     if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
       /* The next two lines are some ugly lines... But work. */
       if (font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
       {
 	buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
       }
       else
       {
@@ -249,23 +250,23 @@ handle_variation_selector_cluster (const
     buffer->next_glyph ();
   }
 }
 
 static inline void
 decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
 {
   hb_buffer_t * const buffer = c->buffer;
-  for (unsigned int i = buffer->idx; i < end && !buffer->in_error; i++)
+  for (unsigned int i = buffer->idx; i < end; i++)
     if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
       handle_variation_selector_cluster (c, end, short_circuit);
       return;
     }
 
-  while (buffer->idx < end && !buffer->in_error)
+  while (buffer->idx < end)
     decompose_current_character (c, short_circuit);
 }
 
 static inline void
 decompose_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool might_short_circuit, bool always_short_circuit)
 {
   if (likely (c->buffer->idx + 1 == end))
     decompose_current_character (c, might_short_circuit);
@@ -315,17 +316,17 @@ void
    * two rounds into the inner loop for the first round, but it's more readable
    * this way. */
 
 
   /* First round, decompose */
 
   buffer->clear_output ();
   count = buffer->len;
-  for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
+  for (buffer->idx = 0; buffer->idx < count;)
   {
     unsigned int end;
     for (end = buffer->idx + 1; end < count; end++)
       if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end]))))
         break;
 
     decompose_cluster (&c, end, might_short_circuit, always_short_circuit);
   }
@@ -365,17 +366,17 @@ void
 
   /* As noted in the comment earlier, we don't try to combine
    * ccc=0 chars with their previous Starter. */
 
   buffer->clear_output ();
   count = buffer->len;
   unsigned int starter = 0;
   buffer->next_glyph ();
-  while (buffer->idx < count && !buffer->in_error)
+  while (buffer->idx < count)
   {
     hb_codepoint_t composed, glyph;
     if (/* We don't try to compose a non-mark character with it's preceding starter.
 	 * This is both an optimization to avoid trying to compose every two neighboring
 	 * glyphs in most scripts AND a desired feature for Hangul.  Apparently Hangul
 	 * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */
 	HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur())) &&
 	/* If there's anything between the starter and this char, they should have CCC
@@ -394,17 +395,17 @@ void
       buffer->next_glyph (); /* Copy to out-buffer. */
       if (unlikely (buffer->in_error))
         return;
       buffer->merge_out_clusters (starter, buffer->out_len);
       buffer->out_len--; /* Remove the second composable. */
       /* Modify starter and carry on. */
       buffer->out_info[starter].codepoint = composed;
       buffer->out_info[starter].glyph_index() = glyph;
-      _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer);
+      _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode);
 
       continue;
     }
 
     /* Blocked, or doesn't compose. */
     buffer->next_glyph ();
 
     if (_hb_glyph_info_get_modified_combining_class (&buffer->prev()) == 0)
--- a/gfx/harfbuzz/src/hb-ot-shape.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape.cc
@@ -223,53 +223,52 @@ struct hb_ot_shape_context_t
 /* Prepare */
 
 static void
 hb_set_unicode_props (hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    _hb_glyph_info_set_unicode_props (&info[i], buffer);
+    _hb_glyph_info_set_unicode_props (&info[i], buffer->unicode);
 }
 
 static void
 hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
 {
   if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
       buffer->context_len[0] ||
       _hb_glyph_info_get_general_category (&buffer->info[0]) !=
       HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
     return;
 
   if (!font->has_glyph (0x25CCu))
     return;
 
   hb_glyph_info_t dottedcircle = {0};
   dottedcircle.codepoint = 0x25CCu;
-  _hb_glyph_info_set_unicode_props (&dottedcircle, buffer);
+  _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode);
 
   buffer->clear_output ();
 
   buffer->idx = 0;
   hb_glyph_info_t info = dottedcircle;
   info.cluster = buffer->cur().cluster;
   info.mask = buffer->cur().mask;
   buffer->output_info (info);
-  while (buffer->idx < buffer->len && !buffer->in_error)
+  while (buffer->idx < buffer->len)
     buffer->next_glyph ();
 
   buffer->swap_buffers ();
 }
 
 static void
 hb_form_clusters (hb_buffer_t *buffer)
 {
-  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
-      buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+  if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
     return;
 
   /* Loop duplicated in hb_ensure_native_direction(). */
   unsigned int base = 0;
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 1; i < count; i++)
   {
@@ -342,18 +341,17 @@ hb_ot_mirror_chars (hb_ot_shape_context_
     else
       info[i].codepoint = codepoint;
   }
 }
 
 static inline void
 hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
 {
-  if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
-      !c->plan->has_frac)
+  if (!c->plan->has_frac)
     return;
 
   hb_buffer_t *buffer = c->buffer;
 
   /* TODO look in pre/post context text also. */
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
@@ -413,36 +411,34 @@ hb_ot_shape_setup_masks (hb_ot_shape_con
   }
 }
 
 static void
 hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c)
 {
   hb_buffer_t *buffer = c->buffer;
 
-  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
-      (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
+  if (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
     return;
 
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   hb_glyph_position_t *pos = buffer->pos;
   unsigned int i = 0;
   for (i = 0; i < count; i++)
     if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
       pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
 }
 
 static void
 hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
 {
   hb_buffer_t *buffer = c->buffer;
 
-  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
-      (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
+  if (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
     return;
 
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   hb_glyph_position_t *pos = buffer->pos;
   unsigned int i = 0;
   for (i = 0; i < count; i++)
   {
@@ -524,17 +520,17 @@ hb_ot_map_glyphs_fast (hb_buffer_t  *buf
 
 static inline void
 hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
 {
   unsigned int count = c->buffer->len;
   hb_glyph_info_t *info = c->buffer->info;
   for (unsigned int i = 0; i < count; i++)
   {
-    hb_ot_layout_glyph_props_flags_t klass;
+    hb_ot_layout_glyph_class_mask_t klass;
 
     /* Never mark default-ignorables as marks.
      * They won't get in the way of lookups anyway,
      * but having them as mark will cause them to be skipped
      * over if the lookup-flag says so, but at least for the
      * Mongolian variation selectors, looks like Uniscribe
      * marks them as non-mark.  Some Mongolian fonts without
      * GDEF rely on this.  Another notable character that
@@ -548,16 +544,19 @@ hb_synthesize_glyph_classes (hb_ot_shape
   }
 }
 
 static inline void
 hb_ot_substitute_default (hb_ot_shape_context_t *c)
 {
   hb_buffer_t *buffer = c->buffer;
 
+  if (c->plan->shaper->preprocess_text)
+    c->plan->shaper->preprocess_text (c->plan, buffer, c->font);
+
   hb_ot_shape_initialize_masks (c);
 
   hb_ot_mirror_chars (c);
 
   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
 
   _hb_ot_shape_normalize (c->plan, buffer, c->font);
 
@@ -572,35 +571,33 @@ hb_ot_substitute_default (hb_ot_shape_co
   HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
 }
 
 static inline void
 hb_ot_substitute_complex (hb_ot_shape_context_t *c)
 {
   hb_buffer_t *buffer = c->buffer;
 
+  _hb_buffer_allocate_gsubgpos_vars (buffer);
   hb_ot_layout_substitute_start (c->font, buffer);
 
   if (!hb_ot_layout_has_glyph_classes (c->face))
     hb_synthesize_glyph_classes (c);
 
   c->plan->substitute (c->font, buffer);
 
   hb_ot_layout_substitute_finish (c->font, buffer);
 
   return;
 }
 
 static inline void
 hb_ot_substitute (hb_ot_shape_context_t *c)
 {
   hb_ot_substitute_default (c);
-
-  _hb_buffer_allocate_gsubgpos_vars (c->buffer);
-
   hb_ot_substitute_complex (c);
 }
 
 /* Position */
 
 static inline void
 adjust_mark_offsets (hb_glyph_position_t *pos)
 {
@@ -613,37 +610,30 @@ zero_mark_width (hb_glyph_position_t *po
 {
   pos->x_advance = 0;
   pos->y_advance = 0;
 }
 
 static inline void
 zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets)
 {
-  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
-    return;
-
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
     if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
     {
       if (adjust_offsets)
         adjust_mark_offsets (&buffer->pos[i]);
       zero_mark_width (&buffer->pos[i]);
     }
 }
 
 static inline void
 zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
 {
-  /* This one is a hack; Technically GDEF can mark ASCII glyphs as marks, but we don't listen. */
-  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
-    return;
-
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
     if (_hb_glyph_info_is_mark (&info[i]))
     {
       if (adjust_offsets)
         adjust_mark_offsets (&buffer->pos[i]);
       zero_mark_width (&buffer->pos[i]);
@@ -652,39 +642,28 @@ zero_mark_widths_by_gdef (hb_buffer_t *b
 
 static inline void
 hb_ot_position_default (hb_ot_shape_context_t *c)
 {
   hb_direction_t direction = c->buffer->props.direction;
   unsigned int count = c->buffer->len;
   hb_glyph_info_t *info = c->buffer->info;
   hb_glyph_position_t *pos = c->buffer->pos;
-
-  if (HB_DIRECTION_IS_HORIZONTAL (direction))
+  for (unsigned int i = 0; i < count; i++)
   {
-    for (unsigned int i = 0; i < count; i++)
-      pos[i].x_advance = c->font->get_glyph_h_advance (info[i].codepoint);
-    if (c->font->has_glyph_h_origin_func ())
-      for (unsigned int i = 0; i < count; i++)
-	c->font->subtract_glyph_h_origin (info[i].codepoint,
-					  &pos[i].x_offset,
-					  &pos[i].y_offset);
+    c->font->get_glyph_advance_for_direction (info[i].codepoint,
+					      direction,
+					      &pos[i].x_advance,
+					      &pos[i].y_advance);
+    c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
+						  direction,
+						  &pos[i].x_offset,
+						  &pos[i].y_offset);
+
   }
-  else
-  {
-    for (unsigned int i = 0; i < count; i++)
-      pos[i].y_advance = c->font->get_glyph_v_advance (info[i].codepoint);
-    if (c->font->has_glyph_v_origin_func ())
-      for (unsigned int i = 0; i < count; i++)
-	c->font->subtract_glyph_v_origin (info[i].codepoint,
-					  &pos[i].x_offset,
-					  &pos[i].y_offset);
-  }
-  if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK)
-    _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer);
 }
 
 static inline bool
 hb_ot_position_complex (hb_ot_shape_context_t *c)
 {
   bool ret = false;
   unsigned int count = c->buffer->len;
   bool has_positioning = hb_ot_layout_has_positioning (c->face);
@@ -719,31 +698,33 @@ hb_ot_position_complex (hb_ot_shape_cont
       break;
   }
 
   if (has_positioning)
   {
     hb_glyph_info_t *info = c->buffer->info;
     hb_glyph_position_t *pos = c->buffer->pos;
 
-    /* Change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
+    /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
 
-    if (c->font->has_glyph_h_origin_func ())
-      for (unsigned int i = 0; i < count; i++)
-	c->font->add_glyph_h_origin (info[i].codepoint,
-				     &pos[i].x_offset,
-				     &pos[i].y_offset);
+    for (unsigned int i = 0; i < count; i++) {
+      c->font->add_glyph_origin_for_direction (info[i].codepoint,
+					       HB_DIRECTION_LTR,
+					       &pos[i].x_offset,
+					       &pos[i].y_offset);
+    }
 
     c->plan->position (c->font, c->buffer);
 
-    if (c->font->has_glyph_h_origin_func ())
-      for (unsigned int i = 0; i < count; i++)
-	c->font->subtract_glyph_h_origin (info[i].codepoint,
-					  &pos[i].x_offset,
-					  &pos[i].y_offset);
+    for (unsigned int i = 0; i < count; i++) {
+      c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
+						    HB_DIRECTION_LTR,
+						    &pos[i].x_offset,
+						    &pos[i].y_offset);
+    }
 
     ret = true;
   }
 
   switch (c->plan->shaper->zero_width_marks)
   {
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
       zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
@@ -792,52 +773,39 @@ hb_ot_position (hb_ot_shape_context_t *c
 
 
 /* Pull it all together! */
 
 static void
 hb_ot_shape_internal (hb_ot_shape_context_t *c)
 {
   c->buffer->deallocate_var_all ();
-  c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
-  if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_EXPANSION_FACTOR)))
-  {
-    c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_EXPANSION_FACTOR,
-			      (unsigned) HB_BUFFER_MAX_LEN_MIN);
-  }
 
   /* Save the original direction, we use it later. */
   c->target_direction = c->buffer->props.direction;
 
   _hb_buffer_allocate_unicode_vars (c->buffer);
 
   c->buffer->clear_output ();
 
   hb_set_unicode_props (c->buffer);
   hb_insert_dotted_circle (c->buffer, c->font);
   hb_form_clusters (c->buffer);
 
   hb_ensure_native_direction (c->buffer);
 
-  if (c->plan->shaper->preprocess_text)
-    c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
-
   hb_ot_substitute (c);
   hb_ot_position (c);
 
   hb_ot_hide_default_ignorables (c);
 
-  if (c->plan->shaper->postprocess_glyphs)
-    c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
-
   _hb_buffer_deallocate_unicode_vars (c->buffer);
 
   c->buffer->props.direction = c->target_direction;
 
-  c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
   c->buffer->deallocate_var_all ();
 }
 
 
 hb_bool_t
 _hb_ot_shape (hb_shape_plan_t    *shape_plan,
 	      hb_font_t          *font,
 	      hb_buffer_t        *buffer,
--- a/gfx/harfbuzz/src/hb-private.hh
+++ b/gfx/harfbuzz/src/hb-private.hh
@@ -114,46 +114,16 @@ extern "C" void  hb_free_impl(void *ptr)
 #if __GNUC__ >= 3
 #define HB_FUNC __PRETTY_FUNCTION__
 #elif defined(_MSC_VER)
 #define HB_FUNC __FUNCSIG__
 #else
 #define HB_FUNC __func__
 #endif
 
-/*
- * Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411
- * HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch
- * cases that fall through without a break or return statement. HB_FALLTHROUGH
- * is only needed on cases that have code:
- *
- * switch (foo) {
- *   case 1: // These cases have no code. No fallthrough annotations are needed.
- *   case 2:
- *   case 3:
- *     foo = 4; // This case has code, so a fallthrough annotation is needed:
- *     HB_FALLTHROUGH;
- *   default:
- *     return foo;
- * }
- */
-#if defined(__clang__) && __cplusplus >= 201103L
-   /* clang's fallthrough annotations are only available starting in C++11. */
-#  define HB_FALLTHROUGH [[clang::fallthrough]]
-#elif defined(_MSC_VER)
-   /*
-    * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):
-    * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx
-    */
-#  include <sal.h>
-#  define HB_FALLTHROUGH __fallthrough
-#else
-#  define HB_FALLTHROUGH /* FALLTHROUGH */
-#endif
-
 #if defined(_WIN32) || defined(__CYGWIN__)
    /* We need Windows Vista for both Uniscribe backend and for
     * MemoryBarrier.  We don't support compiling on Windows XP,
     * though we run on it fine. */
 #  if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
 #    undef _WIN32_WINNT
 #  endif
 #  ifndef _WIN32_WINNT
@@ -235,19 +205,19 @@ static inline unsigned int ARRAY_LENGTH 
 
 #define HB_STMT_START do
 #define HB_STMT_END   while (0)
 
 #define _ASSERT_STATIC1(_line, _cond)	HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
 #define _ASSERT_STATIC0(_line, _cond)	_ASSERT_STATIC1 (_line, (_cond))
 #define ASSERT_STATIC(_cond)		_ASSERT_STATIC0 (__LINE__, (_cond))
 
-template <unsigned int cond> class hb_assert_constant_t {};
-
-#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>))
+/* Note: C++ allows sizeof() of variable-lengh arrays.  So, if _cond is not
+ * constant, it still compiles (ouch!), but at least we'll get a -Wvla warning. */
+#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * sizeof (char[(_cond) ? 1 : -1]))
 
 #define _PASTE1(a,b) a##b
 #define PASTE(a,b) _PASTE1(a,b)
 
 /* Lets assert int types.  Saves trouble down the road. */
 
 ASSERT_STATIC (sizeof (int8_t) == 1);
 ASSERT_STATIC (sizeof (uint8_t) == 1);
@@ -886,44 +856,16 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, 
 
 template <typename T> static inline bool
 hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
 {
   return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
 }
 
 
-/* Enable bitwise ops on enums marked as flags_t */
-/* To my surprise, looks like the function resolver is happy to silently cast
- * one enum to another...  So this doesn't provide the type-checking that I
- * originally had in mind... :(.
- *
- * On MSVC use DEFINE_ENUM_FLAG_OPERATORS.  See:
- * https://github.com/behdad/harfbuzz/pull/163
- */
-#ifdef _MSC_VER
-# pragma warning(disable:4200)
-# pragma warning(disable:4800)
-# define HB_MARK_AS_FLAG_T(flags_t)	DEFINE_ENUM_FLAG_OPERATORS (##flags_t##);
-#else
-# define HB_MARK_AS_FLAG_T(flags_t)	template <> class hb_mark_as_flags_t<flags_t> {};
-template <class T> class hb_mark_as_flags_t;
-template <class T> static inline T operator | (T l, T r)
-{ hb_mark_as_flags_t<T> unused HB_UNUSED; return T ((unsigned int) l | (unsigned int) r); }
-template <class T> static inline T operator & (T l, T r)
-{ hb_mark_as_flags_t<T> unused HB_UNUSED; return T ((unsigned int) l & (unsigned int) r); }
-template <class T> static inline T operator ~ (T r)
-{ hb_mark_as_flags_t<T> unused HB_UNUSED; return T (~(unsigned int) r); }
-template <class T> static inline T& operator |= (T &l, T r)
-{ hb_mark_as_flags_t<T> unused HB_UNUSED; l = l | r; return l; }
-template <class T> static inline T& operator &= (T& l, T r)
-{ hb_mark_as_flags_t<T> unused HB_UNUSED; l = l & r; return l; }
-#endif
-
-
 /* Useful for set-operations on small enums.
  * For example, for testing "x ∈ {x1, x2, x3}" use:
  * (FLAG_SAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
  */
 #define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((x) < 32) + (1U << (x)))
 #define FLAG_SAFE(x) (1U << (x))
 #define FLAG_UNSAFE(x) ((x) < 32 ? FLAG_SAFE(x) : 0)
 #define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
--- a/gfx/harfbuzz/src/hb-unicode-private.hh
+++ b/gfx/harfbuzz/src/hb-unicode-private.hh
@@ -194,60 +194,16 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIM
 	case 0x01: return hb_in_ranges (ch, 0x1BCA0u, 0x1BCA3u,
 					    0x1D173u, 0x1D17Au);
 	case 0x0E: return hb_in_range (ch, 0xE0000u, 0xE0FFFu);
 	default: return false;
       }
     }
   }
 
-  /* Space estimates based on:
-   * http://www.unicode.org/charts/PDF/U2000.pdf
-   * https://www.microsoft.com/typography/developers/fdsspec/spaces.aspx
-   */
-  enum space_t {
-    NOT_SPACE = 0,
-    SPACE_EM   = 1,
-    SPACE_EM_2 = 2,
-    SPACE_EM_3 = 3,
-    SPACE_EM_4 = 4,
-    SPACE_EM_5 = 5,
-    SPACE_EM_6 = 6,
-    SPACE_EM_16 = 16,
-    SPACE_4_EM_18,	/* 4/18th of an EM! */
-    SPACE,
-    SPACE_FIGURE,
-    SPACE_PUNCTUATION,
-    SPACE_NARROW,
-  };
-  static inline space_t
-  space_fallback_type (hb_codepoint_t u)
-  {
-    switch (u)
-    {
-      /* All GC=Zs chars that can use a fallback. */
-      default:	    return NOT_SPACE;	/* Shouldn't happen. */
-      case 0x0020u: return SPACE;	/* U+0020 SPACE */
-      case 0x00A0u: return SPACE;	/* U+00A0 NO-BREAK SPACE */
-      case 0x2000u: return SPACE_EM_2;	/* U+2000 EN QUAD */
-      case 0x2001u: return SPACE_EM;	/* U+2001 EM QUAD */
-      case 0x2002u: return SPACE_EM_2;	/* U+2002 EN SPACE */
-      case 0x2003u: return SPACE_EM;	/* U+2003 EM SPACE */
-      case 0x2004u: return SPACE_EM_3;	/* U+2004 THREE-PER-EM SPACE */
-      case 0x2005u: return SPACE_EM_4;	/* U+2005 FOUR-PER-EM SPACE */
-      case 0x2006u: return SPACE_EM_6;	/* U+2006 SIX-PER-EM SPACE */
-      case 0x2007u: return SPACE_FIGURE;	/* U+2007 FIGURE SPACE */
-      case 0x2008u: return SPACE_PUNCTUATION;	/* U+2008 PUNCTUATION SPACE */
-      case 0x2009u: return SPACE_EM_5;		/* U+2009 THIN SPACE */
-      case 0x200Au: return SPACE_EM_16;		/* U+200A HAIR SPACE */
-      case 0x202Fu: return SPACE_NARROW;	/* U+202F NARROW NO-BREAK SPACE */
-      case 0x205Fu: return SPACE_4_EM_18;	/* U+205F MEDIUM MATHEMATICAL SPACE */
-      case 0x3000u: return SPACE_EM;		/* U+3000 IDEOGRAPHIC SPACE */
-    }
-  }
 
   struct {
 #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_func_t name;
     HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
   } func;
 
   struct {
@@ -352,14 +308,10 @@ extern HB_INTERNAL const hb_unicode_func
 /* Misc */
 
 #define HB_UNICODE_GENERAL_CATEGORY_IS_MARK(gen_cat) \
 	(FLAG_SAFE (gen_cat) & \
 	 (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
 
-#define HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK(gen_cat) \
-	(FLAG_SAFE (gen_cat) & \
-	 (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
 
 #endif /* HB_UNICODE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-utf-private.hh
+++ b/gfx/harfbuzz/src/hb-utf-private.hh
@@ -141,21 +141,21 @@ struct hb_utf16_t
     hb_codepoint_t c = *text++;
 
     if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
     {
       *unicode = c;
       return text;
     }
 
-    if (likely (c <= 0xDBFFu && text < end))
+    if (likely (hb_in_range (c, 0xD800u, 0xDBFFu)))
     {
       /* High-surrogate in c */
-      hb_codepoint_t l = *text;
-      if (likely (hb_in_range (l, 0xDC00u, 0xDFFFu)))
+      hb_codepoint_t l;
+      if (text < end && ((l = *text), likely (hb_in_range (l, 0xDC00u, 0xDFFFu))))
       {
 	/* Low-surrogate in l */
 	*unicode = (c << 10) + l - ((0xD800u << 10) - 0x10000u + 0xDC00u);
 	 text++;
 	 return text;
       }
     }
 
@@ -165,40 +165,33 @@ struct hb_utf16_t
   }
 
   static inline const uint16_t *
   prev (const uint16_t *text,
 	const uint16_t *start,
 	hb_codepoint_t *unicode,
 	hb_codepoint_t replacement)
   {
-    hb_codepoint_t c = *--text;
+    const uint16_t *end = text--;
+    hb_codepoint_t c = *text;
 
     if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
     {
       *unicode = c;
       return text;
     }
 
-    if (likely (c >= 0xDC00u && start < text))
-    {
-      /* Low-surrogate in c */
-      hb_codepoint_t h = text[-1];
-      if (likely (hb_in_range (h, 0xD800u, 0xDBFFu)))
-      {
-        /* High-surrogate in h */
-        *unicode = (h << 10) + c - ((0xD800u << 10) - 0x10000u + 0xDC00u);
-        text--;
-        return text;
-      }
-    }
+    if (likely (start < text && hb_in_range (c, 0xDC00u, 0xDFFFu)))
+      text--;
 
-    /* Lonely / out-of-order surrogate. */
+    if (likely (next (text, end, unicode, replacement) == end))
+      return text;
+
     *unicode = replacement;
-    return text;
+    return end - 1;
   }
 
 
   static inline unsigned int
   strlen (const uint16_t *text)
   {
     unsigned int l = 0;
     while (*text++) l++;
@@ -213,32 +206,35 @@ struct hb_utf32_t
   typedef uint32_t codepoint_t;
 
   static inline const uint32_t *
   next (const uint32_t *text,
 	const uint32_t *end HB_UNUSED,
 	hb_codepoint_t *unicode,
 	hb_codepoint_t replacement)
   {
-    hb_codepoint_t c = *unicode = *text++;
-    if (validate && unlikely (c >= 0xD800u && (c <= 0xDFFFu || c > 0x10FFFFu)))
-      *unicode = replacement;
+    hb_codepoint_t c = *text++;
+    if (validate && unlikely (c > 0x10FFFFu || hb_in_range (c, 0xD800u, 0xDFFFu)))
+      goto error;
+    *unicode = c;
+    return text;
+
+  error:
+    *unicode = replacement;
     return text;
   }
 
   static inline const uint32_t *
   prev (const uint32_t *text,
 	const uint32_t *start HB_UNUSED,
 	hb_codepoint_t *unicode,
 	hb_codepoint_t replacement)
   {
-    hb_codepoint_t c = *unicode = *--text;
-    if (validate && unlikely (c >= 0xD800u && (c <= 0xDFFFu || c > 0x10FFFFu)))
-      *unicode = replacement;
-    return text;
+    next (text - 1, text, unicode, replacement);
+    return text - 1;
   }
 
   static inline unsigned int
   strlen (const uint32_t *text)
   {
     unsigned int l = 0;
     while (*text++) l++;
     return l;
--- a/gfx/harfbuzz/src/hb-version.h
+++ b/gfx/harfbuzz/src/hb-version.h
@@ -32,20 +32,20 @@
 #define HB_VERSION_H
 
 #include "hb-common.h"
 
 HB_BEGIN_DECLS
 
 
 #define HB_VERSION_MAJOR 1
-#define HB_VERSION_MINOR 1
-#define HB_VERSION_MICRO 0
+#define HB_VERSION_MINOR 0
+#define HB_VERSION_MICRO 6
 
-#define HB_VERSION_STRING "1.1.0"
+#define HB_VERSION_STRING "1.0.6"
 
 #define HB_VERSION_ATLEAST(major,minor,micro) \
 	((major)*10000+(minor)*100+(micro) <= \
 	 HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
 
 
 void
 hb_version (unsigned int *major,