bug 801410 - update harfbuzz to release 0.9.6 plus recent commits (to upstream 977f1740..c2ec7c74). r=jdaggett,joe
authorJonathan Kew <jkew@mozilla.com>
Mon, 19 Nov 2012 09:35:39 +0000
changeset 113649 be3a0b4edebdbf2cf4c3c089671f0189bc53c6c9
parent 113648 4fddb9923ef08fbd94ed76c950f49eb6125ff9ec
child 113670 258292c9c929ed3fff61a8c478305977a18ef627
child 127081 338cb56257d0ea1272f430c703ef7cf1fc9903d6
push id23883
push userjkew@mozilla.com
push dateMon, 19 Nov 2012 09:39:43 +0000
treeherdermozilla-central@be3a0b4edebd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett, joe
bugs801410
milestone19.0a1
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
bug 801410 - update harfbuzz to release 0.9.6 plus recent commits (to upstream 977f1740..c2ec7c74). r=jdaggett,joe
gfx/harfbuzz/src/Makefile.am
gfx/harfbuzz/src/Makefile.in
gfx/harfbuzz/src/hb-buffer-private.hh
gfx/harfbuzz/src/hb-buffer.cc
gfx/harfbuzz/src/hb-buffer.h
gfx/harfbuzz/src/hb-fallback-shape.cc
gfx/harfbuzz/src/hb-font-private.hh
gfx/harfbuzz/src/hb-font.cc
gfx/harfbuzz/src/hb-font.h
gfx/harfbuzz/src/hb-ft.cc
gfx/harfbuzz/src/hb-icu-le.cc
gfx/harfbuzz/src/hb-open-type-private.hh
gfx/harfbuzz/src/hb-ot-head-table.hh
gfx/harfbuzz/src/hb-ot-layout-common-private.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-layout.h
gfx/harfbuzz/src/hb-ot-map-private.hh
gfx/harfbuzz/src/hb-ot-map.cc
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-indic-machine.hh
gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.rl
gfx/harfbuzz/src/hb-ot-shape-complex-indic-private.hh
gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
gfx/harfbuzz/src/hb-ot-shape-complex-misc.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-fallback.cc
gfx/harfbuzz/src/hb-ot-shape-normalize-private.hh
gfx/harfbuzz/src/hb-ot-shape-normalize.cc
gfx/harfbuzz/src/hb-ot-shape-private.hh
gfx/harfbuzz/src/hb-ot-shape.cc
gfx/harfbuzz/src/hb-ot-tag.cc
gfx/harfbuzz/src/hb-ot.h
gfx/harfbuzz/src/hb-set-private.hh
gfx/harfbuzz/src/hb-set.cc
gfx/harfbuzz/src/hb-set.h
gfx/harfbuzz/src/hb-shape-plan-private.hh
gfx/harfbuzz/src/hb-shape-plan.cc
gfx/harfbuzz/src/hb-shape-plan.h
gfx/harfbuzz/src/hb-shape.cc
gfx/harfbuzz/src/hb-shaper-list.hh
gfx/harfbuzz/src/hb-shaper-private.hh
gfx/harfbuzz/src/hb-shaper.cc
gfx/harfbuzz/src/hb-unicode-private.hh
gfx/harfbuzz/src/hb-utf-private.hh
gfx/harfbuzz/src/hb-version.h
gfx/harfbuzz/src/hb.h
gfx/harfbuzz/src/test-would-substitute.cc
--- a/gfx/harfbuzz/src/Makefile.am
+++ b/gfx/harfbuzz/src/Makefile.am
@@ -38,17 +38,16 @@ HBSOURCES =  \
 	hb-ot-name-table.hh \
 	hb-ot-tag.cc \
 	hb-private.hh \
 	hb-set-private.hh \
 	hb-set.cc \
 	hb-shape.cc \
 	hb-shape-plan-private.hh \
 	hb-shape-plan.cc \
-	hb-shape-plan.h \
 	hb-shaper-list.hh \
 	hb-shaper-impl-private.hh \
 	hb-shaper-private.hh \
 	hb-shaper.cc \
 	hb-tt-font.cc \
 	hb-unicode-private.hh \
 	hb-unicode.cc \
 	hb-utf-private.hh \
@@ -57,16 +56,17 @@ HBSOURCES =  \
 HBHEADERS = \
 	hb.h \
 	hb-blob.h \
 	hb-buffer.h \
 	hb-common.h \
 	hb-font.h \
 	hb-set.h \
 	hb-shape.h \
+	hb-shape-plan.h \
 	hb-unicode.h \
 	hb-version.h \
 	$(NULL)
 
 if HAVE_OT
 HBSOURCES += \
 	hb-ot-layout.cc \
 	hb-ot-layout-common-private.hh \
@@ -76,21 +76,22 @@ HBSOURCES += \
 	hb-ot-layout-gsub-table.hh \
 	hb-ot-layout-private.hh \
 	hb-ot-map.cc \
 	hb-ot-map-private.hh \
 	hb-ot-shape.cc \
 	hb-ot-shape-complex-arabic.cc \
 	hb-ot-shape-complex-arabic-fallback.hh \
 	hb-ot-shape-complex-arabic-table.hh \
+	hb-ot-shape-complex-default.cc \
 	hb-ot-shape-complex-indic.cc \
 	hb-ot-shape-complex-indic-machine.hh \
 	hb-ot-shape-complex-indic-private.hh \
 	hb-ot-shape-complex-indic-table.hh \
-	hb-ot-shape-complex-misc.cc \
+	hb-ot-shape-complex-thai.cc \
 	hb-ot-shape-complex-private.hh \
 	hb-ot-shape-normalize-private.hh \
 	hb-ot-shape-normalize.cc \
 	hb-ot-shape-fallback-private.hh \
 	hb-ot-shape-fallback.cc \
 	hb-ot-shape-private.hh \
 	$(NULL)
 HBHEADERS += \
@@ -237,17 +238,17 @@ arabic-table: gen-arabic-table.py Arabic
 	$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-arabic-table.hh.tmp && \
 	mv hb-ot-shape-complex-arabic-table.hh.tmp $(srcdir)/hb-ot-shape-complex-arabic-table.hh || \
 	($(RM) hb-ot-shape-complex-arabic-table.hh.tmp; false)
 
 
 .PHONY: unicode-tables arabic-table indic-table
 
 EXTRA_DIST += hb-ot-shape-complex-indic-machine.rl
-hb-ot-shape-complex-indic-machine.hh: hb-ot-shape-complex-indic-machine.rl
+$(srcdir)/hb-ot-shape-complex-indic-machine.hh: hb-ot-shape-complex-indic-machine.rl
 	$(AM_V_GEN)$(top_srcdir)/missing --run ragel -e -F1 -o "$@.tmp" "$<" && \
 	mv "$@.tmp" "$@" || ( $(RM) "$@.tmp" && false )
 
 noinst_PROGRAMS = main test-would-substitute
 bin_PROGRAMS =
 
 main_SOURCES = main.cc
 main_CPPFLAGS = $(HBCFLAGS)
--- a/gfx/harfbuzz/src/Makefile.in
+++ b/gfx/harfbuzz/src/Makefile.in
@@ -42,18 +42,19 @@ CPPSRCS	=                        \
   hb-blob.cc                     \
   hb-buffer.cc                   \
   hb-common.cc                   \
   hb-fallback-shape.cc           \
   hb-font.cc                     \
   hb-ot-layout.cc                \
   hb-ot-map.cc                   \
   hb-ot-shape-complex-arabic.cc  \
+  hb-ot-shape-complex-default.cc \
   hb-ot-shape-complex-indic.cc   \
-  hb-ot-shape-complex-misc.cc    \
+  hb-ot-shape-complex-thai.cc    \
   hb-ot-shape-fallback.cc        \
   hb-ot-shape-normalize.cc       \
   hb-ot-shape.cc                 \
   hb-ot-tag.cc                   \
   hb-set.cc                      \
   hb-shape.cc                    \
   hb-shape-plan.cc               \
   hb-shaper.cc                   \
--- a/gfx/harfbuzz/src/hb-buffer-private.hh
+++ b/gfx/harfbuzz/src/hb-buffer-private.hh
@@ -31,69 +31,33 @@
 #define HB_BUFFER_PRIVATE_HH
 
 #include "hb-private.hh"
 #include "hb-buffer.h"
 #include "hb-object-private.hh"
 #include "hb-unicode-private.hh"
 
 
-
 ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
 ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
 
 
 /*
- * hb_segment_properties_t
- */
-
-typedef struct hb_segment_properties_t {
-    hb_direction_t      direction;
-    hb_script_t         script;
-    hb_language_t       language;
-    ASSERT_POD ();
-} hb_segment_properties_t;
-
-#define _HB_BUFFER_PROPS_DEFAULT { HB_DIRECTION_INVALID, HB_SCRIPT_INVALID, HB_LANGUAGE_INVALID }
-
-static inline hb_bool_t
-hb_segment_properties_equal (const hb_segment_properties_t *a,
-			     const hb_segment_properties_t *b)
-{
-  return a->direction == b->direction &&
-	 a->script    == b->script    &&
-	 a->language  == b->language;
-}
-
-
-#if 0
-static inline unsigned int
-hb_segment_properties_hash (const hb_segment_properties_t *p)
-{
-  /* TODO improve */
-  return (unsigned int) p->direction +
-	 (unsigned int) p->script +
-	 (intptr_t) (p->language);
-}
-#endif
-
-
-
-/*
  * 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_segment_properties_t props; /* Script, language, direction */
+  hb_buffer_flags_t flags; /* BOT / EOT / etc. */
 
   /* Buffer contents */
 
   hb_buffer_content_type_t content_type;
 
   bool in_error; /* Allocation failed */
   bool have_output; /* Whether we have an output buffer going on */
   bool have_positions; /* Whether we have positions */
@@ -128,36 +92,37 @@ struct hb_buffer_t {
   static const unsigned int CONTEXT_LENGTH = 5;
   hb_codepoint_t context[2][CONTEXT_LENGTH];
   unsigned int context_len[2];
 
 
   /* Methods */
 
   HB_INTERNAL void reset (void);
+  HB_INTERNAL void clear (void);
 
   inline unsigned int backtrack_len (void) const
   { return have_output? out_len : idx; }
   inline unsigned int next_serial (void) { return serial++; }
 
   HB_INTERNAL void allocate_var (unsigned int byte_i, unsigned int count, const char *owner);
   HB_INTERNAL void deallocate_var (unsigned int byte_i, unsigned int count, const char *owner);
   HB_INTERNAL void assert_var (unsigned int byte_i, unsigned int count, const char *owner);
   HB_INTERNAL void deallocate_var_all (void);
 
   HB_INTERNAL void add (hb_codepoint_t  codepoint,
-			hb_mask_t       mask,
 			unsigned int    cluster);
 
   HB_INTERNAL void reverse_range (unsigned int start, unsigned int end);
   HB_INTERNAL void reverse (void);
   HB_INTERNAL void reverse_clusters (void);
-  HB_INTERNAL void guess_properties (void);
+  HB_INTERNAL void guess_segment_properties (void);
 
   HB_INTERNAL void swap_buffers (void);
+  HB_INTERNAL void remove_output (void);
   HB_INTERNAL void clear_output (void);
   HB_INTERNAL void clear_positions (void);
 
   HB_INTERNAL void replace_glyphs (unsigned int num_in,
 				   unsigned int num_out,
 				   const hb_codepoint_t *glyph_data);
 
   HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index);
--- a/gfx/harfbuzz/src/hb-buffer.cc
+++ b/gfx/harfbuzz/src/hb-buffer.cc
@@ -30,16 +30,39 @@
 #include "hb-buffer-private.hh"
 #include "hb-utf-private.hh"
 
 
 #ifndef HB_DEBUG_BUFFER
 #define HB_DEBUG_BUFFER (HB_DEBUG+0)
 #endif
 
+
+hb_bool_t
+hb_segment_properties_equal (const hb_segment_properties_t *a,
+			     const hb_segment_properties_t *b)
+{
+  return a->direction == b->direction &&
+	 a->script    == b->script    &&
+	 a->language  == b->language  &&
+	 a->reserved1 == b->reserved1 &&
+	 a->reserved2 == b->reserved2;
+
+}
+
+unsigned int
+hb_segment_properties_hash (const hb_segment_properties_t *p)
+{
+  return (unsigned int) p->direction ^
+	 (unsigned int) p->script ^
+	 (intptr_t) (p->language);
+}
+
+
+
 /* Here is how the buffer works internally:
  *
  * There are two info pointers: info and out_info.  They always have
  * the same allocated size, but different lengths.
  *
  * As an optimization, both info and out_info may point to the
  * same piece of memory, which is owned by info.  This remains the
  * case as long as out_len doesn't exceed i at any time.
@@ -66,17 +89,17 @@ hb_buffer_t::enlarge (unsigned int size)
   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;
 
-  while (size > new_allocated)
+  while (size >= new_allocated)
     new_allocated += (new_allocated >> 1) + 32;
 
   ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
   if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
     goto done;
 
   new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
   new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
@@ -137,18 +160,28 @@ void
 hb_buffer_t::reset (void)
 {
   if (unlikely (hb_object_is_inert (this)))
     return;
 
   hb_unicode_funcs_destroy (unicode);
   unicode = hb_unicode_funcs_get_default ();
 
-  hb_segment_properties_t default_props = _HB_BUFFER_PROPS_DEFAULT;
+  clear ();
+}
+
+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;
+  flags = HB_BUFFER_FLAGS_DEFAULT;
 
   content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
   in_error = false;
   have_output = false;
   have_positions = false;
 
   idx = 0;
   len = 0;
@@ -160,34 +193,46 @@ hb_buffer_t::reset (void)
   memset (allocated_var_owner, 0, sizeof allocated_var_owner);
 
   memset (context, 0, sizeof context);
   memset (context_len, 0, sizeof context_len);
 }
 
 void
 hb_buffer_t::add (hb_codepoint_t  codepoint,
-		  hb_mask_t       mask,
 		  unsigned int    cluster)
 {
   hb_glyph_info_t *glyph;
 
   if (unlikely (!ensure (len + 1))) return;
 
   glyph = &info[len];
 
   memset (glyph, 0, sizeof (*glyph));
   glyph->codepoint = codepoint;
-  glyph->mask = mask;
+  glyph->mask = 1;
   glyph->cluster = cluster;
 
   len++;
 }
 
 void
+hb_buffer_t::remove_output (void)
+{
+  if (unlikely (hb_object_is_inert (this)))
+    return;
+
+  have_output = false;
+  have_positions = false;
+
+  out_len = 0;
+  out_info = info;
+}
+
+void
 hb_buffer_t::clear_output (void)
 {
   if (unlikely (hb_object_is_inert (this)))
     return;
 
   have_output = true;
   have_positions = false;
 
@@ -441,17 +486,17 @@ hb_buffer_t::merge_out_clusters (unsigne
     for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
       info[i].cluster = cluster;
 
   for (unsigned int i = start; i < end; i++)
     out_info[i].cluster = cluster;
 }
 
 void
-hb_buffer_t::guess_properties (void)
+hb_buffer_t::guess_segment_properties (void)
 {
   if (unlikely (!len)) return;
   assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
 
   /* If script is set to INVALID, guess from buffer contents */
   if (props.script == HB_SCRIPT_INVALID) {
     for (unsigned int i = 0; i < len; i++) {
       hb_script_t script = unicode->script (info[i].codepoint);
@@ -543,17 +588,17 @@ void hb_buffer_t::deallocate_var_all (vo
 {
   memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
   memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
 }
 
 /* Public API */
 
 hb_buffer_t *
-hb_buffer_create ()
+hb_buffer_create (void)
 {
   hb_buffer_t *buffer;
 
   if (!(buffer = hb_object_create<hb_buffer_t> ()))
     return hb_buffer_get_empty ();
 
   buffer->reset ();
 
@@ -562,17 +607,18 @@ hb_buffer_create ()
 
 hb_buffer_t *
 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_PROPS_DEFAULT,
+    HB_SEGMENT_PROPERTIES_DEFAULT,
+    HB_BUFFER_FLAGS_DEFAULT,
 
     HB_BUFFER_CONTENT_TYPE_INVALID,
     true, /* in_error */
     true, /* have_output */
     true  /* have_positions */
 
     /* Zero is good enough for everything else. */
   };
@@ -697,42 +743,81 @@ hb_buffer_set_language (hb_buffer_t   *b
 }
 
 hb_language_t
 hb_buffer_get_language (hb_buffer_t *buffer)
 {
   return buffer->props.language;
 }
 
+void
+hb_buffer_set_segment_properties (hb_buffer_t *buffer,
+				  const hb_segment_properties_t *props)
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  buffer->props = *props;
+}
+
+void
+hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+				  hb_segment_properties_t *props)
+{
+  *props = buffer->props;
+}
+
+
+void
+hb_buffer_set_flags (hb_buffer_t       *buffer,
+		     hb_buffer_flags_t  flags)
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  buffer->flags = flags;
+}
+
+hb_buffer_flags_t
+hb_buffer_get_flags (hb_buffer_t *buffer)
+{
+  return buffer->flags;
+}
+
 
 void
 hb_buffer_reset (hb_buffer_t *buffer)
 {
   buffer->reset ();
 }
 
+void
+hb_buffer_clear (hb_buffer_t *buffer)
+{
+  buffer->clear ();
+}
+
 hb_bool_t
 hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
 {
   return buffer->ensure (size);
 }
 
 hb_bool_t
 hb_buffer_allocation_successful (hb_buffer_t  *buffer)
 {
   return !buffer->in_error;
 }
 
 void
 hb_buffer_add (hb_buffer_t    *buffer,
 	       hb_codepoint_t  codepoint,
-	       hb_mask_t       mask,
 	       unsigned int    cluster)
 {
-  buffer->add (codepoint, mask, cluster);
+  buffer->add (codepoint, cluster);
   buffer->clear_context (1);
 }
 
 hb_bool_t
 hb_buffer_set_length (hb_buffer_t  *buffer,
 		      unsigned int  length)
 {
   if (unlikely (hb_object_is_inert (buffer)))
@@ -796,19 +881,19 @@ hb_buffer_reverse (hb_buffer_t *buffer)
 
 void
 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
 {
   buffer->reverse_clusters ();
 }
 
 void
-hb_buffer_guess_properties (hb_buffer_t *buffer)
+hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
 {
-  buffer->guess_properties ();
+  buffer->guess_segment_properties ();
 }
 
 template <typename T>
 static inline void
 hb_buffer_add_utf (hb_buffer_t  *buffer,
 		   const T      *text,
 		   int           text_length,
 		   unsigned int  item_offset,
@@ -823,17 +908,24 @@ hb_buffer_add_utf (hb_buffer_t  *buffer,
   if (text_length == -1)
     text_length = hb_utf_strlen (text);
 
   if (item_length == -1)
     item_length = text_length - item_offset;
 
   buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
 
-  if (!buffer->len)
+  /* If buffer is empty and pre-context provided, install it.
+   * This check is written this way, to make sure people can
+   * provide pre-context in one add_utf() call, then provide
+   * text in a follow-up call.  See:
+   *
+   * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
+   */
+  if (!buffer->len && item_offset > 0)
   {
     /* Add pre-context */
     buffer->clear_context (0);
     const T *prev = text + item_offset;
     const T *start = text;
     while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
     {
       hb_codepoint_t u;
@@ -844,17 +936,17 @@ hb_buffer_add_utf (hb_buffer_t  *buffer,
 
   const T *next = text + item_offset;
   const T *end = next + item_length;
   while (next < end)
   {
     hb_codepoint_t u;
     const T *old_next = next;
     next = hb_utf_next (next, end, &u);
-    buffer->add (u, 1,  old_next - (const T *) text);
+    buffer->add (u, old_next - (const T *) text);
   }
 
   /* Add post-context */
   buffer->clear_context (1);
   end = text + text_length;
   while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
   {
     hb_codepoint_t u;
@@ -967,8 +1059,236 @@ hb_buffer_normalize_glyphs (hb_buffer_t 
   unsigned int end;
   for (end = start + 1; end < count; end++)
     if (info[start].cluster != info[end].cluster) {
       normalize_glyphs_cluster (buffer, start, end, backward);
       start = end;
     }
   normalize_glyphs_cluster (buffer, start, end, backward);
 }
+
+
+/*
+ * Serialize
+ */
+
+static const char *serialize_formats[] = {
+  "TEXT",
+  "JSON",
+  NULL
+};
+
+const char **
+hb_buffer_serialize_list_formats (void)
+{
+  return serialize_formats;
+}
+
+hb_buffer_serialize_format_t
+hb_buffer_serialize_format_from_string (const char *str, int len)
+{
+  /* Upper-case it. */
+  return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020);
+}
+
+const char *
+hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
+{
+  switch (format)
+  {
+    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:	return serialize_formats[0];
+    case HB_BUFFER_SERIALIZE_FORMAT_JSON:	return serialize_formats[1];
+    default:
+    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:	return NULL;
+  }
+}
+
+static unsigned int
+_hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
+				  unsigned int start,
+				  unsigned int end,
+				  char *buf,
+				  unsigned int buf_size,
+				  unsigned int *buf_consumed,
+				  hb_font_t *font,
+				  hb_buffer_serialize_flags_t flags)
+{
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
+
+  *buf_consumed = 0;
+  for (unsigned int i = start; i < end; i++)
+  {
+    char b[1024];
+    char *p = b;
+
+    /* In the following code, we know b is large enough that no overflow can happen. */
+
+#define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END
+
+    if (i)
+      *p++ = ',';
+
+    *p++ = '{';
+
+    APPEND ("\"g\":");
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
+    {
+      char g[128];
+      hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
+      *p++ = '"';
+      for (char *q = g; *q; q++) {
+        if (*q == '"')
+	  *p++ = '\\';
+	*p++ = *q;
+      }
+      *p++ = '"';
+    }
+    else
+      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint);
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
+      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster);
+    }
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
+    {
+      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
+		     pos[i].x_offset, pos[i].y_offset);
+      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
+		     pos[i].x_advance, pos[i].y_advance);
+    }
+
+    *p++ = '}';
+
+    if (buf_size > (p - b))
+    {
+      unsigned int l = p - b;
+      memcpy (buf, b, l);
+      buf += l;
+      buf_size -= l;
+      *buf_consumed += l;
+      *buf = '\0';
+    } else
+      return i - start;
+  }
+
+  return end - start;
+}
+
+static unsigned int
+_hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
+				  unsigned int start,
+				  unsigned int end,
+				  char *buf,
+				  unsigned int buf_size,
+				  unsigned int *buf_consumed,
+				  hb_font_t *font,
+				  hb_buffer_serialize_flags_t flags)
+{
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
+  hb_direction_t direction = hb_buffer_get_direction (buffer);
+
+  *buf_consumed = 0;
+  for (unsigned int i = start; i < end; i++)
+  {
+    char b[1024];
+    char *p = b;
+
+    /* In the following code, we know b is large enough that no overflow can happen. */
+
+    if (i)
+      *p++ = '|';
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
+    {
+      hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
+      p += strlen (p);
+    }
+    else
+      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint);
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
+      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster);
+    }
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
+    {
+      if (pos[i].x_offset || pos[i].y_offset)
+	p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset);
+
+      *p++ = '+';
+      if (HB_DIRECTION_IS_HORIZONTAL (direction) || pos[i].x_advance)
+	p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance);
+      if (HB_DIRECTION_IS_VERTICAL (direction) || pos->y_advance)
+	p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance);
+    }
+
+    if (buf_size > (p - b))
+    {
+      unsigned int l = p - b;
+      memcpy (buf, b, l);
+      buf += l;
+      buf_size -= l;
+      *buf_consumed += l;
+      *buf = '\0';
+    } else
+      return i - start;
+  }
+
+  return end - start;
+}
+
+/* Returns number of items, starting at start, that were serialized. */
+unsigned int
+hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
+			    unsigned int start,
+			    unsigned int end,
+			    char *buf,
+			    unsigned int buf_size,
+			    unsigned int *buf_consumed,
+			    hb_font_t *font, /* May be NULL */
+			    hb_buffer_serialize_format_t format,
+			    hb_buffer_serialize_flags_t flags)
+{
+  assert (start <= end && end <= buffer->len);
+
+  *buf_consumed = 0;
+
+  assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
+	  buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+
+  if (unlikely (start == end))
+    return 0;
+
+  if (!font)
+    font = hb_font_get_empty ();
+
+  switch (format)
+  {
+    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
+      return _hb_buffer_serialize_glyphs_text (buffer, start, end,
+					       buf, buf_size, buf_consumed,
+					       font, flags);
+
+    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
+      return _hb_buffer_serialize_glyphs_json (buffer, start, end,
+					       buf, buf_size, buf_consumed,
+					       font, flags);
+
+    default:
+    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
+      return 0;
+
+  }
+}
+
+hb_bool_t
+hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
+			      const char *buf,
+			      unsigned int buf_len,
+			      unsigned int *buf_consumed,
+			      hb_font_t *font, /* May be NULL */
+			      hb_buffer_serialize_format_t format)
+{
+  return false;
+}
--- a/gfx/harfbuzz/src/hb-buffer.h
+++ b/gfx/harfbuzz/src/hb-buffer.h
@@ -31,22 +31,21 @@
 #error "Include <hb.h> instead."
 #endif
 
 #ifndef HB_BUFFER_H
 #define HB_BUFFER_H
 
 #include "hb-common.h"
 #include "hb-unicode.h"
+#include "hb-font.h"
 
 HB_BEGIN_DECLS
 
 
-typedef struct hb_buffer_t hb_buffer_t;
-
 typedef struct hb_glyph_info_t {
   hb_codepoint_t codepoint;
   hb_mask_t      mask;
   uint32_t       cluster;
 
   /*< private >*/
   hb_var_int_t   var1;
   hb_var_int_t   var2;
@@ -57,22 +56,46 @@ typedef struct hb_glyph_position_t {
   hb_position_t  y_advance;
   hb_position_t  x_offset;
   hb_position_t  y_offset;
 
   /*< private >*/
   hb_var_int_t   var;
 } hb_glyph_position_t;
 
-typedef enum {
-  HB_BUFFER_CONTENT_TYPE_INVALID = 0,
-  HB_BUFFER_CONTENT_TYPE_UNICODE,
-  HB_BUFFER_CONTENT_TYPE_GLYPHS
-} hb_buffer_content_type_t;
+
+typedef struct hb_segment_properties_t {
+  hb_direction_t  direction;
+  hb_script_t     script;
+  hb_language_t   language;
+  /*< private >*/
+  void           *reserved1;
+  void           *reserved2;
+} hb_segment_properties_t;
 
+#define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \
+				       HB_SCRIPT_INVALID, \
+				       HB_LANGUAGE_INVALID, \
+				       NULL, \
+				       NULL}
+
+hb_bool_t
+hb_segment_properties_equal (const hb_segment_properties_t *a,
+			     const hb_segment_properties_t *b);
+
+unsigned int
+hb_segment_properties_hash (const hb_segment_properties_t *p);
+
+
+
+/*
+ * hb_buffer_t
+ */
+
+typedef struct hb_buffer_t hb_buffer_t;
 
 hb_buffer_t *
 hb_buffer_create (void);
 
 hb_buffer_t *
 hb_buffer_get_empty (void);
 
 hb_buffer_t *
@@ -88,16 +111,22 @@ hb_buffer_set_user_data (hb_buffer_t    
 			 hb_destroy_func_t   destroy,
 			 hb_bool_t           replace);
 
 void *
 hb_buffer_get_user_data (hb_buffer_t        *buffer,
 			 hb_user_data_key_t *key);
 
 
+typedef enum {
+  HB_BUFFER_CONTENT_TYPE_INVALID = 0,
+  HB_BUFFER_CONTENT_TYPE_UNICODE,
+  HB_BUFFER_CONTENT_TYPE_GLYPHS
+} hb_buffer_content_type_t;
+
 void
 hb_buffer_set_content_type (hb_buffer_t              *buffer,
 			    hb_buffer_content_type_t  content_type);
 
 hb_buffer_content_type_t
 hb_buffer_get_content_type (hb_buffer_t *buffer);
 
 
@@ -121,51 +150,78 @@ hb_buffer_set_script (hb_buffer_t *buffe
 
 hb_script_t
 hb_buffer_get_script (hb_buffer_t *buffer);
 
 void
 hb_buffer_set_language (hb_buffer_t   *buffer,
 			hb_language_t  language);
 
+
 hb_language_t
 hb_buffer_get_language (hb_buffer_t *buffer);
 
+void
+hb_buffer_set_segment_properties (hb_buffer_t *buffer,
+				  const hb_segment_properties_t *props);
+
+void
+hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+				  hb_segment_properties_t *props);
+
+void
+hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
+
+
+typedef enum {
+  HB_BUFFER_FLAGS_DEFAULT			= 0x00000000,
+  HB_BUFFER_FLAG_BOT				= 0x00000001, /* Beginning-of-text */
+  HB_BUFFER_FLAG_EOT				= 0x00000002, /* End-of-text */
+  HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES	= 0x00000004
+} hb_buffer_flags_t;
+
+void
+hb_buffer_set_flags (hb_buffer_t       *buffer,
+		     hb_buffer_flags_t  flags);
+
+hb_buffer_flags_t
+hb_buffer_get_flags (hb_buffer_t *buffer);
+
 
 /* Resets the buffer.  Afterwards it's as if it was just created,
  * except that it has a larger buffer allocated perhaps... */
 void
 hb_buffer_reset (hb_buffer_t *buffer);
 
+/* Like reset, but does NOT clear unicode_funcs. */
+void
+hb_buffer_clear (hb_buffer_t *buffer);
+
 /* Returns false if allocation failed */
 hb_bool_t
 hb_buffer_pre_allocate (hb_buffer_t  *buffer,
 		        unsigned int  size);
 
 
 /* Returns false if allocation has failed before */
 hb_bool_t
 hb_buffer_allocation_successful (hb_buffer_t  *buffer);
 
 void
 hb_buffer_reverse (hb_buffer_t *buffer);
 
 void
 hb_buffer_reverse_clusters (hb_buffer_t *buffer);
 
-void
-hb_buffer_guess_properties (hb_buffer_t *buffer);
-
 
 /* Filling the buffer in */
 
 void
 hb_buffer_add (hb_buffer_t    *buffer,
 	       hb_codepoint_t  codepoint,
-	       hb_mask_t       mask,
 	       unsigned int    cluster);
 
 void
 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
 		    const char   *text,
 		    int           text_length,
 		    unsigned int  item_offset,
 		    int           item_length);
@@ -208,18 +264,60 @@ hb_buffer_get_glyph_positions (hb_buffer
 
 
 /* Reorders a glyph buffer to have canonical in-cluster glyph order / position.
  * The resulting clusters should behave identical to pre-reordering clusters.
  * NOTE: This has nothing to do with Unicode normalization. */
 void
 hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
 
+
 /*
- * NOT IMPLEMENTED
- void
- hb_buffer_normalize_characters (hb_buffer_t *buffer);
-*/
+ * Serialize
+ */
+
+typedef enum {
+  HB_BUFFER_SERIALIZE_FLAGS_DEFAULT		= 0x00000000,
+  HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS		= 0x00000001,
+  HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS		= 0x00000002,
+  HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES	= 0x00000004
+} hb_buffer_serialize_flags_t;
+
+typedef enum {
+  HB_BUFFER_SERIALIZE_FORMAT_TEXT	= HB_TAG('T','E','X','T'),
+  HB_BUFFER_SERIALIZE_FORMAT_JSON	= HB_TAG('J','S','O','N'),
+  HB_BUFFER_SERIALIZE_FORMAT_INVALID	= HB_TAG_NONE
+} hb_buffer_serialize_format_t;
+
+/* len=-1 means str is NUL-terminated. */
+hb_buffer_serialize_format_t
+hb_buffer_serialize_format_from_string (const char *str, int len);
+
+const char *
+hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format);
+
+const char **
+hb_buffer_serialize_list_formats (void);
+
+/* Returns number of items, starting at start, that were serialized. */
+unsigned int
+hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
+			    unsigned int start,
+			    unsigned int end,
+			    char *buf,
+			    unsigned int buf_size,
+			    unsigned int *buf_consumed,
+			    hb_font_t *font, /* May be NULL */
+			    hb_buffer_serialize_format_t format,
+			    hb_buffer_serialize_flags_t flags);
+
+hb_bool_t
+hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
+			      const char *buf,
+			      unsigned int buf_len,
+			      unsigned int *buf_consumed,
+			      hb_font_t *font, /* May be NULL */
+			      hb_buffer_serialize_format_t format);
 
 
 HB_END_DECLS
 
 #endif /* HB_BUFFER_H */
--- a/gfx/harfbuzz/src/hb-fallback-shape.cc
+++ b/gfx/harfbuzz/src/hb-fallback-shape.cc
@@ -93,24 +93,24 @@ hb_bool_t
 		    hb_font_t          *font,
 		    hb_buffer_t        *buffer,
 		    const hb_feature_t *features HB_UNUSED,
 		    unsigned int        num_features HB_UNUSED)
 {
   hb_codepoint_t space;
   font->get_glyph (' ', 0, &space);
 
-  buffer->guess_properties ();
+  buffer->guess_segment_properties ();
   buffer->clear_positions ();
 
   unsigned int count = buffer->len;
 
   for (unsigned int i = 0; i < count; i++)
   {
-    if (buffer->unicode->is_zero_width (buffer->info[i].codepoint)) {
+    if (buffer->unicode->is_default_ignorable (buffer->info[i].codepoint)) {
       buffer->info[i].codepoint = space;
       buffer->pos[i].x_advance = 0;
       buffer->pos[i].y_advance = 0;
       continue;
     }
     font->get_glyph (buffer->info[i].codepoint, 0, &buffer->info[i].codepoint);
     font->get_glyph_advance_for_direction (buffer->info[i].codepoint,
 					   buffer->props.direction,
--- a/gfx/harfbuzz/src/hb-font-private.hh
+++ b/gfx/harfbuzz/src/hb-font-private.hh
@@ -95,16 +95,17 @@ struct hb_face_t {
   hb_bool_t immutable;
 
   hb_reference_table_func_t  reference_table_func;
   void                      *user_data;
   hb_destroy_func_t          destroy;
 
   unsigned int index;
   mutable unsigned int upem;
+  mutable unsigned int num_glyphs;
 
   struct hb_shaper_data_t shaper_data;
 
   struct plan_node_t {
     hb_shape_plan_t *shape_plan;
     plan_node_t *next;
   } *shape_plans;
 
@@ -125,18 +126,26 @@ struct hb_face_t {
 
   inline unsigned int get_upem (void) const
   {
     if (unlikely (!upem))
       load_upem ();
     return upem;
   }
 
+  inline unsigned int get_num_glyphs (void) const
+  {
+    if (unlikely (num_glyphs == (unsigned int) -1))
+      load_num_glyphs ();
+    return num_glyphs;
+  }
+
   private:
   HB_INTERNAL void load_upem (void) const;
+  HB_INTERNAL void load_num_glyphs (void) const;
 };
 
 #define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, face);
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 #undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
 
--- a/gfx/harfbuzz/src/hb-font.cc
+++ b/gfx/harfbuzz/src/hb-font.cc
@@ -29,16 +29,17 @@
 #include "hb-private.hh"
 
 #include "hb-ot-layout-private.hh"
 
 #include "hb-font-private.hh"
 #include "hb-blob.h"
 #include "hb-open-file-private.hh"
 #include "hb-ot-head-table.hh"
+#include "hb-ot-maxp-table.hh"
 
 #include "hb-cache-private.hh"
 
 #include <string.h>
 
 
 
 /*
@@ -515,16 +516,17 @@ static const hb_face_t _hb_face_nil = {
   true, /* immutable */
 
   NULL, /* reference_table_func */
   NULL, /* user_data */
   NULL, /* destroy */
 
   0,    /* index */
   1000, /* upem */
+  0,    /* num_glyphs */
 
   {
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
   },
 
   NULL, /* shape_plans */
@@ -544,16 +546,17 @@ hb_face_create_for_tables (hb_reference_
     return hb_face_get_empty ();
   }
 
   face->reference_table_func = reference_table_func;
   face->user_data = user_data;
   face->destroy = destroy;
 
   face->upem = 0;
+  face->num_glyphs = (unsigned int) -1;
 
   return face;
 }
 
 
 typedef struct hb_face_for_data_closure_t {
   hb_blob_t *blob;
   unsigned int  index;
@@ -731,26 +734,50 @@ hb_face_set_upem (hb_face_t    *face,
 }
 
 unsigned int
 hb_face_get_upem (hb_face_t *face)
 {
   return face->get_upem ();
 }
 
-
 void
 hb_face_t::load_upem (void) const
 {
   hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (reference_table (HB_OT_TAG_head));
   const OT::head *head_table = OT::Sanitizer<OT::head>::lock_instance (head_blob);
   upem = head_table->get_upem ();
   hb_blob_destroy (head_blob);
 }
 
+void
+hb_face_set_glyph_count (hb_face_t    *face,
+			 unsigned int  glyph_count)
+{
+  if (hb_object_is_inert (face))
+    return;
+
+  face->num_glyphs = glyph_count;
+}
+
+unsigned int
+hb_face_get_glyph_count (hb_face_t *face)
+{
+  return face->get_num_glyphs ();
+}
+
+void
+hb_face_t::load_num_glyphs (void) const
+{
+  hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>::sanitize (reference_table (HB_OT_TAG_maxp));
+  const OT::maxp *maxp_table = OT::Sanitizer<OT::maxp>::lock_instance (maxp_blob);
+  num_glyphs = maxp_table->get_num_glyphs ();
+  hb_blob_destroy (maxp_blob);
+}
+
 
 /*
  * hb_font_t
  */
 
 hb_font_t *
 hb_font_create (hb_face_t *face)
 {
--- a/gfx/harfbuzz/src/hb-font.h
+++ b/gfx/harfbuzz/src/hb-font.h
@@ -100,16 +100,23 @@ hb_face_get_index (hb_face_t    *face);
 
 void
 hb_face_set_upem (hb_face_t    *face,
 		  unsigned int  upem);
 
 unsigned int
 hb_face_get_upem (hb_face_t *face);
 
+void
+hb_face_set_glyph_count (hb_face_t    *face,
+			 unsigned int  glyph_count);
+
+unsigned int
+hb_face_get_glyph_count (hb_face_t *face);
+
 
 /*
  * hb_font_funcs_t
  */
 
 typedef struct hb_font_funcs_t hb_font_funcs_t;
 
 hb_font_funcs_t *
--- a/gfx/harfbuzz/src/hb-ft.cc
+++ b/gfx/harfbuzz/src/hb-ft.cc
@@ -237,17 +237,17 @@ hb_ft_get_glyph_name (hb_font_t *font HB
 		      void *font_data,
 		      hb_codepoint_t glyph,
 		      char *name, unsigned int size,
 		      void *user_data HB_UNUSED)
 {
   FT_Face ft_face = (FT_Face) font_data;
 
   hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
-  if (!ret)
+  if (!ret || (size && !*name))
     snprintf (name, size, "gid%u", glyph);
 
   return ret;
 }
 
 static hb_bool_t
 hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
 			   void *font_data,
--- a/gfx/harfbuzz/src/hb-icu-le.cc
+++ b/gfx/harfbuzz/src/hb-icu-le.cc
@@ -25,17 +25,17 @@
  */
 
 #define HB_SHAPER icu_le
 #define hb_icu_le_shaper_font_data_t PortableFontInstance
 #include "hb-shaper-impl-private.hh"
 
 #include "hb-icu-le/PortableFontInstance.h"
 
-#include "layout/LayoutEngine.h"
+#include "layout/loengine.h"
 #include "unicode/unistr.h"
 
 #include "hb-icu.h"
 
 
 /*
  * shaper face data
  */
@@ -112,87 +112,89 @@ hb_bool_t
 		  const hb_feature_t *features,
 		  unsigned int        num_features)
 {
   LEFontInstance *font_instance = HB_SHAPER_DATA_GET (font);
   le_int32 script_code = hb_icu_script_from_script (shape_plan->props.script);
   le_int32 language_code = -1 /* TODO */;
   le_int32 typography_flags = 3; // essential for ligatures and kerning
   LEErrorCode status = LE_NO_ERROR;
-  LayoutEngine *le = LayoutEngine::layoutEngineFactory (font_instance,
-							script_code,
-							language_code,
-							typography_flags,
-							status);
+  le_engine *le = le_create ((const le_font *) font_instance,
+			     script_code,
+			     language_code,
+			     typography_flags,
+			     &status);
   if (status != LE_NO_ERROR)
-  { delete (le); return false; }
+  { le_close (le); return false; }
 
 retry:
 
   unsigned int scratch_size;
   char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
 
 #define ALLOCATE_ARRAY(Type, name, len) \
   Type *name = (Type *) scratch; \
   scratch += (len) * sizeof ((name)[0]); \
   scratch_size -= (len) * sizeof ((name)[0]);
 
   ALLOCATE_ARRAY (LEUnicode, chars, buffer->len);
   ALLOCATE_ARRAY (unsigned int, clusters, buffer->len);
 
+  /* XXX Use UTF-16 decoder! */
   for (unsigned int i = 0; i < buffer->len; i++) {
     chars[i] = buffer->info[i].codepoint;
     clusters[i] = buffer->info[i].cluster;
   }
 
-  unsigned int glyph_count = le->layoutChars(chars,
+  unsigned int glyph_count = le_layoutChars (le,
+					     chars,
 					     0,
 					     buffer->len,
 					     buffer->len,
 					     HB_DIRECTION_IS_BACKWARD (buffer->props.direction),
 					     0., 0.,
-					     status);
+					     &status);
   if (status != LE_NO_ERROR)
-  { delete (le); return false; }
+  { le_close (le); return false; }
 
   unsigned int num_glyphs = scratch_size / (sizeof (LEGlyphID) +
 					    sizeof (le_int32) +
 					    sizeof (float) * 2);
 
   if (unlikely (glyph_count >= num_glyphs || glyph_count > buffer->allocated)) {
     buffer->ensure (buffer->allocated * 2);
     if (buffer->in_error)
-    { delete (le); return false; }
+    { le_close (le); return false; }
     goto retry;
   }
 
   ALLOCATE_ARRAY (LEGlyphID, glyphs, glyph_count);
   ALLOCATE_ARRAY (le_int32, indices, glyph_count);
   ALLOCATE_ARRAY (float, positions, glyph_count * 2 + 2);
 
-  le->getGlyphs(glyphs, status);
-  le->getCharIndices(indices, status);
-  le->getGlyphPositions(positions, status);
+  le_getGlyphs (le, glyphs, &status);
+  le_getCharIndices (le, indices, &status);
+  le_getGlyphPositions (le, positions, &status);
 
 #undef ALLOCATE_ARRAY
 
   /* Ok, we've got everything we need, now compose output buffer,
    * very, *very*, carefully! */
 
   unsigned int j = 0;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < glyph_count; i++)
   {
     if (glyphs[i] >= 0xFFFE)
 	continue;
 
     info[j].codepoint = glyphs[i];
     info[j].cluster = clusters[indices[i]];
 
-    /* icu-le doesn't seem to have separapte advance values. */
+    /* icu-le doesn't seem to have separate advance values. */
     info[j].mask = positions[2 * i + 2] - positions[2 * i];
     info[j].var1.u32 = 0;
     info[j].var2.u32 = -positions[2 * i + 1];
 
     j++;
   }
   buffer->len = j;
 
@@ -203,11 +205,11 @@ retry:
     hb_glyph_position_t *pos = &buffer->pos[i];
 
     /* TODO vertical */
     pos->x_advance = info->mask;
     pos->x_offset = info->var1.u32;
     pos->y_offset = info->var2.u32;
   }
 
-  delete (le);
+  le_close (le);
   return true;
 }
--- a/gfx/harfbuzz/src/hb-open-type-private.hh
+++ b/gfx/harfbuzz/src/hb-open-type-private.hh
@@ -133,23 +133,23 @@ inline Type& StructAfter(TObject &X)
 
 /* Global nul-content Null pool.  Enlarge as necessary. */
 /* TODO This really should be a extern HB_INTERNAL and defined somewhere... */
 static const void *_NullPool[64 / sizeof (void *)];
 
 /* Generic nul-content Null objects. */
 template <typename Type>
 static inline const Type& Null (void) {
-  ASSERT_STATIC (Type::min_size <= sizeof (_NullPool));
+  ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool));
   return *CastP<Type> (_NullPool);
 }
 
 /* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
 #define DEFINE_NULL_DATA(Type, data) \
-static const char _Null##Type[Type::min_size + 1] = data; /* +1 is for nul-termination in data */ \
+static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \
 template <> \
 inline const Type& Null<Type> (void) { \
   return *CastP<Type> (_Null##Type); \
 } /* The following line really exists such that we end in a place needing semicolon */ \
 ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
 
 /* Accessor macro. */
 #define Null(Type) Null<Type>()
--- a/gfx/harfbuzz/src/hb-ot-head-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-head-table.hh
@@ -42,17 +42,17 @@ namespace OT {
 #define HB_OT_TAG_head HB_TAG('h','e','a','d')
 
 struct head
 {
   static const hb_tag_t Tag	= HB_OT_TAG_head;
 
   inline unsigned int get_upem (void) const {
     unsigned int upem = unitsPerEm;
-    /* If no valid head table found, assume 1000, which matches typicaly Type1 usage. */
+    /* If no valid head table found, assume 1000, which matches typical Type1 usage. */
     return 16 <= upem && upem <= 16384 ? upem : 1000;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
   }
 
--- a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
@@ -398,27 +398,30 @@ struct CoverageFormat1
 
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const {
     unsigned int count = glyphArray.len;
     for (unsigned int i = 0; i < count; i++)
       glyphs->add (glyphArray[i]);
   }
 
+  public:
+  /* Older compilers need this to be public. */
   struct Iter {
     inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
     inline bool more (void) { return i < c->glyphArray.len; }
     inline void next (void) { i++; }
     inline uint16_t get_glyph (void) { return c->glyphArray[i]; }
     inline uint16_t get_coverage (void) { return i; }
 
     private:
     const struct CoverageFormat1 *c;
     unsigned int i;
   };
+  private:
 
   protected:
   USHORT	coverageFormat;	/* Format identifier--format = 1 */
   SortedArrayOf<GlyphID>
 		glyphArray;	/* Array of GlyphIDs--in numerical order */
   public:
   DEFINE_SIZE_ARRAY (4, glyphArray);
 };
@@ -492,16 +495,18 @@ struct CoverageFormat2
 
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const {
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
       rangeRecord[i].add_coverage (glyphs);
   }
 
+  public:
+  /* Older compilers need this to be public. */
   struct Iter {
     inline void init (const CoverageFormat2 &c_) {
       c = &c_;
       coverage = 0;
       i = 0;
       j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
     }
     inline bool more (void) { return i < c->rangeRecord.len; }
@@ -517,16 +522,17 @@ struct CoverageFormat2
     }
     inline uint16_t get_glyph (void) { return j; }
     inline uint16_t get_coverage (void) { return coverage; }
 
     private:
     const struct CoverageFormat2 *c;
     unsigned int i, j, coverage;
   };
+  private:
 
   protected:
   USHORT	coverageFormat;	/* Format identifier--format = 2 */
   SortedArrayOf<RangeRecord>
 		rangeRecord;	/* Array of glyph ranges--ordered by
 				 * Start GlyphID. rangeCount entries
 				 * long */
   public:
--- a/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
@@ -1338,16 +1338,17 @@ struct SubstLookup : Lookup
 	    c->buffer->next_glyph ();
 	}
 	if (ret)
 	  c->buffer->swap_buffers ();
     }
     else
     {
 	/* in-place backward substitution */
+	c->buffer->remove_output ();
 	c->buffer->idx = c->buffer->len - 1;
 	do
 	{
 	  if ((c->buffer->cur().mask & c->lookup_mask) &&
 	      digest->may_have (c->buffer->cur().codepoint) &&
 	      apply_once (c))
 	    ret = true;
 	  else
--- a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
@@ -454,17 +454,17 @@ static inline bool match_input (hb_apply
   unsigned int first_lig_comp = get_lig_comp (c->buffer->cur());
 
   for (unsigned int i = 1; i < count; i++)
   {
     unsigned int property;
 
     if (!skippy_iter.next (&property)) return TRACE_RETURN (false);
 
-    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data))) return false;
+    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data))) return TRACE_RETURN (false);
 
     unsigned int this_lig_id = get_lig_id (c->buffer->info[skippy_iter.idx]);
     unsigned int this_lig_comp = get_lig_comp (c->buffer->info[skippy_iter.idx]);
 
     if (first_lig_id && first_lig_comp) {
       /* If first component was attached to a previous ligature component,
        * all subsequent components should be attached to the same ligature
        * component, otherwise we shouldn't ligate them. */
@@ -486,17 +486,17 @@ static inline bool match_input (hb_apply
     *end_offset = skippy_iter.idx - c->buffer->idx + 1;
 
   if (p_is_mark_ligature)
     *p_is_mark_ligature = is_mark_ligature;
 
   if (p_total_component_count)
     *p_total_component_count = total_component_count;
 
-  return true;
+  return TRACE_RETURN (true);
 }
 static inline void ligate_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 */
 				 hb_codepoint_t lig_glyph,
 				 match_func_t match_func,
 				 const void *match_data,
 				 bool is_mark_ligature,
@@ -650,66 +650,67 @@ static inline void closure_lookup (hb_cl
 }
 
 static inline bool apply_lookup (hb_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph */
 				 unsigned int lookupCount,
 				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
 				 apply_lookup_func_t apply_func)
 {
+  hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
   unsigned int end = c->buffer->len;
   if (unlikely (count == 0 || c->buffer->idx + count > end))
-    return false;
+    return TRACE_RETURN (false);
 
   /* TODO We don't support lookupRecord arrays that are not increasing:
    *      Should be easy for in_place ones at least. */
 
   /* Note: If sublookup is reverse, it will underflow after the first loop
    * and we jump out of it.  Not entirely disastrous.  So we don't check
    * for reverse lookup here.
    */
   for (unsigned int i = 0; i < count; /* NOP */)
   {
     if (unlikely (c->buffer->idx == end))
-      return true;
+      return TRACE_RETURN (true);
     while (c->should_mark_skip_current_glyph ())
     {
       /* No lookup applied for this index */
       c->buffer->next_glyph ();
       if (unlikely (c->buffer->idx == end))
-	return true;
+	return TRACE_RETURN (true);
     }
 
     if (lookupCount && i == lookupRecord->sequenceIndex)
     {
       unsigned int old_pos = c->buffer->idx;
 
       /* Apply a lookup */
       bool done = apply_func (c, lookupRecord->lookupListIndex);
 
       lookupRecord++;
       lookupCount--;
       /* Err, this is wrong if the lookup jumped over some glyphs */
       i += c->buffer->idx - old_pos;
       if (unlikely (c->buffer->idx == end))
-	return true;
+	return TRACE_RETURN (true);
 
       if (!done)
 	goto not_applied;
     }
     else
     {
     not_applied:
       /* No lookup applied for this index */
       c->buffer->next_glyph ();
       i++;
     }
   }
 
-  return true;
+  return TRACE_RETURN (true);
 }
 
 
 
 /* Contextual lookups */
 
 struct ContextClosureLookupContext
 {
--- a/gfx/harfbuzz/src/hb-ot-layout-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-private.hh
@@ -44,24 +44,16 @@
 #define lig_props()		var1.u8[3] /* GSUB/GPOS ligature tracking */
 
 #define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
 
 /*
  * GDEF
  */
 
-typedef enum {
-  HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED	= 0x0001,
-  HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH	= 0x0002,
-  HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE	= 0x0004,
-  HB_OT_LAYOUT_GLYPH_CLASS_MARK		= 0x0008,
-  HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT	= 0x0010
-} hb_ot_layout_glyph_class_t;
-
 
 
 /*
  * GSUB/GPOS
  */
 
 /* lig_id / lig_comp
  *
@@ -133,17 +125,17 @@ static inline uint8_t allocate_lig_id (h
   uint8_t lig_id = buffer->next_serial () & 0x07;
   if (unlikely (!lig_id))
     lig_id = allocate_lig_id (buffer); /* in case of overflow */
   return lig_id;
 }
 
 
 HB_INTERNAL hb_bool_t
-hb_ot_layout_would_substitute_lookup_fast (hb_face_t            *face,
+hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
 					   unsigned int          lookup_index,
 					   const hb_codepoint_t *glyphs,
 					   unsigned int          glyphs_length,
 					   hb_bool_t             zero_context);
 
 
 /* Should be called before all the substitute_lookup's are done. */
 HB_INTERNAL void
--- a/gfx/harfbuzz/src/hb-ot-layout.cc
+++ b/gfx/harfbuzz/src/hb-ot-layout.cc
@@ -369,22 +369,22 @@ hb_ot_layout_language_find_feature (hb_f
     }
   }
 
   if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
   return false;
 }
 
 unsigned int
-hb_ot_layout_feature_get_lookup_indexes (hb_face_t    *face,
-					 hb_tag_t      table_tag,
-					 unsigned int  feature_index,
-					 unsigned int  start_offset,
-					 unsigned int *lookup_count /* IN/OUT */,
-					 unsigned int *lookup_indexes /* OUT */)
+hb_ot_layout_feature_get_lookups (hb_face_t    *face,
+				  hb_tag_t      table_tag,
+				  unsigned int  feature_index,
+				  unsigned int  start_offset,
+				  unsigned int *lookup_count /* IN/OUT */,
+				  unsigned int *lookup_indexes /* OUT */)
 {
   const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
   const OT::Feature &f = g.get_feature (feature_index);
 
   return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
 }
 
 
@@ -394,28 +394,28 @@ hb_ot_layout_feature_get_lookup_indexes 
 
 hb_bool_t
 hb_ot_layout_has_substitution (hb_face_t *face)
 {
   return &_get_gsub (face) != &OT::Null(OT::GSUB);
 }
 
 hb_bool_t
-hb_ot_layout_would_substitute_lookup (hb_face_t            *face,
+hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
 				      unsigned int          lookup_index,
 				      const hb_codepoint_t *glyphs,
 				      unsigned int          glyphs_length,
 				      hb_bool_t             zero_context)
 {
   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
-  return hb_ot_layout_would_substitute_lookup_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
+  return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
 }
 
 hb_bool_t
-hb_ot_layout_would_substitute_lookup_fast (hb_face_t            *face,
+hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
 					   unsigned int          lookup_index,
 					   const hb_codepoint_t *glyphs,
 					   unsigned int          glyphs_length,
 					   hb_bool_t             zero_context)
 {
   if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
   OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
 
@@ -447,17 +447,17 @@ hb_ot_layout_substitute_lookup (hb_font_
 
 void
 hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
 {
   OT::GSUB::substitute_finish (font, buffer);
 }
 
 void
-hb_ot_layout_substitute_closure_lookup (hb_face_t    *face,
+hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
 				        unsigned int  lookup_index,
 				        hb_set_t     *glyphs)
 {
   OT::hb_closure_context_t c (face, glyphs);
   _get_gsub (face).closure_lookup (&c, lookup_index);
 }
 
 /*
--- a/gfx/harfbuzz/src/hb-ot-layout.h
+++ b/gfx/harfbuzz/src/hb-ot-layout.h
@@ -45,16 +45,37 @@ HB_BEGIN_DECLS
 
 /*
  * GDEF
  */
 
 hb_bool_t
 hb_ot_layout_has_glyph_classes (hb_face_t *face);
 
+typedef enum {
+  HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED	= 0x0001,
+  HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH	= 0x0002,
+  HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE	= 0x0004,
+  HB_OT_LAYOUT_GLYPH_CLASS_MARK		= 0x0008,
+  HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT	= 0x0010
+} hb_ot_layout_glyph_class_t;
+
+#ifdef HB_NOT_IMPLEMENTED
+hb_ot_layout_glyph_class_t
+Xhb_ot_layout_get_glyph_class (hb_face_t      *face,
+			      hb_codepoint_t  glyph);
+#endif
+
+#ifdef HB_NOT_IMPLEMENTED
+Xhb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
+				  hb_ot_layout_glyph_class_t  klass,
+				  hb_set_t                   *glyphs /* OUT */);
+#endif
+
+
 /* Not that useful.  Provides list of attach points for a glyph that a
  * client may want to cache */
 unsigned int
 hb_ot_layout_get_attach_points (hb_face_t      *face,
 				hb_codepoint_t  glyph,
 				unsigned int    start_offset,
 				unsigned int   *point_count /* IN/OUT */,
 				unsigned int   *point_array /* OUT */);
@@ -149,46 +170,121 @@ hb_bool_t
 hb_ot_layout_language_find_feature (hb_face_t    *face,
 				    hb_tag_t      table_tag,
 				    unsigned int  script_index,
 				    unsigned int  language_index,
 				    hb_tag_t      feature_tag,
 				    unsigned int *feature_index);
 
 unsigned int
-hb_ot_layout_feature_get_lookup_indexes (hb_face_t    *face,
+hb_ot_layout_feature_get_lookups (hb_face_t    *face,
+				  hb_tag_t      table_tag,
+				  unsigned int  feature_index,
+				  unsigned int  start_offset,
+				  unsigned int *lookup_count /* IN/OUT */,
+				  unsigned int *lookup_indexes /* OUT */);
+
+#ifdef HB_NOT_IMPLEMENTED
+void
+Xhb_ot_layout_collect_lookups (hb_face_t      *face,
+			      hb_tag_t        table_tag,
+			      const hb_tag_t *scripts,
+			      const hb_tag_t *languages,
+			      const hb_tag_t *features,
+			      hb_set_t       *lookup_indexes /* OUT */);
+#endif
+
+void
+hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
+				  hb_tag_t         table_tag,
+				  hb_set_t        *lookup_indexes /* OUT */);
+
+#ifdef HB_NOT_IMPLEMENTED
+void
+Xhb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
+				    hb_tag_t      table_tag,
+				    unsigned int  lookup_index,
+				    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 */);
+#endif
+
+#ifdef HB_NOT_IMPLEMENTED
+typedef struct
+{
+  const hb_codepoint_t *before,
+  unsigned int          before_length,
+  const hb_codepoint_t *input,
+  unsigned int          input_length,
+  const hb_codepoint_t *after,
+  unsigned int          after_length,
+} hb_ot_layout_glyph_sequence_t;
+
+typedef hb_bool_t
+(*hb_ot_layout_glyph_sequence_func_t) (hb_font_t    *font,
+				       hb_tag_t      table_tag,
+				       unsigned int  lookup_index,
+				       const hb_ot_layout_glyph_sequence_t *sequence,
+				       void         *user_data);
+
+void
+Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t    *face,
 					 hb_tag_t      table_tag,
-					 unsigned int  feature_index,
-					 unsigned int  start_offset,
-					 unsigned int *lookup_count /* IN/OUT */,
-					 unsigned int *lookup_indexes /* OUT */);
+					 unsigned int  lookup_index,
+					 hb_ot_layout_glyph_sequence_func_t callback,
+					 void         *user_data);
+#endif
 
 
 /*
  * GSUB
  */
 
 hb_bool_t
 hb_ot_layout_has_substitution (hb_face_t *face);
 
 hb_bool_t
-hb_ot_layout_would_substitute_lookup (hb_face_t            *face,
+hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
 				      unsigned int          lookup_index,
 				      const hb_codepoint_t *glyphs,
 				      unsigned int          glyphs_length,
 				      hb_bool_t             zero_context);
 
 void
-hb_ot_layout_substitute_closure_lookup (hb_face_t    *face,
+hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
 				        unsigned int  lookup_index,
-				        hb_set_t     *glyphs);
+				        hb_set_t     *glyphs
+					/*TODO , hb_bool_t  inclusive */);
+
+#ifdef HB_NOT_IMPLEMENTED
+/* Note: You better have GDEF when using this API, or marks won't do much. */
+hb_bool_t
+Xhb_ot_layout_lookup_substitute (hb_font_t            *font,
+				unsigned int          lookup_index,
+				const hb_ot_layout_glyph_sequence_t *sequence,
+				unsigned int          out_size,
+				hb_codepoint_t       *glyphs_out,   /* OUT */
+				unsigned int         *clusters_out, /* OUT */
+				unsigned int         *out_length    /* OUT */);
+#endif
+
 
 /*
  * GPOS
  */
 
 hb_bool_t
 hb_ot_layout_has_positioning (hb_face_t *face);
 
+#ifdef HB_NOT_IMPLEMENTED
+/* Note: You better have GDEF when using this API, or marks won't do much. */
+hb_bool_t
+Xhb_ot_layout_lookup_position (hb_font_t            *font,
+			      unsigned int          lookup_index,
+			      const hb_ot_layout_glyph_sequence_t *sequence,
+			      hb_glyph_position_t  *positions /* IN / OUT */);
+#endif
+
 
 HB_END_DECLS
 
 #endif /* HB_OT_LAYOUT_H */
--- a/gfx/harfbuzz/src/hb-ot-map-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-map-private.hh
@@ -110,67 +110,65 @@ struct hb_ot_map_t
     }
     assert (stage <= pauses[table_index].len);
     unsigned int start = stage ? pauses[table_index][stage - 1].num_lookups : 0;
     unsigned int end   = stage < pauses[table_index].len ? pauses[table_index][stage].num_lookups : lookups[table_index].len;
     *plookups = &lookups[table_index][start];
     *lookup_count = end - start;
   }
 
-  inline hb_tag_t get_chosen_script (unsigned int table_index) const
-  { return chosen_script[table_index]; }
-
-  HB_INTERNAL void substitute_closure (const struct hb_ot_shape_plan_t *plan, hb_face_t *face, hb_set_t *glyphs) const;
+  HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const;
   HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
   HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
 
   inline void finish (void) {
     features.finish ();
     lookups[0].finish ();
     lookups[1].finish ();
     pauses[0].finish ();
     pauses[1].finish ();
   }
 
+  public:
+  hb_tag_t chosen_script[2];
+  bool found_script[2];
 
   private:
 
   HB_INTERNAL void add_lookups (hb_face_t    *face,
 				unsigned int  table_index,
 				unsigned int  feature_index,
 				hb_mask_t     mask);
 
   hb_mask_t global_mask;
 
-  hb_tag_t chosen_script[2];
   hb_prealloced_array_t<feature_map_t, 8> features;
   hb_prealloced_array_t<lookup_map_t, 32> lookups[2]; /* GSUB/GPOS */
   hb_prealloced_array_t<pause_map_t, 1> pauses[2]; /* GSUB/GPOS */
 };
 
 
 struct hb_ot_map_builder_t
 {
   public:
 
-  hb_ot_map_builder_t (void) { memset (this, 0, sizeof (*this)); }
+  HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_,
+				   const hb_segment_properties_t *props_);
 
   HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value, bool global, bool has_fallback = false);
 
   inline void add_bool_feature (hb_tag_t tag, bool global = true, bool has_fallback = false)
   { add_feature (tag, 1, global, has_fallback); }
 
   inline void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func)
   { add_pause (0, pause_func); }
   inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func)
   { add_pause (1, pause_func); }
 
-  HB_INTERNAL void compile (hb_face_t *face,
-			    const hb_segment_properties_t *props,
-			    struct hb_ot_map_t &m);
+  HB_INTERNAL void compile (struct hb_ot_map_t &m);
 
   inline void finish (void) {
     feature_infos.finish ();
     pauses[0].finish ();
     pauses[1].finish ();
   }
 
   private:
@@ -190,16 +188,27 @@ struct hb_ot_map_builder_t
 
   struct pause_info_t {
     unsigned int stage;
     hb_ot_map_t::pause_func_t callback;
   };
 
   HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func);
 
+  public:
+
+  hb_face_t *face;
+  hb_segment_properties_t props;
+
+  hb_tag_t chosen_script[2];
+  bool found_script[2];
+  unsigned int script_index[2], language_index[2];
+
+  private:
+
   unsigned int current_stage[2]; /* GSUB/GPOS */
   hb_prealloced_array_t<feature_info_t,16> feature_infos;
   hb_prealloced_array_t<pause_info_t, 1> pauses[2]; /* GSUB/GPOS */
 };
 
 
 
 #endif /* HB_OT_MAP_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-map.cc
+++ b/gfx/harfbuzz/src/hb-ot-map.cc
@@ -36,34 +36,58 @@ hb_ot_map_t::add_lookups (hb_face_t    *
 			  hb_mask_t     mask)
 {
   unsigned int lookup_indices[32];
   unsigned int offset, len;
 
   offset = 0;
   do {
     len = ARRAY_LENGTH (lookup_indices);
-    hb_ot_layout_feature_get_lookup_indexes (face,
-					     table_tags[table_index],
-					     feature_index,
-					     offset, &len,
-					     lookup_indices);
+    hb_ot_layout_feature_get_lookups (face,
+				      table_tags[table_index],
+				      feature_index,
+				      offset, &len,
+				      lookup_indices);
 
     for (unsigned int i = 0; i < len; i++) {
       hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push ();
       if (unlikely (!lookup))
         return;
       lookup->mask = mask;
       lookup->index = lookup_indices[i];
     }
 
     offset += len;
   } while (len == ARRAY_LENGTH (lookup_indices));
 }
 
+hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
+					  const hb_segment_properties_t *props_)
+{
+  memset (this, 0, sizeof (*this));
+
+  face = face_;
+  props = *props_;
+
+
+  /* Fetch script/language indices for GSUB/GPOS.  We need these later to skip
+   * features not available in either table and not waste precious bits for them. */
+
+  hb_tag_t script_tags[3] = {HB_TAG_NONE, HB_TAG_NONE, HB_TAG_NONE};
+  hb_tag_t language_tag;
+
+  hb_ot_tags_from_script (props.script, &script_tags[0], &script_tags[1]);
+  language_tag = hb_ot_tag_from_language (props.language);
+
+  for (unsigned int table_index = 0; table_index < 2; table_index++) {
+    hb_tag_t table_tag = table_tags[table_index];
+    found_script[table_index] = hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]);
+    hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
+  }
+}
 
 void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, bool global, bool has_fallback)
 {
   feature_info_t *info = feature_infos.push();
   if (unlikely (!info)) return;
   info->tag = tag;
   info->seq = feature_infos.len;
   info->max_value = value;
@@ -109,62 +133,46 @@ void hb_ot_map_t::position (const hb_ot_
     if (pause->callback)
       pause->callback (plan, font, buffer);
   }
 
   for (; i < lookups[table_index].len; i++)
     hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
 }
 
-void hb_ot_map_t::substitute_closure (const hb_ot_shape_plan_t *plan, hb_face_t *face, hb_set_t *glyphs) const
+void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
 {
-  unsigned int table_index = 0;
   for (unsigned int i = 0; i < lookups[table_index].len; i++)
-    hb_ot_layout_substitute_closure_lookup (face, lookups[table_index][i].index, glyphs);
+    hb_set_add (lookups_out, lookups[table_index][i].index);
 }
 
 void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
 {
   pause_info_t *p = pauses[table_index].push ();
   if (likely (p)) {
     p->stage = current_stage[table_index];
     p->callback = pause_func;
   }
 
   current_stage[table_index]++;
 }
 
 void
-hb_ot_map_builder_t::compile (hb_face_t *face,
-			      const hb_segment_properties_t *props,
-			      hb_ot_map_t &m)
+hb_ot_map_builder_t::compile (hb_ot_map_t &m)
 {
- m.global_mask = 1;
+  m.global_mask = 1;
+
+  for (unsigned int table_index = 0; table_index < 2; table_index++) {
+    m.chosen_script[table_index] = chosen_script[table_index];
+    m.found_script[table_index] = found_script[table_index];
+  }
 
   if (!feature_infos.len)
     return;
 
-
-  /* Fetch script/language indices for GSUB/GPOS.  We need these later to skip
-   * features not available in either table and not waste precious bits for them. */
-
-  hb_tag_t script_tags[3] = {HB_TAG_NONE};
-  hb_tag_t language_tag;
-
-  hb_ot_tags_from_script (props->script, &script_tags[0], &script_tags[1]);
-  language_tag = hb_ot_tag_from_language (props->language);
-
-  unsigned int script_index[2], language_index[2];
-  for (unsigned int table_index = 0; table_index < 2; table_index++) {
-    hb_tag_t table_tag = table_tags[table_index];
-    hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &m.chosen_script[table_index]);
-    hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
-  }
-
-
   /* Sort features and merge duplicates */
   {
     feature_infos.sort ();
     unsigned int j = 0;
     for (unsigned int i = 1; i < feature_infos.len; i++)
       if (feature_infos[i].tag != feature_infos[j].tag)
 	feature_infos[++j] = feature_infos[i];
       else {
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
@@ -59,25 +59,41 @@ enum {
 static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
 {
   if (likely (hb_in_range<hb_codepoint_t> (u, JOINING_TABLE_FIRST, JOINING_TABLE_LAST))) {
     unsigned int j_type = joining_table[u - JOINING_TABLE_FIRST];
     if (likely (j_type != JOINING_TYPE_X))
       return j_type;
   }
 
-  /* Mongolian joining data is not in ArabicJoining.txt yet */
+  /* Mongolian joining data is not in ArabicJoining.txt yet. */
   if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1800, 0x18AF)))
   {
+    if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1880, 0x1886)))
+      return JOINING_TYPE_U;
+
     /* All letters, SIBE SYLLABLE BOUNDARY MARKER, and NIRUGU are D */
-    if (gen_cat == HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER || u == 0x1807 || u == 0x180A)
+    if ((FLAG(gen_cat) & (FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) |
+			  FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER)))
+	|| u == 0x1807 || u == 0x180A)
       return JOINING_TYPE_D;
   }
 
-  if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x200C, 0x200D))) {
+  /* 'Phags-pa joining data is not in ArabicJoining.txt yet. */
+  if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xA840, 0xA872)))
+  {
+      if (unlikely (u == 0xA872))
+	/* XXX Looks like this should be TYPE_L, but we don't support that yet! */
+	return JOINING_TYPE_R;
+
+      return JOINING_TYPE_D;
+  }
+
+  if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x200C, 0x200D)))
+  {
     return u == 0x200C ? JOINING_TYPE_U : JOINING_TYPE_C;
   }
 
   return (FLAG(gen_cat) & (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))) ?
 	 JOINING_TYPE_T : JOINING_TYPE_U;
 }
 
 static const hb_tag_t arabic_features[] =
@@ -173,18 +189,19 @@ collect_features_arabic (hb_ot_shape_pla
   map->add_gsub_pause (NULL);
 
   map->add_bool_feature (HB_TAG('r','l','i','g'), true, true);
   map->add_gsub_pause (arabic_fallback_shape);
 
   map->add_bool_feature (HB_TAG('c','a','l','t'));
   map->add_gsub_pause (NULL);
 
-  /* ArabicOT spec enables 'cswh' for Arabic where as for basic shaper it's disabled by default. */
   map->add_bool_feature (HB_TAG('c','s','w','h'));
+  map->add_bool_feature (HB_TAG('d','l','i','g'));
+  map->add_bool_feature (HB_TAG('m','s','e','t'));
 }
 
 #include "hb-ot-shape-complex-arabic-fallback.hh"
 
 struct arabic_shape_plan_t
 {
   ASSERT_POD ();
 
@@ -229,27 +246,28 @@ static void
 arabic_joining (hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
   unsigned int prev = (unsigned int) -1, state = 0;
 
   HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
 
   /* Check pre-context */
-  for (unsigned int i = 0; i < buffer->context_len[0]; i++)
-  {
-    unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i]));
+  if (!(buffer->flags & HB_BUFFER_FLAG_BOT))
+    for (unsigned int i = 0; i < buffer->context_len[0]; i++)
+    {
+      unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i]));
 
-    if (unlikely (this_type == JOINING_TYPE_T))
-      continue;
+      if (unlikely (this_type == JOINING_TYPE_T))
+	continue;
 
-    const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
-    state = entry->next_state;
-    break;
-  }
+      const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
+      state = entry->next_state;
+      break;
+    }
 
   for (unsigned int i = 0; i < count; i++)
   {
     unsigned int this_type = get_joining_type (buffer->info[i].codepoint, _hb_glyph_info_get_general_category (&buffer->info[i]));
 
     if (unlikely (this_type == JOINING_TYPE_T)) {
       buffer->info[i].arabic_shaping_action() = NONE;
       continue;
@@ -261,28 +279,29 @@ arabic_joining (hb_buffer_t *buffer)
       buffer->info[prev].arabic_shaping_action() = entry->prev_action;
 
     buffer->info[i].arabic_shaping_action() = entry->curr_action;
 
     prev = i;
     state = entry->next_state;
   }
 
-  for (unsigned int i = 0; i < buffer->context_len[1]; i++)
-  {
-    unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[0][i]));
+  if (!(buffer->flags & HB_BUFFER_FLAG_EOT))
+    for (unsigned int i = 0; i < buffer->context_len[1]; i++)
+    {
+      unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i]));
 
-    if (unlikely (this_type == JOINING_TYPE_T))
-      continue;
+      if (unlikely (this_type == JOINING_TYPE_T))
+	continue;
 
-    const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
-    if (entry->prev_action != NONE && prev != (unsigned int) -1)
-      buffer->info[prev].arabic_shaping_action() = entry->prev_action;
-    break;
-  }
+      const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
+      if (entry->prev_action != NONE && prev != (unsigned int) -1)
+	buffer->info[prev].arabic_shaping_action() = entry->prev_action;
+      break;
+    }
 
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
 }
 
 static void
 setup_masks_arabic (const hb_ot_shape_plan_t *plan,
 		    hb_buffer_t              *buffer,
@@ -327,11 +346,14 @@ const hb_ot_complex_shaper_t _hb_ot_comp
 {
   "arabic",
   collect_features_arabic,
   NULL, /* override_features */
   data_create_arabic,
   data_destroy_arabic,
   NULL, /* preprocess_text_arabic */
   NULL, /* normalization_preference */
+  NULL, /* decompose */
+  NULL, /* compose */
   setup_masks_arabic,
   true, /* zero_width_attached_marks */
+  true, /* fallback_position */
 };
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
@@ -0,0 +1,225 @@
+/*
+ * Copyright © 2010,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+/* TODO Add kana, and other small shapers here */
+
+
+/* The default shaper *only* adds additional per-script features.*/
+
+static const hb_tag_t hangul_features[] =
+{
+  HB_TAG('l','j','m','o'),
+  HB_TAG('v','j','m','o'),
+  HB_TAG('t','j','m','o'),
+  HB_TAG_NONE
+};
+
+static const hb_tag_t tibetan_features[] =
+{
+  HB_TAG('a','b','v','s'),
+  HB_TAG('b','l','w','s'),
+  HB_TAG('a','b','v','m'),
+  HB_TAG('b','l','w','m'),
+  HB_TAG_NONE
+};
+
+static void
+collect_features_default (hb_ot_shape_planner_t *plan)
+{
+  const hb_tag_t *script_features = NULL;
+
+  switch ((hb_tag_t) plan->props.script)
+  {
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_HANGUL:
+      script_features = hangul_features;
+      break;
+
+    /* Unicode-2.0 additions */
+    case HB_SCRIPT_TIBETAN:
+      script_features = tibetan_features;
+      break;
+  }
+
+  for (; script_features && *script_features; script_features++)
+    plan->map.add_bool_feature (*script_features);
+}
+
+static hb_ot_shape_normalization_mode_t
+normalization_preference_default (const hb_segment_properties_t *props)
+{
+  switch ((hb_tag_t) props->script)
+  {
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_HANGUL:
+      return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL;
+  }
+  return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
+}
+
+static bool
+compose_default (const hb_ot_shape_normalize_context_t *c,
+		 hb_codepoint_t  a,
+		 hb_codepoint_t  b,
+		 hb_codepoint_t *ab)
+{
+  /* Hebrew presentation-form shaping.
+   * https://bugzilla.mozilla.org/show_bug.cgi?id=728866 */
+  // Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA;
+  // note that some letters do not have a dagesh presForm encoded
+  static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = {
+    0xFB30, // ALEF
+    0xFB31, // BET
+    0xFB32, // GIMEL
+    0xFB33, // DALET
+    0xFB34, // HE
+    0xFB35, // VAV
+    0xFB36, // ZAYIN
+    0, // HET
+    0xFB38, // TET
+    0xFB39, // YOD
+    0xFB3A, // FINAL KAF
+    0xFB3B, // KAF
+    0xFB3C, // LAMED
+    0, // FINAL MEM
+    0xFB3E, // MEM
+    0, // FINAL NUN
+    0xFB40, // NUN
+    0xFB41, // SAMEKH
+    0, // AYIN
+    0xFB43, // FINAL PE
+    0xFB44, // PE
+    0, // FINAL TSADI
+    0xFB46, // TSADI
+    0xFB47, // QOF
+    0xFB48, // RESH
+    0xFB49, // SHIN
+    0xFB4A // TAV
+  };
+
+  bool found = c->unicode->compose (a, b, ab);
+
+  if (!found && (b & ~0x7F) == 0x0580) {
+      // special-case Hebrew presentation forms that are excluded from
+      // standard normalization, but wanted for old fonts
+      switch (b) {
+      case 0x05B4: // HIRIQ
+	  if (a == 0x05D9) { // YOD
+	      *ab = 0xFB1D;
+	      found = true;
+	  }
+	  break;
+      case 0x05B7: // patah
+	  if (a == 0x05F2) { // YIDDISH YOD YOD
+	      *ab = 0xFB1F;
+	      found = true;
+	  } else if (a == 0x05D0) { // ALEF
+	      *ab = 0xFB2E;
+	      found = true;
+	  }
+	  break;
+      case 0x05B8: // QAMATS
+	  if (a == 0x05D0) { // ALEF
+	      *ab = 0xFB2F;
+	      found = true;
+	  }
+	  break;
+      case 0x05B9: // HOLAM
+	  if (a == 0x05D5) { // VAV
+	      *ab = 0xFB4B;
+	      found = true;
+	  }
+	  break;
+      case 0x05BC: // DAGESH
+	  if (a >= 0x05D0 && a <= 0x05EA) {
+	      *ab = sDageshForms[a - 0x05D0];
+	      found = (*ab != 0);
+	  } else if (a == 0xFB2A) { // SHIN WITH SHIN DOT
+	      *ab = 0xFB2C;
+	      found = true;
+	  } else if (a == 0xFB2B) { // SHIN WITH SIN DOT
+	      *ab = 0xFB2D;
+	      found = true;
+	  }
+	  break;
+      case 0x05BF: // RAFE
+	  switch (a) {
+	  case 0x05D1: // BET
+	      *ab = 0xFB4C;
+	      found = true;
+	      break;
+	  case 0x05DB: // KAF
+	      *ab = 0xFB4D;
+	      found = true;
+	      break;
+	  case 0x05E4: // PE
+	      *ab = 0xFB4E;
+	      found = true;
+	      break;
+	  }
+	  break;
+      case 0x05C1: // SHIN DOT
+	  if (a == 0x05E9) { // SHIN
+	      *ab = 0xFB2A;
+	      found = true;
+	  } else if (a == 0xFB49) { // SHIN WITH DAGESH
+	      *ab = 0xFB2C;
+	      found = true;
+	  }
+	  break;
+      case 0x05C2: // SIN DOT
+	  if (a == 0x05E9) { // SHIN
+	      *ab = 0xFB2B;
+	      found = true;
+	  } else if (a == 0xFB49) { // SHIN WITH DAGESH
+	      *ab = 0xFB2D;
+	      found = true;
+	  }
+	  break;
+      }
+  }
+
+  return found;
+}
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
+{
+  "default",
+  collect_features_default,
+  NULL, /* override_features */
+  NULL, /* data_create */
+  NULL, /* data_destroy */
+  NULL, /* preprocess_text */
+  normalization_preference_default,
+  NULL, /* decompose */
+  compose_default,
+  NULL, /* setup_masks */
+  true, /* zero_width_attached_marks */
+  true, /* fallback_position */
+};
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
@@ -47,54 +47,54 @@ static const unsigned char _indic_syllab
 	5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 4u, 4u, 6u, 6u, 
 	16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 
 	6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 
 	4u, 14u, 4u, 14u, 4u, 14u, 1u, 16u, 13u, 13u, 5u, 7u, 5u, 7u, 7u, 7u, 
 	5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 
 	7u, 7u, 4u, 4u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 
 	6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 
 	4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 1u, 16u, 
-	3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 
-	3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 
-	3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 8u, 14u, 5u, 9u, 9u, 9u, 9u, 9u, 
-	3u, 13u, 3u, 9u, 8u, 9u, 3u, 9u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 
+	3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 
+	3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 
+	3u, 17u, 3u, 14u, 4u, 14u, 5u, 14u, 8u, 14u, 5u, 9u, 9u, 9u, 9u, 9u, 
+	3u, 17u, 3u, 9u, 8u, 9u, 3u, 9u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 
 	5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 
 	4u, 14u, 6u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 
-	1u, 16u, 3u, 14u, 3u, 14u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 
-	3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 
-	3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 8u, 14u, 
-	5u, 9u, 9u, 9u, 9u, 9u, 3u, 13u, 3u, 9u, 8u, 9u, 3u, 9u, 3u, 13u, 
+	1u, 16u, 3u, 14u, 3u, 14u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 
+	3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 
+	3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 5u, 14u, 8u, 14u, 
+	5u, 9u, 9u, 9u, 9u, 9u, 3u, 17u, 3u, 9u, 8u, 9u, 3u, 9u, 3u, 13u, 
 	3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 
 	4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 6u, 14u, 3u, 14u, 1u, 16u, 3u, 14u, 
 	3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 
 	1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 
-	3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 
-	3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 
-	8u, 14u, 5u, 9u, 9u, 9u, 9u, 9u, 3u, 13u, 3u, 9u, 8u, 9u, 3u, 9u, 
+	3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 
+	3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 5u, 14u, 
+	8u, 14u, 5u, 9u, 9u, 9u, 9u, 9u, 3u, 17u, 3u, 9u, 8u, 9u, 3u, 9u, 
 	3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 
 	3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 6u, 14u, 3u, 14u, 1u, 16u, 
 	3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 
 	3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 
 	1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 14u, 3u, 14u, 4u, 14u, 3u, 14u, 
-	3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 
-	3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 
-	3u, 14u, 4u, 14u, 5u, 14u, 8u, 14u, 5u, 9u, 9u, 9u, 9u, 9u, 3u, 13u, 
+	3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 
+	3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 
+	3u, 14u, 4u, 14u, 5u, 14u, 8u, 14u, 5u, 9u, 9u, 9u, 9u, 9u, 3u, 17u, 
 	3u, 9u, 8u, 9u, 3u, 9u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 
 	3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 
 	6u, 14u, 3u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 
 	1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 
 	3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 
-	1u, 16u, 3u, 14u, 1u, 16u, 0
+	1u, 16u, 3u, 17u, 1u, 16u, 0
 };
 
 static const char _indic_syllable_machine_key_spans[] = {
 	16, 1, 3, 3, 1, 3, 3, 1, 
 	3, 3, 1, 3, 3, 1, 1, 1, 
 	1, 4, 1, 1, 4, 1, 1, 4, 
 	1, 1, 11, 11, 11, 11, 11, 11, 
 	11, 11, 11, 11, 16, 1, 3, 3, 
@@ -106,54 +106,54 @@ static const char _indic_syllable_machin
 	3, 3, 1, 3, 3, 1, 1, 1, 
 	1, 4, 1, 1, 4, 1, 1, 4, 
 	1, 1, 11, 11, 11, 11, 11, 11, 
 	11, 11, 11, 16, 1, 3, 3, 1, 
 	3, 3, 1, 3, 3, 1, 3, 3, 
 	1, 1, 1, 1, 4, 1, 1, 4, 
 	1, 1, 4, 1, 1, 11, 11, 11, 
 	11, 11, 11, 11, 11, 11, 11, 16, 
-	12, 12, 11, 16, 12, 12, 11, 16, 
-	12, 12, 11, 16, 12, 12, 11, 16, 
-	12, 12, 11, 10, 7, 5, 1, 1, 
-	11, 7, 2, 7, 11, 12, 12, 11, 
+	15, 12, 11, 16, 15, 12, 11, 16, 
+	15, 12, 11, 16, 15, 12, 11, 16, 
+	15, 12, 11, 10, 7, 5, 1, 1, 
+	15, 7, 2, 7, 11, 12, 12, 11, 
 	10, 12, 11, 10, 12, 11, 10, 12, 
 	11, 9, 12, 11, 16, 12, 12, 16, 
 	16, 16, 16, 16, 12, 12, 16, 16, 
 	16, 16, 16, 12, 12, 16, 16, 16, 
 	16, 16, 12, 12, 16, 16, 16, 16, 
-	16, 12, 12, 12, 12, 11, 16, 12, 
-	12, 11, 16, 12, 12, 11, 16, 12, 
-	12, 11, 16, 12, 12, 11, 10, 7, 
-	5, 1, 1, 11, 7, 2, 7, 11, 
+	16, 12, 12, 12, 12, 11, 16, 15, 
+	12, 11, 16, 15, 12, 11, 16, 15, 
+	12, 11, 16, 15, 12, 11, 10, 7, 
+	5, 1, 1, 15, 7, 2, 7, 11, 
 	12, 12, 11, 10, 12, 11, 10, 12, 
 	11, 10, 12, 11, 9, 12, 16, 12, 
 	12, 16, 16, 16, 16, 16, 12, 12, 
 	16, 16, 16, 16, 16, 12, 12, 16, 
 	16, 16, 16, 16, 12, 12, 16, 16, 
 	16, 16, 11, 16, 12, 12, 11, 16, 
-	12, 12, 11, 16, 12, 12, 11, 16, 
-	12, 12, 11, 16, 12, 12, 11, 10, 
-	7, 5, 1, 1, 11, 7, 2, 7, 
+	15, 12, 11, 16, 15, 12, 11, 16, 
+	15, 12, 11, 16, 15, 12, 11, 10, 
+	7, 5, 1, 1, 15, 7, 2, 7, 
 	11, 12, 12, 11, 10, 12, 11, 10, 
 	12, 11, 10, 12, 11, 9, 12, 16, 
 	12, 12, 16, 16, 16, 16, 16, 12, 
 	12, 16, 16, 16, 16, 16, 12, 12, 
 	16, 16, 16, 16, 16, 12, 12, 16, 
 	16, 16, 16, 16, 11, 12, 11, 12, 
-	12, 11, 16, 12, 12, 11, 16, 12, 
-	12, 11, 16, 12, 12, 11, 16, 12, 
-	12, 11, 10, 7, 5, 1, 1, 11, 
+	12, 11, 16, 15, 12, 11, 16, 15, 
+	12, 11, 16, 15, 12, 11, 16, 15, 
+	12, 11, 10, 7, 5, 1, 1, 15, 
 	7, 2, 7, 11, 12, 12, 11, 10, 
 	12, 11, 10, 12, 11, 10, 12, 11, 
 	9, 12, 16, 12, 12, 16, 16, 16, 
 	16, 16, 12, 12, 16, 16, 16, 16, 
 	16, 12, 12, 16, 16, 16, 16, 16, 
 	12, 12, 16, 16, 16, 16, 16, 12, 
-	16, 12, 16
+	16, 15, 16
 };
 
 static const short _indic_syllable_machine_index_offsets[] = {
 	0, 17, 19, 23, 27, 29, 33, 37, 
 	39, 43, 47, 49, 53, 57, 59, 61, 
 	63, 65, 70, 72, 74, 79, 81, 83, 
 	88, 90, 92, 104, 116, 128, 140, 152, 
 	164, 176, 188, 200, 212, 229, 231, 235, 
@@ -165,54 +165,54 @@ static const short _indic_syllable_machi
 	463, 467, 471, 473, 477, 481, 483, 485, 
 	487, 489, 494, 496, 498, 503, 505, 507, 
 	512, 514, 516, 528, 540, 552, 564, 576, 
 	588, 600, 612, 624, 641, 643, 647, 651, 
 	653, 657, 661, 663, 667, 671, 673, 677, 
 	681, 683, 685, 687, 689, 694, 696, 698, 
 	703, 705, 707, 712, 714, 716, 728, 740, 
 	752, 764, 776, 788, 800, 812, 824, 836, 
-	853, 866, 879, 891, 908, 921, 934, 946, 
-	963, 976, 989, 1001, 1018, 1031, 1044, 1056, 
-	1073, 1086, 1099, 1111, 1122, 1130, 1136, 1138, 
-	1140, 1152, 1160, 1163, 1171, 1183, 1196, 1209, 
-	1221, 1232, 1245, 1257, 1268, 1281, 1293, 1304, 
-	1317, 1329, 1339, 1352, 1364, 1381, 1394, 1407, 
-	1424, 1441, 1458, 1475, 1492, 1505, 1518, 1535, 
-	1552, 1569, 1586, 1603, 1616, 1629, 1646, 1663, 
-	1680, 1697, 1714, 1727, 1740, 1757, 1774, 1791, 
-	1808, 1825, 1838, 1851, 1864, 1877, 1889, 1906, 
-	1919, 1932, 1944, 1961, 1974, 1987, 1999, 2016, 
-	2029, 2042, 2054, 2071, 2084, 2097, 2109, 2120, 
-	2128, 2134, 2136, 2138, 2150, 2158, 2161, 2169, 
-	2181, 2194, 2207, 2219, 2230, 2243, 2255, 2266, 
-	2279, 2291, 2302, 2315, 2327, 2337, 2350, 2367, 
-	2380, 2393, 2410, 2427, 2444, 2461, 2478, 2491, 
-	2504, 2521, 2538, 2555, 2572, 2589, 2602, 2615, 
-	2632, 2649, 2666, 2683, 2700, 2713, 2726, 2743, 
-	2760, 2777, 2794, 2806, 2823, 2836, 2849, 2861, 
-	2878, 2891, 2904, 2916, 2933, 2946, 2959, 2971, 
-	2988, 3001, 3014, 3026, 3043, 3056, 3069, 3081, 
-	3092, 3100, 3106, 3108, 3110, 3122, 3130, 3133, 
-	3141, 3153, 3166, 3179, 3191, 3202, 3215, 3227, 
-	3238, 3251, 3263, 3274, 3287, 3299, 3309, 3322, 
-	3339, 3352, 3365, 3382, 3399, 3416, 3433, 3450, 
-	3463, 3476, 3493, 3510, 3527, 3544, 3561, 3574, 
-	3587, 3604, 3621, 3638, 3655, 3672, 3685, 3698, 
-	3715, 3732, 3749, 3766, 3783, 3795, 3808, 3820, 
-	3833, 3846, 3858, 3875, 3888, 3901, 3913, 3930, 
-	3943, 3956, 3968, 3985, 3998, 4011, 4023, 4040, 
-	4053, 4066, 4078, 4089, 4097, 4103, 4105, 4107, 
-	4119, 4127, 4130, 4138, 4150, 4163, 4176, 4188, 
-	4199, 4212, 4224, 4235, 4248, 4260, 4271, 4284, 
-	4296, 4306, 4319, 4336, 4349, 4362, 4379, 4396, 
-	4413, 4430, 4447, 4460, 4473, 4490, 4507, 4524, 
-	4541, 4558, 4571, 4584, 4601, 4618, 4635, 4652, 
-	4669, 4682, 4695, 4712, 4729, 4746, 4763, 4780, 
-	4793, 4810, 4823
+	853, 869, 882, 894, 911, 927, 940, 952, 
+	969, 985, 998, 1010, 1027, 1043, 1056, 1068, 
+	1085, 1101, 1114, 1126, 1137, 1145, 1151, 1153, 
+	1155, 1171, 1179, 1182, 1190, 1202, 1215, 1228, 
+	1240, 1251, 1264, 1276, 1287, 1300, 1312, 1323, 
+	1336, 1348, 1358, 1371, 1383, 1400, 1413, 1426, 
+	1443, 1460, 1477, 1494, 1511, 1524, 1537, 1554, 
+	1571, 1588, 1605, 1622, 1635, 1648, 1665, 1682, 
+	1699, 1716, 1733, 1746, 1759, 1776, 1793, 1810, 
+	1827, 1844, 1857, 1870, 1883, 1896, 1908, 1925, 
+	1941, 1954, 1966, 1983, 1999, 2012, 2024, 2041, 
+	2057, 2070, 2082, 2099, 2115, 2128, 2140, 2151, 
+	2159, 2165, 2167, 2169, 2185, 2193, 2196, 2204, 
+	2216, 2229, 2242, 2254, 2265, 2278, 2290, 2301, 
+	2314, 2326, 2337, 2350, 2362, 2372, 2385, 2402, 
+	2415, 2428, 2445, 2462, 2479, 2496, 2513, 2526, 
+	2539, 2556, 2573, 2590, 2607, 2624, 2637, 2650, 
+	2667, 2684, 2701, 2718, 2735, 2748, 2761, 2778, 
+	2795, 2812, 2829, 2841, 2858, 2871, 2884, 2896, 
+	2913, 2929, 2942, 2954, 2971, 2987, 3000, 3012, 
+	3029, 3045, 3058, 3070, 3087, 3103, 3116, 3128, 
+	3139, 3147, 3153, 3155, 3157, 3173, 3181, 3184, 
+	3192, 3204, 3217, 3230, 3242, 3253, 3266, 3278, 
+	3289, 3302, 3314, 3325, 3338, 3350, 3360, 3373, 
+	3390, 3403, 3416, 3433, 3450, 3467, 3484, 3501, 
+	3514, 3527, 3544, 3561, 3578, 3595, 3612, 3625, 
+	3638, 3655, 3672, 3689, 3706, 3723, 3736, 3749, 
+	3766, 3783, 3800, 3817, 3834, 3846, 3859, 3871, 
+	3884, 3897, 3909, 3926, 3942, 3955, 3967, 3984, 
+	4000, 4013, 4025, 4042, 4058, 4071, 4083, 4100, 
+	4116, 4129, 4141, 4152, 4160, 4166, 4168, 4170, 
+	4186, 4194, 4197, 4205, 4217, 4230, 4243, 4255, 
+	4266, 4279, 4291, 4302, 4315, 4327, 4338, 4351, 
+	4363, 4373, 4386, 4403, 4416, 4429, 4446, 4463, 
+	4480, 4497, 4514, 4527, 4540, 4557, 4574, 4591, 
+	4608, 4625, 4638, 4651, 4668, 4685, 4702, 4719, 
+	4736, 4749, 4762, 4779, 4796, 4813, 4830, 4847, 
+	4860, 4877, 4893
 };
 
 static const short _indic_syllable_machine_indicies[] = {
 	1, 2, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 1, 
 	0, 3, 0, 4, 4, 5, 0, 6, 
 	6, 5, 0, 5, 0, 7, 7, 8, 
 	0, 9, 9, 8, 0, 8, 0, 10, 
@@ -314,514 +314,522 @@ static const short _indic_syllable_machi
 	148, 118, 118, 119, 114, 114, 114, 114, 
 	114, 149, 148, 114, 150, 118, 118, 119, 
 	114, 114, 114, 114, 114, 114, 150, 114, 
 	150, 118, 118, 119, 114, 114, 114, 114, 
 	114, 151, 150, 114, 153, 154, 155, 156, 
 	157, 158, 81, 159, 160, 152, 161, 161, 
 	162, 163, 164, 165, 152, 167, 168, 169, 
 	170, 5, 171, 172, 173, 166, 166, 37, 
-	174, 166, 175, 168, 176, 176, 5, 171, 
-	172, 173, 166, 166, 166, 174, 166, 168, 
-	176, 176, 5, 171, 172, 173, 166, 166, 
-	166, 174, 166, 177, 166, 166, 166, 18, 
-	178, 166, 171, 172, 166, 166, 166, 166, 
-	179, 166, 177, 166, 180, 181, 182, 183, 
-	5, 171, 172, 173, 166, 166, 35, 184, 
-	166, 185, 181, 186, 186, 5, 171, 172, 
-	173, 166, 166, 166, 184, 166, 181, 186, 
-	186, 5, 171, 172, 173, 166, 166, 166, 
-	184, 166, 187, 166, 166, 166, 18, 188, 
+	174, 166, 166, 153, 166, 175, 168, 176, 
+	176, 5, 171, 172, 173, 166, 166, 166, 
+	174, 166, 168, 176, 176, 5, 171, 172, 
+	173, 166, 166, 166, 174, 166, 177, 166, 
+	166, 166, 18, 178, 166, 171, 172, 166, 
+	166, 166, 166, 179, 166, 177, 166, 180, 
+	181, 182, 183, 5, 171, 172, 173, 166, 
+	166, 35, 184, 166, 166, 177, 166, 185, 
+	181, 186, 186, 5, 171, 172, 173, 166, 
+	166, 166, 184, 166, 181, 186, 186, 5, 
+	171, 172, 173, 166, 166, 166, 184, 166, 
+	187, 166, 166, 166, 18, 188, 166, 171, 
+	172, 166, 166, 166, 166, 179, 166, 187, 
+	166, 189, 190, 191, 192, 5, 171, 172, 
+	173, 166, 166, 33, 193, 166, 166, 187, 
+	166, 194, 190, 195, 195, 5, 171, 172, 
+	173, 166, 166, 166, 193, 166, 190, 195, 
+	195, 5, 171, 172, 173, 166, 166, 166, 
+	193, 166, 196, 166, 166, 166, 18, 197, 
 	166, 171, 172, 166, 166, 166, 166, 179, 
-	166, 187, 166, 189, 190, 191, 192, 5, 
-	171, 172, 173, 166, 166, 33, 193, 166, 
-	194, 190, 195, 195, 5, 171, 172, 173, 
-	166, 166, 166, 193, 166, 190, 195, 195, 
-	5, 171, 172, 173, 166, 166, 166, 193, 
-	166, 196, 166, 166, 166, 18, 197, 166, 
-	171, 172, 166, 166, 166, 166, 179, 166, 
-	196, 166, 198, 199, 200, 201, 5, 171, 
-	172, 173, 166, 166, 31, 202, 166, 203, 
-	199, 204, 204, 5, 171, 172, 173, 166, 
-	166, 166, 202, 166, 199, 204, 204, 5, 
+	166, 196, 166, 198, 199, 200, 201, 5, 
+	171, 172, 173, 166, 166, 31, 202, 166, 
+	166, 196, 166, 203, 199, 204, 204, 5, 
 	171, 172, 173, 166, 166, 166, 202, 166, 
-	205, 166, 166, 166, 18, 206, 166, 171, 
-	172, 166, 166, 166, 166, 179, 166, 205, 
-	166, 207, 208, 209, 210, 5, 171, 172, 
-	173, 166, 166, 29, 211, 166, 212, 208, 
-	213, 213, 5, 171, 172, 173, 166, 166, 
-	166, 211, 166, 208, 213, 213, 5, 171, 
-	172, 173, 166, 166, 166, 211, 166, 18, 
-	214, 166, 171, 172, 166, 166, 166, 166, 
-	179, 166, 171, 172, 166, 166, 166, 166, 
-	179, 166, 215, 166, 166, 166, 172, 166, 
-	172, 166, 216, 166, 217, 166, 218, 219, 
-	166, 171, 172, 166, 166, 166, 3, 166, 
-	2, 166, 166, 166, 166, 171, 172, 166, 
-	171, 172, 166, 217, 166, 166, 166, 166, 
-	171, 172, 166, 217, 166, 218, 166, 166, 
-	171, 172, 166, 166, 166, 3, 166, 18, 
-	166, 220, 220, 5, 171, 172, 166, 166, 
-	166, 166, 179, 166, 221, 27, 222, 223, 
-	8, 171, 172, 166, 166, 166, 166, 179, 
-	166, 27, 222, 223, 8, 171, 172, 166, 
-	166, 166, 166, 179, 166, 222, 222, 8, 
-	171, 172, 166, 166, 166, 166, 179, 166, 
-	224, 24, 225, 226, 11, 171, 172, 166, 
-	166, 166, 166, 179, 166, 24, 225, 226, 
-	11, 171, 172, 166, 166, 166, 166, 179, 
-	166, 225, 225, 11, 171, 172, 166, 166, 
-	166, 166, 179, 166, 227, 21, 228, 229, 
-	14, 171, 172, 166, 166, 166, 166, 179, 
-	166, 21, 228, 229, 14, 171, 172, 166, 
-	166, 166, 166, 179, 166, 228, 228, 14, 
-	171, 172, 166, 166, 166, 166, 179, 166, 
-	230, 18, 166, 231, 166, 171, 172, 166, 
-	166, 166, 166, 179, 166, 18, 166, 231, 
+	199, 204, 204, 5, 171, 172, 173, 166, 
+	166, 166, 202, 166, 205, 166, 166, 166, 
+	18, 206, 166, 171, 172, 166, 166, 166, 
+	166, 179, 166, 205, 166, 207, 208, 209, 
+	210, 5, 171, 172, 173, 166, 166, 29, 
+	211, 166, 166, 205, 166, 212, 208, 213, 
+	213, 5, 171, 172, 173, 166, 166, 166, 
+	211, 166, 208, 213, 213, 5, 171, 172, 
+	173, 166, 166, 166, 211, 166, 18, 214, 
+	166, 171, 172, 166, 166, 166, 166, 179, 
 	166, 171, 172, 166, 166, 166, 166, 179, 
-	166, 232, 166, 171, 172, 166, 166, 166, 
-	166, 179, 166, 18, 166, 166, 166, 166, 
+	166, 215, 166, 166, 166, 172, 166, 172, 
+	166, 216, 166, 217, 166, 218, 219, 166, 
+	171, 172, 166, 166, 166, 3, 166, 166, 
+	166, 1, 166, 2, 166, 166, 166, 166, 
+	171, 172, 166, 171, 172, 166, 217, 166, 
+	166, 166, 166, 171, 172, 166, 217, 166, 
+	218, 166, 166, 171, 172, 166, 166, 166, 
+	3, 166, 18, 166, 220, 220, 5, 171, 
+	172, 166, 166, 166, 166, 179, 166, 221, 
+	27, 222, 223, 8, 171, 172, 166, 166, 
+	166, 166, 179, 166, 27, 222, 223, 8, 
+	171, 172, 166, 166, 166, 166, 179, 166, 
+	222, 222, 8, 171, 172, 166, 166, 166, 
+	166, 179, 166, 224, 24, 225, 226, 11, 
+	171, 172, 166, 166, 166, 166, 179, 166, 
+	24, 225, 226, 11, 171, 172, 166, 166, 
+	166, 166, 179, 166, 225, 225, 11, 171, 
+	172, 166, 166, 166, 166, 179, 166, 227, 
+	21, 228, 229, 14, 171, 172, 166, 166, 
+	166, 166, 179, 166, 21, 228, 229, 14, 
+	171, 172, 166, 166, 166, 166, 179, 166, 
+	228, 228, 14, 171, 172, 166, 166, 166, 
+	166, 179, 166, 230, 18, 166, 231, 166, 
 	171, 172, 166, 166, 166, 166, 179, 166, 
-	208, 213, 213, 5, 171, 172, 166, 166, 
-	166, 166, 211, 166, 1, 2, 166, 166, 
-	18, 214, 166, 171, 172, 166, 166, 166, 
-	166, 179, 166, 1, 166, 207, 208, 213, 
-	213, 5, 171, 172, 173, 166, 166, 166, 
-	211, 166, 207, 208, 209, 213, 5, 171, 
-	172, 173, 166, 166, 29, 211, 166, 205, 
-	166, 233, 166, 220, 220, 5, 171, 172, 
-	166, 166, 166, 166, 179, 166, 205, 166, 
-	205, 166, 166, 166, 166, 166, 166, 171, 
-	172, 166, 166, 166, 166, 179, 166, 205, 
-	166, 205, 166, 166, 166, 166, 234, 166, 
+	18, 166, 231, 166, 171, 172, 166, 166, 
+	166, 166, 179, 166, 232, 166, 171, 172, 
+	166, 166, 166, 166, 179, 166, 18, 166, 
+	166, 166, 166, 171, 172, 166, 166, 166, 
+	166, 179, 166, 208, 213, 213, 5, 171, 
+	172, 166, 166, 166, 166, 211, 166, 1, 
+	2, 166, 166, 18, 214, 166, 171, 172, 
+	166, 166, 166, 166, 179, 166, 1, 166, 
+	207, 208, 213, 213, 5, 171, 172, 173, 
+	166, 166, 166, 211, 166, 207, 208, 209, 
+	213, 5, 171, 172, 173, 166, 166, 29, 
+	211, 166, 205, 166, 233, 166, 220, 220, 
+	5, 171, 172, 166, 166, 166, 166, 179, 
+	166, 205, 166, 205, 166, 166, 166, 166, 
+	166, 166, 171, 172, 166, 166, 166, 166, 
+	179, 166, 205, 166, 205, 166, 166, 166, 
+	166, 234, 166, 171, 172, 166, 166, 166, 
+	166, 179, 166, 205, 166, 205, 166, 233, 
+	166, 166, 166, 166, 171, 172, 166, 166, 
+	166, 166, 179, 166, 205, 166, 205, 2, 
+	166, 166, 18, 206, 166, 171, 172, 166, 
+	166, 166, 166, 179, 166, 205, 166, 198, 
+	199, 204, 204, 5, 171, 172, 173, 166, 
+	166, 166, 202, 166, 198, 199, 200, 204, 
+	5, 171, 172, 173, 166, 166, 31, 202, 
+	166, 196, 166, 235, 166, 220, 220, 5, 
 	171, 172, 166, 166, 166, 166, 179, 166, 
-	205, 166, 205, 166, 233, 166, 166, 166, 
+	196, 166, 196, 166, 166, 166, 166, 166, 
 	166, 171, 172, 166, 166, 166, 166, 179, 
-	166, 205, 166, 205, 2, 166, 166, 18, 
-	206, 166, 171, 172, 166, 166, 166, 166, 
-	179, 166, 205, 166, 198, 199, 204, 204, 
-	5, 171, 172, 173, 166, 166, 166, 202, 
-	166, 198, 199, 200, 204, 5, 171, 172, 
-	173, 166, 166, 31, 202, 166, 196, 166, 
-	235, 166, 220, 220, 5, 171, 172, 166, 
-	166, 166, 166, 179, 166, 196, 166, 196, 
-	166, 166, 166, 166, 166, 166, 171, 172, 
-	166, 166, 166, 166, 179, 166, 196, 166, 
-	196, 166, 166, 166, 166, 236, 166, 171, 
-	172, 166, 166, 166, 166, 179, 166, 196, 
-	166, 196, 166, 235, 166, 166, 166, 166, 
+	166, 196, 166, 196, 166, 166, 166, 166, 
+	236, 166, 171, 172, 166, 166, 166, 166, 
+	179, 166, 196, 166, 196, 166, 235, 166, 
+	166, 166, 166, 171, 172, 166, 166, 166, 
+	166, 179, 166, 196, 166, 196, 2, 166, 
+	166, 18, 197, 166, 171, 172, 166, 166, 
+	166, 166, 179, 166, 196, 166, 189, 190, 
+	195, 195, 5, 171, 172, 173, 166, 166, 
+	166, 193, 166, 189, 190, 191, 195, 5, 
+	171, 172, 173, 166, 166, 33, 193, 166, 
+	187, 166, 237, 166, 220, 220, 5, 171, 
+	172, 166, 166, 166, 166, 179, 166, 187, 
+	166, 187, 166, 166, 166, 166, 166, 166, 
 	171, 172, 166, 166, 166, 166, 179, 166, 
-	196, 166, 196, 2, 166, 166, 18, 197, 
+	187, 166, 187, 166, 166, 166, 166, 238, 
 	166, 171, 172, 166, 166, 166, 166, 179, 
-	166, 196, 166, 189, 190, 195, 195, 5, 
-	171, 172, 173, 166, 166, 166, 193, 166, 
-	189, 190, 191, 195, 5, 171, 172, 173, 
-	166, 166, 33, 193, 166, 187, 166, 237, 
-	166, 220, 220, 5, 171, 172, 166, 166, 
-	166, 166, 179, 166, 187, 166, 187, 166, 
-	166, 166, 166, 166, 166, 171, 172, 166, 
-	166, 166, 166, 179, 166, 187, 166, 187, 
-	166, 166, 166, 166, 238, 166, 171, 172, 
-	166, 166, 166, 166, 179, 166, 187, 166, 
-	187, 166, 237, 166, 166, 166, 166, 171, 
-	172, 166, 166, 166, 166, 179, 166, 187, 
-	166, 187, 2, 166, 166, 18, 188, 166, 
-	171, 172, 166, 166, 166, 166, 179, 166, 
-	187, 166, 180, 181, 186, 186, 5, 171, 
-	172, 173, 166, 166, 166, 184, 166, 180, 
-	181, 182, 186, 5, 171, 172, 173, 166, 
-	166, 35, 184, 166, 177, 166, 239, 166, 
-	220, 220, 5, 171, 172, 166, 166, 166, 
-	166, 179, 166, 177, 166, 177, 166, 166, 
-	166, 166, 166, 166, 171, 172, 166, 166, 
-	166, 166, 179, 166, 177, 166, 177, 166, 
-	166, 166, 166, 240, 166, 171, 172, 166, 
-	166, 166, 166, 179, 166, 177, 166, 177, 
-	166, 239, 166, 166, 166, 166, 171, 172, 
+	166, 187, 166, 187, 166, 237, 166, 166, 
+	166, 166, 171, 172, 166, 166, 166, 166, 
+	179, 166, 187, 166, 187, 2, 166, 166, 
+	18, 188, 166, 171, 172, 166, 166, 166, 
+	166, 179, 166, 187, 166, 180, 181, 186, 
+	186, 5, 171, 172, 173, 166, 166, 166, 
+	184, 166, 180, 181, 182, 186, 5, 171, 
+	172, 173, 166, 166, 35, 184, 166, 177, 
+	166, 239, 166, 220, 220, 5, 171, 172, 
 	166, 166, 166, 166, 179, 166, 177, 166, 
-	177, 2, 166, 166, 18, 178, 166, 171, 
+	177, 166, 166, 166, 166, 166, 166, 171, 
 	172, 166, 166, 166, 166, 179, 166, 177, 
-	166, 167, 168, 176, 176, 5, 171, 172, 
-	173, 166, 166, 166, 174, 166, 167, 168, 
-	169, 176, 5, 171, 172, 173, 166, 166, 
-	37, 174, 166, 242, 243, 244, 245, 43, 
-	246, 247, 241, 241, 241, 75, 248, 241, 
-	249, 243, 250, 245, 43, 246, 247, 241, 
-	241, 241, 241, 248, 241, 243, 250, 245, 
-	43, 246, 247, 241, 241, 241, 241, 248, 
-	241, 251, 241, 241, 241, 56, 252, 241, 
-	246, 247, 241, 241, 241, 241, 253, 241, 
-	251, 241, 254, 255, 256, 257, 43, 246, 
-	247, 241, 241, 241, 73, 258, 241, 259, 
-	255, 260, 260, 43, 246, 247, 241, 241, 
-	241, 241, 258, 241, 255, 260, 260, 43, 
-	246, 247, 241, 241, 241, 241, 258, 241, 
-	261, 241, 241, 241, 56, 262, 241, 246, 
-	247, 241, 241, 241, 241, 253, 241, 261, 
-	241, 263, 264, 265, 266, 43, 246, 247, 
-	241, 241, 241, 71, 267, 241, 268, 264, 
-	269, 269, 43, 246, 247, 241, 241, 241, 
-	241, 267, 241, 264, 269, 269, 43, 246, 
-	247, 241, 241, 241, 241, 267, 241, 270, 
-	241, 241, 241, 56, 271, 241, 246, 247, 
-	241, 241, 241, 241, 253, 241, 270, 241, 
-	272, 273, 274, 275, 43, 246, 247, 241, 
-	241, 241, 69, 276, 241, 277, 273, 278, 
-	278, 43, 246, 247, 241, 241, 241, 241, 
-	276, 241, 273, 278, 278, 43, 246, 247, 
-	241, 241, 241, 241, 276, 241, 279, 241, 
-	241, 241, 56, 280, 241, 246, 247, 241, 
-	241, 241, 241, 253, 241, 279, 241, 281, 
-	282, 283, 284, 43, 246, 247, 241, 241, 
-	241, 67, 285, 241, 286, 282, 287, 287, 
-	43, 246, 247, 241, 241, 241, 241, 285, 
-	241, 282, 287, 287, 43, 246, 247, 241, 
-	241, 241, 241, 285, 241, 56, 288, 241, 
-	246, 247, 241, 241, 241, 241, 253, 241, 
-	246, 247, 241, 241, 241, 241, 253, 241, 
-	289, 241, 241, 241, 247, 241, 247, 241, 
-	290, 241, 291, 241, 292, 293, 241, 246, 
-	247, 241, 241, 241, 41, 241, 40, 241, 
-	241, 241, 241, 246, 247, 241, 246, 247, 
-	241, 291, 241, 241, 241, 241, 246, 247, 
-	241, 291, 241, 292, 241, 241, 246, 247, 
-	241, 241, 241, 41, 241, 56, 241, 294, 
-	294, 43, 246, 247, 241, 241, 241, 241, 
-	253, 241, 295, 65, 296, 297, 46, 246, 
-	247, 241, 241, 241, 241, 253, 241, 65, 
-	296, 297, 46, 246, 247, 241, 241, 241, 
-	241, 253, 241, 296, 296, 46, 246, 247, 
-	241, 241, 241, 241, 253, 241, 298, 62, 
-	299, 300, 49, 246, 247, 241, 241, 241, 
-	241, 253, 241, 62, 299, 300, 49, 246, 
-	247, 241, 241, 241, 241, 253, 241, 299, 
-	299, 49, 246, 247, 241, 241, 241, 241, 
-	253, 241, 301, 59, 302, 303, 52, 246, 
-	247, 241, 241, 241, 241, 253, 241, 59, 
-	302, 303, 52, 246, 247, 241, 241, 241, 
-	241, 253, 241, 302, 302, 52, 246, 247, 
-	241, 241, 241, 241, 253, 241, 304, 56, 
-	241, 305, 241, 246, 247, 241, 241, 241, 
-	241, 253, 241, 56, 241, 305, 241, 246, 
-	247, 241, 241, 241, 241, 253, 241, 306, 
-	241, 246, 247, 241, 241, 241, 241, 253, 
-	241, 56, 241, 241, 241, 241, 246, 247, 
-	241, 241, 241, 241, 253, 241, 39, 40, 
-	241, 241, 56, 288, 241, 246, 247, 241, 
-	241, 241, 241, 253, 241, 39, 241, 281, 
-	282, 287, 287, 43, 246, 247, 241, 241, 
-	241, 241, 285, 241, 281, 282, 283, 287, 
-	43, 246, 247, 241, 241, 241, 67, 285, 
-	241, 279, 241, 307, 241, 294, 294, 43, 
-	246, 247, 241, 241, 241, 241, 253, 241, 
-	279, 241, 279, 241, 241, 241, 241, 241, 
-	241, 246, 247, 241, 241, 241, 241, 253, 
-	241, 279, 241, 279, 241, 241, 241, 241, 
-	308, 241, 246, 247, 241, 241, 241, 241, 
-	253, 241, 279, 241, 279, 241, 307, 241, 
-	241, 241, 241, 246, 247, 241, 241, 241, 
-	241, 253, 241, 279, 241, 279, 40, 241, 
-	241, 56, 280, 241, 246, 247, 241, 241, 
-	241, 241, 253, 241, 279, 241, 272, 273, 
-	278, 278, 43, 246, 247, 241, 241, 241, 
-	241, 276, 241, 272, 273, 274, 278, 43, 
-	246, 247, 241, 241, 241, 69, 276, 241, 
-	270, 241, 309, 241, 294, 294, 43, 246, 
-	247, 241, 241, 241, 241, 253, 241, 270, 
-	241, 270, 241, 241, 241, 241, 241, 241, 
-	246, 247, 241, 241, 241, 241, 253, 241, 
-	270, 241, 270, 241, 241, 241, 241, 310, 
-	241, 246, 247, 241, 241, 241, 241, 253, 
-	241, 270, 241, 270, 241, 309, 241, 241, 
-	241, 241, 246, 247, 241, 241, 241, 241, 
-	253, 241, 270, 241, 270, 40, 241, 241, 
-	56, 271, 241, 246, 247, 241, 241, 241, 
-	241, 253, 241, 270, 241, 263, 264, 269, 
-	269, 43, 246, 247, 241, 241, 241, 241, 
-	267, 241, 263, 264, 265, 269, 43, 246, 
-	247, 241, 241, 241, 71, 267, 241, 261, 
-	241, 311, 241, 294, 294, 43, 246, 247, 
-	241, 241, 241, 241, 253, 241, 261, 241, 
-	261, 241, 241, 241, 241, 241, 241, 246, 
-	247, 241, 241, 241, 241, 253, 241, 261, 
-	241, 261, 241, 241, 241, 241, 312, 241, 
-	246, 247, 241, 241, 241, 241, 253, 241, 
-	261, 241, 261, 241, 311, 241, 241, 241, 
-	241, 246, 247, 241, 241, 241, 241, 253, 
-	241, 261, 241, 261, 40, 241, 241, 56, 
-	262, 241, 246, 247, 241, 241, 241, 241, 
-	253, 241, 261, 241, 254, 255, 260, 260, 
-	43, 246, 247, 241, 241, 241, 241, 258, 
-	241, 254, 255, 256, 260, 43, 246, 247, 
-	241, 241, 241, 73, 258, 241, 251, 241, 
-	313, 241, 294, 294, 43, 246, 247, 241, 
-	241, 241, 241, 253, 241, 251, 241, 251, 
-	241, 241, 241, 241, 241, 241, 246, 247, 
-	241, 241, 241, 241, 253, 241, 251, 241, 
-	251, 241, 241, 241, 241, 314, 241, 246, 
-	247, 241, 241, 241, 241, 253, 241, 251, 
-	241, 251, 241, 313, 241, 241, 241, 241, 
-	246, 247, 241, 241, 241, 241, 253, 241, 
-	251, 241, 74, 42, 42, 43, 241, 241, 
-	241, 241, 241, 241, 74, 241, 251, 40, 
-	241, 241, 56, 252, 241, 246, 247, 241, 
-	241, 241, 241, 253, 241, 251, 241, 242, 
+	166, 177, 166, 166, 166, 166, 240, 166, 
+	171, 172, 166, 166, 166, 166, 179, 166, 
+	177, 166, 177, 166, 239, 166, 166, 166, 
+	166, 171, 172, 166, 166, 166, 166, 179, 
+	166, 177, 166, 177, 2, 166, 166, 18, 
+	178, 166, 171, 172, 166, 166, 166, 166, 
+	179, 166, 177, 166, 167, 168, 176, 176, 
+	5, 171, 172, 173, 166, 166, 166, 174, 
+	166, 167, 168, 169, 176, 5, 171, 172, 
+	173, 166, 166, 37, 174, 166, 242, 243, 
+	244, 245, 43, 246, 247, 241, 241, 241, 
+	75, 248, 241, 249, 243, 250, 245, 43, 
+	246, 247, 241, 241, 241, 241, 248, 241, 
 	243, 250, 245, 43, 246, 247, 241, 241, 
-	241, 241, 248, 241, 316, 156, 317, 317, 
-	81, 159, 160, 315, 315, 315, 315, 163, 
-	315, 156, 317, 317, 81, 159, 160, 315, 
-	315, 315, 315, 163, 315, 318, 315, 315, 
-	315, 95, 319, 315, 159, 160, 315, 315, 
-	315, 315, 320, 315, 318, 315, 321, 322, 
-	323, 324, 81, 159, 160, 315, 315, 315, 
-	112, 325, 315, 326, 322, 327, 327, 81, 
-	159, 160, 315, 315, 315, 315, 325, 315, 
-	322, 327, 327, 81, 159, 160, 315, 315, 
-	315, 315, 325, 315, 328, 315, 315, 315, 
-	95, 329, 315, 159, 160, 315, 315, 315, 
-	315, 320, 315, 328, 315, 330, 331, 332, 
-	333, 81, 159, 160, 315, 315, 315, 110, 
-	334, 315, 335, 331, 336, 336, 81, 159, 
-	160, 315, 315, 315, 315, 334, 315, 331, 
-	336, 336, 81, 159, 160, 315, 315, 315, 
-	315, 334, 315, 337, 315, 315, 315, 95, 
-	338, 315, 159, 160, 315, 315, 315, 315, 
-	320, 315, 337, 315, 339, 340, 341, 342, 
-	81, 159, 160, 315, 315, 315, 108, 343, 
-	315, 344, 340, 345, 345, 81, 159, 160, 
-	315, 315, 315, 315, 343, 315, 340, 345, 
-	345, 81, 159, 160, 315, 315, 315, 315, 
-	343, 315, 346, 315, 315, 315, 95, 347, 
-	315, 159, 160, 315, 315, 315, 315, 320, 
-	315, 346, 315, 348, 349, 350, 351, 81, 
-	159, 160, 315, 315, 315, 106, 352, 315, 
-	353, 349, 354, 354, 81, 159, 160, 315, 
-	315, 315, 315, 352, 315, 349, 354, 354, 
-	81, 159, 160, 315, 315, 315, 315, 352, 
-	315, 95, 355, 315, 159, 160, 315, 315, 
-	315, 315, 320, 315, 159, 160, 315, 315, 
-	315, 315, 320, 315, 356, 315, 315, 315, 
-	160, 315, 160, 315, 357, 315, 358, 315, 
-	359, 360, 315, 159, 160, 315, 315, 315, 
-	79, 315, 78, 315, 315, 315, 315, 159, 
-	160, 315, 159, 160, 315, 358, 315, 315, 
-	315, 315, 159, 160, 315, 358, 315, 359, 
-	315, 315, 159, 160, 315, 315, 315, 79, 
-	315, 95, 315, 361, 361, 81, 159, 160, 
-	315, 315, 315, 315, 320, 315, 362, 104, 
-	363, 364, 85, 159, 160, 315, 315, 315, 
-	315, 320, 315, 104, 363, 364, 85, 159, 
-	160, 315, 315, 315, 315, 320, 315, 363, 
-	363, 85, 159, 160, 315, 315, 315, 315, 
-	320, 315, 365, 101, 366, 367, 88, 159, 
-	160, 315, 315, 315, 315, 320, 315, 101, 
-	366, 367, 88, 159, 160, 315, 315, 315, 
-	315, 320, 315, 366, 366, 88, 159, 160, 
-	315, 315, 315, 315, 320, 315, 368, 98, 
-	369, 370, 91, 159, 160, 315, 315, 315, 
-	315, 320, 315, 98, 369, 370, 91, 159, 
-	160, 315, 315, 315, 315, 320, 315, 369, 
-	369, 91, 159, 160, 315, 315, 315, 315, 
-	320, 315, 371, 95, 315, 372, 315, 159, 
-	160, 315, 315, 315, 315, 320, 315, 95, 
-	315, 372, 315, 159, 160, 315, 315, 315, 
-	315, 320, 315, 373, 315, 159, 160, 315, 
-	315, 315, 315, 320, 315, 95, 315, 315, 
-	315, 315, 159, 160, 315, 315, 315, 315, 
-	320, 315, 77, 78, 315, 315, 95, 355, 
-	315, 159, 160, 315, 315, 315, 315, 320, 
-	315, 77, 315, 348, 349, 354, 354, 81, 
-	159, 160, 315, 315, 315, 315, 352, 315, 
-	348, 349, 350, 354, 81, 159, 160, 315, 
-	315, 315, 106, 352, 315, 346, 315, 374, 
-	315, 361, 361, 81, 159, 160, 315, 315, 
-	315, 315, 320, 315, 346, 315, 346, 315, 
-	315, 315, 315, 315, 315, 159, 160, 315, 
-	315, 315, 315, 320, 315, 346, 315, 346, 
-	315, 315, 315, 315, 375, 315, 159, 160, 
-	315, 315, 315, 315, 320, 315, 346, 315, 
-	346, 315, 374, 315, 315, 315, 315, 159, 
-	160, 315, 315, 315, 315, 320, 315, 346, 
-	315, 346, 78, 315, 315, 95, 347, 315, 
-	159, 160, 315, 315, 315, 315, 320, 315, 
-	346, 315, 339, 340, 345, 345, 81, 159, 
-	160, 315, 315, 315, 315, 343, 315, 339, 
-	340, 341, 345, 81, 159, 160, 315, 315, 
-	315, 108, 343, 315, 337, 315, 376, 315, 
-	361, 361, 81, 159, 160, 315, 315, 315, 
-	315, 320, 315, 337, 315, 337, 315, 315, 
-	315, 315, 315, 315, 159, 160, 315, 315, 
-	315, 315, 320, 315, 337, 315, 337, 315, 
-	315, 315, 315, 377, 315, 159, 160, 315, 
-	315, 315, 315, 320, 315, 337, 315, 337, 
-	315, 376, 315, 315, 315, 315, 159, 160, 
-	315, 315, 315, 315, 320, 315, 337, 315, 
-	337, 78, 315, 315, 95, 338, 315, 159, 
-	160, 315, 315, 315, 315, 320, 315, 337, 
-	315, 330, 331, 336, 336, 81, 159, 160, 
-	315, 315, 315, 315, 334, 315, 330, 331, 
-	332, 336, 81, 159, 160, 315, 315, 315, 
-	110, 334, 315, 328, 315, 378, 315, 361, 
-	361, 81, 159, 160, 315, 315, 315, 315, 
-	320, 315, 328, 315, 328, 315, 315, 315, 
-	315, 315, 315, 159, 160, 315, 315, 315, 
-	315, 320, 315, 328, 315, 328, 315, 315, 
-	315, 315, 379, 315, 159, 160, 315, 315, 
-	315, 315, 320, 315, 328, 315, 328, 315, 
-	378, 315, 315, 315, 315, 159, 160, 315, 
-	315, 315, 315, 320, 315, 328, 315, 328, 
-	78, 315, 315, 95, 329, 315, 159, 160, 
-	315, 315, 315, 315, 320, 315, 328, 315, 
-	321, 322, 327, 327, 81, 159, 160, 315, 
-	315, 315, 315, 325, 315, 321, 322, 323, 
-	327, 81, 159, 160, 315, 315, 315, 112, 
-	325, 315, 318, 315, 380, 315, 361, 361, 
-	81, 159, 160, 315, 315, 315, 315, 320, 
-	315, 318, 315, 318, 315, 315, 315, 315, 
-	315, 315, 159, 160, 315, 315, 315, 315, 
-	320, 315, 318, 315, 318, 315, 315, 315, 
-	315, 381, 315, 159, 160, 315, 315, 315, 
-	315, 320, 315, 318, 315, 318, 315, 380, 
-	315, 315, 315, 315, 159, 160, 315, 315, 
-	315, 315, 320, 315, 318, 315, 318, 78, 
-	315, 315, 95, 319, 315, 159, 160, 315, 
-	315, 315, 315, 320, 315, 318, 315, 113, 
-	80, 80, 81, 382, 382, 382, 382, 382, 
-	162, 113, 382, 155, 156, 317, 317, 81, 
+	241, 241, 248, 241, 251, 241, 241, 241, 
+	56, 252, 241, 246, 247, 241, 241, 241, 
+	241, 253, 241, 251, 241, 254, 255, 256, 
+	257, 43, 246, 247, 241, 241, 241, 73, 
+	258, 241, 241, 251, 241, 259, 255, 260, 
+	260, 43, 246, 247, 241, 241, 241, 241, 
+	258, 241, 255, 260, 260, 43, 246, 247, 
+	241, 241, 241, 241, 258, 241, 261, 241, 
+	241, 241, 56, 262, 241, 246, 247, 241, 
+	241, 241, 241, 253, 241, 261, 241, 263, 
+	264, 265, 266, 43, 246, 247, 241, 241, 
+	241, 71, 267, 241, 241, 261, 241, 268, 
+	264, 269, 269, 43, 246, 247, 241, 241, 
+	241, 241, 267, 241, 264, 269, 269, 43, 
+	246, 247, 241, 241, 241, 241, 267, 241, 
+	270, 241, 241, 241, 56, 271, 241, 246, 
+	247, 241, 241, 241, 241, 253, 241, 270, 
+	241, 272, 273, 274, 275, 43, 246, 247, 
+	241, 241, 241, 69, 276, 241, 241, 270, 
+	241, 277, 273, 278, 278, 43, 246, 247, 
+	241, 241, 241, 241, 276, 241, 273, 278, 
+	278, 43, 246, 247, 241, 241, 241, 241, 
+	276, 241, 279, 241, 241, 241, 56, 280, 
+	241, 246, 247, 241, 241, 241, 241, 253, 
+	241, 279, 241, 281, 282, 283, 284, 43, 
+	246, 247, 241, 241, 241, 67, 285, 241, 
+	241, 279, 241, 286, 282, 287, 287, 43, 
+	246, 247, 241, 241, 241, 241, 285, 241, 
+	282, 287, 287, 43, 246, 247, 241, 241, 
+	241, 241, 285, 241, 56, 288, 241, 246, 
+	247, 241, 241, 241, 241, 253, 241, 246, 
+	247, 241, 241, 241, 241, 253, 241, 289, 
+	241, 241, 241, 247, 241, 247, 241, 290, 
+	241, 291, 241, 292, 293, 241, 246, 247, 
+	241, 241, 241, 41, 241, 241, 241, 39, 
+	241, 40, 241, 241, 241, 241, 246, 247, 
+	241, 246, 247, 241, 291, 241, 241, 241, 
+	241, 246, 247, 241, 291, 241, 292, 241, 
+	241, 246, 247, 241, 241, 241, 41, 241, 
+	56, 241, 294, 294, 43, 246, 247, 241, 
+	241, 241, 241, 253, 241, 295, 65, 296, 
+	297, 46, 246, 247, 241, 241, 241, 241, 
+	253, 241, 65, 296, 297, 46, 246, 247, 
+	241, 241, 241, 241, 253, 241, 296, 296, 
+	46, 246, 247, 241, 241, 241, 241, 253, 
+	241, 298, 62, 299, 300, 49, 246, 247, 
+	241, 241, 241, 241, 253, 241, 62, 299, 
+	300, 49, 246, 247, 241, 241, 241, 241, 
+	253, 241, 299, 299, 49, 246, 247, 241, 
+	241, 241, 241, 253, 241, 301, 59, 302, 
+	303, 52, 246, 247, 241, 241, 241, 241, 
+	253, 241, 59, 302, 303, 52, 246, 247, 
+	241, 241, 241, 241, 253, 241, 302, 302, 
+	52, 246, 247, 241, 241, 241, 241, 253, 
+	241, 304, 56, 241, 305, 241, 246, 247, 
+	241, 241, 241, 241, 253, 241, 56, 241, 
+	305, 241, 246, 247, 241, 241, 241, 241, 
+	253, 241, 306, 241, 246, 247, 241, 241, 
+	241, 241, 253, 241, 56, 241, 241, 241, 
+	241, 246, 247, 241, 241, 241, 241, 253, 
+	241, 39, 40, 241, 241, 56, 288, 241, 
+	246, 247, 241, 241, 241, 241, 253, 241, 
+	39, 241, 281, 282, 287, 287, 43, 246, 
+	247, 241, 241, 241, 241, 285, 241, 281, 
+	282, 283, 287, 43, 246, 247, 241, 241, 
+	241, 67, 285, 241, 279, 241, 307, 241, 
+	294, 294, 43, 246, 247, 241, 241, 241, 
+	241, 253, 241, 279, 241, 279, 241, 241, 
+	241, 241, 241, 241, 246, 247, 241, 241, 
+	241, 241, 253, 241, 279, 241, 279, 241, 
+	241, 241, 241, 308, 241, 246, 247, 241, 
+	241, 241, 241, 253, 241, 279, 241, 279, 
+	241, 307, 241, 241, 241, 241, 246, 247, 
+	241, 241, 241, 241, 253, 241, 279, 241, 
+	279, 40, 241, 241, 56, 280, 241, 246, 
+	247, 241, 241, 241, 241, 253, 241, 279, 
+	241, 272, 273, 278, 278, 43, 246, 247, 
+	241, 241, 241, 241, 276, 241, 272, 273, 
+	274, 278, 43, 246, 247, 241, 241, 241, 
+	69, 276, 241, 270, 241, 309, 241, 294, 
+	294, 43, 246, 247, 241, 241, 241, 241, 
+	253, 241, 270, 241, 270, 241, 241, 241, 
+	241, 241, 241, 246, 247, 241, 241, 241, 
+	241, 253, 241, 270, 241, 270, 241, 241, 
+	241, 241, 310, 241, 246, 247, 241, 241, 
+	241, 241, 253, 241, 270, 241, 270, 241, 
+	309, 241, 241, 241, 241, 246, 247, 241, 
+	241, 241, 241, 253, 241, 270, 241, 270, 
+	40, 241, 241, 56, 271, 241, 246, 247, 
+	241, 241, 241, 241, 253, 241, 270, 241, 
+	263, 264, 269, 269, 43, 246, 247, 241, 
+	241, 241, 241, 267, 241, 263, 264, 265, 
+	269, 43, 246, 247, 241, 241, 241, 71, 
+	267, 241, 261, 241, 311, 241, 294, 294, 
+	43, 246, 247, 241, 241, 241, 241, 253, 
+	241, 261, 241, 261, 241, 241, 241, 241, 
+	241, 241, 246, 247, 241, 241, 241, 241, 
+	253, 241, 261, 241, 261, 241, 241, 241, 
+	241, 312, 241, 246, 247, 241, 241, 241, 
+	241, 253, 241, 261, 241, 261, 241, 311, 
+	241, 241, 241, 241, 246, 247, 241, 241, 
+	241, 241, 253, 241, 261, 241, 261, 40, 
+	241, 241, 56, 262, 241, 246, 247, 241, 
+	241, 241, 241, 253, 241, 261, 241, 254, 
+	255, 260, 260, 43, 246, 247, 241, 241, 
+	241, 241, 258, 241, 254, 255, 256, 260, 
+	43, 246, 247, 241, 241, 241, 73, 258, 
+	241, 251, 241, 313, 241, 294, 294, 43, 
+	246, 247, 241, 241, 241, 241, 253, 241, 
+	251, 241, 251, 241, 241, 241, 241, 241, 
+	241, 246, 247, 241, 241, 241, 241, 253, 
+	241, 251, 241, 251, 241, 241, 241, 241, 
+	314, 241, 246, 247, 241, 241, 241, 241, 
+	253, 241, 251, 241, 251, 241, 313, 241, 
+	241, 241, 241, 246, 247, 241, 241, 241, 
+	241, 253, 241, 251, 241, 74, 42, 42, 
+	43, 241, 241, 241, 241, 241, 241, 74, 
+	241, 251, 40, 241, 241, 56, 252, 241, 
+	246, 247, 241, 241, 241, 241, 253, 241, 
+	251, 241, 242, 243, 250, 245, 43, 246, 
+	247, 241, 241, 241, 241, 248, 241, 316, 
+	156, 317, 317, 81, 159, 160, 315, 315, 
+	315, 315, 163, 315, 156, 317, 317, 81, 
 	159, 160, 315, 315, 315, 315, 163, 315, 
-	113, 80, 80, 81, 382, 382, 382, 382, 
-	382, 382, 113, 382, 384, 385, 386, 387, 
-	119, 388, 389, 383, 383, 383, 151, 390, 
-	383, 391, 385, 387, 387, 119, 388, 389, 
-	383, 383, 383, 383, 390, 383, 385, 387, 
-	387, 119, 388, 389, 383, 383, 383, 383, 
-	390, 383, 392, 383, 383, 383, 132, 393, 
-	383, 388, 389, 383, 383, 383, 383, 394, 
-	383, 392, 383, 395, 396, 397, 398, 119, 
-	388, 389, 383, 383, 383, 149, 399, 383, 
-	400, 396, 401, 401, 119, 388, 389, 383, 
-	383, 383, 383, 399, 383, 396, 401, 401, 
-	119, 388, 389, 383, 383, 383, 383, 399, 
-	383, 402, 383, 383, 383, 132, 403, 383, 
-	388, 389, 383, 383, 383, 383, 394, 383, 
-	402, 383, 404, 405, 406, 407, 119, 388, 
-	389, 383, 383, 383, 147, 408, 383, 409, 
-	405, 410, 410, 119, 388, 389, 383, 383, 
-	383, 383, 408, 383, 405, 410, 410, 119, 
-	388, 389, 383, 383, 383, 383, 408, 383, 
-	411, 383, 383, 383, 132, 412, 383, 388, 
-	389, 383, 383, 383, 383, 394, 383, 411, 
-	383, 413, 414, 415, 416, 119, 388, 389, 
-	383, 383, 383, 145, 417, 383, 418, 414, 
-	419, 419, 119, 388, 389, 383, 383, 383, 
-	383, 417, 383, 414, 419, 419, 119, 388, 
-	389, 383, 383, 383, 383, 417, 383, 420, 
-	383, 383, 383, 132, 421, 383, 388, 389, 
-	383, 383, 383, 383, 394, 383, 420, 383, 
-	422, 423, 424, 425, 119, 388, 389, 383, 
-	383, 383, 143, 426, 383, 427, 423, 428, 
-	428, 119, 388, 389, 383, 383, 383, 383, 
-	426, 383, 423, 428, 428, 119, 388, 389, 
-	383, 383, 383, 383, 426, 383, 132, 429, 
-	383, 388, 389, 383, 383, 383, 383, 394, 
-	383, 388, 389, 383, 383, 383, 383, 394, 
-	383, 430, 383, 383, 383, 389, 383, 389, 
-	383, 431, 383, 432, 383, 433, 434, 383, 
-	388, 389, 383, 383, 383, 117, 383, 116, 
-	383, 383, 383, 383, 388, 389, 383, 388, 
-	389, 383, 432, 383, 383, 383, 383, 388, 
-	389, 383, 432, 383, 433, 383, 383, 388, 
-	389, 383, 383, 383, 117, 383, 132, 383, 
-	435, 435, 119, 388, 389, 383, 383, 383, 
-	383, 394, 383, 436, 141, 437, 438, 122, 
-	388, 389, 383, 383, 383, 383, 394, 383, 
-	141, 437, 438, 122, 388, 389, 383, 383, 
-	383, 383, 394, 383, 437, 437, 122, 388, 
-	389, 383, 383, 383, 383, 394, 383, 439, 
-	138, 440, 441, 125, 388, 389, 383, 383, 
-	383, 383, 394, 383, 138, 440, 441, 125, 
-	388, 389, 383, 383, 383, 383, 394, 383, 
-	440, 440, 125, 388, 389, 383, 383, 383, 
-	383, 394, 383, 442, 135, 443, 444, 128, 
-	388, 389, 383, 383, 383, 383, 394, 383, 
-	135, 443, 444, 128, 388, 389, 383, 383, 
-	383, 383, 394, 383, 443, 443, 128, 388, 
-	389, 383, 383, 383, 383, 394, 383, 445, 
-	132, 383, 446, 383, 388, 389, 383, 383, 
-	383, 383, 394, 383, 132, 383, 446, 383, 
+	318, 315, 315, 315, 95, 319, 315, 159, 
+	160, 315, 315, 315, 315, 320, 315, 318, 
+	315, 321, 322, 323, 324, 81, 159, 160, 
+	315, 315, 315, 112, 325, 315, 315, 318, 
+	315, 326, 322, 327, 327, 81, 159, 160, 
+	315, 315, 315, 315, 325, 315, 322, 327, 
+	327, 81, 159, 160, 315, 315, 315, 315, 
+	325, 315, 328, 315, 315, 315, 95, 329, 
+	315, 159, 160, 315, 315, 315, 315, 320, 
+	315, 328, 315, 330, 331, 332, 333, 81, 
+	159, 160, 315, 315, 315, 110, 334, 315, 
+	315, 328, 315, 335, 331, 336, 336, 81, 
+	159, 160, 315, 315, 315, 315, 334, 315, 
+	331, 336, 336, 81, 159, 160, 315, 315, 
+	315, 315, 334, 315, 337, 315, 315, 315, 
+	95, 338, 315, 159, 160, 315, 315, 315, 
+	315, 320, 315, 337, 315, 339, 340, 341, 
+	342, 81, 159, 160, 315, 315, 315, 108, 
+	343, 315, 315, 337, 315, 344, 340, 345, 
+	345, 81, 159, 160, 315, 315, 315, 315, 
+	343, 315, 340, 345, 345, 81, 159, 160, 
+	315, 315, 315, 315, 343, 315, 346, 315, 
+	315, 315, 95, 347, 315, 159, 160, 315, 
+	315, 315, 315, 320, 315, 346, 315, 348, 
+	349, 350, 351, 81, 159, 160, 315, 315, 
+	315, 106, 352, 315, 315, 346, 315, 353, 
+	349, 354, 354, 81, 159, 160, 315, 315, 
+	315, 315, 352, 315, 349, 354, 354, 81, 
+	159, 160, 315, 315, 315, 315, 352, 315, 
+	95, 355, 315, 159, 160, 315, 315, 315, 
+	315, 320, 315, 159, 160, 315, 315, 315, 
+	315, 320, 315, 356, 315, 315, 315, 160, 
+	315, 160, 315, 357, 315, 358, 315, 359, 
+	360, 315, 159, 160, 315, 315, 315, 79, 
+	315, 315, 315, 77, 315, 78, 315, 315, 
+	315, 315, 159, 160, 315, 159, 160, 315, 
+	358, 315, 315, 315, 315, 159, 160, 315, 
+	358, 315, 359, 315, 315, 159, 160, 315, 
+	315, 315, 79, 315, 95, 315, 361, 361, 
+	81, 159, 160, 315, 315, 315, 315, 320, 
+	315, 362, 104, 363, 364, 85, 159, 160, 
+	315, 315, 315, 315, 320, 315, 104, 363, 
+	364, 85, 159, 160, 315, 315, 315, 315, 
+	320, 315, 363, 363, 85, 159, 160, 315, 
+	315, 315, 315, 320, 315, 365, 101, 366, 
+	367, 88, 159, 160, 315, 315, 315, 315, 
+	320, 315, 101, 366, 367, 88, 159, 160, 
+	315, 315, 315, 315, 320, 315, 366, 366, 
+	88, 159, 160, 315, 315, 315, 315, 320, 
+	315, 368, 98, 369, 370, 91, 159, 160, 
+	315, 315, 315, 315, 320, 315, 98, 369, 
+	370, 91, 159, 160, 315, 315, 315, 315, 
+	320, 315, 369, 369, 91, 159, 160, 315, 
+	315, 315, 315, 320, 315, 371, 95, 315, 
+	372, 315, 159, 160, 315, 315, 315, 315, 
+	320, 315, 95, 315, 372, 315, 159, 160, 
+	315, 315, 315, 315, 320, 315, 373, 315, 
+	159, 160, 315, 315, 315, 315, 320, 315, 
+	95, 315, 315, 315, 315, 159, 160, 315, 
+	315, 315, 315, 320, 315, 77, 78, 315, 
+	315, 95, 355, 315, 159, 160, 315, 315, 
+	315, 315, 320, 315, 77, 315, 348, 349, 
+	354, 354, 81, 159, 160, 315, 315, 315, 
+	315, 352, 315, 348, 349, 350, 354, 81, 
+	159, 160, 315, 315, 315, 106, 352, 315, 
+	346, 315, 374, 315, 361, 361, 81, 159, 
+	160, 315, 315, 315, 315, 320, 315, 346, 
+	315, 346, 315, 315, 315, 315, 315, 315, 
+	159, 160, 315, 315, 315, 315, 320, 315, 
+	346, 315, 346, 315, 315, 315, 315, 375, 
+	315, 159, 160, 315, 315, 315, 315, 320, 
+	315, 346, 315, 346, 315, 374, 315, 315, 
+	315, 315, 159, 160, 315, 315, 315, 315, 
+	320, 315, 346, 315, 346, 78, 315, 315, 
+	95, 347, 315, 159, 160, 315, 315, 315, 
+	315, 320, 315, 346, 315, 339, 340, 345, 
+	345, 81, 159, 160, 315, 315, 315, 315, 
+	343, 315, 339, 340, 341, 345, 81, 159, 
+	160, 315, 315, 315, 108, 343, 315, 337, 
+	315, 376, 315, 361, 361, 81, 159, 160, 
+	315, 315, 315, 315, 320, 315, 337, 315, 
+	337, 315, 315, 315, 315, 315, 315, 159, 
+	160, 315, 315, 315, 315, 320, 315, 337, 
+	315, 337, 315, 315, 315, 315, 377, 315, 
+	159, 160, 315, 315, 315, 315, 320, 315, 
+	337, 315, 337, 315, 376, 315, 315, 315, 
+	315, 159, 160, 315, 315, 315, 315, 320, 
+	315, 337, 315, 337, 78, 315, 315, 95, 
+	338, 315, 159, 160, 315, 315, 315, 315, 
+	320, 315, 337, 315, 330, 331, 336, 336, 
+	81, 159, 160, 315, 315, 315, 315, 334, 
+	315, 330, 331, 332, 336, 81, 159, 160, 
+	315, 315, 315, 110, 334, 315, 328, 315, 
+	378, 315, 361, 361, 81, 159, 160, 315, 
+	315, 315, 315, 320, 315, 328, 315, 328, 
+	315, 315, 315, 315, 315, 315, 159, 160, 
+	315, 315, 315, 315, 320, 315, 328, 315, 
+	328, 315, 315, 315, 315, 379, 315, 159, 
+	160, 315, 315, 315, 315, 320, 315, 328, 
+	315, 328, 315, 378, 315, 315, 315, 315, 
+	159, 160, 315, 315, 315, 315, 320, 315, 
+	328, 315, 328, 78, 315, 315, 95, 329, 
+	315, 159, 160, 315, 315, 315, 315, 320, 
+	315, 328, 315, 321, 322, 327, 327, 81, 
+	159, 160, 315, 315, 315, 315, 325, 315, 
+	321, 322, 323, 327, 81, 159, 160, 315, 
+	315, 315, 112, 325, 315, 318, 315, 380, 
+	315, 361, 361, 81, 159, 160, 315, 315, 
+	315, 315, 320, 315, 318, 315, 318, 315, 
+	315, 315, 315, 315, 315, 159, 160, 315, 
+	315, 315, 315, 320, 315, 318, 315, 318, 
+	315, 315, 315, 315, 381, 315, 159, 160, 
+	315, 315, 315, 315, 320, 315, 318, 315, 
+	318, 315, 380, 315, 315, 315, 315, 159, 
+	160, 315, 315, 315, 315, 320, 315, 318, 
+	315, 318, 78, 315, 315, 95, 319, 315, 
+	159, 160, 315, 315, 315, 315, 320, 315, 
+	318, 315, 113, 80, 80, 81, 382, 382, 
+	382, 382, 382, 162, 113, 382, 155, 156, 
+	317, 317, 81, 159, 160, 315, 315, 315, 
+	315, 163, 315, 113, 80, 80, 81, 382, 
+	382, 382, 382, 382, 382, 113, 382, 384, 
+	385, 386, 387, 119, 388, 389, 383, 383, 
+	383, 151, 390, 383, 391, 385, 387, 387, 
+	119, 388, 389, 383, 383, 383, 383, 390, 
+	383, 385, 387, 387, 119, 388, 389, 383, 
+	383, 383, 383, 390, 383, 392, 383, 383, 
+	383, 132, 393, 383, 388, 389, 383, 383, 
+	383, 383, 394, 383, 392, 383, 395, 396, 
+	397, 398, 119, 388, 389, 383, 383, 383, 
+	149, 399, 383, 383, 392, 383, 400, 396, 
+	401, 401, 119, 388, 389, 383, 383, 383, 
+	383, 399, 383, 396, 401, 401, 119, 388, 
+	389, 383, 383, 383, 383, 399, 383, 402, 
+	383, 383, 383, 132, 403, 383, 388, 389, 
+	383, 383, 383, 383, 394, 383, 402, 383, 
+	404, 405, 406, 407, 119, 388, 389, 383, 
+	383, 383, 147, 408, 383, 383, 402, 383, 
+	409, 405, 410, 410, 119, 388, 389, 383, 
+	383, 383, 383, 408, 383, 405, 410, 410, 
+	119, 388, 389, 383, 383, 383, 383, 408, 
+	383, 411, 383, 383, 383, 132, 412, 383, 
 	388, 389, 383, 383, 383, 383, 394, 383, 
-	447, 383, 388, 389, 383, 383, 383, 383, 
-	394, 383, 132, 383, 383, 383, 383, 388, 
-	389, 383, 383, 383, 383, 394, 383, 115, 
-	116, 383, 383, 132, 429, 383, 388, 389, 
-	383, 383, 383, 383, 394, 383, 115, 383, 
-	422, 423, 428, 428, 119, 388, 389, 383, 
-	383, 383, 383, 426, 383, 422, 423, 424, 
-	428, 119, 388, 389, 383, 383, 383, 143, 
-	426, 383, 420, 383, 448, 383, 435, 435, 
-	119, 388, 389, 383, 383, 383, 383, 394, 
-	383, 420, 383, 420, 383, 383, 383, 383, 
+	411, 383, 413, 414, 415, 416, 119, 388, 
+	389, 383, 383, 383, 145, 417, 383, 383, 
+	411, 383, 418, 414, 419, 419, 119, 388, 
+	389, 383, 383, 383, 383, 417, 383, 414, 
+	419, 419, 119, 388, 389, 383, 383, 383, 
+	383, 417, 383, 420, 383, 383, 383, 132, 
+	421, 383, 388, 389, 383, 383, 383, 383, 
+	394, 383, 420, 383, 422, 423, 424, 425, 
+	119, 388, 389, 383, 383, 383, 143, 426, 
+	383, 383, 420, 383, 427, 423, 428, 428, 
+	119, 388, 389, 383, 383, 383, 383, 426, 
+	383, 423, 428, 428, 119, 388, 389, 383, 
+	383, 383, 383, 426, 383, 132, 429, 383, 
+	388, 389, 383, 383, 383, 383, 394, 383, 
+	388, 389, 383, 383, 383, 383, 394, 383, 
+	430, 383, 383, 383, 389, 383, 389, 383, 
+	431, 383, 432, 383, 433, 434, 383, 388, 
+	389, 383, 383, 383, 117, 383, 383, 383, 
+	115, 383, 116, 383, 383, 383, 383, 388, 
+	389, 383, 388, 389, 383, 432, 383, 383, 
+	383, 383, 388, 389, 383, 432, 383, 433, 
+	383, 383, 388, 389, 383, 383, 383, 117, 
+	383, 132, 383, 435, 435, 119, 388, 389, 
+	383, 383, 383, 383, 394, 383, 436, 141, 
+	437, 438, 122, 388, 389, 383, 383, 383, 
+	383, 394, 383, 141, 437, 438, 122, 388, 
+	389, 383, 383, 383, 383, 394, 383, 437, 
+	437, 122, 388, 389, 383, 383, 383, 383, 
+	394, 383, 439, 138, 440, 441, 125, 388, 
+	389, 383, 383, 383, 383, 394, 383, 138, 
+	440, 441, 125, 388, 389, 383, 383, 383, 
+	383, 394, 383, 440, 440, 125, 388, 389, 
+	383, 383, 383, 383, 394, 383, 442, 135, 
+	443, 444, 128, 388, 389, 383, 383, 383, 
+	383, 394, 383, 135, 443, 444, 128, 388, 
+	389, 383, 383, 383, 383, 394, 383, 443, 
+	443, 128, 388, 389, 383, 383, 383, 383, 
+	394, 383, 445, 132, 383, 446, 383, 388, 
+	389, 383, 383, 383, 383, 394, 383, 132, 
+	383, 446, 383, 388, 389, 383, 383, 383, 
+	383, 394, 383, 447, 383, 388, 389, 383, 
+	383, 383, 383, 394, 383, 132, 383, 383, 
 	383, 383, 388, 389, 383, 383, 383, 383, 
-	394, 383, 420, 383, 420, 383, 383, 383, 
-	383, 449, 383, 388, 389, 383, 383, 383, 
-	383, 394, 383, 420, 383, 420, 383, 448, 
+	394, 383, 115, 116, 383, 383, 132, 429, 
+	383, 388, 389, 383, 383, 383, 383, 394, 
+	383, 115, 383, 422, 423, 428, 428, 119, 
+	388, 389, 383, 383, 383, 383, 426, 383, 
+	422, 423, 424, 428, 119, 388, 389, 383, 
+	383, 383, 143, 426, 383, 420, 383, 448, 
+	383, 435, 435, 119, 388, 389, 383, 383, 
+	383, 383, 394, 383, 420, 383, 420, 383, 
+	383, 383, 383, 383, 383, 388, 389, 383, 
+	383, 383, 383, 394, 383, 420, 383, 420, 
+	383, 383, 383, 383, 449, 383, 388, 389, 
+	383, 383, 383, 383, 394, 383, 420, 383, 
+	420, 383, 448, 383, 383, 383, 383, 388, 
+	389, 383, 383, 383, 383, 394, 383, 420, 
+	383, 420, 116, 383, 383, 132, 421, 383, 
+	388, 389, 383, 383, 383, 383, 394, 383, 
+	420, 383, 413, 414, 419, 419, 119, 388, 
+	389, 383, 383, 383, 383, 417, 383, 413, 
+	414, 415, 419, 119, 388, 389, 383, 383, 
+	383, 145, 417, 383, 411, 383, 450, 383, 
+	435, 435, 119, 388, 389, 383, 383, 383, 
+	383, 394, 383, 411, 383, 411, 383, 383, 
 	383, 383, 383, 383, 388, 389, 383, 383, 
-	383, 383, 394, 383, 420, 383, 420, 116, 
-	383, 383, 132, 421, 383, 388, 389, 383, 
-	383, 383, 383, 394, 383, 420, 383, 413, 
-	414, 419, 419, 119, 388, 389, 383, 383, 
-	383, 383, 417, 383, 413, 414, 415, 419, 
-	119, 388, 389, 383, 383, 383, 145, 417, 
-	383, 411, 383, 450, 383, 435, 435, 119, 
-	388, 389, 383, 383, 383, 383, 394, 383, 
-	411, 383, 411, 383, 383, 383, 383, 383, 
-	383, 388, 389, 383, 383, 383, 383, 394, 
-	383, 411, 383, 411, 383, 383, 383, 383, 
-	451, 383, 388, 389, 383, 383, 383, 383, 
-	394, 383, 411, 383, 411, 383, 450, 383, 
+	383, 383, 394, 383, 411, 383, 411, 383, 
+	383, 383, 383, 451, 383, 388, 389, 383, 
+	383, 383, 383, 394, 383, 411, 383, 411, 
+	383, 450, 383, 383, 383, 383, 388, 389, 
+	383, 383, 383, 383, 394, 383, 411, 383, 
+	411, 116, 383, 383, 132, 412, 383, 388, 
+	389, 383, 383, 383, 383, 394, 383, 411, 
+	383, 404, 405, 410, 410, 119, 388, 389, 
+	383, 383, 383, 383, 408, 383, 404, 405, 
+	406, 410, 119, 388, 389, 383, 383, 383, 
+	147, 408, 383, 402, 383, 452, 383, 435, 
+	435, 119, 388, 389, 383, 383, 383, 383, 
+	394, 383, 402, 383, 402, 383, 383, 383, 
 	383, 383, 383, 388, 389, 383, 383, 383, 
-	383, 394, 383, 411, 383, 411, 116, 383, 
-	383, 132, 412, 383, 388, 389, 383, 383, 
-	383, 383, 394, 383, 411, 383, 404, 405, 
-	410, 410, 119, 388, 389, 383, 383, 383, 
-	383, 408, 383, 404, 405, 406, 410, 119, 
-	388, 389, 383, 383, 383, 147, 408, 383, 
-	402, 383, 452, 383, 435, 435, 119, 388, 
-	389, 383, 383, 383, 383, 394, 383, 402, 
-	383, 402, 383, 383, 383, 383, 383, 383, 
-	388, 389, 383, 383, 383, 383, 394, 383, 
-	402, 383, 402, 383, 383, 383, 383, 453, 
-	383, 388, 389, 383, 383, 383, 383, 394, 
-	383, 402, 383, 402, 383, 452, 383, 383, 
+	383, 394, 383, 402, 383, 402, 383, 383, 
+	383, 383, 453, 383, 388, 389, 383, 383, 
+	383, 383, 394, 383, 402, 383, 402, 383, 
+	452, 383, 383, 383, 383, 388, 389, 383, 
+	383, 383, 383, 394, 383, 402, 383, 402, 
+	116, 383, 383, 132, 403, 383, 388, 389, 
+	383, 383, 383, 383, 394, 383, 402, 383, 
+	395, 396, 401, 401, 119, 388, 389, 383, 
+	383, 383, 383, 399, 383, 395, 396, 397, 
+	401, 119, 388, 389, 383, 383, 383, 149, 
+	399, 383, 392, 383, 454, 383, 435, 435, 
+	119, 388, 389, 383, 383, 383, 383, 394, 
+	383, 392, 383, 392, 383, 383, 383, 383, 
 	383, 383, 388, 389, 383, 383, 383, 383, 
-	394, 383, 402, 383, 402, 116, 383, 383, 
-	132, 403, 383, 388, 389, 383, 383, 383, 
-	383, 394, 383, 402, 383, 395, 396, 401, 
-	401, 119, 388, 389, 383, 383, 383, 383, 
-	399, 383, 395, 396, 397, 401, 119, 388, 
-	389, 383, 383, 383, 149, 399, 383, 392, 
-	383, 454, 383, 435, 435, 119, 388, 389, 
-	383, 383, 383, 383, 394, 383, 392, 383, 
-	392, 383, 383, 383, 383, 383, 383, 388, 
-	389, 383, 383, 383, 383, 394, 383, 392, 
-	383, 392, 383, 383, 383, 383, 455, 383, 
-	388, 389, 383, 383, 383, 383, 394, 383, 
-	392, 383, 392, 383, 454, 383, 383, 383, 
-	383, 388, 389, 383, 383, 383, 383, 394, 
-	383, 392, 383, 392, 116, 383, 383, 132, 
-	393, 383, 388, 389, 383, 383, 383, 383, 
-	394, 383, 392, 383, 384, 385, 387, 387, 
-	119, 388, 389, 383, 383, 383, 383, 390, 
-	383, 153, 154, 382, 382, 382, 382, 382, 
-	382, 382, 382, 161, 161, 382, 382, 382, 
-	153, 382, 167, 456, 169, 170, 5, 171, 
-	172, 173, 166, 166, 37, 174, 166, 177, 
-	154, 166, 166, 18, 178, 166, 171, 172, 
-	166, 161, 161, 166, 179, 166, 177, 166, 
-	0
+	394, 383, 392, 383, 392, 383, 383, 383, 
+	383, 455, 383, 388, 389, 383, 383, 383, 
+	383, 394, 383, 392, 383, 392, 383, 454, 
+	383, 383, 383, 383, 388, 389, 383, 383, 
+	383, 383, 394, 383, 392, 383, 392, 116, 
+	383, 383, 132, 393, 383, 388, 389, 383, 
+	383, 383, 383, 394, 383, 392, 383, 384, 
+	385, 387, 387, 119, 388, 389, 383, 383, 
+	383, 383, 390, 383, 153, 154, 382, 382, 
+	382, 382, 382, 382, 382, 382, 161, 161, 
+	382, 382, 382, 153, 382, 167, 456, 169, 
+	170, 5, 171, 172, 173, 166, 166, 37, 
+	174, 166, 166, 153, 166, 177, 154, 166, 
+	166, 18, 178, 166, 171, 172, 166, 161, 
+	161, 166, 179, 166, 177, 166, 0
 };
 
 static const short _indic_syllable_machine_trans_targs[] = {
 	143, 168, 170, 171, 3, 174, 4, 6, 
 	177, 7, 9, 180, 10, 12, 183, 13, 
 	15, 16, 164, 18, 19, 182, 21, 22, 
 	179, 24, 25, 176, 185, 189, 193, 196, 
 	200, 203, 207, 210, 214, 217, 143, 243, 
@@ -1124,17 +1132,17 @@ static const int indic_syllable_machine_
 
 static const int indic_syllable_machine_en_main = 143;
 
 
 #line 36 "../../src/hb-ot-shape-complex-indic-machine.rl"
 
 
 
-#line 90 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 91 "../../src/hb-ot-shape-complex-indic-machine.rl"
 
 
 #define found_syllable(syllable_type) \
   HB_STMT_START { \
     if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
     for (unsigned int i = last; i < p+1; i++) \
       info[i].syllable() = (syllable_serial << 4) | syllable_type; \
     last = p+1; \
@@ -1144,48 +1152,48 @@ static const int indic_syllable_machine_
 
 static void
 find_syllables (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts, te, act;
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 1153 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1161 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
 	{
 	cs = indic_syllable_machine_start;
 	ts = 0;
 	te = 0;
 	act = 0;
 	}
 
-#line 111 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 112 "../../src/hb-ot-shape-complex-indic-machine.rl"
 
 
   p = 0;
   pe = eof = buffer->len;
 
   unsigned int last = 0;
   unsigned int syllable_serial = 1;
   
-#line 1170 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1178 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
 	{
 	int _slen;
 	int _trans;
 	const unsigned char *_keys;
 	const short *_inds;
 	if ( p == pe )
 		goto _test_eof;
 _resume:
 	switch ( _indic_syllable_machine_from_state_actions[cs] ) {
 	case 9:
-#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 1 "NONE"
 	{ts = p;}
 	break;
-#line 1184 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1192 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
 	}
 
 	_keys = _indic_syllable_machine_trans_keys + (cs<<1);
 	_inds = _indic_syllable_machine_indicies + _indic_syllable_machine_index_offsets[cs];
 
 	_slen = _indic_syllable_machine_key_spans[cs];
 	_trans = _inds[ _slen > 0 && _keys[0] <=( info[p].indic_category()) &&
 		( info[p].indic_category()) <= _keys[1] ?
@@ -1194,121 +1202,121 @@ find_syllables (hb_buffer_t *buffer)
 _eof_trans:
 	cs = _indic_syllable_machine_trans_targs[_trans];
 
 	if ( _indic_syllable_machine_trans_actions[_trans] == 0 )
 		goto _again;
 
 	switch ( _indic_syllable_machine_trans_actions[_trans] ) {
 	case 2:
-#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 1 "NONE"
 	{te = p+1;}
 	break;
 	case 13:
-#line 82 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (consonant_syllable); }}
 	break;
 	case 15:
-#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (vowel_syllable); }}
 	break;
 	case 20:
-#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (standalone_cluster); }}
 	break;
 	case 17:
-#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (broken_cluster); }}
 	break;
 	case 10:
-#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 87 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (non_indic_cluster); }}
 	break;
 	case 12:
-#line 82 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (consonant_syllable); }}
 	break;
 	case 14:
-#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (vowel_syllable); }}
 	break;
 	case 19:
-#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (standalone_cluster); }}
 	break;
 	case 16:
-#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (broken_cluster); }}
 	break;
 	case 18:
-#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 87 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (non_indic_cluster); }}
 	break;
 	case 1:
-#line 82 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
 	break;
 	case 3:
-#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (vowel_syllable); }}
 	break;
 	case 7:
-#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (standalone_cluster); }}
 	break;
 	case 4:
-#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (broken_cluster); }}
 	break;
 	case 5:
-#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 1 "NONE"
 	{	switch( act ) {
 	case 4:
 	{{p = ((te))-1;} found_syllable (broken_cluster); }
 	break;
 	case 5:
 	{{p = ((te))-1;} found_syllable (non_indic_cluster); }
 	break;
 	}
 	}
 	break;
 	case 6:
-#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 1 "NONE"
 	{te = p+1;}
-#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{act = 4;}
 	break;
 	case 11:
-#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 1 "NONE"
 	{te = p+1;}
-#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 87 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{act = 5;}
 	break;
-#line 1286 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1294 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
 	}
 
 _again:
 	switch ( _indic_syllable_machine_to_state_actions[cs] ) {
 	case 8:
-#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 1295 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1303 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
 	}
 
 	if ( ++p != pe )
 		goto _resume;
 	_test_eof: {}
 	if ( p == eof )
 	{
 	if ( _indic_syllable_machine_eof_trans[cs] > 0 ) {
 		_trans = _indic_syllable_machine_eof_trans[cs] - 1;
 		goto _eof_trans;
 	}
 	}
 
 	}
 
-#line 120 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 121 "../../src/hb-ot-shape-complex-indic-machine.rl"
 
 }
 
 #endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.rl
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.rl
@@ -50,18 +50,19 @@ SM   = 8;
 VD   = 9;
 A    = 10;
 NBSP = 11;
 DOTTEDCIRCLE = 12;
 RS   = 13;
 Coeng = 14;
 Repha = 15;
 Ra    = 16;
+CM    = 17;
 
-c = (C | Ra);			# is_consonant
+c = (C | Ra)CM*;		# is_consonant
 n = ((ZWNJ?.RS)? (N.N?)?);	# is_consonant_modifier
 z = ZWJ|ZWNJ;			# is_joiner
 h = H | Coeng;			# is_halant_or_coeng
 reph = (Ra H | Repha);		# possible reph
 
 cn = c.ZWJ?.n?;
 forced_rakar = ZWJ H ZWJ Ra;
 matra_group = z{0,3}.M.N?.(H | forced_rakar)?;
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-private.hh
@@ -34,17 +34,17 @@
 #include "hb-ot-shape-private.hh" /* XXX Remove */
 
 
 /* buffer var allocations */
 #define indic_category() complex_var_u8_0() /* indic_category_t */
 #define indic_position() complex_var_u8_1() /* indic_matra_category_t */
 
 
-#define INDIC_TABLE_ELEMENT_TYPE uint8_t
+#define INDIC_TABLE_ELEMENT_TYPE uint16_t
 
 /* Cateories used in the OpenType spec:
  * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx
  */
 /* Note: This enum is duplicated in the -machine.rl source file.
  * Not sure how to avoid duplication. */
 enum indic_category_t {
   OT_X = 0,
@@ -58,17 +58,18 @@ enum indic_category_t {
   OT_SM,
   OT_VD,
   OT_A,
   OT_NBSP,
   OT_DOTTEDCIRCLE, /* Not in the spec, but special in Uniscribe. /Very very/ special! */
   OT_RS, /* Register Shifter, used in Khmer OT spec */
   OT_Coeng,
   OT_Repha,
-  OT_Ra /* Not explicitly listed in the OT spec, but used in the grammar. */
+  OT_Ra, /* Not explicitly listed in the OT spec, but used in the grammar. */
+  OT_CM
 };
 
 /* Visual positions in a syllable from left to right. */
 enum indic_position_t {
   POS_START,
 
   POS_RA_TO_BECOME_REPH,
   POS_PRE_M,
@@ -98,25 +99,25 @@ enum indic_syllabic_category_t {
   INDIC_SYLLABIC_CATEGORY_OTHER			= OT_X,
 
   INDIC_SYLLABIC_CATEGORY_AVAGRAHA		= OT_X,
   INDIC_SYLLABIC_CATEGORY_BINDU			= OT_SM,
   INDIC_SYLLABIC_CATEGORY_CONSONANT		= OT_C,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD	= OT_C,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL	= OT_C,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER	= OT_C,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL	= OT_C,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL	= OT_CM,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER	= OT_NBSP,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED	= OT_C,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA	= OT_Repha,
   INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER	= OT_X,
   INDIC_SYLLABIC_CATEGORY_NUKTA			= OT_N,
   INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER	= OT_RS,
   INDIC_SYLLABIC_CATEGORY_TONE_LETTER		= OT_X,
-  INDIC_SYLLABIC_CATEGORY_TONE_MARK		= OT_X,
+  INDIC_SYLLABIC_CATEGORY_TONE_MARK		= OT_N,
   INDIC_SYLLABIC_CATEGORY_VIRAMA		= OT_H,
   INDIC_SYLLABIC_CATEGORY_VISARGA		= OT_SM,
   INDIC_SYLLABIC_CATEGORY_VOWEL			= OT_V,
   INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT	= OT_M,
   INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT	= OT_V
 };
 
 /* Categories used in IndicSMatraCategory.txt from UCD */
@@ -133,26 +134,26 @@ enum indic_matra_category_t {
   INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT		= INDIC_MATRA_CATEGORY_RIGHT,
   INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM		= INDIC_MATRA_CATEGORY_BOTTOM,
   INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT	= INDIC_MATRA_CATEGORY_RIGHT,
   INDIC_MATRA_CATEGORY_TOP_AND_LEFT		= INDIC_MATRA_CATEGORY_TOP,
   INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT	= INDIC_MATRA_CATEGORY_RIGHT,
   INDIC_MATRA_CATEGORY_TOP_AND_RIGHT		= INDIC_MATRA_CATEGORY_RIGHT,
 
   INDIC_MATRA_CATEGORY_INVISIBLE		= INDIC_MATRA_CATEGORY_NOT_APPLICABLE,
-  INDIC_MATRA_CATEGORY_OVERSTRUCK		= INDIC_MATRA_CATEGORY_NOT_APPLICABLE,
-  INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT	= INDIC_MATRA_CATEGORY_NOT_APPLICABLE
+  INDIC_MATRA_CATEGORY_OVERSTRUCK		= POS_AFTER_MAIN,
+  INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT	= POS_PRE_M
 };
 
 /* Note: We use ASSERT_STATIC_EXPR_ZERO() instead of ASSERT_STATIC_EXPR() and the comma operation
  * because gcc fails to optimize the latter and fills the table in at runtime. */
 #define INDIC_COMBINE_CATEGORIES(S,M) \
   (ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || (S == INDIC_SYLLABIC_CATEGORY_VIRAMA || S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT)) + \
-   ASSERT_STATIC_EXPR_ZERO (S < 16 && M < 16) + \
-   ((M << 4) | S))
+   ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
+   ((M << 8) | S))
 
 
 #include "hb-ot-shape-complex-indic-table.hh"
 
 
 #define IN_HALF_BLOCK(u, Base) (((u) & ~0x7F) == (Base))
 
 #define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900))
@@ -216,17 +217,17 @@ matra_position (hb_codepoint_t u, indic_
 {
   switch ((int) side)
   {
     case POS_PRE_C:	return MATRA_POS_LEFT (u);
     case POS_POST_C:	return MATRA_POS_RIGHT (u);
     case POS_ABOVE_C:	return MATRA_POS_TOP (u);
     case POS_BELOW_C:	return MATRA_POS_BOTTOM (u);
   };
-  abort ();
+  return side;
 }
 
 
 
 /* XXX
  * This is a hack for now.  We should move this data into the main Indic table.
  * Or completely remove it and just check in the tables.
  */
@@ -280,17 +281,17 @@ is_joiner (const hb_glyph_info_t &info)
   return is_one_of (info, JOINER_FLAGS);
 }
 
 /* Note:
  *
  * We treat Vowels and placeholders as if they were consonants.  This is safe because Vowels
  * cannot happen in a consonant syllable.  The plus side however is, we can call the
  * consonant syllable logic from the vowel syllable function and get it all right! */
-#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE))
+#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CM) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE))
 static inline bool
 is_consonant (const hb_glyph_info_t &info)
 {
   return is_one_of (info, CONSONANT_FLAGS);
 }
 
 #define HALANT_OR_COENG_FLAGS (FLAG (OT_H) | FLAG (OT_Coeng))
 static inline bool
@@ -299,18 +300,18 @@ is_halant_or_coeng (const hb_glyph_info_
   return is_one_of (info, HALANT_OR_COENG_FLAGS);
 }
 
 static inline void
 set_indic_properties (hb_glyph_info_t &info)
 {
   hb_codepoint_t u = info.codepoint;
   unsigned int type = get_indic_categories (u);
-  indic_category_t cat = (indic_category_t) (type & 0x0F);
-  indic_position_t pos = (indic_position_t) (type >> 4);
+  indic_category_t cat = (indic_category_t) (type & 0x7F);
+  indic_position_t pos = (indic_position_t) (type >> 8);
 
 
   /*
    * Re-assign category
    */
 
 
   /* The spec says U+0952 is OT_A.  However, testing shows that Uniscribe
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
@@ -118,16 +118,18 @@ static const indic_config_t indic_config
   {HB_SCRIPT_GUJARATI,	true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT},
   {HB_SCRIPT_ORIYA,	true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT},
   {HB_SCRIPT_TAMIL,	true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT},
   {HB_SCRIPT_TELUGU,	true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT},
   {HB_SCRIPT_KANNADA,	true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT},
   {HB_SCRIPT_MALAYALAM,	true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA},
   {HB_SCRIPT_SINHALA,	false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT},
   {HB_SCRIPT_KHMER,	false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT,    REPH_MODE_VIS_REPHA},
+  /* Myanmar does not have the "old_indic" behavior, even though it has a "new" tag. */
+  {HB_SCRIPT_MYANMAR,	false, 0x1039,BASE_POS_LAST, REPH_POS_DEFAULT,    REPH_MODE_EXPLICIT},
 };
 
 
 
 /*
  * Indic shaper.
  */
 
@@ -242,16 +244,18 @@ collect_features_indic (hb_ot_shape_plan
 }
 
 static void
 override_features_indic (hb_ot_shape_planner_t *plan)
 {
   /* Uniscribe does not apply 'kern'. */
   if (indic_options ().uniscribe_bug_compatible)
     plan->map.add_feature (HB_TAG('k','e','r','n'), 0, true);
+
+  plan->map.add_feature (HB_TAG('l','i','g','a'), 0, true);
 }
 
 
 struct would_substitute_feature_t
 {
   inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag)
   {
     map->get_stage_lookups (0/*GSUB*/,
@@ -260,17 +264,17 @@ struct would_substitute_feature_t
   }
 
   inline bool would_substitute (hb_codepoint_t    *glyphs,
 				unsigned int       glyphs_count,
 				bool               zero_context,
 				hb_face_t         *face) const
   {
     for (unsigned int i = 0; i < count; i++)
-      if (hb_ot_layout_would_substitute_lookup_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context))
+      if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context))
 	return true;
     return false;
   }
 
   private:
   const hb_ot_map_t::lookup_map_t *lookups;
   unsigned int count;
 };
@@ -298,16 +302,17 @@ struct indic_shape_plan_t
     return glyph != 0;
   }
 
   const indic_config_t *config;
 
   bool is_old_spec;
   hb_codepoint_t virama_glyph;
 
+  would_substitute_feature_t rphf;
   would_substitute_feature_t pref;
   would_substitute_feature_t blwf;
   would_substitute_feature_t pstf;
 
   hb_mask_t mask_array[INDIC_NUM_FEATURES];
 };
 
 static void *
@@ -319,19 +324,20 @@ data_create_indic (const hb_ot_shape_pla
 
   indic_plan->config = &indic_configs[0];
   for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++)
     if (plan->props.script == indic_configs[i].script) {
       indic_plan->config = &indic_configs[i];
       break;
     }
 
-  indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.get_chosen_script (0) & 0x000000FF) != '2');
+  indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FF) != '2');
   indic_plan->virama_glyph = (hb_codepoint_t) -1;
 
+  indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'));
   indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'));
   indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'));
   indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'));
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++)
     indic_plan->mask_array[i] = indic_features[i].is_global ? 0 : plan->map.get_1_mask (indic_features[i].tag);
 
   return indic_plan;
@@ -423,17 +429,19 @@ update_consonant_positions (const hb_ot_
   }
 }
 
 
 /* Rules from:
  * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */
 
 static void
-initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer,
+initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
+				       hb_face_t *face,
+				       hb_buffer_t *buffer,
 				       unsigned int start, unsigned int end)
 {
   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
   hb_glyph_info_t *info = buffer->info;
 
 
   /* 1. Find base consonant:
    *
@@ -454,32 +462,39 @@ initial_reordering_consonant_syllable (c
 
   {
     /* -> If the syllable starts with Ra + Halant (in a script that has Reph)
      *    and has more than one consonant, Ra is excluded from candidates for
      *    base consonants. */
     unsigned int limit = start;
     if (indic_plan->mask_array[RPHF] &&
 	start + 3 <= end &&
-	info[start].indic_category() == OT_Ra &&
-	info[start + 1].indic_category() == OT_H &&
 	(/* TODO Handle other Reph modes. */
 	 (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) ||
 	 (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ)
 	))
     {
-      limit += 2;
-      while (limit < end && is_joiner (info[limit]))
-        limit++;
-      base = start;
-      has_reph = true;
+      /* See if it matches the 'rphf' feature. */
+      hb_codepoint_t glyphs[2] = {info[start].codepoint, info[start + 1].codepoint};
+      if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face))
+      {
+	limit += 2;
+	while (limit < end && is_joiner (info[limit]))
+	  limit++;
+	base = start;
+	has_reph = true;
+      }
     };
 
     switch (indic_plan->config->base_pos)
     {
+      default:
+        assert (false);
+	/* fallthrough */
+
       case BASE_POS_LAST:
       {
 	/* -> starting from the end of the syllable, move backwards */
 	unsigned int i = end;
 	bool seen_below = false;
 	do {
 	  i--;
 	  /* -> until a consonant is found */
@@ -509,17 +524,17 @@ initial_reordering_consonant_syllable (c
 	    base = i;
 	  }
 	  else
 	  {
 	    /* A ZWJ after a Halant stops the base search, and requests an explicit
 	     * half form.
 	     * A ZWJ before a Halant, requests a subjoined form instead, and hence
 	     * search continues.  This is particularly important for Bengali
-	     * sequence Ra,H,Ya that shouls form Ya-Phalaa by subjoining Ya. */
+	     * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */
 	    if (start < i &&
 		info[i].indic_category() == OT_ZWJ &&
 		info[i - 1].indic_category() == OT_H)
 	      break;
 	  }
 	} while (i > limit);
       }
       break;
@@ -543,19 +558,16 @@ initial_reordering_consonant_syllable (c
 	  }
 
 	/* Mark all subsequent consonants as below. */
 	for (unsigned int i = base + 1; i < end; i++)
 	  if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C)
 	    info[i].indic_position() = POS_BELOW_C;
       }
       break;
-
-      default:
-      abort ();
     }
 
     /* -> If the syllable starts with Ra + Halant (in a script that has Reph)
      *    and has more than one consonant, Ra is excluded from candidates for
      *    base consonants.
      *
      *  Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */
     if (has_reph && base == start && start + 2 == limit) {
@@ -646,23 +658,27 @@ initial_reordering_consonant_syllable (c
   /* Attach misc marks to previous char to move with them. */
   {
     indic_position_t last_pos = POS_START;
     for (unsigned int i = start; i < end; i++)
     {
       if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | HALANT_OR_COENG_FLAGS)))
       {
 	info[i].indic_position() = last_pos;
-	if (unlikely (indic_options ().uniscribe_bug_compatible &&
-		      info[i].indic_category() == OT_H &&
+	if (unlikely (info[i].indic_category() == OT_H &&
 		      info[i].indic_position() == POS_PRE_M))
 	{
 	  /*
 	   * Uniscribe doesn't move the Halant with Left Matra.
 	   * TEST: U+092B,U+093F,U+094DE
+	   * We follow.  This is important for the Sinhala
+	   * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA
+	   * where U+0DD9 is a left matra and U+0DCA is the virama.
+	   * We don't want to move the virama with the left matra.
+	   * TEST: U+0D9A,U+0DDA
 	   */
 	  for (unsigned int j = i; j > start; j--)
 	    if (info[j - 1].indic_position() != POS_PRE_M) {
 	      info[i].indic_position() = info[j - 1].indic_position();
 	      break;
 	    }
 	}
       } else if (info[i].indic_position() != POS_SMVD) {
@@ -720,34 +736,35 @@ initial_reordering_consonant_syllable (c
     mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF];
     for (unsigned int i = base + 1; i < end; i++)
       info[i].mask  |= mask;
   }
 
   if (indic_plan->mask_array[PREF] && base + 2 < end)
   {
     /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
-    for (unsigned int i = base + 1; i + 1 < end; i++)
-      if (is_halant_or_coeng (info[i + (indic_plan->is_old_spec ? 1 : 0)]) &&
-	  info[i + (indic_plan->is_old_spec ? 0 : 1)].indic_category() == OT_Ra)
+    for (unsigned int i = base + 1; i + 1 < end; i++) {
+      hb_codepoint_t glyphs[2] = {info[i].codepoint, info[i + 1].codepoint};
+      if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face))
       {
 	info[i++].mask |= indic_plan->mask_array[PREF];
 	info[i++].mask |= indic_plan->mask_array[PREF];
 
 	/* Mark the subsequent stuff with 'cfar'.  Used in Khmer.
 	 * Read the feature spec.
 	 * This allows distinguishing the following cases with MS Khmer fonts:
 	 * U+1784,U+17D2,U+179A,U+17D2,U+1782
 	 * U+1784,U+17D2,U+1782,U+17D2,U+179A
 	 */
 	for (; i < end; i++)
 	  info[i].mask |= indic_plan->mask_array[CFAR];
 
 	break;
       }
+    }
   }
 
   /* Apply ZWJ/ZWNJ effects */
   for (unsigned int i = start + 1; i < end; i++)
     if (is_joiner (info[i])) {
       bool non_joiner = info[i].indic_category() == OT_ZWNJ;
       unsigned int j = i;
 
@@ -763,74 +780,79 @@ initial_reordering_consonant_syllable (c
 
       } while (j > start && !is_consonant (info[j]));
     }
 }
 
 
 static void
 initial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan,
+				   hb_face_t *face,
 				   hb_buffer_t *buffer,
 				   unsigned int start, unsigned int end)
 {
   /* We made the vowels look like consonants.  So let's call the consonant logic! */
-  initial_reordering_consonant_syllable (plan, buffer, start, end);
+  initial_reordering_consonant_syllable (plan, face, buffer, start, end);
 }
 
 static void
 initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
+				       hb_face_t *face,
 				       hb_buffer_t *buffer,
 				       unsigned int start, unsigned int end)
 {
   /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain.
    * Only if not in compatibility mode that is... */
 
   if (indic_options ().uniscribe_bug_compatible)
   {
     /* For dotted-circle, this is what Uniscribe does:
      * If dotted-circle is the last glyph, it just does nothing.
      * Ie. It doesn't form Reph. */
     if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE)
       return;
   }
 
-  initial_reordering_consonant_syllable (plan, buffer, start, end);
+  initial_reordering_consonant_syllable (plan, face, buffer, start, end);
 }
 
 static void
 initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
+				   hb_face_t *face,
 				   hb_buffer_t *buffer,
 				   unsigned int start, unsigned int end)
 {
   /* We already inserted dotted-circles, so just call the standalone_cluster. */
-  initial_reordering_standalone_cluster (plan, buffer, start, end);
+  initial_reordering_standalone_cluster (plan, face, buffer, start, end);
 }
 
 static void
 initial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+				      hb_face_t *face HB_UNUSED,
 				      hb_buffer_t *buffer HB_UNUSED,
 				      unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
 {
   /* Nothing to do right now.  If we ever switch to using the output
    * buffer in the reordering process, we'd need to next_glyph() here. */
 }
 
 
 static void
 initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
+			     hb_face_t *face,
 			     hb_buffer_t *buffer,
 			     unsigned int start, unsigned int end)
 {
   syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
   switch (syllable_type) {
-  case consonant_syllable:	initial_reordering_consonant_syllable (plan, buffer, start, end); return;
-  case vowel_syllable:		initial_reordering_vowel_syllable     (plan, buffer, start, end); return;
-  case standalone_cluster:	initial_reordering_standalone_cluster (plan, buffer, start, end); return;
-  case broken_cluster:		initial_reordering_broken_cluster     (plan, buffer, start, end); return;
-  case non_indic_cluster:	initial_reordering_non_indic_cluster  (plan, buffer, start, end); return;
+  case consonant_syllable:	initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
+  case vowel_syllable:		initial_reordering_vowel_syllable     (plan, face, buffer, start, end); return;
+  case standalone_cluster:	initial_reordering_standalone_cluster (plan, face, buffer, start, end); return;
+  case broken_cluster:		initial_reordering_broken_cluster     (plan, face, buffer, start, end); return;
+  case non_indic_cluster:	initial_reordering_non_indic_cluster  (plan, face, buffer, start, end); return;
   }
 }
 
 static inline void
 insert_dotted_circles (const hb_ot_shape_plan_t *plan,
 		       hb_font_t *font,
 		       hb_buffer_t *buffer)
 {
@@ -845,17 +867,17 @@ insert_dotted_circles (const hb_ot_shape
   if (likely (!has_broken_syllables))
     return;
 
 
   hb_codepoint_t dottedcircle_glyph;
   if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph))
     return;
 
-  hb_glyph_info_t dottedcircle;
+  hb_glyph_info_t dottedcircle = {0};
   dottedcircle.codepoint = 0x25CC;
   set_indic_properties (dottedcircle);
   dottedcircle.codepoint = dottedcircle_glyph;
 
   buffer->clear_output ();
 
   buffer->idx = 0;
   unsigned int last_syllable = 0;
@@ -888,21 +910,21 @@ initial_reordering (const hb_ot_shape_pl
 
   hb_glyph_info_t *info = buffer->info;
   unsigned int count = buffer->len;
   if (unlikely (!count)) return;
   unsigned int last = 0;
   unsigned int last_syllable = info[0].syllable();
   for (unsigned int i = 1; i < count; i++)
     if (last_syllable != info[i].syllable()) {
-      initial_reordering_syllable (plan, buffer, last, i);
+      initial_reordering_syllable (plan, font->face, buffer, last, i);
       last = i;
       last_syllable = info[last].syllable();
     }
-  initial_reordering_syllable (plan, buffer, last, count);
+  initial_reordering_syllable (plan, font->face, buffer, last, count);
 }
 
 static void
 final_reordering_syllable (const hb_ot_shape_plan_t *plan,
 			   hb_buffer_t *buffer,
 			   unsigned int start, unsigned int end)
 {
   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
@@ -1152,31 +1174,38 @@ final_reordering_syllable (const hb_ot_s
 	   *       2. Try to find a target position the same way as for pre-base matra.
 	   *          If it is found, reorder pre-base consonant glyph.
 	   *
 	   *       3. If position is not found, reorder immediately before main
 	   *          consonant.
 	   */
 
 	  unsigned int new_pos = base;
-	  while (new_pos > start &&
-		 !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS)))
-	    new_pos--;
-
-	  /* In Khmer coeng model, a V,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)
+	  /* Malayalam / Tamil do not have "half" forms or explicit virama forms.
+	   * The glyphs formed by 'half' are Chillus or ligated explicit viramas.
+	   * We want to position matra after them.
+	   */
+	  if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
 	  {
-	    unsigned int old_pos = i;
-	    for (unsigned int i = base + 1; i < old_pos; i++)
-	      if (info[i].indic_category() == OT_M)
-	      {
-		new_pos--;
-		break;
-	      }
+	    while (new_pos > start &&
+		   !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS)))
+	      new_pos--;
+
+	    /* In Khmer coeng model, a V,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 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]))
 	    /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
 	    if (new_pos < end && is_joiner (info[new_pos]))
 	      new_pos++;
 
 	  {
@@ -1239,25 +1268,125 @@ final_reordering (const hb_ot_shape_plan
     info[i].syllable() = 0;
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
 }
 
 
 static hb_ot_shape_normalization_mode_t
-normalization_preference_indic (const hb_ot_shape_plan_t *plan)
+normalization_preference_indic (const hb_segment_properties_t *props)
 {
   return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
 }
 
+static bool
+decompose_indic (const hb_ot_shape_normalize_context_t *c,
+		 hb_codepoint_t  ab,
+		 hb_codepoint_t *a,
+		 hb_codepoint_t *b)
+{
+  switch (ab)
+  {
+    /* Don't decompose these. */
+    case 0x0931  : return false;
+    case 0x0B94  : return false;
+
+
+    /*
+     * Decompose split matras that don't have Unicode decompositions.
+     */
+
+    case 0x0F77  : *a = 0x0FB2; *b= 0x0F81; return true;
+    case 0x0F79  : *a = 0x0FB3; *b= 0x0F81; return true;
+    case 0x17BE  : *a = 0x17C1; *b= 0x17BE; return true;
+    case 0x17BF  : *a = 0x17C1; *b= 0x17BF; return true;
+    case 0x17C0  : *a = 0x17C1; *b= 0x17C0; return true;
+    case 0x17C4  : *a = 0x17C1; *b= 0x17C4; return true;
+    case 0x17C5  : *a = 0x17C1; *b= 0x17C5; return true;
+    case 0x1925  : *a = 0x1920; *b= 0x1923; return true;
+    case 0x1926  : *a = 0x1920; *b= 0x1924; return true;
+    case 0x1B3C  : *a = 0x1B42; *b= 0x1B3C; return true;
+    case 0x1112E  : *a = 0x11127; *b= 0x11131; return true;
+    case 0x1112F  : *a = 0x11127; *b= 0x11132; return true;
+#if 0
+    /* This one has no decomposition in Unicode, but needs no decomposition either. */
+    /* case 0x0AC9  : return false; */
+    case 0x0B57  : *a = no decomp, -> RIGHT; return true;
+    case 0x1C29  : *a = no decomp, -> LEFT; return true;
+    case 0xA9C0  : *a = no decomp, -> RIGHT; return true;
+    case 0x111BF  : *a = no decomp, -> ABOVE; return true;
+#endif
+  }
+
+  if ((ab == 0x0DDA || hb_in_range<hb_codepoint_t> (ab, 0x0DDC, 0x0DDE)))
+  {
+    /*
+     * Sinhala split matras...  Let the fun begin.
+     *
+     * These four characters have Unicode decompositions.  However, Uniscribe
+     * decomposes them "Khmer-style", that is, it uses the character itself to
+     * get the second half.  The first half of all four decompositions is always
+     * U+0DD9.
+     *
+     * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are
+     * broken with Uniscribe.  But we need to support them.  As such, we only
+     * do the Uniscribe-style decomposition if the character is transformed into
+     * its "sec.half" form by the 'pstf' feature.  Otherwise, we fall back to
+     * Unicode decomposition.
+     *
+     * Note that we can't unconditionally use Unicode decomposition.  That would
+     * break some other fonts, that are designed to work with Uniscribe, and
+     * don't have positioning features for the Unicode-style decomposition.
+     *
+     * Argh...
+     */
+
+    const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data;
+
+    hb_codepoint_t glyph;
+
+    if (indic_options ().uniscribe_bug_compatible ||
+	(c->font->get_glyph (ab, 0, &glyph) &&
+	 indic_plan->pstf.would_substitute (&glyph, 1, true, c->font->face)))
+    {
+      /* Ok, safe to use Uniscribe-style decomposition. */
+      *a = 0x0DD9;
+      *b = ab;
+      return true;
+    }
+  }
+
+  return c->unicode->decompose (ab, a, b);
+}
+
+static bool
+compose_indic (const hb_ot_shape_normalize_context_t *c,
+	       hb_codepoint_t  a,
+	       hb_codepoint_t  b,
+	       hb_codepoint_t *ab)
+{
+  /* Avoid recomposing split matras. */
+  if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a)))
+    return false;
+
+  /* Composition-exclusion exceptions that we want to recompose. */
+  if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; }
+
+  return c->unicode->compose (a, b, ab);
+}
+
+
 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 */
   normalization_preference_indic,
+  decompose_indic,
+  compose_indic,
   setup_masks_indic,
   false, /* zero_width_attached_marks */
+  false, /* fallback_position */
 };
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-misc.cc
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright © 2010,2012  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#include "hb-ot-shape-complex-private.hh"
-
-
-/* TODO Add kana, and other small shapers here */
-
-
-/* The default shaper *only* adds additional per-script features.*/
-
-static const hb_tag_t hangul_features[] =
-{
-  HB_TAG('l','j','m','o'),
-  HB_TAG('v','j','m','o'),
-  HB_TAG('t','j','m','o'),
-  HB_TAG_NONE
-};
-
-static const hb_tag_t tibetan_features[] =
-{
-  HB_TAG('a','b','v','s'),
-  HB_TAG('b','l','w','s'),
-  HB_TAG('a','b','v','m'),
-  HB_TAG('b','l','w','m'),
-  HB_TAG_NONE
-};
-
-static void
-collect_features_default (hb_ot_shape_planner_t *plan)
-{
-  const hb_tag_t *script_features = NULL;
-
-  switch ((hb_tag_t) plan->props.script)
-  {
-    /* Unicode-1.1 additions */
-    case HB_SCRIPT_HANGUL:
-      script_features = hangul_features;
-      break;
-
-    /* Unicode-2.0 additions */
-    case HB_SCRIPT_TIBETAN:
-      script_features = tibetan_features;
-      break;
-  }
-
-  for (; script_features && *script_features; script_features++)
-    plan->map.add_bool_feature (*script_features);
-}
-
-static hb_ot_shape_normalization_mode_t
-normalization_preference_default (const hb_ot_shape_plan_t *plan)
-{
-  switch ((hb_tag_t) plan->props.script)
-  {
-    /* Unicode-1.1 additions */
-    case HB_SCRIPT_HANGUL:
-      return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL;
-  }
-  return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
-}
-
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
-{
-  "default",
-  collect_features_default,
-  NULL, /* override_features */
-  NULL, /* data_create */
-  NULL, /* data_destroy */
-  NULL, /* preprocess_text */
-  normalization_preference_default,
-  NULL, /* setup_masks */
-  true, /* zero_width_attached_marks */
-};
-
-
-/* Thai / Lao shaper */
-
-static void
-preprocess_text_thai (const hb_ot_shape_plan_t *plan HB_UNUSED,
-		      hb_buffer_t              *buffer,
-		      hb_font_t                *font HB_UNUSED)
-{
-  /* The following is NOT specified in the MS OT Thai spec, however, it seems
-   * to be what Uniscribe and other engines implement.  According to Eric Muller:
-   *
-   * When you have a SARA AM, decompose it in NIKHAHIT + SARA AA, *and* move the
-   * NIKHAHIT backwards over any tone mark (0E48-0E4B).
-   *
-   * <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32>
-   *
-   * This reordering is legit only when the NIKHAHIT comes from a SARA AM, not
-   * when it's there to start with. The string <0E14, 0E4B, 0E4D> is probably
-   * not what a user wanted, but the rendering is nevertheless nikhahit above
-   * chattawa.
-   *
-   * Same for Lao.
-   *
-   * Note:
-   *
-   * Uniscribe also does so below-marks reordering.  Namely, it positions U+0E3A
-   * after U+0E38 and U+0E39.  We do that by modifying the ccc for U+0E3A.
-   * See unicode->modified_combining_class ().  Lao does NOT have a U+0E3A
-   * equivalent.
-   */
-
-
-  /*
-   * Here are the characters of significance:
-   *
-   *			Thai	Lao
-   * SARA AM:		U+0E33	U+0EB3
-   * SARA AA:		U+0E32	U+0EB2
-   * Nikhahit:		U+0E4D	U+0ECD
-   *
-   * Testing shows that Uniscribe reorder the following marks:
-   * Thai:	<0E31,0E34..0E37,0E47..0E4E>
-   * Lao:	<0EB1,0EB4..0EB7,0EC7..0ECE>
-   *
-   * Note how the Lao versions are the same as Thai + 0x80.
-   */
-
-  /* We only get one script at a time, so a script-agnostic implementation
-   * is adequate here. */
-#define IS_SARA_AM(x) (((x) & ~0x0080) == 0x0E33)
-#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0xE33 + 0xE4D)
-#define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
-#define IS_TONE_MARK(x) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080, 0x0E34, 0x0E37, 0x0E47, 0x0E4E, 0x0E31, 0x0E31))
-
-  buffer->clear_output ();
-  unsigned int count = buffer->len;
-  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;
-
-    /* Ok, let's see... */
-    unsigned int end = buffer->out_len;
-    unsigned int start = end - 2;
-    while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
-      start--;
-
-    if (start + 2 < end)
-    {
-      /* Move Nikhahit (end-2) to the beginning */
-      buffer->merge_out_clusters (start, end);
-      hb_glyph_info_t t = buffer->out_info[end - 2];
-      memmove (buffer->out_info + start + 1,
-	       buffer->out_info + start,
-	       sizeof (buffer->out_info[0]) * (end - start - 2));
-      buffer->out_info[start] = t;
-    }
-    else
-    {
-      /* Since we decomposed, and NIKHAHIT is combining, merge clusters with the
-       * previous cluster. */
-      if (start)
-	buffer->merge_out_clusters (start - 1, end);
-    }
-  }
-  buffer->swap_buffers ();
-}
-
-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, /* normalization_preference */
-  NULL, /* setup_masks */
-  true, /* zero_width_attached_marks */
-};
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
@@ -51,95 +51,127 @@
 
 struct hb_ot_complex_shaper_t
 {
   char name[8];
 
   /* collect_features()
    * Called during shape_plan().
    * Shapers should use plan->map to add their features and callbacks.
+   * May be NULL.
    */
   void (*collect_features) (hb_ot_shape_planner_t *plan);
 
   /* override_features()
    * Called during shape_plan().
    * Shapers should use plan->map to override features and add callbacks after
    * common features are added.
+   * May be NULL.
    */
   void (*override_features) (hb_ot_shape_planner_t *plan);
 
 
   /* data_create()
    * Called at the end of shape_plan().
    * Whatever shapers return will be accessible through plan->data later.
    * If NULL is returned, means a plan failure.
    */
   void *(*data_create) (const hb_ot_shape_plan_t *plan);
 
   /* data_destroy()
    * Called when the shape_plan is being destroyed.
    * plan->data is passed here for destruction.
    * If NULL is returned, means a plan failure.
-   * May be NULL. */
+   * May be NULL.
+   */
   void (*data_destroy) (void *data);
 
 
   /* preprocess_text()
    * 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);
 
 
   /* normalization_preference()
    * Called during shape().
+   * May be NULL.
    */
   hb_ot_shape_normalization_mode_t
-  (*normalization_preference) (const hb_ot_shape_plan_t *plan);
+  (*normalization_preference) (const hb_segment_properties_t *props);
+
+  /* decompose()
+   * Called during shape()'s normalization.
+   * May be NULL.
+   */
+  bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
+		     hb_codepoint_t  ab,
+		     hb_codepoint_t *a,
+		     hb_codepoint_t *b);
+
+  /* compose()
+   * Called during shape()'s normalization.
+   * May be NULL.
+   */
+  bool (*compose) (const hb_ot_shape_normalize_context_t *c,
+		   hb_codepoint_t  a,
+		   hb_codepoint_t  b,
+		   hb_codepoint_t *ab);
 
   /* setup_masks()
    * Called during shape().
    * Shapers should use map to get feature masks and set on buffer.
    * Shapers may NOT modify characters.
+   * May be NULL.
    */
   void (*setup_masks) (const hb_ot_shape_plan_t *plan,
 		       hb_buffer_t              *buffer,
 		       hb_font_t                *font);
 
   bool zero_width_attached_marks;
+  bool fallback_position;
 };
 
 #define HB_COMPLEX_SHAPER_IMPLEMENT(name) extern HB_INTERNAL const hb_ot_complex_shaper_t _hb_ot_complex_shaper_##name;
 HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
 #undef HB_COMPLEX_SHAPER_IMPLEMENT
 
 
 static inline const hb_ot_complex_shaper_t *
-hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
+hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
 {
-  switch ((hb_tag_t) props->script)
+  switch ((hb_tag_t) planner->props.script)
   {
     default:
       return &_hb_ot_complex_shaper_default;
 
 
     /* Unicode-1.1 additions */
     case HB_SCRIPT_ARABIC:
     case HB_SCRIPT_MONGOLIAN:
     case HB_SCRIPT_SYRIAC:
 
     /* Unicode-5.0 additions */
     case HB_SCRIPT_NKO:
+    case HB_SCRIPT_PHAGS_PA:
 
     /* Unicode-6.0 additions */
     case HB_SCRIPT_MANDAIC:
 
-      return &_hb_ot_complex_shaper_arabic;
+      /* For Arabic script, use the Arabic shaper even if no OT script tag was found.
+       * This is because we do fallback shaping for Arabic script (and not others). */
+      if (planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
+	  planner->props.script == HB_SCRIPT_ARABIC)
+	return &_hb_ot_complex_shaper_arabic;
+      else
+	return &_hb_ot_complex_shaper_default;
 
 
     /* Unicode-1.1 additions */
     case HB_SCRIPT_THAI:
     case HB_SCRIPT_LAO:
 
       return &_hb_ot_complex_shaper_thai;
 
@@ -165,19 +197,16 @@ hb_ot_shape_complex_categorize (const hb
 
     /* Unicode-3.2 additions */
     case HB_SCRIPT_BUHID:
     case HB_SCRIPT_HANUNOO:
 
     /* Unicode-5.1 additions */
     case HB_SCRIPT_SAURASHTRA:
 
-    /* Unicode-5.2 additions */
-    case HB_SCRIPT_MEETEI_MAYEK:
-
     /* Unicode-6.0 additions */
     case HB_SCRIPT_BATAK:
     case HB_SCRIPT_BRAHMI:
 
 
     /* Simple */
 
     /* Unicode-1.1 additions */
@@ -192,73 +221,89 @@ hb_ot_shape_complex_categorize (const hb
     case HB_SCRIPT_TAGALOG:
     case HB_SCRIPT_TAGBANWA:
 
     /* Unicode-4.0 additions */
     case HB_SCRIPT_LIMBU:
     case HB_SCRIPT_TAI_LE:
 
     /* Unicode-4.1 additions */
+    case HB_SCRIPT_KHAROSHTHI:
     case HB_SCRIPT_SYLOTI_NAGRI:
 
-    /* Unicode-5.0 additions */
-    case HB_SCRIPT_PHAGS_PA:
-
     /* Unicode-5.1 additions */
     case HB_SCRIPT_KAYAH_LI:
 
     /* Unicode-5.2 additions */
     case HB_SCRIPT_TAI_VIET:
 
 
-    /* May need Indic treatment in the future? */
-
-    /* Unicode-3.0 additions */
-    case HB_SCRIPT_MYANMAR:
-
-
 #endif
 
     /* Unicode-1.1 additions */
     case HB_SCRIPT_BENGALI:
     case HB_SCRIPT_DEVANAGARI:
     case HB_SCRIPT_GUJARATI:
     case HB_SCRIPT_GURMUKHI:
     case HB_SCRIPT_KANNADA:
     case HB_SCRIPT_MALAYALAM:
     case HB_SCRIPT_ORIYA:
     case HB_SCRIPT_TAMIL:
     case HB_SCRIPT_TELUGU:
 
     /* Unicode-3.0 additions */
-    case HB_SCRIPT_KHMER:
     case HB_SCRIPT_SINHALA:
 
     /* Unicode-4.1 additions */
     case HB_SCRIPT_BUGINESE:
-    case HB_SCRIPT_KHAROSHTHI:
     case HB_SCRIPT_NEW_TAI_LUE:
 
     /* Unicode-5.0 additions */
     case HB_SCRIPT_BALINESE:
 
     /* Unicode-5.1 additions */
     case HB_SCRIPT_CHAM:
     case HB_SCRIPT_LEPCHA:
     case HB_SCRIPT_REJANG:
     case HB_SCRIPT_SUNDANESE:
 
     /* Unicode-5.2 additions */
     case HB_SCRIPT_JAVANESE:
     case HB_SCRIPT_KAITHI:
+    case HB_SCRIPT_MEETEI_MAYEK:
     case HB_SCRIPT_TAI_THAM:
 
+
     /* Unicode-6.1 additions */
     case HB_SCRIPT_CHAKMA:
     case HB_SCRIPT_SHARADA:
     case HB_SCRIPT_TAKRI:
 
-      return &_hb_ot_complex_shaper_indic;
+      /* Only use Indic shaper if the font has Indic tables. */
+      if (planner->map.found_script[0])
+	return &_hb_ot_complex_shaper_indic;
+      else
+	return &_hb_ot_complex_shaper_default;
+
+    case HB_SCRIPT_KHMER:
+      /* If the font has 'liga', let the generic shaper do it. */
+      if (!planner->map.found_script[0] ||
+	  hb_ot_layout_language_find_feature (planner->face, HB_OT_TAG_GSUB,
+					      planner->map.script_index[0],
+					      planner->map.language_index[0],
+					      HB_TAG ('l','i','g','a'), NULL))
+	return &_hb_ot_complex_shaper_default;
+      else
+	return &_hb_ot_complex_shaper_indic;
+
+
+    case HB_SCRIPT_MYANMAR:
+      /* For Myanmar, we only want to use the Indic shaper if the "new" script
+       * tag is found.  For "old" script tag we want to use the default shaper. */
+      if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','2'))
+	return &_hb_ot_complex_shaper_indic;
+      else
+	return &_hb_ot_complex_shaper_default;
   }
 }
 
 
 #endif /* HB_OT_SHAPE_COMPLEX_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
@@ -0,0 +1,378 @@
+/*
+ * Copyright © 2010,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+/* Thai / Lao shaper */
+
+
+/* PUA shaping */
+
+
+enum thai_consonant_type_t
+{
+  NC,
+  AC,
+  RC,
+  DC,
+  NOT_CONSONANT,
+  NUM_CONSONANT_TYPES = NOT_CONSONANT
+};
+
+static thai_consonant_type_t
+get_consonant_type (hb_codepoint_t u)
+{
+  if (u == 0x0E1B || u == 0x0E1D || u == 0x0E1F/* || u == 0x0E2C*/)
+    return AC;
+  if (u == 0x0E0D || u == 0x0E10)
+    return RC;
+  if (u == 0x0E0E || u == 0x0E0F)
+    return DC;
+  if (hb_in_range<hb_codepoint_t> (u, 0x0E01, 0x0E2E))
+    return NC;
+  return NOT_CONSONANT;
+}
+
+
+enum thai_mark_type_t
+{
+  AV,
+  BV,
+  T,
+  NOT_MARK,
+  NUM_MARK_TYPES = NOT_MARK
+};
+
+static thai_mark_type_t
+get_mark_type (hb_codepoint_t u)
+{
+  if (u == 0x0E31 || hb_in_range<hb_codepoint_t> (u, 0x0E34, 0x0E37) ||
+      u == 0x0E47 || hb_in_range<hb_codepoint_t> (u, 0x0E4D, 0x0E4E))
+    return AV;
+  if (hb_in_range<hb_codepoint_t> (u, 0x0E38, 0x0E3A))
+    return BV;
+  if (hb_in_range<hb_codepoint_t> (u, 0x0E48, 0x0E4C))
+    return T;
+  return NOT_MARK;
+}
+
+
+enum thai_action_t
+{
+  NOP,
+  SD,  /* Shift combining-mark down */
+  SL,  /* Shift combining-mark left */
+  SDL, /* Shift combining-mark down-left */
+  RD   /* Remove descender from base */
+};
+
+static hb_codepoint_t
+thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font)
+{
+  struct thai_pua_mapping_t {
+    hb_codepoint_t u;
+    hb_codepoint_t win_pua;
+    hb_codepoint_t mac_pua;
+  } const *pua_mappings = NULL;
+  static const thai_pua_mapping_t SD_mappings[] = {
+    {0x0E48, 0xF70A, 0xF88B}, /* MAI EK */
+    {0x0E49, 0xF70B, 0xF88E}, /* MAI THO */
+    {0x0E4A, 0xF70C, 0xF891}, /* MAI TRI */
+    {0x0E4B, 0xF70D, 0xF894}, /* MAI CHATTAWA */
+    {0x0E4C, 0xF70E, 0xF897}, /* THANTHAKHAT */
+    {0x0E38, 0xF718, 0xF89B}, /* SARA U */
+    {0x0E39, 0xF719, 0xF89C}, /* SARA UU */
+    {0x0E3A, 0xF71A, 0xF89D}, /* PHINTHU */
+    {0x0000, 0x0000, 0x0000}
+  };
+  static const thai_pua_mapping_t SDL_mappings[] = {
+    {0x0E48, 0xF705, 0xF88C}, /* MAI EK */
+    {0x0E49, 0xF706, 0xF88F}, /* MAI THO */
+    {0x0E4A, 0xF707, 0xF892}, /* MAI TRI */
+    {0x0E4B, 0xF708, 0xF895}, /* MAI CHATTAWA */
+    {0x0E4C, 0xF709, 0xF898}, /* THANTHAKHAT */
+    {0x0000, 0x0000, 0x0000}
+  };
+  static const thai_pua_mapping_t SL_mappings[] = {
+    {0x0E48, 0xF713, 0xF88A}, /* MAI EK */
+    {0x0E49, 0xF714, 0xF88D}, /* MAI THO */
+    {0x0E4A, 0xF715, 0xF890}, /* MAI TRI */
+    {0x0E4B, 0xF716, 0xF893}, /* MAI CHATTAWA */
+    {0x0E4C, 0xF717, 0xF896}, /* THANTHAKHAT */
+    {0x0E31, 0xF710, 0xF884}, /* MAI HAN-AKAT */
+    {0x0E34, 0xF701, 0xF885}, /* SARA I */
+    {0x0E35, 0xF702, 0xF886}, /* SARA II */
+    {0x0E36, 0xF703, 0xF887}, /* SARA UE */
+    {0x0E37, 0xF704, 0xF888}, /* SARA UEE */
+    {0x0E47, 0xF712, 0xF889}, /* MAITAIKHU */
+    {0x0E4D, 0xF711, 0xF899}, /* NIKHAHIT */
+    {0x0000, 0x0000, 0x0000}
+  };
+  static const thai_pua_mapping_t RD_mappings[] = {
+    {0x0E0D, 0xF70F, 0xF89A}, /* YO YING */
+    {0x0E10, 0xF700, 0xF89E}, /* THO THAN */
+    {0x0000, 0x0000, 0x0000}
+  };
+
+  switch (action) {
+    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)
+    {
+      hb_codepoint_t glyph;
+      if (hb_font_get_glyph (font, pua_mappings->win_pua, 0, &glyph))
+	return pua_mappings->win_pua;
+      if (hb_font_get_glyph (font, pua_mappings->mac_pua, 0, &glyph))
+	return pua_mappings->mac_pua;
+      break;
+    }
+  return u;
+}
+
+
+static enum thai_above_state_t
+{     /* Cluster above looks like: */
+  T0, /*  ⣤                      */
+  T1, /*     ⣼                   */
+  T2, /*        ⣾                */
+  T3, /*           ⣿             */
+  NUM_ABOVE_STATES
+} thai_above_start_state[NUM_CONSONANT_TYPES + 1/* For NOT_CONSONANT */] =
+{
+  T0, /* NC */
+  T1, /* AC */
+  T0, /* RC */
+  T0, /* DC */
+  T3, /* NOT_CONSONANT */
+};
+
+static const struct thai_above_state_machine_edge_t {
+  thai_action_t action;
+  thai_above_state_t next_state;
+} thai_above_state_machine[NUM_ABOVE_STATES][NUM_MARK_TYPES] =
+{        /*AV*/    /*BV*/    /*T*/
+/*T0*/ {{NOP,T3}, {NOP,T0}, {SD, T3}},
+/*T1*/ {{SL, T2}, {NOP,T1}, {SDL,T2}},
+/*T2*/ {{NOP,T3}, {NOP,T2}, {SL, T3}},
+/*T3*/ {{NOP,T3}, {NOP,T3}, {NOP,T3}},
+};
+
+
+static enum thai_below_state_t
+{
+  B0, /* No descender */
+  B1, /* Removable descender */
+  B2, /* Strict descender */
+  NUM_BELOW_STATES
+} thai_below_start_state[NUM_CONSONANT_TYPES + 1/* For NOT_CONSONANT */] =
+{
+  B0, /* NC */
+  B0, /* AC */
+  B1, /* RC */
+  B2, /* DC */
+  B2, /* NOT_CONSONANT */
+};
+
+static const struct thai_below_state_machine_edge_t {
+  thai_action_t action;
+  thai_below_state_t next_state;
+} thai_below_state_machine[NUM_BELOW_STATES][NUM_MARK_TYPES] =
+{        /*AV*/    /*BV*/    /*T*/
+/*B0*/ {{NOP,B0}, {NOP,B2}, {NOP, B0}},
+/*B1*/ {{NOP,B1}, {RD, B2}, {NOP, B1}},
+/*B2*/ {{NOP,B2}, {SD, B2}, {NOP, B2}},
+};
+
+
+static void
+do_thai_pua_shaping (const hb_ot_shape_plan_t *plan,
+		     hb_buffer_t              *buffer,
+		     hb_font_t                *font)
+{
+  thai_above_state_t above_state = thai_above_start_state[NOT_CONSONANT];
+  thai_below_state_t below_state = thai_below_start_state[NOT_CONSONANT];
+  unsigned int base = 0;
+
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    thai_mark_type_t mt = get_mark_type (info[i].codepoint);
+
+    if (mt == NOT_MARK) {
+      thai_consonant_type_t ct = get_consonant_type (info[i].codepoint);
+      above_state = thai_above_start_state[ct];
+      below_state = thai_below_start_state[ct];
+      base = i;
+      continue;
+    }
+
+    const thai_above_state_machine_edge_t &above_edge = thai_above_state_machine[above_state][mt];
+    const thai_below_state_machine_edge_t &below_edge = thai_below_state_machine[below_state][mt];
+    above_state = above_edge.next_state;
+    below_state = below_edge.next_state;
+
+    /* At least one of the above/below actions is NOP. */
+    thai_action_t action = above_edge.action != NOP ? above_edge.action : below_edge.action;
+
+    if (action == RD)
+      info[base].codepoint = thai_pua_shape (info[base].codepoint, action, font);
+    else
+      info[i].codepoint = thai_pua_shape (info[i].codepoint, action, font);
+  }
+}
+
+
+static void
+preprocess_text_thai (const hb_ot_shape_plan_t *plan,
+		      hb_buffer_t              *buffer,
+		      hb_font_t                *font)
+{
+  /* This function implements the shaping logic documented here:
+   *
+   *   http://linux.thai.net/~thep/th-otf/shaping.html
+   *
+   * The first shaping rule listed there is needed even if the font has Thai
+   * OpenType tables.  The rest do fallback positioning based on PUA codepoints.
+   * We implement that only if there exist no Thai GSUB in the font.
+   */
+
+  /* The following is NOT specified in the MS OT Thai spec, however, it seems
+   * to be what Uniscribe and other engines implement.  According to Eric Muller:
+   *
+   * When you have a SARA AM, decompose it in NIKHAHIT + SARA AA, *and* move the
+   * NIKHAHIT backwards over any tone mark (0E48-0E4B).
+   *
+   * <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32>
+   *
+   * This reordering is legit only when the NIKHAHIT comes from a SARA AM, not
+   * when it's there to start with. The string <0E14, 0E4B, 0E4D> is probably
+   * not what a user wanted, but the rendering is nevertheless nikhahit above
+   * chattawa.
+   *
+   * Same for Lao.
+   *
+   * Note:
+   *
+   * Uniscribe also does some below-marks reordering.  Namely, it positions U+0E3A
+   * after U+0E38 and U+0E39.  We do that by modifying the ccc for U+0E3A.
+   * See unicode->modified_combining_class ().  Lao does NOT have a U+0E3A
+   * equivalent.
+   */
+
+
+  /*
+   * Here are the characters of significance:
+   *
+   *			Thai	Lao
+   * SARA AM:		U+0E33	U+0EB3
+   * SARA AA:		U+0E32	U+0EB2
+   * Nikhahit:		U+0E4D	U+0ECD
+   *
+   * Testing shows that Uniscribe reorder the following marks:
+   * Thai:	<0E31,0E34..0E37,0E47..0E4E>
+   * Lao:	<0EB1,0EB4..0EB7,0EC7..0ECE>
+   *
+   * Note how the Lao versions are the same as Thai + 0x80.
+   */
+
+  /* We only get one script at a time, so a script-agnostic implementation
+   * is adequate here. */
+#define IS_SARA_AM(x) (((x) & ~0x0080) == 0x0E33)
+#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0xE33 + 0xE4D)
+#define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
+#define IS_TONE_MARK(x) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080, 0x0E34, 0x0E37, 0x0E47, 0x0E4E, 0x0E31, 0x0E31))
+
+  buffer->clear_output ();
+  unsigned int count = buffer->len;
+  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;
+
+    /* Ok, let's see... */
+    unsigned int end = buffer->out_len;
+    unsigned int start = end - 2;
+    while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
+      start--;
+
+    if (start + 2 < end)
+    {
+      /* Move Nikhahit (end-2) to the beginning */
+      buffer->merge_out_clusters (start, end);
+      hb_glyph_info_t t = buffer->out_info[end - 2];
+      memmove (buffer->out_info + start + 1,
+	       buffer->out_info + start,
+	       sizeof (buffer->out_info[0]) * (end - start - 2));
+      buffer->out_info[start] = t;
+    }
+    else
+    {
+      /* Since we decomposed, and NIKHAHIT is combining, merge clusters with the
+       * previous cluster. */
+      if (start)
+	buffer->merge_out_clusters (start - 1, end);
+    }
+  }
+  buffer->swap_buffers ();
+
+  /* If font has Thai GSUB, we are done. */
+  if (plan->props.script == HB_SCRIPT_THAI && !plan->map.found_script[0])
+    do_thai_pua_shaping (plan, buffer, font);
+}
+
+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, /* normalization_preference */
+  NULL, /* decompose */
+  NULL, /* compose */
+  NULL, /* setup_masks */
+  true, /* zero_width_attached_marks */
+  false,/* fallback_position */
+};
--- a/gfx/harfbuzz/src/hb-ot-shape-fallback.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-fallback.cc
@@ -133,20 +133,20 @@ recategorize_combining_class (hb_codepoi
 
     case HB_MODIFIED_COMBINING_CLASS_CCC107: /* mai */
       return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
 
 
     /* Lao */
 
     case HB_MODIFIED_COMBINING_CLASS_CCC118: /* sign u / sign uu */
-      return HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
+      return HB_UNICODE_COMBINING_CLASS_BELOW;
 
     case HB_MODIFIED_COMBINING_CLASS_CCC122: /* mai */
-      return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
+      return HB_UNICODE_COMBINING_CLASS_ABOVE;
 
 
     /* Tibetan */
 
     case HB_MODIFIED_COMBINING_CLASS_CCC129: /* sign aa */
       return HB_UNICODE_COMBINING_CLASS_BELOW;
 
     case HB_MODIFIED_COMBINING_CLASS_CCC130: /* sign i*/
@@ -306,17 +306,17 @@ position_around_base (const hb_ot_shape_
   if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
     x_offset -= buffer->pos[base].x_advance;
     y_offset -= buffer->pos[base].y_advance;
   }
 
   hb_glyph_extents_t component_extents = base_extents;
   unsigned int last_lig_component = (unsigned int) -1;
   unsigned int last_combining_class = 255;
-  hb_glyph_extents_t cluster_extents;
+  hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */
   for (unsigned int i = base + 1; i < end; i++)
     if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]))
     {
       if (num_lig_components > 1) {
 	unsigned int this_lig_id = get_lig_id (buffer->info[i]);
 	unsigned int this_lig_component = get_lig_comp (buffer->info[i]) - 1;
 	/* Conditions for attaching to the last component. */
 	if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components)
--- a/gfx/harfbuzz/src/hb-ot-shape-normalize-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-normalize-private.hh
@@ -30,22 +30,42 @@
 #include "hb-private.hh"
 
 #include "hb-font.h"
 #include "hb-buffer.h"
 
 /* buffer var allocations, used during the normalization process */
 #define glyph_index()	var1.u32
 
+struct hb_ot_shape_plan_t;
+
 enum hb_ot_shape_normalization_mode_t {
   HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED,
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* never composes base-to-base */
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* always fully decomposes and then recompose back */
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL, /* including base-to-base composition */
 
   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS
 };
 
-HB_INTERNAL void _hb_ot_shape_normalize (hb_font_t *font,
+HB_INTERNAL void _hb_ot_shape_normalize (const hb_ot_shape_plan_t *shaper,
 					 hb_buffer_t *buffer,
-					 hb_ot_shape_normalization_mode_t mode);
+					 hb_font_t *font);
+
+
+struct hb_ot_shape_normalize_context_t
+{
+  const hb_ot_shape_plan_t *plan;
+  hb_buffer_t *buffer;
+  hb_font_t *font;
+  hb_unicode_funcs_t *unicode;
+  bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
+		     hb_codepoint_t  ab,
+		     hb_codepoint_t *a,
+		     hb_codepoint_t *b);
+  bool (*compose) (const hb_ot_shape_normalize_context_t *c,
+		   hb_codepoint_t  a,
+		   hb_codepoint_t  b,
+		   hb_codepoint_t *ab);
+};
+
 
 #endif /* HB_OT_SHAPE_NORMALIZE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
@@ -20,16 +20,17 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-ot-shape-normalize-private.hh"
+#include "hb-ot-shape-complex-private.hh"
 #include "hb-ot-shape-private.hh"
 
 
 /*
  * HIGHLEVEL DESIGN:
  *
  * This file exports one main function: _hb_ot_shape_normalize().
  *
@@ -76,191 +77,34 @@
  *     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 hb_bool_t
-decompose_func (hb_unicode_funcs_t *unicode,
-		hb_codepoint_t  ab,
-		hb_codepoint_t *a,
-		hb_codepoint_t *b)
+static bool
+decompose_unicode (const hb_ot_shape_normalize_context_t *c,
+		   hb_codepoint_t  ab,
+		   hb_codepoint_t *a,
+		   hb_codepoint_t *b)
 {
-  /* XXX FIXME, move these to complex shapers and propagage to normalizer.*/
-  switch (ab) {
-    case 0x0AC9  : return false;
-
-    case 0x0931  : return false;
-    case 0x0B94  : return false;
-
-    /* These ones have Unicode decompositions, but we do it
-     * this way to be close to what Uniscribe does. */
-    case 0x0DDA  : *a = 0x0DD9; *b= 0x0DDA; return true;
-    case 0x0DDC  : *a = 0x0DD9; *b= 0x0DDC; return true;
-    case 0x0DDD  : *a = 0x0DD9; *b= 0x0DDD; return true;
-    case 0x0DDE  : *a = 0x0DD9; *b= 0x0DDE; return true;
-
-    case 0x0F77  : *a = 0x0FB2; *b= 0x0F81; return true;
-    case 0x0F79  : *a = 0x0FB3; *b= 0x0F81; return true;
-    case 0x17BE  : *a = 0x17C1; *b= 0x17BE; return true;
-    case 0x17BF  : *a = 0x17C1; *b= 0x17BF; return true;
-    case 0x17C0  : *a = 0x17C1; *b= 0x17C0; return true;
-    case 0x17C4  : *a = 0x17C1; *b= 0x17C4; return true;
-    case 0x17C5  : *a = 0x17C1; *b= 0x17C5; return true;
-    case 0x1925  : *a = 0x1920; *b= 0x1923; return true;
-    case 0x1926  : *a = 0x1920; *b= 0x1924; return true;
-    case 0x1B3C  : *a = 0x1B42; *b= 0x1B3C; return true;
-    case 0x1112E  : *a = 0x11127; *b= 0x11131; return true;
-    case 0x1112F  : *a = 0x11127; *b= 0x11132; return true;
-#if 0
-    case 0x0B57  : *a = 0xno decomp, -> RIGHT; return true;
-    case 0x1C29  : *a = 0xno decomp, -> LEFT; return true;
-    case 0xA9C0  : *a = 0xno decomp, -> RIGHT; return true;
-    case 0x111BF  : *a = 0xno decomp, -> ABOVE; return true;
-#endif
-  }
-  return unicode->decompose (ab, a, b);
+  return c->unicode->decompose (ab, a, b);
 }
 
-static hb_bool_t
-compose_func (hb_unicode_funcs_t *unicode,
-	      hb_codepoint_t  a,
-	      hb_codepoint_t  b,
-	      hb_codepoint_t *ab)
+static bool
+compose_unicode (const hb_ot_shape_normalize_context_t *c,
+		 hb_codepoint_t  a,
+		 hb_codepoint_t  b,
+		 hb_codepoint_t *ab)
 {
-  /* XXX, this belongs to indic normalizer. */
-  if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (a)))
-    return false;
-  /* XXX, add composition-exclusion exceptions to Indic shaper. */
-  if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; }
-
-  /* XXX, these belong to the hebew / default shaper. */
-  /* Hebrew presentation-form shaping.
-   * https://bugzilla.mozilla.org/show_bug.cgi?id=728866 */
-  // Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA;
-  // note that some letters do not have a dagesh presForm encoded
-  static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = {
-    0xFB30, // ALEF
-    0xFB31, // BET
-    0xFB32, // GIMEL
-    0xFB33, // DALET
-    0xFB34, // HE
-    0xFB35, // VAV
-    0xFB36, // ZAYIN
-    0, // HET
-    0xFB38, // TET
-    0xFB39, // YOD
-    0xFB3A, // FINAL KAF
-    0xFB3B, // KAF
-    0xFB3C, // LAMED
-    0, // FINAL MEM
-    0xFB3E, // MEM
-    0, // FINAL NUN
-    0xFB40, // NUN
-    0xFB41, // SAMEKH
-    0, // AYIN
-    0xFB43, // FINAL PE
-    0xFB44, // PE
-    0, // FINAL TSADI
-    0xFB46, // TSADI
-    0xFB47, // QOF
-    0xFB48, // RESH
-    0xFB49, // SHIN
-    0xFB4A // TAV
-  };
-
-  hb_bool_t found = unicode->compose (a, b, ab);
-
-  if (!found && (b & ~0x7F) == 0x0580) {
-      // special-case Hebrew presentation forms that are excluded from
-      // standard normalization, but wanted for old fonts
-      switch (b) {
-      case 0x05B4: // HIRIQ
-	  if (a == 0x05D9) { // YOD
-	      *ab = 0xFB1D;
-	      found = true;
-	  }
-	  break;
-      case 0x05B7: // patah
-	  if (a == 0x05F2) { // YIDDISH YOD YOD
-	      *ab = 0xFB1F;
-	      found = true;
-	  } else if (a == 0x05D0) { // ALEF
-	      *ab = 0xFB2E;
-	      found = true;
-	  }
-	  break;
-      case 0x05B8: // QAMATS
-	  if (a == 0x05D0) { // ALEF
-	      *ab = 0xFB2F;
-	      found = true;
-	  }
-	  break;
-      case 0x05B9: // HOLAM
-	  if (a == 0x05D5) { // VAV
-	      *ab = 0xFB4B;
-	      found = true;
-	  }
-	  break;
-      case 0x05BC: // DAGESH
-	  if (a >= 0x05D0 && a <= 0x05EA) {
-	      *ab = sDageshForms[a - 0x05D0];
-	      found = (*ab != 0);
-	  } else if (a == 0xFB2A) { // SHIN WITH SHIN DOT
-	      *ab = 0xFB2C;
-	      found = true;
-	  } else if (a == 0xFB2B) { // SHIN WITH SIN DOT
-	      *ab = 0xFB2D;
-	      found = true;
-	  }
-	  break;
-      case 0x05BF: // RAFE
-	  switch (a) {
-	  case 0x05D1: // BET
-	      *ab = 0xFB4C;
-	      found = true;
-	      break;
-	  case 0x05DB: // KAF
-	      *ab = 0xFB4D;
-	      found = true;
-	      break;
-	  case 0x05E4: // PE
-	      *ab = 0xFB4E;
-	      found = true;
-	      break;
-	  }
-	  break;
-      case 0x05C1: // SHIN DOT
-	  if (a == 0x05E9) { // SHIN
-	      *ab = 0xFB2A;
-	      found = true;
-	  } else if (a == 0xFB49) { // SHIN WITH DAGESH
-	      *ab = 0xFB2C;
-	      found = true;
-	  }
-	  break;
-      case 0x05C2: // SIN DOT
-	  if (a == 0x05E9) { // SHIN
-	      *ab = 0xFB2B;
-	      found = true;
-	  } else if (a == 0xFB49) { // SHIN WITH DAGESH
-	      *ab = 0xFB2D;
-	      found = true;
-	  }
-	  break;
-      }
-  }
-
-  return found;
+  return c->unicode->compose (a, b, ab);
 }
 
-
 static inline void
 set_glyph (hb_glyph_info_t &info, hb_font_t *font)
 {
   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)
@@ -280,165 +124,181 @@ next_char (hb_buffer_t *buffer, hb_codep
 static inline void
 skip_char (hb_buffer_t *buffer)
 {
   buffer->skip_glyph ();
 }
 
 /* Returns 0 if didn't decompose, number of resulting characters otherwise. */
 static inline unsigned int
-decompose (hb_font_t *font, hb_buffer_t *buffer, bool shortest, hb_codepoint_t ab)
+decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint_t ab)
 {
   hb_codepoint_t a, b, a_glyph, b_glyph;
 
-  if (!decompose_func (buffer->unicode, ab, &a, &b) ||
-      (b && !font->get_glyph (b, 0, &b_glyph)))
+  if (!c->decompose (c, ab, &a, &b) ||
+      (b && !c->font->get_glyph (b, 0, &b_glyph)))
     return 0;
 
-  bool has_a = font->get_glyph (a, 0, &a_glyph);
+  bool has_a = c->font->get_glyph (a, 0, &a_glyph);
   if (shortest && has_a) {
     /* Output a and b */
-    output_char (buffer, a, a_glyph);
+    output_char (c->buffer, a, a_glyph);
     if (likely (b)) {
-      output_char (buffer, b, b_glyph);
+      output_char (c->buffer, b, b_glyph);
       return 2;
     }
     return 1;
   }
 
   unsigned int ret;
-  if ((ret = decompose (font, buffer, shortest, a))) {
+  if ((ret = decompose (c, shortest, a))) {
     if (b) {
-      output_char (buffer, b, b_glyph);
+      output_char (c->buffer, b, b_glyph);
       return ret + 1;
     }
     return ret;
   }
 
   if (has_a) {
-    output_char (buffer, a, a_glyph);
+    output_char (c->buffer, a, a_glyph);
     if (likely (b)) {
-      output_char (buffer, b, b_glyph);
+      output_char (c->buffer, b, b_glyph);
       return 2;
     }
     return 1;
   }
 
   return 0;
 }
 
 /* Returns 0 if didn't decompose, number of resulting characters otherwise. */
 static inline bool
-decompose_compatibility (hb_font_t *font, hb_buffer_t *buffer, hb_codepoint_t u)
+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 = buffer->unicode->decompose_compatibility (u, decomposed);
+  len = c->buffer->unicode->decompose_compatibility (u, decomposed);
   if (!len)
     return 0;
 
   for (i = 0; i < len; i++)
-    if (!font->get_glyph (decomposed[i], 0, &glyphs[i]))
+    if (!c->font->get_glyph (decomposed[i], 0, &glyphs[i]))
       return 0;
 
   for (i = 0; i < len; i++)
-    output_char (buffer, decomposed[i], glyphs[i]);
+    output_char (c->buffer, decomposed[i], glyphs[i]);
 
   return len;
 }
 
 /* Returns true if recomposition may be benefitial. */
 static inline bool
-decompose_current_character (hb_font_t *font, hb_buffer_t *buffer, bool shortest)
+decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shortest)
 {
+  hb_buffer_t * const buffer = c->buffer;
   hb_codepoint_t glyph;
   unsigned int len = 1;
 
   /* Kind of a cute waterfall here... */
-  if (shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph))
+  if (shortest && c->font->get_glyph (buffer->cur().codepoint, 0, &glyph))
     next_char (buffer, glyph);
-  else if ((len = decompose (font, buffer, shortest, buffer->cur().codepoint)))
+  else if ((len = decompose (c, shortest, buffer->cur().codepoint)))
     skip_char (buffer);
-  else if (!shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph))
+  else if (!shortest && c->font->get_glyph (buffer->cur().codepoint, 0, &glyph))
     next_char (buffer, glyph);
-  else if ((len = decompose_compatibility (font, buffer, buffer->cur().codepoint)))
+  else if ((len = decompose_compatibility (c, buffer->cur().codepoint)))
     skip_char (buffer);
   else
     next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
 
   /*
    * A recomposition would only be useful if we decomposed into at least three
    * characters...
    */
   return len > 2;
 }
 
 static inline void
-handle_variation_selector_cluster (hb_font_t *font, hb_buffer_t *buffer, unsigned int end)
+handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end)
 {
+  hb_buffer_t * const buffer = c->buffer;
   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. */
-      font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index());
+      c->font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index());
       buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
     } else {
-      set_glyph (buffer->cur(), font);
+      set_glyph (buffer->cur(), c->font);
       buffer->next_glyph ();
     }
   }
   if (likely (buffer->idx < end)) {
-    set_glyph (buffer->cur(), font);
+    set_glyph (buffer->cur(), c->font);
     buffer->next_glyph ();
   }
 }
 
 /* Returns true if recomposition may be benefitial. */
 static inline bool
-decompose_multi_char_cluster (hb_font_t *font, hb_buffer_t *buffer, unsigned int end)
+decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end)
 {
+  hb_buffer_t * const buffer = c->buffer;
   /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
   for (unsigned int i = buffer->idx; i < end; i++)
     if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
-      handle_variation_selector_cluster (font, buffer, end);
+      handle_variation_selector_cluster (c, end);
       return false;
     }
 
   while (buffer->idx < end)
-    decompose_current_character (font, buffer, false);
+    decompose_current_character (c, false);
   /* We can be smarter here and only return true if there are at least two ccc!=0 marks.
    * But does not matter. */
   return true;
 }
 
 static inline bool
-decompose_cluster (hb_font_t *font, hb_buffer_t *buffer, bool short_circuit, unsigned int end)
+decompose_cluster (const hb_ot_shape_normalize_context_t *c, bool short_circuit, unsigned int end)
 {
-  if (likely (buffer->idx + 1 == end))
-    return decompose_current_character (font, buffer, short_circuit);
+  if (likely (c->buffer->idx + 1 == end))
+    return decompose_current_character (c, short_circuit);
   else
-    return decompose_multi_char_cluster (font, buffer, end);
+    return decompose_multi_char_cluster (c, end);
 }
 
 
 static int
 compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
 {
   unsigned int a = _hb_glyph_info_get_modified_combining_class (pa);
   unsigned int b = _hb_glyph_info_get_modified_combining_class (pb);
 
   return a < b ? -1 : a == b ? 0 : +1;
 }
 
 
 void
-_hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
-			hb_ot_shape_normalization_mode_t mode)
+_hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
+			hb_buffer_t *buffer,
+			hb_font_t *font)
 {
+  hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference ?
+					  plan->shaper->normalization_preference (&buffer->props) :
+					  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT;
+  const hb_ot_shape_normalize_context_t c = {
+    plan,
+    buffer,
+    font,
+    buffer->unicode,
+    plan->shaper->decompose ? plan->shaper->decompose : decompose_unicode,
+    plan->shaper->compose   ? plan->shaper->compose   : compose_unicode
+  };
+
   bool short_circuit = mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED &&
 		       mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
   bool can_use_recompose = false;
   unsigned int count;
 
   /* We do a fairly straightforward yet custom normalization process in three
    * separate rounds: decompose, reorder, recompose (if desired).  Currently
    * this makes two buffer swaps.  We can make it faster by moving the last
@@ -452,17 +312,17 @@ void
   count = buffer->len;
   for (buffer->idx = 0; buffer->idx < count;)
   {
     unsigned int end;
     for (end = buffer->idx + 1; end < count; end++)
       if (buffer->cur().cluster != buffer->info[end].cluster)
         break;
 
-    can_use_recompose = decompose_cluster (font, buffer, short_circuit, end) || can_use_recompose;
+    can_use_recompose = decompose_cluster (&c, short_circuit, end) || can_use_recompose;
   }
   buffer->swap_buffers ();
 
 
   if (mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL && !can_use_recompose)
     return; /* Done! */
 
 
@@ -512,20 +372,20 @@ void
 	 * compose a CCC=0 character with it's preceding starter. */
 	(mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL ||
 	 _hb_glyph_info_get_modified_combining_class (&buffer->cur()) != 0) &&
 	/* If there's anything between the starter and this char, they should have CCC
 	 * smaller than this character's. */
 	(starter == buffer->out_len - 1 ||
 	 _hb_glyph_info_get_modified_combining_class (&buffer->prev()) < _hb_glyph_info_get_modified_combining_class (&buffer->cur())) &&
 	/* And compose. */
-	compose_func (buffer->unicode,
-		      buffer->out_info[starter].codepoint,
-		      buffer->cur().codepoint,
-		      &composed) &&
+	c.compose (&c,
+		   buffer->out_info[starter].codepoint,
+		   buffer->cur().codepoint,
+		   &composed) &&
 	/* And the font has glyph for the composite. */
 	font->get_glyph (composed, 0, &glyph))
     {
       /* Composes. */
       buffer->next_glyph (); /* Copy to out-buffer. */
       if (unlikely (buffer->in_error))
         return;
       buffer->merge_out_clusters (starter, buffer->out_len);
--- a/gfx/harfbuzz/src/hb-ot-shape-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-private.hh
@@ -41,17 +41,26 @@
 
 struct hb_ot_shape_plan_t
 {
   hb_segment_properties_t props;
   const struct hb_ot_complex_shaper_t *shaper;
   hb_ot_map_t map;
   const void *data;
 
-  inline void substitute_closure (hb_face_t *face, hb_set_t *glyphs) const { map.substitute_closure (this, face, glyphs); }
+  inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
+  {
+    unsigned int table_index;
+    switch (table_tag) {
+      case HB_OT_TAG_GSUB: table_index = 0; break;
+      case HB_OT_TAG_GPOS: table_index = 1; break;
+      default: return;
+    }
+    map.collect_lookups (table_index, lookups);
+  }
   inline void substitute (hb_font_t *font, hb_buffer_t *buffer) const { map.substitute (this, font, buffer); }
   inline void position (hb_font_t *font, hb_buffer_t *buffer) const { map.position (this, font, buffer); }
 
   void finish (void) { map.finish (); }
 };
 
 struct hb_ot_shape_planner_t
 {
@@ -60,37 +69,37 @@ struct hb_ot_shape_planner_t
   hb_segment_properties_t props;
   const struct hb_ot_complex_shaper_t *shaper;
   hb_ot_map_builder_t map;
 
   hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) :
 			 face (master_plan->face),
 			 props (master_plan->props),
 			 shaper (NULL),
-			 map () {}
+			 map (face, &props) {}
   ~hb_ot_shape_planner_t (void) { map.finish (); }
 
   inline void compile (hb_ot_shape_plan_t &plan)
   {
     plan.props = props;
     plan.shaper = shaper;
-    map.compile (face, &props, plan.map);
+    map.compile (plan.map);
   }
 
   private:
   NO_COPY (hb_ot_shape_planner_t);
 };
 
 
 
 inline void
 _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
 {
   info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
-			   (unicode->is_zero_width (info->codepoint) ? 0x80 : 0);
+			   (unicode->is_default_ignorable (info->codepoint) ? 0x80 : 0);
   info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
 }
 
 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_props0() & 0x7F);
 }
@@ -103,14 +112,14 @@ inline void
 
 inline unsigned int
 _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
 {
   return info->unicode_props1();
 }
 
 inline hb_bool_t
-_hb_glyph_info_is_zero_width (const hb_glyph_info_t *info)
+_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
 {
   return !!(info->unicode_props0() & 0x80);
 }
 
 #endif /* HB_OT_SHAPE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-shape.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape.cc
@@ -170,17 +170,17 @@ hb_ot_shaper_shape_plan_data_t *
 				      unsigned int        num_user_features)
 {
   hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
   if (unlikely (!plan))
     return NULL;
 
   hb_ot_shape_planner_t planner (shape_plan);
 
-  planner.shaper = hb_ot_shape_complex_categorize (&shape_plan->props);
+  planner.shaper = hb_ot_shape_complex_categorize (&planner);
 
   hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features);
 
   planner.compile (*plan);
 
   if (plan->shaper->data_create) {
     plan->data = plan->shaper->data_create (plan);
     if (unlikely (!plan->data))
@@ -232,17 +232,17 @@ hb_set_unicode_props (hb_buffer_t *buffe
   unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
     _hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode);
 }
 
 static void
 hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
 {
-  if (buffer->context_len[0] ||
+  if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
       _hb_glyph_info_get_general_category (&buffer->info[0]) !=
       HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
     return;
 
   hb_codepoint_t dottedcircle_glyph;
   if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph))
     return;
 
@@ -357,20 +357,17 @@ hb_ot_substitute_default (hb_ot_shape_co
 {
   if (c->plan->shaper->preprocess_text)
     c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
 
   hb_ot_mirror_chars (c);
 
   HB_BUFFER_ALLOCATE_VAR (c->buffer, glyph_index);
 
-  _hb_ot_shape_normalize (c->font, c->buffer,
-			  c->plan->shaper->normalization_preference ?
-			  c->plan->shaper->normalization_preference (c->plan) :
-			  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT);
+  _hb_ot_shape_normalize (c->plan, c->buffer, c->font);
 
   hb_ot_shape_setup_masks (c);
 
   /* This is unfortunate to go here, but necessary... */
   if (!hb_ot_layout_has_positioning (c->face))
     _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, c->buffer);
 
   hb_ot_map_glyphs_fast (c->buffer);
@@ -450,22 +447,16 @@ hb_ot_position_complex (hb_ot_shape_cont
   }
 
   hb_ot_layout_position_finish (c->font, c->buffer, c->plan->shaper->zero_width_attached_marks);
 
   return ret;
 }
 
 static inline void
-hb_ot_position_complex_fallback (hb_ot_shape_context_t *c)
-{
-  _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
-}
-
-static inline void
 hb_ot_truetype_kern (hb_ot_shape_context_t *c)
 {
   /* TODO Check for kern=0 */
   unsigned int count = c->buffer->len;
   for (unsigned int i = 1; i < count; i++) {
     hb_position_t x_kern, y_kern, kern1, kern2;
     c->font->get_glyph_kerning_for_direction (c->buffer->info[i - 1].codepoint, c->buffer->info[i].codepoint,
 					      c->buffer->props.direction,
@@ -481,50 +472,49 @@ hb_ot_truetype_kern (hb_ot_shape_context
     kern2 = y_kern - kern1;
     c->buffer->pos[i - 1].y_advance += kern1;
     c->buffer->pos[i].y_advance += kern2;
     c->buffer->pos[i].y_offset += kern2;
   }
 }
 
 static inline void
-hb_position_complex_fallback_visual (hb_ot_shape_context_t *c)
-{
-  hb_ot_truetype_kern (c);
-}
-
-static inline void
 hb_ot_position (hb_ot_shape_context_t *c)
 {
   hb_ot_position_default (c);
 
   hb_bool_t fallback = !hb_ot_position_complex (c);
 
-  if (fallback)
-    hb_ot_position_complex_fallback (c);
+  if (fallback && c->plan->shaper->fallback_position)
+    _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
 
   if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
     hb_buffer_reverse (c->buffer);
 
+  /* Visual fallback goes here. */
+
   if (fallback)
-    hb_position_complex_fallback_visual (c);
+    hb_ot_truetype_kern (c);
 }
 
 
 /* Post-process */
 
 static void
-hb_ot_hide_zerowidth (hb_ot_shape_context_t *c)
+hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
 {
+  if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
+    return;
+
   hb_codepoint_t space = 0;
 
   unsigned int count = c->buffer->len;
   for (unsigned int i = 0; i < count; i++)
     if (unlikely (!is_a_ligature (c->buffer->info[i]) &&
-		  _hb_glyph_info_is_zero_width (&c->buffer->info[i])))
+		  _hb_glyph_info_is_default_ignorable (&c->buffer->info[i])))
     {
       if (!space) {
         /* We assume that the space glyph is not gid0. */
         if (unlikely (!c->font->get_glyph (' ', 0, &space)) || !space)
 	return; /* No point! */
       }
       c->buffer->info[i].codepoint = space;
       c->buffer->pos[i].x_advance = 0;
@@ -552,17 +542,17 @@ hb_ot_shape_internal (hb_ot_shape_contex
   hb_insert_dotted_circle (c->buffer, c->font);
   hb_form_clusters (c->buffer);
 
   hb_ensure_native_direction (c->buffer);
 
   hb_ot_substitute (c);
   hb_ot_position (c);
 
-  hb_ot_hide_zerowidth (c);
+  hb_ot_hide_default_ignorables (c);
 
   HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props1);
   HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props0);
 
   c->buffer->props.direction = c->target_direction;
 
   c->buffer->deallocate_var_all ();
 }
@@ -577,53 +567,73 @@ hb_bool_t
 {
   hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features};
   hb_ot_shape_internal (&c);
 
   return true;
 }
 
 
-
-static inline void
-hb_ot_map_glyphs_dumb (hb_font_t    *font,
-		       hb_buffer_t  *buffer)
+void
+hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
+				  hb_tag_t         table_tag,
+				  hb_set_t        *lookup_indexes /* OUT */)
 {
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    font->get_glyph (buffer->info[i].codepoint, 0, &buffer->info[i].codepoint);
+  HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes);
 }
 
+
+/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
+static void
+add_char (hb_font_t          *font,
+	  hb_unicode_funcs_t *unicode,
+	  hb_bool_t           mirror,
+	  hb_codepoint_t      u,
+	  hb_set_t           *glyphs)
+{
+  hb_codepoint_t glyph;
+  if (font->get_glyph (u, 0, &glyph))
+    glyphs->add (glyph);
+  if (mirror)
+  {
+    hb_codepoint_t m = unicode->mirroring (u);
+    if (m != u && font->get_glyph (m, 0, &glyph))
+      glyphs->add (glyph);
+  }
+}
+
+
 void
 hb_ot_shape_glyphs_closure (hb_font_t          *font,
 			    hb_buffer_t        *buffer,
 			    const hb_feature_t *features,
 			    unsigned int        num_features,
 			    hb_set_t           *glyphs)
 {
   hb_ot_shape_plan_t plan;
 
-  buffer->guess_properties ();
-
-  /* TODO cache / ensure correct backend, etc. */
-  hb_shape_plan_t *shape_plan = hb_shape_plan_create (font->face, &buffer->props, features, num_features, NULL);
+  buffer->guess_segment_properties ();
 
-  /* TODO: normalization? have shapers do closure()? */
-  /* TODO: Deal with mirrored chars? */
-  hb_ot_map_glyphs_dumb (font, buffer);
+  const char *shapers[] = {"ot", NULL};
+  hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
+							     features, num_features, shapers);
 
-  /* Seed it.  It's user's responsibility to have cleard glyphs
-   * if that's what they desire. */
+  bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
+
   unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
-    glyphs->add (buffer->info[i].codepoint);
+    add_char (font, buffer->unicode, mirror, buffer->info[i].codepoint, glyphs);
+
+  hb_set_t lookups;
+  lookups.init ();
+  hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups);
 
   /* And find transitive closure. */
   hb_set_t copy;
   copy.init ();
-
   do {
     copy.set (glyphs);
-    HB_SHAPER_DATA_GET (shape_plan)->substitute_closure (font->face, glyphs);
-  } while (!copy.equal (glyphs));
+    for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);)
+      hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs);
+  } while (!copy.is_equal (glyphs));
 
   hb_shape_plan_destroy (shape_plan);
 }
--- a/gfx/harfbuzz/src/hb-ot-tag.cc
+++ b/gfx/harfbuzz/src/hb-ot-tag.cc
@@ -33,16 +33,18 @@
 
 
 
 /* hb_script_t */
 
 static hb_tag_t
 hb_ot_old_tag_from_script (hb_script_t script)
 {
+  /* This seems to be accurate as of end of 2012. */
+
   switch ((hb_tag_t) script) {
     case HB_SCRIPT_INVALID:		return HB_OT_TAG_DEFAULT_SCRIPT;
 
     /* KATAKANA and HIRAGANA both map to 'kana' */
     case HB_SCRIPT_HIRAGANA:		return HB_TAG('k','a','n','a');
 
     /* Spaces at the end are preserved, unlike ISO 15924 */
     case HB_SCRIPT_LAO:			return HB_TAG('l','a','o',' ');
@@ -86,16 +88,17 @@ hb_ot_new_tag_from_script (hb_script_t s
     case HB_SCRIPT_DEVANAGARI:		return HB_TAG('d','e','v','2');
     case HB_SCRIPT_GUJARATI:		return HB_TAG('g','j','r','2');
     case HB_SCRIPT_GURMUKHI:		return HB_TAG('g','u','r','2');
     case HB_SCRIPT_KANNADA:		return HB_TAG('k','n','d','2');
     case HB_SCRIPT_MALAYALAM:		return HB_TAG('m','l','m','2');
     case HB_SCRIPT_ORIYA:		return HB_TAG('o','r','y','2');
     case HB_SCRIPT_TAMIL:		return HB_TAG('t','m','l','2');
     case HB_SCRIPT_TELUGU:		return HB_TAG('t','e','l','2');
+    case HB_SCRIPT_MYANMAR:		return HB_TAG('m','y','m','2');
   }
 
   return HB_OT_TAG_DEFAULT_SCRIPT;
 }
 
 static hb_script_t
 hb_ot_new_tag_to_script (hb_tag_t tag)
 {
@@ -104,16 +107,17 @@ hb_ot_new_tag_to_script (hb_tag_t tag)
     case HB_TAG('d','e','v','2'):	return HB_SCRIPT_DEVANAGARI;
     case HB_TAG('g','j','r','2'):	return HB_SCRIPT_GUJARATI;
     case HB_TAG('g','u','r','2'):	return HB_SCRIPT_GURMUKHI;
     case HB_TAG('k','n','d','2'):	return HB_SCRIPT_KANNADA;
     case HB_TAG('m','l','m','2'):	return HB_SCRIPT_MALAYALAM;
     case HB_TAG('o','r','y','2'):	return HB_SCRIPT_ORIYA;
     case HB_TAG('t','m','l','2'):	return HB_SCRIPT_TAMIL;
     case HB_TAG('t','e','l','2'):	return HB_SCRIPT_TELUGU;
+    case HB_TAG('m','y','m','2'):	return HB_SCRIPT_MYANMAR;
   }
 
   return HB_SCRIPT_UNKNOWN;
 }
 
 /*
  * Complete list at:
  * https://www.microsoft.com/typography/otspec/scripttags.htm
--- a/gfx/harfbuzz/src/hb-ot.h
+++ b/gfx/harfbuzz/src/hb-ot.h
@@ -30,16 +30,17 @@
 
 #include "hb.h"
 
 #include "hb-ot-layout.h"
 #include "hb-ot-tag.h"
 
 HB_BEGIN_DECLS
 
+/* TODO remove */
 void
 hb_ot_shape_glyphs_closure (hb_font_t          *font,
 			    hb_buffer_t        *buffer,
 			    const hb_feature_t *features,
 			    unsigned int        num_features,
 			    hb_set_t           *glyphs);
 
 HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-set-private.hh
+++ b/gfx/harfbuzz/src/hb-set-private.hh
@@ -93,17 +93,17 @@ struct hb_set_digest_lowest_bits_t
   }
 
   inline bool may_have (hb_codepoint_t g) const {
     return !!(mask & mask_for (g));
   }
 
   private:
 
-  mask_t mask_for (hb_codepoint_t g) const { return ((mask_t) 1) << (g & (sizeof (mask_t) * 8 - 1)); }
+  static inline mask_t mask_for (hb_codepoint_t g) { return ((mask_t) 1) << (g & (sizeof (mask_t) * 8 - 1)); }
   mask_t mask;
 };
 
 struct hb_set_digest_t
 {
   ASSERT_POD ();
 
   inline void init (void) {
@@ -142,55 +142,62 @@ struct hb_set_t
     header.init ();
     clear ();
   }
   inline void fini (void) {
   }
   inline void clear (void) {
     memset (elts, 0, sizeof elts);
   }
-  inline bool empty (void) const {
+  inline bool is_empty (void) const {
     for (unsigned int i = 0; i < ARRAY_LENGTH (elts); i++)
       if (elts[i])
         return false;
     return true;
   }
   inline void add (hb_codepoint_t g)
   {
     if (unlikely (g == SENTINEL)) return;
     if (unlikely (g > MAX_G)) return;
     elt (g) |= mask (g);
   }
   inline void add_range (hb_codepoint_t a, hb_codepoint_t b)
   {
+    /* TODO Speedup */
     for (unsigned int i = a; i < b + 1; i++)
       add (i);
   }
   inline void del (hb_codepoint_t g)
   {
     if (unlikely (g > MAX_G)) return;
     elt (g) &= ~mask (g);
   }
+  inline void del_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    /* TODO Speedup */
+    for (unsigned int i = a; i < b + 1; i++)
+      del (i);
+  }
   inline bool has (hb_codepoint_t g) const
   {
     if (unlikely (g > MAX_G)) return false;
     return !!(elt (g) & mask (g));
   }
   inline bool intersects (hb_codepoint_t first,
 			  hb_codepoint_t last) const
   {
     if (unlikely (first > MAX_G)) return false;
     if (unlikely (last  > MAX_G)) last = MAX_G;
     unsigned int end = last + 1;
     for (hb_codepoint_t i = first; i < end; i++)
       if (has (i))
         return true;
     return false;
   }
-  inline bool equal (const hb_set_t *other) const
+  inline bool is_equal (const hb_set_t *other) const
   {
     for (unsigned int i = 0; i < ELTS; i++)
       if (elts[i] != other->elts[i])
         return false;
     return true;
   }
   inline void set (const hb_set_t *other)
   {
@@ -212,33 +219,55 @@ struct hb_set_t
     for (unsigned int i = 0; i < ELTS; i++)
       elts[i] &= ~other->elts[i];
   }
   inline void symmetric_difference (const hb_set_t *other)
   {
     for (unsigned int i = 0; i < ELTS; i++)
       elts[i] ^= other->elts[i];
   }
-  inline bool next (hb_codepoint_t *codepoint)
+  inline bool next (hb_codepoint_t *codepoint) const
   {
     if (unlikely (*codepoint == SENTINEL)) {
       hb_codepoint_t i = get_min ();
       if (i != SENTINEL) {
         *codepoint = i;
 	return true;
       } else
         return false;
     }
     for (hb_codepoint_t i = *codepoint + 1; i < MAX_G + 1; i++)
       if (has (i)) {
         *codepoint = i;
 	return true;
       }
     return false;
   }
+  inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    hb_codepoint_t i;
+
+    i = *last;
+    if (!next (&i))
+      return false;
+
+    *last = *first = i;
+    while (next (&i) && i == *last + 1)
+      (*last)++;
+
+    return true;
+  }
+
+  inline unsigned int get_population (void) const
+  {
+    unsigned int count = 0;
+    for (unsigned int i = 0; i < ELTS; i++)
+      count += _hb_popcount32 (elts[i]);
+    return count;
+  }
   inline hb_codepoint_t get_min (void) const
   {
     for (unsigned int i = 0; i < ELTS; i++)
       if (elts[i])
 	for (unsigned int j = 0; i < BITS; j++)
 	  if (elts[i] & (1 << j))
 	    return i * BITS + j;
     return SENTINEL;
--- a/gfx/harfbuzz/src/hb-set.cc
+++ b/gfx/harfbuzz/src/hb-set.cc
@@ -27,17 +27,17 @@
 #include "hb-set-private.hh"
 
 
 
 /* Public API */
 
 
 hb_set_t *
-hb_set_create ()
+hb_set_create (void)
 {
   hb_set_t *set;
 
   if (!(set = hb_object_create<hb_set_t> ()))
     return hb_set_get_empty ();
 
   set->clear ();
 
@@ -68,124 +68,154 @@ hb_set_destroy (hb_set_t *set)
   if (!hb_object_destroy (set)) return;
 
   set->fini ();
 
   free (set);
 }
 
 hb_bool_t
-hb_set_set_user_data (hb_set_t        *set,
-			 hb_user_data_key_t *key,
-			 void *              data,
-			 hb_destroy_func_t   destroy,
-			 hb_bool_t           replace)
+hb_set_set_user_data (hb_set_t           *set,
+		      hb_user_data_key_t *key,
+		      void *              data,
+		      hb_destroy_func_t   destroy,
+		      hb_bool_t           replace)
 {
   return hb_object_set_user_data (set, key, data, destroy, replace);
 }
 
 void *
-hb_set_get_user_data (hb_set_t        *set,
-			 hb_user_data_key_t *key)
+hb_set_get_user_data (hb_set_t           *set,
+		      hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (set, key);
 }
 
 
 hb_bool_t
-hb_set_allocation_successful (hb_set_t  *set HB_UNUSED)
+hb_set_allocation_successful (const hb_set_t  *set HB_UNUSED)
 {
   return true;
 }
 
 void
 hb_set_clear (hb_set_t *set)
 {
   set->clear ();
 }
 
 hb_bool_t
-hb_set_empty (hb_set_t *set)
+hb_set_is_empty (const hb_set_t *set)
 {
-  return set->empty ();
+  return set->is_empty ();
 }
 
 hb_bool_t
-hb_set_has (hb_set_t       *set,
+hb_set_has (const hb_set_t *set,
 	    hb_codepoint_t  codepoint)
 {
   return set->has (codepoint);
 }
 
 void
 hb_set_add (hb_set_t       *set,
 	    hb_codepoint_t  codepoint)
 {
   set->add (codepoint);
 }
 
 void
+hb_set_add_range (hb_set_t       *set,
+		  hb_codepoint_t  first,
+		  hb_codepoint_t  last)
+{
+  set->add_range (first, last);
+}
+
+void
 hb_set_del (hb_set_t       *set,
 	    hb_codepoint_t  codepoint)
 {
   set->del (codepoint);
 }
 
+void
+hb_set_del_range (hb_set_t       *set,
+		  hb_codepoint_t  first,
+		  hb_codepoint_t  last)
+{
+  set->del_range (first, last);
+}
+
 hb_bool_t
-hb_set_equal (hb_set_t *set,
-	      hb_set_t *other)
+hb_set_is_equal (const hb_set_t *set,
+		 const hb_set_t *other)
 {
-  return set->equal (other);
+  return set->is_equal (other);
 }
 
 void
-hb_set_set (hb_set_t *set,
-	    hb_set_t *other)
+hb_set_set (hb_set_t       *set,
+	    const hb_set_t *other)
 {
   set->set (other);
 }
 
 void
-hb_set_union (hb_set_t *set,
-	      hb_set_t *other)
+hb_set_union (hb_set_t       *set,
+	      const hb_set_t *other)
 {
   set->union_ (other);
 }
 
 void
-hb_set_intersect (hb_set_t *set,
-		  hb_set_t *other)
+hb_set_intersect (hb_set_t       *set,
+		  const hb_set_t *other)
 {
   set->intersect (other);
 }
 
 void
-hb_set_subtract (hb_set_t *set,
-		 hb_set_t *other)
+hb_set_subtract (hb_set_t       *set,
+		 const hb_set_t *other)
 {
   set->subtract (other);
 }
 
 void
-hb_set_symmetric_difference (hb_set_t *set,
-			     hb_set_t *other)
+hb_set_symmetric_difference (hb_set_t       *set,
+			     const hb_set_t *other)
 {
   set->symmetric_difference (other);
 }
 
+unsigned int
+hb_set_population (const hb_set_t *set)
+{
+  return set->get_population ();
+}
+
 hb_codepoint_t
-hb_set_min (hb_set_t *set)
+hb_set_get_min (const hb_set_t *set)
 {
   return set->get_min ();
 }
 
 hb_codepoint_t
-hb_set_max (hb_set_t *set)
+hb_set_get_max (const hb_set_t *set)
 {
   return set->get_max ();
 }
 
 hb_bool_t
-hb_set_next (hb_set_t       *set,
+hb_set_next (const hb_set_t *set,
 	     hb_codepoint_t *codepoint)
 {
   return set->next (codepoint);
 }
+
+hb_bool_t
+hb_set_next_range (const hb_set_t *set,
+		   hb_codepoint_t *first,
+		   hb_codepoint_t *last)
+{
+  return set->next_range (first, last);
+}
--- a/gfx/harfbuzz/src/hb-set.h
+++ b/gfx/harfbuzz/src/hb-set.h
@@ -60,73 +60,90 @@ hb_set_set_user_data (hb_set_t          
 
 void *
 hb_set_get_user_data (hb_set_t           *set,
 		      hb_user_data_key_t *key);
 
 
 /* Returns false if allocation has failed before */
 hb_bool_t
-hb_set_allocation_successful (hb_set_t  *set);
+hb_set_allocation_successful (const hb_set_t *set);
 
 void
 hb_set_clear (hb_set_t *set);
 
 hb_bool_t
-hb_set_empty (hb_set_t *set);
+hb_set_is_empty (const hb_set_t *set);
 
 hb_bool_t
-hb_set_has (hb_set_t       *set,
+hb_set_has (const hb_set_t *set,
 	    hb_codepoint_t  codepoint);
 
 /* Right now limited to 16-bit integers.  Eventually will do full codepoint range, sans -1
  * which we will use as a sentinel. */
 void
 hb_set_add (hb_set_t       *set,
 	    hb_codepoint_t  codepoint);
 
 void
+hb_set_add_range (hb_set_t       *set,
+		  hb_codepoint_t  first,
+		  hb_codepoint_t  last);
+
+void
 hb_set_del (hb_set_t       *set,
 	    hb_codepoint_t  codepoint);
 
+void
+hb_set_del_range (hb_set_t       *set,
+		  hb_codepoint_t  first,
+		  hb_codepoint_t  last);
+
 hb_bool_t
-hb_set_equal (hb_set_t *set,
-	      hb_set_t *other);
+hb_set_is_equal (const hb_set_t *set,
+		 const hb_set_t *other);
 
 void
-hb_set_set (hb_set_t *set,
-	    hb_set_t *other);
+hb_set_set (hb_set_t       *set,
+	    const hb_set_t *other);
 
 void
-hb_set_union (hb_set_t *set,
-	      hb_set_t *other);
+hb_set_union (hb_set_t       *set,
+	      const hb_set_t *other);
+
+void
+hb_set_intersect (hb_set_t       *set,
+		  const hb_set_t *other);
 
 void
-hb_set_intersect (hb_set_t *set,
-		  hb_set_t *other);
+hb_set_subtract (hb_set_t       *set,
+		 const hb_set_t *other);
 
 void
-hb_set_subtract (hb_set_t *set,
-		 hb_set_t *other);
+hb_set_symmetric_difference (hb_set_t       *set,
+			     const hb_set_t *other);
 
-void
-hb_set_symmetric_difference (hb_set_t *set,
-			     hb_set_t *other);
+unsigned int
+hb_set_population (const hb_set_t *set);
 
 /* Returns -1 if set empty. */
 hb_codepoint_t
-hb_set_min (hb_set_t *set);
+hb_set_get_min (const hb_set_t *set);
 
 /* Returns -1 if set empty. */
 hb_codepoint_t
-hb_set_max (hb_set_t *set);
+hb_set_get_max (const hb_set_t *set);
 
 /* Pass -1 in to get started. */
 hb_bool_t
-hb_set_next (hb_set_t       *set,
+hb_set_next (const hb_set_t *set,
 	     hb_codepoint_t *codepoint);
 
-/* TODO: Add faster iteration API? */
+/* Pass -1 for first and last to get started. */
+hb_bool_t
+hb_set_next_range (const hb_set_t *set,
+		   hb_codepoint_t *first,
+		   hb_codepoint_t *last);
 
 
 HB_END_DECLS
 
 #endif /* HB_SET_H */
--- a/gfx/harfbuzz/src/hb-shape-plan-private.hh
+++ b/gfx/harfbuzz/src/hb-shape-plan-private.hh
@@ -23,19 +23,18 @@
  *
  * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_SHAPE_PLAN_PRIVATE_HH
 #define HB_SHAPE_PLAN_PRIVATE_HH
 
 #include "hb-private.hh"
-
 #include "hb-shape-plan.h"
-
+#include "hb-object-private.hh"
 #include "hb-shaper-private.hh"
 
 
 struct hb_shape_plan_t
 {
   hb_object_header_t header;
   ASSERT_POD ();
 
--- a/gfx/harfbuzz/src/hb-shape-plan.cc
+++ b/gfx/harfbuzz/src/hb-shape-plan.cc
@@ -19,18 +19,16 @@
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb-private.hh"
-
 #include "hb-shape-plan-private.hh"
 #include "hb-shaper-private.hh"
 #include "hb-font-private.hh"
 
 #define HB_SHAPER_IMPLEMENT(shaper) \
 	HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \
 	HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font)
 #include "hb-shaper-list.hh"
@@ -114,17 +112,17 @@ hb_shape_plan_create (hb_face_t         
 hb_shape_plan_t *
 hb_shape_plan_get_empty (void)
 {
   static const hb_shape_plan_t _hb_shape_plan_nil = {
     HB_OBJECT_HEADER_STATIC,
 
     true, /* default_shaper_list */
     NULL, /* face */
-    _HB_BUFFER_PROPS_DEFAULT, /* props */
+    HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
 
     NULL, /* shaper_func */
 
     {
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
     }
@@ -148,19 +146,36 @@ hb_shape_plan_destroy (hb_shape_plan_t *
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 
   hb_face_destroy (shape_plan->face);
 
   free (shape_plan);
 }
 
+hb_bool_t
+hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
+			     hb_user_data_key_t *key,
+			     void *              data,
+			     hb_destroy_func_t   destroy,
+			     hb_bool_t           replace)
+{
+  return hb_object_set_user_data (shape_plan, key, data, destroy, replace);
+}
+
+void *
+hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
+			     hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (shape_plan, key);
+}
+
 
 hb_bool_t
-hb_shape_plan_execute (hb_shape_plan      *shape_plan,
+hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
 		       hb_font_t          *font,
 		       hb_buffer_t        *buffer,
 		       const hb_feature_t *features,
 		       unsigned int        num_features)
 {
   if (unlikely (shape_plan->face != font->face))
     return false;
 
--- a/gfx/harfbuzz/src/hb-shape-plan.h
+++ b/gfx/harfbuzz/src/hb-shape-plan.h
@@ -19,57 +19,73 @@
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
 #ifndef HB_SHAPE_PLAN_H
 #define HB_SHAPE_PLAN_H
 
-/* TODO To become public one day */
-
-#include "hb-private.hh"
-
-#include "hb-buffer-private.hh"
-
+#include "hb-common.h"
+#include "hb-font.h"
 
-typedef struct hb_shape_plan_t hb_shape_plan;
+HB_BEGIN_DECLS
 
-/*
- * hb_shape_plan_t
- */
+typedef struct hb_shape_plan_t hb_shape_plan_t;
 
-HB_INTERNAL hb_shape_plan_t *
+hb_shape_plan_t *
 hb_shape_plan_create (hb_face_t                     *face,
 		      const hb_segment_properties_t *props,
 		      const hb_feature_t            *user_features,
 		      unsigned int                   num_user_features,
 		      const char * const            *shaper_list);
 
-HB_INTERNAL hb_shape_plan_t *
+hb_shape_plan_t *
 hb_shape_plan_create_cached (hb_face_t                     *face,
 			     const hb_segment_properties_t *props,
 			     const hb_feature_t            *user_features,
 			     unsigned int                   num_user_features,
 			     const char * const            *shaper_list);
 
-HB_INTERNAL hb_shape_plan_t *
+hb_shape_plan_t *
 hb_shape_plan_get_empty (void);
 
-HB_INTERNAL hb_shape_plan_t *
+hb_shape_plan_t *
 hb_shape_plan_reference (hb_shape_plan_t *shape_plan);
 
-HB_INTERNAL void
+void
 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan);
 
+hb_bool_t
+hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
+			     hb_user_data_key_t *key,
+			     void *              data,
+			     hb_destroy_func_t   destroy,
+			     hb_bool_t           replace);
 
-HB_INTERNAL hb_bool_t
-hb_shape_plan_execute (hb_shape_plan      *shape_plan,
+void *
+hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
+			     hb_user_data_key_t *key);
+
+
+hb_bool_t
+hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
 		       hb_font_t          *font,
 		       hb_buffer_t        *buffer,
 		       const hb_feature_t *features,
 		       unsigned int        num_features);
 
+#ifdef HB_NOT_IMPLEMENTED
+const char *
+Xhb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan);
+#endif
+
+
+HB_END_DECLS
 
 #endif /* HB_SHAPE_PLAN_H */
--- a/gfx/harfbuzz/src/hb-shape.cc
+++ b/gfx/harfbuzz/src/hb-shape.cc
@@ -171,17 +171,17 @@ hb_feature_to_string (hb_feature_t *feat
   char s[128];
   unsigned int len = 0;
   if (feature->value == 0)
     s[len++] = '-';
   hb_tag_to_string (feature->tag, s + len);
   len += 4;
   while (len && s[len - 1] == ' ')
     len--;
-  if (feature->start != 0 || feature->start != (unsigned int) -1)
+  if (feature->start != 0 || feature->end != (unsigned int) -1)
   {
     s[len++] = '[';
     if (feature->start)
       len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->start);
     if (feature->end != feature->start + 1) {
       s[len++] = ':';
       if (feature->end != (unsigned int) -1)
 	len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->end);
@@ -250,17 +250,17 @@ hb_shape_full (hb_font_t          *font,
 	       unsigned int        num_features,
 	       const char * const *shaper_list)
 {
   if (unlikely (!buffer->len))
     return true;
 
   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
 
-  buffer->guess_properties ();
+  buffer->guess_segment_properties ();
 
   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
   hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
   hb_shape_plan_destroy (shape_plan);
 
   if (res)
     buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
   return res;
--- a/gfx/harfbuzz/src/hb-shaper-list.hh
+++ b/gfx/harfbuzz/src/hb-shaper-list.hh
@@ -24,31 +24,32 @@
  * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_SHAPER_LIST_HH
 #define HB_SHAPER_LIST_HH
 #endif /* HB_SHAPER_LIST_HH */ /* Dummy header guards */
 
 /* v--- Add new shapers in the right place here. */
+
 #ifdef HAVE_GRAPHITE2
+/* Only picks up fonts that have a "Silf" table. */
 HB_SHAPER_IMPLEMENT (graphite2)
 #endif
-#ifdef HAVE_UNISCRIBE
-HB_SHAPER_IMPLEMENT (uniscribe)
-#endif
-#ifdef HAVE_CORETEXT
-HB_SHAPER_IMPLEMENT (coretext)
-#endif
 
 #ifdef HAVE_OT
 HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
 #endif
 
 #ifdef HAVE_HB_OLD
 HB_SHAPER_IMPLEMENT (old)
 #endif
-
 #ifdef HAVE_ICU_LE
 HB_SHAPER_IMPLEMENT (icu_le)
 #endif
+#ifdef HAVE_UNISCRIBE
+HB_SHAPER_IMPLEMENT (uniscribe)
+#endif
+#ifdef HAVE_CORETEXT
+HB_SHAPER_IMPLEMENT (coretext)
+#endif
 
 HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */
--- a/gfx/harfbuzz/src/hb-shaper-private.hh
+++ b/gfx/harfbuzz/src/hb-shaper-private.hh
@@ -24,18 +24,16 @@
  * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_SHAPER_PRIVATE_HH
 #define HB_SHAPER_PRIVATE_HH
 
 #include "hb-private.hh"
 
-#include "hb-shape-plan.h" /* TODO remove */
-
 typedef hb_bool_t hb_shape_func_t (hb_shape_plan_t    *shape_plan,
 				   hb_font_t          *font,
 				   hb_buffer_t        *buffer,
 				   const hb_feature_t *features,
 				   unsigned int        num_features);
 
 #define HB_SHAPER_IMPLEMENT(name) \
 	extern "C" HB_INTERNAL hb_shape_func_t _hb_##name##_shape;
--- a/gfx/harfbuzz/src/hb-shaper.cc
+++ b/gfx/harfbuzz/src/hb-shaper.cc
@@ -20,18 +20,18 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.hh"
-
 #include "hb-shaper-private.hh"
+#include "hb-atomic-private.hh"
 
 
 static const hb_shaper_pair_t all_shapers[] = {
 #define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape},
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 };
 
--- a/gfx/harfbuzz/src/hb-unicode-private.hh
+++ b/gfx/harfbuzz/src/hb-unicode-private.hh
@@ -114,57 +114,83 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIM
   is_variation_selector (hb_codepoint_t unicode)
   {
     return unlikely (hb_in_ranges<hb_codepoint_t> (unicode,
 						   0x180B, 0x180D, /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
 						   0xFE00, 0xFE0F, /* VARIATION SELECTOR-1..16 */
 						   0xE0100, 0xE01EF));  /* VARIATION SELECTOR-17..256 */
   }
 
-  /* Zero-Width invisible characters:
+  /* Default_Ignorable codepoints:
    *
-   *  00AD  SOFT HYPHEN
-   *  034F  COMBINING GRAPHEME JOINER
+   * Note that as of Oct 2012 (Unicode 6.2), U+180E MONGOLIAN VOWEL SEPARATOR
+   * is NOT Default_Ignorable, but it really behaves in a way that it should
+   * be.  That has been reported to the Unicode Technical Committee for
+   * consideration.  As such, we include it here, since Uniscribe removes it.
    *
-   *  180E  MONGOLIAN VOWEL SEPARATOR
+   * Gathered from:
+   * http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:DI:]&abb=on&ucd=on&esc=on
    *
-   *  200B  ZERO WIDTH SPACE
-   *  200C  ZERO WIDTH NON-JOINER
-   *  200D  ZERO WIDTH JOINER
-   *  200E  LEFT-TO-RIGHT MARK
-   *  200F  RIGHT-TO-LEFT MARK
+   * Last updated to the page with the following versions:
+   * Version 3.6; ICU version: 50.0.1.0; Unicode version: 6.1.0.0
+   *
+   * 4,167 Code Points
+   *
+   * [\u00AD\u034F\u115F\u1160\u17B4\u17B5\u180B-\u180D\u200B-\u200F\u202A-\u202E\u2060-\u206F\u3164\uFE00-\uFE0F\uFEFF\uFFA0\uFFF0-\uFFF8\U0001D173-\U0001D17A\U000E0000-\U000E0FFF]
    *
-   *  2028  LINE SEPARATOR
-   *
-   *  202A  LEFT-TO-RIGHT EMBEDDING
-   *  202B  RIGHT-TO-LEFT EMBEDDING
-   *  202C  POP DIRECTIONAL FORMATTING
-   *  202D  LEFT-TO-RIGHT OVERRIDE
-   *  202E  RIGHT-TO-LEFT OVERRIDE
-   *
-   *  2060  WORD JOINER
-   *  2061  FUNCTION APPLICATION
-   *  2062  INVISIBLE TIMES
-   *  2063  INVISIBLE SEPARATOR
-   *
-   *  FEFF  ZERO WIDTH NO-BREAK SPACE
+   * 00AD ;SOFT HYPHEN
+   * 034F ;COMBINING GRAPHEME JOINER
+   * 115F ;HANGUL CHOSEONG FILLER
+   * 1160 ;HANGUL JUNGSEONG FILLER
+   * 17B4 ;KHMER VOWEL INHERENT AQ
+   * 17B5 ;KHMER VOWEL INHERENT AA
+   * 180B..180D ;MONGOLIAN FREE VARIATION SELECTOR THREE
+   * 200B..200F ;RIGHT-TO-LEFT MARK
+   * 202A..202E ;RIGHT-TO-LEFT OVERRIDE
+   * 2060..206F ;NOMINAL DIGIT SHAPES
+   * 3164 ;HANGUL FILLER
+   * FE00..FE0F ;VARIATION SELECTOR-16
+   * FEFF ;ZERO WIDTH NO-BREAK SPACE
+   * FFA0 ;HALFWIDTH HANGUL FILLER
+   * FFF0..FFF8 ;<unassigned-FFF8>
+   * 1D173..1D17A ;MUSICAL SYMBOL END PHRASE
+   * E0000..E0FFF ;<unassigned-E0FFF>
    */
   inline hb_bool_t
-  is_zero_width (hb_codepoint_t ch)
+  is_default_ignorable (hb_codepoint_t ch)
   {
-    return ((ch & ~0x007F) == 0x2000 && (hb_in_ranges<hb_codepoint_t> (ch,
-								       0x200B, 0x200F,
-								       0x202A, 0x202E,
-								       0x2060, 0x2064) ||
-					 (ch == 0x2028))) ||
-	    unlikely (ch == 0x0009 ||
-		      ch == 0x00AD ||
-		      ch == 0x034F ||
-		      ch == 0x180E ||
-		      ch == 0xFEFF);
+    hb_codepoint_t plane = ch >> 16;
+    if (likely (plane == 0))
+    {
+      /* BMP */
+      hb_codepoint_t page = ch >> 8;
+      switch (page) {
+	case 0x00: return unlikely (ch == 0x00AD);
+	case 0x03: return unlikely (ch == 0x034F);
+	case 0x11: return hb_in_range<hb_codepoint_t> (ch, 0x115F, 0x1160);
+	case 0x17: return hb_in_range<hb_codepoint_t> (ch, 0x17B4, 0x17B5);
+	case 0x18: return hb_in_range<hb_codepoint_t> (ch, 0x180B, 0x180E);
+	case 0x20: return hb_in_ranges<hb_codepoint_t> (ch, 0x200B, 0x200F,
+							    0x202A, 0x202E,
+							    0x2060, 0x206F);
+	case 0x31: return unlikely (ch == 0x3164);
+	case 0xFE: return hb_in_range<hb_codepoint_t> (ch, 0xFE00, 0xFE0F) || ch == 0xFEFF;
+	case 0xFF: return hb_in_range<hb_codepoint_t> (ch, 0xFFF0, 0xFFF8) || ch == 0xFFA0;
+	default: return false;
+      }
+    }
+    else
+    {
+      /* Other planes */
+      switch (plane) {
+	case 0x01: return hb_in_range<hb_codepoint_t> (ch, 0x0001D173, 0x0001D17A);
+	case 0x0E: return hb_in_range<hb_codepoint_t> (ch, 0x000E0000, 0x000E0FFF);
+	default: return false;
+      }
+    }
   }
 
 
   struct {
 #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_func_t name;
     HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
   } func;
--- a/gfx/harfbuzz/src/hb-utf-private.hh
+++ b/gfx/harfbuzz/src/hb-utf-private.hh
@@ -72,18 +72,18 @@ hb_utf_next (const uint8_t *text,
   }
 }
 
 static inline const uint8_t *
 hb_utf_prev (const uint8_t *text,
 	     const uint8_t *start,
 	     hb_codepoint_t *unicode)
 {
-  const uint8_t *end = text;
-  while (start < text && (*--text & 0xc0) == 0x80 && end - text < 4)
+  const uint8_t *end = text--;
+  while (start < text && (*text & 0xc0) == 0x80 && end - text < 4)
     text--;
 
   hb_codepoint_t c = *text, mask;
   unsigned int len;
 
   /* TODO check for overlong sequences? */
 
   HB_UTF8_COMPUTE (c, mask, len);
--- a/gfx/harfbuzz/src/hb-version.h
+++ b/gfx/harfbuzz/src/hb-version.h
@@ -33,19 +33,19 @@
 
 #include "hb-common.h"
 
 HB_BEGIN_DECLS
 
 
 #define HB_VERSION_MAJOR 0
 #define HB_VERSION_MINOR 9
-#define HB_VERSION_MICRO 4
+#define HB_VERSION_MICRO 6
 
-#define HB_VERSION_STRING "0.9.4"
+#define HB_VERSION_STRING "0.9.6"
 
 #define HB_VERSION_CHECK(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,
--- a/gfx/harfbuzz/src/hb.h
+++ b/gfx/harfbuzz/src/hb.h
@@ -29,16 +29,17 @@
 #define HB_H_IN
 
 #include "hb-blob.h"
 #include "hb-buffer.h"
 #include "hb-common.h"
 #include "hb-font.h"
 #include "hb-set.h"
 #include "hb-shape.h"
+#include "hb-shape-plan.h"
 #include "hb-unicode.h"
 #include "hb-version.h"
 
 HB_BEGIN_DECLS
 HB_END_DECLS
 
 #undef HB_H_IN
 #endif /* HB_H */
--- a/gfx/harfbuzz/src/test-would-substitute.cc
+++ b/gfx/harfbuzz/src/test-would-substitute.cc
@@ -94,10 +94,10 @@ main (int argc, char **argv)
 #endif
 
   unsigned int len = argc - 3;
   hb_codepoint_t glyphs[2];
   if (!hb_font_glyph_from_string (font, argv[3], -1, &glyphs[0]) ||
       (argc > 4 &&
        !hb_font_glyph_from_string (font, argv[4], -1, &glyphs[1])))
     return 2;
-  return !hb_ot_layout_would_substitute_lookup (face, strtol (argv[2], NULL, 0), glyphs, len, false);
+  return !hb_ot_layout_lookup_would_substitute (face, strtol (argv[2], NULL, 0), glyphs, len, false);
 }